]> git.saurik.com Git - apple/security.git/commitdiff
Security-59306.61.1.tar.gz macos-10152 v59306.61.1
authorApple <opensource@apple.com>
Thu, 2 Apr 2020 16:50:48 +0000 (16:50 +0000)
committerApple <opensource@apple.com>
Thu, 2 Apr 2020 16:50:48 +0000 (16:50 +0000)
190 files changed:
KeychainCircle/Tests/FakeSOSControl.m
KeychainSyncAccountNotification/KeychainSyncAccountNotification.m
OSX/config/security_framework_macos.xcconfig
OSX/lib/en.lproj/authorization.dfr.prompts.strings
OSX/lib/en.lproj/authorization.prompts.strings
OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp
OSX/libsecurity_asn1/lib/secport-tapi.h [new file with mode: 0644]
OSX/libsecurity_codesigning/lib/SecCodePriv.h
OSX/libsecurity_keychain/lib/AppleBaselineEscrowCertificates.h [deleted file]
OSX/libsecurity_keychain/lib/SecCertificate.cpp
OSX/libsecurity_keychain/lib/SecCertificateBundle.h
OSX/libsecurity_smime/lib/cms-tapi.h [new file with mode: 0644]
OSX/libsecurity_ssl/lib/sslDeprecated.h [new file with mode: 0644]
OSX/libsecurity_transform/lib/SecTransformValidator.h
OSX/sec/Security/Regressions/secitem/si-25-cms-skid.m
OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c
OSX/sec/Security/SecEC-tapi.h [new file with mode: 0644]
OSX/sec/Security/SecExports.exp-in
OSX/sec/Security/SecItem.c
OSX/sec/Security/SecPolicy-tapi.h [new file with mode: 0644]
OSX/sec/Security/SecPolicy.c
OSX/sec/Security/SecTrust.c
OSX/sec/Security/SecTrustInternal.h
OSX/sec/Security/Security-tapi.h [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist
OSX/utilities/SecABC.h
OSX/utilities/SecABC.m
OSX/utilities/SecAppleAnchor-tapi.h [new file with mode: 0644]
RegressionTests/PreprocessPlist.sh [new file with mode: 0755]
RegressionTests/Security.plist
RegressionTests/bats_utd_plist.h [new file with mode: 0644]
SecExperiment/SecExperiment.m [deleted file]
SecExperiment/SecExperimentInternal.h [deleted file]
SecExperiment/SecExperimentPriv.h [deleted file]
SecExperiment/TLSAssets/Info.plist [deleted file]
SecExperiment/TLSAssets/Makefile [deleted file]
SecExperiment/TLSAssets/TLSConfig.plist [deleted file]
SecExperiment/test/SecExperimentTests.m [deleted file]
Security.exp-in
Security.xcodeproj/project.pbxproj
Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme
SecurityTool/macOS/trusted_cert_ssl.m
SecurityTool/macOS/verify_cert.c
SecurityTool/sharedTool/sos.m
TestPlan.xctestplan [new file with mode: 0644]
base/Security.h
experiment/SecExperiment.m [new file with mode: 0644]
experiment/SecExperimentInternal.h [new file with mode: 0644]
experiment/SecExperimentPriv.h [new file with mode: 0644]
experiment/test/SecExperimentTests.m [new file with mode: 0644]
experiment/tool/experimentTool-Entitlements.plist [new file with mode: 0644]
experiment/tool/experimentTool.m [new file with mode: 0644]
keychain/SecureObjectSync/SOSAccount.h
keychain/SecureObjectSync/SOSAccount.m
keychain/SecureObjectSync/SOSAccountConfiguration.proto [new file with mode: 0644]
keychain/SecureObjectSync/SOSAccountPersistence.m
keychain/SecureObjectSync/SOSAccountPriv.h
keychain/SecureObjectSync/SOSAccountRecovery.m
keychain/SecureObjectSync/SOSAccountTransaction.m
keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m
keychain/SecureObjectSync/SOSAccountUpdate.m
keychain/SecureObjectSync/SOSCircle.c
keychain/SecureObjectSync/SOSControlHelper.m
keychain/SecureObjectSync/SOSControlServer.m
keychain/SecureObjectSync/SOSManifest.c
keychain/SecureObjectSync/SOSPeer.m
keychain/SecureObjectSync/SOSRingTypes.m
keychain/SecureObjectSync/SOSRingUtils.c
keychain/SecureObjectSync/SOSTypes.h
keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h [new file with mode: 0644]
keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m [new file with mode: 0644]
keychain/Signin Metrics/Resources/SFTMTests-Info.plist [deleted file]
keychain/Signin Metrics/SFSignInAnalytics+Internal.h [deleted file]
keychain/Signin Metrics/SFSignInAnalytics.h [deleted file]
keychain/Signin Metrics/SFSignInAnalytics.m [deleted file]
keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m [deleted file]
keychain/SigninMetrics/OctagonSignPosts.h [new file with mode: 0644]
keychain/SigninMetrics/OctagonSignPosts.m [new file with mode: 0644]
keychain/SigninMetrics/Resources/SFTMTests-Info.plist [new file with mode: 0644]
keychain/SigninMetrics/Resources/com.apple.security.signposts.plist [new file with mode: 0644]
keychain/SigninMetrics/SFSignInAnalytics+Internal.h [new file with mode: 0644]
keychain/SigninMetrics/SFSignInAnalytics.h [new file with mode: 0644]
keychain/SigninMetrics/SFSignInAnalytics.m [new file with mode: 0644]
keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m [new file with mode: 0644]
keychain/Trieste/OctagonTestHarnessXPCService/Entitlements.plist
keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m
keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m
keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDeviceProtocol.h
keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h
keychain/TrustedPeersHelper/Client.swift
keychain/TrustedPeersHelper/Container.swift
keychain/TrustedPeersHelper/Container_MachineIDs.swift
keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h
keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m
keychain/TrustedPeersHelperUnitTests/ContainerSync.swift
keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift
keychain/ckks/CKKS.h
keychain/ckks/CKKSAnalytics.h
keychain/ckks/CKKSAnalytics.m
keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h
keychain/ckks/CKKSKeychainView.m
keychain/ckks/CKKSNearFutureScheduler.h
keychain/ckks/CKKSNearFutureScheduler.m
keychain/ckks/CKKSOutgoingQueueOperation.m
keychain/ckks/CKKSPBFileStorage.h [new file with mode: 0644]
keychain/ckks/CKKSPBFileStorage.m [new file with mode: 0644]
keychain/ckks/CKKSResultOperation.h
keychain/ckks/CKKSResultOperation.m
keychain/ckks/CKKSZoneChangeFetcher.h
keychain/ckks/CKKSZoneChangeFetcher.m
keychain/ckks/CKKSZoneModifier.m
keychain/ckks/CloudKitCategories.h
keychain/ckks/CloudKitCategories.m
keychain/ckks/OctagonAPSReceiver.h
keychain/ckks/OctagonAPSReceiver.m
keychain/ckks/tests/CKKSAPSHandlingTests.m
keychain/ckks/tests/CKKSPBFileStorageTests.m [new file with mode: 0644]
keychain/ckks/tests/CKKSTests.m
keychain/ckks/tests/CloudKitMockXCTest.h
keychain/ckks/tests/CloudKitMockXCTest.m
keychain/ckks/tests/MockCloudKit.h
keychain/ckks/tests/MockCloudKit.m
keychain/escrowrequest/EscrowRequestController.m
keychain/ot/CuttlefishXPCWrapper.m
keychain/ot/OTAuthKitAdapter.h
keychain/ot/OTAuthKitAdapter.m
keychain/ot/OTClientStateMachine.m
keychain/ot/OTClique.m
keychain/ot/OTConstants.h
keychain/ot/OTConstants.m
keychain/ot/OTCuttlefishContext.h
keychain/ot/OTCuttlefishContext.m
keychain/ot/OTDefines.h
keychain/ot/OTDetermineHSA2AccountStatusOperation.m
keychain/ot/OTManager.m
keychain/ot/OTPrepareOperation.m
keychain/ot/OTSOSUpgradeOperation.m
keychain/ot/OTSetRecoveryKeyOperation.m
keychain/ot/OTStates.h
keychain/ot/OTStates.m
keychain/ot/OTVouchWithBottleOperation.m
keychain/ot/OTVouchWithRecoveryKeyOperation.m
keychain/ot/ObjCImprovements.h
keychain/ot/OctagonCKKSPeerAdapter.m
keychain/ot/OctagonFlags.h
keychain/ot/OctagonFlags.m
keychain/ot/OctagonStateMachine.h
keychain/ot/OctagonStateMachine.m
keychain/ot/OctagonStateMachineHelpers.h
keychain/ot/OctagonStateMachineHelpers.m
keychain/ot/OctagonStateMachineObservers.h
keychain/ot/OctagonStateMachineObservers.m
keychain/ot/tests/octagon/OctagonTests+DeviceList.swift
keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift
keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift
keychain/ot/tests/octagon/OctagonTests+Reset.swift
keychain/ot/tests/octagon/OctagonTests+SOS.swift
keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h
keychain/ot/tests/octagon/OctagonTests.swift
keychain/securityd/Regressions/SOSAccountTesting.h
keychain/securityd/Regressions/secd-62-account-backup.m
keychain/securityd/Regressions/secd-66-account-recovery.m
keychain/securityd/SOSCloudCircleServer.h
keychain/securityd/SOSCloudCircleServer.m
keychain/securityd/SecDbKeychainItemV7.m
keychain/securityd/SecDbKeychainMetadataKeyStore.m
keychain/tpctl/main.swift
protocol/SecProtocol.c
protocol/SecProtocolPriv.h
protocol/SecProtocolTest.m
secdxctests/KeychainAPITests.m
securityd/etc/com.apple.securityd.sb
tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist
tests/secdmockaks/MockAKSOptionalParameters.proto [new file with mode: 0644]
tests/secdmockaks/MockAKSRefKey.proto [new file with mode: 0644]
tests/secdmockaks/generated_source/MockAKSOptionalParameters.h [new file with mode: 0644]
tests/secdmockaks/generated_source/MockAKSOptionalParameters.m [new file with mode: 0644]
tests/secdmockaks/generated_source/MockAKSRefKey.h [new file with mode: 0644]
tests/secdmockaks/generated_source/MockAKSRefKey.m [new file with mode: 0644]
tests/secdmockaks/mockaks.h
tests/secdmockaks/mockaks.m
tests/secdmockaks/mockaksKeychain.m
tests/secdmockaks/mockaksxcbase.m
trust/trustd/SecRevocationDb.c
trust/trustd/SecTrustServer.c
trust/trustd/SecTrustServer.h
trust/trustd/md.h [new file with mode: 0644]
trust/trustd/md.m [new file with mode: 0644]
xcconfig/PlatformLibraries.xcconfig
xcconfig/Security.xcconfig

index e0a2c500f181ca6c064be56af7a86d245bc5e3bc..b8edbae990b3aa87dbe2a82e1adfdbe0eef4b20b 100644 (file)
     complete(true, NULL);
 }
 
-- (void)triggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
 {
     complete(true, NULL);
 }
     complete(nil, nil);
 }
 
+- (void)rpcTriggerBackup:(NSArray<NSString *> *)backupPeers complete:(void (^)(NSError *))complete {
+    complete(nil);
+}
+
+- (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete {
+    complete(nil);
+}
+
+
 @end
index 7120509f0bb3de3d0f018bd09dd5de036df9616c..030606c437f8abf2a5315530faf21b270098c207 100644 (file)
 
 #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];
 
         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;
                 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");
index b970865649323233f355d00e9f67e8c63607e238..f341fbd7ed5a8b3b5122e38f7a5d049e2e9bcbbc 100644 (file)
@@ -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
index 2ee028fd06b75747f79f08463fbe2b9a176f2eba..e54e35f7ba6b68c0f64b16744f0145f9cf2b11f6 100644 (file)
@@ -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.";
 
 
 "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.";
 
index 7986719b2094624e3188bb0d5d47df5c68fc4f51..1686dbd63897d2832a56026ebbfc9c7b6bd88e09 100644 (file)
@@ -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.";
 
 
 "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.";
 
index 786c21f1e55f70bbbc9eece37f4e5df4c69a7c4b..17c152f83cd3036028314ee7ea87762f5f0a2f81 100644 (file)
@@ -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 (file)
index 0000000..e0054f0
--- /dev/null
@@ -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_ */
index f4d8e2a7a020abbe70fea70baed2409e673098aa..d88239c8c832be674a9443a6b4e1c54ec14e1b39 100644 (file)
@@ -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 (file)
index ba5e31d..0000000
+++ /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
index 7c1e40b4a440b272c57f267caf122ae756fff655..ca154314f95f560b729adeab1b4a1ee4eb431486 100644 (file)
@@ -46,9 +46,6 @@
 #include <syslog.h>
 #include "CertificateValues.h"
 
-#include "AppleBaselineEscrowCertificates.h"
-
-
 OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle);
 extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage);
 
index d2bc3e10fa087089f14f611b6c1a2c6cfaee6e42..a20f1bc1a68e72e93cd28d90240226590a8fb0c6 100644 (file)
@@ -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 (file)
index 0000000..3866e63
--- /dev/null
@@ -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 (file)
index 0000000..54703bf
--- /dev/null
@@ -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_ */
index e6c8a496771b8a9c78d0db23e9d479457f4ce057..2e69f2432e54455464ce600655eb8c19296d7c55 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _SEC_TRANSFORMVALIDATOR_H__
 #define _SEC_TRANSFORMVALIDATOR_H__
 
+#include <Security/SecCustomTransform.h>
+
 CF_EXTERN_C_BEGIN
 
 
index d6d53b982b5ca4299029ca81a9498927946afc05..7ed59fb0e2cf3d3b85e78c9ffce8a42b1c6c1289 100644 (file)
@@ -28,6 +28,7 @@
 
 #import <Security/SecCMS.h>
 #import <Security/SecTrust.h>
+#import <Security/SecTrustPriv.h>
 #include <utilities/SecCFRelease.h>
 
 #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();
 
index c6bfdcfac7aa032347bbf5d043224ffe93cccd13..9119beb26d617551121687f06859c3647d02706b 100644 (file)
@@ -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 (file)
index 0000000..fe4c8e0
--- /dev/null
@@ -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 <Security/SecBase.h>
+#include <corecrypto/ccec.h>
+
+__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
index 896958183bda83a9bc6cbcf3ad48dba42c313fc9..7067b56d2c2392641c3f8818b867c7b693d020d9 100644 (file)
@@ -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
index 433acca771b978036e6d493d34e9b9241ba905e6..b526d63292249ec136d96672c1002a165fc5b078 100644 (file)
@@ -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 (file)
index 0000000..cdd5846
--- /dev/null
@@ -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 <xpc/xpc.h>
+
+#include <Security/SecPolicy.h>
+#include <Security/SecTrust.h>
+#include <CoreFoundation/CFArray.h>
+#include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFRuntime.h>
+
+__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_ */
index 2c37c6b4a42778baf5fa0372a1618063a97773e6..98db0bf9a785f7b6b63bc3142e7371596bf88946 100644 (file)
@@ -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) {
index bf3cbaab5d06c068bdba69d82ae0b0b742196311..d64de6dd4b7923bce1416c602c0f5cee9d43fcd9 100644 (file)
@@ -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"
index f363940105ca82e9359ea72762a2403fd9b80942..4921bdd9ec5ae979d1d7d009fb07ae010ea8d132 100644 (file)
@@ -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 (file)
index 0000000..e3e068f
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+
+#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_ */
index cc6821c800c5ed9a4747a484853a472ca9b36265..2f480cf61adf3894fae8f3d03e384cf4088f7944 100644 (file)
                <key>MajorTestName</key>
                <string>EscrowService</string>
                <key>MinorTestName</key>
-               <string>NegativeTest-v1</string>
-               <key>Policies</key>
-               <dict>
-                       <key>PolicyIdentifier</key>
-                       <string>1.2.840.113635.100.1.24</string>
-               </dict>
-               <key>Leaf</key>
-               <string>escrow_service_key_B157A8D4</string>
-               <key>Intermediates</key>
-               <string>EscrowServiceRootCA0</string>
-               <key>Anchors</key>
-               <string>EscrowServiceRootCA0</string>
-               <key>ExpectedResult</key>
-               <integer>5</integer>
-       </dict>
-       <dict>
-               <key>CertDirectory</key>
-               <string>si-20-sectrust-policies-data</string>
-               <key>BridgeOSDisable</key>
-               <true/>
-               <key>MajorTestName</key>
-               <string>EscrowService</string>
-               <key>MinorTestName</key>
-               <string>NegativeTest-v2</string>
-               <key>Policies</key>
-               <dict>
-                       <key>PolicyIdentifier</key>
-                       <string>1.2.840.113635.100.1.24</string>
-               </dict>
-               <key>Leaf</key>
-               <string>escrow_service_key_049F9D11</string>
-               <key>Intermediates</key>
-               <string>EscrowServiceRootCA101</string>
-               <key>Anchors</key>
-               <string>EscrowServiceRootCA101</string>
-               <key>ExpectedResult</key>
-               <integer>5</integer>
-       </dict>
-       <dict>
-               <key>CertDirectory</key>
-               <string>si-20-sectrust-policies-data</string>
-               <key>BridgeOSDisable</key>
-               <true/>
-               <key>MajorTestName</key>
-               <string>PCSEscrowService</string>
-               <key>MinorTestName</key>
                <string>PositiveTest</string>
                <key>Policies</key>
                <dict>
index 53c3f7b7dd6a31a8dc98df84c78cbf0ce3912a3e..000223960ca311bb600d046e195cb80b9608c9de 100644 (file)
@@ -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
index 23519a62cbd4aebaeb03e453643ba5b4dce5622c..71e41ae3b789c6b24ff0abace607104e0288b0ba 100644 (file)
@@ -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 (file)
index 0000000..811e8e5
--- /dev/null
@@ -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 <CoreFoundation/CoreFoundation.h>
+#include <Security/Security.h>
+#include <sys/cdefs.h>
+
+__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 (executable)
index 0000000..851e4b1
--- /dev/null
@@ -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/<string>_FALSE_<\/string>/<false\/>/' -e 's/<string>_TRUE_<\/string>/<true\/>/' > "$dstPath"
+plutil -convert binary1 "$dstPath"
+
+[ "$(whoami)" == "root" ] || exit 0
+chown root:wheel "$dstPath"
index 15cb464c994c7cadb87008f26d66334785e65f60..e08137ea059066f4d44d731a7480520cdd18d223 100644 (file)
@@ -14,6 +14,8 @@
                                <string>/usr/local/bin/keystorectl</string>
                                <string>get-lock-state</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_keystorectl_get_lock_state</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -22,6 +24,8 @@
                        <array>
                                <string>/usr/libexec/security-sysdiagnose</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_security_sysdiagnose</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -30,6 +34,8 @@
                        <array>
                                <string>/AppleInternal/CoreOS/tests/Security/secedumodetest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_EduModeTest</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -38,6 +44,8 @@
                        <array>
                                <string>/AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionstest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_1</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -46,6 +54,8 @@
                        <array>
                                <string>/AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionsystemdaemontest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_2</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -54,6 +64,8 @@
                        <array>
                                <string>/AppleInternal/CoreOS/tests/Security/seckeychainnetworkextensionunauthorizedaccesstest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_3</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -66,6 +78,8 @@
                                <string>-t</string>
                                <string>KCPairingTests</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_KCPairingTest</string>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -74,8 +88,8 @@
                        <array>
                                <string>/AppleInternal/CoreOS/tests/Security/authdtest</string>
                        </array>
-                       <key>EligibleResource</key>
-                       <string>type != &apos;CAMEmbeddedDeviceResource&apos;</string>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_AuthorizationTest</string>
                </dict>
                <dict>
                        <key>TestName</key>
                                <string>BATS_XCTEST_CMD</string>
                                <string>/AppleInternal/XCTests/com.apple.security/KeychainAnalyticsTests.xctest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_KeychainAnalyticsTests</string>
                </dict>
                <dict>
                        <key>TestName</key>
                                <string>BATS_XCTEST_CMD</string>
                                <string>/AppleInternal/XCTests/com.apple.security/secdmockaks.xctest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_KeychainMockAKSTests</string>
                </dict>
                <dict>
                        <key>TestName</key>
                                <string>BATS_XCTEST_CMD</string>
                                <string>/AppleInternal/XCTests/com.apple.security/secdxctests_mac.xctest</string>
                        </array>
-                       <key>EligibleResource</key>
-                       <string>type != &apos;CAMEmbeddedDeviceResource&apos;</string>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_KeychainSecd_macOS</string>
                </dict>
                <dict>
                        <key>TestName</key>
                                <string>BATS_XCTEST_CMD</string>
                                <string>/AppleInternal/XCTests/com.apple.security/secdxctests_ios.xctest</string>
                        </array>
-                       <key>EligibleResource</key>
-                       <string>type == &apos;CAMEmbeddedDeviceResource&apos;</string>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_KeychainSecd_iOS</string>
                </dict>
                <dict>
                        <key>TestName</key>
                                <string>BATS_XCTEST_CMD</string>
                                <string>/AppleInternal/XCTests/com.apple.security/SecurityUtilitiesTests.xctest</string>
                        </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_SecurityUtiltitesTests</string>
                </dict>
        </array>
 </dict>
diff --git a/RegressionTests/bats_utd_plist.h b/RegressionTests/bats_utd_plist.h
new file mode 100644 (file)
index 0000000..e8549e9
--- /dev/null
@@ -0,0 +1,81 @@
+#include <TargetConditionals.h>
+
+/*
+ * 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:
+ *     <dict>
+ *             <key>TestName</key>
+ *             <string>KeychainSecd_iOS</string>
+ *             <key>Disabled</key>
+ *             <string>BATS_UTD_Disabled_KeychainSecd_iOS</string>
+ *     </dict>
+ *
+ * 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:
+ *     <dict>
+ *             <key>TestName</key>
+ *             <string>KeychainSecd_iOS</string>
+ *             <key>Disabled</key>
+ *             <true/>
+ *     </dict>
+ *
+ * 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 (file)
index fac3efd..0000000
+++ /dev/null
@@ -1,322 +0,0 @@
-//
-//  SecExperiment.m
-//  Security
-//
-
-#include <xpc/xpc.h>
-#include <os/log.h>
-#include <Security/SecTrustPriv.h>
-#include <uuid/uuid.h>
-
-#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<OS_OBJECT_CLASS(external_type)>                \
-_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 <Foundation/Foundation.h>
-#import <CoreFoundation/CFXPCBridge.h>
-
-#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 (file)
index 6bd4fb2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-//  SecExperimentInternal.h
-//  Security
-//
-
-#ifndef SecExperimentInternal_h
-#define SecExperimentInternal_h
-
-#include <Security/SecExperimentPriv.h>
-
-/*!
- * @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 (file)
index 5e99758..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-//  SecExperimentPriv.h
-//  Security
-//
-
-#ifndef SecExperiment_h
-#define SecExperiment_h
-
-#include <Security/SecProtocolObject.h>
-
-#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 (file)
index d314b50..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleIdentifier</key>
-       <string>com.apple.MobileAsset.SecExperimentAssets</string>
-       <key>CFBundleName</key>
-       <string>SecExperimentAssets</string>
-       <key>CFBundleVersion</key>
-       <string>1.0</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0.0</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>1</string>
-       <key>MobileAssetProperties</key>
-       <dict>
-               <key>_ContentVersion</key>
-               <string>1</string>
-               <key>_CompatibilityVersion</key>
-               <string>1</string>
-       </dict>
-</dict>
-</plist>
diff --git a/SecExperiment/TLSAssets/Makefile b/SecExperiment/TLSAssets/Makefile
deleted file mode 100644 (file)
index e3577db..0000000
+++ /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 (file)
index 83b98cb..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>validate</key>
-       <dict>
-               <key>tcp</key>
-               <dict/>
-               <key>tls</key>
-               <dict>
-                       <key>max_version</key>
-                       <integer>771</integer>
-                       <key>false_start_enabled</key>
-                       <false/>
-               </dict>
-       </dict>
-       <key>transform</key>
-       <dict>
-               <key>tcp</key>
-               <dict/>
-               <key>tls</key>
-               <dict>
-                       <key>max_version</key>
-                       <integer>772</integer>
-                       <key>false_start_enabled</key>
-                       <true/>
-               </dict>
-       </dict>
-</dict>
-</plist>
diff --git a/SecExperiment/test/SecExperimentTests.m b/SecExperiment/test/SecExperimentTests.m
deleted file mode 100644 (file)
index 4374136..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-//  SecExperimentTests.m
-//
-//
-
-#import <XCTest/XCTest.h>
-#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
index 5da8fa4d6d05329538a96ddcc21de39112558cae..a027eee76deae4ad53aa81801fc719fdb43e09d3 100644 (file)
@@ -341,6 +341,10 @@ SEC_EXP_CLASS(OTOperationConfiguration)
 _kSecEntitlementPrivateOctagonEscrow
 #endif
 
+__OctagonSignpostCreate
+__OctagonSignpostGetNanoseconds
+__OctagonSignpostLogSystem
+
 _OTCliqueStatusToString
 _OTCliqueStatusFromString
 
index 5d5176ea3ce0b0dab81cea60708e61081b7a3d78..63d915ed8fb1ac2e334407fe05bebdb2519ea58c 100644 (file)
                        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 = (
                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, ); }; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                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, ); }; };
                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 */; };
                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 */; };
                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, ); }; };
                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 */; };
                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 */; };
                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, ); }; };
                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 */; };
                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 */; };
                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 */; };
                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 */; };
                        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 */;
                        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 */;
                        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 */;
                        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 */;
                        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 */;
                        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;
                        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 */,
                0C8BBF101FCB486B00580909 /* OTManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTManager.h; sourceTree = "<group>"; };
                0C8FD546214AEC650098E3FB /* OTJoiningConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTJoiningConfiguration.h; sourceTree = "<group>"; };
                0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTJoiningConfiguration.m; sourceTree = "<group>"; };
+               0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.signposts.plist; sourceTree = "<group>"; };
                0C9AE289214054F4003BFDB5 /* OTSponsorToApplicantRound1M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound1M2.h; sourceTree = "<group>"; };
                0C9AE28A214054F5003BFDB5 /* OTSponsorToApplicantRound2M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound2M2.h; sourceTree = "<group>"; };
                0C9AE28B214054F5003BFDB5 /* OTApplicantToSponsorRound2M1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTApplicantToSponsorRound2M1.h; sourceTree = "<group>"; };
                0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = "<group>"; };
                0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = "<group>"; };
                0CD8D654207D6E65005CDBE8 /* SFAnalytics+Signin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Signin.h"; sourceTree = "<group>"; };
+               0CD9E33E235928D1002995DE /* OctagonSignPosts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonSignPosts.h; sourceTree = "<group>"; };
+               0CD9E340235928E9002995DE /* OctagonSignPosts.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OctagonSignPosts.m; sourceTree = "<group>"; };
                0CDBCD8620AD03FB007F8EA7 /* OTClique.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClique.h; sourceTree = "<group>"; };
                0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTTriggerEscrowUpdateOperation.m; sourceTree = "<group>"; };
                0CDD6F78226E62BC009094C2 /* OTTriggerEscrowUpdateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTTriggerEscrowUpdateOperation.h; sourceTree = "<group>"; };
                107226D10D91DB32003CF14F /* SecTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTask.h; path = sectask/SecTask.h; sourceTree = "<group>"; };
                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 = "<group>"; };
+               1B2BD391235E050D009A8624 /* SecEC-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SecEC-tapi.h"; path = "OSX/sec/Security/SecEC-tapi.h"; sourceTree = "<group>"; };
+               1B2BD393235E050E009A8624 /* SecPolicy-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SecPolicy-tapi.h"; path = "OSX/sec/Security/SecPolicy-tapi.h"; sourceTree = "<group>"; };
+               1B2BD394235E050E009A8624 /* Security-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Security-tapi.h"; path = "OSX/sec/Security/Security-tapi.h"; sourceTree = "<group>"; };
                1B4C4448223AE65400C6F97F /* TPPBPolicyKeyViewMapping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPPBPolicyKeyViewMapping.h; sourceTree = "<group>"; };
                1B4C444A223AE65400C6F97F /* TPPBPolicyKeyViewMapping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPPBPolicyKeyViewMapping.m; sourceTree = "<group>"; };
                1B5EAAD92252ABCC008D27E7 /* OTFetchViewsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTFetchViewsOperation.h; sourceTree = "<group>"; };
                1BC6F79821C9955E005ED67A /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
                1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = policy_dryrun.m; sourceTree = "<group>"; };
                1BDEBEFA2252E1DD009AD3D6 /* policy_dryrun.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policy_dryrun.h; sourceTree = "<group>"; };
+               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 = "<group>"; };
+               1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "secport-tapi.h"; sourceTree = "<group>"; };
+               1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sslDeprecated.h; path = OSX/libsecurity_ssl/lib/sslDeprecated.h; sourceTree = "<group>"; };
                1BF640EE222EEB6C002D0FCB /* TPPolicyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPPolicyTests.m; sourceTree = "<group>"; };
                1F631C5122387F27005920D8 /* legacydevid.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = legacydevid.cpp; sourceTree = "<group>"; usesTabs = 0; };
                1F631C5222387F27005920D8 /* legacydevid.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = legacydevid.h; sourceTree = "<group>"; };
                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 = "<group>"; };
-               3D1A57412166931B009C24FD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               3D421458216C0A2400D62870 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
                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 = "<group>"; };
-               3D7AA28E2187AD0000F1575C /* SecExperimentTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecExperimentTests.m; sourceTree = "<group>"; };
-               3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecExperimentPriv.h; sourceTree = "<group>"; };
                3DD1FE78201AA50C0086D049 /* STLegacyTests+clientauth41.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STLegacyTests+clientauth41.m"; sourceTree = "<group>"; };
                3DD1FE79201AA50D0086D049 /* SecureTransport_macosTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SecureTransport_macosTests.plist; sourceTree = "<group>"; };
                3DD1FE7A201AA50D0086D049 /* STLegacyTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "STLegacyTests-Entitlements.plist"; sourceTree = "<group>"; };
                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 = "<group>"; };
-               3DD852B02177FF72009E705D /* SecExperiment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecExperiment.m; sourceTree = "<group>"; };
                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 = "<group>"; };
                5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSDate+SFAnalytics.m"; sourceTree = "<group>"; };
                5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSDate+SFAnalytics.h"; sourceTree = "<group>"; };
                5A1A1C2122A71D2A00CB8D1D /* NSDate+SFAnalyticsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+SFAnalyticsTests.m"; sourceTree = "<group>"; };
-               5A2551F12229F40800512FAE /* SecExperimentInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecExperimentInternal.h; sourceTree = "<group>"; };
                5A43A07F225FA38D005450E4 /* SecProtocolHelperTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecProtocolHelperTest.m; path = protocol/SecProtocolHelperTest.m; sourceTree = "<group>"; };
+               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 = "<group>"; };
+               5A442F9A233C34C000918373 /* SecExperimentTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecExperimentTests.m; sourceTree = "<group>"; };
+               5A442F9B233C34C000918373 /* SecExperimentInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecExperimentInternal.h; sourceTree = "<group>"; };
+               5A442F9C233C34C000918373 /* SecExperiment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecExperiment.m; sourceTree = "<group>"; };
+               5A442F9E233C34C000918373 /* experimentTool-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "experimentTool-Entitlements.plist"; sourceTree = "<group>"; };
+               5A442F9F233C34C000918373 /* experimentTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = experimentTool.m; sourceTree = "<group>"; };
                5A47FFB1228F5DF700F781B8 /* KCInitialMessageData.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = KCInitialMessageData.proto; sourceTree = "<group>"; };
                5A47FFB4228F5E9000F781B8 /* KCInitialMessageData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KCInitialMessageData.h; path = generated_source/KCInitialMessageData.h; sourceTree = "<group>"; };
                5A47FFB5228F5E9000F781B8 /* KCInitialMessageData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCInitialMessageData.m; path = generated_source/KCInitialMessageData.m; sourceTree = "<group>"; };
                BEC373C120D8224A00DBDF5B /* TPPBDispositionEntry.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = TPPBDispositionEntry.proto; sourceTree = "<group>"; };
                BEC373C920D822CD00DBDF5B /* TPPBDispositionEntry.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPPBDispositionEntry.m; sourceTree = "<group>"; };
                BEC373CA20D822CE00DBDF5B /* TPPBDispositionEntry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPPBDispositionEntry.h; sourceTree = "<group>"; };
+               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 = "<group>"; };
                BECEC11020A508F600E97255 /* TPVoucher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPVoucher.h; sourceTree = "<group>"; };
                BECEC11120A508F600E97255 /* TPVoucher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPVoucher.m; sourceTree = "<group>"; };
                D4707A2B2114B31A005BCFDA /* SecCmsContentInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsContentInfo.h; path = CMS/SecCmsContentInfo.h; sourceTree = "<group>"; };
                D4707A2E2114C30A005BCFDA /* SecCmsDigestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsDigestContext.h; path = CMS/SecCmsDigestContext.h; sourceTree = "<group>"; };
                D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/Trust.strings; sourceTree = "<group>"; };
+               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 = "<group>"; };
                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 = "<group>"; };
                D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = "<group>"; };
                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 = "<group>"; };
+               D47DCCB723427C8D00B80E37 /* md.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = md.h; sourceTree = "<group>"; };
                D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecCFAllocator.h; sourceTree = "<group>"; };
                D48BD193206C47530075DDC9 /* si-35-cms-expiration-time.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-35-cms-expiration-time.m"; sourceTree = "<group>"; };
                D48BD195206C476B0075DDC9 /* si-35-cms-expiration-time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-35-cms-expiration-time.h"; sourceTree = "<group>"; };
                DCFF82702162834C00D54B02 /* OctagonTestsXPCConnections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OctagonTestsXPCConnections.swift; sourceTree = "<group>"; };
                DCFF82722162876400D54B02 /* OTResetOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTResetOperation.h; sourceTree = "<group>"; };
                DCFF82732162876400D54B02 /* OTResetOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTResetOperation.m; sourceTree = "<group>"; };
-               E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OctagonTrieste.xcodeproj; path = OctagonTriesteTests/OctagonTrieste.xcodeproj; sourceTree = "<group>"; };
                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 = "<group>"; };
                E060D19F2124780F0025B833 /* OctagonTestHarnessXPCService.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTestHarnessXPCService.h; sourceTree = "<group>"; };
                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 = "<group>"; };
                EB0BC9661C3C794700785842 /* secedumodetest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secedumodetest.m; path = secedumodetest/secedumodetest.m; sourceTree = "<group>"; };
+               EB0E1AC72352A81E002B6037 /* SOSAccountConfiguration.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SOSAccountConfiguration.proto; sourceTree = "<group>"; };
+               EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSPBFileStorageTests.m; sourceTree = "<group>"; };
+               EB0E1B922358FADE002B6037 /* SOSAccountConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSAccountConfiguration.h; sourceTree = "<group>"; };
+               EB0E1B932358FADE002B6037 /* SOSAccountConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSAccountConfiguration.m; sourceTree = "<group>"; };
                EB10556B1E14DC0F0003C309 /* SecCertificateFuzzer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateFuzzer.c; sourceTree = "<group>"; };
                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; };
                EB4E0CD51FF36A1900CDCACC /* CKKSReachabilityTracker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSReachabilityTracker.m; sourceTree = "<group>"; };
                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 = "<group>"; };
+               EB627A6F233E323600F32437 /* MockAKSOptionalParameters.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = MockAKSOptionalParameters.proto; sourceTree = "<group>"; };
+               EB627A75233E342800F32437 /* MockAKSRefKey.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockAKSRefKey.m; sourceTree = "<group>"; };
+               EB627A76233E342900F32437 /* MockAKSRefKey.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAKSRefKey.h; sourceTree = "<group>"; };
+               EB627A77233E342B00F32437 /* MockAKSOptionalParameters.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MockAKSOptionalParameters.m; sourceTree = "<group>"; };
+               EB627A78233E342B00F32437 /* MockAKSOptionalParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MockAKSOptionalParameters.h; sourceTree = "<group>"; };
                EB6667BE204CD65E000B404F /* testPlistDER.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = testPlistDER.m; sourceTree = "<group>"; };
                EB6928BE1D9C9C5900062A18 /* SecRecoveryKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRecoveryKey.h; sourceTree = "<group>"; };
                EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecRecoveryKey.m; sourceTree = "<group>"; };
                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 = "<group>"; };
                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 = "<group>"; };
                EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-37-pairing-initial-sync.m"; sourceTree = "<group>"; };
                EB9C1D7A1BDFD0E000F89272 /* secbackupntest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secbackupntest; sourceTree = BUILT_PRODUCTS_DIR; };
                EBDAA7E320EC46CF003EA6E5 /* SecurityLocalKeychain.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = SecurityLocalKeychain.plist; sourceTree = "<group>"; };
                EBDAF15B21C75FF200EAE89F /* NSXPCConnectionMock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NSXPCConnectionMock.h; sourceTree = "<group>"; };
                EBDAF15C21C75FF200EAE89F /* NSXPCConnectionMock.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSXPCConnectionMock.m; sourceTree = "<group>"; };
+               EBDCBFFE233DD31700806566 /* MockAKSRefKey.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = MockAKSRefKey.proto; sourceTree = "<group>"; };
                EBDE5DF922BA3D5D00A229C8 /* CKKSMockOctagonAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSMockOctagonAdapter.h; sourceTree = "<group>"; };
                EBDE5DFA22BA3D5D00A229C8 /* CKKSMockOctagonAdapter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSMockOctagonAdapter.m; sourceTree = "<group>"; };
                EBE2026420908A8A00B48020 /* tpctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = tpctl.8; sourceTree = "<group>"; };
                        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 */,
                        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 */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               5A442F89233C330F00918373 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5A442F8A233C330F00918373 /* Security.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                5E10992219A5E55800A60E2B /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        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 */,
                                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 */,
                                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 */,
                                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 */,
                                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;
                };
                        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 */,
                        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 */,
                                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 */,
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               EB8A9381233C900D0015A794 /* CloudServices.framework in Frameworks */,
                                EBFF95EF214C823F0021CD14 /* KeychainCircle.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        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 */,
                        isa = PBXGroup;
                        children = (
                                0C9FB40120D8729A00864612 /* CoreCDP.framework */,
+                               DCD067E71D8CDF7E007602F1 /* SecCodeHostLib.h */,
+                               DCD067E81D8CDF7E007602F1 /* SecCodeHostLib.c */,
                        );
                        name = "Recovered References";
                        sourceTree = "<group>";
                        name = RecoveryKey;
                        sourceTree = "<group>";
                };
-               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 = "<group>";
                };
                0CF405F32072E295003D6A7F /* tests */ = {
                0CF405FB2072E351003D6A7F /* Resources */ = {
                        isa = PBXGroup;
                        children = (
+                               0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */,
                                0CF405FC2072E352003D6A7F /* SFTMTests-Info.plist */,
                        );
                        path = Resources;
                        path = ../../../sectask;
                        sourceTree = "<group>";
                };
-               3D1A573E21669291009C24FD /* TLSAssets */ = {
-                       isa = PBXGroup;
-                       children = (
-                               3D1A57412166931B009C24FD /* Info.plist */,
-                               3D6C25BA216C00D800AB2A71 /* TLSConfig.plist */,
-                               3D421458216C0A2400D62870 /* Makefile */,
-                       );
-                       path = TLSAssets;
-                       sourceTree = "<group>";
-               };
-               3D7AA28D2187ACD500F1575C /* test */ = {
-                       isa = PBXGroup;
-                       children = (
-                               3D7AA28E2187AD0000F1575C /* SecExperimentTests.m */,
-                       );
-                       path = test;
-                       sourceTree = "<group>";
-               };
-               3DA3384121658755008C0CE1 /* SecExperiment */ = {
-                       isa = PBXGroup;
-                       children = (
-                               3DA3384421658AA8008C0CE1 /* SecExperimentPriv.h */,
-                               5A2551F12229F40800512FAE /* SecExperimentInternal.h */,
-                               3DD852B02177FF72009E705D /* SecExperiment.m */,
-                               3D7AA28D2187ACD500F1575C /* test */,
-                               3D1A573E21669291009C24FD /* TLSAssets */,
-                       );
-                       path = SecExperiment;
-                       sourceTree = "<group>";
-               };
                3DD1FE72201AA38A0086D049 /* SecureTransportTests */ = {
                        isa = PBXGroup;
                        children = (
                47B3A90B21027D71001F4281 /* Trieste */ = {
                        isa = PBXGroup;
                        children = (
-                               E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */,
                                E060D19D2124780F0025B833 /* OctagonTestHarness */,
                                E060D1BD212478120025B833 /* OctagonTestHarnessXPCService */,
                                E060D23E21247C680025B833 /* OctagonTestHarnessXPCServiceProtocol */,
                                EB6952B9223B75C300F02C1C /* secitemd */,
                                DA41FE0E2241ADC000838FB3 /* otpaird */,
                                EBB851EC22F7912400424FD0 /* SecurityUtilitiesTests.xctest */,
+                               5A442F90233C330F00918373 /* experimentTool */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                4C922CB2097F1984004CEEBD /* Security */ = {
                        isa = PBXGroup;
                        children = (
+                               1BE85ECD235CEB610051E1D8 /* cms-tapi.h */,
                                5F00F95A230614A200B832E0 /* SecImportExportPriv.h */,
                                D44D08B420AB890E0023C439 /* Security.apinotes */,
                                D4707A1021137525005BCFDA /* CMSDecoder.h */,
                        path = test;
                        sourceTree = "<group>";
                };
+               5A442F97233C34C000918373 /* experiment */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5A442F98233C34C000918373 /* SecExperimentPriv.h */,
+                               5A442F9B233C34C000918373 /* SecExperimentInternal.h */,
+                               5A442F9C233C34C000918373 /* SecExperiment.m */,
+                               5A442F99233C34C000918373 /* test */,
+                               5A442F9D233C34C000918373 /* tool */,
+                       );
+                       path = experiment;
+                       sourceTree = "<group>";
+               };
+               5A442F99233C34C000918373 /* test */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5A442F9A233C34C000918373 /* SecExperimentTests.m */,
+                       );
+                       path = test;
+                       sourceTree = "<group>";
+               };
+               5A442F9D233C34C000918373 /* tool */ = {
+                       isa = PBXGroup;
+                       children = (
+                               5A442F9E233C34C000918373 /* experimentTool-Entitlements.plist */,
+                               5A442F9F233C34C000918373 /* experimentTool.m */,
+                       );
+                       path = tool;
+                       sourceTree = "<group>";
+               };
                5A47FFAF228F5DAB00F781B8 /* Protocol Buffers */ = {
                        isa = PBXGroup;
                        children = (
                DC0BC9D01D8B825900070CB0 /* ssl */ = {
                        isa = PBXGroup;
                        children = (
+                               1BE85ED4235CEC250051E1D8 /* sslDeprecated.h */,
                                DC1786FD1D778F5000B50D50 /* SecureTransportPriv.h */,
                                DC1786FB1D778F3C00B50D50 /* sslTypes.h */,
                                DC1785A31D778D0D00B50D50 /* CipherSuite.h */,
                                DCF158C52064895C00B87B6D /* OctagonAPSReceiverTests.h */,
                                DCE7F2081F21726500DDB0F7 /* OctagonAPSReceiverTests.m */,
                                DC9C95951F748D0B000D19E5 /* CKKSServerValidationRecoveryTests.m */,
+                               EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */,
                        );
                        name = "Tests (Local)";
                        path = tests;
                DC59E9AA1D91C9BE001BDDF5 /* Security.framework (Shared) */ = {
                        isa = PBXGroup;
                        children = (
-                               3DA3384121658755008C0CE1 /* SecExperiment */,
+                               5A442F97233C34C000918373 /* experiment */,
                                5AF593FD1FA0EE2C00A5C1EC /* Protocol */,
                                DCC78E4F1D8085FC00865A7C /* SecFramework.c */,
                                4723C9B51F152E8E0082882F /* Analytics */,
                                BED01530206F050F0027A2B4 /* README.txt */,
                                DCC78D911D8085F200865A7C /* SecureObjectSync */,
                                47C51B851EEA657D0032D9E5 /* SecurityUnitTests */,
-                               0CF0E2DD1F8EE37C00BD18E4 /* Signin Metrics */,
+                               0CF0E2DD1F8EE37C00BD18E4 /* SigninMetrics */,
                                DC0EF8F0208697C600AB9E95 /* tpctl */,
                                BECFA42F20F91AFE00B11002 /* tppolicy */,
                                47B3A90B21027D71001F4281 /* Trieste */,
                DC8834501D8A21AA00CE0ACA /* lib */ = {
                        isa = PBXGroup;
                        children = (
+                               1BE85ED1235CEBB30051E1D8 /* secport-tapi.h */,
                                DC88340A1D8A21AA00CE0ACA /* SecAsn1Coder.c */,
                                DC88340C1D8A21AA00CE0ACA /* SecAsn1Templates.c */,
                                DC88340F1D8A21AA00CE0ACA /* certExtensionTemplates.c */,
                                DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */,
                                6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */,
                                6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */,
+                               EB97364F234E8F4A00518B2B /* CKKSPBFileStorage.h */,
+                               EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */,
                                6CA2B9431E9F9F5700C43444 /* RateLimiter.h */,
                                6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */,
                                DC9C95B21F79CFD1000D19E5 /* CKKSControl.h */,
                DCC78D911D8085F200865A7C /* SecureObjectSync */ = {
                        isa = PBXGroup;
                        children = (
+                               EB0E1B902358FA4B002B6037 /* generated_source */,
                                CD1D64461DD386C9006D4139 /* AccountTrust */,
                                DCC78D2D1D8085F200865A7C /* Account */,
                                DCC78D4E1D8085F200865A7C /* Circle */,
                                48FE668F20E6E69B00FAEF17 /* SOSAuthKitHelpers.m */,
                                480C03D621459CD70034570E /* SOSTrustedDeviceAttributes.h */,
                                480C03D321459CD60034570E /* SOSTrustedDeviceAttributes.m */,
+                               EB0E1AC72352A81E002B6037 /* SOSAccountConfiguration.proto */,
                        );
                        name = SecureObjectSync;
                        path = keychain/SecureObjectSync;
                                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 */,
                        name = "dispatch Support";
                        sourceTree = "<group>";
                };
-               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 = "<group>";
-               };
                E060D19D2124780F0025B833 /* OctagonTestHarness */ = {
                        isa = PBXGroup;
                        children = (
                        isa = PBXGroup;
                        children = (
                                4C922CB2097F1984004CEEBD /* Security */,
+                               1B2BD391235E050D009A8624 /* SecEC-tapi.h */,
+                               1B2BD393235E050E009A8624 /* SecPolicy-tapi.h */,
+                               1B2BD394235E050E009A8624 /* Security-tapi.h */,
                        );
                        name = Headers;
                        sourceTree = "<group>";
                E7FCBE401314471B000DE34E /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               BEC6A9142331992800080069 /* Network.framework */,
+                               D47AB2CA2356AD72005A3801 /* Network.framework */,
                                0C6C2B6C2258295D00C53C96 /* UIKitCore.framework */,
                                0C6C2B682258211800C53C96 /* AppleAccount.framework */,
                                DC4A76A92212698B006F2D8F /* CloudServices.framework */,
                        name = secedumodetest;
                        sourceTree = "<group>";
                };
+               EB0E1B902358FA4B002B6037 /* generated_source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               EB0E1B922358FADE002B6037 /* SOSAccountConfiguration.h */,
+                               EB0E1B932358FADE002B6037 /* SOSAccountConfiguration.m */,
+                       );
+                       path = generated_source;
+                       sourceTree = "<group>";
+               };
                EB1055641E14DB370003C309 /* secfuzzer */ = {
                        isa = PBXGroup;
                        children = (
                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 */,
                                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 */,
                        path = tests/secdmockaks;
                        sourceTree = "<group>";
                };
+               EB627A74233E33A300F32437 /* generated_source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               EB627A78233E342B00F32437 /* MockAKSOptionalParameters.h */,
+                               EB627A77233E342B00F32437 /* MockAKSOptionalParameters.m */,
+                               EB627A76233E342900F32437 /* MockAKSRefKey.h */,
+                               EB627A75233E342800F32437 /* MockAKSRefKey.m */,
+                       );
+                       path = generated_source;
+                       sourceTree = "<group>";
+               };
                EB74CC182207E48000F1BBAD /* KeychainSettings */ = {
                        isa = PBXGroup;
                        children = (
                        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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                        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" */;
                        buildRules = (
                        );
                        dependencies = (
-                               EBBC11B32200D3BB00F95738 /* PBXTargetDependency */,
                                BED01526206EEC710027A2B4 /* PBXTargetDependency */,
                        );
                        name = TrustedPeersHelper;
                        buildRules = (
                        );
                        dependencies = (
-                               DCE0775C21ADD6A0002662FD /* PBXTargetDependency */,
                                D437C33121EBF8A000DD1E06 /* PBXTargetDependency */,
                        );
                        name = TrustedPeers;
                        buildRules = (
                        );
                        dependencies = (
-                               DC7479A022272361001E0E8C /* PBXTargetDependency */,
                        );
                        name = tpctl;
                        productName = tpctl;
                        buildRules = (
                        );
                        dependencies = (
-                               DCE0777E21ADEADA002662FD /* PBXTargetDependency */,
                        );
                        name = libsecurityd_ios;
                        productName = libsecurity;
                        buildRules = (
                        );
                        dependencies = (
-                               0C604F0221B8E5090036C175 /* PBXTargetDependency */,
                                DC65E7221D8CB27900152EF0 /* PBXTargetDependency */,
                        );
                        name = KeychainCircle;
                        productRefGroup = 4C35DC36094F9120002917C4 /* Products */;
                        projectDirPath = "";
                        projectReferences = (
-                               {
-                                       ProductGroup = E058E53321626583002CA574 /* Products */;
-                                       ProjectRef = E058E53221626582002CA574 /* OctagonTrieste.xcodeproj */;
-                               },
                                {
                                        ProductGroup = DC5AC0AE1D83533400CF422C /* Products */;
                                        ProjectRef = DC5AC0AD1D83533400CF422C /* securityd_service.xcodeproj */;
                                D4F47B3822270B6E003483E9 /* Security_all_watchos */,
                                D4F47B3C22270B89003483E9 /* Security_all_tvos */,
                                D4F47B4022270B97003483E9 /* Security_all_bridge */,
+                               DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */,
                                DC8E04991D7F6D9C006D80EB /* ====== Frameworks ======== */,
                                4C32C0AE0A4975F6002891BD /* Security_ios */,
                                DC1789031D77980500B50D50 /* Security_osx */,
                                BEAA002A202A832500E51F45 /* TrustedPeersHelper */,
                                DA41FE0D2241ADC000838FB3 /* otpaird */,
                                DC8E04B11D7F6EC9006D80EB /* ======= Libraries ========= */,
+                               DCDA5E4F2124B9C5009B11B2 /* aks_support */,
+                               DC36895D21235F42003A3735 /* aks_mock */,
+                               DC311E6E2124B8A8002F5EAE /* aks_real_witness */,
                                DCC78EA81D8088E200865A7C /* security */,
                                DC52E7731D80BC8000B0A59C /* libsecurityd_ios */,
                                4718AE2E205B39C40068EC3F /* libsecurityd_bridge */,
                                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 */,
                                DCD067561D8CDCF3007602F1 /* codesigning_DTrace */,
                                DCD0675B1D8CDD6D007602F1 /* codesigning_SystemPolicy */,
                                BECFA42D20F91AFE00B11002 /* tppolicy */,
-                               DCF216D621ADD5B10029CCC1 /* protobuf_source_generation */,
                                DC8E04AD1D7F6E76006D80EB /* ======= misc ========= */,
                                DC7FC44721EE914C003C39B8 /* FeatureFlagsPlist */,
                                E7B01BBD166594AB000485F1 /* SyncDevTest2 */,
                                E060D1B6212478110025B833 /* OctagonTestHarnessXPCService */,
                                EB7E90F12193F90700B1FA21 /* Build C2 Metrics */,
                                3D58392D21890FFB000ACA44 /* SecExperimentTests */,
+                               5A442F81233C330F00918373 /* experimentTool */,
                        );
                };
 /* End PBXProject section */
                        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 */
                        );
                        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;
                        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 */ = {
                        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;
                };
                        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 */,
                                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 */,
                                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 */,
                                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 */,
                                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 */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               5A442F82233C330F00918373 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               5A442FAE233C352200918373 /* experimentTool.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                5E10992119A5E55800A60E2B /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                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 */,
                                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 */,
                        );
                                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 */,
                                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;
                };
                                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 */,
                        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;
                };
                                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 */,
                                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 */,
                                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 */,
                        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 */,
                                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;
                };
                        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 */,
                                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 */,
                                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;
                };
                        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 */;
                        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 */;
                        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 */;
                        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 */;
                        };
                        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 = {
                        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 = (
index 7229163804ca4cf8486f4dadf94f2bfe73aae03e..09059a5058385ecfcfe208a985066e1a1c0b820e 100644 (file)
                ReferencedContainer = "container:Security.xcodeproj">
             </BuildableReference>
          </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "DC3502B41E0208BE00BC0587"
+               BuildableName = "CKKSTests.xctest"
+               BlueprintName = "CKKSTests"
+               ReferencedContainer = "container:Security.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction
index 1b88b964886e2e12d0042bfd8ccfe208f120bd59..24ee1bf8d9980628677f39695ae10ab44e5e59aa 100644 (file)
@@ -27,6 +27,7 @@
 #import "trusted_cert_ssl.h"
 #include <Foundation/Foundation.h>
 #include <CoreServices/CoreServices.h>
+#include <Network/Network.h>
 
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 
 #include <Security/SecKey.h>
 #include <Security/SecCertificate.h>
 #include <Security/SecTrust.h>
+#include <Security/SecProtocolOptions.h>
 
-#include <CFNetwork/CFNetwork.h>
 #include <SecurityFoundation/SFCertificateData.h>
 
-typedef CFTypeRef CFURLResponseRef;
-CFDictionaryRef _CFURLResponseGetSSLCertificateContext(CFURLResponseRef);
+#include <nw/private.h>
 
-@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 <NSURLDownloadDelegate>
-{
-    @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] : "<missing host>");
+            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;
 }
index 58618c7b1edb17ae00c086fdbcd38ba687de9ec9..65ffbbb0616ede3e4081eb190ac9e3c98c080254 100644 (file)
@@ -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);
index ee18108f4fa1a2bf17b3052d729326ca1124fae2..e52156b70b50712fd3ed1195be4ee7afc3197950 100644 (file)
@@ -177,16 +177,21 @@ command_sos_control(__unused int argc, __unused char * const * argv)
 
         bool assertStashAccountKey = false;
         bool triggerSync = false;
-        NSString *syncingPeer = NULL;
+        NSMutableArray<NSString *>* syncingPeers = NULL;
+        bool triggerBackup = false;
+        NSMutableArray<NSString*>* 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<NSString *> *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 (file)
index 0000000..551dd81
--- /dev/null
@@ -0,0 +1,18 @@
+{
+  "configurations" : [
+    {
+      "id" : "E61600EC-4F68-414B-932D-2A0655D233A4",
+      "name" : "Configuration 1",
+      "options" : {
+
+      }
+    }
+  ],
+  "defaultOptions" : {
+
+  },
+  "testTargets" : [
+
+  ],
+  "version" : 1
+}
index e4e5435d265c6501ffbea6bf7b071a89e02287cc..c5c4914c46d996be3d8beec4c7b3d5e18cb725c3 100644 (file)
@@ -85,6 +85,7 @@
 /* Code Signing */
 #include <Security/SecStaticCode.h>
 #include <Security/SecCode.h>
+#include <Security/SecCodeHost.h>
 #include <Security/SecRequirement.h>
 #include <Security/SecTask.h>
 
diff --git a/experiment/SecExperiment.m b/experiment/SecExperiment.m
new file mode 100644 (file)
index 0000000..c39ddaa
--- /dev/null
@@ -0,0 +1,590 @@
+//
+//  SecExperiment.m
+//  Security
+//
+
+#include <xpc/xpc.h>
+#include <os/log.h>
+#include <Security/SecTrustPriv.h>
+#include <uuid/uuid.h>
+
+#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<OS_OBJECT_CLASS(external_type)>                \
+_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 <Foundation/Foundation.h>
+#import <CoreFoundation/CFXPCBridge.h>
+#import <System/sys/codesign.h>
+#import <sys/errno.h>
+
+#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<NSString *> *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 (file)
index 0000000..e475dcd
--- /dev/null
@@ -0,0 +1,141 @@
+//
+//  SecExperimentInternal.h
+//  Security
+//
+
+#ifndef SecExperimentInternal_h
+#define SecExperimentInternal_h
+
+#include <Security/SecExperimentPriv.h>
+
+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 (file)
index 0000000..35f3b50
--- /dev/null
@@ -0,0 +1,204 @@
+//
+//  SecExperimentPriv.h
+//  Security
+//
+
+#ifndef SecExperiment_h
+#define SecExperiment_h
+
+#include <Security/SecProtocolObject.h>
+#include <xpc/xpc.h>
+
+#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 (file)
index 0000000..d53cd27
--- /dev/null
@@ -0,0 +1,358 @@
+//
+//  SecExperimentTests.m
+//
+//
+
+#import <XCTest/XCTest.h>
+#import <OCMock/OCMock.h>
+#import <CoreFoundation/CFXPCBridge.h>
+#import <nw/private.h>
+#import <Security/SecProtocolPriv.h>
+#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 (file)
index 0000000..0c67376
--- /dev/null
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict/>
+</plist>
diff --git a/experiment/tool/experimentTool.m b/experiment/tool/experimentTool.m
new file mode 100644 (file)
index 0000000..e08c385
--- /dev/null
@@ -0,0 +1,133 @@
+//
+//  experimentTool.m
+//  experimentTool
+//
+
+#import <Foundation/Foundation.h>
+#import <Security/SecExperimentPriv.h>
+#import <Security/SecTrustPriv.h>
+#import <CoreFoundation/CFXPCBridge.h>
+#import <xpc/xpc.h>
+
+static NSString *kExperimentRunResultKeySkips = @"Skips";
+static NSString *kExperimentRunResultKeyConfigurations = @"Configurations";
+static NSString *kExperimentRunResultKeyRuns = @"Runs";
+
+static NSDictionary<NSString *, NSObject *> *
+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<NSDictionary *> *configurations = [[NSMutableArray<NSDictionary *> 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 <experiment>] [-n <number of runs>]\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(&copy_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<NSString *, NSObject *> *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;
+}
index 9fed6f2f3fcb617f1f03da75d97aa6826c5e153c..a50be3eee2512ffeed7a41a09262ca17692da56f 100644 (file)
@@ -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
 //      
index 41035e2f3109d4db921660a83882ed651f1aa896..cd5951a2545f654c916d3861f1ad7025444e5582 100644 (file)
@@ -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"
 #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 <Security/SecItemInternal.h>
 #include <Security/SecEntitlements.h>
-#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 <utilities/SecCFWrappers.h>
 #include <utilities/SecCFError.h>
 #include <utilities/SecADWrapper.h>
+#include <utilities/SecFileLocations.h>
 
 #include <os/activity.h>
 #include <os/state_private.h>
@@ -67,6 +75,7 @@
 #include <utilities/der_plist_internal.h>
 #include <corecrypto/ccder.h>
 
+
 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<OctagonState*, NSNumber*>* SOSStateMap(void);
 
-        self.waitForInitialSync_blocks = [NSMutableDictionary dictionary];
-        
-        self.accountKeyIsTrusted = false;
-        self.accountKeyDerivationParamters = nil;
+@interface SOSAccount () <OctagonStateMachineEngine>
+@property dispatch_queue_t stateMachineQueue;
+@property (readwrite) OctagonStateMachine* stateMachine;
 
-        self.accountKey = NULL;
-        self.accountPrivateKey = NULL;
-        self.previousAccountKey = NULL;
-        
-        self.saveBlock = nil;
+@property (readwrite) CKKSPBFileStorage<SOSAccountConfiguration*>* 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 <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray <NSString *> *)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<NSString *>* _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<OctagonState*, NSNumber*>* SOSStateMap(void) {
+    static NSDictionary<OctagonState*, NSNumber*>* map = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        map = @{
+            SOSStateReady:                              @0U,
+            SOSStateError:                              @1U,
+            SOSStatePerformBackup:                      @2U,
+            SOSStatePerformRingUpdate:                  @3U,
+        };
+    });
+    return map;
+}
+
+static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
+    static NSSet<OctagonFlag*>* 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<NSString*>*)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<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueNextStateMachineTransition:(OctagonState*)currentState
+                                                                                                        flags:(nonnull OctagonFlags *)flags
+                                                                                                 pendingFlags:(nonnull id<OctagonStateOnqueuePendingFlagHandler>)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 (file)
index 0000000..bb26993
--- /dev/null
@@ -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;
+}
index 5b63e744296ff4a3370da4840f7b429bd1fbe1d3..eb4b7a0f076ec329d1d4b293f9c85d17a5b98d40 100644 (file)
@@ -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;
     }];
index fd6d2b1b5b826eb6e7b5390c46beefa4ca5dbf10..798d1fb17832ee9aa5c7023a9a386669548970f5 100644 (file)
@@ -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<NSString*>*)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);
 
index cd272013ac04f9a12504e5306d4ab610891d012a..39d749939239d09ff496beb2a9a5cd4f73316a53 100644 (file)
@@ -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)) {
index 1c014b29b2428662d3acfb5aecc156bd6e0d0c99..168d096d2f89625fb541b82dc62da012e9548474 100644 (file)
@@ -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];
index ef78b1980a319b45805d817111a44cd955f41efb..b6273573b5b44caf305c8d2a80cd51c901f22b3c 100644 (file)
@@ -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);
     }
index 9c0cad82bce4d5ffd64c75fd6184e09efaf03c71..f24e67135a20de79eea9a423530443e0385f63af 100644 (file)
@@ -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;
index cba4a3b60db61d284ad86f57121e71be281246ae..68d47e37568dede44dddaf17a18592ca6f64788d 100644 (file)
@@ -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));
     });
 }
 
index a8335cac40b6aacbe8f5286d45399b97a96a6833..aaf58c28cb1f1aeeeba48602d18787f379029aec 100644 (file)
@@ -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];
 }
index 6412bad32f36cf7855021f7a1216c2c45b1a10c8..5f8a748d97d8af95d444b10dcb277382669b7a9b 100644 (file)
         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);
     [self.account importInitialSyncCredentials:items complete:complete];
 }
 
-- (void)triggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray <NSString *> *)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
     [self.account ghostBustInfo:complete];
 }
 
+- (void)rpcTriggerBackup:(NSArray<NSString *>* _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
index 92b85f6c95173bab1cdbd7b005303c312b5745fb..12d928e29a72fed1c740b06d8d40e75944c7569d 100644 (file)
@@ -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);
index 495c561c5937ac139c9369330702d2784db470f1..25375bad4cafa986d03d85cecb48d5205d847659 100644 (file)
@@ -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<NSString *> *backupPeerList = @[ (__bridge NSString *)SOSPeerGetID(peer) ];
+        SOSCCRequestSyncWithBackupPeerList((__bridge CFArrayRef)backupPeerList);
     }
     return ok;
 }
index 5cee2f1e9c9abb08e8c5b84aff870ef4452ddf47..6a5ed6be29232f3b8e70dcda68081870c71866cf 100644 (file)
@@ -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;
index e1592ccc95dfcb9a0472f3e23420afca74e32191..bb0d62215e15b48fbc9d8ea8fc2cfb1a55b84a63 100644 (file)
@@ -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("<SOSRing@%p: '%@', Version %u, "), ring, SOSRingGetName(ring), SOSRingGetVersion(ring));
-    CFStringAppendFormat(description, formatOpts, CFSTR("UUID: %@, "), SOSRingGetIdentifier(ring));
+    CFStringAppendFormat(description, formatOpts, CFSTR("<SOSRing: '%@'"), SOSRingGetName(ring));
     SOSGenerationCountWithDescription(SOSRingGetGeneration(ring), ^(CFStringRef gcString) {
         CFStringAppendFormat(description, formatOpts, CFSTR("Gen: %@, "), gcString);
     });
-    CFStringAppendFormat(description, formatOpts, CFSTR("Mod: %@, "), SOSRingGetLastModifier(ring));
-    
-    CFStringAppendFormat(description, formatOpts, CFSTR("D: %ld "), payload ? CFDataGetLength(payload) : 0);
-
-    SOSBackupSliceKeyBagRef payloadAsBSKB = SOSRingCopyBackupSliceKeyBag(ring, NULL);
-
-    if (payloadAsBSKB) {
-        CFStringAppendFormat(description, formatOpts, CFSTR("%@ "), payloadAsBSKB);
-    }
-
-    CFReleaseSafe(payloadAsBSKB);
+    CFStringRef modifierID = CFStringCreateTruncatedCopy(SOSRingGetLastModifier(ring), 8);
+    CFStringAppendFormat(description, formatOpts, CFSTR("Mod: %@, "), modifierID);
+    CFReleaseNull(modifierID);
 
     CFStringAppendFormat(description, formatOpts, CFSTR("P: [%@], "), CFDictionaryGetValue(peers, CFSTR("MEMBER")));
     CFStringAppendFormat(description, formatOpts, CFSTR("A: [%@], "), CFDictionaryGetValue(peers, CFSTR("APPLICANTS")));
index ba6bc9f39bd7bef4fb7743472f60a8b85e941c86..a9e748aef107662c4eec7d15f373e589bd2d60d0 100644 (file)
@@ -124,10 +124,14 @@ typedef NS_OPTIONS(uint32_t, SOSAccountGhostBustingOptions) {
 - (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete;
 - (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete;
 
-- (void)triggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete;
+- (void)rpcTriggerSync:(NSArray <NSString *> *)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<NSString *>*)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 (file)
index 0000000..c381e08
--- /dev/null
@@ -0,0 +1,47 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from SOSAccountConfiguration.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#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 <NSCopying>
+{
+    NSMutableArray<NSString *> *_pendingBackupPeers;
+    BOOL _ringUpdateFlag;
+    struct {
+        int ringUpdateFlag:1;
+    } _has;
+}
+
+
+@property (nonatomic, retain) NSMutableArray<NSString *> *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 (file)
index 0000000..0314479
--- /dev/null
@@ -0,0 +1,206 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from SOSAccountConfiguration.proto
+
+#import "SOSAccountConfiguration.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#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/Signin Metrics/Resources/SFTMTests-Info.plist b/keychain/Signin Metrics/Resources/SFTMTests-Info.plist
deleted file mode 100644 (file)
index 6c40a6c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>$(DEVELOPMENT_LANGUAGE)</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIdentifier</key>
-       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
diff --git a/keychain/Signin Metrics/SFSignInAnalytics+Internal.h b/keychain/Signin Metrics/SFSignInAnalytics+Internal.h
deleted file mode 100644 (file)
index 9801140..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 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@
- */
-
-#if __OBJC2__
-#ifndef SFSignInAnalytics_Internal_h
-#define SFSignInAnalytics_Internal_h
-
-#import "SFSignInAnalytics.h"
-
-@interface SFSignInAnalytics (Internal)
-@property (readonly) NSString *signin_uuid;
-@property (readonly) NSString *my_uuid;
--(instancetype) initChildWithSignInUUID:(NSString*)signin_uuid andCategory:(NSString*)category andEventName:(NSString*)eventName;
-@end
-
-@interface SFSIALoggerObject : SFAnalytics
-+ (instancetype)logger;
-- (instancetype)init NS_UNAVAILABLE;
-@end
-
-#endif /* SFSignInAnalytics+Internal_h */
-#endif
diff --git a/keychain/Signin Metrics/SFSignInAnalytics.h b/keychain/Signin Metrics/SFSignInAnalytics.h
deleted file mode 100644 (file)
index 2863a4d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 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@
- */
-
-#if __OBJC2__
-#ifndef SignInAnalytics_h
-#define SignInAnalytics_h
-
-#import <Foundation/Foundation.h>
-#import <Security/SFAnalytics.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SFSignInAnalytics : NSObject <NSSecureCoding>
-
-@property (readonly) NSString* eventName;
-@property (readonly) NSString* category;
-@property (readonly) BOOL stopped;
-
-/*
- abstract: creates a new SignInAnalytics object, automatically starts a timer for this task.
- uuid: iCloud sign in transaction UUID
- category: name of client subsystem.  This will be used as the category name when logging
- eventName: name of the event we are measuring
- */
-- (instancetype _Nullable)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName;
-- (instancetype)init NS_UNAVAILABLE;
-
-/*
- abstract: creates a new SignInAnalytics that starts a timer for the subtask.
-           ideal for fine grained timing of sub events and automatically creates a dependency chain.
- eventNmae: name of the event being timed
- */
-- (SFSignInAnalytics* _Nullable)newSubTaskForEvent:(NSString*)eventName;
-
-/*
- abstract: call to log when a recoverable error occurs during sign in
- error: error that occured during iCloud Sign in
- */
-- (void)logRecoverableError:(NSError*)error;
-
-/*
- abstract: call to log when a unrecoverable error occurs during sign in
- error: error that occured during iCloud Sign in
- */
-- (void)logUnrecoverableError:(NSError*)error;
-
-/*
- abstract: call to cancel the timer object.
- */
-- (void)cancel;
-
-/*
- abstract: call to stop a timer and log the time spent.
- eventName: subsystem name
- attributes: a dictionary containing event attributes
- */
-- (void)stopWithAttributes:(NSDictionary<NSString*, id>* _Nullable)attributes;
-
-/*
- abstract: call to signal iCloud sign in has finished.
- */
-- (void)signInCompleted;
-
-@end
-NS_ASSUME_NONNULL_END
-#endif /* SignInAnalytics_h */
-#endif
diff --git a/keychain/Signin Metrics/SFSignInAnalytics.m b/keychain/Signin Metrics/SFSignInAnalytics.m
deleted file mode 100644 (file)
index 3b079c9..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (c) 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@
- */
-
-#if __OBJC2__
-
-#import "SFSignInAnalytics.h"
-#import "SFSignInAnalytics+Internal.h"
-
-#import <Analytics/SFAnalytics+Signin.h>
-#import "Analytics/SFAnalyticsDefines.h"
-#import "Analytics/SFAnalyticsSQLiteStore.h"
-#import "Analytics/SFAnalytics.h"
-
-#import <os/log_private.h>
-#import <mach/mach_time.h>
-#import <utilities/SecFileLocations.h>
-#import "utilities/debugging.h"
-#import <utilities/SecCFWrappers.h>
-
-//metrics database location
-NSString* signinMetricsDatabase = @"signin_metrics";
-
-//defaults write results location
-static NSString* const SFSignInAnalyticsDumpLoggedResultsToLocation = @"/tmp/signin_results.txt";
-static NSString* const SFSignInAnalyticsPersistedEventList = @"/tmp/signin_eventlist";
-
-//analytics constants
-static NSString* const SFSignInAnalyticsAttributeRecoverableError = @"recoverableError";
-static NSString* const SFSignInAnalyticsAttributeErrorDomain = @"errorDomain";
-static NSString* const SFSignInAnalyticsAttributeErrorCode = @"errorCode";
-static NSString* const SFSignInAnalyticsAttributeErrorChain = @"errorChain";
-static NSString* const SFSignInAnalyticsAttributeParentUUID = @"parentUUID";
-static NSString* const SFSignInAnalyticsAttributeMyUUID = @"myUUID";
-static NSString* const SFSignInAnalyticsAttributeSignInUUID = @"signinUUID";
-static NSString* const SFSignInAnalyticsAttributeEventName = @"eventName";
-static NSString* const SFSignInAnalyticsAttributeSubsystemName = @"subsystemName";
-static NSString* const SFSignInAnalyticsAttributeBuiltDependencyChains = @"dependencyChains";
-static NSString* const SFSignInAnalyticsAttributeTrackerTime = @"trackerTime";
-
-@implementation SFSIALoggerObject
-+ (NSString*)databasePath {
-    return [SFSIALoggerObject defaultAnalyticsDatabasePath:signinMetricsDatabase];
-}
-
-+ (instancetype)logger
-{
-    return [super logger];
-}
-@end
-
-
-@interface SFSignInAnalytics ()
-@property (nonatomic, copy) NSString *signin_uuid;
-@property (nonatomic, copy) NSString *my_uuid;
-@property (nonatomic, copy) NSString *parent_uuid;
-@property (nonatomic, copy) NSString *category;
-@property (nonatomic, copy) NSString *eventName;
-@property (nonatomic, copy) NSString *persistencePath;
-
-@property (nonatomic, strong) NSURL *persistedEventPlist;
-@property (nonatomic, strong) NSMutableDictionary *eventDependencyList;
-@property (nonatomic, strong) NSMutableArray *builtDependencyChains;
-
-@property (nonatomic) BOOL canceled;
-@property (nonatomic) BOOL stopped;
-
-@property (nonatomic, strong) os_log_t logObject;
-
-@property (nonatomic, strong) NSNumber *measurement;
-
-@property (nonatomic, strong) dispatch_queue_t queue;
-
-@property (nonatomic, strong) SFSignInAnalytics *root;
-@property (nonatomic, strong) SFAnalyticsActivityTracker *tracker;
-
--(os_log_t) newLogForCategoryName:(NSString*) category;
--(os_log_t) logForCategoryName:(NSString*) category;
-
-@end
-
-static NSMutableDictionary *logObjects;
-static const NSString* signInLogSpace = @"com.apple.security.wiiss";
-
-@implementation SFSignInAnalytics
-
-+ (BOOL)supportsSecureCoding {
-    return YES;
-}
-
--(os_log_t) logForCategoryName:(NSString*) category
-{
-    return logObjects[category];
-}
-
--(os_log_t) newLogForCategoryName:(NSString*) category
-{
-    return os_log_create([signInLogSpace UTF8String], [category UTF8String]);
-}
-
-- (BOOL)writeDependencyList:(NSError**)error
-{
-    NSError *localError = nil;
-    if (![NSPropertyListSerialization propertyList: self.root.eventDependencyList isValidForFormat: NSPropertyListXMLFormat_v1_0]){
-        os_log_error(self.logObject, "can't save PersistentState as XML");
-        return false;
-    }
-
-    NSData *data = [NSPropertyListSerialization dataWithPropertyList: self.root.eventDependencyList
-                                                              format: NSPropertyListXMLFormat_v1_0 options: 0 error: &localError];
-    if (data == nil){
-        os_log_error(self.logObject, "error serializing PersistentState to xml: %@", localError);
-        return false;
-    }
-
-    BOOL writeStatus = [data writeToURL:self.root.persistedEventPlist options: NSDataWritingAtomic error: &localError];
-    if (!writeStatus){
-        os_log_error(self.logObject, "error writing PersistentState to file: %@", localError);
-    }
-    if(localError && error){
-        *error = localError;
-    }
-
-    return writeStatus;
-}
-
-- (instancetype)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = uuid;
-
-        _my_uuid = uuid;
-        _parent_uuid = uuid;
-        _eventName = eventName;
-        _category = category;
-        _root = self;
-        _canceled = NO;
-        _stopped = NO;
-        _builtDependencyChains = [NSMutableArray array];
-
-        if ([self writeResultsToTmp]) {
-            //make plist file containing uuid parent/child
-            _persistencePath = [NSString stringWithFormat:@"%@-%@.plist", SFSignInAnalyticsPersistedEventList, eventName];
-            _persistedEventPlist = [NSURL fileURLWithPath:_persistencePath isDirectory:NO];
-        }
-
-        _eventDependencyList = [NSMutableDictionary dictionary];
-        [_eventDependencyList setObject:[NSMutableArray array] forKey:_signin_uuid];
-
-        _tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
-        [_tracker start];
-
-        NSError* error = nil;
-
-        if(self.root.persistedEventPlist && ![self writeDependencyList:&error] ){
-            os_log(self.logObject, "attempting to write dependency list: %@", error);
-        }
-
-        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-
-        static dispatch_once_t onceToken;
-        dispatch_once(&onceToken, ^{
-            logObjects = [NSMutableDictionary dictionary];
-        });
-        @synchronized(logObjects){
-            if(category){
-                _logObject = [self logForCategoryName:category];
-
-                if(!_logObject){
-                    _logObject = [self newLogForCategoryName:category];
-                    [logObjects setObject:_logObject forKey:category];
-                }
-            }
-        }
-    }
-    return self;
-}
-
--(instancetype) initChildWithSignInUUID:(NSString*)uuid andCategory:(NSString*)category andEventName:(NSString*)eventName
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = uuid;
-
-        _my_uuid = uuid;
-        _parent_uuid = uuid;
-        _eventName = eventName;
-        _category = category;
-        _canceled = NO;
-    }
-    return self;
-}
-
-- (void)encodeWithCoder:(NSCoder *)coder {
-    [coder encodeObject:_signin_uuid forKey:@"UUID"];
-    [coder encodeObject:_category forKey:@"category"];
-    [coder encodeObject:_parent_uuid forKey:@"parentUUID"];
-    [coder encodeObject:_my_uuid forKey:@"myUUID"];
-    [coder encodeObject:_measurement forKey:@"measurement"];
-    [coder encodeObject:_eventName forKey:@"eventName"];
-}
-
-- (nullable instancetype)initWithCoder:(NSCoder *)decoder
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"UUID"];
-        _category = [decoder decodeObjectOfClass:[NSString class] forKey:@"category"];
-        _parent_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"parentUUID"];
-        _my_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"myUUID"];
-        _measurement = [decoder decodeObjectOfClass:[NSString class] forKey:@"measurement"];
-        _eventName = [decoder decodeObjectOfClass:[NSString class] forKey:@"eventName"];
-        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-
-        if(_signin_uuid == nil ||
-           _category == nil ||
-           _parent_uuid == nil){
-            [decoder failWithError:[NSError errorWithDomain:@"securityd" code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Failed to decode SignInAnalytics object"}]];
-            return nil;
-        }
-    }
-    return self;
-}
-
-- (SFSignInAnalytics*)newSubTaskForEvent:(NSString*)eventName
-{
-    SFSignInAnalytics *newSubTask = [[SFSignInAnalytics alloc] initChildWithSignInUUID:self.signin_uuid andCategory:self.category andEventName:self.eventName];
-    if(newSubTask){
-        newSubTask.my_uuid = [NSUUID UUID].UUIDString;
-        newSubTask.parent_uuid = self.my_uuid;
-        newSubTask.signin_uuid = self.signin_uuid;
-
-        newSubTask.category = self.category;
-        newSubTask.eventName = [eventName copy];
-        newSubTask.root = self.root;
-        newSubTask.canceled = NO;
-        newSubTask.stopped = NO;
-
-        newSubTask.queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-        newSubTask.tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
-        [newSubTask.tracker start];
-
-        @synchronized(_eventDependencyList){
-            NSMutableArray *parentEntry = [newSubTask.root.eventDependencyList objectForKey:newSubTask.parent_uuid];
-            
-            //add new subtask entry to parent event's list
-            [parentEntry addObject:newSubTask.my_uuid];
-            [newSubTask.root.eventDependencyList setObject:parentEntry forKey:newSubTask.parent_uuid];
-            
-            //create new array list for this new subtask incase it has subtasks
-            [newSubTask.root.eventDependencyList setObject:[NSMutableArray array] forKey:newSubTask.my_uuid];
-            NSError* error = nil;
-            if(self.root.persistedEventPlist && ![newSubTask writeDependencyList:&error] ){
-                os_log(self.logObject, "attempting to write dependency list: %@", error);
-            }
-        }
-    }
-
-    return newSubTask;
-}
-
-- (void)logRecoverableError:(NSError*)error
-{
-
-    if (error == nil){
-        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
-        return;
-    }
-
-    os_log_error(self.logObject, "%@", error);
-
-    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
-
-    [eventAttributes setValuesForKeysWithDictionary:@{
-                                                      SFSignInAnalyticsAttributeRecoverableError : @(YES),
-                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
-                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
-                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
-                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
-                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
-                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
-                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
-                                                      }];
-
-    [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:eventAttributes];
-
-}
-
-- (void)logUnrecoverableError:(NSError*)error
-{
-    if (error == nil){
-        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
-        return;
-    }
-
-    os_log_error(self.logObject, "%@", error);
-
-    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
-
-    [eventAttributes setValuesForKeysWithDictionary:@{
-                                                      SFSignInAnalyticsAttributeRecoverableError : @(NO),
-                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
-                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
-                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
-                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
-                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
-                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
-                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
-                                                      }];
-
-    [[SFSIALoggerObject logger] logHardFailureForEventNamed:self.eventName withAttributes:eventAttributes];
-}
-
--(void)cancel
-{
-    dispatch_sync(self.queue, ^{
-        [self.tracker cancel];
-        self.canceled = YES;
-        os_log(self.logObject, "canceled timer for %@", self.eventName);
-    });
-}
-
-- (void)stopWithAttributes:(NSDictionary<NSString*, id>*)attributes
-{
-    dispatch_sync(self.queue, ^{
-
-        if(self.canceled || self.stopped){
-            return;
-        }
-
-        self.stopped = YES;
-
-        [self.tracker stop];
-
-        NSMutableDictionary *mutableAttributes = nil;
-
-        if(attributes){
-            mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
-        }
-        else{
-            mutableAttributes = [NSMutableDictionary dictionary];
-        }
-        mutableAttributes[SFSignInAnalyticsAttributeMyUUID] = self.my_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeParentUUID] = self.parent_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeSignInUUID] = self.signin_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeEventName] = self.eventName;
-        mutableAttributes[SFSignInAnalyticsAttributeSubsystemName] = self.category;
-        mutableAttributes[SFSignInAnalyticsAttributeTrackerTime] = self.tracker.measurement;
-
-        [mutableAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL * stop) {
-            os_log(self.logObject, "event: %@, %@  :  %@", self.eventName, key, obj);
-        }];
-        
-        [[SFSIALoggerObject logger] logSuccessForEventNamed:self.eventName];
-        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:mutableAttributes];
-    });
-}
-
--(BOOL) writeResultsToTmp {
-
-    bool shouldWriteResultsToTemp = NO;
-    CFBooleanRef toTmp = (CFBooleanRef)CFPreferencesCopyValue(CFSTR("DumpResultsToTemp"),
-                                                                CFSTR("com.apple.security"),
-                                                                kCFPreferencesAnyUser, kCFPreferencesAnyHost);
-    if(toTmp && CFGetTypeID(toTmp) == CFBooleanGetTypeID()){
-        if(toTmp == kCFBooleanFalse){
-            os_log(self.logObject, "writing results to splunk");
-            shouldWriteResultsToTemp = NO;
-        }
-        if(toTmp == kCFBooleanTrue){
-            os_log(self.logObject, "writing results to /tmp");
-            shouldWriteResultsToTemp = YES;
-        }
-    }
-
-    CFReleaseNull(toTmp);
-    return shouldWriteResultsToTemp;
-}
-
-- (void)processEventChainForUUID:(NSString*)uuid dependencyChain:(NSString*)dependencyChain
-{
-    NSString* newChain = dependencyChain;
-
-    NSArray* children = [self.root.eventDependencyList objectForKey:uuid];
-    for (NSString* child in children) {
-        newChain = [NSString stringWithFormat:@"%@, %@", dependencyChain, child];
-        [self processEventChainForUUID:child dependencyChain:newChain];
-    }
-    if([children count] == 0){
-        [self.root.builtDependencyChains addObject:newChain];
-        os_log(self.logObject, "current dependency chain list: %@", newChain);
-    }
-}
-
-- (void)signInCompleted
-{
-    //print final
-    os_log(self.logObject, "sign in complete");
-    NSError* error = nil;
-
-    //create dependency chains and log them
-    [self processEventChainForUUID:self.root.my_uuid dependencyChain:self.root.signin_uuid];
-    //write to database
-    if([self.root.builtDependencyChains count] > 0){
-        NSDictionary* eventAttributes =  @{SFSignInAnalyticsAttributeBuiltDependencyChains : self.root.builtDependencyChains};
-        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:SFSignInAnalyticsAttributeBuiltDependencyChains withAttributes:eventAttributes];
-    }
-
-    if([self writeResultsToTmp]){ //writing sign in analytics to /tmp
-        os_log(self.logObject, "logging to /tmp");
-
-        NSData* eventData = [NSKeyedArchiver archivedDataWithRootObject:[[SFSIALoggerObject logger].database allEvents] requiringSecureCoding:YES error:&error];
-        if(eventData){
-            [eventData writeToFile:SFSignInAnalyticsDumpLoggedResultsToLocation options:0 error:&error];
-
-            if(error){
-                os_log_error(self.logObject, "error writing to file [%@], error:%@", SFSignInAnalyticsDumpLoggedResultsToLocation, error);
-            }else{
-                os_log(self.logObject, "successfully wrote sign in analytics to:%@", SFSignInAnalyticsDumpLoggedResultsToLocation);
-            }
-        }else{
-            os_log_error(self.logObject, "collected no data");
-        }
-
-    }else{ //writing to splunk
-        os_log(self.logObject, "logging to splunk");
-    }
-
-    if (self.persistencePath) {
-        //remove dependency list
-        BOOL removedPersistedDependencyList = [[NSFileManager defaultManager] removeItemAtPath:self.persistencePath error:&error];
-        if(!removedPersistedDependencyList || error){
-            os_log(self.logObject, "encountered error when attempting to remove persisted event list: %@", error);
-        }
-    }
-}
-
-@end
-#endif
-
diff --git a/keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m b/keychain/Signin Metrics/tests/SFSignInAnalyticsTests.m
deleted file mode 100644 (file)
index 8cafd23..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright (c) 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@
- */
-
-#import <XCTest/XCTest.h>
-#import "keychain/Signin Metrics/SFSignInAnalytics.h"
-#import "keychain/Signin Metrics/SFSignInAnalytics+Internal.h"
-#import "keychain/ot/OTDefines.h"
-#import "SFAnalytics+Signin.h"
-#import <Security/SecureObjectSync/SOSCloudCircle.h>
-
-static NSInteger _testnum;
-static NSString* _path;
-
-@interface SFSignInAnalyticsTester : SFSignInAnalytics
--(instancetype)init;
-@end
-
-@implementation SFSignInAnalyticsTester
-
-+ (NSString*)databasePath {
-    return _path;
-}
-
--(instancetype)init
-{
-    self = [super initWithSignInUUID:[NSUUID UUID].UUIDString category:@"CoreCDP" eventName:@"signin"];
-
-    return self;
-}
-
-@end
-
-
-@interface SignInAnalyticsTests : XCTestCase
-@property (nonatomic) SFSignInAnalyticsTester *metric;
-@end
-
-@implementation SignInAnalyticsTests
-
-
-- (void)setUp {
-    [super setUp];
-    _testnum = 0;
-    self.continueAfterFailure = NO;
-    _path = [@"/tmp" stringByAppendingFormat:@"/test_%ld.db", (long)++_testnum];
-    _metric = [[SFSignInAnalyticsTester alloc] init];
-    XCTAssertNotNil(_metric, "SignInAnalyticsTester object should not be nil");
-}
-
-- (void)tearDown
-{
-    dispatch_async([SFSIALoggerObject logger].queue, ^{
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from all_events"];
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from soft_failures"];
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from hard_failures"];
-    });
-
-    [[SFSIALoggerObject logger] removeState];
-    _metric = nil;
-    [super tearDown];
-}
-
-- (void)testStop
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"restore",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-    
-    [_metric stopWithAttributes:attributes];
-
-    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([results count], 2, @"should have 2 results");
-    
-}
-
-- (void)testCancel
-{
-    [_metric cancel];
-}
-
-- (void)testLogError
-{
-    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
-    [_metric logRecoverableError:error];
-    NSArray* results = [[SFSIALoggerObject logger].database softFailures];
-    XCTAssertEqual([results count], 1, @"should have 1 results");
-}
-
-- (void)testCreateNewSubtask
-{
-    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
-    XCTAssertNotNil(child, "child should be created");
-    [[SFSIALoggerObject logger] removeState];
-    child = nil;
-}
-
-
-- (void)testCreateNewSubtaskAndStop
-{
-    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
-
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-
-    [child stopWithAttributes:attributes];
-    
-    XCTAssertNotNil(child, "child should be created");
-
-    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([results count], 2, @"should have 2 results");
-
-    [[SFSIALoggerObject logger] removeState];
-    child = nil;
-}
-
-- (void)testStopAfterCancel
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-
-    [_metric cancel];
-
-    [_metric stopWithAttributes:attributes];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([allEvents count], 0, @"should have 0 things logged");
-}
-
-- (void)testStopAfterStop
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-
-    [_metric stopWithAttributes:attributes];
-
-    [_metric stopWithAttributes:attributes];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([allEvents count], 2, @"should have 2 things logged");
-}
-
--(void)testSignInComplete
-{
-    NSDictionary* attributes = [NSDictionary dictionary];
-    [_metric stopWithAttributes:attributes];
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array should not be nil");
-    XCTAssertTrue(allEvents && [allEvents count] > 0, "array should not be nil and contain an entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    XCTAssertTrue(dependencyEntry && [dependencyEntry count] > 0, "dictionary should not be nil and contain an entry");
-
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 1, "should be one list");
-
-    XCTAssertTrue([chains containsObject:_metric.signin_uuid], "should contain 1 uuid");
-}
-
--(void)testSingleChainDependencyList
-{
-    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
-    XCTAssertNotNil(child1, "child1 should be created");
-
-    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
-    XCTAssertNotNil(child2, "child2 should be created");
-
-    SFSignInAnalytics* child3 = [child2 newSubTaskForEvent:@"backup"];
-    XCTAssertNotNil(child3, "child3 should be created");
-
-    SFSignInAnalytics* child4 = [child3 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child4, "child4 should be created");
-
-    [_metric signInCompleted];
-
-    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", child1.signin_uuid, child1.my_uuid, child2.my_uuid, child3.my_uuid, child4.my_uuid];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "should not be nil");
-    XCTAssertTrue([allEvents count] > 0, "should be events");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 1, "should be one list");
-    XCTAssertTrue([expectedChain isEqualToString:[chains objectAtIndex:0]], "chains should be the same");
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-}
-
--(void)testMultipleChildrenPerEvent
-{
-    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
-    XCTAssertNotNil(child1, "child1 should be created");
-
-    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
-    XCTAssertNotNil(child2, "child2 should be created");
-
-    SFSignInAnalytics* child3 = [child1 newSubTaskForEvent:@"backup"];
-    XCTAssertNotNil(child3, "child3 should be created");
-
-    SFSignInAnalytics* child4 = [child1 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child4, "child4 should be created");
-
-    SFSignInAnalytics* child5 = [child2 newSubTaskForEvent:@"processing second ring"];
-    XCTAssertNotNil(child5, "child5 should be created");
-
-    SFSignInAnalytics* child6 = [child2 newSubTaskForEvent:@"processing third ring"];
-    XCTAssertNotNil(child6, "child6 should be created");
-
-    SFSignInAnalytics* child7 = [child2 newSubTaskForEvent:@"processing fourth ring"];
-    XCTAssertNotNil(child7, "child7 should be created");
-
-    SFSignInAnalytics* child8 = [child7 newSubTaskForEvent:@"processing fifth ring"];
-    XCTAssertNotNil(child8, "child8 should be created");
-
-    SFSignInAnalytics* child9 = [child7 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child9, "child9 should be created");
-
-    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
-
-    NSString *expectedChain1 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child3.my_uuid];
-
-    NSString *expectedChain2 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child4.my_uuid];
-
-    NSString *expectedChain3 = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
-
-    NSString *expectedChain4 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child8.my_uuid];
-
-    NSString *expectedChain5 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child9.my_uuid];
-
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertTrue([allEvents count] > 0, "array should not be empty");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 6, "should be one list");
-
-    XCTAssertTrue([chains containsObject:expectedChain], "chains should contain expectedChain");
-    XCTAssertTrue([chains containsObject:expectedChain1], "chains should contain expectedChain1");
-    XCTAssertTrue([chains containsObject:expectedChain2], "chains should contain expectedChain2");
-    XCTAssertTrue([chains containsObject:expectedChain3], "chains should contain expectedChain3");
-    XCTAssertTrue([chains containsObject:expectedChain4], "chains should contain expectedChain4");
-    XCTAssertTrue([chains containsObject:expectedChain5], "chains should contain expectedChain5");
-
-    [[SFSIALoggerObject logger] removeState];
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-    child5 = nil;
-    child6 = nil;
-    child7 = nil;
-    child8 = nil;
-    child9 = nil;
-
-}
-
--(void)testSOSCCWaitForInitialSync
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    bool worked = SOSCCWaitForInitialSyncWithAnalytics(parentData, &error);
-    XCTAssertTrue(worked, "should have worked");
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRemoveThisDeviceFromCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    bool worked = SOSCCRemoveThisDeviceFromCircleWithAnalytics(parentData, &error);
-    XCTAssertTrue(worked, "should have worked");
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRequestToJoinCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCRequestToJoinCircleWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRequestToJoinCircleAfterRestore
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCRequestToJoinCircleAfterRestoreWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRemovePeersFromCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    NSArray* peers = [NSArray array];
-    SOSCCRemovePeersFromCircleWithAnalytics((__bridge CFArrayRef)peers, parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
-
--(void)testSOSCCViewSet
-{
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    CFSetRef enabledViews = nil;
-    CFSetRef disabledViews = nil;
-    SOSCCViewSetWithAnalytics(enabledViews, disabledViews, parentData);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCSetUserCredentialsAndDSID
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    CFStringRef label = nil;
-    CFDataRef password = nil;
-    CFStringRef dsid = nil;
-    SOSCCSetUserCredentialsAndDSIDWithAnalytics(label, password, dsid, parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCResetToEmpty
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCResetToEmptyWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
-- (void)testMultipleDBConnections
-{
-    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
-    dispatch_queue_t test_queue = dispatch_queue_create("com.apple.security.signin.tests", DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL);
-
-    for(int i = 0; i < 1000; i++){
-        SFSignInAnalytics *test1 = [_metric newSubTaskForEvent:@"connection1"];
-        SFSignInAnalytics *test2 = [_metric newSubTaskForEvent:@"connection2"];
-
-        dispatch_async(test_queue, ^{
-            [test1 logRecoverableError:error];
-        });
-        dispatch_async(test_queue, ^{
-            [test2 stopWithAttributes:nil];
-        });
-        dispatch_async(test_queue, ^{
-            [self->_metric logRecoverableError:error];
-        });
-    }
-}
-@end
diff --git a/keychain/SigninMetrics/OctagonSignPosts.h b/keychain/SigninMetrics/OctagonSignPosts.h
new file mode 100644 (file)
index 0000000..34c07c6
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+#import <os/activity.h>
+#import <os/log.h>
+#import <os/signpost.h>
+#import <os/signpost_private.h>
+
+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 (file)
index 0000000..5466a38
--- /dev/null
@@ -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 <Foundation/Foundation.h>
+#import <mach/mach_time.h>
+
+#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/SigninMetrics/Resources/SFTMTests-Info.plist b/keychain/SigninMetrics/Resources/SFTMTests-Info.plist
new file mode 100644 (file)
index 0000000..6c40a6c
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+</dict>
+</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 (file)
index 0000000..8b1c81d
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>DEFAULT-OPTIONS</key>
+       <dict>
+               <key>Propagate-with-Activity</key>
+               <true/>
+               <key>TTL</key>
+               <dict>
+                       <key>Default</key>
+                       <integer>7</integer>
+                       <key>Info</key>
+                       <integer>7</integer>
+                       <key>Debug</key>
+                       <integer>0</integer>
+               </dict>
+               <key>Level</key>
+               <dict>
+                       <key>Enable</key>
+                       <string>Default</string>
+                       <key>Persist</key>
+                       <string>Default</string>
+               </dict>
+       </dict>
+</dict>
+</plist>
diff --git a/keychain/SigninMetrics/SFSignInAnalytics+Internal.h b/keychain/SigninMetrics/SFSignInAnalytics+Internal.h
new file mode 100644 (file)
index 0000000..9801140
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 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@
+ */
+
+#if __OBJC2__
+#ifndef SFSignInAnalytics_Internal_h
+#define SFSignInAnalytics_Internal_h
+
+#import "SFSignInAnalytics.h"
+
+@interface SFSignInAnalytics (Internal)
+@property (readonly) NSString *signin_uuid;
+@property (readonly) NSString *my_uuid;
+-(instancetype) initChildWithSignInUUID:(NSString*)signin_uuid andCategory:(NSString*)category andEventName:(NSString*)eventName;
+@end
+
+@interface SFSIALoggerObject : SFAnalytics
++ (instancetype)logger;
+- (instancetype)init NS_UNAVAILABLE;
+@end
+
+#endif /* SFSignInAnalytics+Internal_h */
+#endif
diff --git a/keychain/SigninMetrics/SFSignInAnalytics.h b/keychain/SigninMetrics/SFSignInAnalytics.h
new file mode 100644 (file)
index 0000000..2863a4d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 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@
+ */
+
+#if __OBJC2__
+#ifndef SignInAnalytics_h
+#define SignInAnalytics_h
+
+#import <Foundation/Foundation.h>
+#import <Security/SFAnalytics.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface SFSignInAnalytics : NSObject <NSSecureCoding>
+
+@property (readonly) NSString* eventName;
+@property (readonly) NSString* category;
+@property (readonly) BOOL stopped;
+
+/*
+ abstract: creates a new SignInAnalytics object, automatically starts a timer for this task.
+ uuid: iCloud sign in transaction UUID
+ category: name of client subsystem.  This will be used as the category name when logging
+ eventName: name of the event we are measuring
+ */
+- (instancetype _Nullable)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName;
+- (instancetype)init NS_UNAVAILABLE;
+
+/*
+ abstract: creates a new SignInAnalytics that starts a timer for the subtask.
+           ideal for fine grained timing of sub events and automatically creates a dependency chain.
+ eventNmae: name of the event being timed
+ */
+- (SFSignInAnalytics* _Nullable)newSubTaskForEvent:(NSString*)eventName;
+
+/*
+ abstract: call to log when a recoverable error occurs during sign in
+ error: error that occured during iCloud Sign in
+ */
+- (void)logRecoverableError:(NSError*)error;
+
+/*
+ abstract: call to log when a unrecoverable error occurs during sign in
+ error: error that occured during iCloud Sign in
+ */
+- (void)logUnrecoverableError:(NSError*)error;
+
+/*
+ abstract: call to cancel the timer object.
+ */
+- (void)cancel;
+
+/*
+ abstract: call to stop a timer and log the time spent.
+ eventName: subsystem name
+ attributes: a dictionary containing event attributes
+ */
+- (void)stopWithAttributes:(NSDictionary<NSString*, id>* _Nullable)attributes;
+
+/*
+ abstract: call to signal iCloud sign in has finished.
+ */
+- (void)signInCompleted;
+
+@end
+NS_ASSUME_NONNULL_END
+#endif /* SignInAnalytics_h */
+#endif
diff --git a/keychain/SigninMetrics/SFSignInAnalytics.m b/keychain/SigninMetrics/SFSignInAnalytics.m
new file mode 100644 (file)
index 0000000..3b079c9
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 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@
+ */
+
+#if __OBJC2__
+
+#import "SFSignInAnalytics.h"
+#import "SFSignInAnalytics+Internal.h"
+
+#import <Analytics/SFAnalytics+Signin.h>
+#import "Analytics/SFAnalyticsDefines.h"
+#import "Analytics/SFAnalyticsSQLiteStore.h"
+#import "Analytics/SFAnalytics.h"
+
+#import <os/log_private.h>
+#import <mach/mach_time.h>
+#import <utilities/SecFileLocations.h>
+#import "utilities/debugging.h"
+#import <utilities/SecCFWrappers.h>
+
+//metrics database location
+NSString* signinMetricsDatabase = @"signin_metrics";
+
+//defaults write results location
+static NSString* const SFSignInAnalyticsDumpLoggedResultsToLocation = @"/tmp/signin_results.txt";
+static NSString* const SFSignInAnalyticsPersistedEventList = @"/tmp/signin_eventlist";
+
+//analytics constants
+static NSString* const SFSignInAnalyticsAttributeRecoverableError = @"recoverableError";
+static NSString* const SFSignInAnalyticsAttributeErrorDomain = @"errorDomain";
+static NSString* const SFSignInAnalyticsAttributeErrorCode = @"errorCode";
+static NSString* const SFSignInAnalyticsAttributeErrorChain = @"errorChain";
+static NSString* const SFSignInAnalyticsAttributeParentUUID = @"parentUUID";
+static NSString* const SFSignInAnalyticsAttributeMyUUID = @"myUUID";
+static NSString* const SFSignInAnalyticsAttributeSignInUUID = @"signinUUID";
+static NSString* const SFSignInAnalyticsAttributeEventName = @"eventName";
+static NSString* const SFSignInAnalyticsAttributeSubsystemName = @"subsystemName";
+static NSString* const SFSignInAnalyticsAttributeBuiltDependencyChains = @"dependencyChains";
+static NSString* const SFSignInAnalyticsAttributeTrackerTime = @"trackerTime";
+
+@implementation SFSIALoggerObject
++ (NSString*)databasePath {
+    return [SFSIALoggerObject defaultAnalyticsDatabasePath:signinMetricsDatabase];
+}
+
++ (instancetype)logger
+{
+    return [super logger];
+}
+@end
+
+
+@interface SFSignInAnalytics ()
+@property (nonatomic, copy) NSString *signin_uuid;
+@property (nonatomic, copy) NSString *my_uuid;
+@property (nonatomic, copy) NSString *parent_uuid;
+@property (nonatomic, copy) NSString *category;
+@property (nonatomic, copy) NSString *eventName;
+@property (nonatomic, copy) NSString *persistencePath;
+
+@property (nonatomic, strong) NSURL *persistedEventPlist;
+@property (nonatomic, strong) NSMutableDictionary *eventDependencyList;
+@property (nonatomic, strong) NSMutableArray *builtDependencyChains;
+
+@property (nonatomic) BOOL canceled;
+@property (nonatomic) BOOL stopped;
+
+@property (nonatomic, strong) os_log_t logObject;
+
+@property (nonatomic, strong) NSNumber *measurement;
+
+@property (nonatomic, strong) dispatch_queue_t queue;
+
+@property (nonatomic, strong) SFSignInAnalytics *root;
+@property (nonatomic, strong) SFAnalyticsActivityTracker *tracker;
+
+-(os_log_t) newLogForCategoryName:(NSString*) category;
+-(os_log_t) logForCategoryName:(NSString*) category;
+
+@end
+
+static NSMutableDictionary *logObjects;
+static const NSString* signInLogSpace = @"com.apple.security.wiiss";
+
+@implementation SFSignInAnalytics
+
++ (BOOL)supportsSecureCoding {
+    return YES;
+}
+
+-(os_log_t) logForCategoryName:(NSString*) category
+{
+    return logObjects[category];
+}
+
+-(os_log_t) newLogForCategoryName:(NSString*) category
+{
+    return os_log_create([signInLogSpace UTF8String], [category UTF8String]);
+}
+
+- (BOOL)writeDependencyList:(NSError**)error
+{
+    NSError *localError = nil;
+    if (![NSPropertyListSerialization propertyList: self.root.eventDependencyList isValidForFormat: NSPropertyListXMLFormat_v1_0]){
+        os_log_error(self.logObject, "can't save PersistentState as XML");
+        return false;
+    }
+
+    NSData *data = [NSPropertyListSerialization dataWithPropertyList: self.root.eventDependencyList
+                                                              format: NSPropertyListXMLFormat_v1_0 options: 0 error: &localError];
+    if (data == nil){
+        os_log_error(self.logObject, "error serializing PersistentState to xml: %@", localError);
+        return false;
+    }
+
+    BOOL writeStatus = [data writeToURL:self.root.persistedEventPlist options: NSDataWritingAtomic error: &localError];
+    if (!writeStatus){
+        os_log_error(self.logObject, "error writing PersistentState to file: %@", localError);
+    }
+    if(localError && error){
+        *error = localError;
+    }
+
+    return writeStatus;
+}
+
+- (instancetype)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName
+{
+    self = [super init];
+    if (self) {
+        _signin_uuid = uuid;
+
+        _my_uuid = uuid;
+        _parent_uuid = uuid;
+        _eventName = eventName;
+        _category = category;
+        _root = self;
+        _canceled = NO;
+        _stopped = NO;
+        _builtDependencyChains = [NSMutableArray array];
+
+        if ([self writeResultsToTmp]) {
+            //make plist file containing uuid parent/child
+            _persistencePath = [NSString stringWithFormat:@"%@-%@.plist", SFSignInAnalyticsPersistedEventList, eventName];
+            _persistedEventPlist = [NSURL fileURLWithPath:_persistencePath isDirectory:NO];
+        }
+
+        _eventDependencyList = [NSMutableDictionary dictionary];
+        [_eventDependencyList setObject:[NSMutableArray array] forKey:_signin_uuid];
+
+        _tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
+        [_tracker start];
+
+        NSError* error = nil;
+
+        if(self.root.persistedEventPlist && ![self writeDependencyList:&error] ){
+            os_log(self.logObject, "attempting to write dependency list: %@", error);
+        }
+
+        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+
+        static dispatch_once_t onceToken;
+        dispatch_once(&onceToken, ^{
+            logObjects = [NSMutableDictionary dictionary];
+        });
+        @synchronized(logObjects){
+            if(category){
+                _logObject = [self logForCategoryName:category];
+
+                if(!_logObject){
+                    _logObject = [self newLogForCategoryName:category];
+                    [logObjects setObject:_logObject forKey:category];
+                }
+            }
+        }
+    }
+    return self;
+}
+
+-(instancetype) initChildWithSignInUUID:(NSString*)uuid andCategory:(NSString*)category andEventName:(NSString*)eventName
+{
+    self = [super init];
+    if (self) {
+        _signin_uuid = uuid;
+
+        _my_uuid = uuid;
+        _parent_uuid = uuid;
+        _eventName = eventName;
+        _category = category;
+        _canceled = NO;
+    }
+    return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder {
+    [coder encodeObject:_signin_uuid forKey:@"UUID"];
+    [coder encodeObject:_category forKey:@"category"];
+    [coder encodeObject:_parent_uuid forKey:@"parentUUID"];
+    [coder encodeObject:_my_uuid forKey:@"myUUID"];
+    [coder encodeObject:_measurement forKey:@"measurement"];
+    [coder encodeObject:_eventName forKey:@"eventName"];
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)decoder
+{
+    self = [super init];
+    if (self) {
+        _signin_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"UUID"];
+        _category = [decoder decodeObjectOfClass:[NSString class] forKey:@"category"];
+        _parent_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"parentUUID"];
+        _my_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"myUUID"];
+        _measurement = [decoder decodeObjectOfClass:[NSString class] forKey:@"measurement"];
+        _eventName = [decoder decodeObjectOfClass:[NSString class] forKey:@"eventName"];
+        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+
+        if(_signin_uuid == nil ||
+           _category == nil ||
+           _parent_uuid == nil){
+            [decoder failWithError:[NSError errorWithDomain:@"securityd" code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Failed to decode SignInAnalytics object"}]];
+            return nil;
+        }
+    }
+    return self;
+}
+
+- (SFSignInAnalytics*)newSubTaskForEvent:(NSString*)eventName
+{
+    SFSignInAnalytics *newSubTask = [[SFSignInAnalytics alloc] initChildWithSignInUUID:self.signin_uuid andCategory:self.category andEventName:self.eventName];
+    if(newSubTask){
+        newSubTask.my_uuid = [NSUUID UUID].UUIDString;
+        newSubTask.parent_uuid = self.my_uuid;
+        newSubTask.signin_uuid = self.signin_uuid;
+
+        newSubTask.category = self.category;
+        newSubTask.eventName = [eventName copy];
+        newSubTask.root = self.root;
+        newSubTask.canceled = NO;
+        newSubTask.stopped = NO;
+
+        newSubTask.queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+        newSubTask.tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
+        [newSubTask.tracker start];
+
+        @synchronized(_eventDependencyList){
+            NSMutableArray *parentEntry = [newSubTask.root.eventDependencyList objectForKey:newSubTask.parent_uuid];
+            
+            //add new subtask entry to parent event's list
+            [parentEntry addObject:newSubTask.my_uuid];
+            [newSubTask.root.eventDependencyList setObject:parentEntry forKey:newSubTask.parent_uuid];
+            
+            //create new array list for this new subtask incase it has subtasks
+            [newSubTask.root.eventDependencyList setObject:[NSMutableArray array] forKey:newSubTask.my_uuid];
+            NSError* error = nil;
+            if(self.root.persistedEventPlist && ![newSubTask writeDependencyList:&error] ){
+                os_log(self.logObject, "attempting to write dependency list: %@", error);
+            }
+        }
+    }
+
+    return newSubTask;
+}
+
+- (void)logRecoverableError:(NSError*)error
+{
+
+    if (error == nil){
+        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
+        return;
+    }
+
+    os_log_error(self.logObject, "%@", error);
+
+    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
+
+    [eventAttributes setValuesForKeysWithDictionary:@{
+                                                      SFSignInAnalyticsAttributeRecoverableError : @(YES),
+                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
+                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
+                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
+                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
+                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
+                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
+                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
+                                                      }];
+
+    [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:eventAttributes];
+
+}
+
+- (void)logUnrecoverableError:(NSError*)error
+{
+    if (error == nil){
+        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
+        return;
+    }
+
+    os_log_error(self.logObject, "%@", error);
+
+    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
+
+    [eventAttributes setValuesForKeysWithDictionary:@{
+                                                      SFSignInAnalyticsAttributeRecoverableError : @(NO),
+                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
+                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
+                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
+                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
+                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
+                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
+                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
+                                                      }];
+
+    [[SFSIALoggerObject logger] logHardFailureForEventNamed:self.eventName withAttributes:eventAttributes];
+}
+
+-(void)cancel
+{
+    dispatch_sync(self.queue, ^{
+        [self.tracker cancel];
+        self.canceled = YES;
+        os_log(self.logObject, "canceled timer for %@", self.eventName);
+    });
+}
+
+- (void)stopWithAttributes:(NSDictionary<NSString*, id>*)attributes
+{
+    dispatch_sync(self.queue, ^{
+
+        if(self.canceled || self.stopped){
+            return;
+        }
+
+        self.stopped = YES;
+
+        [self.tracker stop];
+
+        NSMutableDictionary *mutableAttributes = nil;
+
+        if(attributes){
+            mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
+        }
+        else{
+            mutableAttributes = [NSMutableDictionary dictionary];
+        }
+        mutableAttributes[SFSignInAnalyticsAttributeMyUUID] = self.my_uuid;
+        mutableAttributes[SFSignInAnalyticsAttributeParentUUID] = self.parent_uuid;
+        mutableAttributes[SFSignInAnalyticsAttributeSignInUUID] = self.signin_uuid;
+        mutableAttributes[SFSignInAnalyticsAttributeEventName] = self.eventName;
+        mutableAttributes[SFSignInAnalyticsAttributeSubsystemName] = self.category;
+        mutableAttributes[SFSignInAnalyticsAttributeTrackerTime] = self.tracker.measurement;
+
+        [mutableAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL * stop) {
+            os_log(self.logObject, "event: %@, %@  :  %@", self.eventName, key, obj);
+        }];
+        
+        [[SFSIALoggerObject logger] logSuccessForEventNamed:self.eventName];
+        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:mutableAttributes];
+    });
+}
+
+-(BOOL) writeResultsToTmp {
+
+    bool shouldWriteResultsToTemp = NO;
+    CFBooleanRef toTmp = (CFBooleanRef)CFPreferencesCopyValue(CFSTR("DumpResultsToTemp"),
+                                                                CFSTR("com.apple.security"),
+                                                                kCFPreferencesAnyUser, kCFPreferencesAnyHost);
+    if(toTmp && CFGetTypeID(toTmp) == CFBooleanGetTypeID()){
+        if(toTmp == kCFBooleanFalse){
+            os_log(self.logObject, "writing results to splunk");
+            shouldWriteResultsToTemp = NO;
+        }
+        if(toTmp == kCFBooleanTrue){
+            os_log(self.logObject, "writing results to /tmp");
+            shouldWriteResultsToTemp = YES;
+        }
+    }
+
+    CFReleaseNull(toTmp);
+    return shouldWriteResultsToTemp;
+}
+
+- (void)processEventChainForUUID:(NSString*)uuid dependencyChain:(NSString*)dependencyChain
+{
+    NSString* newChain = dependencyChain;
+
+    NSArray* children = [self.root.eventDependencyList objectForKey:uuid];
+    for (NSString* child in children) {
+        newChain = [NSString stringWithFormat:@"%@, %@", dependencyChain, child];
+        [self processEventChainForUUID:child dependencyChain:newChain];
+    }
+    if([children count] == 0){
+        [self.root.builtDependencyChains addObject:newChain];
+        os_log(self.logObject, "current dependency chain list: %@", newChain);
+    }
+}
+
+- (void)signInCompleted
+{
+    //print final
+    os_log(self.logObject, "sign in complete");
+    NSError* error = nil;
+
+    //create dependency chains and log them
+    [self processEventChainForUUID:self.root.my_uuid dependencyChain:self.root.signin_uuid];
+    //write to database
+    if([self.root.builtDependencyChains count] > 0){
+        NSDictionary* eventAttributes =  @{SFSignInAnalyticsAttributeBuiltDependencyChains : self.root.builtDependencyChains};
+        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:SFSignInAnalyticsAttributeBuiltDependencyChains withAttributes:eventAttributes];
+    }
+
+    if([self writeResultsToTmp]){ //writing sign in analytics to /tmp
+        os_log(self.logObject, "logging to /tmp");
+
+        NSData* eventData = [NSKeyedArchiver archivedDataWithRootObject:[[SFSIALoggerObject logger].database allEvents] requiringSecureCoding:YES error:&error];
+        if(eventData){
+            [eventData writeToFile:SFSignInAnalyticsDumpLoggedResultsToLocation options:0 error:&error];
+
+            if(error){
+                os_log_error(self.logObject, "error writing to file [%@], error:%@", SFSignInAnalyticsDumpLoggedResultsToLocation, error);
+            }else{
+                os_log(self.logObject, "successfully wrote sign in analytics to:%@", SFSignInAnalyticsDumpLoggedResultsToLocation);
+            }
+        }else{
+            os_log_error(self.logObject, "collected no data");
+        }
+
+    }else{ //writing to splunk
+        os_log(self.logObject, "logging to splunk");
+    }
+
+    if (self.persistencePath) {
+        //remove dependency list
+        BOOL removedPersistedDependencyList = [[NSFileManager defaultManager] removeItemAtPath:self.persistencePath error:&error];
+        if(!removedPersistedDependencyList || error){
+            os_log(self.logObject, "encountered error when attempting to remove persisted event list: %@", error);
+        }
+    }
+}
+
+@end
+#endif
+
diff --git a/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m b/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m
new file mode 100644 (file)
index 0000000..b52d9b4
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 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@
+ */
+
+#import <XCTest/XCTest.h>
+#import "keychain/SigninMetrics/SFSignInAnalytics.h"
+#import "keychain/SigninMetrics/SFSignInAnalytics+Internal.h"
+#import "keychain/ot/OTDefines.h"
+#import "SFAnalytics+Signin.h"
+#import <Security/SecureObjectSync/SOSCloudCircle.h>
+
+static NSInteger _testnum;
+static NSString* _path;
+
+@interface SFSignInAnalyticsTester : SFSignInAnalytics
+-(instancetype)init;
+@end
+
+@implementation SFSignInAnalyticsTester
+
++ (NSString*)databasePath {
+    return _path;
+}
+
+-(instancetype)init
+{
+    self = [super initWithSignInUUID:[NSUUID UUID].UUIDString category:@"CoreCDP" eventName:@"signin"];
+
+    return self;
+}
+
+@end
+
+
+@interface SignInAnalyticsTests : XCTestCase
+@property (nonatomic) SFSignInAnalyticsTester *metric;
+@end
+
+@implementation SignInAnalyticsTests
+
+
+- (void)setUp {
+    [super setUp];
+    _testnum = 0;
+    self.continueAfterFailure = NO;
+    _path = [@"/tmp" stringByAppendingFormat:@"/test_%ld.db", (long)++_testnum];
+    _metric = [[SFSignInAnalyticsTester alloc] init];
+    XCTAssertNotNil(_metric, "SignInAnalyticsTester object should not be nil");
+}
+
+- (void)tearDown
+{
+    dispatch_async([SFSIALoggerObject logger].queue, ^{
+        [[SFSIALoggerObject logger].database executeSQL:@"delete from all_events"];
+        [[SFSIALoggerObject logger].database executeSQL:@"delete from soft_failures"];
+        [[SFSIALoggerObject logger].database executeSQL:@"delete from hard_failures"];
+    });
+
+    [[SFSIALoggerObject logger] removeState];
+    _metric = nil;
+    [super tearDown];
+}
+
+- (void)testStop
+{
+    sleep(2);
+    NSDictionary *attributes = @{@"success": @YES,
+                                 @"takenFlow" : @"restore",
+                                 };
+    XCTAssertNotNil(attributes, "attributes dictionary should exist");
+    
+    [_metric stopWithAttributes:attributes];
+
+    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
+
+    XCTAssertEqual([results count], 2, @"should have 2 results");
+    
+}
+
+- (void)testCancel
+{
+    [_metric cancel];
+}
+
+- (void)testLogError
+{
+    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
+    [_metric logRecoverableError:error];
+    NSArray* results = [[SFSIALoggerObject logger].database softFailures];
+    XCTAssertEqual([results count], 1, @"should have 1 results");
+}
+
+- (void)testCreateNewSubtask
+{
+    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
+    XCTAssertNotNil(child, "child should be created");
+    [[SFSIALoggerObject logger] removeState];
+    child = nil;
+}
+
+
+- (void)testCreateNewSubtaskAndStop
+{
+    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
+
+    sleep(2);
+    NSDictionary *attributes = @{@"success": @YES,
+                                 @"takenFlow" : @"piggyback",
+                                 };
+
+    [child stopWithAttributes:attributes];
+    
+    XCTAssertNotNil(child, "child should be created");
+
+    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
+
+    XCTAssertEqual([results count], 2, @"should have 2 results");
+
+    [[SFSIALoggerObject logger] removeState];
+    child = nil;
+}
+
+- (void)testStopAfterCancel
+{
+    sleep(2);
+    NSDictionary *attributes = @{@"success": @YES,
+                                 @"takenFlow" : @"piggyback",
+                                 };
+    XCTAssertNotNil(attributes, "attributes dictionary should exist");
+
+    [_metric cancel];
+
+    [_metric stopWithAttributes:attributes];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+
+    XCTAssertEqual([allEvents count], 0, @"should have 0 things logged");
+}
+
+- (void)testStopAfterStop
+{
+    sleep(2);
+    NSDictionary *attributes = @{@"success": @YES,
+                                 @"takenFlow" : @"piggyback",
+                                 };
+    XCTAssertNotNil(attributes, "attributes dictionary should exist");
+
+    [_metric stopWithAttributes:attributes];
+
+    [_metric stopWithAttributes:attributes];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+
+    XCTAssertEqual([allEvents count], 2, @"should have 2 things logged");
+}
+
+-(void)testSignInComplete
+{
+    NSDictionary* attributes = [NSDictionary dictionary];
+    [_metric stopWithAttributes:attributes];
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array should not be nil");
+    XCTAssertTrue(allEvents && [allEvents count] > 0, "array should not be nil and contain an entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    XCTAssertTrue(dependencyEntry && [dependencyEntry count] > 0, "dictionary should not be nil and contain an entry");
+
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+
+    XCTAssertEqual([chains count], 1, "should be one list");
+
+    XCTAssertTrue([chains containsObject:_metric.signin_uuid], "should contain 1 uuid");
+}
+
+-(void)testSingleChainDependencyList
+{
+    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
+    XCTAssertNotNil(child1, "child1 should be created");
+
+    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
+    XCTAssertNotNil(child2, "child2 should be created");
+
+    SFSignInAnalytics* child3 = [child2 newSubTaskForEvent:@"backup"];
+    XCTAssertNotNil(child3, "child3 should be created");
+
+    SFSignInAnalytics* child4 = [child3 newSubTaskForEvent:@"processing one ring"];
+    XCTAssertNotNil(child4, "child4 should be created");
+
+    [_metric signInCompleted];
+
+    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", child1.signin_uuid, child1.my_uuid, child2.my_uuid, child3.my_uuid, child4.my_uuid];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "should not be nil");
+    XCTAssertTrue([allEvents count] > 0, "should be events");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+
+    XCTAssertEqual([chains count], 1, "should be one list");
+    XCTAssertTrue([expectedChain isEqualToString:[chains objectAtIndex:0]], "chains should be the same");
+
+    child1 = nil;
+    child2 = nil;
+    child3 = nil;
+    child4 = nil;
+
+    child1 = nil;
+    child2 = nil;
+    child3 = nil;
+    child4 = nil;
+}
+
+-(void)testMultipleChildrenPerEvent
+{
+    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
+    XCTAssertNotNil(child1, "child1 should be created");
+
+    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
+    XCTAssertNotNil(child2, "child2 should be created");
+
+    SFSignInAnalytics* child3 = [child1 newSubTaskForEvent:@"backup"];
+    XCTAssertNotNil(child3, "child3 should be created");
+
+    SFSignInAnalytics* child4 = [child1 newSubTaskForEvent:@"processing one ring"];
+    XCTAssertNotNil(child4, "child4 should be created");
+
+    SFSignInAnalytics* child5 = [child2 newSubTaskForEvent:@"processing second ring"];
+    XCTAssertNotNil(child5, "child5 should be created");
+
+    SFSignInAnalytics* child6 = [child2 newSubTaskForEvent:@"processing third ring"];
+    XCTAssertNotNil(child6, "child6 should be created");
+
+    SFSignInAnalytics* child7 = [child2 newSubTaskForEvent:@"processing fourth ring"];
+    XCTAssertNotNil(child7, "child7 should be created");
+
+    SFSignInAnalytics* child8 = [child7 newSubTaskForEvent:@"processing fifth ring"];
+    XCTAssertNotNil(child8, "child8 should be created");
+
+    SFSignInAnalytics* child9 = [child7 newSubTaskForEvent:@"processing one ring"];
+    XCTAssertNotNil(child9, "child9 should be created");
+
+    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
+
+    NSString *expectedChain1 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child3.my_uuid];
+
+    NSString *expectedChain2 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child4.my_uuid];
+
+    NSString *expectedChain3 = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
+
+    NSString *expectedChain4 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child8.my_uuid];
+
+    NSString *expectedChain5 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child9.my_uuid];
+
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertTrue([allEvents count] > 0, "array should not be empty");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+
+    XCTAssertEqual([chains count], 6, "should be one list");
+
+    XCTAssertTrue([chains containsObject:expectedChain], "chains should contain expectedChain");
+    XCTAssertTrue([chains containsObject:expectedChain1], "chains should contain expectedChain1");
+    XCTAssertTrue([chains containsObject:expectedChain2], "chains should contain expectedChain2");
+    XCTAssertTrue([chains containsObject:expectedChain3], "chains should contain expectedChain3");
+    XCTAssertTrue([chains containsObject:expectedChain4], "chains should contain expectedChain4");
+    XCTAssertTrue([chains containsObject:expectedChain5], "chains should contain expectedChain5");
+
+    [[SFSIALoggerObject logger] removeState];
+
+    child1 = nil;
+    child2 = nil;
+    child3 = nil;
+    child4 = nil;
+    child5 = nil;
+    child6 = nil;
+    child7 = nil;
+    child8 = nil;
+    child9 = nil;
+
+}
+
+-(void)testSOSCCWaitForInitialSync
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    bool worked = SOSCCWaitForInitialSyncWithAnalytics(parentData, &error);
+    XCTAssertTrue(worked, "should have worked");
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCRemoveThisDeviceFromCircle
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    bool worked = SOSCCRemoveThisDeviceFromCircleWithAnalytics(parentData, &error);
+    XCTAssertTrue(worked, "should have worked");
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCRequestToJoinCircle
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    SOSCCRequestToJoinCircleWithAnalytics(parentData, &error);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCRequestToJoinCircleAfterRestore
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    SOSCCRequestToJoinCircleAfterRestoreWithAnalytics(parentData, &error);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCRemovePeersFromCircle
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    NSArray* peers = [NSArray array];
+    SOSCCRemovePeersFromCircleWithAnalytics((__bridge CFArrayRef)peers, parentData, &error);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+
+-(void)testSOSCCViewSet
+{
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    CFSetRef enabledViews = nil;
+    CFSetRef disabledViews = nil;
+    SOSCCViewSetWithAnalytics(enabledViews, disabledViews, parentData);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCSetUserCredentialsAndDSID
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    CFStringRef label = nil;
+    CFDataRef password = nil;
+    CFStringRef dsid = nil;
+    SOSCCSetUserCredentialsAndDSIDWithAnalytics(label, password, dsid, parentData, &error);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+-(void)testSOSCCResetToEmpty
+{
+    CFErrorRef error = nil;
+    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
+    XCTAssertNotNil(archiver, "should not be nil");
+    [_metric encodeWithCoder:archiver];
+    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
+    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
+    SOSCCResetToEmptyWithAnalytics(parentData, &error);
+
+    [_metric signInCompleted];
+
+    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
+    XCTAssertNotNil(allEvents, "array is not nil");
+    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
+
+    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
+    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
+    XCTAssertNotNil(chains, "chains is not nil");
+    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
+}
+
+- (void)testMultipleDBConnections
+{
+    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
+    dispatch_queue_t test_queue = dispatch_queue_create("com.apple.security.signin.tests", DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL);
+
+    for(int i = 0; i < 1000; i++){
+        SFSignInAnalytics *test1 = [_metric newSubTaskForEvent:@"connection1"];
+        SFSignInAnalytics *test2 = [_metric newSubTaskForEvent:@"connection2"];
+
+        dispatch_async(test_queue, ^{
+            [test1 logRecoverableError:error];
+        });
+        dispatch_async(test_queue, ^{
+            [test2 stopWithAttributes:nil];
+        });
+        dispatch_async(test_queue, ^{
+            [self->_metric logRecoverableError:error];
+        });
+    }
+}
+@end
index f8ec5419f2c91c2400a7d259c454ddf998a6c1b8..0058b605a28e80ec93b92228a8f9d49d5344c194 100644 (file)
@@ -8,5 +8,7 @@
        <true/>
        <key>com.apple.private.octagon</key>
        <true/>
+       <key>com.apple.securebackupd.access</key>
+       <true/>
 </dict>
 </plist>
index 00fe01592a2464aab1744dbccb7866fd57722d21..6724a7d950bb32b43f1bcfdc609234c8634bb68a 100644 (file)
@@ -5,6 +5,8 @@
 #import <objc/runtime.h>
 #import <Security/CKKSControlProtocol.h>
 #import <Security/SecAccessControlPriv.h>
+#import <CloudServices/CloudServices.h>
+
 #import "SecDbKeychainItem.h"
 #import "SecRemoteDevice.h"
 #import "OTControl.h"
 #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 {
 }
 
 
+//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<NSDictionary *>* _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<NSDictionary *>* 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
 
index c6404265b41a680e46bdb472da3d0d0f678cdf3a..db9d9914d50a51a54e8d5a6c11f6df96e9a6dc03 100644 (file)
 
 @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<NSDictionary *>*))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<NSDictionary *>* 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
 {
 }
 
 - (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
-
 }
 
 
     }
 }
 
-// MARK: - CKKS
-- (void)selfPeersForView:(NSString *)view complete:(void (^)(NSArray<NSDictionary *> *result, NSError *error))complete
-{
-    complete(@[], NULL);
-}
-
 // MARK: - Octagon
 - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success, NSError *_Nullable error))complete
 {
index b2194038c71d6b7c63ecbc474ff29bc8b542079d..22a41217140fae3b628b11874d7336ff7c31dee2 100644 (file)
@@ -36,10 +36,6 @@ NS_ASSUME_NONNULL_BEGIN
 
 @protocol SecRemoteDeviceProtocol <NSObject>
 
-// Local Keychain
-- (void)secItemAdd:(NSDictionary *)input complete:(void (^)(OSStatus, NSDictionary * _Nullable))reply;
-- (void)secItemCopyMatching:(NSDictionary *)input complete:(void (^)(OSStatus, NSArray<NSDictionary *>* _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<NSDictionary *> *result, NSError *error))complete;
-
 // Octagon
 - (void)otReset:(NSString *)altDSID complete:(void (^)(bool success,  NSError *_Nullable error))complete;
 
index af5f20897e4c07b8172f231e978d8214fb26ca7f..9ca2bfe7432bd6851933433833e88cbda6252bc6 100644 (file)
@@ -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<NSDictionary *>* _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
index a7c5f127c2926cdf87657a879667fe0d4c7bed4c..0a062b7910c361672deba6c2274855fedf7761b3 100644 (file)
@@ -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<String>?, 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))
+        }
+
+    }
 }
index c64e51b8dfa3fd609ab9c7d1e4e38e5cfcdb1df4..fffd68b15587078f20f49bb6814719b6545f45c6 100644 (file)
@@ -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 = {
index 0e5f5c8cc6b05c42171c4009fa6fbf303e1793b4..0a8dd0bcaee916e7ef85ef186dc0af3656a4252f 100644 (file)
@@ -293,6 +293,24 @@ extension Container {
         }
     }
 
+    func fetchAllowedMachineIDs(reply: @escaping (Set<String>?, Error?) -> Void) {
+        self.semaphore.wait()
+        let reply: (Set<String>?, 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<MachineMO> ?? 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<MachineMO> ?? Set()
index be36cc1f2c7396cfade77e596c8aa8820f83e56d..197d419b45a32cbddf45517a75437ebf904b0e53 100644 (file)
@@ -69,12 +69,17 @@ NS_ASSUME_NONNULL_BEGIN
 
 // Note: this field does not include untrusted peers
 @property NSDictionary<NSString*, NSNumber*>* viablePeerCountsByModelID;
+
+// Note: this field does include untrusted peers
+@property NSDictionary<NSString*, NSNumber*>* peerCountsByMachineID;
+
 @property BOOL isExcluded;
 @property BOOL isLocked;
 
 - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID
                            status:(TPPeerStatus)egoStatus
         viablePeerCountsByModelID:(NSDictionary<NSString*, NSNumber*>*)viablePeerCountsByModelID
+            peerCountsByMachineID:(NSDictionary<NSString*, NSNumber*>*)peerCountsByMachineID
                        isExcluded:(BOOL)isExcluded
                          isLocked:(BOOL)isLocked;
 
@@ -136,6 +141,10 @@ NS_ASSUME_NONNULL_BEGIN
                                   machineIDs:(NSArray<NSString*> *)machineIDs
                                        reply:(void (^)(NSError * _Nullable error))reply;
 
+- (void)fetchAllowedMachineIDsWithContainer:(NSString *)container
+                                    context:(NSString *)context
+                                      reply:(void (^)(NSSet<NSString*>* _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
 
 /*
index f04ac68ec326575a6d27610ab710020d0a4ce327..6603111379090d2d5cdcb5beacfff0826c49d64c 100644 (file)
@@ -205,6 +205,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
 - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID
                            status:(TPPeerStatus)egoStatus
         viablePeerCountsByModelID:(NSDictionary<NSString*, NSNumber*>*)viablePeerCountsByModelID
+            peerCountsByMachineID:(NSDictionary<NSString *,NSNumber *> * _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"];
 }
index 30916147ce5d3501cf642959e3878daf8584da19..f3b3eb19a5c82ba4a1f2dcaf7953690ee10a3f20 100644 (file)
@@ -249,6 +249,19 @@ extension Container {
         return reterr
     }
 
+    func fetchAllowedMachineIDsSync(test: XCTestCase) -> (Set<String>?, Error?) {
+        let expectation = XCTestExpectation(description: "fetchMIDList replied")
+        var retlist: Set<String>?
+        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
index 0516c23a594dc2139ffc351248100dfbf3e2e922..7d7ecae1ac710c6bc43bb3bc34305d2d9d07b0be 100644 (file)
@@ -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 {
index 88584fcb21e2eeac8d23ef3077b15cebd4ecbb18..50070ebc5780493bf6a841f98230e970d8c71fe2 100644 (file)
@@ -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,
index dd876eaf60daf960f4fa2f1c477e4b07e3e26307..6c80b5c5c59c099b8b69e68270fd18c0a5c76f4c 100644 (file)
@@ -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 <NSObject>
 @end
 typedef NSString<CKKSAnalyticsSignpostEvent> CKKSAnalyticsSignpostEvent;
index ce66283da2b05ed25c3d6b215bf47b7a7bd0e2a8..dea0502bbf4a6465fafa23426940dbadafd430dc 100644 (file)
@@ -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";
index 763195b2fd22e0ea78fdecba1ed8e1cabe84a070..ae8a2d95ff22f506d1ba757b72ed895710ddbae0 100644 (file)
@@ -60,8 +60,10 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync;
 @end
 
 @class CKKSCloudKitDeletion;
+
 @protocol CKKSChangeFetcherClient <NSObject>
 - (CKRecordZoneID*)zoneID;
+- (BOOL)zoneIsReadyForFetching;
 - (CKKSCloudKitFetchRequest*)participateInFetch;
 
 // Return false if this is a 'fatal' error and you don't want another fetch to be tried
index 1bbb06cd15da485bc6d2298bd8613edc0a9acf90..3e7a16fed619cda9246d9291d43e7638d55b3407 100644 (file)
         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
                     // 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);
                 }
 
 #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;
         }
 
             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 {
index e84f7f59b93885477e52cf2c8e3e36a3748a327a..e034f438e967c3a181cd6649c80de997e2b38a82 100644 (file)
@@ -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
index 815b21975b035ffc559e820c3b0db657a86b6284..162af55da503c0761d9210dd68bfeeda622200da 100644 (file)
@@ -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;
index c1d3810d4bc54f77e15590d10227656aebc6c637..940cf26a6baa494d9da4f383fb6405b3db3eea22 100644 (file)
@@ -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"
                             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) {
     }
 }
 
+- (BOOL)_onqueueIsErrorMissingSyncKey:(NSError*)ckerror {
+    if([ckerror.domain isEqualToString:CKErrorDomain] && (ckerror.code == CKErrorPartialFailure)) {
+        NSMutableDictionary<CKRecordID*, NSError*>* 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 (file)
index 0000000..90fd08e
--- /dev/null
@@ -0,0 +1,29 @@
+//
+//  CKKSPBFileStorage.h
+//
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@protocol CKKSPBCodable <NSObject>
+@property (nonatomic, readonly) NSData *data;
++ (instancetype)alloc;
+- (id)initWithData:(NSData*)data;
+@end
+
+@interface CKKSPBFileStorage<__covariant CKKSConfigurationStorageType : PBCodable *> : NSObject
+
+- (CKKSPBFileStorage *)initWithStoragePath:(NSURL *)storageFile
+                              storageClass:(Class<CKKSPBCodable>)storageClass;
+
+- (CKKSConfigurationStorageType _Nullable)storage;
+- (void)setStorage:(CKKSConfigurationStorageType _Nonnull)storage;
+@end
+
+@interface PBCodable () <CKKSPBCodable>
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/keychain/ckks/CKKSPBFileStorage.m b/keychain/ckks/CKKSPBFileStorage.m
new file mode 100644 (file)
index 0000000..a7ef628
--- /dev/null
@@ -0,0 +1,56 @@
+//
+//  CKKSPBFileStorage.m
+//
+
+#import "keychain/ckks/CKKSPBFileStorage.h"
+
+@interface CKKSPBFileStorage ()
+@property NSURL *storageFile;
+@property Class<CKKSPBCodable> storageClass;
+@property id<CKKSPBCodable> protobufStorage;
+@end
+
+@implementation CKKSPBFileStorage
+
+- (CKKSPBFileStorage *)initWithStoragePath:(NSURL *)storageFile
+                              storageClass:(Class<CKKSPBCodable>) 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<CKKSPBCodable> c = storage;
+        NSData *data = c.data;
+        [data writeToURL:self.storageFile atomically:YES];
+        self.protobufStorage = [[self.storageClass alloc] initWithData:data];
+    }
+}
+
+
+@end
index 95a1428695ba07ab839c8aaefd211f2f84765ca5..5b29fcccd833e4970f63783fef1123ab11d1d6cf 100644 (file)
@@ -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<CKKSResultOperation*>*)operations;
index 1c107b4f53971ca29b4be83f9bc2aef464abde09..57417657e9fc4212127ea38d1c4103c580250093 100644 (file)
     op.name = name;
     return op;
 }
+
 @end
 
 #endif // OCTAGON
index d1e60c14c01bb467ddc609cb081073747e437545..08510fb26205cee96ebebd4419bd2abe4692f345 100644 (file)
@@ -55,7 +55,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (CKKSResultOperation*)requestSuccessfulFetch:(CKKSFetchBecause*)why;
 - (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet<CKKSFetchBecause*>*)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;
index 0ec4cff41e701a96f1ae62876a15bf286e7d05c3..ead140b93cd73dbb211e5bcfab799d4932cc02da 100644 (file)
@@ -169,31 +169,41 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     }
 }
 
+- (NSArray<id<CKKSChangeFetcherClient>>*)clients {
+    NSMutableArray<id<CKKSChangeFetcherClient>> *clients = [NSMutableArray array];
+    @synchronized (self.clientMap) {
+        for(id<CKKSChangeFetcherClient> 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<CKKSFetchBecause*>*)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<id<CKKSChangeFetcherClient>> *clients = [self clients];
+
+    for(id<CKKSChangeFetcherClient> client in clients) {
+        if([client zoneIsReadyForFetching]) {
+            notReady = NO;
+        }
+    }
 
-- (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet<CKKSFetchBecause*>*)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<CKKSFetchBecause*>*)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<id<CKKSChangeFetcherClient>>* clients = [NSMutableArray array];
-    @synchronized(self.clientMap) {
-        for(id<CKKSChangeFetcherClient> client in [self.clientMap objectEnumerator]) {
-            if(client != nil) {
-                [clients addObject:client];
-            }
-        }
-    }
+    NSArray<id<CKKSChangeFetcherClient>> *clients = [self clients];
 
     if(clients.count == 0u) {
         secnotice("ckksfetcher", "No clients");
index d8afc74bba412daf5593f9bcd80bfbbb4fc578b4..58905c26230cfd740fd373a535cab558f2a5902b 100644 (file)
         CKDatabaseOperation<CKKSModifyRecordZonesOperation>* modifyZonesOperation = [self createModifyZonesOperation:ops];
         CKDatabaseOperation<CKKSModifySubscriptionsOperation>* zoneSubscriptionOperation = [self createModifySubscriptionsOperation:ops];
 
-        [self.operationQueue addOperation:modifyZonesOperation];
+        [self.database addOperation:modifyZonesOperation];
         if(zoneSubscriptionOperation) {
-            [self.operationQueue addOperation:zoneSubscriptionOperation];
+            [self.database addOperation:zoneSubscriptionOperation];
         }
     });
 }
index 2bf92f579971812343659a7d73836552a0aceeee..c7995009d697efd1b1e6d420da7835a9697d4dd8 100644 (file)
@@ -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)
index 22f575971444b0c236174d3e1b541a38b4ceed17..50bb89046dd700f15e69e35b7a6096e03eed3943 100644 (file)
     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)
index 5271338d2e821308b604f52263691d736533d1a7..98b8920c1eeeb562e1df24a7003ae796268b83a3 100644 (file)
@@ -66,16 +66,17 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithEnvironmentName:(NSString*)environmentName
                       namedDelegatePort:(NSString*)namedDelegatePort
                      apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass;
+- (instancetype)initWithEnvironmentName:(NSString*)environmentName
+                      namedDelegatePort:(NSString*)namedDelegatePort
+                     apsConnectionClass:(Class<OctagonAPSConnection>)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<NSString*, NSMutableSet<CKRecordZoneNotification*>*>*)notifications;
 @end
 
 NS_ASSUME_NONNULL_END
index 10499da9c36d7cfab84252f63c709055c32c4c5d..e8eeb4f7df38281cc84354ae6662910c15e32630 100644 (file)
     return aps_dispatch_queue;
 }
 
-+ (int64_t)stalePushTimeout {
-    return 5*60*NSEC_PER_SEC;
-}
-
 - (BOOL) haveStalePushes
 {
     __block BOOL haveStalePushes = NO;
 
 - (instancetype)initWithEnvironmentName:(NSString*)environmentName
                       namedDelegatePort:(NSString*)namedDelegatePort
-                     apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass {
+                     apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
+{
+    return [self initWithEnvironmentName:environmentName
+                       namedDelegatePort:namedDelegatePort
+                      apsConnectionClass:apsConnectionClass
+                        stalePushTimeout:5*60*NSEC_PER_SEC];
+}
+
+- (instancetype)initWithEnvironmentName:(NSString*)environmentName
+                      namedDelegatePort:(NSString*)namedDelegatePort
+                     apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
+                       stalePushTimeout:(uint64_t)stalePushTimeout
+{
     if(self = [super init]) {
         _apsConnectionClass = apsConnectionClass;
         _apsConnection = NULL;
                 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];
index 748de40c3cc6e1fce39b2722977ffc4e39c9e219..4aa357acaaf2b1037637623999503c40a8a8438b 100644 (file)
     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 (file)
index 0000000..112bd55
--- /dev/null
@@ -0,0 +1,49 @@
+//
+//  CKKSPBFileStorageTests.m
+//
+
+#import <XCTest/XCTest.h>
+
+#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<CKKSSerializedKey *> *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
index 8a057b6cda3c7583536896cb1e003de76705e2a7..1aaf5cd8204869cc6edf9ece5845faf9a78aa64e 100644 (file)
     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.
 
     }];
 }
 
+- (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
index a108921ee91d2b1751c7241fcf53809178b52d83..0e3573d6fd7ecee990daafd647cdc9a9821fd415 100644 (file)
@@ -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;
 
index 1eded344ad2118330d35aebebef94cc0ae4fc8a6..76916eabf1ee536c5ef3dda6fcec7e6fc3d137d0 100644 (file)
         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
     }
 }
 
+-(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
 }
 
 - (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
index b551e87a2ca55f2211836f204fbf6430fc901bed..912260561900469fc81c3fa0ddf837012ab412d2 100644 (file)
@@ -144,6 +144,9 @@ typedef NSMutableDictionary<CKRecordZoneID*, FakeCKZone*> 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 <CKKSNotifier>
index a4172271a30e07fbcf4d0061fef8bff090af5d51..1a15ff54961305c0d99d50b07f1d38abb632b6da 100644 (file)
 
 - (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);
 
     }
     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
index f985e503f86e44a84fe6c7946b97165110946abc..517279eed6238dc9c68de88d8ec9b7bd87ec07be 100644 (file)
@@ -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
index c531fb8296ffa71cf0a057d1636e939fe117f0a8..c67395bbd7da7b0e8f580288b13c7d19a7d4c943 100644 (file)
@@ -255,6 +255,28 @@ enum {NUM_RETRIES = 5};
     } while (retry);
 }
 
+
+- (void)fetchAllowedMachineIDsWithContainer:(nonnull NSString *)container
+                                    context:(nonnull NSString *)context
+                                      reply:(nonnull void (^)(NSSet<NSString *> * _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
index d2e4053c92f5a92efef99725e9f0792ae0f7a638..5539aa1f5d28361ededa927b08326ce9c58d7b4c 100644 (file)
@@ -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;
 
index 939e58c51c451835a1df0bf491539b88d71e57c7..b9452d2e6e4e17b313c68753fdc29a3a411f40ad 100644 (file)
@@ -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 <AuthKit/AKDeviceListDeltaMessagePayload.h>
 #import <Foundation/NSDistributedNotificationCenter.h>
 #import "keychain/ckks/CKKSListenerCollection.h"
+#import "keychain/ckks/CKKSAnalytics.h"
+
+#include "utilities/SecABC.h"
 
 #import <AppleAccount/ACAccount+AppleAccount.h>
 
 
 @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;
 
 - (void)fetchCurrentDeviceList:(void (^)(NSSet<NSString*>* _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;
     }
 
 
             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);
         }
index 32f8f044e83f44cca43501394fa5269298ac2045..b36a24aacaa260115f75b55fd00168101f3a8129 100644 (file)
@@ -263,7 +263,6 @@ NSDictionary<OctagonState*, NSNumber*>* 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;
index 8a6c33b36b01e777f11d012a5850049e99f40f92..5bf39ceee3605e50e3d072a024f868072d464a5e 100644 (file)
@@ -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 <utilities/SecCFWrappers.h>
 #import <utilities/debugging.h>
@@ -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<OctagonEscrowRecovererPrococol> 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<NSString*>* 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<NSString*, NSString*>* 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(&copyViewUnawarePeerInfoErrorRef);
@@ -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<NSString*>*)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) {
index 1b7ba2d238f5e60d9578e94292af170ddabc5991..736ab162c2ee4b744116698f58a8d5f11793de87 100644 (file)
@@ -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;
index 9fbf29a385e2101ff5a4234580ec463a40020e2f..e839d139f4d92ac8bf7d32e2e1749a3978997af4 100644 (file)
@@ -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";
index 4665950cdeb8188f1f9178d6611541b991834d93..426c5dc8669b6f600d05adfb3bbb505845c9405e 100644 (file)
@@ -197,6 +197,10 @@ preapprovedKeys:(NSArray<NSData*>* _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
index 3ebe08535b4593f9eceb6bf41af2e39a54d712ea..0eac866a536730399539168e9bbce49796b5cade 100644 (file)
@@ -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<NSData*>* _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<NSData*>* _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<NSString *> * _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
index 216d261445cd208d4b62d73031506597b71e5e38..8d5f6e71fdb7f46637bb51ff1b272cc1ac0e877d 100644 (file)
@@ -26,6 +26,8 @@
 #if OCTAGON
 #include <Foundation/Foundation.h>
 #include <utilities/debugging.h>
+#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
 
index a74ff51526b4ef6f0f6cad8d9eb115db6c6755b2..43a5f127425478e88bbcd9954c32f9cb6ee28572 100644 (file)
@@ -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;
index 323919c18049bc54cb67b71c3f8b6801a1347960..92c0caae60551be701dcfc56e07a19eb44adf0bc 100644 (file)
@@ -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.
index b2e5dd964933203a438107689bb4f0eb8c4942ab..2b34ec232179015ca8a0af644a8baa64560ed7db 100644 (file)
     
     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];
 
index fad75dd89597fa6451f800983634718a953e0e13..8f22398473b08abf9e5e6c49aa4975ee19d81f21 100644 (file)
     [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;
index b83cbefaf1eb57c4c059b4906bcd0d1ed7e90c2f..4761d52582f357f310898140312b1b0392faecf0 100644 (file)
     
     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];
 
index 5133b38141ae7e1b9331e4e3b060670768ce8328..ede2cb05312f7a19d94e21081341804dcdffcec9 100644 (file)
@@ -147,6 +147,7 @@ NSDictionary<NSNumber*, OctagonState*>* OctagonStateInverseMap(void);
 // <rdar://problem/54094162> Octagon: ensure Octagon operations can't occur on SA accounts
 NSSet<OctagonState*>* OctagonInAccountStates(void);
 NSSet<OctagonState *>* OctagonHealthSourceStates(void);
+NSSet<OctagonFlag *>* 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;
 
index 18e42299f4de56b6e4a38a027dc0b947cf2ad80f..5af0ffb4ab082d9bee795558908de4178e5f3766 100644 (file)
@@ -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<OctagonFlag *>* AllOctagonFlags(void)
+{
+    static NSSet<OctagonFlag*>* 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
index c96ba590d73660678f29d9c71429b7245b0545ab..48a381bcb1bc04cd999688d94eeda8247f075033 100644 (file)
     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];
 
index cded9242c67cf671e9005a6b40fbcfa2484e5907..0bb767fefe56dbdf26df9574bf00aca4a0549330 100644 (file)
         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;
index 8e2f54ffeae1d559f99f610e6f28ed008bc26caf..90f93499ba1a34120febc73d7e460a7eee0c9d5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 20178 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2019 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
index 2aac36d8f3cf700930e09adb613d2e0d2680992f..b7707e9eadaae52277469ecd0088bace1a6874c9 100644 (file)
 {
     // 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;
index 6170941ed17d2f425277ccce68a1515a6902b262..60d85855e6211f6a34ca3bf024a88e3c441756f6 100644 (file)
@@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
 @protocol OctagonFlagContainer
 - (BOOL)_onqueueContains:(OctagonFlag*)flag;
 - (NSArray<NSString*>*)dumpFlags;
+- (CKKSCondition*)conditionForFlag:(OctagonFlag*)flag;
 @end
 
 @protocol OctagonFlagSetter <OctagonFlagContainer>
@@ -27,7 +28,11 @@ NS_ASSUME_NONNULL_BEGIN
 @interface OctagonFlags : NSObject <OctagonFlagContainer,
                                     OctagonFlagSetter,
                                     OctagonFlagClearer>
-- (instancetype)initWithQueue:(dispatch_queue_t)queue;
+
+@property NSMutableDictionary<OctagonFlag*, CKKSCondition*>* flagConditions;
+
+- (instancetype)initWithQueue:(dispatch_queue_t)queue
+                        flags:(NSSet<OctagonFlag*>*)possibleFlags;
 
 - (NSString*)contentsAsString;
 @end
index 766ab3fbfa146e6b4c65569a4695507895229f1e..b42fc44707d443822bdfdaf22db3b41d9026c508 100644 (file)
@@ -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<OctagonFlag*>* flags;
+@property (readonly) NSSet* allowableFlags;
 @end
 
 @implementation OctagonFlags
 
 - (instancetype)initWithQueue:(dispatch_queue_t)queue
+                       flags:(NSSet<OctagonFlag*>*)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;
 }
     [self.flags addObject:flag];
 }
 
+- (CKKSCondition*)conditionForFlag:(OctagonFlag*)flag {
+    return self.flagConditions[flag];
+}
+
 - (void)setFlag:(nonnull OctagonFlag *)flag {
     dispatch_sync(self.queue, ^{
         [self _onqueueSetFlag:flag];
 
 - (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
index a4503e08ef38f3c0590b0aad3330e01623a16ea5..4aeabe1cb0852f12c1608b575bb6a8d9c168a706 100644 (file)
@@ -43,6 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (readonly) id<OctagonFlagContainer> flags;
 
 @property NSMutableDictionary<OctagonState*, CKKSCondition*>* stateConditions;
+
 @property (readonly) CKKSCondition* paused;
 
 @property (readonly) NSSet* allowableStates;
@@ -54,10 +55,11 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (instancetype)initWithName:(NSString*)name
                       states:(NSSet<OctagonState*>*)possibleStates
+                       flags:(NSSet<OctagonFlag*>*)possibleFlags
                 initialState:(OctagonState*)initialState
                        queue:(dispatch_queue_t)queue
                  stateEngine:(id<OctagonStateMachineEngine>)stateEngine
-            lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker;
+            lockStateTracker:(CKKSLockStateTracker*)lockStateTracker;
 
 - (void)startOperation;
 - (void)haltOperation;
index ef550aad0c03fc6332cdf724e9b2308352fb8a7c..dcd693ad5f5ec0dbb8dfe8aed514e475b80c3067 100644 (file)
@@ -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<OctagonState*>*)possibleStates
+                       flags:(NSSet<OctagonFlag*>*)possibleFlags
                 initialState:(OctagonState*)initialState
                        queue:(dispatch_queue_t)queue
                  stateEngine:(id<OctagonStateMachineEngine>)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<NSString*, NSString*>* 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<OctagonStateTransitionOperationProtocol>* 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<OctagonStateTransitionOperationProtocol>* 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];
 }
 
index aa2fc920709a8b11a7104017ed64772024a1b576..d936223de07bbf98534701a6e96554353041b171 100644 (file)
@@ -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
 
 
index 1ebd4cb9c83cd1c5f58cf28d95f4dc48818bc566..a2362e3215e558babd39c52564a6bb9daa5f85f8 100644 (file)
@@ -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 ()
index 17094bd0a108b52a1a3e3713b03b3c7e700786a9..afa3084444d3a0b93f57ca5bafd86fe7b99c3ff6 100644 (file)
@@ -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;
 
index b770f8f3d21b457aa3dd63b41c70a059fd0da125..d7e8680882a00878c49a624ad54ebdeec0a66bf5 100644 (file)
 @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
 
 - (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;
         _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;
     }
 }
 
+- (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;
         return;
     }
 
-
     OctagonStateTransitionPathStep* nextPath = [self.remainingPath nextStep:attempt.nextState];
 
     if(nextPath) {
index 3fa30c285b65d8344d26466ee279f9ca6fafdf91..848bb213e12bff37a75f00b400971ece52f46c9c 100644 (file)
@@ -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)
 
index e838a1afd2f28fbc74e70bd5ee01ccd2c6c4144f..b5069a737c11ff9fafc3451bcbf540a62581aa60 100644 (file)
@@ -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")
         }
     }
index 0bf2b04ce70631390a9106fec4eab4af9bd59825..ad69de5b3b09a010995c1e411e6a3d5fd65c1cee 100644 (file)
         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)
         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")
index 562d627098f0e7deee1a0f94aa0d86d9d916f4ee..00037248579768448709953afb8e778a63de59b6 100644 (file)
@@ -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 {
index 67a55f23e84dcf06867fe7959d5b019793bab813..a239ad9b6ffbc74879096c40d5121ee7d49a3a27 100644 (file)
@@ -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")
         }
     }
index 086a45bc7823e60e9e2d75cc1afb4c45b4c44250..850a15b1291ee53fcebd410eaa65b594b5a94492 100644 (file)
@@ -25,6 +25,7 @@
 #import <Security/SecItemPriv.h>
 #import "keychain/ckks/CKKS.h"
 #import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSResultOperation.h"
 
 #import <SecurityFoundation/SFKeychain.h>
 #import <SecurityFoundation/SFIdentity.h>
@@ -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"
 
index 0fa46d1554e30e06230dc9da614f3e674e376293..de42b91099047aecba03756fc516cb1927254cd5 100644 (file)
@@ -77,8 +77,13 @@ class OTMockAuthKitAdapter: OTAuthKitAdapter {
         self.listeners = CKKSListenerCollection<OTAuthKitAdapterNotifier>(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<CKKSResultOperation & OctagonStateTransitionOperationProtocol>))
+        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
index 37565454ee05ab7aa6c4050e8cf7d54075a460ab..f2d431ee6895e272e03ea2cabd3d8e7f2b4b8657 100644 (file)
@@ -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;
 }
 
index 8205fdd9919ac816bb45043e8c4bd4a99981c417..f62cc0224b6338e7e5be432070e3f16b349d7d31 100644 (file)
@@ -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
index 60664cb896611c3b62205cf2a682da68c65992cd..2a2fa0baf6aa61781972491e73431bf309f1b35c 100644 (file)
@@ -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);
     
index 6c363684f00928ae5a0a2b66b7a68b04722b5831..3adf34ebc69c7af61e931250709b342603828062 100644 (file)
@@ -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);
 
index ef07ff9814b7033ca294118ed8e0036d40f17503..51bccb51f6b70718e03235c520c9440d1b31c693 100644 (file)
@@ -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 <utilities/SecADWrapper.h>
@@ -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.
         // <rdar://problem/32732066>
@@ -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
+}
+
index 1fd3957d1e8caa3d21b001bf3c549bcd272856f4..90ccbe00180d2fb6c761387308caf34031c9719a 100644 (file)
@@ -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;
index 9a366661aab5b09e7dbba3f635637e68df5b9d32..860529cfd731ae6aa00742d479a3d4c2c7846f91 100644 (file)
@@ -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, ^{
index 4f20f4b79b1639fb29224e97257f96490c16efe7..fd98b35381f8db56c1f5c23478d5f3e67bdf7f4a 100644 (file)
@@ -43,6 +43,7 @@ enum Command {
     case vouch(String, Data, Data, Data, Data)
     case vouchWithBottle(String, Data, String)
     case allow(Set<String>, 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)
 
index 048db40f67c3a0e4809758d9094cca888d8531f1..ad12a40eb06e55843ec03572c0fa45d2c7cd9ef9 100644 (file)
@@ -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) {
index 0101c43fd4cd09ef0235287c9cf144d4ecc2cc5b..b209bc6f383611643897a284997594a3dd28ec62 100644 (file)
@@ -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;
index e1b8cdb9cddf51238e4322e7cac2907a5d77da85..4ae69401e2bf56d4344fcaa131deb838feb8de20 100644 (file)
@@ -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
index 5c54545b6be295d257b532614684c0c0dd308502..a68d4f2d3264a5736a47624bf72e63cdf5c6a77a 100644 (file)
@@ -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[] = {
index c91b48fb1b0103de8c01d74f24aa99c11aeedd2e..c59ca4d27d92f20e111fd8d904c02a8ac0462161 100644 (file)
@@ -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")
index cafcfaf1088650bb1376b3c781615d60bfa2580a..7305d05540f1d70f1938089d35822ba9117fc71f 100644 (file)
                <key>Policies</key>
                <dict>
                        <key>PolicyIdentifier</key>
-                       <string>1.2.840.113635.100.1.24</string>
+                       <string>1.2.840.113635.100.1.51</string>
                </dict>
                <key>Leaf</key>
                <string>escrow_service_key_049F9D11</string>
diff --git a/tests/secdmockaks/MockAKSOptionalParameters.proto b/tests/secdmockaks/MockAKSOptionalParameters.proto
new file mode 100644 (file)
index 0000000..02a9d20
--- /dev/null
@@ -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 (file)
index 0000000..9162041
--- /dev/null
@@ -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 (file)
index 0000000..eb39a40
--- /dev/null
@@ -0,0 +1,43 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from MockAKSOptionalParameters.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define MOCKAKSOPTIONALPARAMETERS_FUNCTION extern "C"
+#else
+#define MOCKAKSOPTIONALPARAMETERS_FUNCTION extern
+#endif
+
+@interface MockAKSOptionalParameters : PBCodable <NSCopying>
+{
+    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 (file)
index 0000000..2d4450a
--- /dev/null
@@ -0,0 +1,194 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from MockAKSOptionalParameters.proto
+
+#import "MockAKSOptionalParameters.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#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 (file)
index 0000000..84420ef
--- /dev/null
@@ -0,0 +1,39 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from MockAKSRefKey.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define MOCKAKSREFKEY_FUNCTION extern "C"
+#else
+#define MOCKAKSREFKEY_FUNCTION extern
+#endif
+
+@interface MockAKSRefKey : PBCodable <NSCopying>
+{
+    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 (file)
index 0000000..f0c8c7a
--- /dev/null
@@ -0,0 +1,159 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from MockAKSRefKey.proto
+
+#import "MockAKSRefKey.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#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
+
index d4d0ee8fd247c86178222abec99f27e6afcea616..068c33fbb20754ca230abf0264c7d48cf9a15283 100644 (file)
 
 #if __has_include(<MobileKeyBag/MobileKeyBag.h>)
 #include <MobileKeyBag/MobileKeyBag.h>
-#else
+#define HAVE_MobileKeyBag_MobileKeyBag 1
+#endif
+
+#if __OBJC2__
+#import <Foundation/Foundation.h>
+#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 // <MobileKeyBag/MobileKeyBag.h>
 
+#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 */
index 71ac9ce5e171c62b3769c1302619131fc5b93e9b..4bf815b80822cb82d2780efd56985525a8eca486 100644 (file)
@@ -48,6 +48,9 @@
 #import <LocalAuthentication/LACFSupport.h>
 #import <SecurityFoundation/SFEncryptionOperation.h>
 #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<NSError *>* _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
index 27662ddd5d295bed19be0d30ca01e2888b90e853..d69762fe3be1ae37694e190dbadf44cfc9ac78e6 100644 (file)
 #import "SecItemServer.h"
 #import "SecItemSchema.h"
 #include "OSX/sec/Security/SecItemShim.h"
+#import "server_security_helpers.h"
 #import "spi.h"
 #import <utilities/SecCFWrappers.h>
 #import <utilities/SecFileLocations.h>
+#import "utilities/der_plist.h"
 #import <SecurityFoundation/SFEncryptionOperation.h>
 #import <XCTest/XCTest.h>
 #import <OCMock/OCMock.h>
 @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
 
 
     }
 }
 
+- (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;
 
 - (void)testSecItemServerDeleteAll
 {
+
     [self addAccessGroup:@"com.apple.bluetooth"];
     [self addAccessGroup:@"lockdown-identities"];
+    [self addAccessGroup:@"apple"];
 
     // BT root key, should not be deleted
     NSMutableDictionary* bt = [@{
 {
     [self createManyItems];
     [self createManyKeys];
+    [self createManyACLKeyItems];
 
     
     NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword,
 
     [self createManyItems];
     [self createManyKeys];
+    [self createManyACLKeyItems];
 
     /*
      sleep(600);
     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
index 22dfdc0a9f03c6c9a024d341594263e562da8ed6..86670e171c83ee56e9e3a006b75ea252134a36ae 100644 (file)
@@ -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];
 }
index 92f9ae420965c047fb8367b245d8b0b2c5465561..fb0028ca2efb6d8cd22569167db1652d362e62d8 100644 (file)
@@ -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
index 1227f246cdb2f04ab56654a0c7f42cda602b46d7..06f56077ab55d47803fb714313f1cd4c335409de 100644 (file)
@@ -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 <utilities/SecIOFormat.h>
 #include <utilities/SecDispatchRelease.h>
@@ -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
         /* <rdar://32728029> 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 */
index 531ba549724f04c6818cdce5ace37af8a42f2f3d..898e71f30d1e4aaf81635de03e5d52ba7cd02115 100644 (file)
@@ -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 (file)
index 0000000..8a8e12c
--- /dev/null
@@ -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 (file)
index 0000000..c918e7d
--- /dev/null
@@ -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 <AssertMacros.h>
+#import <Foundation/Foundation.h>
+#import <CFNetwork/CFHostPriv.h>
+#import <Network/Network.h>
+#import <Network/Network_Private.h>
+
+#import <Security/SecCertificatePriv.h>
+#import <Security/SecPolicyPriv.h>
+#import <Security/SecTrustInternal.h>
+#import <Security/SecFramework.h>
+
+#include <utilities/SecCFWrappers.h>
+#include <utilities/SecFileLocations.h>
+#include <utilities/sec_action.h>
+
+#include "trust/trustd/SecTrustServer.h"
+#include "trust/trustd/SecCertificateSource.h"
+#include "trust/trustd/SecPolicyServer.h"
+#include "trust/trustd/SecTrustLoggingServer.h"
+
index 8c2490e6f23cfc6692d588b037658dcf441bc14d..1960abdc0453c015916204c7c6c6a1ba18dc66be 100644 (file)
@@ -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
index c4dd5a07cdb3648bd66ce277eec9bf9529206f93..195db7c328ffdf2fe46ab6189f3147ee2894be7b 100644 (file)
@@ -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