From 7fb2cbd2e68c73bf213d9907905431dbdb74c908 Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 24 Mar 2020 21:08:16 +0000 Subject: [PATCH] Security-59306.41.2.tar.gz --- CircleJoinRequested/CircleJoinRequested.m | 95 +- KeychainCircle/KCAccountKCCircleDelegate.h | 2 +- KeychainCircle/KCAccountKCCircleDelegate.m | 4 +- KeychainCircle/KCJoiningAcceptSession.m | 47 +- .../KCJoiningRequestSecretSession.m | 8 +- KeychainCircle/KCJoiningSession.h | 2 +- KeychainCircle/PairingChannel.m | 15 +- KeychainCircle/Tests/KCJoiningSessionTest.m | 2 +- OSX/authd/authorization.plist | 4 +- OSX/config/security_framework_macos.xcconfig | 2 +- OSX/libsecurity_keychain/lib/Item.cpp | 2 +- OSX/libsecurity_keychain/lib/SecItem.cpp | 12 +- OSX/libsecurity_keychain/lib/SecKey.cpp | 4 +- .../lib/SecTrustOSXEntryPoints.cpp | 2 +- OSX/libsecurity_keychain/lib/TokenLogin.cpp | 74 +- OSX/libsecurity_smime/lib/cmssiginfo.c | 119 +-- .../STLegacyTests+tls12.m | 2 +- OSX/regressions/test/testenv.m | 2 +- .../secitem/si-26-sectrust-copyproperties.c | 15 +- .../secitem/si-30-keychain-upgrade.c | 2 +- .../Regressions/secitem/si-31-keychain-bad.c | 2 +- .../secitem/si-31-keychain-unreadable.c | 2 +- .../secitem/si-33-keychain-backup.c | 2 +- .../Security/Regressions/secitem/si-60-cms.c | 121 ++- .../secitem/si_77_SecAccessControl.c | 2 +- OSX/sec/Security/SecBackupKeybagEntry.h | 2 +- OSX/sec/Security/SecBackupKeybagEntry.m | 4 +- OSX/sec/Security/SecCertificate.c | 24 +- OSX/sec/Security/SecExports.exp-in | 2 + OSX/sec/Security/SecItemBackup.c | 2 +- OSX/sec/Security/SecKey.m | 12 +- OSX/sec/Security/SecPolicy.c | 1 + OSX/sec/Security/SecTrust.c | 2 +- OSX/sec/Security/SecuritydXPC.c | 1 + OSX/sec/SharedWebCredential/swcagent.m | 8 +- OSX/sec/ipc/securityd_client.h | 5 +- OSX/sec/ipc/server.c | 33 +- OSX/sec/ipc/server_endpoint.m | 2 +- OSX/sec/ipc/server_security_helpers.m | 2 +- OSX/sec/ipc/server_xpc.m | 8 +- .../com.apple.security.trustedpeers.plist | 35 + .../AppleISTCA2_Baltimore.cer | Bin 0 -> 1186 bytes .../BaltimoreCyberTrustRoot.cer | Bin 0 -> 891 bytes .../si-82-sectrust-ct-data/basejumper.cer | Bin 0 -> 1484 bytes .../iphonesubmissions.cer | Bin 0 -> 1468 bytes OSX/utilities/SecABC.h | 32 + OSX/utilities/SecABC.m | 71 ++ OSX/utilities/SecCFWrappers.h | 3 + OSX/utilities/SecDb.c | 4 +- OSX/utilities/debugging.h | 1 + OSX/utilities/simulate_crash.c | 98 -- OSX/utilities/simulate_crash.m | 58 ++ RegressionTests/Security.plist | 36 - RegressionTests/SecurityLocalKeychain.plist | 30 +- .../secitemfunctionality.m | 41 +- Security.exp-in | 8 +- Security.xcodeproj/project.pbxproj | 532 +++++------ .../xcschemes/osx - secdtests.xcscheme | 22 +- SecurityTests/testlist.h | 2 +- SecurityTool/sharedTool/SecurityTool.c | 2 +- dtlsEcho/dtlsEchoClient.c | 2 +- dtlsEcho/dtlsEchoServer.c | 2 +- featureflags/Security.plist | 13 +- header_symlinks/Security/SecAccessControl.h | 2 +- header_symlinks/Security/SecCertificate.h | 2 +- header_symlinks/Security/SecCertificatePriv.h | 2 +- .../Security/SecCertificateRequest.h | 2 +- header_symlinks/Security/SecIdentity.h | 2 +- header_symlinks/Security/SecIdentityPriv.h | 2 +- header_symlinks/Security/SecImportExport.h | 2 +- .../Security/SecImportExportPriv.h | 2 +- header_symlinks/Security/SecItem.h | 2 +- header_symlinks/Security/SecItemPriv.h | 2 +- header_symlinks/Security/SecKey.h | 2 +- header_symlinks/Security/SecKeyPriv.h | 2 +- header_symlinks/Security/SecKeyProxy.h | 2 +- header_symlinks/Security/SecPolicy.h | 2 +- header_symlinks/Security/SecPolicyPriv.h | 2 +- .../Security/SecSharedCredential.h | 2 +- header_symlinks/Security/SecTrust.h | 2 +- header_symlinks/Security/SecTrustPriv.h | 2 +- header_symlinks/Security/SecTrustSettings.h | 2 +- .../Security/SecTrustSettingsPriv.h | 2 +- header_symlinks/Security/oids.h | 2 +- header_symlinks/utilities/SecCFRelease.h | 1 - keychain/KeychainSettings/KeychainSettings.m | 1 + .../Regressions/SOSTestDevice.c | 20 +- .../Regressions/sc-40-circle.c | 2 +- .../Regressions/sc-42-circlegencount.c | 2 +- keychain/SecureObjectSync/SOSAccount.h | 4 +- keychain/SecureObjectSync/SOSAccount.m | 42 +- keychain/SecureObjectSync/SOSAccountGhost.m | 12 +- keychain/SecureObjectSync/SOSAccountPriv.h | 2 +- .../SecureObjectSync/SOSAccountTransaction.h | 1 - .../SecureObjectSync/SOSAccountTransaction.m | 8 - .../SOSAccountTrustClassic+Circle.h | 1 + .../SOSAccountTrustClassic+Circle.m | 83 +- .../SecureObjectSync/SOSAccountTrustClassic.h | 1 + keychain/SecureObjectSync/SOSCloudCircle.h | 8 +- keychain/SecureObjectSync/SOSCloudCircle.m | 35 +- .../SecureObjectSync/SOSCloudCircleInternal.h | 2 +- keychain/SecureObjectSync/SOSDataSource.h | 6 - keychain/SecureObjectSync/SOSEngine.c | 211 +---- keychain/SecureObjectSync/SOSFullPeerInfo.m | 5 +- keychain/SecureObjectSync/SOSInternal.m | 2 +- keychain/SecureObjectSync/SOSIntervalEvent.h | 26 + keychain/SecureObjectSync/SOSIntervalEvent.m | 70 ++ keychain/SecureObjectSync/SOSMessage.c | 43 +- keychain/SecureObjectSync/SOSPeer.m | 4 +- keychain/SecureObjectSync/SOSPiggyback.m | 8 +- keychain/SecureObjectSync/SOSRingUtils.h | 15 - .../SOSTransportKeyParameter.m | 2 +- .../SecureObjectSync/SOSTransportMessage.m | 2 +- .../Tool/accountCirclesViewsPrint.m | 2 +- keychain/SecureObjectSync/Tool/keychain_log.m | 2 +- .../SecureObjectSync/Tool/keychain_sync.m | 2 +- .../OctagonTestHarnessXPCService.m | 31 +- .../SecRemoteDevice.m | 4 +- .../OctagonTestHarnessXPCServiceProtocol.h | 8 +- .../BottledPeer/EscrowKeys.swift | 51 +- keychain/TrustedPeersHelper/Client.swift | 25 +- keychain/TrustedPeersHelper/Container.swift | 148 ++- .../TrustedPeersHelper/ContainerMap.swift | 70 +- .../Container_MachineIDs.swift | 43 +- .../CuttlefishAPIHelpers.swift | 2 +- .../TrustedPeersHelper/CuttlefishErrors.swift | 28 +- .../RecoveryKey/RecoverKeySet.swift | 44 +- .../SetValueTransformer.swift | 6 +- .../TrustedPeersHelper-Bridging-Header.h | 1 + .../TrustedPeersHelper-entitlements.plist | 2 + .../TrustedPeersHelperProtocol.h | 22 +- .../TrustedPeersHelperProtocol.m | 21 +- .../categories/OTPrivateKey+SF.m | 9 +- .../ContainerSync.swift | 18 +- .../FakeCuttlefish.swift | 74 +- .../MockCuttlefish.swift | 8 +- ...ustedPeersHelperUnitTests-BridgingHeader.h | 4 +- .../TrustedPeersHelperUnitTests.swift | 195 +++- keychain/ckks/CKKS.m | 2 +- keychain/ckks/CKKSAccountStateTracker.m | 4 + keychain/ckks/CKKSAnalytics.h | 5 +- keychain/ckks/CKKSAnalytics.m | 6 +- keychain/ckks/CKKSDeviceStateEntry.h | 2 +- .../CKKSFetchAllRecordZoneChangesOperation.h | 15 +- .../CKKSFetchAllRecordZoneChangesOperation.m | 88 +- keychain/ckks/CKKSIncomingQueueEntry.h | 2 +- keychain/ckks/CKKSIncomingQueueEntry.m | 4 +- keychain/ckks/CKKSIncomingQueueOperation.m | 4 +- keychain/ckks/CKKSItem.h | 2 +- keychain/ckks/CKKSItem.m | 4 +- keychain/ckks/CKKSItemEncrypter.h | 2 +- keychain/ckks/CKKSItemEncrypter.m | 2 +- keychain/ckks/CKKSKey.m | 2 +- keychain/ckks/CKKSKeychainView.h | 30 +- keychain/ckks/CKKSKeychainView.m | 330 ++++--- keychain/ckks/CKKSManifest.m | 4 +- keychain/ckks/CKKSMirrorEntry.h | 2 +- keychain/ckks/CKKSMirrorEntry.m | 4 +- keychain/ckks/CKKSNearFutureScheduler.h | 8 + keychain/ckks/CKKSNearFutureScheduler.m | 56 +- keychain/ckks/CKKSOutgoingQueueEntry.h | 2 +- keychain/ckks/CKKSOutgoingQueueEntry.m | 4 +- keychain/ckks/CKKSOutgoingQueueOperation.m | 4 +- keychain/ckks/CKKSPeer.h | 23 - keychain/ckks/CKKSPeerProvider.h | 69 ++ keychain/ckks/CKKSPeerProvider.m | 76 ++ keychain/ckks/CKKSRecordHolder.h | 2 +- keychain/ckks/CKKSRecordHolder.m | 4 +- keychain/ckks/CKKSSQLDatabaseObject.h | 2 +- keychain/ckks/CKKSSQLDatabaseObject.m | 2 +- keychain/ckks/CKKSScanLocalItemsOperation.m | 6 +- .../CKKSUpdateCurrentItemPointerOperation.m | 8 +- keychain/ckks/CKKSViewManager.h | 6 +- keychain/ckks/CKKSViewManager.m | 31 +- keychain/ckks/CKKSZoneChangeFetcher.h | 2 +- keychain/ckks/CKKSZoneChangeFetcher.m | 36 +- keychain/ckks/CKKSZoneModifier.m | 8 +- keychain/ckks/CKKSZoneStateEntry.h | 4 +- keychain/ckks/CKKSZoneStateEntry.m | 12 +- keychain/ckks/CloudKitCategories.h | 1 + keychain/ckks/CloudKitCategories.m | 39 +- keychain/ckks/NSOperationCategories.m | 4 + keychain/ckks/OctagonAPSReceiver.h | 4 + keychain/ckks/OctagonAPSReceiver.m | 38 +- .../ckks/tests/CKKSAESSIVEncryptionTests.m | 2 +- keychain/ckks/tests/CKKSAPSHandlingTests.m | 13 +- keychain/ckks/tests/CKKSCloudKitTests.m | 4 +- keychain/ckks/tests/CKKSFetchTests.m | 183 ++++ keychain/ckks/tests/CKKSMockOctagonAdapter.m | 5 + .../ckks/tests/CKKSMockSOSPresentAdapter.h | 2 + .../ckks/tests/CKKSMockSOSPresentAdapter.m | 7 + .../ckks/tests/CKKSNearFutureSchedulerTests.m | 116 +++ keychain/ckks/tests/CKKSSQLTests.m | 5 +- .../ckks/tests/CKKSTests+CurrentPointerAPI.m | 21 +- keychain/ckks/tests/CKKSTests+MultiZone.m | 80 ++ keychain/ckks/tests/CKKSTests.m | 27 +- .../tests/CloudKitKeychainSyncingMockXCTest.h | 2 +- .../tests/CloudKitKeychainSyncingMockXCTest.m | 18 +- keychain/ckks/tests/CloudKitMockXCTest.m | 12 +- keychain/ckks/tests/MockCloudKit.m | 10 +- keychain/ckksctl/ckksctl.m | 2 + .../tests/SecEscrowRequestTests.m | 4 +- keychain/{ => headers}/SecAccessControl.h | 0 keychain/{ => headers}/SecIdentity.h | 0 keychain/{ => headers}/SecIdentityPriv.h | 0 keychain/{ => headers}/SecImportExport.h | 0 keychain/{ => headers}/SecImportExportPriv.h | 0 keychain/{ => headers}/SecItem.h | 0 keychain/{ => headers}/SecItemPriv.h | 0 keychain/{ => headers}/SecKey.h | 0 keychain/{ => headers}/SecKeyPriv.h | 0 keychain/{ => headers}/SecKeyProxy.h | 0 keychain/{ => headers}/SecSharedCredential.h | 0 ...PreflightInfo.h => CuttlefishXPCWrapper.h} | 24 +- keychain/ot/CuttlefishXPCWrapper.m | 844 ++++++++++++++++++ keychain/ot/OTBottledPeer.h | 59 -- keychain/ot/OTBottledPeer.m | 205 ----- keychain/ot/OTBottledPeerRecord.h | 44 - keychain/ot/OTBottledPeerRecord.m | 52 -- keychain/ot/OTBottledPeerSigned.h | 64 -- keychain/ot/OTBottledPeerSigned.m | 165 ---- keychain/ot/OTBottledPeerState.h | 59 -- keychain/ot/OTBottledPeerState.m | 35 - keychain/ot/OTCheckHealthOperation.m | 60 +- keychain/ot/OTClientStateMachine.m | 9 +- keychain/ot/OTClientVoucherOperation.m | 51 +- keychain/ot/OTClique.h | 26 +- keychain/ot/OTClique.m | 364 +++++--- keychain/ot/OTCloudStore.h | 83 -- keychain/ot/OTCloudStore.m | 764 ---------------- keychain/ot/OTCloudStoreState.h | 57 -- keychain/ot/OTCloudStoreState.m | 151 ---- keychain/ot/OTConstants.h | 13 + keychain/ot/OTConstants.m | 26 + keychain/ot/OTContext.h | 83 -- keychain/ot/OTContext.m | 633 ------------- keychain/ot/OTContextRecord.h | 56 -- keychain/ot/OTContextRecord.m | 40 - keychain/ot/OTControl.h | 25 +- keychain/ot/OTControl.m | 3 +- keychain/ot/OTControlProtocol.h | 3 +- keychain/ot/OTControlProtocol.m | 1 + keychain/ot/OTCuttlefishContext.h | 18 +- keychain/ot/OTCuttlefishContext.m | 491 +++++----- keychain/ot/OTDefines.h | 87 +- keychain/ot/OTDefines.m | 2 + keychain/ot/OTDeviceInformationAdapter.h | 7 + keychain/ot/OTDeviceInformationAdapter.m | 63 +- keychain/ot/OTEnsureOctagonKeyConsistency.m | 6 +- keychain/ot/OTEpochOperation.h | 12 +- keychain/ot/OTEpochOperation.m | 56 +- keychain/ot/OTEscrowKeys.h | 74 -- keychain/ot/OTEscrowKeys.m | 417 --------- keychain/ot/OTEstablishOperation.m | 89 +- keychain/ot/OTFetchViewsOperation.m | 66 +- keychain/ot/OTFollowup.h | 9 +- keychain/ot/OTFollowup.m | 16 +- keychain/ot/OTIdentity.h | 58 -- keychain/ot/OTIdentity.m | 214 ----- keychain/ot/OTJoinWithVoucherOperation.m | 149 +--- keychain/ot/OTLeaveCliqueOperation.m | 48 +- keychain/ot/OTLocalCuttlefishReset.h | 3 +- keychain/ot/OTLocalCuttlefishReset.m | 39 +- keychain/ot/OTLocalStore.h | 77 -- keychain/ot/OTLocalStore.m | 684 -------------- keychain/ot/OTManager.h | 40 +- keychain/ot/OTManager.m | 819 +++-------------- keychain/ot/OTOperationDependencies.h | 8 +- keychain/ot/OTOperationDependencies.m | 6 +- keychain/ot/OTPreflightInfo.m | 32 - keychain/ot/OTPrepareOperation.m | 113 ++- keychain/ot/OTRemovePeersOperation.m | 34 +- keychain/ot/OTResetOperation.h | 8 +- keychain/ot/OTResetOperation.m | 46 +- keychain/ot/OTSOSAdapter.h | 1 + keychain/ot/OTSOSAdapter.m | 36 +- .../ot/OTSOSUpdatePreapprovalsOperation.m | 43 +- keychain/ot/OTSOSUpgradeOperation.m | 256 +++--- keychain/ot/OTSetRecoveryKeyOperation.m | 40 +- keychain/ot/OTStates.h | 8 +- keychain/ot/OTStates.m | 11 +- keychain/ot/OTUpdateTPHOperation.m | 117 ++- .../ot/OTUpdateTrustedDeviceListOperation.m | 55 +- keychain/ot/OTUploadNewCKKSTLKsOperation.h | 1 + keychain/ot/OTUploadNewCKKSTLKsOperation.m | 109 +-- keychain/ot/OTVouchWithBottleOperation.m | 94 +- keychain/ot/OTVouchWithRecoveryKeyOperation.m | 44 +- keychain/ot/OctagonCKKSPeerAdapter.m | 65 +- keychain/ot/OctagonCheckTrustStateOperation.m | 60 +- keychain/ot/tests/OTBottledPeerTLK.m | 162 ---- keychain/ot/tests/OTBottledPeerTests.m | 149 ---- .../tests/OTBottledPeerUpdateBottlesTests.m | 324 ------- keychain/ot/tests/OTCliqueTests.m | 238 ----- keychain/ot/tests/OTCloudStoreTests.m | 295 ------ keychain/ot/tests/OTContextTests.m | 240 ----- keychain/ot/tests/OTCuttlefishContextTests.m | 103 --- keychain/ot/tests/OTEscrowKeyTests.m | 192 ---- keychain/ot/tests/OTLocalStoreTests.m | 266 ------ .../ot/tests/OTLockStateNetworkingTests.m | 675 -------------- keychain/ot/tests/OTRampingTests.m | 474 ---------- keychain/ot/tests/OTTestsBase.h | 117 --- keychain/ot/tests/OTTestsBase.m | 326 ------- .../octagon/OctagonDataPersistenceTests.swift | 2 +- .../ot/tests/octagon/OctagonTestMocks.swift | 36 +- .../ot/tests/octagon/OctagonTests+CKKS.swift | 4 +- .../OctagonTests+CloudKitAccount.swift | 95 +- .../octagon/OctagonTests+CoreFollowUp.swift | 182 +++- .../octagon/OctagonTests+DeviceList.swift | 19 +- .../octagon/OctagonTests+ErrorHandling.swift | 138 ++- .../octagon/OctagonTests+EscrowRecovery.swift | 56 +- .../octagon/OctagonTests+HealthCheck.swift | 95 +- .../octagon/OctagonTests+RecoveryKey.swift | 127 ++- .../ot/tests/octagon/OctagonTests+Reset.swift | 341 ++++++- .../ot/tests/octagon/OctagonTests+SOS.swift | 112 +++ .../octagon/OctagonTests+SOSUpgrade.swift | 190 +++- .../octagon/OctagonTests-BridgingHeader.h | 12 +- keychain/ot/tests/octagon/OctagonTests.swift | 483 ++++++---- .../octagon/OctagonTestsXPCConnections.swift | 2 +- .../OctagonPairingTests+ProximitySetup.swift | 173 +--- .../octagon/Pairing/OctagonPairingTests.swift | 5 +- keychain/otctl/OTControlCLI.m | 1 + keychain/otpaird/OTPairingConstants.h | 2 + keychain/otpaird/OTPairingService.h | 2 + keychain/otpaird/OTPairingService.m | 18 + keychain/otpaird/main.m | 118 ++- .../securityd/CheckV12DevEnabled.h | 0 .../securityd/CheckV12DevEnabled.m | 0 .../securityd/Info-macOS.plist | 0 .../securityd/PolicyReporter.h | 0 .../securityd/PolicyReporter.m | 0 .../securityd/Regressions/SOSAccountTesting.h | 0 .../Regressions/SOSTransportTestTransports.h | 0 .../Regressions/SOSTransportTestTransports.m | 0 .../Regressions/SecdTestKeychainUtilities.c | 2 +- .../Regressions/SecdTestKeychainUtilities.h | 0 .../Regressions/ios6_1_keychain_2_db.h | 0 .../Regressions/ios8-inet-keychain-2.h | 0 .../securityd/Regressions/sd-10-policytree.m | 2 +- .../securityd/Regressions/secd-01-items.m | 4 +- .../secd-02-upgrade-while-locked.m | 6 +- .../Regressions/secd-03-corrupted-items.m | 6 +- .../Regressions/secd-04-corrupted-items.m | 6 +- .../Regressions/secd-05-corrupted-items.m | 4 +- .../Regressions/secd-100-initialsync.m | 2 +- .../Regressions/secd-130-other-peer-views.m | 0 .../Regressions/secd-154-engine-backoff.m | 0 .../secd-155-otr-negotiation-monitor.m | 2 +- .../securityd/Regressions/secd-156-timers.m | 2 +- .../Regressions/secd-20-keychain_upgrade.m | 2 +- .../securityd/Regressions/secd-200-logstate.m | 2 +- .../securityd/Regressions/secd-201-coders.m | 2 +- .../Regressions/secd-202-recoverykey.m | 0 .../Regressions/secd-21-transmogrify.m | 2 +- .../Regressions/secd-210-keyinterest.m | 0 .../Regressions/secd-230-keybagtable.m | 4 +- .../Regressions/secd-30-keychain-upgrade.m | 2 +- .../Regressions/secd-31-keychain-unreadable.m | 2 +- .../Regressions/secd-32-restore-bad-backup.m | 2 +- .../Regressions/secd-33-keychain-backup.m | 2 +- .../Regressions/secd-33-keychain-ctk.m | 0 .../Regressions/secd-34-backup-der-parse.m | 2 +- .../secd-35-keychain-migrate-inet.m | 4 +- .../Regressions/secd-36-ks-encrypt.m | 0 .../secd-37-pairing-initial-sync.m | 2 +- .../Regressions/secd-40-cc-gestalt.m | 2 +- .../securityd/Regressions/secd-49-manifests.m | 2 +- .../securityd/Regressions/secd-50-account.m | 2 +- .../securityd/Regressions/secd-50-message.m | 2 +- .../Regressions/secd-51-account-inflate.m | 2 +- .../Regressions/secd-52-account-changed.m | 2 +- .../secd-52-offering-gencount-reset.m | 2 +- .../Regressions/secd-55-account-circle.m | 2 +- .../secd-55-account-incompatibility.m | 2 +- .../Regressions/secd-56-account-apply.m | 2 +- .../secd-57-1-account-last-standing.m | 2 +- .../Regressions/secd-57-account-leave.m | 2 +- .../Regressions/secd-58-password-change.m | 2 +- .../Regressions/secd-59-account-cleanup.m | 2 +- .../secd-60-account-cloud-identity.m | 22 +- ...d-61-account-leave-not-in-kansas-anymore.m | 2 +- .../Regressions/secd-62-account-backup.m | 2 +- .../secd-63-account-resurrection.m | 2 +- .../Regressions/secd-64-circlereset.m | 2 +- .../secd-65-account-retirement-reset.m | 2 +- .../Regressions/secd-66-account-recovery.m | 2 +- .../securityd/Regressions/secd-668-ghosts.m | 0 .../Regressions/secd-67-prefixedKeyIDs.m | 0 .../Regressions/secd-70-engine-corrupt.m | 4 +- .../Regressions/secd-70-engine-smash.m | 0 .../securityd/Regressions/secd-70-engine.m | 4 +- .../Regressions/secd-70-otr-remote.m | 0 .../Regressions/secd-71-engine-save-sample1.h | 0 .../Regressions/secd-71-engine-save.m | 4 +- .../Regressions/secd-74-engine-beer-servers.m | 0 .../Regressions/secd-75-engine-views.m | 0 .../Regressions/secd-76-idstransport.m | 0 .../Regressions/secd-80-views-alwayson.m | 0 .../Regressions/secd-80-views-basic.m | 2 +- .../Regressions/secd-81-item-acl-stress.m | 2 +- .../securityd/Regressions/secd-81-item-acl.m | 2 +- .../Regressions/secd-82-persistent-ref.m | 0 .../Regressions/secd-83-item-match-policy.m | 0 .../Regressions/secd-83-item-match-trusted.m | 0 .../secd-83-item-match-valid-on-date.m | 0 .../Regressions/secd-83-item-match.h | 0 .../Regressions/secd-95-escrow-persistence.m | 2 +- .../secd60-account-cloud-exposure.m | 2 +- .../Regressions/secd_77_ids_messaging.m | 0 .../securityd/Regressions/secd_regressions.h | 0 .../Regressions/securityd_regressions.h | 0 .../securityd/SFKeychainControlManager.h | 0 .../securityd/SFKeychainControlManager.m | 0 .../securityd/SFKeychainServer.h | 0 .../securityd/SFKeychainServer.m | 0 .../securityd/SOSCloudCircleServer.h | 2 +- .../securityd/SOSCloudCircleServer.m | 21 +- .../securityd/SecAKSObjCWrappers.h | 0 .../securityd/SecAKSObjCWrappers.m | 0 .../SecDbBackupRecoverySet.proto | 0 .../generated_source/SecDbBackupBag.h | 0 .../generated_source/SecDbBackupBag.m | 0 .../generated_source/SecDbBackupBagIdentity.h | 0 .../generated_source/SecDbBackupBagIdentity.m | 0 .../SecDbBackupKeyClassSigningKey.h | 0 .../SecDbBackupKeyClassSigningKey.m | 0 .../SecDbBackupMetadataClassKey.h | 0 .../SecDbBackupMetadataClassKey.m | 0 .../generated_source/SecDbBackupRecoverySet.h | 0 .../generated_source/SecDbBackupRecoverySet.m | 0 .../securityd/SecDbBackupManager.h | 0 .../securityd/SecDbBackupManager.m | 0 .../securityd/SecDbBackupManager_Internal.h | 0 {OSX/sec => keychain}/securityd/SecDbItem.c | 8 +- {OSX/sec => keychain}/securityd/SecDbItem.h | 2 +- .../securityd/SecDbKeychainItem.h | 6 +- .../securityd/SecDbKeychainItem.m | 10 +- .../securityd/SecDbKeychainItemV7.h | 0 .../securityd/SecDbKeychainItemV7.m | 0 .../securityd/SecDbKeychainMetadataKeyStore.h | 0 .../securityd/SecDbKeychainMetadataKeyStore.m | 14 +- ...SecDbKeychainSerializedAKSWrappedKey.proto | 0 .../SecDbKeychainSerializedItemV7.proto | 0 .../SecDbKeychainSerializedMetadata.proto | 0 .../SecDbKeychainSerializedSecretData.proto | 0 .../SecDbKeychainSerializedAKSWrappedKey.h | 0 .../SecDbKeychainSerializedAKSWrappedKey.m | 0 .../SecDbKeychainSerializedItemV7.h | 0 .../SecDbKeychainSerializedItemV7.m | 0 .../SecDbKeychainSerializedMetadata.h | 0 .../SecDbKeychainSerializedMetadata.m | 0 .../SecDbKeychainSerializedSecretData.h | 0 .../SecDbKeychainSerializedSecretData.m | 0 {OSX/sec => keychain}/securityd/SecDbQuery.c | 10 +- {OSX/sec => keychain}/securityd/SecDbQuery.h | 4 +- .../securityd/SecItemBackupServer.c | 6 +- .../securityd/SecItemBackupServer.h | 0 .../securityd/SecItemDataSource.c | 21 +- .../securityd/SecItemDataSource.h | 0 {OSX/sec => keychain}/securityd/SecItemDb.c | 22 +- {OSX/sec => keychain}/securityd/SecItemDb.h | 2 +- .../securityd/SecItemSchema.c | 59 +- .../securityd/SecItemSchema.h | 2 +- .../securityd/SecItemServer.c | 16 +- .../securityd/SecItemServer.h | 2 +- .../securityd/SecKeybagSupport.c | 22 +- .../securityd/SecKeybagSupport.h | 0 .../securityd/SecLogSettingsServer.h | 0 .../securityd/SecLogSettingsServer.m | 2 +- .../sec => keychain}/securityd/SecOTRRemote.h | 0 .../sec => keychain}/securityd/SecOTRRemote.m | 4 +- .../securityd/com.apple.secd.sb | 1 + .../securityd/entitlements.plist | 2 + {OSX/sec => keychain}/securityd/iCloudTrace.c | 2 +- {OSX/sec => keychain}/securityd/iCloudTrace.h | 0 {OSX/sec => keychain}/securityd/spi.c | 16 +- {OSX/sec => keychain}/securityd/spi.h | 0 keychain/tpctl/main.swift | 2 +- libsecurity_smime/lib/cmssiginfo.c | 75 +- secdtests/main.m | 2 +- secdtests/testlist.h | 2 +- secdxctests/KeychainAPITests.m | 4 + secdxctests/KeychainCryptoTests.m | 6 + secdxctests/KeychainXCTest.m | 2 + securityd/etc/com.apple.securityd.sb | 16 +- sslViewer/sslEcdsa.cpp | 2 +- sslViewer/sslServer.cpp | 2 +- tests/SecDbBackupTests/SecDbBackupTests.m | 4 +- .../DaemonTests/LoggingServerTests.m | 2 +- tests/TrustTests/EvaluationTests/CTTests.m | 118 ++- .../TrustTests/EvaluationTests/PolicyTests.m | 46 + .../EvaluationTests/TrustEvaluationTestCase.h | 20 +- .../EvaluationTests/TrustEvaluationTestCase.m | 24 +- .../CertificateInterfaceTests.m | 2 +- tests/secdmockaks/mockaksKeychain.m | 3 + tests/secdmockaks/mockaksxcbase.h | 2 + tests/secdmockaks/mockaksxcbase.m | 30 +- trust/{ => headers}/SecCertificate.h | 0 trust/{ => headers}/SecCertificatePriv.h | 32 +- trust/{ => headers}/SecCertificateRequest.h | 0 trust/{ => headers}/SecPolicy.h | 0 trust/{ => headers}/SecPolicyPriv.h | 3 + trust/{ => headers}/SecTrust.h | 0 trust/{ => headers}/SecTrustPriv.h | 0 trust/{ => headers}/SecTrustSettings.h | 0 trust/{ => headers}/SecTrustSettingsPriv.h | 0 trust/{ => headers}/oids.h | 0 .../trustd}/OTATrustUtilities.h | 0 .../trustd}/OTATrustUtilities.m | 4 +- .../trustd}/SecCAIssuerCache.c | 4 +- .../trustd}/SecCAIssuerCache.h | 2 +- .../trustd}/SecCAIssuerRequest.h | 0 .../trustd}/SecCAIssuerRequest.m | 4 +- .../trustd}/SecCertificateServer.c | 8 +- .../trustd}/SecCertificateServer.h | 2 +- .../trustd}/SecCertificateSource.c | 8 +- .../trustd}/SecCertificateSource.h | 0 .../securityd => trust/trustd}/SecOCSPCache.c | 4 +- .../securityd => trust/trustd}/SecOCSPCache.h | 4 +- .../trustd}/SecOCSPRequest.c | 2 +- .../trustd}/SecOCSPRequest.h | 0 .../trustd}/SecOCSPResponse.c | 2 +- .../trustd}/SecOCSPResponse.h | 2 +- .../securityd => trust/trustd}/SecPinningDb.h | 0 .../securityd => trust/trustd}/SecPinningDb.m | 42 +- .../trustd}/SecPolicyServer.c | 87 +- .../trustd}/SecPolicyServer.h | 4 +- .../trustd}/SecRevocationDb.c | 8 +- .../trustd}/SecRevocationDb.h | 0 .../trustd}/SecRevocationNetworking.h | 2 +- .../trustd}/SecRevocationNetworking.m | 0 .../trustd}/SecRevocationServer.c | 20 +- .../trustd}/SecRevocationServer.h | 8 +- .../trustd}/SecTrustExceptionResetCount.h | 0 .../trustd}/SecTrustExceptionResetCount.m | 0 .../trustd}/SecTrustLoggingServer.h | 0 .../trustd}/SecTrustLoggingServer.m | 0 .../trustd}/SecTrustServer.c | 14 +- .../trustd}/SecTrustServer.h | 4 +- .../trustd}/SecTrustStoreServer.c | 4 +- .../trustd}/SecTrustStoreServer.h | 0 .../trustd}/SecTrustStoreServer.m | 0 .../trustd}/TrustURLSessionDelegate.h | 0 .../trustd}/TrustURLSessionDelegate.m | 0 {OSX => trust}/trustd/com.apple.trustd.asl | 0 .../trustd/iOS/AppleCorporateRootCA.cer | Bin .../trustd/iOS/AppleCorporateRootCA2.cer | Bin .../trustd/iOS/com.apple.trustd.plist | 0 {OSX => trust}/trustd/iOS/entitlements.plist | 0 .../trustd/macOS/SecTrustOSXEntryPoints.h | 0 .../trustd/macOS/com.apple.trustd.agent.plist | 0 .../trustd/macOS/com.apple.trustd.plist | 0 .../trustd/macOS/com.apple.trustd.sb | 0 .../trustd/macOS/entitlements.plist | 0 {OSX => trust}/trustd/macOS/trustd.8 | 0 .../trustd}/nameconstraints.c | 2 +- .../trustd}/nameconstraints.h | 0 .../trustd}/personalization.c | 0 .../trustd}/personalization.h | 0 .../securityd => trust/trustd}/policytree.c | 0 .../securityd => trust/trustd}/policytree.h | 0 {OSX => trust}/trustd/trustd-Info.plist | 0 {OSX => trust}/trustd/trustd-Prefix.pch | 0 {OSX => trust}/trustd/trustd.c | 20 +- {OSX => trust}/trustd/trustd_spi.c | 20 +- {OSX => trust}/trustd/trustd_spi.h | 0 xcconfig/PlatformFeatures.xcconfig | 13 +- xcconfig/PlatformLibraries.xcconfig | 9 +- xcconfig/Security.xcconfig | 4 +- xcconfig/swift_binary.xcconfig | 2 +- 569 files changed, 7626 insertions(+), 12593 deletions(-) create mode 100644 OSX/sec/os_log/com.apple.security.trustedpeers.plist create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/BaltimoreCyberTrustRoot.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer create mode 100644 OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer create mode 100644 OSX/utilities/SecABC.h create mode 100644 OSX/utilities/SecABC.m delete mode 100644 OSX/utilities/simulate_crash.c create mode 100644 OSX/utilities/simulate_crash.m delete mode 120000 header_symlinks/utilities/SecCFRelease.h create mode 100644 keychain/SecureObjectSync/SOSIntervalEvent.h create mode 100644 keychain/SecureObjectSync/SOSIntervalEvent.m create mode 100644 keychain/ckks/CKKSPeerProvider.h create mode 100644 keychain/ckks/CKKSPeerProvider.m rename keychain/{ => headers}/SecAccessControl.h (100%) rename keychain/{ => headers}/SecIdentity.h (100%) rename keychain/{ => headers}/SecIdentityPriv.h (100%) rename keychain/{ => headers}/SecImportExport.h (100%) rename keychain/{ => headers}/SecImportExportPriv.h (100%) rename keychain/{ => headers}/SecItem.h (100%) rename keychain/{ => headers}/SecItemPriv.h (100%) rename keychain/{ => headers}/SecKey.h (100%) rename keychain/{ => headers}/SecKeyPriv.h (100%) rename keychain/{ => headers}/SecKeyProxy.h (100%) rename keychain/{ => headers}/SecSharedCredential.h (100%) rename keychain/ot/{OTPreflightInfo.h => CuttlefishXPCWrapper.h} (59%) create mode 100644 keychain/ot/CuttlefishXPCWrapper.m delete mode 100644 keychain/ot/OTBottledPeer.h delete mode 100644 keychain/ot/OTBottledPeer.m delete mode 100644 keychain/ot/OTBottledPeerRecord.h delete mode 100644 keychain/ot/OTBottledPeerRecord.m delete mode 100644 keychain/ot/OTBottledPeerSigned.h delete mode 100644 keychain/ot/OTBottledPeerSigned.m delete mode 100644 keychain/ot/OTBottledPeerState.h delete mode 100644 keychain/ot/OTBottledPeerState.m delete mode 100644 keychain/ot/OTCloudStore.h delete mode 100644 keychain/ot/OTCloudStore.m delete mode 100644 keychain/ot/OTCloudStoreState.h delete mode 100644 keychain/ot/OTCloudStoreState.m delete mode 100644 keychain/ot/OTContext.h delete mode 100644 keychain/ot/OTContext.m delete mode 100644 keychain/ot/OTContextRecord.h delete mode 100644 keychain/ot/OTContextRecord.m delete mode 100644 keychain/ot/OTEscrowKeys.h delete mode 100644 keychain/ot/OTEscrowKeys.m delete mode 100644 keychain/ot/OTIdentity.h delete mode 100644 keychain/ot/OTIdentity.m delete mode 100644 keychain/ot/OTLocalStore.h delete mode 100644 keychain/ot/OTLocalStore.m delete mode 100644 keychain/ot/OTPreflightInfo.m delete mode 100644 keychain/ot/tests/OTBottledPeerTLK.m delete mode 100644 keychain/ot/tests/OTBottledPeerTests.m delete mode 100644 keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m delete mode 100644 keychain/ot/tests/OTCliqueTests.m delete mode 100644 keychain/ot/tests/OTCloudStoreTests.m delete mode 100644 keychain/ot/tests/OTContextTests.m delete mode 100644 keychain/ot/tests/OTCuttlefishContextTests.m delete mode 100644 keychain/ot/tests/OTEscrowKeyTests.m delete mode 100644 keychain/ot/tests/OTLocalStoreTests.m delete mode 100644 keychain/ot/tests/OTLockStateNetworkingTests.m delete mode 100644 keychain/ot/tests/OTRampingTests.m delete mode 100644 keychain/ot/tests/OTTestsBase.h delete mode 100644 keychain/ot/tests/OTTestsBase.m rename {OSX/sec => keychain}/securityd/CheckV12DevEnabled.h (100%) rename {OSX/sec => keychain}/securityd/CheckV12DevEnabled.m (100%) rename {OSX/sec => keychain}/securityd/Info-macOS.plist (100%) rename {OSX/sec => keychain}/securityd/PolicyReporter.h (100%) rename {OSX/sec => keychain}/securityd/PolicyReporter.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/SOSAccountTesting.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/SOSTransportTestTransports.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/SOSTransportTestTransports.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/SecdTestKeychainUtilities.c (98%) rename {OSX/sec => keychain}/securityd/Regressions/SecdTestKeychainUtilities.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/ios6_1_keychain_2_db.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/ios8-inet-keychain-2.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/sd-10-policytree.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-01-items.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-02-upgrade-while-locked.m (97%) rename {OSX/sec => keychain}/securityd/Regressions/secd-03-corrupted-items.m (97%) rename {OSX/sec => keychain}/securityd/Regressions/secd-04-corrupted-items.m (97%) rename {OSX/sec => keychain}/securityd/Regressions/secd-05-corrupted-items.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-100-initialsync.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-130-other-peer-views.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-154-engine-backoff.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-155-otr-negotiation-monitor.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-156-timers.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-20-keychain_upgrade.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-200-logstate.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-201-coders.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-202-recoverykey.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-21-transmogrify.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-210-keyinterest.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-230-keybagtable.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-30-keychain-upgrade.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-31-keychain-unreadable.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-32-restore-bad-backup.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-33-keychain-backup.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-33-keychain-ctk.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-34-backup-der-parse.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-35-keychain-migrate-inet.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-36-ks-encrypt.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-37-pairing-initial-sync.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-40-cc-gestalt.m (96%) rename {OSX/sec => keychain}/securityd/Regressions/secd-49-manifests.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-50-account.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-50-message.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-51-account-inflate.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-52-account-changed.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-52-offering-gencount-reset.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-55-account-circle.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-55-account-incompatibility.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-56-account-apply.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-57-1-account-last-standing.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-57-account-leave.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-58-password-change.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-59-account-cleanup.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-60-account-cloud-identity.m (97%) rename {OSX/sec => keychain}/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-62-account-backup.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-63-account-resurrection.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-64-circlereset.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-65-account-retirement-reset.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-66-account-recovery.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-668-ghosts.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-67-prefixedKeyIDs.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-70-engine-corrupt.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-70-engine-smash.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-70-engine.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-70-otr-remote.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-71-engine-save-sample1.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-71-engine-save.m (98%) rename {OSX/sec => keychain}/securityd/Regressions/secd-74-engine-beer-servers.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-75-engine-views.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-76-idstransport.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-80-views-alwayson.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-80-views-basic.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-81-item-acl-stress.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-81-item-acl.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd-82-persistent-ref.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-83-item-match-policy.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-83-item-match-trusted.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-83-item-match-valid-on-date.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-83-item-match.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd-95-escrow-persistence.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd60-account-cloud-exposure.m (99%) rename {OSX/sec => keychain}/securityd/Regressions/secd_77_ids_messaging.m (100%) rename {OSX/sec => keychain}/securityd/Regressions/secd_regressions.h (100%) rename {OSX/sec => keychain}/securityd/Regressions/securityd_regressions.h (100%) rename {OSX/sec => keychain}/securityd/SFKeychainControlManager.h (100%) rename {OSX/sec => keychain}/securityd/SFKeychainControlManager.m (100%) rename {OSX/sec => keychain}/securityd/SFKeychainServer.h (100%) rename {OSX/sec => keychain}/securityd/SFKeychainServer.m (100%) rename {OSX/sec => keychain}/securityd/SOSCloudCircleServer.h (99%) rename {OSX/sec => keychain}/securityd/SOSCloudCircleServer.m (99%) rename {OSX/sec => keychain}/securityd/SecAKSObjCWrappers.h (100%) rename {OSX/sec => keychain}/securityd/SecAKSObjCWrappers.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager.h (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager.m (100%) rename {OSX/sec => keychain}/securityd/SecDbBackupManager_Internal.h (100%) rename {OSX/sec => keychain}/securityd/SecDbItem.c (99%) rename {OSX/sec => keychain}/securityd/SecDbItem.h (99%) rename {OSX/sec => keychain}/securityd/SecDbKeychainItem.h (96%) rename {OSX/sec => keychain}/securityd/SecDbKeychainItem.m (99%) rename {OSX/sec => keychain}/securityd/SecDbKeychainItemV7.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainItemV7.m (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainMetadataKeyStore.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainMetadataKeyStore.m (94%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h (100%) rename {OSX/sec => keychain}/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m (100%) rename {OSX/sec => keychain}/securityd/SecDbQuery.c (99%) rename {OSX/sec => keychain}/securityd/SecDbQuery.h (98%) rename {OSX/sec => keychain}/securityd/SecItemBackupServer.c (97%) rename {OSX/sec => keychain}/securityd/SecItemBackupServer.h (100%) rename {OSX/sec => keychain}/securityd/SecItemDataSource.c (98%) rename {OSX/sec => keychain}/securityd/SecItemDataSource.h (100%) rename {OSX/sec => keychain}/securityd/SecItemDb.c (99%) rename {OSX/sec => keychain}/securityd/SecItemDb.h (99%) rename {OSX/sec => keychain}/securityd/SecItemSchema.c (98%) rename {OSX/sec => keychain}/securityd/SecItemSchema.h (98%) rename {OSX/sec => keychain}/securityd/SecItemServer.c (99%) rename {OSX/sec => keychain}/securityd/SecItemServer.h (99%) rename {OSX/sec => keychain}/securityd/SecKeybagSupport.c (96%) rename {OSX/sec => keychain}/securityd/SecKeybagSupport.h (100%) rename {OSX/sec => keychain}/securityd/SecLogSettingsServer.h (100%) rename {OSX/sec => keychain}/securityd/SecLogSettingsServer.m (95%) rename {OSX/sec => keychain}/securityd/SecOTRRemote.h (100%) rename {OSX/sec => keychain}/securityd/SecOTRRemote.m (98%) rename {OSX/sec => keychain}/securityd/com.apple.secd.sb (98%) rename {OSX/sec => keychain}/securityd/entitlements.plist (98%) rename {OSX/sec => keychain}/securityd/iCloudTrace.c (96%) rename {OSX/sec => keychain}/securityd/iCloudTrace.h (100%) rename {OSX/sec => keychain}/securityd/spi.c (96%) rename {OSX/sec => keychain}/securityd/spi.h (100%) rename trust/{ => headers}/SecCertificate.h (100%) rename trust/{ => headers}/SecCertificatePriv.h (95%) rename trust/{ => headers}/SecCertificateRequest.h (100%) rename trust/{ => headers}/SecPolicy.h (100%) rename trust/{ => headers}/SecPolicyPriv.h (99%) rename trust/{ => headers}/SecTrust.h (100%) rename trust/{ => headers}/SecTrustPriv.h (100%) rename trust/{ => headers}/SecTrustSettings.h (100%) rename trust/{ => headers}/SecTrustSettingsPriv.h (100%) rename trust/{ => headers}/oids.h (100%) rename {OSX/sec/securityd => trust/trustd}/OTATrustUtilities.h (100%) rename {OSX/sec/securityd => trust/trustd}/OTATrustUtilities.m (99%) rename {OSX/sec/securityd => trust/trustd}/SecCAIssuerCache.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecCAIssuerCache.h (97%) rename {OSX/sec/securityd => trust/trustd}/SecCAIssuerRequest.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecCAIssuerRequest.m (99%) rename {OSX/sec/securityd => trust/trustd}/SecCertificateServer.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecCertificateServer.h (99%) rename {OSX/sec/securityd => trust/trustd}/SecCertificateSource.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecCertificateSource.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPCache.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPCache.h (99%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPRequest.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPRequest.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPResponse.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecOCSPResponse.h (99%) rename {OSX/sec/securityd => trust/trustd}/SecPinningDb.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecPinningDb.m (96%) rename {OSX/sec/securityd => trust/trustd}/SecPolicyServer.c (97%) rename {OSX/sec/securityd => trust/trustd}/SecPolicyServer.h (97%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationDb.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationDb.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationNetworking.h (96%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationNetworking.m (100%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationServer.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecRevocationServer.h (95%) rename {OSX/sec/securityd => trust/trustd}/SecTrustExceptionResetCount.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecTrustExceptionResetCount.m (100%) rename {OSX/sec/securityd => trust/trustd}/SecTrustLoggingServer.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecTrustLoggingServer.m (100%) rename {OSX/sec/securityd => trust/trustd}/SecTrustServer.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecTrustServer.h (98%) rename {OSX/sec/securityd => trust/trustd}/SecTrustStoreServer.c (99%) rename {OSX/sec/securityd => trust/trustd}/SecTrustStoreServer.h (100%) rename {OSX/sec/securityd => trust/trustd}/SecTrustStoreServer.m (100%) rename {OSX/sec/securityd => trust/trustd}/TrustURLSessionDelegate.h (100%) rename {OSX/sec/securityd => trust/trustd}/TrustURLSessionDelegate.m (100%) rename {OSX => trust}/trustd/com.apple.trustd.asl (100%) rename {OSX => trust}/trustd/iOS/AppleCorporateRootCA.cer (100%) rename {OSX => trust}/trustd/iOS/AppleCorporateRootCA2.cer (100%) rename {OSX => trust}/trustd/iOS/com.apple.trustd.plist (100%) rename {OSX => trust}/trustd/iOS/entitlements.plist (100%) rename {OSX => trust}/trustd/macOS/SecTrustOSXEntryPoints.h (100%) rename {OSX => trust}/trustd/macOS/com.apple.trustd.agent.plist (100%) rename {OSX => trust}/trustd/macOS/com.apple.trustd.plist (100%) rename {OSX => trust}/trustd/macOS/com.apple.trustd.sb (100%) rename {OSX => trust}/trustd/macOS/entitlements.plist (100%) rename {OSX => trust}/trustd/macOS/trustd.8 (100%) rename {OSX/sec/securityd => trust/trustd}/nameconstraints.c (99%) rename {OSX/sec/securityd => trust/trustd}/nameconstraints.h (100%) rename {OSX/sec/securityd => trust/trustd}/personalization.c (100%) rename {OSX/sec/securityd => trust/trustd}/personalization.h (100%) rename {OSX/sec/securityd => trust/trustd}/policytree.c (100%) rename {OSX/sec/securityd => trust/trustd}/policytree.h (100%) rename {OSX => trust}/trustd/trustd-Info.plist (100%) rename {OSX => trust}/trustd/trustd-Prefix.pch (100%) rename {OSX => trust}/trustd/trustd.c (98%) rename {OSX => trust}/trustd/trustd_spi.c (88%) rename {OSX => trust}/trustd/trustd_spi.h (100%) diff --git a/CircleJoinRequested/CircleJoinRequested.m b/CircleJoinRequested/CircleJoinRequested.m index 2009f377..38e7c8ea 100644 --- a/CircleJoinRequested/CircleJoinRequested.m +++ b/CircleJoinRequested/CircleJoinRequested.m @@ -62,6 +62,7 @@ #include "utilities/SecAKSWrappers.h" #include "utilities/SecCFWrappers.h" #include +#import #import "CoreCDP/CDPFollowUpController.h" #import "CoreCDP/CDPFollowUpContext.h" @@ -561,13 +562,21 @@ static NSString *getLocalizedApplicationReminder() { return (__bridge_transfer NSString *) applicationReminder; } +static bool isSOSInternalDevice(void) { + static dispatch_once_t onceToken; + static BOOL internal = NO; + dispatch_once(&onceToken, ^{ + internal = os_variant_has_internal_diagnostics("com.apple.security"); + }); + return internal; +} static void postApplicationReminderAlert(NSDate *nowish, PersistentState *state, unsigned int alertInterval) { NSString *body = getLocalizedApplicationReminder(); bool has_iCSC = iCloudResetAvailable(); - if (CPIsInternalDevice() && + if (isSOSInternalDevice() && state.defaultPendingApplicationReminderAlertInterval != state.pendingApplicationReminderAlertInterval) { #ifdef DEBUG body = [body stringByAppendingFormat: @"〖debug interval %u; wait time %@〗", @@ -686,7 +695,7 @@ static void postKickedOutAlert(enum DepartureReason reason) break; } - if (CPIsInternalDevice()) { + if (isSOSInternalDevice()) { static const char *departureReasonStrings[] = { "kSOSDepartureReasonError", "kSOSNeverLeftCircle", @@ -758,6 +767,22 @@ static void postKickedOutAlert(enum DepartureReason reason) debugState = @"pKOA Z"; } +static void askForCDPFollowup() { + doOnceInMain(^{ + NSError *localError = nil; + CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; + CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; + [cdpd postFollowUpWithContext:context error:&localError ]; + if(localError){ + secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); + } + else{ + secnotice("cjr", "CoreCDP handling follow up"); + _hasPostedFollowupAndStillInError = true; + } + }); +} + static bool processEvents() { debugState = @"processEvents A"; @@ -805,49 +830,47 @@ static bool processEvents() } if(_isAccountICDP){ - if((circleStatus == kSOSCCError || circleStatus == kSOSCCCircleAbsent || circleStatus == kSOSCCNotInCircle) && _hasPostedFollowupAndStillInError == false) { - if(circleStatus == kSOSCCError) { - secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); - } - + state.lastCircleStatus = circleStatus; + [state writeToStorage]; + if(_hasPostedFollowupAndStillInError == true) { + secnotice("cjr", "followup not resolved"); + _executeProcessEventsOnce = true; + return false; + } + + switch(circleStatus) { + case kSOSCCInCircle: + secnotice("cjr", "follow up should be resolved"); + _executeProcessEventsOnce = true; + _hasPostedFollowupAndStillInError = false; + break; + case kSOSCCError: + secnotice("cjr", "error from SOSCCThisDeviceIsInCircle: %@", error); + askForCDPFollowup(); + _executeProcessEventsOnce = true; + return false; + case kSOSCCCircleAbsent: + case kSOSCCNotInCircle: /* - You would think we could count on not being iCDP if the account was signed out. Evidently that's wrong. - So we'll go based on the artifact that when the account object is reset (like by signing out) the - departureReason will be set to kSOSDepartureReasonError. So we won't push to get back into a circle if that's - the current reason. I've checked code for other ways we could be out. If we boot and can't load the account - we'll end up with kSOSDepartureReasonError. Then too if we end up in kSOSDepartureReasonError and reboot we end up - in the same place. Leave it to cdpd to decide whether the user needs to sign in to an account. + You would think we could count on not being iCDP if the account was signed out. Evidently that's wrong. + So we'll go based on the artifact that when the account object is reset (like by signing out) the + departureReason will be set to kSOSDepartureReasonError. So we won't push to get back into a circle if that's + the current reason. I've checked code for other ways we could be out. If we boot and can't load the account + we'll end up with kSOSDepartureReasonError. Then too if we end up in kSOSDepartureReasonError and reboot we end up + in the same place. Leave it to cdpd to decide whether the user needs to sign in to an account. */ if(departureReason != kSOSDepartureReasonError) { secnotice("cjr", "iCDP: We need to get back into the circle"); - doOnceInMain(^{ - NSError *localError = nil; - CDPFollowUpController *cdpd = [[CDPFollowUpController alloc] init]; - CDPFollowUpContext *context = [CDPFollowUpContext contextForStateRepair]; - [cdpd postFollowUpWithContext:context error:&localError ]; - if(localError){ - secnotice("cjr", "request to CoreCDP to follow up failed: %@", localError); - } - else{ - secnotice("cjr", "CoreCDP handling follow up"); - _hasPostedFollowupAndStillInError = true; - } - }); + askForCDPFollowup(); } else { secnotice("cjr", "iCDP: We appear to not be associated with an iCloud account"); } - state.lastCircleStatus = circleStatus; _executeProcessEventsOnce = true; return false; - } - else if(circleStatus == kSOSCCInCircle){ - secnotice("cjr", "follow up should be resolved"); - _executeProcessEventsOnce = true; - _hasPostedFollowupAndStillInError = false; - } - else{ - secnotice("cjr", "followup not resolved"); - _executeProcessEventsOnce = true; + case kSOSCCRequestPending: + break; + default: + secnotice("cjr", "Unknown circle status %d", circleStatus); return false; } } else if(circleStatus == kSOSCCError && state.lastCircleStatus != kSOSCCError && (departureReason == kSOSNeverLeftCircle)) { diff --git a/KeychainCircle/KCAccountKCCircleDelegate.h b/KeychainCircle/KCAccountKCCircleDelegate.h index 62e26e2e..3e1d3497 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.h +++ b/KeychainCircle/KCAccountKCCircleDelegate.h @@ -40,7 +40,7 @@ */ - (NSData*) circleJoinDataFor: (SOSPeerInfoRef) peer error: (NSError**) error; --(NSData*) circleGetInitialSyncViews: (NSError**) error; +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error; + (instancetype) delegate; diff --git a/KeychainCircle/KCAccountKCCircleDelegate.m b/KeychainCircle/KCAccountKCCircleDelegate.m index 71e86c63..a0fa541d 100644 --- a/KeychainCircle/KCAccountKCCircleDelegate.m +++ b/KeychainCircle/KCAccountKCCircleDelegate.m @@ -69,9 +69,9 @@ return (__bridge_transfer NSData*) result; } --(NSData*) circleGetInitialSyncViews: (NSError**) error{ +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{ CFErrorRef failure = NULL; - CFDataRef result = SOSCCCopyInitialSyncData(&failure); + CFDataRef result = SOSCCCopyInitialSyncData(flags, &failure); if (failure != NULL && error != nil) { *error = (__bridge_transfer NSError*) failure; } diff --git a/KeychainCircle/KCJoiningAcceptSession.m b/KeychainCircle/KCJoiningAcceptSession.m index 743b60e3..01285024 100644 --- a/KeychainCircle/KCJoiningAcceptSession.m +++ b/KeychainCircle/KCJoiningAcceptSession.m @@ -42,8 +42,8 @@ typedef enum { @interface KCJoiningAcceptSession () @property (readonly) uint64_t dsid; -@property (readonly) NSObject* secretDelegate; -@property (readonly) NSObject* circleDelegate; +@property (weak) id secretDelegate; +@property (weak) id circleDelegate; @property (readonly) KCSRPServerContext* context; @property (readonly) KCAESGCMDuplexSession* session; @property (readonly) KCJoiningAcceptSessionState state; @@ -114,8 +114,8 @@ typedef enum { digestInfo: ccsha256_di() group: ccsrp_gp_rfc5054_3072() randomSource: rng]; - self->_secretDelegate = secretDelegate; - self->_circleDelegate = circleDelegate; + self.secretDelegate = secretDelegate; + self.circleDelegate = circleDelegate; self->_state = kExpectingA; self->_dsid = dsid; self->_piggy_uuid = nil; @@ -273,25 +273,27 @@ typedef enum { return nil; } + id secretDelegate = self.secretDelegate; + // We handle failure, don't capture the error. NSData* confirmation = [self.context copyConfirmationFor:message.firstData error:NULL]; if (!confirmation) { // Find out what kind of error we should send. NSData* errorData = nil; - KCRetryOrNot status = [self.secretDelegate verificationFailed: error]; + KCRetryOrNot status = [secretDelegate verificationFailed: error]; secerror("processResponse: handle error: %d", (int)status); switch (status) { case kKCRetryError: // We fill in an error if they didn't, but if they did this wont bother. - KCJoiningErrorCreate(kInternalError, error, @"Delegate returned error without filling in error: %@", self.secretDelegate); + KCJoiningErrorCreate(kInternalError, error, @"Delegate returned error without filling in error: %@", secretDelegate); return nil; case kKCRetryWithSameChallenge: errorData = [NSData data]; break; case kKCRetryWithNewChallenge: - if ([self.context resetWithPassword:[self.secretDelegate secret] error:error]) { + if ([self.context resetWithPassword:[secretDelegate secret] error:error]) { errorData = [self copyChallengeMessage: error]; } break; @@ -303,7 +305,7 @@ typedef enum { error:error] der]; } - NSData* encoded = [NSData dataWithEncodedString:[self.secretDelegate accountCode] error:error]; + NSData* encoded = [NSData dataWithEncodedString:[secretDelegate accountCode] error:error]; if (encoded == nil) return nil; @@ -323,6 +325,8 @@ typedef enum { NSData* decryptedPayload = [self.session decryptAndVerify:message error:error]; if (decryptedPayload == nil) return nil; + id circleDelegate = self.circleDelegate; + CFErrorRef cfError = NULL; SOSPeerInfoRef ref = SOSPeerInfoCreateFromData(NULL, &cfError, (__bridge CFDataRef) decryptedPayload); if (ref == NULL) { @@ -331,7 +335,7 @@ typedef enum { return nil; } - NSData* joinData = [self.circleDelegate circleJoinDataFor:ref error:error]; + NSData* joinData = [circleDelegate circleJoinDataFor:ref error:error]; if(ref) { CFRelease(ref); ref = NULL; @@ -339,13 +343,26 @@ typedef enum { if (joinData == nil) return nil; - if(self->_piggy_version == kPiggyV1){ + SOSInitialSyncFlags flags = 0; + switch (self.piggy_version) { + case kPiggyV0: + break; + case kPiggyV1: + secnotice("acceptor", "piggy version is 1"); + flags |= kSOSInitialSyncFlagTLKs | kSOSInitialSyncFlagiCloudIdentity; + break; + case kPiggyV2: + secnotice("acceptor", "piggy version is 2"); + flags |= kSOSInitialSyncFlagiCloudIdentity; + break; + } + + if (flags) { //grab iCloud Identities, TLKs - secnotice("acceptor", "piggy version is 1"); - NSError *localV1Error = nil; - NSData* initialSyncData = [self.circleDelegate circleGetInitialSyncViews:&localV1Error]; - if(localV1Error){ - secnotice("piggy", "PB v1 threw an error: %@", localV1Error); + NSError *localISVError = nil; + NSData* initialSyncData = [circleDelegate circleGetInitialSyncViews:flags error:&localISVError]; + if(initialSyncData == NULL){ + secnotice("piggy", "PB threw an error: %@", localISVError); } NSMutableData* growPacket = [[NSMutableData alloc] initWithData:joinData]; diff --git a/KeychainCircle/KCJoiningRequestSecretSession.m b/KeychainCircle/KCJoiningRequestSecretSession.m index f251465c..2cb52bcf 100644 --- a/KeychainCircle/KCJoiningRequestSecretSession.m +++ b/KeychainCircle/KCJoiningRequestSecretSession.m @@ -61,7 +61,7 @@ bool KCJoiningOctagonPiggybackingEnabled() { @interface KCJoiningRequestSecretSession () -@property (readonly) NSObject* secretDelegate; +@property (weak) id secretDelegate; @property (readonly) KCSRPClientContext* context; @property (readonly) uint64_t dsid; @property (readonly) KCJoiningRequestSecretSessionState state; @@ -245,9 +245,11 @@ bool KCJoiningOctagonPiggybackingEnabled() { - (NSData*) handleVerification: (KCJoiningMessage*) message error: (NSError**) error { secnotice("joining", "joining: KCJoiningRequestSecretSession handleVerification called"); + id secretDelegate = self.secretDelegate; + if ([message type] == kError) { bool newCode = [[message firstData] length] == 0; - NSString* nextSecret = [self.secretDelegate verificationFailed: newCode]; + NSString* nextSecret = [secretDelegate verificationFailed: newCode]; if (nextSecret) { if (newCode) { @@ -279,7 +281,7 @@ bool KCJoiningOctagonPiggybackingEnabled() { NSString* accountCode = [NSString decodeFromDER:payload error:error]; if (accountCode == nil) return nil; - if (![self.secretDelegate processAccountCode:accountCode error:error]) return nil; + if (![secretDelegate processAccountCode:accountCode error:error]) return nil; } self->_state = kRequestSecretDone; diff --git a/KeychainCircle/KCJoiningSession.h b/KeychainCircle/KCJoiningSession.h index f94064a0..dd0d61c4 100644 --- a/KeychainCircle/KCJoiningSession.h +++ b/KeychainCircle/KCJoiningSession.h @@ -138,7 +138,7 @@ NS_ASSUME_NONNULL_BEGIN @result Data blob contains tlks, icloud identities, and backupv0 */ --(NSData*) circleGetInitialSyncViews: (NSError**) error; +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error; @end typedef enum { diff --git a/KeychainCircle/PairingChannel.m b/KeychainCircle/PairingChannel.m index e2d2b677..b65d3f6b 100644 --- a/KeychainCircle/PairingChannel.m +++ b/KeychainCircle/PairingChannel.m @@ -273,16 +273,25 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE; return; } - if(OctagonIsEnabled() && self.sessionSupportsOctagon && !self.testFailOctagon) { + if(self.sessionSupportsOctagon && self.sessionSupportsSOS && !self.testFailOctagon) { __weak typeof(self) weakSelf = self; self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; }; complete(false, @{ @"d" : @YES, @"o" : @{@"v" : @"O"} }, NULL); - } else if (OctagonIsEnabled() && self.testFailOctagon) { + return; + } else if (self.sessionSupportsOctagon && self.testFailOctagon) { complete(true, nil, NULL); return; - } else { + } else if (self.sessionSupportsOctagon && !self.sessionSupportsSOS) { + __weak typeof(self) weakSelf = self; + self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ + [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; + }; + complete(false, @{ @"o" : @{@"v" : @"O"} }, NULL); + return; + } + else { __weak typeof(self) weakSelf = self; self.nextState = ^(NSDictionary *nsdata, KCPairingInternalCompletion kscomplete){ [weakSelf initiatorSecondPacket:nsdata complete:kscomplete]; diff --git a/KeychainCircle/Tests/KCJoiningSessionTest.m b/KeychainCircle/Tests/KCJoiningSessionTest.m index a8919e9d..a3d71d0f 100644 --- a/KeychainCircle/Tests/KCJoiningSessionTest.m +++ b/KeychainCircle/Tests/KCJoiningSessionTest.m @@ -254,7 +254,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) { return [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ]; } --(NSData*) circleGetInitialSyncViews: (NSError**) error{ +-(NSData*) circleGetInitialSyncViews:(SOSInitialSyncFlags)flags error:(NSError**) error{ return [NSData data]; } diff --git a/OSX/authd/authorization.plist b/OSX/authd/authorization.plist index 2b135078..2a1930aa 100644 --- a/OSX/authd/authorization.plist +++ b/OSX/authd/authorization.plist @@ -857,7 +857,9 @@ See remaining rules for examples. shared timeout - 300 + 900 + version + 2 system.install.software.iap diff --git a/OSX/config/security_framework_macos.xcconfig b/OSX/config/security_framework_macos.xcconfig index 6aa60fd8..b9708656 100644 --- a/OSX/config/security_framework_macos.xcconfig +++ b/OSX/config/security_framework_macos.xcconfig @@ -26,7 +26,7 @@ APPLY_RULES_IN_COPY_FILES = NO // Adding things here is against the spirit of TAPI. If something is in the framework, it should be in the framework headers. // Don't add things. -OTHER_TAPI_FLAGS_TRUST = -extra-private-header $(PROJECT_DIR)/OSX/trustd/macOS/SecTrustOSXEntryPoints.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecCertificateInternal.h +OTHER_TAPI_FLAGS_TRUST = -extra-private-header $(PROJECT_DIR)/trust/trustd/macOS/SecTrustOSXEntryPoints.h -extra-private-header $(PROJECT_DIR)/OSX/sec/Security/SecCertificateInternal.h OTHER_TAPI_FLAGS_USR_LIB_HEADERS = -extra-private-header $(PROJECT_DIR)/OSX/utilities/debugging.h OTHER_TAPI_FLAGS_HACKS = -exclude-public-header $(BUILT_PRODUCTS_DIR)/Security.framework/Versions/A/Headers/AuthorizationPlugin.h -extra-public-header $(PROJECT_DIR)/OSX/macos_tapi_hacks.h -extra-public-header $(PROJECT_DIR)/OSX/sec/Security/SecItemShim.h -D SECURITY_PROJECT_TAPI_HACKS=1 diff --git a/OSX/libsecurity_keychain/lib/Item.cpp b/OSX/libsecurity_keychain/lib/Item.cpp index 474aba73..4d4dc772 100644 --- a/OSX/libsecurity_keychain/lib/Item.cpp +++ b/OSX/libsecurity_keychain/lib/Item.cpp @@ -1526,7 +1526,7 @@ ItemImpl::getAttributesAndData(SecKeychainAttributeInfo *info, SecItemClass *ite theList->count = 0; theList->attr = NULL; } else { - SecKeychainAttribute *attr=reinterpret_cast(malloc(sizeof(SecKeychainAttribute)*attrCount)); + SecKeychainAttribute *attr=reinterpret_cast(calloc(attrCount, sizeof(SecKeychainAttribute))); theList->count=attrCount; theList->attr=attr; diff --git a/OSX/libsecurity_keychain/lib/SecItem.cpp b/OSX/libsecurity_keychain/lib/SecItem.cpp index 40122c76..b1b571c2 100644 --- a/OSX/libsecurity_keychain/lib/SecItem.cpp +++ b/OSX/libsecurity_keychain/lib/SecItem.cpp @@ -539,6 +539,12 @@ _ConvertNewFormatToOldFormat( SecKeychainAttributeList* &attrList ) { + // make storage to extract the dictionary items + CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); + if (itemsInDictionary > 10000) { + return errSecParam; + } + // get the keychain attributes array from the data item // here's the problem. On the one hand, we have a dictionary that is purported to contain // attributes for our type. On the other hand, the dictionary may contain items we don't support, @@ -547,8 +553,6 @@ _ConvertNewFormatToOldFormat( // setup the return attrList = (SecKeychainAttributeList*) calloc(1, sizeof(SecKeychainAttributeList)); - // make storage to extract the dictionary items - CFIndex itemsInDictionary = CFDictionaryGetCount(dictionaryRef); std::vector keys(itemsInDictionary); std::vector values(itemsInDictionary); @@ -592,7 +596,7 @@ _ConvertNewFormatToOldFormat( if(count == 0) { attrList->attr = NULL; } else { - attrList->attr = (SecKeychainAttribute*) malloc(sizeof(SecKeychainAttribute) * count); + attrList->attr = (SecKeychainAttribute*) calloc(count, sizeof(SecKeychainAttribute)); // fill out the array int resultPointer = 0; @@ -2362,7 +2366,7 @@ _ReplaceKeychainItem( // make attribute list for new item (the data is still owned by attrList) newAttrList.count = attrList->count; - newAttrList.attr = (SecKeychainAttribute *) malloc(sizeof(SecKeychainAttribute) * attrList->count); + newAttrList.attr = (SecKeychainAttribute *) calloc(attrList->count, sizeof(SecKeychainAttribute)); int i, newCount; for (i=0, newCount=0; i < attrList->count; i++) { if (attrList->attr[i].length > 0) { diff --git a/OSX/libsecurity_keychain/lib/SecKey.cpp b/OSX/libsecurity_keychain/lib/SecKey.cpp index 1495ca1d..7ef6027b 100644 --- a/OSX/libsecurity_keychain/lib/SecKey.cpp +++ b/OSX/libsecurity_keychain/lib/SecKey.cpp @@ -863,9 +863,9 @@ namespace Security { } } } else { - cdsaKey = SecKeyCreateFromData(keyAttributes, keyData, NULL); + cdsaKey.take(SecKeyCreateFromData(keyAttributes, keyData, NULL)); if (cdsaKey) { - SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.retain()); + SecKeySetAuxilliaryCDSAKeyForKey(key, cdsaKey.get()); } } } diff --git a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp index 0ce7406d..3d64c65d 100644 --- a/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp +++ b/OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp @@ -26,7 +26,7 @@ * Framework. */ -#include "OSX/trustd/macOS/SecTrustOSXEntryPoints.h" +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" #include #include diff --git a/OSX/libsecurity_keychain/lib/TokenLogin.cpp b/OSX/libsecurity_keychain/lib/TokenLogin.cpp index 77b27a02..347d007b 100644 --- a/OSX/libsecurity_keychain/lib/TokenLogin.cpp +++ b/OSX/libsecurity_keychain/lib/TokenLogin.cpp @@ -119,7 +119,7 @@ static CFDataRef getPubKeyHashWrap(CFDictionaryRef context) return pubKeyHashWrap; } -static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey, CFTypeRef *laCtx) +static OSStatus privKeyForPubKeyHashWrap(CFDictionaryRef context, SecKeyRef *privKey, CFTypeRef *laCtx) { if (!context) { os_log_error(TL_LOG, "private key for pubkeyhash wrong params"); @@ -133,14 +133,14 @@ static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey if (pin) { CFRef LAContext = LACreateNewContextWithACMContext(NULL, error.take()); if (!LAContext) { - os_log_error(TL_LOG, "Failed to LA Context: %@", error.get()); + os_log_error(TL_LOG, "Failed to LA Context: %{public}@", error.get()); return errSecParam; } if (laCtx) *laCtx = (CFTypeRef)CFRetain(LAContext); CFRef externalizedContext = LACopyACMContext(LAContext, error.take()); if (!externalizedContext) { - os_log_error(TL_LOG, "Failed to get externalized context: %@", error.get()); + os_log_error(TL_LOG, "Failed to get externalized context: %{public}@", error.get()); return errSecParam; } CFDictionarySetValue(tokenAttributes, kSecUseCredentialReference, externalizedContext.get()); @@ -149,13 +149,13 @@ static OSStatus privKeyForPubKeyHash(CFDictionaryRef context, SecKeyRef *privKey CFRef token = TKTokenCreate(tokenAttributes, error.take()); if (!token) { - os_log_error(TL_LOG, "Failed to create token: %@", error.get()); + os_log_error(TL_LOG, "Failed to create token: %{public}@", error.get()); return errSecParam; } CFRef identities = TKTokenCopyIdentities(token, TKTokenKeyUsageAny, error.take()); if (!identities || !CFArrayGetCount(identities)) { - os_log_error(TL_LOG, "No identities found for token: %@", error.get()); + os_log_error(TL_LOG, "No identities found for token: %{public}@", error.get()); return errSecParam; } @@ -218,12 +218,12 @@ OSStatus TokenLoginGetContext(const void *base64TokenLoginData, UInt32 base64Tok NULL, error.take()); if (!*context || CFGetTypeID(*context) != CFDictionaryGetTypeID()) { - os_log_error(TL_LOG, "Invalid token login data property list, %@", error.get()); + os_log_error(TL_LOG, "Invalid token login data property list, %{public}@", error.get()); return errSecParam; } if (!getPin(*context) || !getTokenId(*context) || !getPubKeyHash(*context) || !getPubKeyHashWrap(*context)) { - os_log_error(TL_LOG, "Invalid token login data context, %@", error.get()); + os_log_error(TL_LOG, "Invalid token login data context, %{public}@", error.get()); return errSecParam; } @@ -236,8 +236,8 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) os_log_error(TL_LOG, "Get unlock key - wrong params"); return errSecParam; } - - CFRef loginData; + + CFRef loginData; OSStatus result = TokenLoginGetLoginData(context, loginData.take()); if (result != errSecSuccess) { os_log_error(TL_LOG, "Failed to get login data: %d", (int)result); @@ -254,12 +254,23 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) os_log_error(TL_LOG, "Algorithm not found in unlock key data"); return errSecParam; } + CFDataRef pubKeyHashWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); + if (pubKeyHashWrapFromPlist == NULL) { + os_log_error(TL_LOG, "Failed to get wrapkey for unlock key data"); + return errSecInternal; + } + CFRef ctx = makeCFDictionary(3, + kSecAttrTokenID, getTokenId(context), + kSecAttrService, getPin(context), + kSecAttrAccount, pubKeyHashWrapFromPlist + ); + CFRef privKey; CFRef LAContext; - result = privKeyForPubKeyHash(context, privKey.take(), LAContext.take()); + result = privKeyForPubKeyHashWrap(ctx, privKey.take(), LAContext.take()); if (result != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int)result); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist, (int)result); return result; } @@ -274,14 +285,14 @@ OSStatus TokenLoginGetUnlockKey(CFDictionaryRef context, CFDataRef *unlockKey) wrappedUnlockKey, error.take()); if (!*unlockKey) { - os_log_error(TL_LOG, "Failed to unwrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to unwrap unlock key: %{public}@", error.get()); return errSecDecode; } // we need to re-wrap already unwrapped data to avoid capturing and reusing communication with the smartcard CFRef reWrappedUnlockKey = SecKeyCreateEncryptedData(pubKey, algorithm, *unlockKey, error.take()); if (!reWrappedUnlockKey) { - os_log_error(TL_LOG, "Failed to rewrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to rewrap unlock key: %{public}@", error.get()); TokenLoginDeleteUnlockData(getPubKeyHash(context)); return errSecParam; } @@ -319,7 +330,7 @@ OSStatus TokenLoginGetLoginData(CFDictionaryRef context, CFDictionaryRef *loginD NULL, error.take()); if (!*loginData || CFGetTypeID(*loginData) != CFDictionaryGetTypeID()) { - os_log_error(TL_LOG, "Failed to deserialize unlock key data: %@", error.get()); + os_log_error(TL_LOG, "Failed to deserialize unlock key data: %{public}@", error.get()); return errSecParam; } @@ -366,9 +377,9 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF kSecAttrAccount, pubKeyHashWrap ); CFRef privKey; - OSStatus result = privKeyForPubKeyHash(ctx, privKey.take(), NULL); + OSStatus result = privKeyForPubKeyHashWrap(ctx, privKey.take(), NULL); if (result != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int) result); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap, (int)result); return result; } @@ -407,7 +418,7 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF CFRef error; CFRef wrappedUnlockKey = SecKeyCreateEncryptedData(pubKey, algorithm, unlockKey, error.take()); if (!wrappedUnlockKey) { - os_log_error(TL_LOG, "Failed to wrap unlock key: %@", error.get()); + os_log_error(TL_LOG, "Failed to wrap unlock key: %{public}@", error.get()); return errSecParam; } @@ -422,7 +433,7 @@ OSStatus TokenLoginCreateLoginData(CFStringRef tokenId, CFDataRef pubKeyHash, CF OSStatus TokenLoginStoreUnlockData(CFDictionaryRef context, CFDictionaryRef loginData) { - os_log(TL_LOG, "Storing unlock data"); + os_log_debug(TL_LOG, "Storing unlock data"); CFRef error; CFRef data = CFPropertyListCreateData(kCFAllocatorDefault, @@ -431,24 +442,24 @@ OSStatus TokenLoginStoreUnlockData(CFDictionaryRef context, CFDictionaryRef logi 0, error.take()); if (!data) { - os_log_error(TL_LOG, "Failed to create unlock data: %@", error.get()); + os_log_error(TL_LOG, "Failed to create unlock data: %{public}@", error.get()); return errSecInternal; } CFRef pubKeyHashHex = cfDataToHex(getPubKeyHash(context)); - os_log(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); + os_log_debug(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); CFPreferencesSetValue(pubKeyHashHex, data, kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - os_log(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); + os_log_debug(TL_LOG, "Pubkeyhash %@", pubKeyHashHex.get()); CFPreferencesSynchronize(kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); CFRef storedData = (CFDataRef)CFPreferencesCopyValue(pubKeyHashHex, kSecTokenLoginDomain, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); - os_log(TL_LOG, "Stored data %@", storedData.get()); + os_log_debug(TL_LOG, "Stored data %@", storedData.get()); if (!storedData || !CFEqual(storedData, data)) { os_log_error(TL_LOG, "Failed to write token login plist"); return errSecIO; } - os_log(TL_LOG, "Original data %@. Everything is OK", data.get()); + os_log_debug(TL_LOG, "Original data %@. Everything is OK", data.get()); return errSecSuccess; } @@ -481,9 +492,9 @@ OSStatus TokenLoginGetScBlob(CFDataRef pubKeyHashWrap, CFStringRef tokenId, CFSt ); CFRef privKey; - OSStatus retval = privKeyForPubKeyHash(ctx, privKey.take(), NULL); + OSStatus retval = privKeyForPubKeyHashWrap(ctx, privKey.take(), NULL); if (retval != errSecSuccess) { - os_log_error(TL_LOG, "TokenLoginGetScBlob failed to get private key for public key hash: %d", (int) retval); + os_log_error(TL_LOG, "TokenLoginGetScBlob failed to get private key for public key hash %{public}@: %d", pubKeyHashWrap, (int)retval); return retval; } @@ -556,25 +567,24 @@ OSStatus TokenLoginUnlockKeybag(CFDictionaryRef context, CFDictionaryRef loginDa return errSecInternal; } - CFDataRef pubKeyWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); - if (pubKeyWrapFromPlist == NULL) { + CFDataRef pubKeyHashWrapFromPlist = (CFDataRef)CFDictionaryGetValue(loginData, kSecAttrPublicKeyHash); + if (pubKeyHashWrapFromPlist == NULL) { os_log_error(TL_LOG, "Failed to get wrapkey"); return errSecInternal; } - CFRef ctx = makeCFDictionary(4, + CFRef ctx = makeCFDictionary(3, kSecAttrTokenID, getTokenId(context), kSecAttrService, getPin(context), - kSecAttrPublicKeyHash, getPubKeyHash(context), - kSecAttrAccount, pubKeyWrapFromPlist + kSecAttrAccount, pubKeyHashWrapFromPlist ); CFRef error; CFRef privKey; CFRef LAContext; - OSStatus retval = privKeyForPubKeyHash(ctx, privKey.take(), LAContext.take()); + OSStatus retval = privKeyForPubKeyHashWrap(ctx, privKey.take(), LAContext.take()); if (retval != errSecSuccess) { - os_log_error(TL_LOG, "Failed to get private key for public key hash: %d", (int) retval); + os_log_error(TL_LOG, "Failed to get private key for public key hash %{public}@: %d", pubKeyHashWrapFromPlist, (int)retval); return retval; } diff --git a/OSX/libsecurity_smime/lib/cmssiginfo.c b/OSX/libsecurity_smime/lib/cmssiginfo.c index 470b6098..3a83746d 100644 --- a/OSX/libsecurity_smime/lib/cmssiginfo.c +++ b/OSX/libsecurity_smime/lib/cmssiginfo.c @@ -58,6 +58,7 @@ #include #include #include +#include #include "tsaSupport.h" #include "tsaSupportPriv.h" @@ -93,104 +94,60 @@ static OSStatus DER_UTCTimeToCFDate(const CSSM_DATA_PTR utcTime, CFAbsoluteTime *date) { - CFGregorianDate gdate; - char *string = (char *)utcTime->Data; - long year, month, mday, hour, minute, second, hourOff, minOff; - CFTimeZoneRef timeZone; - - /* Verify time is formatted properly and capture information */ - second = 0; - hourOff = 0; - minOff = 0; - CAPTURE(year,string+0,loser); - if (year < 50) { - /* ASSUME that year # is in the 2000's, not the 1900's */ - year += 100; - } - CAPTURE(month,string+2,loser); - if ((month == 0) || (month > 12)) goto loser; - CAPTURE(mday,string+4,loser); - if ((mday == 0) || (mday > 31)) goto loser; - CAPTURE(hour,string+6,loser); - if (hour > 23) goto loser; - CAPTURE(minute,string+8,loser); - if (minute > 59) goto loser; - if (ISDIGIT(string[10])) { - CAPTURE(second,string+10,loser); - if (second > 59) goto loser; - string += 2; - } - if (string[10] == '+') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - } else if (string[10] == '-') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - hourOff = -hourOff; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - minOff = -minOff; - } else if (string[10] != 'Z') { - goto loser; + CFErrorRef error = NULL; + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + CFAbsoluteTime result = SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME, utcTime->Data, utcTime->Length, &error); + if (error) { + CFReleaseNull(error); + return SECFailure; } - gdate.year = (SInt32)(year + 1900); - gdate.month = month; - gdate.day = mday; - gdate.hour = hour; - gdate.minute = minute; - gdate.second = second; - - if (hourOff == 0 && minOff == 0) - timeZone = NULL; /* GMT */ - else - { - timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, (hourOff * 60 + minOff) * 60); + if (date) { + *date = result; } - - *date = CFGregorianDateGetAbsoluteTime(gdate, timeZone); - if (timeZone) - CFRelease(timeZone); - return SECSuccess; - -loser: - return SECFailure; } static OSStatus DER_CFDateToUTCTime(CFAbsoluteTime date, CSSM_DATA_PTR utcTime) { - CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(date, NULL /* GMT */); unsigned char *d; - SInt8 second; utcTime->Length = 13; utcTime->Data = d = PORT_Alloc(13); - if (!utcTime->Data) - return SECFailure; + if (!utcTime->Data) { + return SECFailure; + } - /* UTC time does not handle the years before 1950 */ - if (gdate.year < 1950) - return SECFailure; + __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; + __block bool result; + SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { + result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second); + }); + if (!result) { + return SECFailure; + } + + /* UTC time does not handle the years before 1950 or after 2049 */ + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + if (year < 1950 || year > 2049) { + return SECFailure; + } /* remove the century since it's added to the year by the CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */ - gdate.year %= 100; - second = gdate.second + 0.5; - - d[0] = HIDIGIT(gdate.year); - d[1] = LODIGIT(gdate.year); - d[2] = HIDIGIT(gdate.month); - d[3] = LODIGIT(gdate.month); - d[4] = HIDIGIT(gdate.day); - d[5] = LODIGIT(gdate.day); - d[6] = HIDIGIT(gdate.hour); - d[7] = LODIGIT(gdate.hour); - d[8] = HIDIGIT(gdate.minute); - d[9] = LODIGIT(gdate.minute); + year %= 100; + + d[0] = HIDIGIT(year); + d[1] = LODIGIT(year); + d[2] = HIDIGIT(month); + d[3] = LODIGIT(month); + d[4] = HIDIGIT(day); + d[5] = LODIGIT(day); + d[6] = HIDIGIT(hour); + d[7] = LODIGIT(hour); + d[8] = HIDIGIT(minute); + d[9] = LODIGIT(minute); d[10] = HIDIGIT(second); d[11] = LODIGIT(second); d[12] = 'Z'; diff --git a/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m b/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m index 795b0f29..adaa8a98 100644 --- a/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m +++ b/OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m @@ -224,7 +224,7 @@ static OSStatus securetransport(ssl_test_handle * ssl) SecTrustResultType trust_result = 0; /* this won't verify without setting up a trusted anchor */ require_noerr(SecTrustEvaluate(trust, &trust_result), out); - require((trust_result == kSecTrustResultUnspecified), out); + require((trust_result == kSecTrustResultUnspecified || trust_result == kSecTrustResultProceed), out); } } while (ortn == errSSLWouldBlock diff --git a/OSX/regressions/test/testenv.m b/OSX/regressions/test/testenv.m index ac5096d2..8692ff3c 100644 --- a/OSX/regressions/test/testenv.m +++ b/OSX/regressions/test/testenv.m @@ -62,7 +62,7 @@ int test_check_leaks = 0; char **test_skip_leaks_test = NULL; #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" static int current_dir = -1; static char scratch_dir[50]; diff --git a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c index 13a902fa..c6bfdcfa 100644 --- a/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c +++ b/OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c @@ -391,7 +391,7 @@ static void tests(void) SecTrustResultType trustResult; CFArrayRef properties = NULL; properties = SecTrustCopyProperties(trust); -#if TARGET_OS_IPHONE +#if TARGET_OS_IPHONE // Note: OS X will trigger the evaluation in order to return the properties. is(properties, NULL, "no properties returned before eval"); #endif @@ -407,8 +407,15 @@ static void tests(void) print_cert(wwdr_intermediate, false); } #endif - CFReleaseNull(properties); + // verify wrapper functions are available + properties = SecCertificateCopyProperties(leaf); + isnt(properties, NULL, "leaf properties returned"); + CFReleaseNull(properties); + properties = SecCertificateCopyLocalizedProperties(leaf, true); + isnt(properties, NULL, "localized leaf properties returned"); + CFReleaseNull(properties); + CFReleaseNull(trust); CFReleaseNull(wwdr_intermediate); CFReleaseNull(leaf); @@ -420,10 +427,10 @@ static void tests(void) int si_26_sectrust_copyproperties(int argc, char *const *argv) { #if TARGET_OS_IPHONE - plan_tests(8); + plan_tests(10); #else // - plan_tests(7); + plan_tests(9); #endif diff --git a/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c b/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c index e28fcf59..a5e11478 100644 --- a/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c +++ b/OSX/sec/Security/Regressions/secitem/si-30-keychain-upgrade.c @@ -34,7 +34,7 @@ #include #include "Security_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" /* TODO: This test needs to be updated. It was originally created to test upgrades from DB prior to the introduction of versionning, circa 2008. We don't support upgrading from that old of keychain, but this test should be upgraded to test upgrades from v5 to v6 keychain, or more current diff --git a/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c b/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c index 05fc5bb3..1be9af7f 100644 --- a/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c +++ b/OSX/sec/Security/Regressions/secitem/si-31-keychain-bad.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c b/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c index ecff54fc..0760e00d 100644 --- a/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c +++ b/OSX/sec/Security/Regressions/secitem/si-31-keychain-unreadable.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c index 258e5895..6e7b25d2 100644 --- a/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c +++ b/OSX/sec/Security/Regressions/secitem/si-33-keychain-backup.c @@ -24,7 +24,7 @@ #include -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include diff --git a/OSX/sec/Security/Regressions/secitem/si-60-cms.c b/OSX/sec/Security/Regressions/secitem/si-60-cms.c index 7a90e5fa..6a294a7a 100644 --- a/OSX/sec/Security/Regressions/secitem/si-60-cms.c +++ b/OSX/sec/Security/Regressions/secitem/si-60-cms.c @@ -44,8 +44,6 @@ #include "shared_regressions.h" -#define VERBOSE_ERRORS 1 - /* Bag Attributes friendlyName: uranusLeaf @@ -1746,18 +1744,7 @@ static void tests(void) ok_status(SecCMSSignDataAndAttributes(identity, test_data, false, message_data, simple_attr), "encode message"); ok_status(SecCMSVerifyCopyDataAndAttributes(message_data, NULL, policy, &trust, &message, &attrs), "decode message again"); CFReleaseNull(trust); -#if VERBOSE_ERRORS - size_t message_len = CFDataGetLength(message_data); - const uint8_t* message_ptr = CFDataGetBytePtr(message_data); - char *message_hex = (char *)calloc(1, 2 * message_len + 1); - for (size_t ix = 0; ix < message_len; ix++) { - snprintf(&message_hex[2*ix], 3, "%02X", message_ptr[ix]); - } - is(CFDictionaryGetCount(attrs), 6, "5 signed attributes + cooked date. \n\tattrs=%@\tmessage_data=%s", attrs, message_hex); - free(message_hex); -#else is(CFDictionaryGetCount(attrs), 6, "5 signed attributes + cooked date"); -#endif isnt(CFDictionaryGetValue(attrs, kSecCMSSignDate), NULL, "failed to get cooked data from attributes"); isnt(CFDictionaryGetValue(attrs, kSecCMSAllCerts), NULL, "failed to get cert(s) from attributes"); isnt(CFDictionaryGetValue(attrs, oid_data), NULL, "failed to get user-defined attribute"); @@ -1952,16 +1939,120 @@ out: CFReleaseNull(recipients); } +const uint8_t _sixty_seconds_message[] = { + 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, + 0x80, 0x02, 0x01, 0x01, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, + 0x24, 0x80, 0x04, 0x08, 0x68, 0x6f, 0x69, 0x20, 0x6a, 0x6f, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa0, 0x82, 0x02, 0xe4, 0x30, 0x82, 0x02, 0xe0, 0x30, 0x82, 0x01, 0xc8, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x07, + 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x40, 0x70, 0x6c, + 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x35, 0x31, 0x32, 0x31, + 0x37, 0x30, 0x30, 0x30, 0x34, 0x32, 0x35, 0x5a, 0x17, 0x0d, 0x30, 0x36, 0x31, 0x32, 0x31, 0x37, + 0x30, 0x30, 0x30, 0x34, 0x32, 0x35, 0x5a, 0x30, 0x37, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x0a, 0x75, 0x72, 0x61, 0x6e, 0x75, 0x73, 0x4c, 0x65, 0x61, 0x66, 0x31, 0x20, + 0x30, 0x1e, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x11, 0x75, + 0x72, 0x61, 0x6e, 0x75, 0x73, 0x40, 0x75, 0x72, 0x61, 0x6e, 0x75, 0x73, 0x2e, 0x63, 0x6f, 0x6d, + 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, 0xa6, 0x82, 0x8e, 0xc6, 0x7e, 0xc9, 0x8c, 0x99, 0x6f, 0xb0, 0x62, 0x32, 0x35, 0xe7, 0xdb, + 0xff, 0x34, 0x84, 0xdc, 0x72, 0xa8, 0xef, 0x22, 0x6f, 0x93, 0x63, 0x64, 0x80, 0x80, 0x5d, 0x50, + 0x7e, 0xb4, 0x2e, 0x1b, 0x93, 0x93, 0x49, 0xca, 0xae, 0xcd, 0x34, 0x44, 0x4b, 0xd7, 0xfa, 0x9f, + 0x3c, 0xfc, 0x9e, 0x65, 0xa9, 0xfb, 0x5e, 0x5d, 0x18, 0xa3, 0xf8, 0xb0, 0x08, 0xac, 0x8f, 0xfd, + 0x03, 0xcb, 0xbd, 0x7f, 0xa0, 0x2a, 0xa6, 0xea, 0xca, 0xa3, 0x24, 0xef, 0x7c, 0xc3, 0xeb, 0x95, + 0xcb, 0x90, 0x3f, 0x5e, 0xde, 0x78, 0xf2, 0x3d, 0x32, 0x72, 0xdb, 0x33, 0x6e, 0x9b, 0x52, 0x9f, + 0x0c, 0x60, 0x4a, 0x24, 0xa1, 0xf6, 0x3b, 0x80, 0xbd, 0xa1, 0xdc, 0x40, 0x03, 0xe7, 0xa0, 0x59, + 0x1f, 0xdb, 0xb4, 0xed, 0x57, 0xdc, 0x74, 0x0d, 0x99, 0x5a, 0x12, 0x74, 0x64, 0xaa, 0xb6, 0xa5, + 0x96, 0x75, 0xf9, 0x42, 0x43, 0xe2, 0x52, 0xc2, 0x57, 0x23, 0x75, 0xd7, 0xa9, 0x4f, 0x07, 0x32, + 0x99, 0xbd, 0x3d, 0x44, 0xbd, 0x04, 0x62, 0xe5, 0xb7, 0x2c, 0x0c, 0x11, 0xc5, 0xb2, 0x2e, 0xc4, + 0x12, 0x1d, 0x7f, 0x42, 0x1e, 0x71, 0xaf, 0x39, 0x2b, 0x78, 0x47, 0x92, 0x23, 0x44, 0xef, 0xe3, + 0xc1, 0x47, 0x69, 0x5a, 0xf1, 0x48, 0xaa, 0x37, 0xa4, 0x94, 0x6b, 0x96, 0xe5, 0x4b, 0xfd, 0x05, + 0xc7, 0x9c, 0xcc, 0x38, 0xd1, 0x47, 0x85, 0x60, 0x7f, 0xef, 0xe9, 0x2e, 0x25, 0x08, 0xf8, 0x7d, + 0x98, 0xdd, 0x6c, 0xeb, 0x4a, 0x32, 0x33, 0x44, 0x0b, 0x61, 0xb3, 0xf9, 0xae, 0x26, 0x41, 0xb5, + 0x38, 0xdb, 0xcf, 0x13, 0x72, 0x23, 0x5b, 0x66, 0x20, 0x86, 0x4d, 0x24, 0xc2, 0xd4, 0x94, 0xde, + 0xe3, 0x24, 0xb7, 0xcd, 0x75, 0x9e, 0x1d, 0x9f, 0xbc, 0xd0, 0x60, 0x34, 0x7d, 0xf8, 0xcb, 0x41, + 0x39, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x17, 0xa5, 0x22, 0xed, 0xb8, 0x3e, + 0x1f, 0x11, 0x99, 0xc5, 0xba, 0x28, 0x3e, 0x7e, 0xa6, 0xeb, 0x02, 0x81, 0x06, 0xa1, 0xc6, 0x80, + 0xb9, 0x7e, 0x5c, 0x5a, 0x63, 0xe0, 0x8d, 0xeb, 0xd0, 0xec, 0x9c, 0x3a, 0x94, 0x64, 0x7c, 0x13, + 0x54, 0x0d, 0xd6, 0xe3, 0x27, 0x88, 0xa6, 0xd2, 0x4b, 0x36, 0xdd, 0x2e, 0xfa, 0x94, 0xe5, 0x03, + 0x27, 0xc9, 0xa6, 0x31, 0x02, 0xea, 0x40, 0x77, 0x2e, 0x93, 0xc4, 0x4d, 0xe2, 0x70, 0xe2, 0x67, + 0x1c, 0xa8, 0x0d, 0xcd, 0x1a, 0x72, 0x86, 0x2c, 0xea, 0xdc, 0x7f, 0x8c, 0x49, 0x2c, 0xe7, 0x99, + 0x13, 0xda, 0x3f, 0x58, 0x9e, 0xf5, 0x4d, 0x3c, 0x8c, 0x1c, 0xed, 0x85, 0xa7, 0xe2, 0xae, 0xda, + 0x5f, 0xbe, 0x36, 0x1c, 0x9f, 0x5a, 0xa0, 0xdc, 0x2a, 0xc0, 0xee, 0x71, 0x07, 0x26, 0x8b, 0xe8, + 0x8a, 0xf8, 0x2d, 0x36, 0x78, 0xc9, 0x79, 0xfa, 0xbe, 0x98, 0x59, 0x95, 0x12, 0x24, 0xf1, 0xda, + 0x20, 0xc7, 0x78, 0xf9, 0x7c, 0x6a, 0x24, 0x43, 0x82, 0xa8, 0x0f, 0xb1, 0x7d, 0x94, 0xaa, 0x30, + 0x35, 0xe5, 0x69, 0xdc, 0x0a, 0x0e, 0xaf, 0x10, 0x5e, 0x1a, 0x81, 0x50, 0x5c, 0x7e, 0x24, 0xb3, + 0x07, 0x65, 0x4b, 0xc1, 0x7e, 0xc6, 0x38, 0xdb, 0xd3, 0x6a, 0xf0, 0xd8, 0x85, 0x61, 0x9a, 0x9f, + 0xfe, 0x02, 0x46, 0x29, 0xb2, 0x9a, 0xe2, 0x04, 0xe7, 0x72, 0xcc, 0x87, 0x46, 0xba, 0x7d, 0xa8, + 0xf9, 0xd0, 0x0f, 0x29, 0xfc, 0xfd, 0xd1, 0xd0, 0x7f, 0x36, 0xc1, 0xd8, 0x7d, 0x88, 0x03, 0x62, + 0xf5, 0x8c, 0x00, 0xb5, 0xc2, 0x81, 0x44, 0x67, 0x58, 0x11, 0xb4, 0x3a, 0xbb, 0xd1, 0x8c, 0x94, + 0x20, 0x60, 0xea, 0xa0, 0xac, 0xc1, 0xf1, 0x08, 0x54, 0xb8, 0xf6, 0x5e, 0xac, 0xf1, 0xec, 0x78, + 0x69, 0x9d, 0x7e, 0x4d, 0x06, 0x3b, 0x9b, 0x78, 0x78, 0x10, 0x31, 0x82, 0x01, 0xd4, 0x30, 0x82, + 0x01, 0xd0, 0x02, 0x01, 0x01, 0x30, 0x37, 0x30, 0x32, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x07, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x43, 0x41, 0x31, 0x1e, 0x30, 0x1c, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x0c, 0x0f, 0x70, 0x6c, 0x75, 0x74, + 0x6f, 0x40, 0x70, 0x6c, 0x75, 0x74, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x01, 0x02, 0x30, 0x09, + 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0xa0, 0x74, 0x30, 0x15, 0x06, 0x08, 0x2b, + 0x06, 0x01, 0x04, 0x01, 0x3f, 0x2a, 0x06, 0x31, 0x09, 0x04, 0x07, 0x68, 0x6f, 0x69, 0x20, 0x6a, + 0x6f, 0x68, 0x30, 0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03, 0x31, + 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0x30, 0x1c, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x39, 0x30, + 0x39, 0x31, 0x31, 0x30, 0x32, 0x35, 0x34, 0x36, 0x30, 0x5a, 0x30, 0x23, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0x11, 0xe1, 0xcc, 0x76, 0x17, + 0x3a, 0x5f, 0xc7, 0x06, 0x23, 0x74, 0x4a, 0x68, 0x40, 0x7d, 0x0b, 0x30, 0x65, 0x14, 0x75, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x01, 0x00, 0x51, 0x0c, 0x91, 0x28, 0x6d, 0x4b, 0x19, 0xc9, 0xb1, 0x0f, 0x24, 0xda, 0xe4, 0xe2, + 0x56, 0x4f, 0xda, 0x87, 0x57, 0xc6, 0x11, 0xb0, 0x00, 0xcb, 0xa6, 0x38, 0x5c, 0x04, 0x8b, 0xd3, + 0xc7, 0xdb, 0x36, 0x85, 0x66, 0xa7, 0x5b, 0xcd, 0x8d, 0x32, 0x5c, 0x4e, 0xc4, 0x8a, 0x50, 0xb5, + 0xb5, 0x19, 0xf6, 0x7c, 0x31, 0xdd, 0xf9, 0x9c, 0xdd, 0xce, 0xf6, 0x3a, 0x51, 0xf9, 0xc7, 0x53, + 0xe1, 0x72, 0x89, 0xaa, 0x8c, 0xf7, 0xa9, 0xed, 0xa8, 0xc9, 0x93, 0x2a, 0xc0, 0x89, 0x24, 0x8e, + 0xd7, 0x7e, 0x66, 0x30, 0x1e, 0x46, 0x15, 0xbc, 0xe0, 0x0b, 0x37, 0xdc, 0xd5, 0xe0, 0x88, 0xed, + 0xbe, 0x0c, 0x7c, 0x6c, 0xd9, 0xd0, 0x58, 0x64, 0xff, 0x91, 0x5f, 0x18, 0xaa, 0x91, 0xa8, 0x3e, + 0x36, 0x4f, 0xe1, 0xda, 0x85, 0x35, 0x3e, 0xa3, 0x87, 0xbc, 0xa2, 0xec, 0x71, 0x71, 0xb5, 0xc9, + 0xc8, 0x71, 0x43, 0x01, 0x8f, 0x1d, 0x64, 0x5e, 0xfa, 0xdd, 0x58, 0xce, 0x6d, 0xb5, 0x46, 0x09, + 0xef, 0x6e, 0x87, 0xc4, 0xe7, 0x61, 0x6d, 0x7e, 0x8b, 0x2c, 0x57, 0x2f, 0x9f, 0x36, 0xc5, 0xd4, + 0x34, 0x4c, 0xbb, 0xa2, 0xca, 0xee, 0xbb, 0x48, 0xbe, 0x93, 0x06, 0x44, 0xbc, 0x54, 0xdc, 0x28, + 0xa6, 0x57, 0x80, 0x5c, 0xc0, 0x0c, 0xa5, 0x1c, 0x50, 0x9a, 0x44, 0x26, 0x56, 0xc1, 0xc4, 0xfd, + 0x1a, 0xc1, 0xcf, 0x42, 0xf0, 0x49, 0xf5, 0x49, 0xbe, 0x37, 0x98, 0xb5, 0xfe, 0x66, 0x13, 0x7d, + 0xec, 0xda, 0xd6, 0x59, 0xf7, 0x3b, 0x89, 0x20, 0x8f, 0x73, 0xf7, 0x9f, 0x2f, 0x6e, 0x09, 0x62, + 0x25, 0x6a, 0xec, 0x2b, 0x19, 0x5a, 0x37, 0x77, 0x30, 0x30, 0x74, 0x3b, 0x40, 0xb2, 0xed, 0x44, + 0xf2, 0xe7, 0x5e, 0x2c, 0xbb, 0x53, 0x5d, 0x36, 0x73, 0x1c, 0xbd, 0xd7, 0xf7, 0xdf, 0x82, 0x7d, + 0xce, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void test_decode_signing_time_leap_seconds(void) { + SecCertificateRef cert = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateBasicX509(); + CFDictionaryRef attrs = NULL; + CFDataRef message = NULL; + + CFDataRef message_data = CFDataCreate(NULL, _sixty_seconds_message, sizeof(_sixty_seconds_message)); + ok_status(SecCMSVerifyCopyDataAndAttributes(message_data, NULL, policy, &trust, &message, &attrs), "decode message again"); + CFReleaseNull(trust); + isnt(CFDictionaryGetValue(attrs, kSecCMSSignDate), NULL, "failed to get cooked data from attributes"); + + CFReleaseNull(cert); + CFReleaseNull(policy); + CFReleaseNull(attrs); + CFReleaseNull(message); + CFReleaseNull(message_data); +} + int si_60_cms(int argc, char *const *argv) { #if TARGET_OS_IPHONE - plan_tests(46); + plan_tests(48); #else - plan_tests(45); + plan_tests(47); #endif tests(); test_key_usage_enveloped_data(); + test_decode_signing_time_leap_seconds(); return 0; } diff --git a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c index f3de052c..44b57a7d 100644 --- a/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c +++ b/OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c @@ -37,7 +37,7 @@ #if TARGET_HAS_KEYSTORE #include -#include +#include "keychain/securityd/SecDbItem.h" #include #include #endif /* TARGET_HAS_KEYSTORE */ diff --git a/OSX/sec/Security/SecBackupKeybagEntry.h b/OSX/sec/Security/SecBackupKeybagEntry.h index c01bc2b5..eb4fd07a 100644 --- a/OSX/sec/Security/SecBackupKeybagEntry.h +++ b/OSX/sec/Security/SecBackupKeybagEntry.h @@ -23,7 +23,7 @@ #import "CKKSSQLDatabaseObject.h" #include -#include +#include "keychain/securityd/SecDbItem.h" #ifndef SecBackupKeybagEntry_h #define SecBackupKeybagEntry_h diff --git a/OSX/sec/Security/SecBackupKeybagEntry.m b/OSX/sec/Security/SecBackupKeybagEntry.m index 558c4e44..6ab0f79f 100644 --- a/OSX/sec/Security/SecBackupKeybagEntry.m +++ b/OSX/sec/Security/SecBackupKeybagEntry.m @@ -26,8 +26,8 @@ #import #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON diff --git a/OSX/sec/Security/SecCertificate.c b/OSX/sec/Security/SecCertificate.c index 0850a4b7..d9b3f39d 100644 --- a/OSX/sec/Security/SecCertificate.c +++ b/OSX/sec/Security/SecCertificate.c @@ -2260,7 +2260,7 @@ static inline int parseDecimalPair(const DERByte **p) { Note that this is needed to distinguish an error condition from a valid time which specifies 2001-01-01 00:00:00 (i.e. a value of 0). */ -static CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, +CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, const uint8_t *bytes, size_t length, CFErrorRef *error) { @@ -2367,7 +2367,8 @@ static CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; int is_leap_year = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0; - if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 59 + /* Some basic checks on the date, allowing leap seconds */ + if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || minute > 59 || second > 60 || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year) || (month != 2 && day > mdays[month] - mdays[month - 1])) { /* Invalid date. */ @@ -4306,13 +4307,12 @@ CFArrayRef SecCertificateCopyLegacyProperties(SecCertificateRef certificate) { return properties; } -CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { +static CFArrayRef CopyProperties(SecCertificateRef certificate, Boolean localized) { if (!certificate->_properties) { CFAllocatorRef allocator = CFGetAllocator(certificate); CFMutableArrayRef properties = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); require_quiet(properties, out); - bool localized = true; /* First we put the Subject Name in the property list. */ CFArrayRef subject_plist = createPropertiesForX501NameContent(allocator, @@ -4383,6 +4383,22 @@ out: return certificate->_properties; } +CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate) { + /* + Wrapper function which defaults to localized string properties + for compatibility with prior releases. + */ + return CopyProperties(certificate, true); +} + +CFArrayRef SecCertificateCopyLocalizedProperties(SecCertificateRef certificate, Boolean localized) { + /* + Wrapper function which permits caller to specify whether + localized string properties are used. + */ + return CopyProperties(certificate, localized); +} + /* Unified serial number API */ CFDataRef SecCertificateCopySerialNumberData( SecCertificateRef certificate, diff --git a/OSX/sec/Security/SecExports.exp-in b/OSX/sec/Security/SecExports.exp-in index 706bf85f..89695818 100644 --- a/OSX/sec/Security/SecExports.exp-in +++ b/OSX/sec/Security/SecExports.exp-in @@ -80,6 +80,7 @@ _kSecPolicyNameAppleEscrowProxyService _kSecPolicyNameAppleFMiPService _kSecPolicyNameAppleGSService _kSecPolicyNameAppleHealthProviderService +_kSecPolicyNameAppleHomeAppClipUploadService _kSecPolicyNameAppleHomeKitService _kSecPolicyNameAppleiCloudSetupService _kSecPolicyNameAppleIDSService @@ -379,6 +380,7 @@ _SecCertificateCopyIssuerSummary _SecCertificateCopyKey _SecCertificateCopyKeychainItem _SecCertificateCopyLegacyProperties +_SecCertificateCopyLocalizedProperties _SecCertificateCopyNormalizedIssuerSequence _SecCertificateCopyNormalizedSubjectSequence _SecCertificateCopyNTPrincipalNames diff --git a/OSX/sec/Security/SecItemBackup.c b/OSX/sec/Security/SecItemBackup.c index cf58386f..614e40d8 100644 --- a/OSX/sec/Security/SecItemBackup.c +++ b/OSX/sec/Security/SecItemBackup.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include "keychain/SecureObjectSync/SOSBackupEvent.h" #include diff --git a/OSX/sec/Security/SecKey.m b/OSX/sec/Security/SecKey.m index 6fa9f866..218f1a9b 100644 --- a/OSX/sec/Security/SecKey.m +++ b/OSX/sec/Security/SecKey.m @@ -170,11 +170,21 @@ static CFMutableDictionaryRef auxilliaryCDSAKeyMap; static struct os_unfair_lock_s auxilliaryCDSAKeyMapLock = OS_UNFAIR_LOCK_INIT; static void SecKeyDestroyAuxilliaryCDSAKeyForKey(CFTypeRef cf) { + CFTypeRef keyToDestroy = NULL; os_unfair_lock_lock(&auxilliaryCDSAKeyMapLock); if (auxilliaryCDSAKeyMap != NULL) { - CFDictionaryRemoveValue(auxilliaryCDSAKeyMap, cf); + keyToDestroy = CFDictionaryGetValue(auxilliaryCDSAKeyMap, cf); + if (keyToDestroy != NULL) { + CFRetain(keyToDestroy); + CFDictionaryRemoveValue(auxilliaryCDSAKeyMap, cf); + } } os_unfair_lock_unlock(&auxilliaryCDSAKeyMapLock); + + // Actual aux key destruction is performed outside unfair lock to avoid recursive lock. + if (keyToDestroy != NULL) { + CFRelease(keyToDestroy); + } } void SecKeySetAuxilliaryCDSAKeyForKey(SecKeyRef cf, SecKeyRef auxKey) { diff --git a/OSX/sec/Security/SecPolicy.c b/OSX/sec/Security/SecPolicy.c index fa34a2b4..2c37c6b4 100644 --- a/OSX/sec/Security/SecPolicy.c +++ b/OSX/sec/Security/SecPolicy.c @@ -131,6 +131,7 @@ SEC_CONST_DECL (kSecPolicyNameAppleHealthProviderService, "HealthProvider"); SEC_CONST_DECL (kSecPolicyNameAppleParsecService, "Parsec"); SEC_CONST_DECL (kSecPolicyNameAppleAMPService, "AMP"); SEC_CONST_DECL (kSecPolicyNameAppleSiriService, "Siri"); +SEC_CONST_DECL (kSecPolicyNameAppleHomeAppClipUploadService, "HomeAppClipUploadService"); #define kSecPolicySHA1Size 20 #define kSecPolicySHA256Size 32 diff --git a/OSX/sec/Security/SecTrust.c b/OSX/sec/Security/SecTrust.c index 85d45e7f..bf3cbaab 100644 --- a/OSX/sec/Security/SecTrust.c +++ b/OSX/sec/Security/SecTrust.c @@ -65,7 +65,7 @@ #include -#include +#include "trust/trustd/SecTrustServer.h" #pragma clang diagnostic ignored "-Wformat=2" diff --git a/OSX/sec/Security/SecuritydXPC.c b/OSX/sec/Security/SecuritydXPC.c index 65597c29..696d1f2c 100644 --- a/OSX/sec/Security/SecuritydXPC.c +++ b/OSX/sec/Security/SecuritydXPC.c @@ -41,6 +41,7 @@ const char *kSecXPCKeyPeerInfo = "peer-info"; const char *kSecXPCKeyUserLabel = "userlabel"; const char *kSecXPCKeyBackup = "backup"; const char *kSecXPCKeyKeybag = "keybag"; +const char *kSecXPCKeyFlags = "flags"; const char *kSecXPCKeyUserPassword = "password"; const char *kSecXPCKeyEMCSBackup = "emcsbackup"; const char *kSecXPCKeyDSID = "dsid"; diff --git a/OSX/sec/SharedWebCredential/swcagent.m b/OSX/sec/SharedWebCredential/swcagent.m index 146df58e..6c873d22 100644 --- a/OSX/sec/SharedWebCredential/swcagent.m +++ b/OSX/sec/SharedWebCredential/swcagent.m @@ -62,10 +62,10 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void); #include #include "swcagent_client.h" -#include -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "keychain/securityd/spi.h" #include #include diff --git a/OSX/sec/ipc/securityd_client.h b/OSX/sec/ipc/securityd_client.h index 1927babc..afbd42d6 100644 --- a/OSX/sec/ipc/securityd_client.h +++ b/OSX/sec/ipc/securityd_client.h @@ -25,7 +25,7 @@ #include -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include @@ -88,6 +88,7 @@ extern const char *kSecXPCKeyPeerInfoArray; extern const char *kSecXPCKeyUserLabel; extern const char *kSecXPCKeyBackup; extern const char *kSecXPCKeyKeybag; +extern const char *kSecXPCKeyFlags; extern const char *kSecXPCKeyUserPassword; extern const char *kSecXPCKeyEMCSBackup; extern const char *kSecXPCKeyDSID; @@ -438,7 +439,7 @@ struct securityd { bool (*soscc_DeleteEngineState)(CFErrorRef *error); SOSPeerInfoRef (*soscc_CopyApplicant)(CFErrorRef *error); CFDataRef (*soscc_CopyCircleJoiningBlob)(SOSPeerInfoRef applicant, CFErrorRef *error); - CFDataRef (*soscc_CopyInitialSyncData)(CFErrorRef *error); + CFDataRef (*soscc_CopyInitialSyncData)(SOSInitialSyncFlags flags, CFErrorRef *error); bool (*soscc_JoinWithCircleJoiningBlob)(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); bool (*soscc_SOSCCCleanupKVSKeys)(CFErrorRef *error); bool (*soscc_SOSCCTestPopulateKVSWithBadKeys)(CFErrorRef *error); diff --git a/OSX/sec/ipc/server.c b/OSX/sec/ipc/server.c index cfef1c39..917ac3e6 100644 --- a/OSX/sec/ipc/server.c +++ b/OSX/sec/ipc/server.c @@ -48,16 +48,16 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "trust/trustd/OTATrustUtilities.h" +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecLogSettingsServer.h" +#include "keychain/securityd/SecOTRRemote.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "keychain/securityd/iCloudTrace.h" +#include "keychain/securityd/spi.h" #include #include #include @@ -67,17 +67,17 @@ #include #include #include -#include -#include -#include +#include "trust/trustd/personalization.h" +#include "trust/trustd/SecPinningDb.h" +#include "keychain/securityd/SFKeychainControlManager.h" #include #include #include "keychain/ot/OctagonControlServer.h" -#include +#include "keychain/securityd/SFKeychainServer.h" #if !TARGET_OS_BRIDGE -#include +#include "keychain/securityd/PolicyReporter.h" #endif #include @@ -1537,7 +1537,8 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection, break; case kSecXPCOpCopyInitialSyncBlob: if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementCircleJoin, &error)) { - CFDataRef initialblob = SOSCCCopyInitialSyncData_Server(&error); + uint64_t flags = xpc_dictionary_get_uint64(event, kSecXPCKeyFlags); // 0 is a valid flags, so no error checking + CFDataRef initialblob = SOSCCCopyInitialSyncData_Server((uint32_t)flags, &error); if (initialblob) { xpc_object_t xpc_object = _CFXPCCreateXPCObjectFromCFObject(initialblob); xpc_dictionary_set_value(replyMessage, kSecXPCKeyResult, xpc_object); diff --git a/OSX/sec/ipc/server_endpoint.m b/OSX/sec/ipc/server_endpoint.m index 4d3fa424..8db291ac 100644 --- a/OSX/sec/ipc/server_endpoint.m +++ b/OSX/sec/ipc/server_endpoint.m @@ -32,7 +32,7 @@ #include "ipc/server_entitlement_helpers.h" #include "ipc/server_endpoint.h" -#include "securityd/SecItemServer.h" +#include "keychain/securityd/SecItemServer.h" #include #pragma mark - Securityd Server diff --git a/OSX/sec/ipc/server_security_helpers.m b/OSX/sec/ipc/server_security_helpers.m index 946e16f3..cd7f0e15 100644 --- a/OSX/sec/ipc/server_security_helpers.m +++ b/OSX/sec/ipc/server_security_helpers.m @@ -34,7 +34,7 @@ #include "utilities/SecCFRelease.h" #include "utilities/SecCFWrappers.h" #include "utilities/debugging.h" -#include "securityd/SecDbQuery.h" +#include "keychain/securityd/SecDbQuery.h" #if __has_include() && TARGET_HAS_KEYSTORE #include diff --git a/OSX/sec/ipc/server_xpc.m b/OSX/sec/ipc/server_xpc.m index c311212f..27413305 100644 --- a/OSX/sec/ipc/server_xpc.m +++ b/OSX/sec/ipc/server_xpc.m @@ -47,13 +47,13 @@ #include #include -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemDb.h" #include "keychain/ckks/CKKSViewManager.h" -#import "securityd/SecDbBackupManager.h" +#import "keychain/securityd/SecDbBackupManager.h" @interface SecOSTransactionHolder : NSObject @property os_transaction_t transaction; diff --git a/OSX/sec/os_log/com.apple.security.trustedpeers.plist b/OSX/sec/os_log/com.apple.security.trustedpeers.plist new file mode 100644 index 00000000..29e89f75 --- /dev/null +++ b/OSX/sec/os_log/com.apple.security.trustedpeers.plist @@ -0,0 +1,35 @@ + + + + + DEFAULT-OPTIONS + + Enabled + True + Persist + Default + Enable-Oversize-Messages + + TTL + Default + Development + + Enabled + True + Persist + Default + TTL + Default + + Debug + + Enabled + True + Persist + True + TTL + 2 + + + + diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/AppleISTCA2_Baltimore.cer new file mode 100644 index 0000000000000000000000000000000000000000..9e2b0a667ce36341f038a657a670d4950463468b GIT binary patch literal 1186 zcmXqLVwq>q#N4)knTe5!Nq{xz`1^lvG__ZLw5VoZKWV-JFB_*;n@8JsUPeZ4RtAG8 zLv903Hs(+kHen`DS3@BK0T72vnA0gSrzA5szbMsE*gy~@#x2a{T$z+w6jD@LTw&w9SaI_ zQWZRdLlm4H6^s;g72FLC6%6Dc7K=Nl7L{bCWhN(tMdIO~1~y&Rr%w z=+so!*hgl8tp~28H<;#&-nIKHd+Be#Nx+RaWm@|lU%vI^?}^tMOw$CXizmvwJQ8W` zbjRo-r|hj|7oFSw$8Flvb3W}hV>i>fDIT9K`v1N%TEX$AZF=Ao6+2JQX~8cl7dkY) zWZgY^YT%#8e`^H2zt7{?Eb1xB{_~>wg4y0i-?kpPlXdYA*V}Ioj%qGg(OvkDcha7J zAq5g#xyRq~{64A6cDSeY&*`?9Yi4~y-JJEmC8aE`ewboV#lNiQGZQl-1LNW*#xP)r z1R2Nz!&{b*MT|w{M%5ITnh6CH#OB=_4AX93-nSl(=(HS=|V3#Ki9wt zWRg6Kv4Nq1{sP?v+HIOprO8D(#wbel{d4m&i-5_~$iT={4=8OA4brQ?5@HZ!z{AD` z&K$`ptlTUH9BgdqjXc0yWMIL@mC)wF*!DMvfr-UH%RmF>C?-ZR8IVoIKv$KQm!sO` z91x70_JG+9nD!VMq8MJ}F00^MZ|w2BDC)zkpJsDkJ9ixL&zfwz;(k#p=K-ES+8^V# zi~E{sd<}A+r+MT@eo)gR*Uo^{J*95 z<*sYb>?bWBThFk)(<|xRvP-RI@<-V`#d~qH%OWN$yc!UD_haDJiz|(K12@*@bX2_d zt<#d3sqejo{rlu))Bj(27xZhP!$|?=^^y5C?Y*+Izh2Xs|LEPl9UF4uY$o6P{NdP+ zg-duCpUvLSCluD+vHrb__0rP^GDYG$X7KbEnAAk*ulhJU`o^>Ees)~@&-YE8XAoVk bvEn@5qwPB{BO@y-gF%!bw*e;`b0`a&Fq5aN zp^$+9h{Gk!>6DmLl9`)dlxiq!AP5rU7UpuUOiC>ZDJm^4F;p^800}Y+OTrZ@Afy$7 z^7Bg!!|F<^IChw;MQFb8lbttNLc@n^wolb5B&#(PO+Vy_3-8?#l#`0j4ZA-VJ!F6KYLwB<*Txh2chm4;Ok`xj_^5t{jZv1`*~o4BuY=WRVPuSW00l6ig{BHp=w z3v#oilJ}-Oliz;s!>9RryQQ~(3g{@Fbm-AzvEErmOso4O?!FWdd{<|>dct};gDF)P zjBS^v@_+r)H!tbDyNeEE>~7huMwi?#S?FE(*LcS$OK$5so2!4GH_A#LR&jcjY`GEu Dq-#{f literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/basejumper.cer new file mode 100644 index 0000000000000000000000000000000000000000..7b9d9be5191cd324bd3e0e7de3241f0b45c70fd8 GIT binary patch literal 1484 zcmZvcdr%X15XWe^|&12XddU?Aw^WY zjHEh)6${$(5UF-h>!V6##2J)n#frSFQ)Oxub#xdDYAr3*@kw*x(J<5he*4?s?tX4} zzX$A+4q!)4Hi%&ehW*qV4JF%_KFFRIUw=FMis=mSk$Pzy%N);qAjn%H0=ZZqm?agb zBVvUjfu_wQn!M70CMKXdGy+|UVJMg_c)b;>M3UjCJc__M%4S6q3b}k6Lvh8J0!$ZP z$P}{icq^gByn&Z+DOJGfE5U4)4;BOTI!p%^=yeOSRX#d^0W3y`0X+cOU^5m30$dDo z|6H6U3koeX$!Ku_M@!f&SSV1tAmo7-+=`n>3u)yRQbr4_H8HkAT8m*IN{3C7$lXcC z@jT_SMBGf}*%&K@PsOuCA?{s)BqFgLnkE8vNCw*>NOV@&*tX-Qa-0waVtZrZL*TpM`G(JB>c^*0> zHg5t<2KxX{qb1^P9u&e3{wY_o#J*B4Q65X-pkma^9edgE2IxF%@5{88ke- zlaiQTGJKXVKD(nJ`uX;#-QlWr4=G(iRc~nRPrZcKrL_1b!)4q4yp~fP8Jm52=v?c9 z?wL1l$wi#3KU01GtA{_otbTnrw&c#|paT3Q)Z@I&&aypbYbY&uDP%n5Of%MrH!#R{vi&RwZq!pevO1{i-@BN$lv;%mrJdp5anRBJqGAgaI^|KVbvd z5th$!^uowU!ns-Of8&mH4W42-0@s-^t&wEFyOU9nW8Qd_jbLfFAi)Ish$*qoEpq`* z7Xa=5yIX)C6+Qt)_-BA00sOF3=8^|tlz1b6zX$klCThbl;J=jfRcWM|!mR{}I%UA+ zQ!Fa*k12yhbBj^jT8z>-!#PhZTWBF!6ekFh=Eh?3Tz&!5DWzPe-Z+x6IGd7KFi^pOAD+P#7t5`%82m}6%`e^HOP$;pAc^( zL*pPwXh0~U1pX5_#PH+^0?~py7y&>F<~3*@=g;L2@%7R26qWMe@spZI=2qX_ndZ$sHvzs-X$$J zY)@-hE;{h`ihW*i#f`_S^iMW(H@7^TTOXov+bP;A;opo4KcKOY6 zZANRgcVb4{ZAG#eZF@X%+>6rhpgsTm-Wz0m@h>QA3rzq3 literal 0 HcmV?d00001 diff --git a/OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer b/OSX/shared_regressions/si-82-sectrust-ct-data/iphonesubmissions.cer new file mode 100644 index 0000000000000000000000000000000000000000..b17a7614e093ec32ab5b0456aca719b02d91c754 GIT binary patch literal 1468 zcmaJ>Yfuwc6wW>pAPJk6cvll`b-+OO7jE)SWNcd<7^Z0b0*2Pp<-kWMUC8<72>R39TuFrA+7>JLWWc&9jv#L zdRztq1gAs=FUSC6H41zRh{fZ9F=jFzw^*Yv;vf#6JZOTY_&5+Tz(F2LGggP4V)M+o zG|Tcptey~9=}AZK8zi|e(jdIQT$)1IXp6&Xr-|Y4ZYaX{)sR?(xS>E1a6?kq4MC#T zyGIvwHO42><>iNVJ*hr0?Zns7x>${=sxiOKSkhSm@37r+9b0g3b$`aZW+=#GTpw>* zxci^NzhnzfcIl?nr$)S;R-LwS&UeudW!G9aw>uM91~G4zAG!G}o^3d#R{T zxH#wDlD3~B3(qBenN&A>OD%LG>9Uqxr5H7`wd#m=acy|ZhPa!*PCK?gY0LG5jpH*9 z7b_a}mL4mqwrUzqKR!Qd-ftULrJ0mjjm_wshuS26ZTCBU>pn+Wd(}4w9^`MTb`(v$ z5*WKOO5Zdo{FN?b{-f>`gLc>9r`~P+axcY@e40ZJaS2u7yl}HCvKxT_& zC~*A(Ts1=!U>LY6<*tf!%0?4*lEV0H=d3h~3D0;f017h~VuZaAV+be5pIA08mtrx3 zBq@e_U1J%D3v7ACn0Z-olrxu4v1enX!=6nGB4ROz1au@?eMSK`yH3ewbSU3<@JYm20QkLG4RZQ3mZPD=uhpfe%>{= z?@U<-;<}0$avmf%_Qabxyz9ZfG2F+tZMQCA$M4pREb8m+h}n1MKt`$c#az?gPB`k| z?!M{R_NIf@&a3$;NT~l@<;%XxKR;~$<0O2sr}N0ZAC$rVif0WC4N*bgW~S|bnON$b z`EaTFY<_4%nexfaGnIi~Y`Xtw(x(blSxD$duf~MIw@z4g + +void SecABCTrigger(CFStringRef _Nonnull type, + CFStringRef _Nonnull subtype, + CFStringRef _Nullable subtypeContext, + CFDictionaryRef _Nullable payload); + +#if __OBJC__ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SecABC : NSObject + ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType + subtypeContext:(NSString * _Nullable)subtypeContext + events:(NSArray * _Nullable)events + payload:(NSDictionary * _Nullable)payload + detectedProcess:(NSString * _Nullable)process; + + +@end + +NS_ASSUME_NONNULL_END + +#endif diff --git a/OSX/utilities/SecABC.m b/OSX/utilities/SecABC.m new file mode 100644 index 00000000..23519a62 --- /dev/null +++ b/OSX/utilities/SecABC.m @@ -0,0 +1,71 @@ +// +// SecABC.m +// Security +// + +#import "SecABC.h" +#import + + +#if ABC_BUGCAPTURE +#import +#endif + +void SecABCTrigger(CFStringRef type, + CFStringRef subtype, + CFStringRef subtypeContext, + CFDictionaryRef payload) +{ + [SecABC triggerAutoBugCaptureWithType:(__bridge NSString *)type + subType:(__bridge NSString *)subtype + subtypeContext:(__bridge NSString *)subtypeContext + events:nil + payload:(__bridge NSDictionary *)payload + detectedProcess:nil]; +} + + +@implementation SecABC + ++ (void)triggerAutoBugCaptureWithType:(NSString *)type + subType:(NSString *)subType + subtypeContext:(NSString *)subtypeContext + events:(NSArray *)events + payload:(NSDictionary *)payload + detectedProcess:(NSString *)process +{ +#if ABC_BUGCAPTURE + os_log(OS_LOG_DEFAULT, "TriggerABC for %{public}@/%{public}@/%{public}@", + type, subType, subtypeContext); + + // no ABC on darwinos + if ([SDRDiagnosticReporter class] == nil) { + return; + } + + SDRDiagnosticReporter *diagnosticReporter = [[SDRDiagnosticReporter alloc] init]; + NSMutableDictionary *signature = [diagnosticReporter signatureWithDomain:@"com.apple.security.keychain" + type:type + subType:subType + subtypeContext:subtypeContext + detectedProcess:process?:[[NSProcessInfo processInfo] processName] + triggerThresholdValues:nil]; + if (signature == NULL) { + os_log(OS_LOG_DEFAULT, "TriggerABC signature generation failed"); + return; + } + + (void)[diagnosticReporter snapshotWithSignature:signature + duration:30.0 + events:events + payload:payload + actions:NULL + reply:^void(NSDictionary *response) + { + os_log(OS_LOG_DEFAULT, "Received response from Diagnostic Reporter - %{public}@/%{public}@/%{public}@: %{public}@", + type, subType, subtypeContext, response); + }]; +#endif +} + +@end diff --git a/OSX/utilities/SecCFWrappers.h b/OSX/utilities/SecCFWrappers.h index b9672113..f1efbf3f 100644 --- a/OSX/utilities/SecCFWrappers.h +++ b/OSX/utilities/SecCFWrappers.h @@ -902,6 +902,9 @@ static inline CFMutableSetRef CFSetCreateIntersection(CFAllocatorRef allocator, static inline CFSetRef CFSetCreateCopyOfArrayForCFTypes(CFArrayRef array) { CFIndex count = CFArrayGetCount(array); + if (SIZE_MAX/sizeof(const void *) < (size_t)count) { + return NULL; + } const void **values = (const void **)malloc(sizeof(const void *) * count); CFArrayGetValues(array, CFRangeMake(0, count), values); CFSetRef set = CFSetCreate(CFGetAllocator(array), values, count, &kCFTypeSetCallBacks); diff --git a/OSX/utilities/SecDb.c b/OSX/utilities/SecDb.c index dbc32864..729520a4 100644 --- a/OSX/utilities/SecDb.c +++ b/OSX/utilities/SecDb.c @@ -408,7 +408,9 @@ static bool SecDbDidCreateFirstConnection(SecDbConnectionRef dbconn, bool didCre void SecDbCorrupt(SecDbConnectionRef dbconn, CFErrorRef error) { - os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error); + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecEmergency"), "SecDBCorrupt: %@", error); + } dbconn->isCorrupted = true; CFRetainAssign(dbconn->corruptionError, error); } diff --git a/OSX/utilities/debugging.h b/OSX/utilities/debugging.h index 3a2a3106..52769f19 100644 --- a/OSX/utilities/debugging.h +++ b/OSX/utilities/debugging.h @@ -148,6 +148,7 @@ void __security_stackshotreport(CFStringRef reason, uint32_t code); /* For testing only, turns off/on simulated crashes, when turning on, returns number of simulated crashes which were not reported since last turned off. */ int __security_simulatecrash_enable(bool enable); +bool __security_simulatecrash_enabled(void); /* Logging control functions */ diff --git a/OSX/utilities/simulate_crash.c b/OSX/utilities/simulate_crash.c deleted file mode 100644 index 0ccd2f5d..00000000 --- a/OSX/utilities/simulate_crash.c +++ /dev/null @@ -1,98 +0,0 @@ -// -// simulate_crash -// utilities -// -// Copyright (c) 2014 Apple Inc. All Rights Reserved. -// - -#include "debugging.h" - -#include -#include -#include - -/// Type to represent a boolean value. -#if TARGET_OS_IPHONE && __LP64__ -typedef bool BOOL; -#else -typedef signed char BOOL; -// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" -// even if -funsigned-char is used. -#endif - -static void * -__security_get_CrashReporterSupport(void) -{ - static void *image = NULL; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - image = dlopen("/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport", RTLD_NOW); - }); - return image; -} - -static void __security_simulatecrash_link(CFStringRef reason, uint32_t code) -{ -#if !TARGET_OS_SIMULATOR - // Prototype defined in , but objC only. - // Soft linking here so we don't link unless we hit this. - static BOOL (*__SimulateCrash)(pid_t pid, mach_exception_data_type_t exceptionCode, CFStringRef description) = NULL; - - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ - void *image = __security_get_CrashReporterSupport(); - if (image) - __SimulateCrash = dlsym(image, "SimulateCrash"); - }); - - if (__SimulateCrash) - __SimulateCrash(getpid(), code, reason); - else - secerror("SimulateCrash not available"); -#else - secerror("SimulateCrash not available in iOS simulator"); -#endif -} - -static int __simulate_crash_counter = -1; - -void __security_simulatecrash(CFStringRef reason, uint32_t code) -{ - secerror("Simulating crash, reason: %@, code=%08x", reason, code); - if (__simulate_crash_counter < 0) - __security_simulatecrash_link(reason, code); - else - __simulate_crash_counter++; -} - -void __security_stackshotreport(CFStringRef reason, uint32_t code) -{ - secerror("stackshot report, reason: %@, code=%08x", reason, code); -#if !TARGET_OS_SIMULATOR - // Prototype defined in , but objC only. - // Soft linking here so we don't link unless we hit this. - static BOOL (*__WriteStackshotReport)(void *, mach_exception_data_type_t) = NULL; - - static dispatch_once_t once = 0; - dispatch_once(&once, ^{ - void *image = __security_get_CrashReporterSupport(); - if (image) - __WriteStackshotReport = dlsym(image, "WriteStackshotReport"); - }); - - if (__WriteStackshotReport) - __WriteStackshotReport((void *)reason, code); - else - secerror("WriteStackshotReport not available"); -#else - secerror("WriteStackshotReport not available in iOS simulator"); -#endif -} - - -int __security_simulatecrash_enable(bool enable) -{ - int count = __simulate_crash_counter; - __simulate_crash_counter = enable ? -1 : 0; - return count; -} diff --git a/OSX/utilities/simulate_crash.m b/OSX/utilities/simulate_crash.m new file mode 100644 index 00000000..197dfe35 --- /dev/null +++ b/OSX/utilities/simulate_crash.m @@ -0,0 +1,58 @@ +// +// simulate_crash +// utilities +// +// Copyright (c) 2014 Apple Inc. All Rights Reserved. +// + +#include "debugging.h" + +#import +#import +#import + +SOFT_LINK_FRAMEWORK_SAFE(PrivateFrameworks, CrashReporterSupport); + +SOFT_LINK_FUNCTION(CrashReporterSupport, SimulateCrash, soft_SimulateCrash, \ + BOOL, (pid_t pid, mach_exception_data_type_t exceptionCode, NSString *description), + (pid, exceptionCode, description)); +SOFT_LINK_FUNCTION(CrashReporterSupport, WriteStackshotReport, soft_WriteStackshotReport, \ + BOOL, (NSString *reason, mach_exception_data_type_t exceptionCode), + (reason, exceptionCode)); + +static int __simulate_crash_counter = -1; + +void __security_simulatecrash(CFStringRef reason, uint32_t code) +{ + secerror("Simulating crash, reason: %@, code=%08x", reason, code); + if (__security_simulatecrash_enabled() && isCrashReporterSupportAvailable()) { + soft_SimulateCrash(getpid(), code, (__bridge NSString *)reason); + } else { + __simulate_crash_counter++; + } +} + +void __security_stackshotreport(CFStringRef reason, uint32_t code) +{ + secerror("stackshot report, reason: %@, code=%08x", reason, code); + if (!__security_simulatecrash_enabled() && isCrashReporterSupportAvailable()) { + return; + } + if (isCrashReporterSupportAvailable()) { + soft_WriteStackshotReport((__bridge NSString *)reason, code); + } +} + + +int __security_simulatecrash_enable(bool enable) +{ + int count = __simulate_crash_counter; + __simulate_crash_counter = enable ? -1 : 0; + return count; +} + +bool __security_simulatecrash_enabled(void) +{ + return __simulate_crash_counter == -1; +} + diff --git a/RegressionTests/Security.plist b/RegressionTests/Security.plist index 0c9e0521..15cb464c 100644 --- a/RegressionTests/Security.plist +++ b/RegressionTests/Security.plist @@ -31,42 +31,6 @@ /AppleInternal/CoreOS/tests/Security/secedumodetest - - TestName - secitemstresstest - Command - - /AppleInternal/CoreOS/tests/Security/secitemstresstest - - - - TestName - secitemnotifications - Command - - /AppleInternal/CoreOS/tests/Security/secitemnotifications - - - - TestName - secd_02_upgrade_while_locked - Command - - /usr/local/bin/secdtests - -1 - secd_02_upgrade_while_locked - - - - TestName - secd_35_keychain_migrate_inet - Command - - /usr/local/bin/secdtests - -1 - secd_35_keychain_migrate_inet - - TestName keychainnetworkextensionsharing-1 diff --git a/RegressionTests/SecurityLocalKeychain.plist b/RegressionTests/SecurityLocalKeychain.plist index 39337485..dfca88b5 100644 --- a/RegressionTests/SecurityLocalKeychain.plist +++ b/RegressionTests/SecurityLocalKeychain.plist @@ -35,42 +35,28 @@ TestName secitemfunctionality - EnableEasyperf - - EasyperfArgs - - -p - secd - Command /AppleInternal/CoreOS/tests/Security/secitemfunctionality ShowSubtestResults - EligibleResource - type != 'CAMEmbeddedDeviceResource' TestName - secitemfunctionality - EnableEasyperf - - EasyperfArgs + secitemstresstest + Command - -p - securityd + /AppleInternal/CoreOS/tests/Security/secitemstresstest - AsRoot - + + + TestName + secitemnotifications Command - /AppleInternal/CoreOS/tests/Security/secitemfunctionality + /AppleInternal/CoreOS/tests/Security/secitemnotifications - ShowSubtestResults - - EligibleResource - type == 'CAMEmbeddedDeviceResource' diff --git a/RegressionTests/secitemfunctionality/secitemfunctionality.m b/RegressionTests/secitemfunctionality/secitemfunctionality.m index 4afbc161..e7810946 100644 --- a/RegressionTests/secitemfunctionality/secitemfunctionality.m +++ b/RegressionTests/secitemfunctionality/secitemfunctionality.m @@ -38,6 +38,7 @@ fail(const char *fmt, ...) va_end(ap); } +#if 0 /* * Create item w/o data, try to make sure we end up in the OS X keychain */ @@ -78,6 +79,7 @@ CheckItemAddDeleteMaybeLegacyKeychainNoData(void) printf("[PASS] %s\n", __FUNCTION__); } +#endif static void CheckItemAddDeleteNoData(void) @@ -91,6 +93,7 @@ CheckItemAddDeleteNoData(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemDelete((__bridge CFDictionaryRef)query); if (status != errSecSuccess && status != errSecItemNotFound) @@ -125,10 +128,12 @@ CheckItemUpdateAccessGroupGENP(void) NSDictionary *clean1 = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", + (id)kSecUseDataProtectionKeychain: @YES, }; NSDictionary *clean2 = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test2", + (id)kSecUseDataProtectionKeychain: @YES, }; (void)SecItemDelete((__bridge CFDictionaryRef)clean1); @@ -144,6 +149,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecAttrAccount : @"item-delete-me", (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemAdd((__bridge CFDictionaryRef)add, NULL); if (status != errSecSuccess) @@ -156,7 +162,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; NSDictionary *modified = @{ (id)kSecAttrAccessGroup : @"keychain-test2", @@ -173,7 +179,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check1, NULL); if (status != errSecItemNotFound) @@ -184,7 +190,7 @@ CheckItemUpdateAccessGroupGENP(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccessGroup : @"keychain-test2", (id)kSecAttrAccount : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check2, NULL); if (status != errSecSuccess) @@ -280,7 +286,7 @@ CheckIdentityItem(NSString *accessGroup, OSStatus expectedStatus) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : accessGroup, (id)kSecAttrLabel : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)check, NULL); if (status != expectedStatus) @@ -324,7 +330,7 @@ CheckItemUpdateAccessGroupIdentity(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"item-delete-me", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemAdd((__bridge CFDictionaryRef)add, &ref); @@ -371,7 +377,7 @@ CheckItemUpdateAccessGroupIdentity(void) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : @"keychain-test2", (id)kSecAttrLabel : @"item-delete-me", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef : (id)kCFBooleanTrue, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)prefQuery, (CFTypeRef *)&data); @@ -444,7 +450,7 @@ CheckFindIdentityByReference(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock, - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemAdd((__bridge CFDictionaryRef)add, (CFTypeRef *)&pref); @@ -483,6 +489,7 @@ CheckFindIdentityByReference(void) (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemCopyMatching((CFDictionaryRef)query2, (CFTypeRef *)&pref2); @@ -506,6 +513,7 @@ CheckFindIdentityByReference(void) (id)kSecAttrAccessGroup : @"keychain-test1", (id)kSecAttrLabel : @"CheckItemReference", (id)kSecValueRef : (__bridge id)identity, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecReturnPersistentRef: (id)kCFBooleanTrue, }; status = SecItemCopyMatching((CFDictionaryRef)query3, (CFTypeRef *)&pref2); @@ -636,7 +644,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, (id)kSecAttrAccessGroup : @"keychain-test1", - (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue, + (id)kSecUseDataProtectionKeychain: @YES, (id)kSecValueData : data, }; SecItemAdd((__bridge CFDictionaryRef)item, NULL); @@ -647,17 +655,20 @@ CheckItemPerformance(void) (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitOne, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"FindOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrAccount : @"account-0", (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"Find1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunDigestPerfTest(@"Digest1000Items", (id)kSecClassGenericPassword, @"keychain-test1", 1000); RunCopyPerfTest(@"GetAttrOneItemUnique", @{ @@ -666,12 +677,14 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetData1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -679,6 +692,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataAttrOneItemUnique", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -687,6 +701,7 @@ CheckItemPerformance(void) (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); #if TARGET_OS_IPHONE /* macOS doesn't support fetching data for more then one item */ RunCopyPerfTest(@"GetData1000Items", @{ @@ -694,6 +709,7 @@ CheckItemPerformance(void) (id)kSecAttrService : @"service", (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); RunCopyPerfTest(@"GetDataAttr1000Items", @{ (id)kSecClass : (id)kSecClassGenericPassword, @@ -701,6 +717,7 @@ CheckItemPerformance(void) (id)kSecReturnData : (id)kCFBooleanTrue, (id)kSecReturnAttributes : (id)kCFBooleanTrue, (id)kSecMatchLimit : (id)kSecMatchLimitAll, + (id)kSecUseDataProtectionKeychain: @YES, }); #endif @@ -715,17 +732,11 @@ main(int argc, const char ** argv) { printf("[TEST] secitemfunctionality\n"); -#if TARGET_OS_OSX - char *user = getenv("USER"); - if (user && strcmp("bats", user) == 0) { - (void)SecKeychainUnlock(NULL, 4, "bats", true); - } -#endif CheckItemPerformance(); CheckFindIdentityByReference(); - CheckItemAddDeleteMaybeLegacyKeychainNoData(); + //CheckItemAddDeleteMaybeLegacyKeychainNoData(); CheckItemAddDeleteNoData(); CheckItemUpdateAccessGroupGENP(); CheckItemUpdateAccessGroupIdentity(); diff --git a/Security.exp-in b/Security.exp-in index bf1ddfe8..5da8fa4d 100644 --- a/Security.exp-in +++ b/Security.exp-in @@ -324,6 +324,7 @@ _kSSLSessionConfig_anonymous /* end workaround */ _SecAbsoluteTimeFromDateContent +_SecAbsoluteTimeFromDateContentWithError /* Internal securityd RPC stuff */ _CKKSSetupControlProtocol @@ -343,9 +344,6 @@ _kSecEntitlementPrivateOctagonEscrow _OTCliqueStatusToString _OTCliqueStatusFromString -_OTCliqueCFTypeRepair -_OTCliqueCFTypePasscode -_OTCliqueCFTypeUpgrade _OTCliqueCDPContextTypeNone _OTCliqueCDPContextTypeSignIn _OTCliqueCDPContextTypeRepair @@ -375,6 +373,7 @@ _OTCKContainerName _CuttlefishTrustZone _CuttlefishErrorDomain _TrustedPeersHelperErrorDomain +_CuttlefishErrorRetryAfterKey _OctagonPlatformSupportsSOS _OctagonSetPlatformSupportsSOS @@ -386,6 +385,8 @@ _OctagonRecoveryKeyIsEnabled _OctagonRecoveryKeySetIsEnabled _OctagonAuthoritativeTrustIsEnabled _OctagonAuthoritativeTrustSetIsEnabled +_OctagonIsSOSFeatureEnabled +_OctagonSetSOSFeatureEnabled SEC_EXP_CLASS(OTJoiningConfiguration) SEC_EXP_CLASS(OTControl) @@ -2032,6 +2033,7 @@ _ApplyScopeListForID _SecLogAPICreate ___security_simulatecrash ___security_simulatecrash_enable +___security_simulatecrash_enabled ___security_stackshotreport _api_trace _secLogEnabled diff --git a/Security.xcodeproj/project.pbxproj b/Security.xcodeproj/project.pbxproj index 1dfe15aa..5d5176ea 100644 --- a/Security.xcodeproj/project.pbxproj +++ b/Security.xcodeproj/project.pbxproj @@ -211,6 +211,7 @@ D4E0E9982224DF9A00A802E0 /* PBXTargetDependency */, D4E0E9962224DF9300A802E0 /* PBXTargetDependency */, D4E0E9942224DF8D00A802E0 /* PBXTargetDependency */, + D4E0E95C2224DE1000A802E0 /* PBXTargetDependency */, D4E0E9902224DF8500A802E0 /* PBXTargetDependency */, D4E0E9922224DF8500A802E0 /* PBXTargetDependency */, D4E0E98E2224DF7D00A802E0 /* PBXTargetDependency */, @@ -778,17 +779,16 @@ 0C0DA5D01FE1F1F3003BD3BB /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; }; 0C0E60DA20D033E400E654F2 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; 0C0E60E020D033E400E654F2 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; - 0C101F942053528700387951 /* OTBottledPeerState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C101F932053528700387951 /* OTBottledPeerState.m */; }; 0C12B1F12138D31600BE0A98 /* OTClientStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */; }; 0C16371C1FD116B300210823 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; }; - 0C1637211FD12F1500210823 /* OTCloudStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */; }; 0C1637271FD2065400210823 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; }; 0C1637291FD2066A00210823 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; }; 0C16372B1FD2067F00210823 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; 0C16372D1FD2069300210823 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; }; 0C1637301FD206BC00210823 /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; }; 0C1B8BB72233244F0094D5DA /* OTVouchWithRecoveryKeyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */; }; - 0C24D693204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */; }; + 0C29BF222323288C003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; + 0C29BF2523232897003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; }; 0C2BCBAF1D06401F00ED7A2F /* ioSock.c in Sources */ = {isa = PBXBuildFile; fileRef = 4CE5A65809C79E0600D27A3F /* ioSock.c */; }; 0C2BCBB01D06401F00ED7A2F /* sslAppUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE5A65A09C79E0600D27A3F /* sslAppUtils.cpp */; }; 0C2BCBB41D06401F00ED7A2F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; }; @@ -809,12 +809,9 @@ 0C3C00731EF3636500AB19FE /* secd-155-otr-negotiation-monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */; }; 0C3E316B21372FA50093C04B /* OctagonPairingTests+ProximitySetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604812134DD5D00BFBBB8 /* OctagonPairingTests+ProximitySetup.swift */; }; 0C46A5712034C6BA00F17112 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; }; - 0C46A57B2035019800F17112 /* OTLockStateNetworkingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */; }; 0C48990B1E0E0FF300C6CF70 /* SOSTransportCircleCK.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */; }; 0C4899121E0E105D00C6CF70 /* SOSTransportCircleCK.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */; }; 0C4899231E0F386900C6CF70 /* SOSAccountTrustClassic.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C4899221E0F386900C6CF70 /* SOSAccountTrustClassic.h */; }; - 0C48B371202E3ED800A0E1AA /* OTIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */; }; - 0C48B377202E3EE700A0E1AA /* OTContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE981FC9DA5A00580909 /* OTContext.m */; }; 0C48B380202E438100A0E1AA /* CloudKitKeychainSyncingMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */; }; 0C4C547620E1A0B400BA61BA /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C4C548020E1A53D00BA61BA /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; @@ -830,7 +827,6 @@ 0C5824A52286002D009E8C15 /* OctagonTests+HealthCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C5824A322860001009E8C15 /* OctagonTests+HealthCheck.swift */; }; 0C5960641FB2E2070095BA29 /* libprequelite.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CE98B5B1FA9360700CF1D54 /* libprequelite.tbd */; settings = {ATTRIBUTES = (Weak, ); }; }; 0C5960811FB369C50095BA29 /* CKKSHealTLKSharesOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBF2F841F913EF000ED0CA4 /* CKKSHealTLKSharesOperation.m */; }; - 0C5A8C1D200A9B0C004C771D /* OTPreflightInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */; }; 0C61F1F62194FC79009566D4 /* OTPrivateKey+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3522188E18A0018FC14 /* OTPrivateKey+SF.m */; }; 0C61F1F92194FC82009566D4 /* OTAuthenticatedCiphertext+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3542188E18B0018FC14 /* OTAuthenticatedCiphertext+SF.m */; }; 0C66046A2134983900BFBBB8 /* OTEstablishOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604692134983900BFBBB8 /* OTEstablishOperation.m */; }; @@ -842,8 +838,6 @@ 0C6C0FD221F146E700CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; 0C6C0FD621F14D3900CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; }; - 0C770EBC1FCF7C9800B5F0E2 /* OTCloudStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */; }; - 0C770EC41FCF7E2000B5F0E2 /* OTCloudStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */; }; 0C78826F20132069002B7475 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0C78827520132074002B7475 /* SFSignInAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */; }; 0C78F1CC16A5E1BF00654E08 /* sectask-10-sectask.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */; }; @@ -884,12 +878,6 @@ 0C87D3E4229368BD007853B5 /* OctagonTests+SOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C87D3E2229368A7007853B5 /* OctagonTests+SOS.swift */; }; 0C8884012154C4E80053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; 0C8884042154C4EA0053224D /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; }; - 0C8A03461FDF42BA0042E8BE /* OTEscrowKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */; }; - 0C8A034D1FDF4CCE0042E8BE /* OTLocalStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */; }; - 0C8A034F1FDF60070042E8BE /* OTBottledPeerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */; }; - 0C8BBE9F1FC9DBA400580909 /* OTBottledPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */; }; - 0C8BBEA51FC9DBB100580909 /* OTEscrowKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */; }; - 0C8BBEA91FC9DBBF00580909 /* OTLocalStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */; }; 0C8FD52521483EF20098E3FB /* OT.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCCC7C820261D310024405E /* OT.m */; }; 0C98122821ACCC9300784441 /* OTClique.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F336A20DD643B0031A92D /* OTClique.m */; }; 0C9AEEAF20783FBB00BF6237 /* SFSignInAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */; }; @@ -912,7 +900,6 @@ 0CAD1E5D1E1C5CF900537693 /* secd-80-views-alwayson.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E08B1DFD0A380021E1B7 /* secd-80-views-alwayson.m */; }; 0CAD1E5E1E1C5D0600537693 /* secd-95-escrow-persistence.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C741D8085D800865A7C /* secd-95-escrow-persistence.m */; }; 0CADDF0721545CF100DF8B06 /* OctagonPairingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CADDF0421545C8E00DF8B06 /* OctagonPairingTests.swift */; }; - 0CAEC9D81FD740CF00D1F2CA /* OTContextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */; }; 0CB50A0D20AA486800FE4675 /* SOSAccountTrustClassic+Expansion.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */; }; 0CB50A0E20AA4C2F00FE4675 /* SOSAccountTrustClassic+Circle.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */; }; 0CB582C82189157F0040C5F2 /* OTAuthenticatedCiphertext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C5218915390040C5F2 /* OTAuthenticatedCiphertext.m */; }; @@ -932,10 +919,8 @@ 0CB72DA121E42FCF00D8BC9B /* OTSponsorToApplicantRound2M2.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C9AE290214054F7003BFDB5 /* OTSponsorToApplicantRound2M2.m */; }; 0CB8DC9A2194B14C0021A7C8 /* OTVouchWithBottleOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */; }; 0CB9754F2023A8F5008D6B48 /* CloudKitMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */; }; - 0CB975512023B199008D6B48 /* OTRampingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB975502023B199008D6B48 /* OTRampingTests.m */; }; 0CBA047D214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA047C214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift */; }; 0CBD55B31FE883F200A8CE21 /* SFBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */; }; - 0CBDF64D1FFC951200433E0D /* OTBottledPeerTLK.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */; }; 0CBEF3432242CA0600015691 /* TestsObjcTranslation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */; }; 0CBFEACA200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0CBFEACB200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; @@ -953,7 +938,6 @@ 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 */; }; - 0CD9E8001FE05B6600F66C38 /* OTContextRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.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 */; }; @@ -970,8 +954,6 @@ 0CE15E43222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; 0CE15E44222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; 0CE15E46222DF6A800B7EAA4 /* Recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */; }; - 0CE1BCCE1FCE11680017230E /* OTBottledPeerSigned.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */; }; - 0CE407AC1FD4769B00F59B31 /* OTCloudStoreState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */; }; 0CE751AF20ACC497002B2832 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; }; 0CE760501E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE7604F1E1301DC00B4381E /* SOSAccountTrustClassic+Expansion.h */; }; 0CE760521E1314F700B4381E /* SOSAccountTrustClassic+Identity.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE760511E1314F700B4381E /* SOSAccountTrustClassic+Identity.h */; }; @@ -992,13 +974,12 @@ 0CF70BE3218CF2AA00EC3515 /* OTBottle.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C4218915390040C5F2 /* OTBottle.m */; }; 0CF70BE4218CF2AA00EC3515 /* OTBottleContents.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C62189153A0040C5F2 /* OTBottleContents.m */; }; 0CF70BE5218CF2AA00EC3515 /* OTPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB582C3218915390040C5F2 /* OTPrivateKey.m */; }; - 0CF74E4120DDD5290014A5DB /* OTTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337720DD64C20031A92D /* OTTestsBase.m */; }; - 0CF74E4720DDD5390014A5DB /* OTCliqueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337520DD64C10031A92D /* OTCliqueTests.m */; }; 0CFC029C1D41650700E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 0CFC02C21D41651E00E6283B /* libcoretls.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CFC029B1D41650700E6283B /* libcoretls.dylib */; }; 107226D30D91DB32003CF14F /* SecTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 107226D10D91DB32003CF14F /* SecTask.h */; settings = {ATTRIBUTES = (Private, ); }; }; 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 */; }; 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 */; }; @@ -1010,6 +991,8 @@ 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 */; }; + 1BB1CAB7232C05BD001D0C71 /* CuttlefishXPCWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */; }; + 1BB1CAB8232C05BD001D0C71 /* CuttlefishXPCWrapper.h in Sources */ = {isa = PBXBuildFile; fileRef = 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */; }; 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 */; }; @@ -1186,15 +1169,12 @@ 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 */; }; - 4718AE3B205B39C40068EC3F /* OTContextRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */; }; 4718AE3D205B39C40068EC3F /* CKKSManifestLeafRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 476D873A1E6750E200190352 /* CKKSManifestLeafRecord.m */; }; 4718AE3E205B39C40068EC3F /* CKKSItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */; }; 4718AE3F205B39C40068EC3F /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; 4718AE40205B39C40068EC3F /* CKKSOutgoingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9B7AE41DCBF604004E9385 /* CKKSOutgoingQueueEntry.m */; }; 4718AE42205B39C40068EC3F /* CKKSIncomingQueueEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B3B1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m */; }; - 4718AE43205B39C40068EC3F /* OTLocalStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */; }; 4718AE44205B39C40068EC3F /* SFKeychainControlManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 473337781FDAFBCC00E19F30 /* SFKeychainControlManager.m */; }; - 4718AE45205B39C40068EC3F /* OTBottledPeerSigned.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */; }; 4718AE46205B39C40068EC3F /* CKKSIncomingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */; }; 4718AE47205B39C40068EC3F /* CKKSOutgoingQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5BB4FD1E0C98320010F836 /* CKKSOutgoingQueueOperation.m */; }; 4718AE48205B39C40068EC3F /* CKKSZoneStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DC378B371DEFADB500A3DAFA /* CKKSZoneStateEntry.m */; }; @@ -1203,7 +1183,6 @@ 4718AE4C205B39C40068EC3F /* CKKSCurrentItemPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278DC1ED789EF0083B485 /* CKKSCurrentItemPointer.m */; }; 4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3D748B1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m */; }; 4718AE4E205B39C40068EC3F /* OTManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0F1FCB481800580909 /* OTManager.m */; }; - 4718AE4F205B39C40068EC3F /* OTEscrowKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */; }; 4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */; }; 4718AE51205B39C40068EC3F /* CKKSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */; }; 4718AE52205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C501F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m */; }; @@ -1238,18 +1217,15 @@ 4718AE6F205B39C40068EC3F /* OTConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = EB10A3E420356E2000E84270 /* OTConstants.m */; }; 4718AE71205B39C40068EC3F /* SecItemServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9A1D8085D800865A7C /* SecItemServer.c */; }; 4718AE72205B39C40068EC3F /* SecDbKeychainSerializedAKSWrappedKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 47922D361FAA7C030008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.m */; }; - 4718AE74205B39C40068EC3F /* OTContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE981FC9DA5A00580909 /* OTContext.m */; }; 4718AE75205B39C40068EC3F /* NSOperationCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1447951F5766D200236DB4 /* NSOperationCategories.m */; }; 4718AE76205B39C40068EC3F /* SecKeybagSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */; }; 4718AE77205B39C40068EC3F /* SecLogSettingsServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CAE1D8085D800865A7C /* SecLogSettingsServer.m */; }; 4718AE78205B39C40068EC3F /* CKKSDeviceStateEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C261F17E455007640C8 /* CKKSDeviceStateEntry.m */; }; 4718AE79205B39C40068EC3F /* CKKSFixups.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAD9B431F8D939C00C5E2AE /* CKKSFixups.m */; }; - 4718AE7A205B39C40068EC3F /* OTIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */; }; 4718AE7C205B39C40068EC3F /* SecOTRRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB41D8085D800865A7C /* SecOTRRemote.m */; }; 4718AE7D205B39C40068EC3F /* CKKSUpdateCurrentItemPointerOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE278E71ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.m */; }; 4718AE7E205B39C40068EC3F /* CKKSNewTLKOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */; }; 4718AE7F205B39C40068EC3F /* CKKSLockStateTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */; }; - 4718AE80205B39C40068EC3F /* OTCloudStoreState.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */; }; 4718AE81205B39C40068EC3F /* SecDbKeychainSerializedSecretData.m in Sources */ = {isa = PBXBuildFile; fileRef = 47922D3F1FAA7C1B0008F7E0 /* SecDbKeychainSerializedSecretData.m */; }; 4718AE82205B39C40068EC3F /* CKKSKeychainView.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */; }; 4718AE83205B39C40068EC3F /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; }; @@ -1261,12 +1237,8 @@ 4718AE8A205B39C40068EC3F /* SecBackupKeybagEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */; }; 4718AE8B205B39C40068EC3F /* iCloudTrace.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB31D8085D800865A7C /* iCloudTrace.c */; }; 4718AE8C205B39C40068EC3F /* OctagonAPSReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D841E2F14810089CF55 /* OctagonAPSReceiver.m */; }; - 4718AE8D205B39C40068EC3F /* OTBottledPeer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */; }; 4718AE8F205B39C40068EC3F /* SOSEnsureBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C860C7A1F4F63DB004100A1 /* SOSEnsureBackup.m */; }; - 4718AE90205B39C40068EC3F /* OTBottledPeerRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */; }; - 4718AE91205B39C40068EC3F /* OTCloudStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */; }; 4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */; }; - 4718AE93205B39C40068EC3F /* OTPreflightInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */; }; 4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */ = {isa = PBXBuildFile; fileRef = DC9082C31EA0276000D0C1C5 /* CKKSZoneChangeFetcher.m */; }; 4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFE1C331F17ECE5007640C8 /* CKKSCondition.m */; }; 4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D961E3014250089CF55 /* CKKSZone.m */; }; @@ -1279,7 +1251,6 @@ 4718AEA2205B39C40068EC3F /* CKKSGroupOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */; }; 4718AEA3205B39C40068EC3F /* CKKSRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */; }; 4718AEA4205B39C40068EC3F /* SecDbKeychainSerializedItemV7.h in Headers */ = {isa = PBXBuildFile; fileRef = 47922D501FAA7DF60008F7E0 /* SecDbKeychainSerializedItemV7.h */; }; - 4718AEA5205B39C40068EC3F /* OTCloudStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */; }; 4718AEA6205B39C40068EC3F /* CKKSResultOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1447881F5764C600236DB4 /* CKKSResultOperation.h */; }; 4718AEA7205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFE1C4F1F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h */; }; 4718AEA8205B39C40068EC3F /* CKKSViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */; }; @@ -1492,6 +1463,7 @@ 482FE56E2177CF340031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 482FE56B2177C7AE0031C11E /* AuthKit.framework */; }; 482FE56F2177CF520031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; }; 483E798F1DC87605005C0008 /* secd-67-prefixedKeyIDs.m in Sources */ = {isa = PBXBuildFile; fileRef = 483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */; }; + 48AC7B73232B1DA600F02B6F /* SOSIntervalEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */; }; 48CC589F1DA5FF2700EBD9DB /* secd-66-account-recovery.m in Sources */ = {isa = PBXBuildFile; fileRef = 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */; }; 48E617211DBEC6BA0098EAAD /* SOSBackupInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 48E6171A1DBEC40D0098EAAD /* SOSBackupInformation.m */; }; 48E617221DBEC6C60098EAAD /* SOSBackupInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 48E6171B1DBEC40D0098EAAD /* SOSBackupInformation.h */; }; @@ -2064,8 +2036,6 @@ BE22FBD11EE2084100893431 /* Config.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBD01EE2084100893431 /* Config.m */; }; BE22FC041EE3584400893431 /* mark.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBFC1EE23D9100893431 /* mark.m */; }; BE25C41618B83491003320E0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; - BE2AD2B31FDA07EF00739F96 /* OTBottledPeerRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */; }; - BE2AD2BA1FDA080800739F96 /* OTBottledPeerRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */; }; BE405EE21DC2F10E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; BE405EE31DC2F11E00E227B1 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; }; BE442BAE18B7FDB800F24DAE /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; }; @@ -2587,6 +2557,8 @@ DA20716222E9367500E209E4 /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; }; DA2C402E2189302F005F1CC3 /* mach_notify.defs in Sources */ = {isa = PBXBuildFile; fileRef = DA2C402D2189302E005F1CC3 /* mach_notify.defs */; settings = {ATTRIBUTES = (Server, ); }; }; DA30D6851DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */; }; + DA31CB212319DC8F0039F1CC /* TPStringTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA700FC82310C0E00051A7DE /* TPStringTable.m */; }; + DA3AD86A2319AA5D0049AFD6 /* TPStringTableTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */; }; DA41FE1A2241AF4600838FB3 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DA41FE192241AF3E00838FB3 /* main.m */; }; DA41FE1B2241AF8200838FB3 /* IDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD744683195A00BB00FB01C0 /* IDS.framework */; }; DA45865C2245AEDB0073F993 /* OTPairingService.m in Sources */ = {isa = PBXBuildFile; fileRef = DA4586592245AEDA0073F993 /* OTPairingService.m */; }; @@ -2594,6 +2566,8 @@ DA5B871D2065A8440093F083 /* SecAutorelease.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5B871B2065A8430093F083 /* SecAutorelease.m */; }; DA6AA1651FE88AFB004565B0 /* CKKSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */; }; DA6AA1671FE88AFB004565B0 /* CKKSControlServer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6AA1641FE88AFA004565B0 /* CKKSControlServer.h */; }; + DA700FC92310C0E00051A7DE /* TPStringTable.h in Headers */ = {isa = PBXBuildFile; fileRef = DA700FC62310C0DF0051A7DE /* TPStringTable.h */; }; + DA700FCA2310C0E00051A7DE /* TPStringTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA700FC82310C0E00051A7DE /* TPStringTable.m */; }; DAB27AE11FA29EE300DEBBDE /* SOSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB27AE01FA29EB800DEBBDE /* SOSControlServer.m */; }; DAC58D1B22443C0700D4CD41 /* KeychainCircle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C75AC642141F18D0073A2F9 /* KeychainCircle.framework */; }; DAC58D202244528B00D4CD41 /* OTPairingPacketContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DAC58D1E2244528000D4CD41 /* OTPairingPacketContext.m */; }; @@ -3149,7 +3123,7 @@ DC0BCDA91D8C6A1F00070CB0 /* SecFileLocations.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */; }; DC0BCDAA1D8C6A1F00070CB0 /* SecXPCError.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */; }; DC0BCDAB1D8C6A1F00070CB0 /* SecXPCError.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */; }; - DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */; }; + DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.m in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */; }; DC0BCDAD1D8C6A1F00070CB0 /* SecSCTUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */; }; DC0BCDAE1D8C6A1F00070CB0 /* SecSCTUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */; }; DC0BCDAF1D8C6A1F00070CB0 /* SecAppleAnchor.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */; }; @@ -3309,7 +3283,6 @@ DC1787851D7791CE00B50D50 /* SecTrustSettingsPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */; settings = {ATTRIBUTES = (Private, ); }; }; DC17890B1D77980500B50D50 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; }; DC1789131D7798B300B50D50 /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; - DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DC17891D1D77999700B50D50 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891C1D77999700B50D50 /* libpam.dylib */; }; DC17891F1D77999D00B50D50 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; @@ -3355,6 +3328,8 @@ DC19484D21812EC5007C2260 /* OTDeviceInformationAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC19484B21812EC5007C2260 /* OTDeviceInformationAdapter.m */; }; DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */; }; DC1DA6681E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */; }; + DC1E5AB623063A4E00918162 /* CKKSPeerProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */; }; + DC1E5AB723063A4E00918162 /* CKKSPeerProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */; }; DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */; }; DC1ED8C61DD55476002BDCFA /* CKKS.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1ED8C51DD55476002BDCFA /* CKKS.m */; }; DC221BAB2267E2A60068DBCF /* OTUpdateTPHOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC221BA92267E2A60068DBCF /* OTUpdateTPHOperation.h */; }; @@ -3370,6 +3345,7 @@ DC2353311ECA658B00D7C1BE /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; }; DC2353321ECA659000D7C1BE /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; DC2353331ECA659000D7C1BE /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; + DC25B3AC233C2EBC00CB1409 /* CloudKitCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC94BCC91F10448600E07CEB /* CloudKitCategories.m */; }; DC26666A21CAC32700F19960 /* OTControlCLI.m in Sources */ = {isa = PBXBuildFile; fileRef = DC26666921CAC32700F19960 /* OTControlCLI.m */; }; DC26666C21CAC97000F19960 /* OTControlCLI.m in Sources */ = {isa = PBXBuildFile; fileRef = DC26666921CAC32700F19960 /* OTControlCLI.m */; }; DC2670F21F3E6EC500816EED /* debugging.h in Headers */ = {isa = PBXBuildFile; fileRef = DC0BCC531D8C68CF00070CB0 /* debugging.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -3546,7 +3522,6 @@ DC4EA5961E70A237008840B4 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; DC5060EB20E2D88300925005 /* OTCuttlefishContext.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5060E920E2D88300925005 /* OTCuttlefishContext.h */; }; DC5060ED20E2D88300925005 /* OTCuttlefishContext.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5060EA20E2D88300925005 /* OTCuttlefishContext.m */; }; - DC5060F520E2DB9700925005 /* OTCuttlefishContextTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */; }; DC52E7C41D80BCAD00B0A59C /* SecDbItem.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C8E1D8085D800865A7C /* SecDbItem.c */; }; DC52E7C51D80BCB300B0A59C /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; }; DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C9C1D8085D800865A7C /* SecItemBackupServer.c */; }; @@ -3880,7 +3855,6 @@ DC5AC0C71D8353C800CF422C /* PCSC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0C61D8353C800CF422C /* PCSC.framework */; }; DC5AC0C91D8353D100CF422C /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789181D77998C00B50D50 /* libbsm.dylib */; }; DC5AC0CE1D83542B00CF422C /* libsecurity_tokend_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0CD1D83542700CF422C /* libsecurity_tokend_client.a */; }; - DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789161D77998700B50D50 /* libauto.dylib */; }; DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; }; DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0B91D83533400CF422C /* libsecuritydservice_client.a */; }; DC5AC0D61D83548300CF422C /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */; }; @@ -5997,6 +5971,9 @@ EB3A8DFF1BEEC66F001A89AA /* Security_edumode.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */; }; EB3D1FBA2092CB030049EF95 /* SecurityInduceLowDisk.plist in Install BATS plist */ = {isa = PBXBuildFile; fileRef = EBE202752092913500B48020 /* SecurityInduceLowDisk.plist */; }; EB3F9C9D21FCFD67007B6EBA /* OctagonTestHarness.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3F9C9B21FCFC60007B6EBA /* OctagonTestHarness.m */; }; + EB3FB9B8231C12AD00DF52EA /* com.apple.security.trustedpeers.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */; }; + EB3FBB4F231F836500DF52EA /* CKKSListenerCollection.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3AF52B2229E6C0006577E8 /* CKKSListenerCollection.m */; }; + EB3FBC09232063A100DF52EA /* SecABC.m in Sources */ = {isa = PBXBuildFile; fileRef = EB3FBBF52320629400DF52EA /* SecABC.m */; }; EB413B801E663AEB00592085 /* PairingChannel.m in Sources */ = {isa = PBXBuildFile; fileRef = EB413B761E6624A500592085 /* PairingChannel.m */; }; EB413B821E663AFA00592085 /* PairingChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = EB413B751E6624A400592085 /* PairingChannel.h */; settings = {ATTRIBUTES = (Public, ); }; }; EB425CA21C65846D000ECE53 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; }; @@ -6009,9 +5986,7 @@ EB49B2B1202D8780003F34A0 /* mockaksKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = EB49B2B0202D8780003F34A0 /* mockaksKeychain.m */; }; EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; }; EB49B2BC202DEF14003F34A0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CB96BB41F966E0C00E11457 /* libsqlite3.tbd */; }; - EB49B2BD202DEF29003F34A0 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; }; EB49B2BE202DEF29003F34A0 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; }; - EB49B2BF202DEF67003F34A0 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; }; EB49B2C0202DEF7D003F34A0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; }; EB49B2C1202DEF8D003F34A0 /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; }; EB49B2C2202DF002003F34A0 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246911F9AE2E400D63882 /* libDER.a */; }; @@ -6021,7 +5996,6 @@ EB49B2D1202DF15F003F34A0 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; }; EB49B2D2202DF17D003F34A0 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; }; EB49B2D3202DF1AC003F34A0 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; }; - EB49B2D4202DF1C1003F34A0 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; }; EB49B2D5202DF1D8003F34A0 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; }; EB49B2D7202DF1F7003F34A0 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; }; EB49B2D8202DF1F7003F34A0 /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; }; @@ -11544,6 +11518,17 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + EB3FB9A3231C125400DF52EA /* Copy Logging Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /System/Library/Preferences/Logging/Subsystems; + dstSubfolderSpec = 0; + files = ( + EB3FB9B8231C12AD00DF52EA /* com.apple.security.trustedpeers.plist in Copy Logging Files */, + ); + name = "Copy Logging Files"; + runOnlyForDeploymentPostprocessing = 1; + }; EB6952B4223B75C300F02C1C /* launchd plist */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; @@ -11678,7 +11663,7 @@ /* Begin PBXFileReference section */ 091B396D2063B64A00ECAB6F /* RemoteServiceDiscovery.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RemoteServiceDiscovery.framework; path = System/Library/PrivateFrameworks/RemoteServiceDiscovery.framework; sourceTree = SDKROOT; }; - 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecKeyProxy.h; path = keychain/SecKeyProxy.h; sourceTree = ""; }; + 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecKeyProxy.h; path = keychain/headers/SecKeyProxy.h; sourceTree = ""; }; 09A3B9DF1F8271A200C5C324 /* si-44-seckey-proxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "si-44-seckey-proxy.m"; path = "OSX/shared_regressions/si-44-seckey-proxy.m"; sourceTree = SOURCE_ROOT; }; 09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainEntitlementsTest.m; sourceTree = ""; }; 09C3E08B22A83B40004ACFC4 /* securityd.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = securityd.entitlements; sourceTree = ""; }; @@ -11695,15 +11680,11 @@ 0C0CEC9D1DA45EA200C22FBC /* recovery_key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recovery_key.h; sourceTree = ""; }; 0C0CEC9E1DA45EA200C22FBC /* recovery_key.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = recovery_key.m; sourceTree = ""; }; 0C0F76DD21399AF40074EDDF /* OTPairingMessage.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = OTPairingMessage.proto; sourceTree = ""; }; - 0C101F932053528700387951 /* OTBottledPeerState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerState.m; sourceTree = ""; }; - 0C101F96205352AF00387951 /* OTBottledPeerState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerState.h; sourceTree = ""; }; 0C108C4B208A677100E8CF70 /* SFSignInAnalytics+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFSignInAnalytics+Internal.h"; sourceTree = ""; }; 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientStateMachine.m; sourceTree = ""; }; 0C12B1F52138D32F00BE0A98 /* OTClientStateMachine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClientStateMachine.h; sourceTree = ""; }; - 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStoreTests.m; sourceTree = ""; }; 0C1B8BB3223323710094D5DA /* OTVouchWithRecoveryKeyOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTVouchWithRecoveryKeyOperation.h; sourceTree = ""; }; 0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTVouchWithRecoveryKeyOperation.m; sourceTree = ""; }; - 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerUpdateBottlesTests.m; sourceTree = ""; }; 0C2A04152152ED7F00FD4FAD /* KCJoiningAcceptSession+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KCJoiningAcceptSession+Internal.h"; sourceTree = ""; }; 0C2A041A2152EF3000FD4FAD /* KCJoiningRequestSession+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "KCJoiningRequestSession+Internal.h"; sourceTree = ""; }; 0C2BCBA51D063F7D00ED7A2F /* dtlsEchoClient.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dtlsEchoClient.c; sourceTree = ""; }; @@ -11714,17 +11695,11 @@ 0C2F336A20DD643B0031A92D /* OTClique.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTClique.m; sourceTree = ""; }; 0C2F337020DD647C0031A92D /* OTRamping.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRamping.h; sourceTree = ""; }; 0C2F337120DD647D0031A92D /* OTRamping.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTRamping.m; sourceTree = ""; }; - 0C2F337520DD64C10031A92D /* OTCliqueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTCliqueTests.m; sourceTree = ""; }; - 0C2F337620DD64C20031A92D /* OTTestsBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTTestsBase.h; sourceTree = ""; }; - 0C2F337720DD64C20031A92D /* OTTestsBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTTestsBase.m; sourceTree = ""; }; - 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTPreflightInfo.m; sourceTree = ""; }; - 0C36B3202007EE9B0029F7A2 /* OTPreflightInfo.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPreflightInfo.h; sourceTree = ""; }; 0C3BB3522188E18A0018FC14 /* OTPrivateKey+SF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OTPrivateKey+SF.m"; path = "keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m"; sourceTree = SOURCE_ROOT; }; 0C3BB3542188E18B0018FC14 /* OTAuthenticatedCiphertext+SF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OTAuthenticatedCiphertext+SF.m"; path = "keychain/TrustedPeersHelper/categories/OTAuthenticatedCiphertext+SF.m"; sourceTree = SOURCE_ROOT; }; 0C3BB3562188E18B0018FC14 /* OTPrivateKey+SF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OTPrivateKey+SF.h"; path = "keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.h"; sourceTree = SOURCE_ROOT; }; 0C3BB3572188E18C0018FC14 /* OTAuthenticatedCiphertext+SF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OTAuthenticatedCiphertext+SF.h"; path = "keychain/TrustedPeersHelper/categories/OTAuthenticatedCiphertext+SF.h"; sourceTree = SOURCE_ROOT; }; 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-155-otr-negotiation-monitor.m"; sourceTree = ""; }; - 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLockStateNetworkingTests.m; sourceTree = ""; }; 0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircleCK.h; sourceTree = ""; }; 0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircleCK.m; sourceTree = ""; }; 0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrustClassic.m; path = SecureObjectSync/SOSAccountTrustClassic.m; sourceTree = ""; }; @@ -11744,7 +11719,6 @@ 0C6C2B682258211800C53C96 /* AppleAccount.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleAccount.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/AppleAccount.framework; sourceTree = DEVELOPER_DIR; }; 0C6C2B6C2258295D00C53C96 /* UIKitCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKitCore.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/UIKitCore.framework; sourceTree = DEVELOPER_DIR; }; 0C75AC642141F18D0073A2F9 /* KeychainCircle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = KeychainCircle.framework; path = System/Library/PrivateFrameworks/KeychainCircle.framework; sourceTree = SDKROOT; }; - 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStore.m; sourceTree = ""; }; 0C78F1C916A5E13400654E08 /* sectask_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sectask_regressions.h; sourceTree = ""; }; 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "sectask-10-sectask.c"; sourceTree = ""; }; 0C78F1CB16A5E1BF00654E08 /* sectask_ipc.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = sectask_ipc.defs; sourceTree = ""; }; @@ -11754,22 +11728,7 @@ 0C87D3E2229368A7007853B5 /* OctagonTests+SOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+SOS.swift"; sourceTree = ""; }; 0C89BDA021554DD2003F3CC0 /* OTAccountMetadataClassC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTAccountMetadataClassC.m; sourceTree = ""; }; 0C89BDA121554DD3003F3CC0 /* OTAccountMetadataClassC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTAccountMetadataClassC.h; sourceTree = ""; }; - 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTEscrowKeyTests.m; sourceTree = ""; }; - 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLocalStoreTests.m; sourceTree = ""; }; - 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerTests.m; sourceTree = ""; }; - 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTCloudStore.h; sourceTree = ""; }; - 0C8BBE8A1FC9DA5300580909 /* OTIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTIdentity.h; sourceTree = ""; }; - 0C8BBE8B1FC9DA5300580909 /* OTContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTContext.h; sourceTree = ""; }; - 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTLocalStore.m; sourceTree = ""; }; - 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTIdentity.m; sourceTree = ""; }; - 0C8BBE8E1FC9DA5500580909 /* OTLocalStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTLocalStore.h; sourceTree = ""; }; - 0C8BBE921FC9DA5700580909 /* OTEscrowKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTEscrowKeys.h; sourceTree = ""; }; - 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeer.m; sourceTree = ""; }; - 0C8BBE951FC9DA5800580909 /* OTBottledPeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTBottledPeer.h; sourceTree = ""; }; - 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTEscrowKeys.m; sourceTree = ""; }; 0C8BBE971FC9DA5A00580909 /* OTDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTDefines.h; sourceTree = ""; }; - 0C8BBE981FC9DA5A00580909 /* OTContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTContext.m; sourceTree = ""; }; - 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTContextTests.m; sourceTree = ""; }; 0C8BBEF71FCB405700580909 /* otctl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = otctl.m; sourceTree = ""; }; 0C8BBEF81FCB407700580909 /* otctl-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "otctl-Entitlements.plist"; sourceTree = ""; }; 0C8BBF081FCB446400580909 /* otctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = otctl; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -11814,9 +11773,7 @@ 0CB582C72189153A0040C5F2 /* OTBottle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTBottle.h; sourceTree = ""; }; 0CB8DC962194B1300021A7C8 /* OTVouchWithBottleOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTVouchWithBottleOperation.h; sourceTree = ""; }; 0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTVouchWithBottleOperation.m; sourceTree = ""; }; - 0CB975502023B199008D6B48 /* OTRampingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTRampingTests.m; sourceTree = ""; }; 0CBA047C214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonPairingTests+ProxMultiClients.swift"; sourceTree = ""; }; - 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerTLK.m; sourceTree = ""; }; 0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestsObjcTranslation.m; sourceTree = ""; }; 0CBEF3422242C9BE00015691 /* TestsObjcTranslation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestsObjcTranslation.h; sourceTree = ""; }; 0CC8A8FA2123A9EB005D7F6A /* OTClientVoucherOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientVoucherOperation.m; sourceTree = ""; }; @@ -11832,8 +11789,6 @@ 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = ""; }; 0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = ""; }; 0CD8D654207D6E65005CDBE8 /* SFAnalytics+Signin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Signin.h"; sourceTree = ""; }; - 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTContextRecord.m; sourceTree = ""; }; - 0CD9E8071FE05B8700F66C38 /* OTContextRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTContextRecord.h; sourceTree = ""; }; 0CDBCD8620AD03FB007F8EA7 /* OTClique.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClique.h; sourceTree = ""; }; 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTTriggerEscrowUpdateOperation.m; sourceTree = ""; }; 0CDD6F78226E62BC009094C2 /* OTTriggerEscrowUpdateOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTTriggerEscrowUpdateOperation.h; sourceTree = ""; }; @@ -11845,10 +11800,6 @@ 0CE15E3B222DF6A700B7EAA4 /* Recovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Recovery.h; sourceTree = ""; }; 0CE15E3C222DF6A700B7EAA4 /* Recovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Recovery.m; sourceTree = ""; }; 0CE15E3D222DF6A700B7EAA4 /* OTRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTRecovery.h; sourceTree = ""; }; - 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerSigned.m; sourceTree = ""; }; - 0CE1BCCD1FCE11610017230E /* OTBottledPeerSigned.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerSigned.h; sourceTree = ""; }; - 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCloudStoreState.m; sourceTree = ""; }; - 0CE407B31FD476E000F59B31 /* OTCloudStoreState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTCloudStoreState.h; sourceTree = ""; }; 0CE760471E12F2F200B4381E /* SOSAccountTrustClassic+Expansion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Expansion.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Expansion.m"; sourceTree = ""; }; 0CE760491E12F30200B4381E /* SOSAccountTrustClassic+Circle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Circle.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Circle.m"; sourceTree = ""; }; 0CE7604B1E12F56800B4381E /* SOSAccountTrustClassic+Identity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "SOSAccountTrustClassic+Identity.m"; path = "SecureObjectSync/SOSAccountTrustClassic+Identity.m"; sourceTree = ""; }; @@ -11878,6 +11829,8 @@ 1B8341B72239AD39002BF18A /* TPPBPolicyKeyViewMapping.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = TPPBPolicyKeyViewMapping.proto; sourceTree = ""; }; 1B995256226681ED00A2D6CD /* PolicyReporter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PolicyReporter.h; sourceTree = ""; }; 1B995258226681EE00A2D6CD /* PolicyReporter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PolicyReporter.m; sourceTree = ""; }; + 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CuttlefishXPCWrapper.m; sourceTree = ""; }; + 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CuttlefishXPCWrapper.h; sourceTree = ""; }; 1BC6F79621C9955D005ED67A /* util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = util.m; sourceTree = ""; }; 1BC6F79821C9955E005ED67A /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = ""; }; 1BDEBEF72252DEB1009AD3D6 /* policy_dryrun.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = policy_dryrun.m; sourceTree = ""; }; @@ -11930,7 +11883,7 @@ 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ProtectedCloudStorage.framework; path = System/Library/PrivateFrameworks/ProtectedCloudStorage.framework; sourceTree = SDKROOT; }; 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libcoreauthd_client.a; path = usr/local/lib/libcoreauthd_client.a; sourceTree = SDKROOT; }; 4432AF8C1A01472C000958DC /* libaks_acl.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; name = libaks_acl.a; path = usr/local/lib/libaks_acl.a; sourceTree = SDKROOT; }; - 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecAccessControl.h; path = ../../../keychain/SecAccessControl.h; sourceTree = ""; }; + 443381D918A3D81400215606 /* SecAccessControl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecAccessControl.h; path = keychain/headers/SecAccessControl.h; sourceTree = ""; }; 443381DA18A3D81400215606 /* SecAccessControlPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecAccessControlPriv.h; sourceTree = ""; }; 4469FBDC1AA0A45C0021AA26 /* libctkclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_test.a; path = usr/local/lib/libctkclient_test.a; sourceTree = SDKROOT; }; 4469FBDD1AA0A45C0021AA26 /* libctkclient_sep.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_sep.a; path = usr/local/lib/libctkclient_sep.a; sourceTree = SDKROOT; }; @@ -12065,6 +12018,8 @@ 48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingRecovery.m; sourceTree = ""; }; 48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingRecovery.h; sourceTree = ""; }; 48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRecovery.m; sourceTree = ""; }; + 48AC7B5C232B1A1700F02B6F /* SOSIntervalEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSIntervalEvent.h; sourceTree = ""; }; + 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSIntervalEvent.m; sourceTree = ""; }; 48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = accountCirclesViewsPrint.m; sourceTree = ""; }; 48C2F9331E4BCFC30093D70C /* accountCirclesViewsPrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = accountCirclesViewsPrint.h; sourceTree = ""; }; 48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-66-account-recovery.m"; sourceTree = ""; }; @@ -12085,7 +12040,7 @@ 4C04A90811924BBC0020550C /* SecKeyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecKeyInternal.h; sourceTree = ""; }; 4C079EBC1794A96200D73970 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/PrivateFrameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 4C0B906C0ACCBD240077CD03 /* SecFramework.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFramework.h; sourceTree = ""; }; - 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettingsPriv.h; path = trust/SecTrustSettingsPriv.h; sourceTree = ""; }; + 4C12828C0BB4957D00985BB0 /* SecTrustSettingsPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettingsPriv.h; path = trust/headers/SecTrustSettingsPriv.h; sourceTree = ""; }; 4C198F1E0ACDB4BF00AAB142 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/Certificate.strings; sourceTree = ""; }; 4C198F200ACDB4BF00AAB142 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/OID.strings; sourceTree = ""; usesTabs = 1; }; 4C1B442C0BB9CAF900461B82 /* SecTrustStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustStore.h; sourceTree = ""; }; @@ -12104,7 +12059,7 @@ 4C3CECF21416E20400947741 /* DigiNotar_Root_CA_G2-RootCertificate.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "DigiNotar_Root_CA_G2-RootCertificate.crt"; sourceTree = ""; }; 4C3DD6AE179755560093F9D8 /* NSDate+TimeIntervalDescription.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+TimeIntervalDescription.h"; sourceTree = ""; }; 4C3DD6AF179755560093F9D8 /* NSDate+TimeIntervalDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+TimeIntervalDescription.m"; sourceTree = ""; }; - 4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/SecTrustSettings.h; sourceTree = ""; }; + 4C4296300BB0A68200491999 /* SecTrustSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustSettings.h; path = trust/headers/SecTrustSettings.h; sourceTree = ""; }; 4C465C7D13AFD82300E841AC /* SecurityDevTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecurityDevTests-Info.plist"; sourceTree = ""; }; 4C47FA8D20A51DC700384CB6 /* AppleFSCompression.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleFSCompression.framework; path = System/Library/PrivateFrameworks/AppleFSCompression.framework; sourceTree = SDKROOT; }; 4C4CB7100DDA44900026B660 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; @@ -12131,27 +12086,27 @@ 4C52D0E416EFCCA20079966E /* com.apple.security.CircleJoinRequested.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.security.CircleJoinRequested.plist; sourceTree = ""; }; 4C52D0E516EFCCA20079966E /* NSArray+map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+map.h"; sourceTree = ""; }; 4C52D0E616EFCCA20079966E /* NSArray+map.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+map.m"; sourceTree = ""; }; - 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyPriv.h; path = trust/SecPolicyPriv.h; sourceTree = ""; }; + 4C6416D40BB34F00001C83FD /* SecPolicyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyPriv.h; path = trust/headers/SecPolicyPriv.h; sourceTree = ""; }; 4C6416F00BB357D5001C83FD /* SecInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecInternal.h; path = base/SecInternal.h; sourceTree = ""; }; 4C64E00B0B8FBBF3009B306C /* Security.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Security.h; path = base/Security.h; sourceTree = ""; }; 4C696B3709BFA94F000CBC75 /* SecBase.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.h; fileEncoding = 4; name = SecBase.h; path = base/SecBase.h; sourceTree = ""; }; - 4C7072840AC9EA4E007CC205 /* SecKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKey.h; path = keychain/SecKey.h; sourceTree = ""; }; - 4C7072D30AC9ED5A007CC205 /* SecKeyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKeyPriv.h; path = keychain/SecKeyPriv.h; sourceTree = ""; }; + 4C7072840AC9EA4E007CC205 /* SecKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKey.h; path = keychain/headers/SecKey.h; sourceTree = ""; }; + 4C7072D30AC9ED5A007CC205 /* SecKeyPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKeyPriv.h; path = keychain/headers/SecKeyPriv.h; sourceTree = ""; }; 4C7073C80ACB2BAD007CC205 /* SecRSAKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRSAKey.h; sourceTree = ""; }; 4C711D7613AFCD0900FE865D /* SecurityDevTests.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SecurityDevTests.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4C7391770B01745000C4CBFA /* vmdh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmdh.h; sourceTree = ""; }; 4C7416020F1D71A2008E0E4D /* SecSCEP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecSCEP.h; sourceTree = ""; }; - 4C7608B10AC34A8100980096 /* SecCertificatePriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificatePriv.h; path = trust/SecCertificatePriv.h; sourceTree = ""; }; + 4C7608B10AC34A8100980096 /* SecCertificatePriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificatePriv.h; path = trust/headers/SecCertificatePriv.h; sourceTree = ""; }; 4C7913241799A5CB00A9633E /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 4C7CE56E0DC7DB0A00AE53FC /* SecEntitlements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecEntitlements.h; sourceTree = ""; }; 4C84DA541720698900AEE225 /* AppleAccount.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppleAccount.framework; path = System/Library/PrivateFrameworks/AppleAccount.framework; sourceTree = SDKROOT; }; 4C84DA6217207E8D00AEE225 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; - 4C87F3A70D611C26000E7104 /* SecTrustPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustPriv.h; path = trust/SecTrustPriv.h; sourceTree = ""; }; + 4C87F3A70D611C26000E7104 /* SecTrustPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustPriv.h; path = trust/headers/SecTrustPriv.h; sourceTree = ""; }; 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudServices.framework; path = System/Library/PrivateFrameworks/CloudServices.framework; sourceTree = SDKROOT; }; 4C8B91C51416EB6A00A254E2 /* Invalid-webmail.portofamsterdam.nl.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-webmail.portofamsterdam.nl.crt"; sourceTree = ""; }; 4C8E99C20FC601D50072EB4C /* SecFrameworkStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFrameworkStrings.h; sourceTree = ""; }; - 4C8FD03D099D5C91006867B6 /* SecCertificate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificate.h; path = trust/SecCertificate.h; sourceTree = ""; }; - 4C8FD03E099D5C91006867B6 /* SecTrust.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecTrust.h; path = trust/SecTrust.h; sourceTree = ""; }; + 4C8FD03D099D5C91006867B6 /* SecCertificate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecCertificate.h; path = trust/headers/SecCertificate.h; sourceTree = ""; }; + 4C8FD03E099D5C91006867B6 /* SecTrust.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecTrust.h; path = trust/headers/SecTrust.h; sourceTree = ""; }; 4C999BA10AB5F0BB0010451D /* NtlmGenerator.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = NtlmGenerator.c; sourceTree = ""; }; 4C999BA20AB5F0BB0010451D /* NtlmGenerator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NtlmGenerator.h; sourceTree = ""; }; 4C999BA30AB5F0BB0010451D /* ntlmBlobPriv.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ntlmBlobPriv.c; sourceTree = ""; }; @@ -12163,17 +12118,17 @@ 4CA880C20DDBC87200D9A0F2 /* sslServer-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "sslServer-entitlements.plist"; sourceTree = ""; }; 4CA880C30DDBC87200D9A0F2 /* sslViewer-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "sslViewer-entitlements.plist"; sourceTree = ""; }; 4CAB97FD1114CC5300EFB38D /* README.keychain */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.keychain; sourceTree = ""; }; - 4CAC87D60B8F82720009C9FC /* SecIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentity.h; path = keychain/SecIdentity.h; sourceTree = ""; }; + 4CAC87D60B8F82720009C9FC /* SecIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentity.h; path = keychain/headers/SecIdentity.h; sourceTree = ""; }; 4CB7405F0A47498100D641BB /* Security.exp-in */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = "Security.exp-in"; sourceTree = ""; }; 4CB740680A4749C800D641BB /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; }; 4CB740A30A47567C00D641BB /* security */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = security; sourceTree = BUILT_PRODUCTS_DIR; }; - 4CBA0E860BB33C0000E72B55 /* SecPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicy.h; path = trust/SecPolicy.h; sourceTree = ""; }; + 4CBA0E860BB33C0000E72B55 /* SecPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicy.h; path = trust/headers/SecPolicy.h; sourceTree = ""; }; 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 4CC3D28F178F310B0070FCC4 /* PersistentState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersistentState.h; sourceTree = ""; }; 4CC3D290178F310C0070FCC4 /* PersistentState.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PersistentState.m; sourceTree = ""; }; 4CC92ABA15A3B3D900C6D578 /* testlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = testlist.h; sourceTree = ""; }; 4CC92B1B15A3BF2F00C6D578 /* testmain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = testmain.c; sourceTree = ""; }; - 4CCE0AD90D41797400DDBB21 /* SecIdentityPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentityPriv.h; path = keychain/SecIdentityPriv.h; sourceTree = ""; }; + 4CCE0AD90D41797400DDBB21 /* SecIdentityPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentityPriv.h; path = keychain/headers/SecIdentityPriv.h; sourceTree = ""; }; 4CCE0AE10D417A2700DDBB21 /* sslAppUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sslAppUtils.h; sourceTree = ""; }; 4CD3BA601106FF4D00BE8B75 /* SecECKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecECKey.h; sourceTree = ""; }; 4CE5A54D09C796E200D27A3F /* sslViewer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sslViewer; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -12190,8 +12145,8 @@ 4CE7EA561AEAE8D60067F5BD /* SecItemBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemBackup.h; sourceTree = ""; }; 4CEDF7370F3A6CFB0027C4FE /* SecItemInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemInternal.h; sourceTree = ""; }; 4CEF4CA70C5551FE00062475 /* SecCertificateInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateInternal.h; sourceTree = ""; }; - 4CF0484A0A5D988F00268236 /* SecItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecItem.h; path = keychain/SecItem.h; sourceTree = ""; }; - 4CF0487F0A5F016300268236 /* SecItemPriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecItemPriv.h; path = keychain/SecItemPriv.h; sourceTree = ""; }; + 4CF0484A0A5D988F00268236 /* SecItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecItem.h; path = keychain/headers/SecItem.h; sourceTree = ""; }; + 4CF0487F0A5F016300268236 /* SecItemPriv.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SecItemPriv.h; path = keychain/headers/SecItemPriv.h; sourceTree = ""; }; 4CF4C19C171E0EA600877419 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; 4CF730310EF9CDE300E17471 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; 4CFBF5F10D5A92E100969BBE /* SecPolicyInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPolicyInternal.h; sourceTree = ""; }; @@ -12248,8 +12203,8 @@ 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; }; 5EBE247A1B00CCAE0007DB0E /* secacltests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secacltests; sourceTree = BUILT_PRODUCTS_DIR; }; 5EBE247C1B00CCAE0007DB0E /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; - 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExportPriv.h; path = keychain/SecImportExportPriv.h; sourceTree = ""; }; - 5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecTrustExceptionResetCount.m; path = OSX/sec/securityd/SecTrustExceptionResetCount.m; sourceTree = ""; }; + 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExportPriv.h; path = keychain/headers/SecImportExportPriv.h; sourceTree = ""; }; + 5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecTrustExceptionResetCount.m; sourceTree = ""; }; 617570BA22C2D19E00EFBA37 /* Security.macOS.private.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = Security.macOS.private.modulemap; path = Modules/Security.macOS.private.modulemap; sourceTree = ""; }; 6C02134C21F7ED16009D5C80 /* SecDbBackupTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = SecDbBackupTests.plist; path = tests/SecDbBackupTests/SecDbBackupTests.plist; sourceTree = SOURCE_ROOT; }; 6C02134D21F7ED16009D5C80 /* SecDbBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecDbBackupTests.m; path = tests/SecDbBackupTests/SecDbBackupTests.m; sourceTree = SOURCE_ROOT; }; @@ -12385,14 +12340,14 @@ 790851B60CA9859F0083CC4D /* securityd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = securityd; sourceTree = BUILT_PRODUCTS_DIR; }; 7913B1DF0D17280500601FE9 /* sslServer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sslServer.cpp; sourceTree = ""; }; 7913B2110D172B3900601FE9 /* sslServer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sslServer; sourceTree = BUILT_PRODUCTS_DIR; }; - 791766DD0DD0162C00F3B974 /* SecCertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateRequest.h; path = trust/SecCertificateRequest.h; sourceTree = ""; }; + 791766DD0DD0162C00F3B974 /* SecCertificateRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateRequest.h; path = trust/headers/SecCertificateRequest.h; sourceTree = ""; }; 7940D4110C3ACF9000FDB5D8 /* SecDH.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SecDH.h; sourceTree = ""; }; 794743191462137C00D638A3 /* Invalid-www.cybersecurity.my.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-www.cybersecurity.my.crt"; sourceTree = ""; }; 7947431C146214E500D638A3 /* Digisign-Server-ID-Enrich-GTETrust-Cert.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Digisign-Server-ID-Enrich-GTETrust-Cert.crt"; sourceTree = ""; }; 795CA9CC0D38435E00BAE6A2 /* p12pbegen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = p12pbegen.h; sourceTree = ""; }; 79679E251462028800CF997F /* Digisign-Server-ID-Enrich-Entrust-Cert.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Digisign-Server-ID-Enrich-Entrust-Cert.crt"; sourceTree = ""; }; 79679E261462028800CF997F /* Invalid-webmail.jaring.my.crt */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Invalid-webmail.jaring.my.crt"; sourceTree = ""; }; - 79EF5B6C0D3D6A31009F5270 /* SecImportExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExport.h; path = keychain/SecImportExport.h; sourceTree = ""; }; + 79EF5B6C0D3D6A31009F5270 /* SecImportExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExport.h; path = keychain/headers/SecImportExport.h; sourceTree = ""; }; 79EF5B720D3D6AFE009F5270 /* p12import.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = p12import.h; sourceTree = ""; }; 8E02FA691107BE460043545E /* pbkdf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pbkdf2.h; sourceTree = ""; }; 8E64DB4C1C17CD3F0076C9DF /* com.apple.security.cloudkeychainproxy3.ios.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.security.cloudkeychainproxy3.ios.plist; path = KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.ios.plist; sourceTree = ""; }; @@ -12416,7 +12371,7 @@ B61577EE1F2021BC004A3930 /* padding-00-mmcs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "padding-00-mmcs.c"; sourceTree = ""; }; B61F67541F1FCFCA00E2FDBB /* SecPaddingConfigurationsPriv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecPaddingConfigurationsPriv.h; sourceTree = ""; }; B61F67551F1FCFCA00E2FDBB /* SecPaddingConfigurations.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecPaddingConfigurations.c; sourceTree = ""; }; - BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSharedCredential.h; path = ../../../keychain/SecSharedCredential.h; sourceTree = ""; }; + BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSharedCredential.h; path = keychain/headers/SecSharedCredential.h; sourceTree = ""; }; BE197F2619116FD100BA91D1 /* SharedWebCredentialViewService.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SharedWebCredentialViewService.app; sourceTree = BUILT_PRODUCTS_DIR; }; BE197F2919116FD100BA91D1 /* SharedWebCredentialViewService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SharedWebCredentialViewService-Info.plist"; sourceTree = ""; }; BE197F2B19116FD100BA91D1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -12436,8 +12391,6 @@ BE22FBD01EE2084100893431 /* Config.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Config.m; path = manifeststresstest/Config.m; sourceTree = ""; }; BE22FBFC1EE23D9100893431 /* mark.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = mark.m; path = manifeststresstest/mark.m; sourceTree = ""; }; BE22FC031EE23DA600893431 /* mark.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mark.h; path = manifeststresstest/mark.h; sourceTree = ""; }; - BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTBottledPeerRecord.h; sourceTree = ""; }; - BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTBottledPeerRecord.m; sourceTree = ""; }; BE442BC118B7FDB800F24DAE /* swcagent */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = swcagent; sourceTree = BUILT_PRODUCTS_DIR; }; BE4AC9A118B7FFAD00B84964 /* swcagent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = swcagent.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; BE4AC9AD18B7FFC800B84964 /* com.apple.security.swcagent.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.swcagent.plist; sourceTree = ""; }; @@ -12575,12 +12528,12 @@ D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleiPhoneDeviceCACertificates.h; sourceTree = ""; }; D4119E72202BDF2B0048587B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; D41257CF1E9410A300781F23 /* trustd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trustd; sourceTree = BUILT_PRODUCTS_DIR; }; - D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.agent.plist; path = OSX/trustd/macOS/com.apple.trustd.agent.plist; sourceTree = ""; }; - D41257EA1E941CF200781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/macOS/com.apple.trustd.plist; sourceTree = ""; }; - D41257EB1E941CF200781F23 /* com.apple.trustd.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = com.apple.trustd.sb; path = OSX/trustd/macOS/com.apple.trustd.sb; sourceTree = ""; }; - D41257EC1E941CF200781F23 /* trustd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = trustd.8; path = OSX/trustd/macOS/trustd.8; sourceTree = ""; }; - D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = OSX/trustd/macOS/SecTrustOSXEntryPoints.h; sourceTree = SOURCE_ROOT; }; - D41257EE1E941DA800781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.trustd.plist; path = OSX/trustd/iOS/com.apple.trustd.plist; sourceTree = ""; }; + D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.trustd.agent.plist; sourceTree = ""; }; + D41257EA1E941CF200781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.trustd.plist; sourceTree = ""; }; + D41257EB1E941CF200781F23 /* com.apple.trustd.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.apple.trustd.sb; sourceTree = ""; }; + D41257EC1E941CF200781F23 /* trustd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = trustd.8; sourceTree = ""; }; + D41257ED1E941D5B00781F23 /* SecTrustOSXEntryPoints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustOSXEntryPoints.h; path = trust/trustd/macOS/SecTrustOSXEntryPoints.h; sourceTree = SOURCE_ROOT; }; + D41257EE1E941DA800781F23 /* com.apple.trustd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.trustd.plist; sourceTree = ""; }; D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libDiagnosticMessagesClient.tbd; path = usr/lib/libDiagnosticMessagesClient.tbd; sourceTree = SDKROOT; }; D42C838721158B3F008D3D83 /* cmsreclist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmsreclist.h; path = libsecurity_smime/lib/cmsreclist.h; sourceTree = SOURCE_ROOT; }; D42C838821158B40008D3D83 /* SecAsn1Item.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecAsn1Item.c; path = libsecurity_smime/lib/SecAsn1Item.c; sourceTree = SOURCE_ROOT; }; @@ -12642,49 +12595,49 @@ D43718BE21168BCC00EA350A /* libsecurity_cms.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = libsecurity_cms.txt; path = OSX/libsecurity_smime/docs/libsecurity_cms.txt; sourceTree = ""; }; D43718BF21168BCD00EA350A /* libsecurity_cms.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = libsecurity_cms.plist; path = OSX/libsecurity_smime/docs/libsecurity_cms.plist; sourceTree = ""; }; D43718C721168D7C00EA350A /* SecSMIME.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecSMIME.h; path = CMS/SecSMIME.h; sourceTree = ""; }; - D43761641EB2996C00954447 /* SecRevocationNetworking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecRevocationNetworking.h; path = OSX/sec/securityd/SecRevocationNetworking.h; sourceTree = ""; }; - D43761651EB2996C00954447 /* SecRevocationNetworking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecRevocationNetworking.m; path = OSX/sec/securityd/SecRevocationNetworking.m; sourceTree = ""; }; - D43DBED71E99D17100C04AEA /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = nameconstraints.c; path = OSX/sec/securityd/nameconstraints.c; sourceTree = ""; }; - D43DBED81E99D17100C04AEA /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nameconstraints.h; path = OSX/sec/securityd/nameconstraints.h; sourceTree = ""; }; - D43DBED91E99D17100C04AEA /* OTATrustUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OTATrustUtilities.m; path = OSX/sec/securityd/OTATrustUtilities.m; sourceTree = ""; }; - D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OTATrustUtilities.h; path = OSX/sec/securityd/OTATrustUtilities.h; sourceTree = ""; }; - D43DBEDB1E99D17100C04AEA /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = personalization.c; path = OSX/sec/securityd/personalization.c; sourceTree = ""; }; - D43DBEDC1E99D17100C04AEA /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = personalization.h; path = OSX/sec/securityd/personalization.h; sourceTree = ""; }; - D43DBEDD1E99D17100C04AEA /* policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = policytree.c; path = OSX/sec/securityd/policytree.c; sourceTree = ""; }; - D43DBEDE1E99D17200C04AEA /* policytree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = policytree.h; path = OSX/sec/securityd/policytree.h; sourceTree = ""; }; - D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCAIssuerCache.c; path = OSX/sec/securityd/SecCAIssuerCache.c; sourceTree = ""; }; - D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerCache.h; path = OSX/sec/securityd/SecCAIssuerCache.h; sourceTree = ""; }; - D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecCAIssuerRequest.m; path = OSX/sec/securityd/SecCAIssuerRequest.m; sourceTree = ""; }; - D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCAIssuerRequest.h; path = OSX/sec/securityd/SecCAIssuerRequest.h; sourceTree = ""; }; - D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateServer.c; path = OSX/sec/securityd/SecCertificateServer.c; sourceTree = ""; }; - D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateServer.h; path = OSX/sec/securityd/SecCertificateServer.h; sourceTree = ""; }; - D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecCertificateSource.c; path = OSX/sec/securityd/SecCertificateSource.c; sourceTree = ""; }; - D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateSource.h; path = OSX/sec/securityd/SecCertificateSource.h; sourceTree = ""; }; - D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPCache.c; path = OSX/sec/securityd/SecOCSPCache.c; sourceTree = ""; }; - D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPCache.h; path = OSX/sec/securityd/SecOCSPCache.h; sourceTree = ""; }; - D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPRequest.c; path = OSX/sec/securityd/SecOCSPRequest.c; sourceTree = ""; }; - D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPRequest.h; path = OSX/sec/securityd/SecOCSPRequest.h; sourceTree = ""; }; - D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecOCSPResponse.c; path = OSX/sec/securityd/SecOCSPResponse.c; sourceTree = ""; }; - D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecOCSPResponse.h; path = OSX/sec/securityd/SecOCSPResponse.h; sourceTree = ""; }; - D43DBEED1E99D17200C04AEA /* SecPinningDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPinningDb.h; path = OSX/sec/securityd/SecPinningDb.h; sourceTree = ""; }; - D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecPinningDb.m; path = OSX/sec/securityd/SecPinningDb.m; sourceTree = ""; }; - D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecPolicyServer.c; path = OSX/sec/securityd/SecPolicyServer.c; sourceTree = ""; }; - D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecPolicyServer.h; path = OSX/sec/securityd/SecPolicyServer.h; sourceTree = ""; }; - D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationDb.c; path = OSX/sec/securityd/SecRevocationDb.c; sourceTree = ""; }; - D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationDb.h; path = OSX/sec/securityd/SecRevocationDb.h; sourceTree = ""; }; - D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecRevocationServer.c; path = OSX/sec/securityd/SecRevocationServer.c; sourceTree = ""; }; - D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecRevocationServer.h; path = OSX/sec/securityd/SecRevocationServer.h; sourceTree = ""; }; - D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecTrustLoggingServer.m; path = OSX/sec/securityd/SecTrustLoggingServer.m; sourceTree = ""; }; - D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustLoggingServer.h; path = OSX/sec/securityd/SecTrustLoggingServer.h; sourceTree = ""; }; - D43DBEF71E99D17300C04AEA /* SecTrustServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustServer.c; path = OSX/sec/securityd/SecTrustServer.c; sourceTree = ""; }; - D43DBEF81E99D17300C04AEA /* SecTrustServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustServer.h; path = OSX/sec/securityd/SecTrustServer.h; sourceTree = ""; }; - D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecTrustStoreServer.c; path = OSX/sec/securityd/SecTrustStoreServer.c; sourceTree = ""; }; - D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTrustStoreServer.h; path = OSX/sec/securityd/SecTrustStoreServer.h; sourceTree = ""; }; + D43761641EB2996C00954447 /* SecRevocationNetworking.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRevocationNetworking.h; sourceTree = ""; }; + D43761651EB2996C00954447 /* SecRevocationNetworking.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecRevocationNetworking.m; sourceTree = ""; }; + D43DBED71E99D17100C04AEA /* nameconstraints.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nameconstraints.c; sourceTree = ""; }; + D43DBED81E99D17100C04AEA /* nameconstraints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nameconstraints.h; sourceTree = ""; }; + D43DBED91E99D17100C04AEA /* OTATrustUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OTATrustUtilities.m; sourceTree = ""; }; + D43DBEDA1E99D17100C04AEA /* OTATrustUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTATrustUtilities.h; sourceTree = ""; }; + D43DBEDB1E99D17100C04AEA /* personalization.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = personalization.c; sourceTree = ""; }; + D43DBEDC1E99D17100C04AEA /* personalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = personalization.h; sourceTree = ""; }; + D43DBEDD1E99D17100C04AEA /* policytree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = policytree.c; sourceTree = ""; }; + D43DBEDE1E99D17200C04AEA /* policytree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = policytree.h; sourceTree = ""; }; + D43DBEDF1E99D17200C04AEA /* SecCAIssuerCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCAIssuerCache.c; sourceTree = ""; }; + D43DBEE01E99D17200C04AEA /* SecCAIssuerCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerCache.h; sourceTree = ""; }; + D43DBEE11E99D17200C04AEA /* SecCAIssuerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecCAIssuerRequest.m; sourceTree = ""; }; + D43DBEE21E99D17200C04AEA /* SecCAIssuerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCAIssuerRequest.h; sourceTree = ""; }; + D43DBEE31E99D17200C04AEA /* SecCertificateServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateServer.c; sourceTree = ""; }; + D43DBEE41E99D17200C04AEA /* SecCertificateServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateServer.h; sourceTree = ""; }; + D43DBEE51E99D17200C04AEA /* SecCertificateSource.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecCertificateSource.c; sourceTree = ""; }; + D43DBEE61E99D17200C04AEA /* SecCertificateSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCertificateSource.h; sourceTree = ""; }; + D43DBEE71E99D17200C04AEA /* SecOCSPCache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPCache.c; sourceTree = ""; }; + D43DBEE81E99D17200C04AEA /* SecOCSPCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPCache.h; sourceTree = ""; }; + D43DBEE91E99D17200C04AEA /* SecOCSPRequest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPRequest.c; sourceTree = ""; }; + D43DBEEA1E99D17200C04AEA /* SecOCSPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPRequest.h; sourceTree = ""; }; + D43DBEEB1E99D17200C04AEA /* SecOCSPResponse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecOCSPResponse.c; sourceTree = ""; }; + D43DBEEC1E99D17200C04AEA /* SecOCSPResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecOCSPResponse.h; sourceTree = ""; }; + D43DBEED1E99D17200C04AEA /* SecPinningDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPinningDb.h; sourceTree = ""; }; + D43DBEEE1E99D17200C04AEA /* SecPinningDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecPinningDb.m; sourceTree = ""; }; + D43DBEEF1E99D17300C04AEA /* SecPolicyServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecPolicyServer.c; sourceTree = ""; }; + D43DBEF01E99D17300C04AEA /* SecPolicyServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPolicyServer.h; sourceTree = ""; }; + D43DBEF11E99D17300C04AEA /* SecRevocationDb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecRevocationDb.c; sourceTree = ""; }; + D43DBEF21E99D17300C04AEA /* SecRevocationDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRevocationDb.h; sourceTree = ""; }; + D43DBEF31E99D17300C04AEA /* SecRevocationServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecRevocationServer.c; sourceTree = ""; }; + D43DBEF41E99D17300C04AEA /* SecRevocationServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecRevocationServer.h; sourceTree = ""; }; + D43DBEF51E99D17300C04AEA /* SecTrustLoggingServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecTrustLoggingServer.m; sourceTree = ""; }; + D43DBEF61E99D17300C04AEA /* SecTrustLoggingServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustLoggingServer.h; sourceTree = ""; }; + D43DBEF71E99D17300C04AEA /* SecTrustServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustServer.c; sourceTree = ""; }; + D43DBEF81E99D17300C04AEA /* SecTrustServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustServer.h; sourceTree = ""; }; + D43DBEF91E99D17300C04AEA /* SecTrustStoreServer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTrustStoreServer.c; sourceTree = ""; }; + D43DBEFA1E99D17300C04AEA /* SecTrustStoreServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecTrustStoreServer.h; sourceTree = ""; }; D43DDE511F620F09009742A5 /* SecPolicyChecks.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicyChecks.list; sourceTree = ""; }; D43DDE581F638061009742A5 /* SecPolicy.list */ = {isa = PBXFileReference; lastKnownFileType = text; path = SecPolicy.list; sourceTree = ""; }; D44282FE22D68556001746B3 /* TrustEvaluationTestHelpers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustEvaluationTestHelpers.m; path = tests/TrustTests/TrustEvaluationTestHelpers.m; sourceTree = ""; }; - D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA2.cer; path = OSX/trustd/iOS/AppleCorporateRootCA2.cer; sourceTree = ""; }; - D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = AppleCorporateRootCA.cer; path = OSX/trustd/iOS/AppleCorporateRootCA.cer; sourceTree = ""; }; + D442AD62215ADA250050B50F /* AppleCorporateRootCA2.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = AppleCorporateRootCA2.cer; sourceTree = ""; }; + D442AD68215ADA250050B50F /* AppleCorporateRootCA.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = AppleCorporateRootCA.cer; sourceTree = ""; }; D44D08B420AB890E0023C439 /* Security.apinotes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Security.apinotes; path = base/Security.apinotes; sourceTree = ""; }; D44D1F662115893000E76E1A /* libCMS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCMS.a; sourceTree = BUILT_PRODUCTS_DIR; }; D44D1F8321158AAB00E76E1A /* plhash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = plhash.h; path = libsecurity_smime/lib/plhash.h; sourceTree = SOURCE_ROOT; }; @@ -12696,8 +12649,8 @@ D44D1F8921158AAE00E76E1A /* cmsreclist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cmsreclist.c; path = libsecurity_smime/lib/cmsreclist.c; sourceTree = SOURCE_ROOT; }; D44D1F8A21158AAF00E76E1A /* cmsencode.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cmsencode.c; path = libsecurity_smime/lib/cmsencode.c; sourceTree = SOURCE_ROOT; }; D44D1F8B21158AAF00E76E1A /* secoidt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = secoidt.h; path = libsecurity_smime/lib/secoidt.h; sourceTree = SOURCE_ROOT; }; - D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/macOS/entitlements.plist; sourceTree = ""; }; - D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = entitlements.plist; path = OSX/trustd/iOS/entitlements.plist; sourceTree = ""; }; + D45068681E948A9E00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; + D45068691E948ACE00FA7675 /* entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = ""; }; D453A4C02122236D00850A26 /* TrustTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrustTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D453C38A1FEC669300DE349B /* trust_update.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = trust_update.m; sourceTree = ""; }; D453C47F1FFD857400DE349B /* security_tool_commands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = security_tool_commands.h; sourceTree = ""; }; @@ -12731,7 +12684,7 @@ D458C51B214E2CFF0043D982 /* si-20-sectrust-policies-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-20-sectrust-policies-data"; path = "OSX/shared_regressions/si-20-sectrust-policies-data"; sourceTree = ""; }; D458C51E214E2E0C0043D982 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Main.storyboard; path = tests/TrustTests/TestRunners/Main.storyboard; sourceTree = ""; }; D46246911F9AE2E400D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; - D46246A21F9AE49E00D63882 /* oids.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = oids.h; path = trust/oids.h; sourceTree = ""; }; + D46246A21F9AE49E00D63882 /* oids.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = oids.h; path = trust/headers/oids.h; sourceTree = ""; }; D46246A91F9AE6C900D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; D46246AF1F9AE73F00D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; D46246C31F9AEA5200D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; @@ -12758,8 +12711,8 @@ D48BD195206C476B0075DDC9 /* si-35-cms-expiration-time.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-35-cms-expiration-time.h"; sourceTree = ""; }; D48F029B1EA1671B00ACC3C9 /* si-61-pkcs12.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-61-pkcs12.h"; sourceTree = ""; }; D4911167209558900066A1E4 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; - D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustURLSessionDelegate.m; path = OSX/sec/securityd/TrustURLSessionDelegate.m; sourceTree = ""; }; - D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TrustURLSessionDelegate.h; path = OSX/sec/securityd/TrustURLSessionDelegate.h; sourceTree = ""; }; + D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TrustURLSessionDelegate.m; sourceTree = ""; }; + D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TrustURLSessionDelegate.h; sourceTree = ""; }; D4A0F8BA211E69CB00443CA1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = tests/TrustTests/Info.plist; sourceTree = ""; }; D4A0F8BB211E69CB00443CA1 /* TestMacroConversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMacroConversions.h; path = tests/TrustTests/TestMacroConversions.h; sourceTree = ""; }; D4A0F8C1211E6A2F00443CA1 /* si-82-sectrust-ct-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-82-sectrust-ct-data"; path = "OSX/shared_regressions/si-82-sectrust-ct-data"; sourceTree = ""; }; @@ -12783,7 +12736,7 @@ D4AC5769214E195400A32C01 /* KeySizeTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = KeySizeTests_data.h; path = tests/TrustTests/EvaluationTests/KeySizeTests_data.h; sourceTree = ""; }; D4AC8BE721320AD0006E9871 /* CertificateParseTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CertificateParseTests.m; path = tests/TrustTests/FrameworkTests/CertificateParseTests.m; sourceTree = ""; }; D4AC8BED2132127A006E9871 /* si-18-certificate-parse */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-18-certificate-parse"; path = "OSX/shared_regressions/si-18-certificate-parse"; sourceTree = ""; }; - D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "trustd-Info.plist"; path = "OSX/trustd/trustd-Info.plist"; sourceTree = ""; }; + D4ADA30E1E2B1E650031CEA3 /* trustd-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "trustd-Info.plist"; sourceTree = ""; }; D4ADA3191E2B41670031CEA3 /* libtrustd.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtrustd.a; sourceTree = BUILT_PRODUCTS_DIR; }; D4B2966822DBFDB100DCF250 /* TestCopyProperties_ios-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "TestCopyProperties_ios-data"; path = "tests/TrustTests/TestData/TestCopyProperties_ios-data"; sourceTree = ""; }; D4B3B1CB2115149C00A43409 /* SecCmsDigestedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsDigestedData.h; path = CMS/SecCmsDigestedData.h; sourceTree = ""; }; @@ -12793,12 +12746,12 @@ D4B3B1D721151B9900A43409 /* SecCmsSignedData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsSignedData.h; path = CMS/SecCmsSignedData.h; sourceTree = ""; }; D4B3B1DA2115293300A43409 /* SecCmsSignerInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsSignerInfo.h; path = CMS/SecCmsSignerInfo.h; sourceTree = ""; }; D4B68C5C211A7D98009FED69 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; }; - D4B68C64211A8186009FED69 /* trustd_spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = trustd_spi.h; path = OSX/trustd/trustd_spi.h; sourceTree = ""; }; - D4B68C65211A8186009FED69 /* trustd_spi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = trustd_spi.c; path = OSX/trustd/trustd_spi.c; sourceTree = ""; }; + D4B68C64211A8186009FED69 /* trustd_spi.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trustd_spi.h; sourceTree = ""; }; + D4B68C65211A8186009FED69 /* trustd_spi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = trustd_spi.c; sourceTree = ""; }; D4B6D57B2069D8450099FBEF /* si-34-cms-timestamp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "si-34-cms-timestamp.m"; sourceTree = ""; }; D4B6D5822069D85B0099FBEF /* si-34-cms-timestamp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-34-cms-timestamp.h"; sourceTree = ""; }; D4B858661D370D9A003B2D95 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; }; - D4BEECE61E93093A00F76D1A /* trustd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = trustd.c; path = OSX/trustd/trustd.c; sourceTree = ""; }; + D4BEECE61E93093A00F76D1A /* trustd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trustd.c; sourceTree = ""; }; D4C263C51F8FF2A9001317EA /* generateErrStrings.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = generateErrStrings.pl; path = OSX/lib/generateErrStrings.pl; sourceTree = ""; usesTabs = 1; }; D4C263C81F952E64001317EA /* SecDebugErrorMessages.strings */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; fileEncoding = 10; name = SecDebugErrorMessages.strings; path = derived_src/SecDebugErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; D4C263CD1F952F6C001317EA /* SecErrorMessages.strings */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = SecErrorMessages.strings; path = derived_src/en.lproj/SecErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -12844,7 +12797,7 @@ D4D92DA72278904F0009A7CF /* nist-certs */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "nist-certs"; path = "SecurityTests/nist-certs"; sourceTree = ""; }; D4EA5CF622B225C000883439 /* LoggingServerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = LoggingServerTests.m; path = tests/TrustTests/DaemonTests/LoggingServerTests.m; sourceTree = ""; }; D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-20-sectrust-policies-data"; path = "../OSX/shared_regressions/si-20-sectrust-policies-data"; sourceTree = ""; }; - D4EF321E215F0F76000A31A5 /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecTrustStoreServer.m; path = OSX/sec/securityd/SecTrustStoreServer.m; sourceTree = ""; }; + D4EF321E215F0F76000A31A5 /* SecTrustStoreServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecTrustStoreServer.m; sourceTree = ""; }; D4EF3222215F102F000A31A5 /* CTTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CTTests_data.h; path = tests/TrustTests/EvaluationTests/CTTests_data.h; sourceTree = ""; }; D4FC521C1EC3E05B00E99785 /* smime_attr_emails.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = smime_attr_emails.h; sourceTree = ""; }; D4FD421B217D7891002B7EE2 /* NameConstraintsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = NameConstraintsTests.m; path = tests/TrustTests/EvaluationTests/NameConstraintsTests.m; sourceTree = ""; }; @@ -12857,6 +12810,7 @@ DA30D6781DF8C8FB00EC6B43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DA30D6831DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeychainSyncAccountUpdater.h; sourceTree = ""; }; DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeychainSyncAccountUpdater.m; sourceTree = ""; }; + DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPStringTableTests.m; sourceTree = ""; }; DA41FE0E2241ADC000838FB3 /* otpaird */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = otpaird; sourceTree = BUILT_PRODUCTS_DIR; }; DA41FE192241AF3E00838FB3 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; DA4586572245AEDA0073F993 /* OTPairingService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OTPairingService.h; sourceTree = ""; }; @@ -12867,6 +12821,8 @@ DA5B871B2065A8430093F083 /* SecAutorelease.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecAutorelease.m; sourceTree = ""; }; DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSControlServer.m; sourceTree = ""; }; DA6AA1641FE88AFA004565B0 /* CKKSControlServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSControlServer.h; sourceTree = ""; }; + DA700FC62310C0DF0051A7DE /* TPStringTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPStringTable.h; sourceTree = ""; }; + DA700FC82310C0E00051A7DE /* TPStringTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPStringTable.m; sourceTree = ""; }; DAB27ADA1FA29EB700DEBBDE /* SOSControlServer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSControlServer.h; sourceTree = ""; }; DAB27AE01FA29EB800DEBBDE /* SOSControlServer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSControlServer.m; sourceTree = ""; }; DAC58D1C2244527E00D4CD41 /* OTPairingPacketContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPairingPacketContext.h; sourceTree = ""; }; @@ -13357,7 +13313,7 @@ DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecFileLocations.h; sourceTree = ""; }; DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecXPCError.h; sourceTree = ""; }; DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecXPCError.c; sourceTree = ""; }; - DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = simulate_crash.c; sourceTree = ""; }; + DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = simulate_crash.m; sourceTree = ""; }; DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecSCTUtils.h; sourceTree = ""; }; DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecSCTUtils.c; sourceTree = ""; }; DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAppleAnchor.c; sourceTree = ""; }; @@ -13499,7 +13455,6 @@ DC1789041D77980500B50D50 /* Security.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Security.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DC1789121D7798B300B50D50 /* libDiagnosticMessagesClient.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libDiagnosticMessagesClient.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libDiagnosticMessagesClient.dylib; sourceTree = DEVELOPER_DIR; }; DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libOpenScriptingUtil.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libOpenScriptingUtil.dylib; sourceTree = DEVELOPER_DIR; }; - DC1789161D77998700B50D50 /* libauto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libauto.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libauto.dylib; sourceTree = DEVELOPER_DIR; }; DC1789181D77998C00B50D50 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libbsm.dylib; sourceTree = DEVELOPER_DIR; }; DC17891C1D77999700B50D50 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libpam.dylib; sourceTree = DEVELOPER_DIR; }; DC17891E1D77999D00B50D50 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libsqlite3.dylib; sourceTree = DEVELOPER_DIR; }; @@ -13542,6 +13497,8 @@ DC19484B21812EC5007C2260 /* OTDeviceInformationAdapter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTDeviceInformationAdapter.m; sourceTree = ""; }; DC1DA65C1E4554620094CE7F /* CKKSScanLocalItemsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSScanLocalItemsOperation.h; sourceTree = ""; }; DC1DA6671E4555D80094CE7F /* CKKSScanLocalItemsOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSScanLocalItemsOperation.m; sourceTree = ""; }; + DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSPeerProvider.h; sourceTree = ""; }; + DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSPeerProvider.m; sourceTree = ""; }; DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSItemEncrypter.m; sourceTree = ""; }; DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSItemEncrypter.h; sourceTree = ""; }; DC1ED8C21DD5538C002BDCFA /* CKKS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKS.h; sourceTree = ""; }; @@ -13649,7 +13606,6 @@ DC4DB15E1E2590B100CD6769 /* CKKSAESSIVEncryptionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSAESSIVEncryptionTests.m; sourceTree = ""; }; DC5060E920E2D88300925005 /* OTCuttlefishContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTCuttlefishContext.h; sourceTree = ""; }; DC5060EA20E2D88300925005 /* OTCuttlefishContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCuttlefishContext.m; sourceTree = ""; }; - DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCuttlefishContextTests.m; sourceTree = ""; }; DC5225091E402D8B0021640A /* PlatformLibraries.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = PlatformLibraries.xcconfig; path = xcconfig/PlatformLibraries.xcconfig; sourceTree = ""; }; DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurityd_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libSecureObjectSyncServer.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -15248,8 +15204,8 @@ DCE4E7CC1D7A4AED00AFB96E /* sectests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sectests; sourceTree = BUILT_PRODUCTS_DIR; }; DCE4E7E11D7A4B7F00AFB96E /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = OSX/sectests/main.c; sourceTree = SOURCE_ROOT; }; DCE4E7F61D7A4DA800AFB96E /* secd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secd; sourceTree = BUILT_PRODUCTS_DIR; }; - DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.secd.plist; path = ../ipc/com.apple.secd.plist; sourceTree = ""; }; - DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.securityd.plist; path = OSX/sec/os_log/com.apple.securityd.plist; sourceTree = ""; }; + DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.secd.plist; sourceTree = ""; }; + DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.securityd.plist; sourceTree = ""; }; DCE4E8141D7A4E6F00AFB96E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; }; DCE4E81B1D7A4E8F00AFB96E /* libsqlite3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.0.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libsqlite3.0.dylib; sourceTree = DEVELOPER_DIR; }; DCE4E8271D7A4F0E00AFB96E /* login.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = login.framework; path = System/Library/PrivateFrameworks/login.framework; sourceTree = SDKROOT; }; @@ -15756,10 +15712,10 @@ E7FCBE411314471B000DE34E /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; E7FCBE431314471B000DE34E /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E7FCBE451314471B000DE34E /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedStore.m; path = ../../../../keychain/SecureObjectSync/CKDSimulatedStore.m; sourceTree = ""; }; - E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedStore.h; path = ../../../../keychain/SecureObjectSync/CKDSimulatedStore.h; sourceTree = ""; }; - E7FE40C71DC8084600F0F5B6 /* CKDSimulatedAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedAccount.h; path = ../../../../keychain/SecureObjectSync/Regressions/CKDSimulatedAccount.h; sourceTree = ""; }; - E7FE40C81DC8084600F0F5B6 /* CKDSimulatedAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedAccount.m; path = ../../../../keychain/SecureObjectSync/Regressions/CKDSimulatedAccount.m; sourceTree = ""; }; + E7FE40C41DC804E400F0F5B6 /* CKDSimulatedStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedStore.m; path = ../../SecureObjectSync/CKDSimulatedStore.m; sourceTree = ""; }; + E7FE40C61DC804FA00F0F5B6 /* CKDSimulatedStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedStore.h; path = ../../SecureObjectSync/CKDSimulatedStore.h; sourceTree = ""; }; + E7FE40C71DC8084600F0F5B6 /* CKDSimulatedAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CKDSimulatedAccount.h; path = ../../SecureObjectSync/Regressions/CKDSimulatedAccount.h; sourceTree = ""; }; + E7FE40C81DC8084600F0F5B6 /* CKDSimulatedAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CKDSimulatedAccount.m; path = ../../SecureObjectSync/Regressions/CKDSimulatedAccount.m; sourceTree = ""; }; E7FEFB80169E26E200E18152 /* sub_commands.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sub_commands.h; sourceTree = ""; }; EB056E401FE5E390000A771E /* SecRemoteDeviceProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRemoteDeviceProtocol.h; sourceTree = ""; }; EB056E411FE5E390000A771E /* SecRemoteDevice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecRemoteDevice.h; sourceTree = ""; }; @@ -15792,6 +15748,9 @@ EB3A8DD71BEEC4D6001A89AA /* Security_edumode.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Security_edumode.plist; sourceTree = ""; }; EB3F9C9B21FCFC60007B6EBA /* OctagonTestHarness.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OctagonTestHarness.m; sourceTree = ""; }; EB3F9C9E21FCFF8E007B6EBA /* OctagonTestHarness.exp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.exports; path = OctagonTestHarness.exp; sourceTree = ""; }; + EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.trustedpeers.plist; sourceTree = ""; }; + EB3FBBF42320629400DF52EA /* SecABC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecABC.h; sourceTree = ""; }; + EB3FBBF52320629400DF52EA /* SecABC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecABC.m; sourceTree = ""; }; EB413B751E6624A400592085 /* PairingChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PairingChannel.h; sourceTree = ""; }; EB413B761E6624A500592085 /* PairingChannel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PairingChannel.m; sourceTree = ""; }; EB413B7E1E663A8300592085 /* KCPairingTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCPairingTest.m; path = Tests/KCPairingTest.m; sourceTree = ""; }; @@ -15820,7 +15779,7 @@ EB6928BF1D9C9C5900062A18 /* SecRecoveryKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecRecoveryKey.m; sourceTree = ""; }; EB6928C91D9C9D9D00062A18 /* rk_01_recoverykey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = rk_01_recoverykey.m; path = Regressions/rk_01_recoverykey.m; sourceTree = ""; }; EB6952B9223B75C300F02C1C /* secitemd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secitemd; sourceTree = BUILT_PRODUCTS_DIR; }; - EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = com.apple.secitemd.plist; path = OSX/sec/ipc/com.apple.secitemd.plist; sourceTree = SOURCE_ROOT; }; + EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.secitemd.plist; sourceTree = ""; }; EB69AB091BF4347700913AF1 /* SecEMCSPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecEMCSPriv.h; sourceTree = ""; }; EB6AC0AA22F22E80003F067B /* SecTapToRadarTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecTapToRadarTests.m; sourceTree = ""; }; EB6D1D5322FE8D3000205E83 /* SecItemTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecItemTests.m; sourceTree = ""; }; @@ -15877,7 +15836,7 @@ EB82A2A41FAFF26900CA64A9 /* SFBehavior.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFBehavior.h; sourceTree = ""; }; EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFBehavior.m; sourceTree = ""; }; 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; name = com.apple.recovery_securityd.plist; path = ../ipc/com.apple.recovery_securityd.plist; sourceTree = ""; }; + EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.recovery_securityd.plist; sourceTree = ""; }; EB89111020E3C15D00DE533F /* UserManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserManagement.framework; path = System/Library/PrivateFrameworks/UserManagement.framework; sourceTree = SDKROOT; }; EB9795B422FE90E6002BDBFB /* SecurityUnitTests.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SecurityUnitTests.entitlements; sourceTree = ""; }; EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-37-pairing-initial-sync.m"; sourceTree = ""; }; @@ -17146,7 +17105,6 @@ DC65E7241D8CB29E00152EF0 /* libutilities.a in Frameworks */, DC1789131D7798B300B50D50 /* libDiagnosticMessagesClient.dylib in Frameworks */, DC1789281D779A0F00B50D50 /* libaks_acl.a in Frameworks */, - DC1789171D77998700B50D50 /* libauto.dylib in Frameworks */, DC1789191D77998C00B50D50 /* libbsm.dylib in Frameworks */, DC17892A1D779A3200B50D50 /* libcoreauthd_client.a in Frameworks */, DC3A81D61D99D57F000C7419 /* libcoretls.dylib in Frameworks */, @@ -17334,7 +17292,6 @@ DC5AC0D41D83547A00CF422C /* libsecuritydservice_client.a in Frameworks */, DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */, BEE523DC1DACAA9200DD0AA3 /* libz.dylib in Frameworks */, - DC5AC0D21D83544800CF422C /* libauto.dylib in Frameworks */, DC1002AF1D8E18870025549C /* libsecurity_codesigning.a in Frameworks */, DCB7D8D11D8E185900867385 /* libsecurity_utilities.a in Frameworks */, DCD22D6C1D8CC6FD001C9B81 /* libsecurityd_client.a in Frameworks */, @@ -18038,22 +17995,20 @@ buildActionMask = 2147483647; files = ( DC4A76AC221269E4006F2D8F /* CloudServices.framework in Frameworks */, - 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */, - EB80DE59219600DF005B10FA /* libz.tbd in Frameworks */, + EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */, DC3E18EB2125FB8700073D80 /* libaks_mock.a in Frameworks */, - 482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */, + EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */, + EB80DE59219600DF005B10FA /* libz.tbd in Frameworks */, EB49B2C2202DF002003F34A0 /* libDER.a in Frameworks */, - EB49B2BD202DEF29003F34A0 /* libSecureObjectSyncFramework.a in Frameworks */, + 482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */, + 0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */, EB49B2BE202DEF29003F34A0 /* libSecureObjectSyncServer.a in Frameworks */, - EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */, - EB49B2BF202DEF67003F34A0 /* libsecurity.a in Frameworks */, EB49B2C1202DEF8D003F34A0 /* libASN1.a in Frameworks */, EB49B2C0202DEF7D003F34A0 /* libutilities.a in Frameworks */, EB49B308202FF421003F34A0 /* OCMock.framework in Frameworks */, EB49B2D2202DF17D003F34A0 /* SecurityFoundation.framework in Frameworks */, EB49B2CD202DF0F9003F34A0 /* SystemConfiguration.framework in Frameworks */, EB49B2C7202DF0E9003F34A0 /* IOKit.framework in Frameworks */, - EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */, EB49B2BC202DEF14003F34A0 /* libsqlite3.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -18247,10 +18202,8 @@ children = ( DCD33D7D220B9D98000A390B /* State Machine Machinery */, DC130B7920D04CFE0065CE61 /* Categories */, - DC68527220D04C6000C61368 /* Octagon via CK API */, DC68527120D04A5800C61368 /* Framework */, DC68527020D04A3200C61368 /* IPC */, - DC68526A20D04A1000C61368 /* Bottled Peers */, DCC67E2A20DDC05900A70A31 /* Operations */, 0CCCC7C720261D050024405E /* OT.h */, 0CCCC7C820261D310024405E /* OT.m */, @@ -18264,18 +18217,12 @@ 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */, DCC67E0C20DD7E0A00A70A31 /* OTStates.h */, DCC67E0D20DD7E0A00A70A31 /* OTStates.m */, - 0CD9E8071FE05B8700F66C38 /* OTContextRecord.h */, - 0CD9E7FF1FE05B6600F66C38 /* OTContextRecord.m */, 0C8BBE971FC9DA5A00580909 /* OTDefines.h */, EBCE06E521C6E26000FB1493 /* OTDefines.m */, 0C6604782134C86500BFBBB8 /* OTDeviceInformation.h */, 0C66047B2134C88C00BFBBB8 /* OTDeviceInformation.m */, 5A04BAF622973E43001848A0 /* OTFollowup.h */, 5A04BAF722973E43001848A0 /* OTFollowup.m */, - 0C8BBE8A1FC9DA5300580909 /* OTIdentity.h */, - 0C8BBE8D1FC9DA5400580909 /* OTIdentity.m */, - 0C8BBE8E1FC9DA5500580909 /* OTLocalStore.h */, - 0C8BBE8C1FC9DA5400580909 /* OTLocalStore.m */, 0C8BBF101FCB486B00580909 /* OTManager.h */, 0C8BBF0F1FCB481800580909 /* OTManager.m */, 0C8FD546214AEC650098E3FB /* OTJoiningConfiguration.h */, @@ -18300,7 +18247,6 @@ isa = PBXGroup; children = ( DC99B89720EAD4D20065B73B /* Octagon */, - DC99B89620EAD4AB0065B73B /* CK API */, ); path = tests; sourceTree = ""; @@ -18618,10 +18564,11 @@ isa = PBXGroup; children = ( DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */, + EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */, 48284A041D1DB06E00C76CB7 /* README_os_log_prefs.txt */, ); name = os_log; - path = ../../..; + path = ../../OSX/sec/os_log; sourceTree = ""; }; 4C198F1A0ACDB4BF00AAB142 /* strings */ = { @@ -18935,6 +18882,7 @@ D4707A0D211373D4005BCFDA /* CMSPrivate.h */, DC1785981D778C5300B50D50 /* cssmapple.h */, 4C28BCD60986EBCB0020C665 /* certextensions.h */, + 443381D918A3D81400215606 /* SecAccessControl.h */, 4C696B3709BFA94F000CBC75 /* SecBase.h */, 4C0208F80D3C154200BFE54E /* SecBasePriv.h */, 4C8FD03D099D5C91006867B6 /* SecCertificate.h */, @@ -18973,6 +18921,7 @@ 5A6D1B9420810EA40057CAC8 /* SecProtocolTypes.h */, AAE91C542162634200B6BF0B /* SecProtocolTypesPriv.h */, 4C2F81D40BF121D2003C4F77 /* SecRandom.h */, + BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */, D43718C721168D7C00EA350A /* SecSMIME.h */, 107226D10D91DB32003CF14F /* SecTask.h */, DCD068031D8CDF7E007602F1 /* SecTaskPriv.h */, @@ -19551,6 +19500,8 @@ BECEC11120A508F600E97255 /* TPVoucher.m */, DC88467F2237431400738068 /* TPDictionaryMatchingRules.h */, DC8846802237431400738068 /* TPDictionaryMatchingRules.m */, + DA700FC62310C0DF0051A7DE /* TPStringTable.h */, + DA700FC82310C0E00051A7DE /* TPStringTable.m */, BEB49F29206E98CD008DA7F4 /* TPECPublicKeyFactory.h */, BEB49F2F206E98CE008DA7F4 /* TPECPublicKeyFactory.m */, BEB49F32206E9A18008DA7F4 /* SFKey+TPKey.h */, @@ -19583,6 +19534,7 @@ BE72782A209D27C800F0DA77 /* TPKeyTests.m */, BEB49F36206E9B89008DA7F4 /* TPECPublicKeyFactoryTests.m */, E291657E2048BCCB0046512B /* TPPBPeerStableInfoTests.m */, + DA3AD8682319AA310049AFD6 /* TPStringTableTests.m */, BEF88C661EB0008E00357577 /* Info.plist */, ); name = Tests; @@ -20695,6 +20647,8 @@ 5A04BB1F2298728A001848A0 /* test */, DC0BCC3A1D8C68CF00070CB0 /* iCloudKeychainTrace.c */, DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */, + EB3FBBF42320629400DF52EA /* SecABC.h */, + EB3FBBF52320629400DF52EA /* SecABC.m */, EBF3749A1DC064200065D840 /* SecADWrapper.c */, EBF3749B1DC064200065D840 /* SecADWrapper.h */, DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */, @@ -20762,7 +20716,7 @@ DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */, DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */, DC0BCC701D8C68CF00070CB0 /* SecXPCError.c */, - DC0BCC711D8C68CF00070CB0 /* simulate_crash.c */, + DC0BCC711D8C68CF00070CB0 /* simulate_crash.m */, DC0BCC721D8C68CF00070CB0 /* SecSCTUtils.h */, DC0BCC731D8C68CF00070CB0 /* SecSCTUtils.c */, DC0BCC741D8C68CF00070CB0 /* SecAppleAnchor.c */, @@ -20782,7 +20736,6 @@ DCC78E281D8085FC00865A7C /* AppleBaselineEscrowCertificates.h */, D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */, DCC78E301D8085FC00865A7C /* SecAccessControl.m */, - 443381D918A3D81400215606 /* SecAccessControl.h */, 443381DA18A3D81400215606 /* SecAccessControlPriv.h */, DCC78E351D8085FC00865A7C /* SecBase64.c */, 18351B8F14CB65870097860E /* SecBase64.h */, @@ -20858,7 +20811,6 @@ DCC78E8A1D8085FC00865A7C /* SecServerEncryptionSupport.c */, E7676DB519411DF300498DD4 /* SecServerEncryptionSupport.h */, DCC78E8C1D8085FC00865A7C /* SecSharedCredential.c */, - BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */, DCC78E8E1D8085FC00865A7C /* SecSignatureVerificationSupport.c */, DCC78E8F1D8085FC00865A7C /* SecSignatureVerificationSupport.h */, DCC78E901D8085FC00865A7C /* SecTrust.c */, @@ -21061,6 +21013,18 @@ path = generated_source; sourceTree = ""; }; + DC33071B2328567C0035CDFB /* ipc */ = { + isa = PBXGroup; + children = ( + DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */, + EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */, + DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */, + EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */, + ); + name = ipc; + path = ../../OSX/sec/ipc; + sourceTree = ""; + }; DC35021A1E009E0700BC0587 /* Database Helpers */ = { isa = PBXGroup; children = ( @@ -21639,10 +21603,7 @@ DC5AC2001D83653E00CF422C /* resources */ = { isa = PBXGroup; children = ( - DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */, - EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */, - DCE4E8091D7A4E1C00AFB96E /* com.apple.secd.plist */, - EB6952BC223B783500F02C1C /* com.apple.secitemd.plist */, + DC33071B2328567C0035CDFB /* ipc */, DC9EBA2F1DEE651500D0F733 /* Info-macOS.plist */, ); name = resources; @@ -21726,25 +21687,6 @@ name = gk_reset_check; sourceTree = ""; }; - DC68526A20D04A1000C61368 /* Bottled Peers */ = { - isa = PBXGroup; - children = ( - 0C8BBE921FC9DA5700580909 /* OTEscrowKeys.h */, - 0C8BBE961FC9DA5900580909 /* OTEscrowKeys.m */, - 0C8BBE951FC9DA5800580909 /* OTBottledPeer.h */, - 0C8BBE931FC9DA5700580909 /* OTBottledPeer.m */, - BE2AD2B11FDA07EF00739F96 /* OTBottledPeerRecord.h */, - BE2AD2B21FDA07EF00739F96 /* OTBottledPeerRecord.m */, - 0CE1BCCD1FCE11610017230E /* OTBottledPeerSigned.h */, - 0CE1BCC61FCE11480017230E /* OTBottledPeerSigned.m */, - 0C101F96205352AF00387951 /* OTBottledPeerState.h */, - 0C101F932053528700387951 /* OTBottledPeerState.m */, - 0C36B3202007EE9B0029F7A2 /* OTPreflightInfo.h */, - 0C36B3172007EE6C0029F7A2 /* OTPreflightInfo.m */, - ); - name = "Bottled Peers"; - sourceTree = ""; - }; DC68527020D04A3200C61368 /* IPC */ = { isa = PBXGroup; children = ( @@ -21769,19 +21711,6 @@ name = Framework; sourceTree = ""; }; - DC68527220D04C6000C61368 /* Octagon via CK API */ = { - isa = PBXGroup; - children = ( - 0C8BBE8B1FC9DA5300580909 /* OTContext.h */, - 0C8BBE981FC9DA5A00580909 /* OTContext.m */, - 0C8BBE891FC9DA5200580909 /* OTCloudStore.h */, - 0C770EC31FCF7E2000B5F0E2 /* OTCloudStore.m */, - 0CE407B31FD476E000F59B31 /* OTCloudStoreState.h */, - 0CE407AB1FD4769B00F59B31 /* OTCloudStoreState.m */, - ); - name = "Octagon via CK API"; - sourceTree = ""; - }; DC6A82061D87731C00418608 /* libsecurityd */ = { isa = PBXGroup; children = ( @@ -22061,26 +21990,6 @@ path = Framework; sourceTree = ""; }; - DC99B89620EAD4AB0065B73B /* CK API */ = { - isa = PBXGroup; - children = ( - 0C8A034E1FDF60070042E8BE /* OTBottledPeerTests.m */, - 0CBDF64C1FFC951200433E0D /* OTBottledPeerTLK.m */, - 0C2F337520DD64C10031A92D /* OTCliqueTests.m */, - 0C8A034C1FDF4CCE0042E8BE /* OTLocalStoreTests.m */, - 0C2F337620DD64C20031A92D /* OTTestsBase.h */, - 0C2F337720DD64C20031A92D /* OTTestsBase.m */, - 0C24D692204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m */, - 0C16371F1FD12F1500210823 /* OTCloudStoreTests.m */, - 0C8BBEAF1FC9DCA400580909 /* OTContextTests.m */, - 0C8A03451FDF42BA0042E8BE /* OTEscrowKeyTests.m */, - 0C46A57A2035019800F17112 /* OTLockStateNetworkingTests.m */, - 0CB975502023B199008D6B48 /* OTRampingTests.m */, - DC5060F420E2DB9700925005 /* OTCuttlefishContextTests.m */, - ); - name = "CK API"; - sourceTree = ""; - }; DC99B89720EAD4D20065B73B /* Octagon */ = { isa = PBXGroup; children = ( @@ -22135,6 +22044,8 @@ DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */, DC9FD3281F8598F300C8AAC8 /* CKKSPeer.h */, DC9FD3291F8598F300C8AAC8 /* CKKSPeer.m */, + DC1E5AB423063A4D00918162 /* CKKSPeerProvider.h */, + DC1E5AB523063A4E00918162 /* CKKSPeerProvider.m */, DC1ED8C01DD51890002BDCFA /* CKKSItemEncrypter.h */, DC1ED8BA1DD51883002BDCFA /* CKKSItemEncrypter.m */, 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */, @@ -22759,6 +22670,8 @@ DCC67E2A20DDC05900A70A31 /* Operations */ = { isa = PBXGroup; children = ( + 1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */, + 1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */, DCB946AD22FCB88400BE4490 /* OTDetermineHSA2AccountStatusOperation.h */, DCB946AE22FCB88500BE4490 /* OTDetermineHSA2AccountStatusOperation.m */, DCE772642290712F005862B4 /* OctagonCheckTrustStateOperation.h */, @@ -22963,7 +22876,7 @@ 1B995258226681EE00A2D6CD /* PolicyReporter.m */, ); name = "securityd iOS"; - path = OSX/sec/securityd; + path = keychain/securityd; sourceTree = ""; }; DCC78CFC1D8085F200865A7C /* CKBridge */ = { @@ -23041,6 +22954,8 @@ DCC78D2C1D8085F200865A7C /* SOSUserKeygen.h */, 485B64081DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.c */, 485B64091DC16E8300B771B9 /* SOSKeyedPubKeyIdentifier.h */, + 48AC7B5C232B1A1700F02B6F /* SOSIntervalEvent.h */, + 48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */, DCC78D111D8085F200865A7C /* SOSExports.exp-in */, ); name = Account; @@ -24243,6 +24158,7 @@ DCE4E85D1D7A584D00AFB96E /* iOS */, ); name = trustd; + path = trust/trustd; sourceTree = ""; }; DCE4E85D1D7A584D00AFB96E /* iOS */ = { @@ -24253,7 +24169,7 @@ D41257EE1E941DA800781F23 /* com.apple.trustd.plist */, D45068691E948ACE00FA7675 /* entitlements.plist */, ); - name = iOS; + path = iOS; sourceTree = ""; }; DCE4E85E1D7A585300AFB96E /* macOS */ = { @@ -24265,7 +24181,7 @@ D41257EA1E941CF200781F23 /* com.apple.trustd.plist */, D41257E91E941CF200781F23 /* com.apple.trustd.agent.plist */, ); - name = macOS; + path = macOS; sourceTree = ""; }; DCE4E8A01D7F352600AFB96E /* authd */ = { @@ -25396,7 +25312,6 @@ DC1789141D77997F00B50D50 /* libOpenScriptingUtil.dylib */, EB2CA4D81D2C28C800AB770F /* libaks.a */, 4432AF8C1A01472C000958DC /* libaks_acl.a */, - DC1789161D77998700B50D50 /* libauto.dylib */, DC1789181D77998C00B50D50 /* libbsm.dylib */, E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */, 0CFC029B1D41650700E6283B /* libcoretls.dylib */, @@ -25702,7 +25617,6 @@ 4718AEA2205B39C40068EC3F /* CKKSGroupOperation.h in Headers */, 4718AEA3205B39C40068EC3F /* CKKSRateLimiter.h in Headers */, 4718AEA4205B39C40068EC3F /* SecDbKeychainSerializedItemV7.h in Headers */, - 4718AEA5205B39C40068EC3F /* OTCloudStore.h in Headers */, 4718AEA6205B39C40068EC3F /* CKKSResultOperation.h in Headers */, 4718AEA7205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.h in Headers */, 4718AEA8205B39C40068EC3F /* CKKSViewManager.h in Headers */, @@ -25868,7 +25782,6 @@ 6C73F48F2006B910003D5D63 /* SOSAnalytics.h in Headers */, DCD7EE9A1F4F5156007D9804 /* oidsocsp.h in Headers */, D4B3B1D821151BBF00A43409 /* SecCmsSignedData.h in Headers */, - BE2AD2B31FDA07EF00739F96 /* OTBottledPeerRecord.h in Headers */, 4AF7000115AFB73800B9D400 /* SecOTRMath.h in Headers */, 4AF7000315AFB73800B9D400 /* SecOTRPacketData.h in Headers */, D4707A232113E74B005BCFDA /* SecCmsEncoder.h in Headers */, @@ -25953,6 +25866,7 @@ BEF88C8E1EB000BE00357577 /* TPTypes.h in Headers */, DCD7DDA022B86A5500161396 /* TPPBDispositionDuplicateMachineID.h in Headers */, BEF88C811EB000BE00357577 /* TPPeer.h in Headers */, + DA700FC92310C0E00051A7DE /* TPStringTable.h in Headers */, BEC373B220D815F500DBDF5B /* TPPBUnknownMachineID.h in Headers */, DC730E1322400D7B0051DD48 /* TPDictionaryMatchingRules.h in Headers */, BEB49F30206E98D0008DA7F4 /* TPECPublicKeyFactory.h in Headers */, @@ -26681,6 +26595,7 @@ DC0FA6B02291F63F00FE01C4 /* OctagonPendingFlag.h in Headers */, 47922D421FAA7C240008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.h in Headers */, DCFE1C341F17ECE5007640C8 /* CKKSCondition.h in Headers */, + DC1E5AB623063A4E00918162 /* CKKSPeerProvider.h in Headers */, DC047081218BB21E0078BDAA /* OTCuttlefishAccountStateHolder.h in Headers */, DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */, DC2C5F5D1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */, @@ -26689,7 +26604,6 @@ 47922D541FAA7E060008F7E0 /* SecDbKeychainSerializedItemV7.h in Headers */, DCD33D93220CFF8A000A390B /* EscrowRequestPerformEscrowEnrollOperation.h in Headers */, DCC54181225C05180095D926 /* OTUploadNewCKKSTLKsOperation.h in Headers */, - 0C770EBC1FCF7C9800B5F0E2 /* OTCloudStore.h in Headers */, DC14478A1F5764C600236DB4 /* CKKSResultOperation.h in Headers */, DCFE1C511F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.h in Headers */, DCBDB3BB1E57CA7A00B61300 /* CKKSViewManager.h in Headers */, @@ -28820,6 +28734,7 @@ BEAA0027202A832500E51F45 /* Sources */, BEAA0029202A832500E51F45 /* Resources */, BEAA0028202A832500E51F45 /* Frameworks */, + EB3FB9A3231C125400DF52EA /* Copy Logging Files */, ); buildRules = ( ); @@ -32524,8 +32439,8 @@ inputFileListPaths = ( ); inputPaths = ( - "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA.cer", - "$(SRCROOT)/OSX/trustd/iOS/AppleCorporateRootCA2.cer", + "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA.cer", + "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA2.cer", ); name = "Install Apple Corporate Roots"; outputFileListPaths = ( @@ -32536,7 +32451,7 @@ ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "ditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/OSX/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n"; + shellScript = "ditto ${SRCROOT}/trust/trustd/iOS/AppleCorporateRootCA.cer ${DSTROOT}/AppleInternal/Library/Security/\nditto ${SRCROOT}/trust/trustd/iOS/AppleCorporateRootCA2.cer ${DSTROOT}/AppleInternal/Library/Security/\nchown -R root:wheel ${DSTROOT}/AppleInternal/Library/Security/\n"; }; D4C263C41F8FEAA8001317EA /* Run Script Generate Error Strings */ = { isa = PBXShellScriptBuildPhase; @@ -33039,20 +32954,12 @@ 0C7A8BBF21714CDC00F4C480 /* OTJoiningConfiguration.m in Sources */, 0C48B380202E438100A0E1AA /* CloudKitKeychainSyncingMockXCTest.m in Sources */, 0CB9754F2023A8F5008D6B48 /* CloudKitMockXCTest.m in Sources */, - 0C24D693204F56E900926E5F /* OTBottledPeerUpdateBottlesTests.m in Sources */, 0C0DA5D01FE1F1F3003BD3BB /* CKKSControlProtocol.m in Sources */, - 0CBDF64D1FFC951200433E0D /* OTBottledPeerTLK.m in Sources */, 0C16371C1FD116B300210823 /* MockCloudKit.m in Sources */, - 0C8A034F1FDF60070042E8BE /* OTBottledPeerTests.m in Sources */, 6C53A44D206AB1EF000FA611 /* LocalKeychainAnalytics.m in Sources */, - 0C1637211FD12F1500210823 /* OTCloudStoreTests.m in Sources */, - 0CAEC9D81FD740CF00D1F2CA /* OTContextTests.m in Sources */, 0C0DA5CF1FE1F1C5003BD3BB /* OTControlProtocol.m in Sources */, - 0C8A03461FDF42BA0042E8BE /* OTEscrowKeyTests.m in Sources */, - 0C8A034D1FDF4CCE0042E8BE /* OTLocalStoreTests.m in Sources */, DCDB296C1FD8820400B5D242 /* SFAnalytics.m in Sources */, 6C73F48D2006B83E003D5D63 /* SOSAnalytics.m in Sources */, - 0C46A57B2035019800F17112 /* OTLockStateNetworkingTests.m in Sources */, DC5B391820C08B39005B09F6 /* SecFramework.c in Sources */, DCDB296E1FD8821400B5D242 /* SFAnalyticsActivityTracker.m in Sources */, DCDB29701FD8821800B5D242 /* SFAnalyticsMultiSampler.m in Sources */, @@ -33061,23 +32968,19 @@ 0C46A5712034C6BA00F17112 /* OTControl.m in Sources */, DCDB29721FD8821D00B5D242 /* SFAnalyticsSampler.m in Sources */, DCDB297E1FD8849D00B5D242 /* SFObjCType.m in Sources */, - 0CF74E4120DDD5290014A5DB /* OTTestsBase.m in Sources */, 5A061197229ED6EB006AF14A /* NSDate+SFAnalytics.m in Sources */, DCDB297C1FD8848A00B5D242 /* SFSQLite.m in Sources */, 0CA4EBF4202B8DBE002B1D96 /* CloudKitKeychainSyncingTestsBase.m in Sources */, DCDB297D1FD8849A00B5D242 /* SFSQLiteStatement.m in Sources */, - 0CF74E4720DDD5390014A5DB /* OTCliqueTests.m in Sources */, DCDB297B1FD8847100B5D242 /* SecTask.c in Sources */, 0CE751AF20ACC497002B2832 /* SFSignInAnalytics.m in Sources */, 0C1637291FD2066A00210823 /* SecdWatchdog.m in Sources */, DCDB29791FD8844C00B5D242 /* client.c in Sources */, DCDB297A1FD8845600B5D242 /* client_endpoint.m in Sources */, - 0CB975512023B199008D6B48 /* OTRampingTests.m in Sources */, 0C16372B1FD2067F00210823 /* server_endpoint.m in Sources */, 0C16372D1FD2069300210823 /* server_entitlement_helpers.c in Sources */, 0C1637301FD206BC00210823 /* server_security_helpers.m in Sources */, 0C1637271FD2065400210823 /* spi.c in Sources */, - DC5060F520E2DB9700925005 /* OTCuttlefishContextTests.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -33255,17 +33158,15 @@ 4718AE37205B39C40068EC3F /* CKKSAccountStateTracker.m in Sources */, 4718AE38205B39C40068EC3F /* SecCDKeychain.m in Sources */, 4718AE3A205B39C40068EC3F /* CKKSGroupOperation.m in Sources */, - 4718AE3B205B39C40068EC3F /* OTContextRecord.m in Sources */, 4718AE3D205B39C40068EC3F /* CKKSManifestLeafRecord.m in Sources */, DC8DF6DF212F8A7D007B3FE8 /* OTSOSAdapter.m in Sources */, 4718AE3E205B39C40068EC3F /* CKKSItem.m in Sources */, 4718AE3F205B39C40068EC3F /* CKKSItemEncrypter.m in Sources */, 4718AE40205B39C40068EC3F /* CKKSOutgoingQueueEntry.m in Sources */, 4718AE42205B39C40068EC3F /* CKKSIncomingQueueEntry.m in Sources */, - 4718AE43205B39C40068EC3F /* OTLocalStore.m in Sources */, 4718AE44205B39C40068EC3F /* SFKeychainControlManager.m in Sources */, DC3AF52F2229E770006577E8 /* CKKSListenerCollection.m in Sources */, - 4718AE45205B39C40068EC3F /* OTBottledPeerSigned.m in Sources */, + 0C29BF2523232897003C807E /* OTDefines.m in Sources */, 4718AE46205B39C40068EC3F /* CKKSIncomingQueueOperation.m in Sources */, 4718AE47205B39C40068EC3F /* CKKSOutgoingQueueOperation.m in Sources */, 4718AE48205B39C40068EC3F /* CKKSZoneStateEntry.m in Sources */, @@ -33275,7 +33176,6 @@ 6C4AEF97218A12810012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */, 4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */, 4718AE4E205B39C40068EC3F /* OTManager.m in Sources */, - 4718AE4F205B39C40068EC3F /* OTEscrowKeys.m in Sources */, 4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */, 4718AE51205B39C40068EC3F /* CKKSControlServer.m in Sources */, 4718AE52205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.m in Sources */, @@ -33315,20 +33215,17 @@ 4718AE71205B39C40068EC3F /* SecItemServer.c in Sources */, 4718AE72205B39C40068EC3F /* SecDbKeychainSerializedAKSWrappedKey.m in Sources */, D491112D209515400066A1E4 /* CKKSAnalytics.m in Sources */, - 4718AE74205B39C40068EC3F /* OTContext.m in Sources */, 4718AE75205B39C40068EC3F /* NSOperationCategories.m in Sources */, 4718AE76205B39C40068EC3F /* SecKeybagSupport.c in Sources */, 4718AE77205B39C40068EC3F /* SecLogSettingsServer.m in Sources */, 4718AE78205B39C40068EC3F /* CKKSDeviceStateEntry.m in Sources */, 4718AE79205B39C40068EC3F /* CKKSFixups.m in Sources */, - 4718AE7A205B39C40068EC3F /* OTIdentity.m in Sources */, 4718AE7C205B39C40068EC3F /* SecOTRRemote.m in Sources */, 4718AE7D205B39C40068EC3F /* CKKSUpdateCurrentItemPointerOperation.m in Sources */, 4718AE7E205B39C40068EC3F /* CKKSNewTLKOperation.m in Sources */, 4718AE7F205B39C40068EC3F /* CKKSLockStateTracker.m in Sources */, 6C9791C821C20CFF0074C609 /* NSError+UsefulConstructors.m in Sources */, 6C4AEFA1218A189B0012C5DA /* SecAKSObjCWrappers.m in Sources */, - 4718AE80205B39C40068EC3F /* OTCloudStoreState.m in Sources */, 6C4AEF89218A09E80012C5DA /* CheckV12DevEnabled.m in Sources */, 4718AE81205B39C40068EC3F /* SecDbKeychainSerializedSecretData.m in Sources */, 4718AE82205B39C40068EC3F /* CKKSKeychainView.m in Sources */, @@ -33343,15 +33240,11 @@ 4718AE8B205B39C40068EC3F /* iCloudTrace.c in Sources */, 4718AE8C205B39C40068EC3F /* OctagonAPSReceiver.m in Sources */, DC391F9F21BF2F8700772585 /* CKKSConstants.m in Sources */, - 4718AE8D205B39C40068EC3F /* OTBottledPeer.m in Sources */, 6C880FCD21C3351500D38D66 /* SecDbBackupBag.m in Sources */, 4718AE8F205B39C40068EC3F /* SOSEnsureBackup.m in Sources */, - 4718AE90205B39C40068EC3F /* OTBottledPeerRecord.m in Sources */, 6C880FD121C3351500D38D66 /* SecDbBackupRecoverySet.m in Sources */, - 4718AE91205B39C40068EC3F /* OTCloudStore.m in Sources */, 6C880FCE21C3351500D38D66 /* SecDbBackupBagIdentity.m in Sources */, 4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */, - 4718AE93205B39C40068EC3F /* OTPreflightInfo.m in Sources */, 4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */, 4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */, 4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */, @@ -33839,6 +33732,7 @@ DC391F9D21BF2F8100772585 /* CKKSConstants.m in Sources */, BE9F8D10206C099800B53D16 /* Container.swift in Sources */, 0CB582D3218920090040C5F2 /* OTPrivateKey.m in Sources */, + DC25B3AC233C2EBC00CB1409 /* CloudKitCategories.m in Sources */, BE55C77C2044D0C90045863D /* Client.swift in Sources */, BE55C77E2044D7E60045863D /* main.swift in Sources */, DCAD8F8622C43EC1007C3872 /* Container_MachineIDs.swift in Sources */, @@ -33881,6 +33775,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1B0CDF64231C9E0E004401F0 /* ContainerMap.swift in Sources */, 0CB582CB2189157F0040C5F2 /* OTPrivateKey.m in Sources */, EBF5323A21C8B6330073C1C7 /* OTDefines.m in Sources */, 0CB582C92189157F0040C5F2 /* OTBottle.m in Sources */, @@ -33963,6 +33858,7 @@ DCE0777221ADD71C002662FD /* TPPBPolicyDocument.m in Sources */, DCE0777421ADD71C002662FD /* TPPBPolicyCategoriesByView.m in Sources */, DCE0777621ADD71C002662FD /* TPPBPolicyIntroducersByCategory.m in Sources */, + DA700FCA2310C0E00051A7DE /* TPStringTable.m in Sources */, DCE0777821ADD71C002662FD /* TPPBPolicyModelToCategory.m in Sources */, DCE0777A21ADD71C002662FD /* TPPBPolicyRedaction.m in Sources */, ); @@ -33973,10 +33869,12 @@ buildActionMask = 2147483647; files = ( 1B4AE38722400A22002188E1 /* TPDictionaryMatchingRules.m in Sources */, + DA31CB212319DC8F0039F1CC /* TPStringTable.m in Sources */, BEF88C941EB000FD00357577 /* TPDummyDecrypter.m in Sources */, BEF88C951EB000FD00357577 /* TPDummyEncrypter.m in Sources */, BE72782B209D27C800F0DA77 /* TPKeyTests.m in Sources */, BEF88C981EB000FD00357577 /* TPModelTests.m in Sources */, + DA3AD86A2319AA5D0049AFD6 /* TPStringTableTests.m in Sources */, DC730E142240103A0051DD48 /* TPDictionaryMatchingRuleTests.m in Sources */, E291657F2048BCCB0046512B /* TPPBPeerStableInfoTests.m in Sources */, BEF88C9B1EB000FD00357577 /* TPPeerTests.m in Sources */, @@ -34593,6 +34491,7 @@ DC0BCDAF1D8C6A1F00070CB0 /* SecAppleAnchor.c in Sources */, DC0BCDA41D8C6A1F00070CB0 /* iOSforOSX-SecAttr.c in Sources */, DC0BCD881D8C6A1E00070CB0 /* SecTrace.c in Sources */, + EB3FBC09232063A100DF52EA /* SecABC.m in Sources */, DC0BCD9A1D8C6A1F00070CB0 /* der_plist_internal.c in Sources */, DC0BCDAE1D8C6A1F00070CB0 /* SecSCTUtils.c in Sources */, DC0BCD971D8C6A1E00070CB0 /* der_number.c in Sources */, @@ -34611,7 +34510,7 @@ DC0BCD9C1D8C6A1F00070CB0 /* der_set.c in Sources */, DC36895821235F23003A3735 /* SecAKSWrappers.c in Sources */, EBB8528122F79F6E00424FD0 /* SecXPCHelper.m in Sources */, - DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.c in Sources */, + DC0BCDAC1D8C6A1F00070CB0 /* simulate_crash.m in Sources */, DC0BCD791D8C6A1E00070CB0 /* SecBuffer.c in Sources */, DC0BCDAB1D8C6A1F00070CB0 /* SecXPCError.c in Sources */, DA5B871D2065A8440093F083 /* SecAutorelease.m in Sources */, @@ -34645,6 +34544,7 @@ files = ( EB18A7BA2238C07600A0FC41 /* OTDeviceInformationAdapter.m in Sources */, DC74799E22272358001E0E8C /* CKKSSerializedKey.m in Sources */, + EB3FBB4F231F836500DF52EA /* CKKSListenerCollection.m in Sources */, DC74799D22272344001E0E8C /* CKKSSIV.m in Sources */, DC74799C22272331001E0E8C /* CKKSPeer.m in Sources */, DC74799A222722BC001E0E8C /* CKKSKeychainBackedKey.m in Sources */, @@ -34779,6 +34679,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1BB1CAB7232C05BD001D0C71 /* CuttlefishXPCWrapper.m in Sources */, + 1BB1CAB8232C05BD001D0C71 /* CuttlefishXPCWrapper.h in Sources */, DCE0778021ADEC4B002662FD /* CKKSSerializedKey.m in Sources */, DCE0777F21ADEC07002662FD /* OTAccountMetadataClassC.m in Sources */, 0C84D8351FCF43BB00B822E3 /* OTControlProtocol.m in Sources */, @@ -34789,7 +34691,6 @@ DC797E1A1DD3F9A400CC9E42 /* CKKSSQLDatabaseObject.m in Sources */, 6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */, DCD33D7C220B99CC000A390B /* EscrowRequestController.m in Sources */, - 0C5A8C1D200A9B0C004C771D /* OTPreflightInfo.m in Sources */, DC19484D21812EC5007C2260 /* OTDeviceInformationAdapter.m in Sources */, 6C4AEFA0218A189A0012C5DA /* SecAKSObjCWrappers.m in Sources */, DCFB12C71E95A4C000510F5F /* CKKSAccountStateTracker.m in Sources */, @@ -34800,7 +34701,6 @@ EBB407B31EBA46B200A541A5 /* CKKSPowerCollection.m in Sources */, 0C84D8391FCF43CA00B822E3 /* OTManager.m in Sources */, DCCD88EA1E42622200F5AA71 /* CKKSGroupOperation.m in Sources */, - 0CD9E8001FE05B6600F66C38 /* OTContextRecord.m in Sources */, DC54DD0F1EA7D9E700108E92 /* CKKSManifestLeafRecord.m in Sources */, DCDCCB901DF7B8D4006E840E /* CKKSItem.m in Sources */, DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */, @@ -34808,10 +34708,7 @@ DC6D2C921DD2835A00BE372D /* CKKSOutgoingQueueEntry.m in Sources */, DC378B3D1DF0CA7200A3DAFA /* CKKSIncomingQueueEntry.m in Sources */, 6C880FCB21C3351400D38D66 /* SecDbBackupMetadataClassKey.m in Sources */, - 0C8BBEA91FC9DBBF00580909 /* OTLocalStore.m in Sources */, 4733377B1FDAFBCC00E19F30 /* SFKeychainControlManager.m in Sources */, - 0C101F942053528700387951 /* OTBottledPeerState.m in Sources */, - 0CE1BCCE1FCE11680017230E /* OTBottledPeerSigned.m in Sources */, DC5BB4FA1E0C90DE0010F836 /* CKKSIncomingQueueOperation.m in Sources */, DC5BB5001E0C98320010F836 /* CKKSOutgoingQueueOperation.m in Sources */, 0CB8DC9A2194B14C0021A7C8 /* OTVouchWithBottleOperation.m in Sources */, @@ -34831,7 +34728,6 @@ DCE278DF1ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */, DC3D748E1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m in Sources */, DCC67E2F20DDC07900A70A31 /* OTPrepareOperation.m in Sources */, - 0C8BBEA51FC9DBB100580909 /* OTEscrowKeys.m in Sources */, DCB41DFC216D5E5B00F219E0 /* OTAccountMetadataClassC+KeychainSupport.m in Sources */, 6C880FCC21C3351400D38D66 /* SecDbBackupRecoverySet.m in Sources */, DCA4D1FF1E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */, @@ -34840,6 +34736,7 @@ DCFE1C531F1825F7007640C8 /* CKKSUpdateDeviceStateOperation.m in Sources */, 47922D481FAA7C3C0008F7E0 /* SecDbKeychainSerializedMetadata.m in Sources */, DCD6C4B41EC5302500414FEE /* CKKSNearFutureScheduler.m in Sources */, + 0C29BF222323288C003C807E /* OTDefines.m in Sources */, DC378B2F1DEF9E0E00A3DAFA /* CKKSMirrorEntry.m in Sources */, DC5681AB224DA05F008F8DEB /* OctagonFlags.m in Sources */, 0CD3D519224048A800024755 /* OTSetRecoveryKeyOperation.m in Sources */, @@ -34881,6 +34778,7 @@ DC52E7CC1D80BCDF00B0A59C /* SecDbQuery.c in Sources */, DC14478C1F5764C600236DB4 /* CKKSResultOperation.m in Sources */, 479DA1721EBBA8D10065C98F /* CKKSManifest.m in Sources */, + DC1E5AB723063A4E00918162 /* CKKSPeerProvider.m in Sources */, DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */, 0C2F337220DD64930031A92D /* OTRamping.m in Sources */, DCF12674218A757A000124C6 /* OTLeaveCliqueOperation.m in Sources */, @@ -34917,7 +34815,6 @@ DCE772672290712F005862B4 /* OctagonCheckTrustStateOperation.m in Sources */, 5A04BAF822973E7F001848A0 /* OTFollowup.m in Sources */, DCB837321ED5045000015C07 /* CKKSLockStateTracker.m in Sources */, - 0CE407AC1FD4769B00F59B31 /* OTCloudStoreState.m in Sources */, EB80DE162195EDA4005B10FA /* SecC2DeviceInfo.m in Sources */, 47922D4C1FAA7C4A0008F7E0 /* SecDbKeychainSerializedSecretData.m in Sources */, DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */, @@ -34925,7 +34822,6 @@ 0C4F4DE221153E9E007F7E20 /* OTEpochOperation.m in Sources */, 47922D561FAA7E0D0008F7E0 /* SecDbKeychainSerializedItemV7.m in Sources */, DC7A17EF1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m in Sources */, - 0C48B377202E3EE700A0E1AA /* OTContext.m in Sources */, DC7341F51F8447AB00AB9BDF /* CKKSTLKShareRecord.m in Sources */, 0C5960811FB369C50095BA29 /* CKKSHealTLKSharesOperation.m in Sources */, DCD33D81220B9DC8000A390B /* OctagonStateMachineHelpers.m in Sources */, @@ -34937,16 +34833,12 @@ DCEA5D871E2F14810089CF55 /* OctagonAPSReceiver.m in Sources */, DC0BD4F521BB060F006B9154 /* CKKSKeychainBackedKey.m in Sources */, 6C880FC921C3351400D38D66 /* SecDbBackupBagIdentity.m in Sources */, - 0C8BBE9F1FC9DBA400580909 /* OTBottledPeer.m in Sources */, 6C869A751F50CAF400957298 /* SOSEnsureBackup.m in Sources */, DC754C722228B57C00A39C8E /* TrustedPeersHelperProtocol.m in Sources */, 0C12B1F12138D31600BE0A98 /* OTClientStateMachine.m in Sources */, - BE2AD2BA1FDA080800739F96 /* OTBottledPeerRecord.m in Sources */, - 0C770EC41FCF7E2000B5F0E2 /* OTCloudStore.m in Sources */, DCEA5D571E2826DB0089CF55 /* CKKSSIV.m in Sources */, EB7E911B2194849900B1FA21 /* SECC2MPDeviceInfo.m in Sources */, EB7E91192194849900B1FA21 /* SECC2MPCloudKitOperationGroupInfo.m in Sources */, - 0C48B371202E3ED800A0E1AA /* OTIdentity.m in Sources */, DC9082C41EA0277600D0C1C5 /* CKKSZoneChangeFetcher.m in Sources */, 6C4AEF96218A127F0012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */, DCFE1C361F17ECE5007640C8 /* CKKSCondition.m in Sources */, @@ -35016,6 +34908,7 @@ DC59244D20E46F0E0073D284 /* SOSTransport.m in Sources */, DC52E8C91D80C2FD00B0A59C /* SOSTransportBackupPeer.m in Sources */, DC59245020E46F800073D284 /* SOSRecoveryKeyBag.m in Sources */, + 48AC7B73232B1DA600F02B6F /* SOSIntervalEvent.m in Sources */, 0CB50A0E20AA4C2F00FE4675 /* SOSAccountTrustClassic+Circle.m in Sources */, DC52E8CA1D80C2FD00B0A59C /* SOSTransportCircle.m in Sources */, DC52E8CB1D80C2FD00B0A59C /* SOSTransportCircleKVS.m in Sources */, @@ -36678,7 +36571,6 @@ EB6667C7204CD69F000B404F /* testPlistDER.m in Sources */, EBC73F29209966AF00AE3350 /* SFSQLite.m in Sources */, EB49B2D5202DF1D8003F34A0 /* SecTask.c in Sources */, - EB49B2D4202DF1C1003F34A0 /* client.c in Sources */, EB49B2D3202DF1AC003F34A0 /* SecdWatchdog.m in Sources */, EB49B2B1202D8780003F34A0 /* mockaksKeychain.m in Sources */, DC5B391B20C08BDC005B09F6 /* SecFramework.c in Sources */, @@ -40651,7 +40543,6 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", - "$(OTHER_LDFLAGS_AOSKIT_FRAMEWORK)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", @@ -40694,7 +40585,6 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", - "$(OTHER_LDFLAGS_AOSKIT_FRAMEWORK)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", @@ -40943,7 +40833,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -40999,7 +40889,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -41531,6 +41421,7 @@ CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = dwarf; GCC_DYNAMIC_NO_PIC = NO; @@ -41563,6 +41454,7 @@ CLANG_WARN_STRICT_PROTOTYPES = NO; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; + CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; @@ -41863,6 +41755,7 @@ MACH_O_TYPE = mh_execute; ONLY_ACTIVE_ARCH = YES; OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "-ObjC", ); @@ -41903,6 +41796,7 @@ INSTALL_PATH = "$(SECURITY_FRAMEWORK_RESOURCES_DIR)"; MACH_O_TYPE = mh_execute; OTHER_LDFLAGS = ( + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "-ObjC", ); @@ -42266,11 +42160,13 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_APPLEACCOUNT)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", "$(OTHER_LDFLAGS_CRASHREPORTER)", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainAnalyticsTests; @@ -42302,12 +42198,14 @@ OTHER_LDFLAGS = ( "$(OTHER_LDFLAGS_APPLEACCOUNT)", "$(OTHER_LDFLAGS_CRASHREPORTER)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-ObjC", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_CRASHREPORTER)", "$(OTHER_LDFLAGS_APPLEACCOUNT)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainAnalyticsTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -43106,7 +43004,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -43157,7 +43055,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "$(inherited)", @@ -43246,7 +43144,6 @@ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; @@ -43334,7 +43231,6 @@ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE; CLANG_WARN__ARC_BRIDGE_CAST_NONARC = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = keychain/SecurityUnitTests/SecurityUnitTests.entitlements; CODE_SIGN_IDENTITY = "-"; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = YES; @@ -43923,7 +43819,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/iOS/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -43947,7 +43843,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/iOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/iOS/entitlements.plist; ENABLE_NS_ASSERTIONS = NO; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", @@ -44788,7 +44684,6 @@ OTHER_LDFLAGS = ( "$(inherited)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", - "$(OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY)", "-framework", Security, ); @@ -44814,7 +44709,6 @@ OTHER_LDFLAGS = ( "$(inherited)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", - "$(OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY)", "-framework", Security, ); @@ -47143,7 +47037,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -47167,7 +47061,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "LIBTRUSTD=1", "$(inherited)", @@ -49448,7 +49342,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_DYNAMIC_NO_PIC = NO; @@ -49461,7 +49355,7 @@ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; + INFOPLIST_FILE = "keychain/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; MTL_ENABLE_DEBUG_INFO = YES; OTHER_CODE_SIGN_FLAGS = "$(OTHER_CODE_SIGN_FLAGS_LIBRARY_VALIDATION)"; @@ -49502,7 +49396,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; COPY_PHASE_STRIP = NO; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; ENABLE_NS_ASSERTIONS = NO; @@ -49516,7 +49410,7 @@ GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = "OSX/sec/securityd/Info-macOS.plist"; + INFOPLIST_FILE = "keychain/securityd/Info-macOS.plist"; INSTALL_PATH = /usr/libexec; MTL_ENABLE_DEBUG_INFO = NO; OTHER_CODE_SIGN_FLAGS = "$(OTHER_CODE_SIGN_FLAGS_LIBRARY_VALIDATION)"; @@ -49557,7 +49451,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/macOS/entitlements.plist; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -49601,7 +49495,7 @@ CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = OSX/trustd/macOS/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = trust/trustd/macOS/entitlements.plist; COPY_PHASE_STRIP = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -51916,7 +51810,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -51939,6 +51833,7 @@ "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = "$(TARGET_NAME)"; REEXPORTED_LIBRARY_NAMES = ""; @@ -51957,7 +51852,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -51980,6 +51875,7 @@ "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)", "$(OTHER_LDFLAGS_AKS_LIBRARY)", "$(OTHER_LDFLAGS_MOBILE_KEYBAG)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = "$(TARGET_NAME)"; REEXPORTED_LIBRARY_NAMES = ""; @@ -52102,7 +51998,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -52122,6 +52018,7 @@ "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_UserManagement)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = recovery_securityd; REEXPORTED_LIBRARY_NAMES = ""; @@ -52140,7 +52037,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ENABLE_MODULES = NO; CLANG_ENABLE_OBJC_ARC = YES; - CODE_SIGN_ENTITLEMENTS = OSX/sec/securityd/entitlements.plist; + CODE_SIGN_ENTITLEMENTS = keychain/securityd/entitlements.plist; GCC_PREPROCESSOR_DEFINITIONS = ( "SECD_SERVER=1", "TARGET_DARWINOS=1", @@ -52160,6 +52057,7 @@ "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)", "$(OTHER_LDFLAGS_CrashReporterSupport)", "$(OTHER_LDFLAGS_UserManagement)", + "$(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER)", ); PRODUCT_NAME = recovery_securityd; REEXPORTED_LIBRARY_NAMES = ""; diff --git a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme index 471ef0c5..30a0789a 100644 --- a/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme +++ b/Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme @@ -41,6 +41,15 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> + + + + @@ -53,17 +62,6 @@ - - - - - - - - #include #include -#include +#include "keychain/securityd/Regressions/securityd_regressions.h" #include "keychain/SecureObjectSync/Regressions/SOSCircle_regressions.h" #include #include diff --git a/SecurityTool/sharedTool/SecurityTool.c b/SecurityTool/sharedTool/SecurityTool.c index 847c4e1a..d883eb4a 100644 --- a/SecurityTool/sharedTool/SecurityTool.c +++ b/SecurityTool/sharedTool/SecurityTool.c @@ -41,7 +41,7 @@ #include #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif /* Maximum length of an input line in interactive mode. */ diff --git a/dtlsEcho/dtlsEchoClient.c b/dtlsEcho/dtlsEchoClient.c index 7a2b553a..e714e043 100644 --- a/dtlsEcho/dtlsEchoClient.c +++ b/dtlsEcho/dtlsEchoClient.c @@ -40,7 +40,7 @@ #include #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif static diff --git a/dtlsEcho/dtlsEchoServer.c b/dtlsEcho/dtlsEchoServer.c index 1306b5a7..ed2d287a 100644 --- a/dtlsEcho/dtlsEchoServer.c +++ b/dtlsEcho/dtlsEchoServer.c @@ -40,7 +40,7 @@ #include #ifdef NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #define PORT 23232 diff --git a/featureflags/Security.plist b/featureflags/Security.plist index 339077b2..1ffb729d 100644 --- a/featureflags/Security.plist +++ b/featureflags/Security.plist @@ -2,6 +2,11 @@ + EnableSecureObjectSync + + Enabled + + octagonTrust Enabled @@ -33,9 +38,9 @@ octagonUseDeviceName - - Enabled - - + + Enabled + + diff --git a/header_symlinks/Security/SecAccessControl.h b/header_symlinks/Security/SecAccessControl.h index cea7071f..8ae6a105 120000 --- a/header_symlinks/Security/SecAccessControl.h +++ b/header_symlinks/Security/SecAccessControl.h @@ -1 +1 @@ -./../keychain/SecAccessControl.h \ No newline at end of file +./../keychain/headers/SecAccessControl.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificate.h b/header_symlinks/Security/SecCertificate.h index abfc83ee..9fc0b655 120000 --- a/header_symlinks/Security/SecCertificate.h +++ b/header_symlinks/Security/SecCertificate.h @@ -1 +1 @@ -./../trust/SecCertificate.h \ No newline at end of file +./../trust/headers/SecCertificate.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificatePriv.h b/header_symlinks/Security/SecCertificatePriv.h index 9499f6f4..74110696 120000 --- a/header_symlinks/Security/SecCertificatePriv.h +++ b/header_symlinks/Security/SecCertificatePriv.h @@ -1 +1 @@ -./../trust/SecCertificatePriv.h \ No newline at end of file +./../trust/headers/SecCertificatePriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecCertificateRequest.h b/header_symlinks/Security/SecCertificateRequest.h index 0ecfd8ea..0f06dc02 120000 --- a/header_symlinks/Security/SecCertificateRequest.h +++ b/header_symlinks/Security/SecCertificateRequest.h @@ -1 +1 @@ -./../trust/SecCertificateRequest.h \ No newline at end of file +./../trust/headers/SecCertificateRequest.h \ No newline at end of file diff --git a/header_symlinks/Security/SecIdentity.h b/header_symlinks/Security/SecIdentity.h index cf2695c1..e57ecc24 120000 --- a/header_symlinks/Security/SecIdentity.h +++ b/header_symlinks/Security/SecIdentity.h @@ -1 +1 @@ -./../keychain/SecIdentity.h \ No newline at end of file +./../keychain/headers/SecIdentity.h \ No newline at end of file diff --git a/header_symlinks/Security/SecIdentityPriv.h b/header_symlinks/Security/SecIdentityPriv.h index 68c25650..39bfc21b 120000 --- a/header_symlinks/Security/SecIdentityPriv.h +++ b/header_symlinks/Security/SecIdentityPriv.h @@ -1 +1 @@ -./../keychain/SecIdentityPriv.h \ No newline at end of file +./../keychain/headers/SecIdentityPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecImportExport.h b/header_symlinks/Security/SecImportExport.h index 5cf7eced..e1c951dc 120000 --- a/header_symlinks/Security/SecImportExport.h +++ b/header_symlinks/Security/SecImportExport.h @@ -1 +1 @@ -./../keychain/SecImportExport.h \ No newline at end of file +./../keychain/headers/SecImportExport.h \ No newline at end of file diff --git a/header_symlinks/Security/SecImportExportPriv.h b/header_symlinks/Security/SecImportExportPriv.h index fd3ad461..a9e8031d 120000 --- a/header_symlinks/Security/SecImportExportPriv.h +++ b/header_symlinks/Security/SecImportExportPriv.h @@ -1 +1 @@ -./../keychain/SecImportExportPriv.h \ No newline at end of file +./../keychain/headers/SecImportExportPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecItem.h b/header_symlinks/Security/SecItem.h index 9976098b..ab75d336 120000 --- a/header_symlinks/Security/SecItem.h +++ b/header_symlinks/Security/SecItem.h @@ -1 +1 @@ -./../keychain/SecItem.h \ No newline at end of file +./../keychain/headers/SecItem.h \ No newline at end of file diff --git a/header_symlinks/Security/SecItemPriv.h b/header_symlinks/Security/SecItemPriv.h index a8169111..e0c3c010 120000 --- a/header_symlinks/Security/SecItemPriv.h +++ b/header_symlinks/Security/SecItemPriv.h @@ -1 +1 @@ -./../keychain/SecItemPriv.h \ No newline at end of file +./../keychain/headers/SecItemPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKey.h b/header_symlinks/Security/SecKey.h index 0d7004f9..5dd0da10 120000 --- a/header_symlinks/Security/SecKey.h +++ b/header_symlinks/Security/SecKey.h @@ -1 +1 @@ -./../keychain/SecKey.h \ No newline at end of file +./../keychain/headers/SecKey.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKeyPriv.h b/header_symlinks/Security/SecKeyPriv.h index 34a07ffa..60e1bf56 120000 --- a/header_symlinks/Security/SecKeyPriv.h +++ b/header_symlinks/Security/SecKeyPriv.h @@ -1 +1 @@ -./../keychain/SecKeyPriv.h \ No newline at end of file +./../keychain/headers/SecKeyPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecKeyProxy.h b/header_symlinks/Security/SecKeyProxy.h index 9356c2c8..c39f74b1 120000 --- a/header_symlinks/Security/SecKeyProxy.h +++ b/header_symlinks/Security/SecKeyProxy.h @@ -1 +1 @@ -./../keychain/SecKeyProxy.h \ No newline at end of file +./../keychain/headers/SecKeyProxy.h \ No newline at end of file diff --git a/header_symlinks/Security/SecPolicy.h b/header_symlinks/Security/SecPolicy.h index a9f75265..a606ce80 120000 --- a/header_symlinks/Security/SecPolicy.h +++ b/header_symlinks/Security/SecPolicy.h @@ -1 +1 @@ -./../trust/SecPolicy.h \ No newline at end of file +./../trust/headers/SecPolicy.h \ No newline at end of file diff --git a/header_symlinks/Security/SecPolicyPriv.h b/header_symlinks/Security/SecPolicyPriv.h index e429b0a9..b0894668 120000 --- a/header_symlinks/Security/SecPolicyPriv.h +++ b/header_symlinks/Security/SecPolicyPriv.h @@ -1 +1 @@ -./../trust/SecPolicyPriv.h \ No newline at end of file +./../trust/headers/SecPolicyPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecSharedCredential.h b/header_symlinks/Security/SecSharedCredential.h index f1b330cf..725e9a37 120000 --- a/header_symlinks/Security/SecSharedCredential.h +++ b/header_symlinks/Security/SecSharedCredential.h @@ -1 +1 @@ -./../keychain/SecSharedCredential.h \ No newline at end of file +./../keychain/headers/SecSharedCredential.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrust.h b/header_symlinks/Security/SecTrust.h index 44fb96fb..afd36555 120000 --- a/header_symlinks/Security/SecTrust.h +++ b/header_symlinks/Security/SecTrust.h @@ -1 +1 @@ -./../trust/SecTrust.h \ No newline at end of file +./../trust/headers/SecTrust.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustPriv.h b/header_symlinks/Security/SecTrustPriv.h index 8c596e1e..e4acf71b 120000 --- a/header_symlinks/Security/SecTrustPriv.h +++ b/header_symlinks/Security/SecTrustPriv.h @@ -1 +1 @@ -./../trust/SecTrustPriv.h \ No newline at end of file +./../trust/headers/SecTrustPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustSettings.h b/header_symlinks/Security/SecTrustSettings.h index 4950c4f4..1691d26d 120000 --- a/header_symlinks/Security/SecTrustSettings.h +++ b/header_symlinks/Security/SecTrustSettings.h @@ -1 +1 @@ -./../trust/SecTrustSettings.h \ No newline at end of file +./../trust/headers/SecTrustSettings.h \ No newline at end of file diff --git a/header_symlinks/Security/SecTrustSettingsPriv.h b/header_symlinks/Security/SecTrustSettingsPriv.h index dc728bca..557202df 120000 --- a/header_symlinks/Security/SecTrustSettingsPriv.h +++ b/header_symlinks/Security/SecTrustSettingsPriv.h @@ -1 +1 @@ -./../trust/SecTrustSettingsPriv.h \ No newline at end of file +./../trust/headers/SecTrustSettingsPriv.h \ No newline at end of file diff --git a/header_symlinks/Security/oids.h b/header_symlinks/Security/oids.h index d760f054..5297b828 120000 --- a/header_symlinks/Security/oids.h +++ b/header_symlinks/Security/oids.h @@ -1 +1 @@ -./../trust/oids.h \ No newline at end of file +./../trust/headers/oids.h \ No newline at end of file diff --git a/header_symlinks/utilities/SecCFRelease.h b/header_symlinks/utilities/SecCFRelease.h deleted file mode 120000 index c0522304..00000000 --- a/header_symlinks/utilities/SecCFRelease.h +++ /dev/null @@ -1 +0,0 @@ -./../OSX/utilities/src/SecCFRelease.h \ No newline at end of file diff --git a/keychain/KeychainSettings/KeychainSettings.m b/keychain/KeychainSettings/KeychainSettings.m index b27a1407..14f4635b 100644 --- a/keychain/KeychainSettings/KeychainSettings.m +++ b/keychain/KeychainSettings/KeychainSettings.m @@ -217,6 +217,7 @@ [[KeychainSettings sharedOTControl] resetAndEstablish:nil context:OTDefaultContext altDSID:[self primaryiCloudAccountAltDSID] + resetReason:CuttlefishResetReasonUserInitiatedReset reply:^(NSError * _Nullable error) { if(error) { diff --git a/keychain/SecureObjectSync/Regressions/SOSTestDevice.c b/keychain/SecureObjectSync/Regressions/SOSTestDevice.c index fb72a1c8..85efa2ec 100644 --- a/keychain/SecureObjectSync/Regressions/SOSTestDevice.c +++ b/keychain/SecureObjectSync/Regressions/SOSTestDevice.c @@ -36,8 +36,8 @@ #include #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" #include #include #include @@ -267,22 +267,6 @@ CFDataRef SOSTestDeviceCreateMessage(SOSTestDeviceRef td, CFStringRef peerID) { return msgData; } -#if 0 -CFDictionaryRef SOSTestDeviceCreateMessages(SOSTestDeviceRef td) { - CFTypeRef peer = NULL; - CFMutableDictionaryRef messages = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFArrayForEachC(td->peers, peer) { - CFStringRef peerID = SOSPeerGetID((SOSPeerRef)peer); - CFDataRef msg = SOSTestDeviceCreateMessage(td, peerID); - if (msg) { - CFDictionaryAddValue(messages, peerID, msg); - CFRelease(msg); - } - } - return messages; -} -#endif - bool SOSTestDeviceHandleMessage(SOSTestDeviceRef td, CFStringRef peerID, CFDataRef msgData) { setup("handle message"); if (!msgData) return false; diff --git a/keychain/SecureObjectSync/Regressions/sc-40-circle.c b/keychain/SecureObjectSync/Regressions/sc-40-circle.c index 365b88bf..6f516bd1 100644 --- a/keychain/SecureObjectSync/Regressions/sc-40-circle.c +++ b/keychain/SecureObjectSync/Regressions/sc-40-circle.c @@ -41,7 +41,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSCircle_regressions.h" diff --git a/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c b/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c index 87158469..7ee15736 100644 --- a/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c +++ b/keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c @@ -26,7 +26,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSCircle_regressions.h" diff --git a/keychain/SecureObjectSync/SOSAccount.h b/keychain/SecureObjectSync/SOSAccount.h index a01d0384..9fed6f2f 100644 --- a/keychain/SecureObjectSync/SOSAccount.h +++ b/keychain/SecureObjectSync/SOSAccount.h @@ -248,7 +248,7 @@ CFStringRef SOSInterestListCopyDescription(CFArrayRef interests); SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount* account, CFErrorRef*); CFDataRef SOSAccountCopyCircleJoiningBlob(SOSAccount* account, SOSPeerInfoRef applicant, CFErrorRef *error); bool SOSAccountJoinWithCircleJoiningBlob(SOSAccount* account, CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); -CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error); +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, SOSInitialSyncFlags flags, CFErrorRef *error); // // MARK: Initial-Sync @@ -288,7 +288,7 @@ bool SOSAccountSendToPeerIsPending(SOSAccountTransaction* txn, SOSPeerInfoRef pe void SOSAccountResetOTRNegotiationCoder(SOSAccount* account, CFStringRef peerid); void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* peerid, NSString* accessGroup); -NSMutableArray* SOSAccountGetAllTLKs(void); +NSArray* SOSAccountGetAllTLKs(void); CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account); __END_DECLS diff --git a/keychain/SecureObjectSync/SOSAccount.m b/keychain/SecureObjectSync/SOSAccount.m index 6c514ce6..41035e2f 100644 --- a/keychain/SecureObjectSync/SOSAccount.m +++ b/keychain/SecureObjectSync/SOSAccount.m @@ -44,13 +44,12 @@ #if OCTAGON #import "keychain/ckks/CKKSViewManager.h" #import "keychain/ckks/CKKSLockStateTracker.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTManager.h" #endif #include #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" -#include +#include "keychain/securityd/SecItemServer.h" #import "SecdWatchdog.h" @@ -2327,11 +2326,11 @@ AddViewManagerResults(NSMutableArray *results, NSMutableSet *seenUUID) } -NSMutableArray* +NSArray* SOSAccountGetAllTLKs(void) { CFTypeRef result = NULL; - NSMutableArray* results = [NSMutableArray array]; + NSMutableArray* results = [NSMutableArray array]; NSMutableSet *seenUUID = [NSMutableSet set]; // first use the TLK from the view manager @@ -2400,6 +2399,7 @@ static uint8_t* piggy_encode_data(NSData* data, } +// you can not add more items here w/o also adding a version, older clients wont understand newer numbers static kTLKTypes name2type(NSString *view) { @@ -2414,6 +2414,7 @@ name2type(NSString *view) return kTLKUnknown; } +// you can not add more items here w/o also adding a version, older clients wont understand newer numbers static unsigned rank_type(NSString *view) { @@ -2613,21 +2614,28 @@ CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* return identities; } -CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, CFErrorRef *error) { - CFMutableArrayRef identities = SOSAccountCopyiCloudIdentities(account); - secnotice("piggy", "identities: %@", identities); +CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, SOSInitialSyncFlags flags, CFErrorRef *error) { - NSMutableArray *encodedIdenities = [NSMutableArray array]; - CFIndex i, count = CFArrayGetCount(identities); - for (i = 0; i < count; i++) { - SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identities, i); - NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, error)); - if (data) - [encodedIdenities addObject:data]; + NSMutableArray* encodedIdenities = [NSMutableArray array]; + NSArray* tlks = nil; + + if (flags & kSOSInitialSyncFlagiCloudIdentity) { + CFMutableArrayRef identities = SOSAccountCopyiCloudIdentities(account); + secnotice("piggy", "identities: %@", identities); + + CFIndex i, count = CFArrayGetCount(identities); + for (i = 0; i < count; i++) { + SOSPeerInfoRef fpi = (SOSPeerInfoRef)CFArrayGetValueAtIndex(identities, i); + NSData *data = CFBridgingRelease(SOSPeerInfoCopyData(fpi, error)); + if (data) + [encodedIdenities addObject:data]; + } + CFRelease(identities); + } + + if (flags & kSOSInitialSyncFlagTLKs) { + tlks = SOSAccountGetAllTLKs(); } - CFRelease(identities); - - NSMutableArray* tlks = SOSAccountGetAllTLKs(); return CFBridgingRetain(SOSPiggyCreateInitialSyncData(encodedIdenities, tlks)); } diff --git a/keychain/SecureObjectSync/SOSAccountGhost.m b/keychain/SecureObjectSync/SOSAccountGhost.m index a278a5a3..f8de69c2 100644 --- a/keychain/SecureObjectSync/SOSAccountGhost.m +++ b/keychain/SecureObjectSync/SOSAccountGhost.m @@ -18,6 +18,8 @@ #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h" #include "keychain/SecureObjectSync/SOSAuthKitHelpers.h" #import "Analytics/Clients/SOSAnalytics.h" +#include "utilities/SecTrace.h" + #define DETECT_IOS_ONLY 1 @@ -290,9 +292,10 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA __block bool result = false; CFErrorRef localError = NULL; __block NSUInteger nbusted = 9999; - __block NSMutableDictionary *attributes =[NSMutableDictionary new]; + NSMutableDictionary *attributes =[NSMutableDictionary new]; + int circleSize = SOSCircleCountPeers(account.trust.trustedCircle); - if ([akh isUseful] && [account isInCircle:nil] && SOSCircleCountPeers(account.trust.trustedCircle) > mincount) { + if ([akh isUseful] && [account isInCircle:nil] && circleSize > mincount) { if(options & SOSGhostBustiCloudIdentities) { secnotice("ghostBust", "Callout to cleanup icloud identities"); result = SOSGhostBustiCloudIdentityPrivateKeys(account); @@ -306,7 +309,8 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA nbusted += thinBusted; attributes[@"byAge"] = @(thinBusted); } - attributes[@"total"] = @(nbusted); + attributes[@"total"] = @(SecBucket1Significant(nbusted)); + attributes[@"startCircleSize"] = @(SecBucket1Significant(circleSize)); result = nbusted > 0; if(result) { SOSAccountRestartPrivateCredentialTimer(account); @@ -318,7 +322,7 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA } return result; }]; - secnotice("circleOps", "Ghostbusting %@ (%@)", result ? CFSTR("Performed") : CFSTR("Not Performed"), localError); + secnotice("circleOps", "Ghostbusting %@ (%@)", result ? CFSTR("Performed") : CFSTR("Not Performed"), localError); } } else { secnotice("circleOps", "Ghostbusting skipped"); diff --git a/keychain/SecureObjectSync/SOSAccountPriv.h b/keychain/SecureObjectSync/SOSAccountPriv.h index 7300f540..fd6d2b1b 100644 --- a/keychain/SecureObjectSync/SOSAccountPriv.h +++ b/keychain/SecureObjectSync/SOSAccountPriv.h @@ -32,7 +32,7 @@ #include "keychain/SecureObjectSync/SOSRing.h" #include "keychain/SecureObjectSync/SOSRingUtils.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "keychain/SecureObjectSync/SOSEngine.h" #include "keychain/SecureObjectSync/SOSPeer.h" #include "keychain/SecureObjectSync/SOSFullPeerInfo.h" diff --git a/keychain/SecureObjectSync/SOSAccountTransaction.h b/keychain/SecureObjectSync/SOSAccountTransaction.h index 36ba7cb3..414e6dcb 100644 --- a/keychain/SecureObjectSync/SOSAccountTransaction.h +++ b/keychain/SecureObjectSync/SOSAccountTransaction.h @@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SOSAccount (Transaction) + (void)performOnQuietAccountQueue:(void (^)(void))action; -+ (void)performWhileHoldingAccountQueue:(void (^)(void))action; - (void) performTransaction: (void (^)(SOSAccountTransaction* txn)) action; - (void) performTransaction_Locked: (void (^)(SOSAccountTransaction* txn)) action; diff --git a/keychain/SecureObjectSync/SOSAccountTransaction.m b/keychain/SecureObjectSync/SOSAccountTransaction.m index 7fa73312..1c014b29 100644 --- a/keychain/SecureObjectSync/SOSAccountTransaction.m +++ b/keychain/SecureObjectSync/SOSAccountTransaction.m @@ -427,14 +427,6 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) { __thread bool __hasAccountQueue = false; -+ (void)performWhileHoldingAccountQueue:(void (^)(void))action -{ - bool hadAccountQueue = __hasAccountQueue; - __hasAccountQueue = true; - action(); - __hasAccountQueue = hadAccountQueue; -} - + (void)performOnQuietAccountQueue:(void (^)(void))action { SOSAccount* account = (__bridge SOSAccount*)GetSharedAccountRef(); diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h index fa7d5b1f..624badd0 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h @@ -33,6 +33,7 @@ action:(SOSModifyPeersInCircleBlock)block; -(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error; -(bool) joinCircle:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef)user_key useCloudPeer:(bool)use_cloud_peer err:(CFErrorRef*) error; +-(bool) fixICloudIdentities:(SOSAccount *) account circle: (SOSCircleRef) circle; @end diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m index e9486c1d..d118ec54 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m @@ -14,10 +14,15 @@ #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h" #import "keychain/SecureObjectSync/SOSAccountGhost.h" +#import "keychain/SecureObjectSync/SOSIntervalEvent.h" #import "keychain/SecureObjectSync/SOSViews.h" +#import "Analytics/Clients/SOSAnalytics.h" + @implementation SOSAccountTrustClassic (Circle) +#define ICLOUDIDDATE @"iCloudIDDate" + -(bool) isInCircleOnly:(CFErrorRef *)error { SOSCCStatus result = [self getCircleStatusOnly:error]; @@ -239,6 +244,16 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO return hasUpdated; } +// Check on the iCloud identity availability every 24-36 hours random interval +- (SOSIntervalEvent *) iCloudCheckEventHandle: (SOSAccount *) account { + return [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"iCloudIDCheck" earliest:60*60*24 latest:60*60*36]; +} + +// Cleanup unusable iCloud identities every 5-7 days random interval +- (SOSIntervalEvent *) iCloudCleanerHandle: (SOSAccount *) account { + return [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"iCloudCleanerCheck" earliest:60*60*24*5 latest:60*60*24*7]; +} + -(bool) handleUpdateCircle:(SOSCircleRef) prospective_circle transport:(SOSKVSCircleStorageTransport*)circleTransport update:(bool) writeUpdate err:(CFErrorRef*)error { bool success = true; @@ -474,6 +489,21 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO } CFReleaseNull(reject); } + + if(me && account.accountKeyIsTrusted && SOSCircleHasPeer(newCircle, me, NULL)) { + // do this on daily interval +/- 8 hours random to keep all peers doing this at the same time + SOSIntervalEvent *iCloudCheckEvent = [self iCloudCheckEventHandle: account]; + if([iCloudCheckEvent checkDate]) { + bool fixedIdentities = [self fixICloudIdentities:account circle:newCircle]; + if(fixedIdentities) { + writeUpdate = true; + secnotice("circleOps", "Fixed iCloud Identity in circle"); + } else { + secnotice("circleOps", "Failed to fix broken icloud identity"); + } + [iCloudCheckEvent followup]; + } + } CFRetainSafe(oldCircle); account.previousAccountKey = account.accountKey; @@ -583,6 +613,45 @@ fail: } +// true means things changed. +-(bool) fixICloudIdentities:(SOSAccount *) account circle: (SOSCircleRef) circle { + bool retval = false; + SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); + if(!icfpi) { + SOSAccountRestartPrivateCredentialTimer(account); + if((SOSAccountGetPrivateCredential(account, NULL) != NULL) || SOSAccountAssertStashedAccountCredential(account, NULL)) { + SecKeyRef privKey = SOSAccountGetPrivateCredential(account, NULL); + if(privKey) { + SOSIntervalEvent *iCloudCleanupEvent = [self iCloudCleanerHandle: account]; + if([iCloudCleanupEvent checkDate]) { + SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); + [iCloudCleanupEvent followup]; + } + CFErrorRef error = NULL; + bool identityAdded = [self addiCloudIdentity:circle key:privKey err:&error]; + if(identityAdded) { + account.notifyBackupOnExit = true; + retval = true; + [[SOSAnalytics logger] logSuccessForEventNamed:@"iCloudIdentityFix"]; + } else { + [[SOSAnalytics logger] logResultForEvent:@"iCloudIdentityFix" hardFailure:true result:(__bridge NSError * _Nullable)(error)]; + } + CFReleaseNull(error); + } else { + NSDictionary *attr = @{ @"reason" : @"noPrivateKey" }; + [[SOSAnalytics logger] logHardFailureForEventNamed:@"iCloudIdentityFix" withAttributes:attr]; + } + } else { + NSDictionary *attr = @{ @"reason" : @"noPrivateKey" }; + [[SOSAnalytics logger] logHardFailureForEventNamed:@"iCloudIdentityFix" withAttributes:attr]; + } + } else { + // everything is fine. + CFReleaseNull(icfpi); + } + return retval; +} + -(void) generationSignatureUpdateWith:(SOSAccount*)account key:(SecKeyRef) privKey { // rdar://51233857 - don't gensign if there isn't a change in the userKey @@ -604,19 +673,11 @@ fail: change |= SOSCircleGenerationSign(circle, privKey, self.fullPeerInfo, NULL); [self setDepartureCode:kSOSNeverLeftCircle]; } else if(iAmPeer) { - SOSFullPeerInfoRef icfpi = SOSCircleCopyiCloudFullPeerInfoRef(circle, NULL); - if(!icfpi) { - SOSAccountRemoveIncompleteiCloudIdentities(account, circle, privKey, NULL); - bool identityAdded = [self addiCloudIdentity:circle key:privKey err:NULL]; - if(identityAdded) { - account.notifyBackupOnExit = true; - } - change |= identityAdded; - } else { - CFReleaseNull(icfpi); - } + change |= [self fixICloudIdentities:account circle:circle]; } secnotice("updatingGenSignature", "we changed the circle? %@", change ? CFSTR("YES") : CFSTR("NO")); + SOSIntervalEvent *iCloudCheckEvent = [self iCloudCheckEventHandle: account]; + [iCloudCheckEvent followup]; return change; }]; } diff --git a/keychain/SecureObjectSync/SOSAccountTrustClassic.h b/keychain/SecureObjectSync/SOSAccountTrustClassic.h index f9b7a9a7..a1a2e237 100644 --- a/keychain/SecureObjectSync/SOSAccountTrustClassic.h +++ b/keychain/SecureObjectSync/SOSAccountTrustClassic.h @@ -60,5 +60,6 @@ -(void) addRingDictionary; -(void) resetRingDictionary; + @end #endif /* SOSAccountTrustClassic_h */ diff --git a/keychain/SecureObjectSync/SOSCloudCircle.h b/keychain/SecureObjectSync/SOSCloudCircle.h index bb26d2db..46bbae1e 100644 --- a/keychain/SecureObjectSync/SOSCloudCircle.h +++ b/keychain/SecureObjectSync/SOSCloudCircle.h @@ -69,6 +69,12 @@ enum { // Types // +typedef CF_OPTIONS(uint32_t, SOSInitialSyncFlags) { + kSOSInitialSyncFlagTLKs = (1UL << 0), + kSOSInitialSyncFlagiCloudIdentity = (1UL << 1), +}; + + enum { kSOSCCInCircle = 0, kSOSCCNotInCircle = 1, @@ -756,7 +762,7 @@ void SOSCCGhostBustTriggerTimed(SOSAccountGhostBustingOptions options, void (^co void SOSCCGhostBustInfo(void (^complete)(NSData *json, NSError *error)); -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error); NSString * SOSCCCircleHash(NSError **error); diff --git a/keychain/SecureObjectSync/SOSCloudCircle.m b/keychain/SecureObjectSync/SOSCloudCircle.m index 4fe74fe0..d1af2e1a 100644 --- a/keychain/SecureObjectSync/SOSCloudCircle.m +++ b/keychain/SecureObjectSync/SOSCloudCircle.m @@ -47,7 +47,7 @@ #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include @@ -63,7 +63,7 @@ #include #define MINIMIZE_INCLUDES MINIMIZE_INCLUDES #include -#include +#include "keychain/securityd/spi.h" #include @@ -396,6 +396,31 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef peer_info_error_request(enum SecXPCOpe return result; } +static CFDataRef flags_to_data_error_request(enum SecXPCOperation op, uint32_t flags, CFErrorRef *error) +{ + __block CFDataRef result = NULL; + + secdebug("sosops", "enter -- operation: %d", op); + securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) { + xpc_dictionary_set_uint64(message, kSecXPCKeyFlags, flags); + return true; + }, ^bool(xpc_object_t response, CFErrorRef *error) { + xpc_object_t temp_result = xpc_dictionary_get_value(response, kSecXPCKeyResult); + if (response && (NULL != temp_result)) { + result = _CFXPCCreateCFObjectFromXPCObject(temp_result); + } + return result != NULL; + }); + + if (!isData(result)) { + SOSErrorCreate(kSOSErrorUnexpectedType, error, NULL, CFSTR("Expected CFData, got: %@"), result); + return NULL; + } + + return result; +} + + static CFDataRef data_to_error_request(enum SecXPCOperation op, CFErrorRef *error) { __block CFDataRef result = NULL; @@ -1731,13 +1756,13 @@ CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error }, CFSTR("return=%@")); } -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error) { +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error) { secnotice("circleJoin", "enter SOSCCCopyInitialSyncData approver"); sec_trace_enter_api(NULL); sec_trace_return_api(CFDataRef, ^{ - do_if_registered(soscc_CopyInitialSyncData, error); - return data_to_error_request(kSecXPCOpCopyInitialSyncBlob, error); + do_if_registered(soscc_CopyInitialSyncData, flags, error); + return flags_to_data_error_request(kSecXPCOpCopyInitialSyncBlob, flags, error); }, CFSTR("return=%@")); } diff --git a/keychain/SecureObjectSync/SOSCloudCircleInternal.h b/keychain/SecureObjectSync/SOSCloudCircleInternal.h index 1ed5dde6..36e5dfbd 100644 --- a/keychain/SecureObjectSync/SOSCloudCircleInternal.h +++ b/keychain/SecureObjectSync/SOSCloudCircleInternal.h @@ -114,7 +114,7 @@ bool SOSCCDeleteEngineState(CFErrorRef *error); CFDataRef SOSCCCopyRecoveryPublicKey(CFErrorRef *error); CFDictionaryRef SOSCCCopyBackupInformation(CFErrorRef *error); bool SOSCCTestPopulateKVSWithBadKeys(CFErrorRef *error); -CFDataRef SOSCCCopyInitialSyncData(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error); void SOSCCForEachEngineStateAsStringFromArray(CFArrayRef states, void (^block)(CFStringRef oneStateString)); diff --git a/keychain/SecureObjectSync/SOSDataSource.h b/keychain/SecureObjectSync/SOSDataSource.h index 39099b58..371edeae 100644 --- a/keychain/SecureObjectSync/SOSDataSource.h +++ b/keychain/SecureObjectSync/SOSDataSource.h @@ -55,7 +55,6 @@ struct SOSDataSourceFactory { CFStringRef (*copy_name)(SOSDataSourceFactoryRef factory); SOSDataSourceRef (*create_datasource)(SOSDataSourceFactoryRef factory, CFStringRef dataSourceName, CFErrorRef *error); void (*release)(SOSDataSourceFactoryRef factory); - void (*circle_changed)(SOSDataSourceFactoryRef factory, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs); }; static inline CFStringRef SOSDataSourceFactoryCopyName(SOSDataSourceFactoryRef dsf) { @@ -71,11 +70,6 @@ static inline void SOSDataSourceFactoryRelease(SOSDataSourceFactoryRef dsf) { dsf->release(dsf); } -static inline void SOSDataSourceFactoryCircleChanged(SOSDataSourceFactoryRef dsf, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs) { - dsf->circle_changed(dsf, myPeerID, trustedPeerIDs, untrustedPeerIDs); -} - - // // MARK: - SOSDataSource protocol // diff --git a/keychain/SecureObjectSync/SOSEngine.c b/keychain/SecureObjectSync/SOSEngine.c index 00a09107..f2a4a9db 100644 --- a/keychain/SecureObjectSync/SOSEngine.c +++ b/keychain/SecureObjectSync/SOSEngine.c @@ -57,12 +57,12 @@ #include #include -#include // TODO: We can't leave this here. -#include // TODO: We can't leave this here. +#include "keychain/securityd/SecItemServer.h" // TODO: We can't leave this here. +#include "keychain/securityd/SOSCloudCircleServer.h" // TODO: We can't leave this here. #include // TODO: We can't leave this here. #include // TODO: We can't leave this here. -#include -#include +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/iCloudTrace.h" #include @@ -1276,51 +1276,6 @@ static void SOSEngineSetNotifyPhaseBlock(SOSEngineRef engine) { }); } -#if 0 // TODO: update these checks -static void SOSEngineCircleChanged_sanitycheck(SOSEngineRef engine, CFStringRef myPeerID, CFArrayRef trustedPeers, CFArrayRef untrustedPeers) { - // Logging code - CFMutableArrayRef addedPeers = CFArrayCreateDifference(kCFAllocatorDefault, trustedPeers, engine->peerIDs); - CFMutableArrayRef deletedPeers = CFArrayCreateDifference(kCFAllocatorDefault, engine->peerIDs, trustedPeers); - CFMutableArrayRef addedUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, untrustedPeers, engine->peerIDs); - CFMutableArrayRef deletedUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, engine->peerIDs, untrustedPeers); - - CFStringRef tpDesc = SOSPeerIDArrayCreateString(trustedPeers); - CFStringRef apDesc = SOSPeerIDArrayCreateString(addedPeers); - CFStringRef dpDesc = SOSPeerIDArrayCreateString(deletedPeers); - CFStringRef aupDesc = SOSPeerIDArrayCreateString(addedUntrustedPeers); - CFStringRef dupDesc = SOSPeerIDArrayCreateString(deletedUntrustedPeers); - secnotice("engine", "trusted %@ added %@ removed %@ add ut: %@ rem ut: %@", tpDesc, apDesc, dpDesc, aupDesc, dupDesc); - CFReleaseSafe(dupDesc); - CFReleaseSafe(aupDesc); - CFReleaseSafe(dpDesc); - CFReleaseSafe(apDesc); - CFReleaseSafe(tpDesc); - - // Assertions: - // Ensure SOSAccount isn't giving us the runaround. - // Assert that trustedPeers, untrustedPeers and myPeerId are disjoint sets - if (trustedPeers) { - CFMutableArrayRef allTrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, trustedPeers, untrustedPeers); - assert(CFEqual(trustedPeers, allTrustedPeers)); - CFReleaseSafe(allTrustedPeers); - assert(!CFArrayContainsValue(trustedPeers, CFRangeMake(0, CFArrayGetCount(trustedPeers)), myPeerID)); - } - if (untrustedPeers) { - CFMutableArrayRef allUntrustedPeers = CFArrayCreateDifference(kCFAllocatorDefault, untrustedPeers, trustedPeers); - assert(CFEqual(untrustedPeers, allUntrustedPeers)); - CFReleaseSafe(allUntrustedPeers); - assert(!CFArrayContainsValue(untrustedPeers, CFRangeMake(0, CFArrayGetCount(trustedPeers)), myPeerID)); - } - - CFReleaseNull(deletedUntrustedPeers); - CFReleaseNull(addedUntrustedPeers); - CFReleaseNull(deletedPeers); - CFReleaseNull(addedPeers); - - // End of logging and asertions, actual code here. -} -#endif - static SOSChangeTrackerRef SOSReferenceAndGetChangeTracker(CFDictionaryRef lookup, CFMutableDictionaryRef referenced, CFSetRef viewNameSet) { SOSChangeTrackerRef ct = (SOSChangeTrackerRef)CFDictionaryGetValue(referenced, viewNameSet); if (!ct) { @@ -2070,163 +2025,6 @@ L local C confirmed */ -#if 0 -static bool SOSAppendRemoveToPatch(CFTypeRef remove, CFMutableDictionaryRef patch, CFErrorRef *error) { -} - -static bool SOSAppendAddToPatch(CFTypeRef add, CFMutableDictionaryRef patch, CFErrorRef *error) { -} - -static bool SOSAppendDiffToPatch(CFTypeRef left, CFTypeRef right, CFMutableDictionaryRef patch, CFErrorRef *error) { - bool ok = true; - if (!left && right) { - SOSAppendAddToPatch(right, patch, error); - } else if (left && !right) { - SOSAppendRemoveToPatch(left, patch, error); - } else if (left && right) { - CFTypeID ltype = CFGetTypeID(left); - CFTypeID rtype = CFGetTypeID(right); - if (ltype == rtype) { - if (CFArrayGetTypeID() == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type array"), ltype); - } else if (CFBooleanGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type boolean"), ltype); - } else if (CFDataGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type data"), ltype); - } else if (CFDictionaryGetTypeID == ltype) { - __block CFMutableDictionaryRef leftnotright = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - __block CFMutableDictionaryRef rightnotleft = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, right); - - CFDictionaryForEach(left, ^(const void *key, const void *lvalue) { - const void *rvalue = NULL; - if (CFDictionaryGetValueIfPresent(right, key, &rvalue)) { - CFDictionaryRemoveValue(rightnotleft, key); - - CFMutableDictionaryRef subpatch = CFDictionaryCreateForCFTypes(kCFAllocatorDefault); - CFDictionaryAddValue(patch, key, subpatch); - SOSAppendDiffToPatch(lvalue, rvalue, subpatch, error); - CFReleaseSafe(subpatch); - } else { - CFDictionaryAddValue(leftnotright, key, lvalue); - } - }); - // Proccess leftnotright and rightnotleft - CFReleaseSafe(leftnotright); - CFReleaseSafe(rightnotleft); - } else if (SOSManifestGetTypeID == ltype) { - SOSManifestRef removed = NULL, added = NULL; - ok &= SOSManifestDiff(left, right, &removed, &added, error); - if (SOSManifestGetCount(removed) || SOSManifestGetCount(added)) { - SOSAppendDiffToPatch(lvalue, rvalue, subpatch, error); - CFStringAppend(, <#CFStringRef appendedString#>) - } - CFReleaseSafe(removed); - CFReleaseSafe(added); - } else if (CFNumberGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type number"), ltype); - } else if (CFSetGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type set"), ltype); - } else if (CFStringGetTypeID == ltype) { - ok = SecError(errSecParam, error, CFSTR("unsupported type string"), ltype); - } else { - ok = SecError(errSecParam, error, CFSTR("unknown type %lu"), ltype); - } - } - } else if (!left && !right) { - // NOOP - } -} -#endif - -static __unused bool SOSEngineCheckPeerIntegrity(SOSEngineRef engine, SOSPeerRef peer, CFErrorRef *error) { -#if 0 - //static CFMutableDictionaryRef p2amtu; - if (!engine->p2amtu) - engine->p2amtu = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault); - CFDictionaryRef amtu = CFDictionaryGetValue(engine->p2amtu, SOSPeerGetID(peer)); -#endif - - // Inputs - SOSManifestRef L = SOSEngineCopyLocalPeerManifest_locked(engine, peer, error); - SOSManifestRef T = SOSPeerGetPendingObjects(peer); - SOSManifestRef C = SOSPeerGetConfirmedManifest(peer); - SOSManifestRef U = SOSPeerGetUnwantedManifest(peer); - - // Computed - SOSManifestRef CunionU = SOSManifestCreateUnion(C, U, error); - SOSManifestRef S = SOSManifestCreateIntersection(L, CunionU, error); - - SOSManifestRef AunionT = NULL, MunionU = NULL; - SOSManifestDiff(L, C, &AunionT, &MunionU, error); - - SOSManifestRef A = SOSManifestCreateComplement(T, AunionT, error); - SOSManifestRef M = SOSManifestCreateComplement(U, MunionU, error); - - SOSManifestRef SunionAunionT = SOSManifestCreateUnion(S, AunionT, error); - SOSManifestRef SunionMunionU = SOSManifestCreateUnion(S, MunionU, error); - - SOSManifestRef AintersectM = SOSManifestCreateIntersection(A, M, error); - SOSManifestRef AintersectS = SOSManifestCreateIntersection(A, S, error); - SOSManifestRef AintersectT = SOSManifestCreateIntersection(A, T, error); - SOSManifestRef AintersectU = SOSManifestCreateIntersection(A, U, error); - SOSManifestRef MintersectS = SOSManifestCreateIntersection(M, S, error); - SOSManifestRef MintersectT = SOSManifestCreateIntersection(M, T, error); - SOSManifestRef MintersectU = SOSManifestCreateIntersection(M, U, error); - SOSManifestRef SintersectT = SOSManifestCreateIntersection(S, T, error); - SOSManifestRef SintersectU = SOSManifestCreateIntersection(S, U, error); - SOSManifestRef TintersectU = SOSManifestCreateIntersection(T, U, error); - -#if 0 - CFDictionaryRef newAmtu = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, CFSTR("A"), A, CFSTR("M"), M, CFSTR("T"), T, CFSTR("U") U, NULL); - CFDictionarySetValue(engine->p2amtu, SOSPeerGetID(peer), newAmtu); - CFMutableStringRef amtuChanges = CFStringCreateMutable(kCFAllocatorDefault, 0); - SOSAppendDiffToString(amtu, newAmtu, amtuChanges); - secnotice("engine", "%@: %@", SOSPeerGetID(peer), amtuChanges); -#endif - -#define SOSASSERT(e) (__builtin_expect(!(e), 0) ? secnotice("engine", "state-assertion %s", #e), assert(e) : (void)0) - - SOSASSERT(L ? CFEqual(L, SunionAunionT) : SOSManifestGetCount(SunionAunionT) == 0); - SOSASSERT(C ? CFEqual(C, SunionMunionU) : SOSManifestGetCount(SunionMunionU) == 0); - - SOSASSERT(SOSManifestGetCount(AintersectM) == 0); - SOSASSERT(SOSManifestGetCount(AintersectS) == 0); - SOSASSERT(SOSManifestGetCount(AintersectT) == 0); - SOSASSERT(SOSManifestGetCount(AintersectU) == 0); - SOSASSERT(SOSManifestGetCount(MintersectS) == 0); - SOSASSERT(SOSManifestGetCount(MintersectT) == 0); - SOSASSERT(SOSManifestGetCount(MintersectU) == 0); - SOSASSERT(SOSManifestGetCount(SintersectT) == 0); - SOSASSERT(SOSManifestGetCount(SintersectU) == 0); - SOSASSERT(SOSManifestGetCount(TintersectU) == 0); - - CFReleaseSafe(AintersectM); - CFReleaseSafe(AintersectS); - CFReleaseSafe(AintersectT); - CFReleaseSafe(AintersectU); - CFReleaseSafe(MintersectS); - CFReleaseSafe(MintersectT); - CFReleaseSafe(MintersectU); - CFReleaseSafe(SintersectT); - CFReleaseSafe(SintersectU); - CFReleaseSafe(TintersectU); - - CFReleaseSafe(AunionT); - CFReleaseSafe(MunionU); - CFReleaseSafe(CunionU); - - CFReleaseNull(SunionAunionT); - CFReleaseNull(SunionMunionU); - - CFReleaseSafe(A); - CFReleaseSafe(M); - CFReleaseSafe(S); - //CFReleaseSafe(T); // Get - //CFReleaseSafe(U); // Get - //CFReleaseSafe(C); // Get - CFReleaseSafe(L); - return true; -} void SOSEngineSetSyncCompleteListener(SOSEngineRef engine, SOSEnginePeerInSyncBlock notify_block) { SOSEngineDoOnQueue(engine, ^{ @@ -2518,7 +2316,6 @@ CFDataRef SOSEngineCreateMessage_locked(SOSEngineRef engine, SOSTransactionRef t SOSPeerAddLocalManifest(pmsc2->peer, pmsc2->local); SOSPeerAddProposedManifest(pmsc2->peer, pmsc2->proposed); secnoticeq("engine", "send %@:%@ %@", pmsc2->engine->myID, SOSPeerGetID(pmsc2->peer), pmsc2->message); - //SOSEngineCheckPeerIntegrity(engine, peer, NULL); } else { secerror("%@:%@ failed to send %@", pmsc2->engine->myID, SOSPeerGetID(pmsc2->peer), pmsc2->message); } diff --git a/keychain/SecureObjectSync/SOSFullPeerInfo.m b/keychain/SecureObjectSync/SOSFullPeerInfo.m index d14f20e9..7b2bee13 100644 --- a/keychain/SecureObjectSync/SOSFullPeerInfo.m +++ b/keychain/SecureObjectSync/SOSFullPeerInfo.m @@ -226,8 +226,9 @@ CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error) exit: CFReleaseNull(query); CFReleaseNull(pubKey); - - secnotice("fpi","no private key found"); + if (vData == NULL) { + secnotice("fpi","no private key found"); + } return (CFDataRef)vData; } diff --git a/keychain/SecureObjectSync/SOSInternal.m b/keychain/SecureObjectSync/SOSInternal.m index 0506af6f..35e8c151 100644 --- a/keychain/SecureObjectSync/SOSInternal.m +++ b/keychain/SecureObjectSync/SOSInternal.m @@ -37,7 +37,7 @@ #include #include #include -#include // For SecError +#include "keychain/securityd/SecDbItem.h" // For SecError #include "utilities/iOSforOSX.h" #include diff --git a/keychain/SecureObjectSync/SOSIntervalEvent.h b/keychain/SecureObjectSync/SOSIntervalEvent.h new file mode 100644 index 00000000..324befa3 --- /dev/null +++ b/keychain/SecureObjectSync/SOSIntervalEvent.h @@ -0,0 +1,26 @@ +// +// SOSIntervalEvent.h +// Security +// +// Created by murf on 9/12/19. +// + +#ifndef SOSIntervalEvent_h +#define SOSIntervalEvent_h + +@interface SOSIntervalEvent : NSObject + +@property (nonatomic, retain) NSUserDefaults *defaults; +@property (nonatomic, retain) NSString *dateDescription; +@property (nonatomic) NSTimeInterval earliestDate; +@property (nonatomic) NSTimeInterval latestDate; + +- (id) initWithDefaults:(NSUserDefaults*) defaults dateDescription:(NSString *)dateDescription earliest:(NSTimeInterval) earliest latest: (NSTimeInterval) latest; +- (void) schedule; +- (bool) checkDate; +- (NSDate *) getDate; +- (void) followup; + +@end + +#endif /* SOSIntervalEvent_h */ diff --git a/keychain/SecureObjectSync/SOSIntervalEvent.m b/keychain/SecureObjectSync/SOSIntervalEvent.m new file mode 100644 index 00000000..30fda736 --- /dev/null +++ b/keychain/SecureObjectSync/SOSIntervalEvent.m @@ -0,0 +1,70 @@ +// +// SOSIntervalEvent.m +// Security_ios +// +// Created by murf on 9/12/19. +// + +#import +#import "SOSIntervalEvent.h" +#import "keychain/SecureObjectSync/SOSInternal.h" + +/* + + interval setting examples: + NSTimeInterval earliestGB = 60*60*24*3; // wait at least 3 days + NSTimeInterval latestGB = 60*60*24*7; // wait at most 7 days + + pattern: + +SOSIntervalEvent fooEvent = [[SOSIntervalEvent alloc] initWithDefaults:account.settings dateDescription:@"foocheck" earliest:60*60*24 latest:60*60*36]; + + // should we foo? + if([fooEvent checkDate]) { + WeDoFooToo(); + // schedule next foo + [fooEvent followup]; + } + // "schedule" is only used if you think there's a date upcoming you don't want altered + // getDate will return the next schedule event date + */ + +@implementation SOSIntervalEvent + +- (NSDate *) getDate { + return [_defaults valueForKey: _dateDescription]; +} + +- (bool) checkDate { + NSDate *theDate = [self getDate]; + if(theDate && ([theDate timeIntervalSinceNow] <= 0)) return true; + return false; +} + +- (void) followup { + NSDate *theDate = SOSCreateRandomDateBetweenNowPlus(_earliestDate, _latestDate); + [_defaults setValue:theDate forKey: _dateDescription]; +} + +- (void)schedule { + NSDate *theDate = [self getDate]; + if(!theDate) { + [self followup]; + } +} + +-(id)initWithDefaults:(NSUserDefaults*) defaults dateDescription:(NSString *)dateDescription earliest:(NSTimeInterval) earliest latest: (NSTimeInterval) latest { + if(!self) return nil; + _defaults = defaults; + if(! _defaults) { + _defaults = [[NSUserDefaults alloc] init]; + } + _dateDescription = dateDescription; + _earliestDate = earliest; + _latestDate = latest; + [self schedule]; + return self; +} + +@end + diff --git a/keychain/SecureObjectSync/SOSMessage.c b/keychain/SecureObjectSync/SOSMessage.c index cc9cfe13..97ab42db 100644 --- a/keychain/SecureObjectSync/SOSMessage.c +++ b/keychain/SecureObjectSync/SOSMessage.c @@ -48,7 +48,7 @@ // TODO: This is a layer violation, we need a better way to do this // Currently it's only used for logging. -#include +#include "keychain/securityd/SecItemDataSource.h" #if defined(SOSMessageFormatSpecification) && 0 @@ -211,29 +211,6 @@ parameters ANY DEFINED BY algorithm OPTIONAL } #endif // defined(SOSMessageFormatSpecification) && 0 -#if 0 -static inline bool SecMallocOk(const void *ptr) { - if (ptr) return true; - - return false; -} -#endif -#if 0 -static void appendObjects(CFMutableStringRef desc, CFArrayRef objects) { - __block bool needComma = false; - CFArrayForEach(objects, ^(const void *value) { - if (needComma) - CFStringAppend(desc, CFSTR(",")); - else - needComma = true; - - SecItemServerAppendItemDescription(desc, value); - }); -} -#endif - - - // // MARK: SOSMessage implementation. // @@ -300,7 +277,7 @@ static void SOSMessageDestroy(CFTypeRef cf) { } // TODO: Remove this layer violation! -#include +#include "keychain/securityd/SecItemServer.h" static uint64_t SOSMessageInferType(SOSMessageRef message, CFErrorRef *error); @@ -975,22 +952,6 @@ static const uint8_t *der_decode_optional_objects(SOSMessageRef message, CFError return seq_end ? seq_end : der; } -#if 0 -// Move to ccder and possibly refactor ccder_decode_constructed_tl to call this. -#ifdef CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -CCDER_DECODE_CONSTRUCTED_LEN_SPECIFIER -#endif -inline CC_NONNULL((1, 3)) -const uint8_t * -ccder_decode_constructed_len(const uint8_t **body_end, - const uint8_t *der, const uint8_t *der_end) { - size_t len; - der = ccder_decode_len(&len, der, der_end); - *body_end = der + len; - return der; -} -#endif - static const uint8_t *der_decode_message_header(SOSMessageRef message, CFErrorRef *error, const uint8_t *der, const uint8_t *der_end) { cc_unit flags[1] = {}; der = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &der_end, der, der_end); diff --git a/keychain/SecureObjectSync/SOSPeer.m b/keychain/SecureObjectSync/SOSPeer.m index 6b35c782..495c561c 100644 --- a/keychain/SecureObjectSync/SOSPeer.m +++ b/keychain/SecureObjectSync/SOSPeer.m @@ -44,7 +44,7 @@ #include "keychain/SecureObjectSync/SOSBackupEvent.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include @@ -53,7 +53,7 @@ #include // Backup Peer Support -#include +#include "keychain/securityd/SecKeybagSupport.h" #include diff --git a/keychain/SecureObjectSync/SOSPiggyback.m b/keychain/SecureObjectSync/SOSPiggyback.m index 5193395e..0234388f 100644 --- a/keychain/SecureObjectSync/SOSPiggyback.m +++ b/keychain/SecureObjectSync/SOSPiggyback.m @@ -29,7 +29,7 @@ #include #include -#include +#include "keychain/securityd/SecItemSchema.h" #include #include @@ -336,7 +336,7 @@ SOSPiggyCopyInitialSyncData(const uint8_t** der, const uint8_t *der_end) /* Don't check length here so we can add more data */ - if(results.count == 0 || tlks.count == 0){ + if(results.count == 0){ secnotice("piggy","NO DATA, falling back to waiting 5 minutes for initial sync to finish"); results = NULL; } @@ -369,11 +369,13 @@ SOSPiggyBackBlobCreateFromDER(SOSGenCountRef *retGencount, *der_p = der_decode_data_or_null(kCFAllocatorDefault, &publicBytes, error, *der_p, sequence_end); *der_p = der_decode_data_or_null(kCFAllocatorDefault, &signature, error, *der_p, sequence_end); - if(version == kPiggyV1){ + if(version != kPiggyV0 && *der_p != der_end) { NSDictionary* initialSyncDict = SOSPiggyCopyInitialSyncData(der_p, der_end); if (initialSyncDict) { NSArray* idents = initialSyncDict[@"idents"]; NSArray* tlks = initialSyncDict[@"tlks"]; + secnotice("piggy", "Piggybacking include identities(%d) and tlks(%d)", + (int)idents.count, (int)tlks.count); SOSPiggyBackAddToKeychain(idents, tlks); *setInitialSyncTimeoutToV0 = false; } diff --git a/keychain/SecureObjectSync/SOSRingUtils.h b/keychain/SecureObjectSync/SOSRingUtils.h index 64201e52..7fe9a6b4 100644 --- a/keychain/SecureObjectSync/SOSRingUtils.h +++ b/keychain/SecureObjectSync/SOSRingUtils.h @@ -135,19 +135,4 @@ SOSRingRef SOSRingCreateFromDER(CFErrorRef* error, const uint8_t** der_p, const CFDictionaryRef SOSRingCreateRetirementTicket(SOSFullPeerInfoRef fpi, CFErrorRef *error); -#if 0 -int SOSRingCountActivePeers(SOSCircleRef circle, SOSRingRef ring); -int SOSRingCountActiveValidPeers(SOSCircleRef circle, SOSRingRef ring, SecKeyRef pubkey); -int SOSRingCountRetiredPeers(SOSCircleRef circle, SOSRingRef ring); -void SOSRingForEachPeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachRetiredPeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachActivePeer(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -void SOSRingForEachActiveValidPeer(SOSCircleRef circle, SOSRingRef ring, SecKeyRef user_public_key, void (^action)(SOSPeerInfoRef peer)); -SOSPeerInfoRef SOSRingCopyPeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, CFErrorRef *error); -bool SOSRingHasActivePeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, CFErrorRef *error); -bool SOSRingHasActiveValidPeerWithID(SOSCircleRef circle, SOSRingRef ring, CFStringRef peerid, SecKeyRef user_public_key, CFErrorRef *error); -void SOSRingForEachApplicant(SOSCircleRef circle, SOSRingRef ring, void (^action)(SOSPeerInfoRef peer)); -bool SOSRingResetToOffering_Internal(SOSCircleRef circle, SOSRingRef ring, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error); -#endif - #endif /* defined(_sec_SOSRingUtils_) */ diff --git a/keychain/SecureObjectSync/SOSTransportKeyParameter.m b/keychain/SecureObjectSync/SOSTransportKeyParameter.m index 784d6a55..84b1bf27 100644 --- a/keychain/SecureObjectSync/SOSTransportKeyParameter.m +++ b/keychain/SecureObjectSync/SOSTransportKeyParameter.m @@ -2,7 +2,7 @@ #include "keychain/SecureObjectSync/SOSTransport.h" #include "keychain/SecureObjectSync/SOSTransportKeyParameter.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/SOSAccountPriv.h" #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/SOSTransportMessage.m b/keychain/SecureObjectSync/SOSTransportMessage.m index 6b0f0482..407c5543 100644 --- a/keychain/SecureObjectSync/SOSTransportMessage.m +++ b/keychain/SecureObjectSync/SOSTransportMessage.m @@ -12,7 +12,7 @@ #include "keychain/SecureObjectSync/SOSInternal.h" #include "keychain/SecureObjectSync/SOSAccountPriv.h" #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" -#include // TODO: Remove this layer violation. +#include "keychain/securityd/SecItemServer.h" // TODO: Remove this layer violation. static const CFStringRef kSecSOSMessageRTT = CFSTR("com.apple.security.sos.messagertt"); static const CFStringRef kSecAccessGroupSecureBackupd = CFSTR("com.apple.securebackupd"); diff --git a/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m b/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m index 96b421a1..9cdf7d3a 100644 --- a/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m +++ b/keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m @@ -39,7 +39,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/Tool/keychain_log.m b/keychain/SecureObjectSync/Tool/keychain_log.m index ee601a3e..fd004c9b 100644 --- a/keychain/SecureObjectSync/Tool/keychain_log.m +++ b/keychain/SecureObjectSync/Tool/keychain_log.m @@ -54,7 +54,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/SecureObjectSync/Tool/keychain_sync.m b/keychain/SecureObjectSync/Tool/keychain_sync.m index f5172661..4d17e4e5 100644 --- a/keychain/SecureObjectSync/Tool/keychain_sync.m +++ b/keychain/SecureObjectSync/Tool/keychain_sync.m @@ -46,7 +46,7 @@ #include "keychain/SecureObjectSync/SOSPeerInfoV2.h" #include "keychain/SecureObjectSync/SOSUserKeygen.h" #include "keychain/SecureObjectSync/SOSKVSKeys.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h" diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m index 235da5d3..00fe0159 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/OctagonTestHarnessXPCService.m @@ -29,30 +29,29 @@ } - (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError *))complete { - NSError *error = nil; - OTControl* rpc = [OTControl controlObject:true error:&error]; - if (rpc == nil) { - complete(@NO, error); + [self.remoteDevice otReset:altDSID complete:^(bool success, NSError * _Nullable error) { + complete([NSNumber numberWithBool:success], error); + }]; +} - return; - } +- (void)octagonPeerID:(NSString *)altDSID complete:(void (^)(NSString *, NSError *))complete { - [rpc resetAndEstablish:NULL context:OTDefaultContext altDSID:altDSID reply:^(NSError * _Nullable e) { - complete([NSNumber numberWithBool:e != NULL], e); + [self.remoteDevice otPeerID:altDSID complete:^(NSString *peerID, NSError * _Nullable error) { + complete(peerID, error); }]; } -/* Oh, ObjC, you are my friend */ -- (void)forwardInvocation:(NSInvocation *)invocation { - struct objc_method_description desc = protocol_getMethodDescription(@protocol(SecRemoteDeviceProtocol), [invocation selector], true, true); - if (desc.name == NULL) { - [super forwardInvocation:invocation]; - } else { - [invocation invokeWithTarget:self.remoteDevice]; - } +- (void)octagonInCircle:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError *_Nullable error))complete +{ + [self.remoteDevice otInCircle:altDSID complete:^(bool inCircle, NSError * _Nullable error) { + complete(@(inCircle), error); + }]; } + + + @end #pragma clang diagnostic pop diff --git a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m index d35615a5..c6404265 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m +++ b/keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m @@ -24,7 +24,7 @@ #import #import -#import +#import "keychain/securityd/SOSCloudCircleServer.h" #import #import #import @@ -428,7 +428,7 @@ #if OCTAGON OTControl *ot = [self OTControl]; - [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID reply:^(NSError * _Nullable error) { + [ot resetAndEstablish:nil context:OTDefaultContext altDSID:altDSID resetReason:CuttlefishResetReasonTestGenerated reply:^(NSError * _Nullable error) { complete(error == NULL, error); }]; #else diff --git a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h index 1cce9364..af5f2089 100644 --- a/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h +++ b/keychain/Trieste/OctagonTestHarnessXPCServiceProtocol/Sources/OctagonTestHarnessXPCServiceProtocol/include/OctagonTestHarnessXPCServiceProtocol.h @@ -2,9 +2,15 @@ #import +NS_ASSUME_NONNULL_BEGIN + @protocol OctagonTestHarnessXPCServiceProtocol // Trieste-compliant Octagon reset -- (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *reset, NSError *error))complete; +- (void)octagonReset:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError * _Nullable))complete; +- (void)octagonPeerID:(NSString *)altDSID complete:(void (^)(NSString *, NSError *_Nullable))complete; +- (void)octagonInCircle:(NSString *)altDSID complete:(void (^)(NSNumber *, NSError * _Nullable))complete; @end + +NS_ASSUME_NONNULL_END diff --git a/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift b/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift index 7308bfd6..04bb5f27 100644 --- a/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift +++ b/keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift @@ -65,7 +65,6 @@ class EscrowKeys: NSObject { class func generateEscrowKey(keyType: escrowKeyType, masterSecret: Data, bottleSalt: String) throws -> (Data) { var keyLength: Int var info: Data - var infoLength: Int var derivedKey: Data var finalKey = Data() @@ -75,7 +74,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Symmetric Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case escrowKeyType.kOTEscrowKeyEncryption: @@ -83,7 +81,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Encryption Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case escrowKeyType.kOTEscrowKeySigning: @@ -91,7 +88,6 @@ class EscrowKeys: NSObject { let infoString = Array("Escrow Signing Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break } @@ -107,30 +103,28 @@ class EscrowKeys: NSObject { derivedKey = Data(count: keyLength) var masterSecretMutable = masterSecret - let masterSecretLength = masterSecret.count - let derivedKeySize = derivedKey.count let bottleSaltData = Data(bytes: Array(bottleSalt.utf8), count: bottleSalt.utf8.count) - try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutablePointer) throws ->Void in - try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutablePointer) throws ->Void in - try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafePointer) throws -> Void in - try info.withUnsafeBytes { (infoBytes: UnsafePointer) throws -> Void in + try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutableRawBufferPointer) throws -> Void in + try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutableRawBufferPointer) throws -> Void in + try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafeRawBufferPointer) throws -> Void in + try info.withUnsafeBytes { (infoBytes: UnsafeRawBufferPointer) throws -> Void in status = cchkdf(ccsha384_di(), - masterSecretLength, masterSecretBytes, - bottleSaltData.count, bottleSaltBytes, - infoLength, infoBytes, - keyLength, derivedKeyBytes) + masterSecretBytes.count, masterSecretBytes.baseAddress!, + bottleSaltBytes.count, bottleSaltBytes.baseAddress!, + infoBytes.count, infoBytes.baseAddress!, + derivedKeyBytes.count, derivedKeyBytes.baseAddress!) if status != 0 { throw EscrowKeysError.corecryptoKeyGeneration(corecryptoError: status) } if(keyType == escrowKeyType.kOTEscrowKeySymmetric) { - finalKey = Data(buffer: UnsafeBufferPointer(start: derivedKeyBytes, count: derivedKeySize)) + finalKey = Data(buffer: derivedKeyBytes.bindMemory(to: UInt8.self)) return } else if(keyType == escrowKeyType.kOTEscrowKeyEncryption || keyType == escrowKeyType.kOTEscrowKeySigning) { status = ccec_generate_key_deterministic(cp, - derivedKeySize, derivedKeyBytes, + derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!, ccDRBGGetRngState(), UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS), fullKey) @@ -141,8 +135,8 @@ class EscrowKeys: NSObject { let space = ccec_x963_export_size(1, ccec_ctx_pub(fullKey)) var key = Data(count: space) - key.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - ccec_x963_export(1, bytes, fullKey) + key.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) -> Void in + ccec_x963_export(1, bytes.baseAddress!, fullKey) } finalKey = Data(key) } @@ -192,11 +186,10 @@ class EscrowKeys: NSObject { let di = ccsha384_di() var result = Data(count: TPHObjectiveC.ccsha384_diSize()) - let derivedKeySize = keyData.count var keyDataMutable = keyData - result.withUnsafeMutableBytes {(resultBytes: UnsafeMutablePointer) -> Void in - keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutablePointer) -> Void in - ccdigest(di, derivedKeySize, keyDataBytes, resultBytes) + result.withUnsafeMutableBytes {(resultBytes: UnsafeMutableRawBufferPointer) -> Void in + keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutableRawBufferPointer) -> Void in + ccdigest(di, keyDataBytes.count, keyDataBytes.baseAddress!, resultBytes.baseAddress!) } } let hash = result.base64EncodedString(options: []) @@ -211,7 +204,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrLabel: label, kSecAttrApplicationLabel: String(format: "Escrowed Encryption Key-%@", NSUUID().uuidString), kSecValueData: keyData, @@ -225,7 +218,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Escrowed Signing Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -239,7 +232,7 @@ class EscrowKeys: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Escrowed Symmetric Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -256,7 +249,7 @@ class EscrowKeys: NSObject { kSecAttrLabel: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitAll, ] @@ -368,14 +361,12 @@ extension EscrowKeysError: CustomNSError { } switch self { case .failedToSaveToKeychain(errorCode: let osError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) case .corecryptoKeyGeneration(corecryptoError: let corecryptoError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) default: break } return userInfo } } - - diff --git a/keychain/TrustedPeersHelper/Client.swift b/keychain/TrustedPeersHelper/Client.swift index fc8327ac..a7c5f127 100644 --- a/keychain/TrustedPeersHelper/Client.swift +++ b/keychain/TrustedPeersHelper/Client.swift @@ -89,7 +89,7 @@ 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, peerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error)) + reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: TPPeerStatus.unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false), CKXPCSuitableError(error)) } } @@ -105,12 +105,12 @@ class Client: TrustedPeersHelperProtocol { } } - func reset(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) { + func reset(withContainer container: String, context: String, resetReason: CuttlefishResetReason, reply: @escaping (Error?) -> Void) { do { let containerName = ContainerName(container: container, context: context) os_log("Resetting for %@", log: tplogDebug, type: .default, containerName.description) let container = try self.containerMap.findOrCreate(name: containerName) - container.reset { error in + container.reset(resetReason: resetReason) { error in self.logComplete(function: "Resetting", container: container.name, error: error) reply(CKXPCSuitableError(error)) } } catch { @@ -290,6 +290,23 @@ class Client: TrustedPeersHelperProtocol { } } + func preflightVouchWithBottle(withContainer container: String, + context: String, + bottleID: String, + reply: @escaping (String?, Error?) -> Void) { + do { + let containerName = ContainerName(container: container, context: context) + os_log("Preflight Vouch With Bottle %@", log: tplogDebug, type: .default, containerName.description) + let container = try self.containerMap.findOrCreate(name: containerName) + container.preflightVouchWithBottle(bottleID: bottleID) { peerID, error in + self.logComplete(function: "Preflight Vouch With Bottle", container: container.name, error: error) + reply(peerID, CKXPCSuitableError(error)) } + } catch { + os_log("Preflighting Vouch With Bottle failed for (%@, %@): %@", log: tplogDebug, type: .default, container, context, error as CVarArg) + reply(nil, CKXPCSuitableError(error)) + } + } + func vouchWithBottle(withContainer container: String, context: String, bottleID: String, @@ -358,7 +375,7 @@ class Client: TrustedPeersHelperProtocol { let containerName = ContainerName(container: container, context: context) os_log("Attempting to preflight a preapproved join for %@", log: tplogDebug, type: .default, containerName.description) let container = try self.containerMap.findOrCreate(name: containerName) - container.preflightPreapprovedJoin() { success, error in reply(success, CKXPCSuitableError(error)) } + container.preflightPreapprovedJoin { success, error in reply(success, CKXPCSuitableError(error)) } } catch { reply(false, CKXPCSuitableError(error)) } diff --git a/keychain/TrustedPeersHelper/Container.swift b/keychain/TrustedPeersHelper/Container.swift index 271e6c1a..c64e51b8 100644 --- a/keychain/TrustedPeersHelper/Container.swift +++ b/keychain/TrustedPeersHelper/Container.swift @@ -33,6 +33,29 @@ let tplogTrace = OSLog(subsystem: "com.apple.security.trustedpeers", category: " let egoIdentitiesAccessGroup = "com.apple.security.egoIdentities" +extension ResetReason { + static func from(cuttlefishResetReason: CuttlefishResetReason) -> ResetReason { + switch cuttlefishResetReason { + case .unknown: + return ResetReason.unknown + case .userInitiatedReset: + return ResetReason.userInitiatedReset + case .healthCheck: + return ResetReason.healthCheck + case .noBottleDuringEscrowRecovery: + return ResetReason.noBottleDuringEscrowRecovery + case .legacyJoinCircle: + return ResetReason.legacyJoinCircle + case .recoveryKey: + return ResetReason.recoveryKey + case .testGenerated: + return ResetReason.testGenerated + @unknown default: + fatalError() + } + } +} + public enum ContainerError: Error { case unableToCreateKeyPair case noPreparedIdentity @@ -74,6 +97,7 @@ public enum ContainerError: Error { case failedToAssembleBottle case invalidPeerID case failedToStoreSecret(errorCode: Int) + case unknownSecurityFoundationError } extension ContainerError: LocalizedError { @@ -159,6 +183,8 @@ extension ContainerError: LocalizedError { return "peerID is invalid" case .failedToStoreSecret(errorCode: let errorCode): return "failed to store the secret in the keychain \(errorCode)" + case .unknownSecurityFoundationError: + return "SecurityFoundation returned an unknown type" } } } @@ -253,6 +279,8 @@ extension ContainerError: CustomNSError { return 41 case .invalidPeerID: return 42 + case .unknownSecurityFoundationError: + return 43 } } @@ -294,7 +322,7 @@ func saveSecret(_ secret: Data, label: String) throws { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrDescription: label, kSecAttrPath: label, kSecValueData: secret, @@ -315,7 +343,7 @@ func saveSecret(_ secret: Data, label: String) throws { findQuery[kSecAttrAccessGroup] = query[kSecAttrAccessGroup] findQuery[kSecAttrServer] = query[kSecAttrDescription] findQuery[kSecAttrPath] = query[kSecAttrPath] - findQuery[kSecUseDataProtectionKeychain] = query[kSecUseDataProtectionKeychain]; + findQuery[kSecUseDataProtectionKeychain] = query[kSecUseDataProtectionKeychain] var updateQuery: [CFString: Any] = query updateQuery[kSecClass] = nil @@ -339,7 +367,7 @@ func loadSecret(label: String) throws -> (Data?) { kSecAttrDescription: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitOne, ] @@ -385,6 +413,8 @@ func loadEgoKeyPair(identifier: String, resultHandler: @escaping (_SFECKeyPair?, resultHandler(nil, ContainerError.needsAuthentication) case .error: resultHandler(nil, result.error) + @unknown default: + resultHandler(nil, ContainerError.unknownSecurityFoundationError) } } } @@ -419,7 +449,7 @@ func removeEgoKeysSync(peerID: String) throws -> Bool { let keychainManager = _SFKeychainManager.default() var retresultForSigningDeletion: Bool = false - var reterrorForSigningDeletion: Error? = nil + var reterrorForSigningDeletion: Error? //remove signing keys keychainManager.removeItem(withIdentifier: signingKeyIdentifier(peerID: peerID)) { result, error in @@ -441,7 +471,7 @@ func removeEgoKeysSync(peerID: String) throws -> Bool { // now let's do the same thing with the encryption keys resultSema = DispatchSemaphore(value: 0) var retresultForEncryptionDeletion: Bool = false - var reterrorForEncryptionDeletion: Error? = nil + var reterrorForEncryptionDeletion: Error? keychainManager.removeItem(withIdentifier: encryptionKeyIdentifier(peerID: peerID)) { result, error in retresultForEncryptionDeletion = result @@ -818,7 +848,7 @@ class Container: NSObject { } func onQueueDetermineLocalTrustStatus(reply: @escaping (TrustedPeersHelperEgoPeerStatus, Error?) -> Void) { - let peerCountsByModelID = self.model.peerCountsByModelID() + let viablePeerCountsByModelID = self.model.viablePeerCountsByModelID() if let egoPeerID = self.containerMO.egoPeerID { var status = self.model.statusOfPeer(withID: egoPeerID) @@ -844,7 +874,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: isExcluded, isLocked: isLocked) reply(egoStatus, returnError) @@ -856,7 +886,7 @@ class Container: NSObject { os_log("trust status: No error but Ego Peer Keys are nil", log: tplogDebug, type: .default) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: .excluded, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: true, isLocked: false) @@ -866,7 +896,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: egoPeerID, status: status, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: isExcluded, isLocked: false) reply(egoStatus, nil) @@ -879,7 +909,7 @@ class Container: NSObject { os_log("No existing peers in account", log: tplogDebug, type: .debug) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: false, isLocked: false) reply(egoStatus, nil) @@ -888,7 +918,7 @@ class Container: NSObject { os_log("Existing peers in account, but we don't have a peer ID. We are excluded.", log: tplogDebug, type: .debug) let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .excluded, - peerCountsByModelID: peerCountsByModelID, + viablePeerCountsByModelID: viablePeerCountsByModelID, isExcluded: true, isLocked: false) reply(egoStatus, nil) @@ -919,7 +949,7 @@ class Container: NSObject { let egoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, - peerCountsByModelID: [:], + viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false) reply(egoStatus, fetchError) @@ -955,14 +985,17 @@ class Container: NSObject { return } - let isPreapproved = self.model.hasPeerPreapprovingKey(permanentInfo.signingPubKey.spki()) + let isPreapproved = self.model.hasPotentiallyTrustedPeerPreapprovingKey(permanentInfo.signingPubKey.spki()) os_log("fetchTrustState: ego peer is %@", log: tplogDebug, type: .default, isPreapproved ? "preapproved" : "not yet preapproved") + let egoStableInfo = self.model.getStableInfoForPeer(withID: egoPeerID) + let egoPeerStatus = TrustedPeersHelperPeerState(peerID: egoPeerID, isPreapproved: isPreapproved, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: false, - unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful()) + unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful(), + osVersion: egoStableInfo?.osVersion) var tphPeers: [TrustedPeersHelperPeer] = [] @@ -990,7 +1023,7 @@ class Container: NSObject { } else { // With no ego peer ID, there are no trusted peers os_log("No peer ID => no trusted peers", log: tplogDebug, type: .debug) - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: false, unknownMachineIDs: false), [], nil) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: false, unknownMachineIDs: false, osVersion: nil), [], nil) } } } @@ -1029,6 +1062,8 @@ class Container: NSObject { let midList = self.onqueueCurrentMIDList() d["machineIDsAllowed"] = midList.machineIDs(in: .allowed).sorted() d["machineIDsDisallowed"] = midList.machineIDs(in: .disallowed).sorted() + d["modelRecoverySigningPublicKey"] = self.model.recoverySigningPublicKey() + d["modelRecoveryEncryptionPublicKey"] = self.model.recoveryEncryptionPublicKey() reply(d, nil) } @@ -1117,7 +1152,7 @@ class Container: NSObject { } } - func reset(reply: @escaping (Error?) -> Void) { + func reset(resetReason: CuttlefishResetReason, reply: @escaping (Error?) -> Void) { self.semaphore.wait() let reply: (Error?) -> Void = { os_log("reset complete %@", log: tplogTrace, type: .info, traceError($0)) @@ -1126,7 +1161,10 @@ class Container: NSObject { } self.moc.performAndWait { - let request = ResetRequest() + let resetReason = ResetReason.from(cuttlefishResetReason: resetReason) + let request = ResetRequest.with { + $0.resetReason = resetReason + } self.cuttlefish.reset(request) { response, error in os_log("Reset(%@): %@, error: %@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))") guard let response = response, error == nil else { @@ -1345,7 +1383,7 @@ class Container: NSObject { } } - func onqueueTTRUntrusted() -> Void { + func onqueueTTRUntrusted() { let ttr = SecTapToRadar(tapToRadar: "Device not IDMS trusted", description: "Device not IDMS trusted", radar: "52874119") @@ -1487,7 +1525,7 @@ class Container: NSObject { // This is an odd error condition: we might be able to fetch again and be in a good state... os_log("fetch-after-establish failed: %@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "no error") reply(nil, keyHierarchyRecords, fetchError) - return; + return } os_log("fetch-after-establish succeeded", log: tplogDebug, type: .default) @@ -1646,7 +1684,7 @@ class Container: NSObject { return !bmos.isEmpty } - func findBottleForEscrowRecordID(bottleID: String, reply: @escaping (BottleMO?, Error?) -> Void) { + func onqueueFindBottle(bottleID: String, reply: @escaping (BottleMO?, Error?) -> Void) { var bmo: BottleMO? var bottles: Set = [] @@ -1681,7 +1719,7 @@ class Container: NSObject { return } - os_log("findBottleForEscrowRecordID found bottle: %@", log: tplogDebug, type: .default, newBottles) + os_log("onqueueFindBottle found bottle: %@", log: tplogDebug, type: .default, newBottles) bottles = newBottles.filter { $0.bottleID == bottleID @@ -1760,6 +1798,29 @@ class Container: NSObject { } } + func preflightVouchWithBottle(bottleID: String, + reply: @escaping (String?, Error?) -> Void) { + self.semaphore.wait() + let reply: (String?, Error?) -> Void = { + os_log("preflightVouchWithBottle complete: %@", + log: tplogTrace, type: .info, traceError($1)) + self.semaphore.signal() + reply($0, $1) + } + + self.moc.performAndWait { + self.onqueueFindBottle(bottleID: bottleID) { bottleMO, error in + guard let bottleMO = bottleMO else { + os_log("preflightVouchWithBottle found no bottle: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "") + reply(nil, error) + return + } + + reply(bottleMO.peerID, nil) + } + } + } + func vouchWithBottle(bottleID: String, entropy: Data, bottleSalt: String, @@ -1780,7 +1841,7 @@ class Container: NSObject { return } - self.findBottleForEscrowRecordID(bottleID: bottleID) { returnedBMO, error in + self.onqueueFindBottle(bottleID: bottleID) { returnedBMO, error in self.moc.performAndWait { guard error == nil else { os_log("vouchWithBottle unable to find bottle for escrow record id: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "") @@ -2248,13 +2309,13 @@ class Container: NSObject { self.moc.performAndWait { guard let egoPeerID = self.containerMO.egoPeerID else { os_log("fetchEscrowContents failed", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.noPreparedIdentity) + reply(nil, nil, nil, ContainerError.noPreparedIdentity) return } guard let bottles = self.containerMO.bottles as? Set else { os_log("fetchEscrowContents failed", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.noBottleForPeer) + reply(nil, nil, nil, ContainerError.noBottleForPeer) return } @@ -2266,19 +2327,19 @@ class Container: NSObject { do { guard let loaded = try loadSecret(label: egoPeerID) else { os_log("fetchEscrowContents failed to load entropy", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.failedToFetchEscrowContents) + reply(nil, nil, nil, ContainerError.failedToFetchEscrowContents) return } entropy = loaded } catch { os_log("fetchEscrowContents failed to load entropy: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error") - reply (nil, nil, nil, error) + reply(nil, nil, nil, error) return } guard let signingPublicKey = bmo.escrowedSigningSPKI else { os_log("fetchEscrowContents no escrow signing spki", log: tplogDebug, type: .default) - reply (nil, nil, nil, ContainerError.bottleDoesNotContainerEscrowKeySPKI) + reply(nil, nil, nil, ContainerError.bottleDoesNotContainerEscrowKeySPKI) return } reply(entropy, bottleID, signingPublicKey, nil) @@ -2321,12 +2382,12 @@ class Container: NSObject { func fetchViableBottlesWithSemaphore(reply: @escaping ([String]?, [String]?, Error?) -> Void) { os_log("beginning a fetchViableBottles", log: tplogDebug, type: .default) - let cachedBottles:TPCachedViableBottles = self.model.currentCachedViableBottlesSet() + let cachedBottles: TPCachedViableBottles = self.model.currentCachedViableBottlesSet() self.moc.performAndWait { if self.onqueueCachedBottlesContainEgoPeerBottle(cachedBottles: cachedBottles) && (cachedBottles.viableBottles.count > 0 || cachedBottles.partialBottles.count > 0) { os_log("returning from fetchViableBottles, using cached bottles", log: tplogDebug, type: .default) - reply (cachedBottles.viableBottles, cachedBottles.partialBottles, nil) + reply(cachedBottles.viableBottles, cachedBottles.partialBottles, nil) return } @@ -2423,7 +2484,7 @@ class Container: NSObject { do { try self.moc.save() os_log("fetchViableBottles saved bottles", log: tplogDebug, type: .default) - let cached = TPCachedViableBottles.init(viableBottles: viableBottleIDs, partialBottles: partialBottleIDs) + let cached = TPCachedViableBottles(viableBottles: viableBottleIDs, partialBottles: partialBottleIDs) self.model.setViableBottles(cached) reply(viableBottleIDs, partialBottleIDs, nil) } catch { @@ -2973,7 +3034,7 @@ class Container: NSObject { return } - guard self.model.hasPeerPreapprovingKey(egoPermanentInfo.signingPubKey.spki()) else { + guard self.model.hasPotentiallyTrustedPeerPreapprovingKey(egoPermanentInfo.signingPubKey.spki()) else { os_log("preflightPreapprovedJoin: no peers preapprove our key", log: tplogDebug, type: .debug) reply(false, ContainerError.noPeersPreapprovePreparedIdentity) return @@ -3048,7 +3109,7 @@ class Container: NSObject { return } - guard self.model.hasPeerPreapprovingKey(egoPeerKeys.signingKey.publicKey().spki()) else { + guard self.model.hasPotentiallyTrustedPeerPreapprovingKey(egoPeerKeys.signingKey.publicKey().spki()) else { os_log("preapprovedJoin: no peers preapprove our key", log: tplogDebug, type: .debug) reply(nil, [], ContainerError.noPeersPreapprovePreparedIdentity) return @@ -3464,6 +3525,7 @@ class Container: NSObject { if let error = error { os_log("fetchChangesAndUpdateTrustIfNeeded: fetching failed: %@", log: tplogDebug, type: .default, error as CVarArg) reply(nil, error) + return } self.updateTrustIfNeeded(stableChanges: stableChanges, changesPending: changesPending, reply: reply) @@ -3486,24 +3548,25 @@ class Container: NSObject { guard let egoPeerID = self.containerMO.egoPeerID else { // No identity, nothing to do os_log("updateTrustIfNeeded: No identity.", log: tplogDebug, type: .default) - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false), nil) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false, osVersion: nil), nil) return } loadEgoKeyPair(identifier: signingKeyIdentifier(peerID: egoPeerID)) { signingKeyPair, error in guard let signingKeyPair = signingKeyPair else { os_log("updateTrustIfNeeded: no signing key pair: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error") - reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false), error) + reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: changesPending, unknownMachineIDs: false, osVersion: nil), error) return } guard self.model.hasPeer(withID: egoPeerID) else { // Not in circle, nothing to do - let isPreapproved = self.model.hasPeerPreapprovingKey(signingKeyPair.publicKey().spki()) + let isPreapproved = self.model.hasPotentiallyTrustedPeerPreapprovingKey(signingKeyPair.publicKey().spki()) os_log("updateTrustIfNeeded: ego peer is not in model, is %@", log: tplogDebug, type: .default, isPreapproved ? "preapproved" : "not yet preapproved") reply(TrustedPeersHelperPeerState(peerID: egoPeerID, isPreapproved: isPreapproved, status: .unknown, memberChanges: changesPending, - unknownMachineIDs: false), + unknownMachineIDs: false, + osVersion: nil), nil) return } @@ -3531,7 +3594,8 @@ class Container: NSObject { isPreapproved: false, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: changesPending, - unknownMachineIDs: false), + unknownMachineIDs: false, + osVersion: nil), error) return } @@ -3555,7 +3619,8 @@ class Container: NSObject { isPreapproved: false, status: self.model.statusOfPeer(withID: egoPeerID), memberChanges: changesPending, - unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful()), + unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful(), + osVersion: peer?.stableInfo?.osVersion), nil) return } @@ -3603,7 +3668,6 @@ class Container: NSObject { } } - private func persist(changes: Changes) throws { // This is some nonsense: I can't figure out how to tell swift to throw an exception across performAndWait. // So, do it ourself @@ -3636,7 +3700,7 @@ class Container: NSObject { if changes.differences.count > 0 { self.model.clearViableBottles() } - + try changes.differences.forEach { peerDifference in if let operation = peerDifference.operation { switch operation { @@ -3647,7 +3711,7 @@ class Container: NSObject { try self.addOrUpdate(peer: peer) // Update containerMO ego data if it has changed. if peer.peerID == self.containerMO.egoPeerID { - guard let stableInfoAndSig:TPPeerStableInfo = peer.stableInfoAndSig.toStableInfo() else { + guard let stableInfoAndSig: TPPeerStableInfo = peer.stableInfoAndSig.toStableInfo() else { break } self.containerMO.egoPeerStableInfo = stableInfoAndSig.data @@ -3913,7 +3977,7 @@ class Container: NSObject { } self.moc.performAndWait { - self.cuttlefish.pushHealthInquiry(HealthInquiryRequest()) { response, error in + self.cuttlefish.pushHealthInquiry(PushHealthInquiryRequest()) { response, error in os_log("pushHealthInquiry(): %@, error: %@", log: tplogDebug, "\(String(describing: response))", "\(String(describing: error))") guard error == nil else { reply(error) diff --git a/keychain/TrustedPeersHelper/ContainerMap.swift b/keychain/TrustedPeersHelper/ContainerMap.swift index 83cfbbb3..59f539dc 100644 --- a/keychain/TrustedPeersHelper/ContainerMap.swift +++ b/keychain/TrustedPeersHelper/ContainerMap.swift @@ -32,6 +32,50 @@ import Foundation let CuttlefishPushTopicBundleIdentifier = "com.apple.security.cuttlefish" +struct CKInternalErrorMatcher { + let code: Int + let internalCode: Int +} + +// Match a CKError/CKInternalError +func ~= (pattern: CKInternalErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + guard let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError else { + return false + } + return error.domain == CKErrorDomain && error.code == pattern.code && + underlyingError.domain == CKInternalErrorDomain && underlyingError.code == pattern.internalCode +} + +struct CKErrorMatcher { + let code: Int +} + +// Match a CKError +func ~= (pattern: CKErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + return error.domain == CKErrorDomain && error.code == pattern.code +} + +struct NSURLErrorMatcher { + let code: Int +} + +// Match an NSURLError +func ~= (pattern: NSURLErrorMatcher, value: Error?) -> Bool { + guard let value = value else { + return false + } + let error = value as NSError + return error.domain == NSURLErrorDomain && error.code == pattern.code +} + public class RetryingInvocable: CloudKitCode.Invocable { private let underlyingInvocable: CloudKitCode.Invocable @@ -39,14 +83,18 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.underlyingInvocable = retry } - private func retryableError(error: Error?) -> Bool { + public class func retryableError(error: Error?) -> Bool { switch error { - case let error as NSError where error.domain == NSURLErrorDomain && error.code == NSURLErrorTimedOut: + case NSURLErrorMatcher(code: NSURLErrorTimedOut): + return true + case CKErrorMatcher(code: CKError.networkFailure.rawValue): return true - case let error as NSError where error.domain == CKErrorDomain && error.code == CKError.networkFailure.rawValue: + case CKInternalErrorMatcher(code: CKError.serverRejectedRequest.rawValue, internalCode: CKInternalErrorCode.errorInternalServerInternalError.rawValue): return true case CuttlefishErrorMatcher(code: CuttlefishErrorCode.retryableServerFailure): return true + case CuttlefishErrorMatcher(code: CuttlefishErrorCode.transactionalFailure): + return true default: return false } @@ -54,7 +102,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { public func invoke(function: String, request: RequestType, - completion: @escaping (ResponseType?, Error?) -> Void) where RequestType : Message, ResponseType : Message { + completion: @escaping (ResponseType?, Error?) -> Void) where RequestType: Message, ResponseType: Message { let now = Date() let deadline = Date(timeInterval: 30, since: now) let delay = TimeInterval(5) @@ -62,7 +110,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.invokeRetry(function: function, request: request, deadline: deadline, - delay: delay, + minimumDelay: delay, completion: completion) } @@ -70,14 +118,20 @@ public class RetryingInvocable: CloudKitCode.Invocable { function: String, request: RequestType, deadline: Date, - delay: TimeInterval, + minimumDelay: TimeInterval, completion: @escaping (ResponseType?, Error?) -> Void) { self.underlyingInvocable.invoke(function: function, request: request) { (response: ResponseType?, error: Error?) in - if self.retryableError(error: error) { + if let error = error, RetryingInvocable.retryableError(error: error) { let now = Date() + + // Check cuttlefish and CKError retry afters. + let cuttlefishDelay = CuttlefishRetryAfter(error: error) + let ckDelay = CKRetryAfterSecondsForError(error) + let delay = max(minimumDelay, cuttlefishDelay, ckDelay) let cutoff = Date(timeInterval: delay, since: now) + guard cutoff.compare(deadline) == ComparisonResult.orderedDescending else { Thread.sleep(forTimeInterval: delay) os_log("%{public}@ error: %{public}@ (retrying, now=%{public}@, deadline=%{public}@)", log: tplogDebug, @@ -88,7 +142,7 @@ public class RetryingInvocable: CloudKitCode.Invocable { self.invokeRetry(function: function, request: request, deadline: deadline, - delay: delay, + minimumDelay: minimumDelay, completion: completion) return } diff --git a/keychain/TrustedPeersHelper/Container_MachineIDs.swift b/keychain/TrustedPeersHelper/Container_MachineIDs.swift index 7c015f98..0e5f5c8c 100644 --- a/keychain/TrustedPeersHelper/Container_MachineIDs.swift +++ b/keychain/TrustedPeersHelper/Container_MachineIDs.swift @@ -1,4 +1,3 @@ - import CoreData import Foundation @@ -8,7 +7,7 @@ extension MachineMO { return false } - let dateLimit = Date(timeIntervalSinceNow: -60*60*TimeInterval(hours)) + let dateLimit = Date(timeIntervalSinceNow: -60 * 60 * TimeInterval(hours)) return modifiedDate.compare(dateLimit) == ComparisonResult.orderedDescending } @@ -89,8 +88,7 @@ extension Container { var differences = false var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) - + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) knownMachines.forEach { machine in guard let mid = machine.machineID else { @@ -162,21 +160,26 @@ extension Container { } } - // Now, are there any machine IDs in the model that aren't in the list? If so, add them as "unknown" - let modelMachineIDs = self.model.allMachineIDs() - modelMachineIDs.forEach { peerMachineID in - if !knownMachineIDs.contains(peerMachineID) && !allowedMachineIDs.contains(peerMachineID) { - os_log("Peer machineID is unknown, beginning grace period: %@", log: tplogDebug, type: .default, peerMachineID) - let machine = MachineMO(context: self.moc) - machine.machineID = peerMachineID - machine.container = containerMO - machine.seenOnFullList = false - machine.modified = Date() - machine.status = Int64(TPMachineIDStatus.unknown.rawValue) - differences = true + // if this account is not a demo account... + if knownMachines.count > 0 { + // Are there any machine IDs in the model that aren't in the list? If so, add them as "unknown" + let modelMachineIDs = self.model.allMachineIDs() + modelMachineIDs.forEach { peerMachineID in + if !knownMachineIDs.contains(peerMachineID) && !allowedMachineIDs.contains(peerMachineID) { + os_log("Peer machineID is unknown, beginning grace period: %@", log: tplogDebug, type: .default, peerMachineID) + let machine = MachineMO(context: self.moc) + machine.machineID = peerMachineID + machine.container = containerMO + machine.seenOnFullList = false + machine.modified = Date() + machine.status = Int64(TPMachineIDStatus.unknown.rawValue) + differences = true - self.containerMO.addToMachines(machine) + self.containerMO.addToMachines(machine) + } } + } else { + os_log("Believe we're in a demo account; not starting an unknown machine ID grace period", log: tplogDebug, type: .default) } // We no longer use allowed machine IDs. @@ -205,7 +208,7 @@ extension Container { self.moc.performAndWait { do { var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) // We treat an add push as authoritative (even though we should really confirm it with a full list fetch). // We can get away with this as we're using this list as a deny-list, and if we accidentally don't deny someone fast enough, that's okay. @@ -254,7 +257,7 @@ extension Container { self.moc.performAndWait { do { var knownMachines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(knownMachines.compactMap { $0.machineID }) // This is an odd approach: we'd like to confirm that this MID was actually removed (and not just a delayed push). // So, let's set the status to "unknown", and its modification date to the distant past. @@ -331,7 +334,7 @@ extension Container { // We don't want to automatically kick out new peers if they rejoin with the same MID. let machines = containerMO.machines as? Set ?? Set() - let knownMachineIDs = Set(machines.compactMap { $0.machineID } ) + let knownMachineIDs = Set(machines.compactMap { $0.machineID }) // Peers trust themselves. So if the ego peer is in Octagon, its machineID will be in this set let trustedMachineIDs = Set(dynamicInfo.includedPeerIDs.compactMap { self.model.peer(withID: $0)?.permanentInfo.machineID }) diff --git a/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift b/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift index 708d1881..af712744 100644 --- a/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift +++ b/keychain/TrustedPeersHelper/CuttlefishAPIHelpers.swift @@ -19,7 +19,7 @@ extension ViewKey { $0.parentkeyUuid = ckksKey.parentKeyUUID $0.keyclass = kc $0.wrappedkeyBase64 = ckksKey.wrappedkey.base64WrappedKey() - $0.uploadOsversion = SecCKKSHostOSVersion() + $0.uploadOsVersion = SecCKKSHostOSVersion() } } } diff --git a/keychain/TrustedPeersHelper/CuttlefishErrors.swift b/keychain/TrustedPeersHelper/CuttlefishErrors.swift index 138c7c6d..04d9b902 100644 --- a/keychain/TrustedPeersHelper/CuttlefishErrors.swift +++ b/keychain/TrustedPeersHelper/CuttlefishErrors.swift @@ -1,32 +1,22 @@ import Foundation -let CuttlefishErrorDomain = "CuttlefishError" -enum CuttlefishErrorCode: Int { - case establishFailed = 1001 - case invalidChangeToken = 1005 - case resultGraphNotFullyReachable = 1007 - case changeTokenExpired = 1018 - case transactionalFailure = 1019 - case retryableServerFailure = 1021 - case keyHierarchyAlreadyExists = 1033 -} - struct CuttlefishErrorMatcher { let code: CuttlefishErrorCode } // Use a 'pattern match operator' to make pretty case statements matching Cuttlefish errors func ~=(pattern: CuttlefishErrorMatcher, value: Error?) -> Bool { - guard let value = value else { + guard let error = value else { return false } + let nserror = error as NSError + return nserror.isCuttlefishError(pattern.code) +} - let error = value as NSError - - guard let underlyingError = error.userInfo[NSUnderlyingErrorKey] as? NSError else { - return false +func CuttlefishRetryAfter(error: Error?) -> TimeInterval { + guard let error = error else { + return 0 } - - return error.domain == CKInternalErrorDomain && error.code == CKInternalErrorCode.errorInternalPluginError.rawValue && - underlyingError.domain == CuttlefishErrorDomain && underlyingError.code == pattern.code.rawValue + let nserror = error as NSError + return nserror.cuttlefishRetryAfter() } diff --git a/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift b/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift index 2ed38843..1ab70461 100644 --- a/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift +++ b/keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift @@ -61,7 +61,6 @@ class RecoveryKeySet: NSObject { class func generateRecoveryKey(keyType: recoveryKeyType, masterSecret: Data, recoverySalt: String) throws -> (Data) { var keyLength: Int var info: Data - var infoLength: Int var derivedKey: Data var finalKey = Data() @@ -71,7 +70,6 @@ class RecoveryKeySet: NSObject { let infoString = Array("Recovery Encryption Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break case recoveryKeyType.kOTRecoveryKeySigning: @@ -79,7 +77,6 @@ class RecoveryKeySet: NSObject { let infoString = Array("Recovery Signing Private Key".utf8) info = Data(bytes: infoString, count: infoString.count) - infoLength = info.count break } @@ -95,27 +92,25 @@ class RecoveryKeySet: NSObject { derivedKey = Data(count: keyLength) var masterSecretMutable = masterSecret - let masterSecretLength = masterSecret.count - let derivedKeySize = derivedKey.count let bottleSaltData = Data(bytes: Array(recoverySalt.utf8), count: recoverySalt.utf8.count) - try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutablePointer) throws ->Void in - try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutablePointer) throws ->Void in - try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafePointer) throws -> Void in - try info.withUnsafeBytes { (infoBytes: UnsafePointer) throws -> Void in + try derivedKey.withUnsafeMutableBytes { (derivedKeyBytes: UnsafeMutableRawBufferPointer) throws ->Void in + try masterSecretMutable.withUnsafeMutableBytes { (masterSecretBytes: UnsafeMutableRawBufferPointer) throws ->Void in + try bottleSaltData.withUnsafeBytes { (bottleSaltBytes: UnsafeRawBufferPointer) throws -> Void in + try info.withUnsafeBytes { (infoBytes: UnsafeRawBufferPointer) throws -> Void in status = cchkdf(ccsha384_di(), - masterSecretLength, masterSecretBytes, - bottleSaltData.count, bottleSaltBytes, - infoLength, infoBytes, - keyLength, derivedKeyBytes) + masterSecretBytes.count, masterSecretBytes.baseAddress!, + bottleSaltBytes.count, bottleSaltBytes.baseAddress!, + infoBytes.count, infoBytes.baseAddress!, + derivedKeyBytes.count, derivedKeyBytes.baseAddress!) if status != 0 { throw RecoveryKeySetError.corecryptoKeyGeneration(corecryptoError: status) } if(keyType == recoveryKeyType.kOTRecoveryKeyEncryption || keyType == recoveryKeyType.kOTRecoveryKeySigning) { status = ccec_generate_key_deterministic(cp, - derivedKeySize, derivedKeyBytes, + derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!, ccDRBGGetRngState(), UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS), fullKey) @@ -126,8 +121,8 @@ class RecoveryKeySet: NSObject { let space = ccec_x963_export_size(1, ccec_ctx_pub(fullKey)) var key = Data(count: space) - key.withUnsafeMutableBytes { (bytes: UnsafeMutablePointer) -> Void in - ccec_x963_export(1, bytes, fullKey) + key.withUnsafeMutableBytes { (bytes: UnsafeMutableRawBufferPointer) -> Void in + ccec_x963_export(1, bytes.baseAddress!, fullKey) } finalKey = Data(key) } @@ -178,11 +173,10 @@ class RecoveryKeySet: NSObject { let di = ccsha384_di() var result = Data(count: TPHObjectiveC.ccsha384_diSize()) - let derivedKeySize = keyData.count var keyDataMutable = keyData - result.withUnsafeMutableBytes {(resultBytes: UnsafeMutablePointer) -> Void in - keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutablePointer) -> Void in - ccdigest(di, derivedKeySize, keyDataBytes, resultBytes) + result.withUnsafeMutableBytes {(resultBytes: UnsafeMutableRawBufferPointer) -> Void in + keyDataMutable.withUnsafeMutableBytes {(keyDataBytes: UnsafeMutableRawBufferPointer) -> Void in + ccdigest(di, keyDataBytes.count, keyDataBytes.baseAddress!, resultBytes.baseAddress!) } } let hash = result.base64EncodedString(options: []) @@ -197,7 +191,7 @@ class RecoveryKeySet: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrLabel: label, kSecAttrApplicationLabel: String(format: "Recoveryed Encryption Key-%@", NSUUID().uuidString), kSecValueData: keyData, @@ -211,7 +205,7 @@ class RecoveryKeySet: NSObject { kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked, kSecUseDataProtectionKeychain: true, kSecAttrAccessGroup: "com.apple.security.octagon", - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecAttrApplicationLabel: String(format: "Recoveryed Signing Key-%@", NSUUID().uuidString), kSecAttrLabel: label, kSecValueData: keyData, @@ -228,7 +222,7 @@ class RecoveryKeySet: NSObject { kSecAttrLabel: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitAll, ] @@ -335,9 +329,9 @@ extension RecoveryKeySetError: CustomNSError { } switch self { case .failedToSaveToKeychain(errorCode: let osError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: NSOSStatusErrorDomain, code: Int(osError), userInfo: nil) case .corecryptoKeyGeneration(corecryptoError: let corecryptoError): - userInfo[NSUnderlyingErrorKey] = NSError.init(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) + userInfo[NSUnderlyingErrorKey] = NSError(domain: "corecrypto", code: Int(corecryptoError), userInfo: nil) default: break } diff --git a/keychain/TrustedPeersHelper/SetValueTransformer.swift b/keychain/TrustedPeersHelper/SetValueTransformer.swift index ced7dd28..2529be27 100644 --- a/keychain/TrustedPeersHelper/SetValueTransformer.swift +++ b/keychain/TrustedPeersHelper/SetValueTransformer.swift @@ -6,11 +6,11 @@ class SetValueTransformer: ValueTransformer { override class func transformedValueClass() -> AnyClass { return NSData.self } - + override class func allowsReverseTransformation() -> Bool { return true } - + override func transformedValue(_ value: Any?) -> Any? { do { guard let value = value else { return nil } @@ -27,7 +27,7 @@ class SetValueTransformer: ValueTransformer { guard let data = dataOp else { return nil } let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data) - return unarchiver.decodeObject(of: [NSSet.self], forKey:NSKeyedArchiveRootObjectKey) + return unarchiver.decodeObject(of: [NSSet.self], forKey: NSKeyedArchiveRootObjectKey) } catch { os_log("Failed to deserialize a purported Set: %@", log: tplogDebug, type: .default, error as CVarArg) return nil diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h b/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h index d46c031d..a633cef5 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h +++ b/keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h @@ -41,6 +41,7 @@ #import "keychain/ckks/CKKSKeychainBackedKey.h" #import "keychain/ckks/CKKSPeer.h" #import "keychain/ckks/CKKSTLKShare.h" +#import "keychain/ckks/CloudKitCategories.h" #import #include diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist b/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist index 555752c4..6947f3d5 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist +++ b/keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist @@ -35,5 +35,7 @@ com.apple.security.octagon com.apple.security.egoIdentities + com.apple.symptom_diagnostics.report + diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h index c313182d..be36cc1f 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h @@ -27,6 +27,8 @@ #import "keychain/ckks/CKKSKeychainBackedKey.h" #import "keychain/ckks/CKKSTLKShare.h" +#import "keychain/ot/OTConstants.h" + NS_ASSUME_NONNULL_BEGIN // Any client hoping to use the TrustedPeersHelperProtocol should have an entitlement @@ -38,13 +40,16 @@ NS_ASSUME_NONNULL_BEGIN @property TPPeerStatus peerStatus; @property BOOL memberChanges; @property BOOL unknownMachineIDsPresent; +@property (nullable) NSString* osVersion; - (instancetype)initWithPeerID:(NSString* _Nullable)peerID isPreapproved:(BOOL)isPreapproved status:(TPPeerStatus)peerStatus memberChanges:(BOOL)memberChanges - unknownMachineIDs:(BOOL)unknownMachineIDs; + unknownMachineIDs:(BOOL)unknownMachineIDs + osVersion:(NSString * _Nullable)osVersion; @end + @interface TrustedPeersHelperPeer : NSObject @property (nullable) NSString* peerID; @property (nullable) NSData* signingSPKI; @@ -61,13 +66,15 @@ NS_ASSUME_NONNULL_BEGIN @property TPPeerStatus egoStatus; @property NSString* _Nullable egoPeerID; @property (assign) uint64_t numberOfPeersInOctagon; -@property NSDictionary* peerCountsByModelID; + +// Note: this field does not include untrusted peers +@property NSDictionary* viablePeerCountsByModelID; @property BOOL isExcluded; @property BOOL isLocked; - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus - peerCountsByModelID:(NSDictionary*)peerCountsByModelID + viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked; @@ -99,6 +106,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)resetWithContainer:(NSString *)container context:(NSString *)context + resetReason:(CuttlefishResetReason)reason reply:(void (^)(NSError * _Nullable error))reply; - (void)localResetWithContainer:(NSString *)container @@ -179,6 +187,14 @@ NS_ASSUME_NONNULL_BEGIN NSData * _Nullable voucherSig, NSError * _Nullable error))reply; +// Preflighting a vouch will return the peer ID associated with the bottle you will be recovering. +// You can then use that peer ID to filter the tlkshares provided to vouchWithBottle. +- (void)preflightVouchWithBottleWithContainer:(NSString *)container + context:(NSString *)context + bottleID:(NSString*)bottleID + reply:(void (^)(NSString* _Nullable peerID, + NSError * _Nullable error))reply; + // Returns a voucher for our own identity, created by the identity inside this bottle - (void)vouchWithBottleWithContainer:(NSString *)container context:(NSString *)context diff --git a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m index a912a227..f04ac68e 100644 --- a/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m +++ b/keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m @@ -149,6 +149,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) status:(TPPeerStatus)peerStatus memberChanges:(BOOL)memberChanges unknownMachineIDs:(BOOL)unknownMachineIDs + osVersion:(NSString *)osVersion { if((self = [super init])) { _peerID = peerID; @@ -156,18 +157,20 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _peerStatus = peerStatus; _memberChanges = memberChanges; _unknownMachineIDsPresent = unknownMachineIDs; + _osVersion = osVersion; } return self; } - (NSString*)description { - return [NSString stringWithFormat:@"", + return [NSString stringWithFormat:@"", self.peerID, self.identityIsPreapproved, (int64_t)self.peerStatus, self.memberChanges ? @"YES" : @"NO", - self.unknownMachineIDsPresent ? @"YES" : @"NO"]; + self.unknownMachineIDsPresent ? @"YES" : @"NO", + self.osVersion?:@"unknown"]; } + (BOOL)supportsSecureCoding { @@ -181,6 +184,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) _peerStatus = (TPPeerStatus)[coder decodeInt64ForKey:@"peerStatus"]; _memberChanges = (BOOL)[coder decodeInt64ForKey:@"memberChanges"]; _unknownMachineIDsPresent = (BOOL)[coder decodeInt64ForKey:@"unknownMachineIDs"]; + _osVersion = [coder decodeObjectOfClass:[NSString class] forKey:@"osVersion"]; } return self; } @@ -191,6 +195,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) [coder encodeInt64:(int64_t)self.peerStatus forKey:@"peerStatus"]; [coder encodeInt64:(int64_t)self.memberChanges forKey:@"memberChanges"]; [coder encodeInt64:(int64_t)self.unknownMachineIDsPresent forKey:@"unknownMachineIDs"]; + [coder encodeObject:self.osVersion forKey:@"osVersion"]; } @end @@ -199,16 +204,16 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) - (instancetype)initWithEgoPeerID:(NSString* _Nullable)egoPeerID status:(TPPeerStatus)egoStatus - peerCountsByModelID:(NSDictionary*)peerCountsByModelID + viablePeerCountsByModelID:(NSDictionary*)viablePeerCountsByModelID isExcluded:(BOOL)isExcluded isLocked:(BOOL)isLocked { if((self = [super init])) { _egoPeerID = egoPeerID; _egoStatus = egoStatus; - _peerCountsByModelID = peerCountsByModelID; + _viablePeerCountsByModelID = viablePeerCountsByModelID; _numberOfPeersInOctagon = 0; - for(NSNumber* n in peerCountsByModelID.allValues) { + for(NSNumber* n in viablePeerCountsByModelID.allValues) { _numberOfPeersInOctagon += [n unsignedIntegerValue]; } _isExcluded = isExcluded; @@ -230,9 +235,9 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) if ((self = [super init])) { _egoPeerID = [coder decodeObjectOfClass:[NSString class] forKey:@"peerID"]; _egoStatus = (TPPeerStatus)[coder decodeInt64ForKey:@"egoStatus"]; - _peerCountsByModelID = [coder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSString class], [NSNumber class]]] forKey:@"peerCountsByModelID"]; + _viablePeerCountsByModelID = [coder decodeObjectOfClasses:[NSSet setWithArray:@[[NSDictionary class], [NSString class], [NSNumber class]]] forKey:@"viablePeerCountsByModelID"]; _numberOfPeersInOctagon = 0; - for(NSNumber* n in _peerCountsByModelID.allValues) { + for(NSNumber* n in _viablePeerCountsByModelID.allValues) { _numberOfPeersInOctagon += [n unsignedIntegerValue]; } @@ -245,7 +250,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface) - (void)encodeWithCoder:(NSCoder *)coder { [coder encodeObject:self.egoPeerID forKey:@"peerID"]; [coder encodeInt64:self.egoStatus forKey:@"egoStatus"]; - [coder encodeObject:self.peerCountsByModelID forKey:@"peerCountsByModelID"]; + [coder encodeObject:self.viablePeerCountsByModelID forKey:@"viablePeerCountsByModelID"]; [coder encodeBool:self.isExcluded forKey:@"isExcluded"]; [coder encodeBool:self.isLocked forKey:@"isLocked"]; } diff --git a/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m b/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m index b2607898..0e4cdeb0 100644 --- a/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m +++ b/keychain/TrustedPeersHelper/categories/OTPrivateKey+SF.m @@ -26,6 +26,7 @@ #import #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTConstants.h" +#import "utilities/SecCFWrappers.h" @implementation OTPrivateKey (SecurityFoundation) @@ -36,7 +37,8 @@ pk.keyData = keyPair.keyData; return pk; } -+ (SecKeyRef) createSecKey:(NSData*)keyData + ++ (SecKeyRef) createSecKey:(NSData*)keyData CF_RETURNS_RETAINED { NSDictionary *keyAttributes = @{ (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, @@ -55,7 +57,10 @@ } return nil; } - return [[SFECKeyPair alloc] initWithSecKey:[OTPrivateKey createSecKey:self.keyData]]; + SecKeyRef secKey = [OTPrivateKey createSecKey:self.keyData]; + SFECKeyPair *result = [[SFECKeyPair alloc] initWithSecKey:secKey]; + CFReleaseNull(secKey); + return result; } @end diff --git a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift index 17ab441f..30916147 100644 --- a/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift +++ b/keychain/TrustedPeersHelperUnitTests/ContainerSync.swift @@ -21,10 +21,10 @@ extension Container { return (reta, reterr) } - func resetSync(test: XCTestCase) -> Error? { + func resetSync(resetReason: CuttlefishResetReason, test: XCTestCase) -> Error? { let expectation = XCTestExpectation(description: "reset replied") var reterr: Error? - self.reset { error in + self.reset(resetReason: resetReason) { error in reterr = error expectation.fulfill() } @@ -126,6 +126,18 @@ extension Container { return (reta, retb, reterr) } + func preflightVouchWithBottleSync(test: XCTestCase, bottleID: String) -> (String?, Error?) { + let expectation = XCTestExpectation(description: "preflightVouchWithBottle replied") + var reta: String?, reterr: Error? + self.preflightVouchWithBottle(bottleID: bottleID) { a, err in + reta = a + reterr = err + expectation.fulfill() + } + test.wait(for: [expectation], timeout: 10.0) + return (reta, reterr) + } + func vouchWithBottleSync(test: XCTestCase, b: String, entropy: Data, bottleSalt: String, tlkShares: [CKKSTLKShare]) -> (Data?, Data?, Error?) { let expectation = XCTestExpectation(description: "vouchWithBottle replied") var reta: Data?, retb: Data?, reterr: Error? @@ -310,7 +322,7 @@ extension Container { func trustStatusSync(test: XCTestCase) -> (TrustedPeersHelperEgoPeerStatus, Error?) { let expectation = XCTestExpectation(description: "trustStatus replied") - var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, peerCountsByModelID: [:], isExcluded: false, isLocked: false) + var retEgoStatus = TrustedPeersHelperEgoPeerStatus(egoPeerID: nil, status: .unknown, viablePeerCountsByModelID: [:], isExcluded: false, isLocked: false) var reterror: Error? self.trustStatus { egoStatus, error in retEgoStatus = egoStatus diff --git a/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift b/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift index fce8f219..fbef651a 100644 --- a/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift +++ b/keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift @@ -210,6 +210,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { var joinListener: ((JoinWithVoucherRequest) -> NSError?)? var healthListener: ((GetRepairActionRequest) -> NSError?)? var fetchViableBottlesListener: ((FetchViableBottlesRequest) -> NSError?)? + var resetListener: ((ResetRequest) -> NSError?)? var fetchViableBottlesDontReturnBottleWithID: String? @@ -233,12 +234,19 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { } } - static func makeCloudKitCuttlefishError(code: CuttlefishErrorCode) -> NSError { - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: code.rawValue, - userInfo: nil)]) + static func makeCloudKitCuttlefishError(code: CuttlefishErrorCode, retryAfter: TimeInterval = 5) -> NSError { + let cuttlefishError = CKPrettyError(domain: CuttlefishErrorDomain, + code: code.rawValue, + userInfo: [CuttlefishErrorRetryAfterKey: retryAfter]) + let internalError = CKPrettyError(domain: CKInternalErrorDomain, + code: CKInternalErrorCode.errorInternalPluginError.rawValue, + userInfo: [NSUnderlyingErrorKey: cuttlefishError, ]) + let ckError = CKPrettyError(domain: CKErrorDomain, + code: CKError.serverRejectedRequest.rawValue, + userInfo: [NSUnderlyingErrorKey: internalError, + CKErrorServerDescriptionKey: "Fake: FunctionError domain: CuttlefishError, code: \(code),\(code.rawValue)", + ]) + return ckError } func makeSnapshot() { @@ -287,6 +295,13 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { func reset(_ request: ResetRequest, completion: @escaping (ResetResponse?, Error?) -> Void) { print("FakeCuttlefish: reset called") + if let resetListener = self.resetListener { + let possibleError = resetListener(request) + guard possibleError == nil else { + completion(nil, possibleError) + return + } + } self.state = State() self.makeSnapshot() completion(ResetResponse.with { @@ -328,11 +343,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { if let fakeZone = self.fakeCKZones[rzid] as? FakeCKZone { fakeZone.queue.sync { - let tlkRecord = viewKeys.newTlk.fakeRecord(zoneID: rzid) + let tlkRecord = viewKeys.newTlk.fakeRecord(zoneID: rzid) let classARecord = viewKeys.newClassA.fakeRecord(zoneID: rzid) let classCRecord = viewKeys.newClassC.fakeRecord(zoneID: rzid) - let tlkPointerRecord = viewKeys.newTlk.fakeKeyPointer(zoneID: rzid) + let tlkPointerRecord = viewKeys.newTlk.fakeKeyPointer(zoneID: rzid) let classAPointerRecord = viewKeys.newClassA.fakeKeyPointer(zoneID: rzid) let classCPointerRecord = viewKeys.newClassC.fakeKeyPointer(zoneID: rzid) @@ -342,11 +357,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let zoneKeys = self.ckksZoneKeys[rzid] as? ZoneKeys ?? ZoneKeys(forZoneName: rzid.zoneName) self.ckksZoneKeys[rzid] = zoneKeys - zoneKeys.tlk = CKKSKey(ckRecord: tlkRecord) + zoneKeys.tlk = CKKSKey(ckRecord: tlkRecord) zoneKeys.classA = CKKSKey(ckRecord: classARecord) zoneKeys.classC = CKKSKey(ckRecord: classCRecord) - zoneKeys.currentTLKPointer = CKKSCurrentKeyPointer(ckRecord: tlkPointerRecord) + zoneKeys.currentTLKPointer = CKKSCurrentKeyPointer(ckRecord: tlkPointerRecord) zoneKeys.currentClassAPointer = CKKSCurrentKeyPointer(ckRecord: classAPointerRecord) zoneKeys.currentClassCPointer = CKKSCurrentKeyPointer(ckRecord: classCPointerRecord) #endif @@ -407,7 +422,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = establishListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -426,7 +441,6 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { self.makeSnapshot() - let response = EstablishResponse.with { if self.nextEstablishReturnsMoreChanges { $0.changes = Changes.with { @@ -450,7 +464,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = joinListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -518,7 +532,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = updateListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -571,7 +585,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = fetchChangesListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -606,7 +620,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = fetchViableBottlesListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -659,8 +673,8 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { func reportHealth(_: ReportHealthRequest, completion: @escaping (ReportHealthResponse?, Error?) -> Void) { completion(ReportHealthResponse(), nil) } - func pushHealthInquiry(_: HealthInquiryRequest, completion: @escaping (HealthInquiryResponse?, Error?) -> Void) { - completion(HealthInquiryResponse(), nil) + func pushHealthInquiry(_: PushHealthInquiryRequest, completion: @escaping (PushHealthInquiryResponse?, Error?) -> Void) { + completion(PushHealthInquiryResponse(), nil) } func getRepairAction(_ request: GetRepairActionRequest, completion: @escaping (GetRepairActionResponse?, Error?) -> Void) { @@ -670,7 +684,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { let possibleError = healthListener(request) guard possibleError == nil else { completion(nil, possibleError) - return; + return } } @@ -679,20 +693,17 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { $0.repairAction = .postRepairEscrow } completion(response, nil) - } - else if self.returnRepairAccountResponse { + } else if self.returnRepairAccountResponse { let response = GetRepairActionResponse.with { $0.repairAction = .postRepairAccount } completion(response, nil) - } - else if self.returnResetOctagonResponse { + } else if self.returnResetOctagonResponse { let response = GetRepairActionResponse.with { $0.repairAction = .resetOctagon } completion(response, nil) - } - else if self.returnNoActionResponse { + } else if self.returnNoActionResponse { let response = GetRepairActionResponse.with { $0.repairAction = .noAction } @@ -702,14 +713,17 @@ class FakeCuttlefishServer: CuttlefishAPIAsync { $0.repairAction = .noAction } completion(response, self.returnRepairErrorResponse) - } - else { + } else { completion(GetRepairActionResponse(), nil) } } + + func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) { + completion(GetSupportAppInfoResponse(), nil) + } } -extension FakeCuttlefishServer : CloudKitCode.Invocable { +extension FakeCuttlefishServer: CloudKitCode.Invocable { func invoke(function: String, request: RequestType, completion: @escaping (ResponseType?, Error?) -> Void) { @@ -745,8 +759,8 @@ extension FakeCuttlefishServer : CloudKitCode.Invocable { case let request as ReportHealthRequest: self.reportHealth(request, completion: completion as! (ReportHealthResponse?, Error?) -> Void) return - case let request as HealthInquiryRequest: - self.pushHealthInquiry(request, completion: completion as! (HealthInquiryResponse?, Error?) -> Void) + case let request as PushHealthInquiryRequest: + self.pushHealthInquiry(request, completion: completion as! (PushHealthInquiryResponse?, Error?) -> Void) return case let request as GetRepairActionRequest: self.getRepairAction(request, completion: completion as! (GetRepairActionResponse?, Error?) -> Void) diff --git a/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift b/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift index 5c0ee671..5d8d2c33 100644 --- a/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift +++ b/keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift @@ -159,11 +159,15 @@ class MockCuttlefishAPIAsyncClient: CuttlefishAPIAsync { print("MockCuttlefish: reportHealth called") completion(ReportHealthResponse(), nil) } - func pushHealthInquiry(_: HealthInquiryRequest, completion: @escaping (HealthInquiryResponse?, Error?) -> Void) { - completion(HealthInquiryResponse(), nil) + func pushHealthInquiry(_: PushHealthInquiryRequest, completion: @escaping (PushHealthInquiryResponse?, Error?) -> Void) { + completion(PushHealthInquiryResponse(), nil) } func getRepairAction(_: GetRepairActionRequest, completion: @escaping (GetRepairActionResponse?, Error?) -> Void) { completion(GetRepairActionResponse(), nil) } + func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) { + completion(GetSupportAppInfoResponse(), nil) + } + } diff --git a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h index b74e57ec..fc2d9223 100644 --- a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h +++ b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h @@ -7,8 +7,8 @@ #import "utilities/SecCFError.h" -#import "securityd/SecItemServer.h" -#import "securityd/spi.h" +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/spi.h" #import #import "keychain/ckks/CKKS.h" diff --git a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift index 0c6f1ef1..0516c23a 100644 --- a/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift +++ b/keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift @@ -16,6 +16,10 @@ let encryptionKey_384 = Data(base64Encoded: "BE1RuazBWmSEx0XVGhobbrdSE6fRQOrUrYE let symmetricKey_384 = Data(base64Encoded: "MfHje3Y/mWV0q+grjwZ4VxuqB7OreYHLxYkeeCiNjjY=") +let recovery_signingKey_384 = Data(base64Encoded: "BK5nrmP6oitJHtGV2Josk5cUKnG3pqxgEP8uzyPtNXgAMNHZoDKwCKFXpUzQSgbYiR4G2XZY2Q0+qSCKN7YSY2KNKE0hM9p4GvABBmAWKW/O9eFd5ugKQWisn25a/7nieIw8CQ81hBDR7R/vBpfLVtzE8ieRA8JPGqulQ5RdLcClFrD3B8BPJAZpLv4OP1CLDA==") + +let recovery_encryptionKey_384 = Data(base64Encoded: "BKkZpYHTbMi2yrWFo+ErM3HbcYJCngPuWDYoVUD7egKkmiHFvv1Bsk0j/Dcj3xTR12vj5QOpZQV3GzE5estf75BV+EZz1cjUUSi/MysfpKsqEbwYrhIEkmeyMGr7CVWQWRLR2LnoihnQajvWi1LmO0AoDl3+LzVgTJBjjDQ5ANyw0Yv1EgOgBvZsLA9UTN4oAg==") + class TrustedPeersHelperUnitTests: XCTestCase { var tmpPath: String! @@ -158,10 +162,11 @@ class TrustedPeersHelperUnitTests: XCTestCase { func establish(reload: Bool, contextID: String, + allowedMachineIDs: Set = Set(["aaa", "bbb", "ccc"]), store: NSPersistentStoreDescription) throws -> (Container, String) { var container = try Container(name: ContainerName(container: "test", context: contextID), persistentStoreDescription: store, cuttlefish: cuttlefish) - XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["aaa", "bbb", "ccc"]), "should be able to set allowed machine IDs") + XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: allowedMachineIDs, listDifference: allowedMachineIDs.count > 0), "should be able to set allowed machine IDs") let (peerID, permanentInfo, permanentInfoSig, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1") do { @@ -243,7 +248,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { persistentStoreDescription: store, cuttlefish: cuttlefish) - XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs), "Should be able to set machine IDs") + XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, listDifference: machineIDs.count > 0), "Should be able to set machine IDs") print("preparing \(containerID)") let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error) = @@ -561,7 +566,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { print("reset A") do { - let error = containerA.resetSync(test: self) + let error = containerA.resetSync(resetReason: .testGenerated, test: self) XCTAssertNil(error) } do { @@ -854,6 +859,31 @@ class TrustedPeersHelperUnitTests: XCTestCase { } } + func testRecoveryKeyTestVectors() { + let secretString = "I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret" + + let secret = secretString.data(using: .utf8) + + do { + let testv1 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeySigning, masterSecret: secret!, recoverySalt: testDSID) + XCTAssertEqual(testv1, recovery_signingKey_384, "signing keys should match") + + let testv2 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeyEncryption, masterSecret: secret!, recoverySalt: testDSID) + XCTAssertEqual(testv2, recovery_encryptionKey_384, "encryption keys should match") + + let newSecretString = "I'm f secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret" + let newSecret = newSecretString.data(using: .utf8) + + let testv4 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeySigning, masterSecret: newSecret!, recoverySalt: testDSID) + XCTAssertNotEqual(testv4, recovery_signingKey_384, "signing keys should not match") + + let testv5 = try RecoveryKeySet.generateRecoveryKey(keyType: recoveryKeyType.kOTRecoveryKeyEncryption, masterSecret: newSecret!, recoverySalt: testDSID) + XCTAssertNotEqual(testv5, recovery_encryptionKey_384, "encryption keys should not match") + } catch { + XCTFail("error testing RecoveryKey test vectors \(error)") + } + } + func testJoiningWithBottle() throws { var bottleA: BottleMO var entropy: Data @@ -916,6 +946,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) @@ -997,6 +1031,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) @@ -1073,6 +1111,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: "wrong escrow record") + XCTAssertNotNil(errorPreflight, "Should be an error preflighting bottle that doesn't exist") + XCTAssertNil(bottlePeerID, "peerID should be nil for no bottle") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: "wrong escrow record", entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1138,6 +1180,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleB.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, bPeerID, "Bottle should be for peer B") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleB.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1205,6 +1251,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "987654321", tlkShares: []) XCTAssertNotNil(error3) @@ -1270,6 +1320,10 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: Data(count: Int(OTMasterSecretLength)), bottleSalt: "123456789", tlkShares: []) XCTAssertNotNil(error3) @@ -1335,10 +1389,13 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B joins via bottle") - // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.fetchViableBottlesError.append(ckError) + self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) + + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNotNil(errorPreflight, "Should be an error preflighting a vouch with bottle with a fetch error") + XCTAssertNil(bottlePeerID, "peerID should be nil") + + self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) @@ -1465,10 +1522,9 @@ class TrustedPeersHelperUnitTests: XCTestCase { let (_, peerID2) = try establish(reload: false, contextID: "second", store: tmpStoreDescription(name: "container-peer2.db")) // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.nextFetchErrors.append(ckError) - _ = c.updateSync(test: self) + self.cuttlefish.nextFetchErrors.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) + let (_, updateError) = c.updateSync(test: self) + XCTAssertNil(updateError, "Update should have succeeded") // and c's model should only include peerID2 c.moc.performAndWait { @@ -1772,16 +1828,17 @@ class TrustedPeersHelperUnitTests: XCTestCase { do { print("B prepares to join via bottle") + let (bottlePeerID, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!) + XCTAssertNil(errorPreflight, "Should be no error preflighting a vouch with bottle") + XCTAssertEqual(bottlePeerID, aPeerID, "Bottle should be for peer A") + let (voucherData, voucherSig, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: []) XCTAssertNil(error3) XCTAssertNotNil(voucherData) XCTAssertNotNil(voucherSig) - // And the first container fetches again, which should succeed - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) - self.cuttlefish.nextFetchErrors.append(ckError) + self.cuttlefish.nextFetchErrors.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired)) // Before B joins, there should be no TLKShares for B assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee")) @@ -1798,7 +1855,6 @@ class TrustedPeersHelperUnitTests: XCTestCase { let containerA = try Container(name: ContainerName(container: "a", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish) let containerB = try Container(name: ContainerName(container: "b", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish) - let machineIDs = Set(["aaa", "bbb"]) XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs)) XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs)) @@ -1912,7 +1968,6 @@ class TrustedPeersHelperUnitTests: XCTestCase { XCTAssertNil(containerA.distrustSync(test: self, peerIDs: Set([bPeerID!])), "Should be no error distrusting peers") assertDistrusts(context: containerA, peerIDs: [bPeerID!]) - let recoveryKey = SecRKCreateRecoveryKeyString(nil) XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") @@ -2089,7 +2144,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { knownMachineMOs.forEach { if $0.machineID == "xxx" { - $0.modified = Date(timeIntervalSinceNow: -60*60*72) + $0.modified = Date(timeIntervalSinceNow: -60 * 60 * 72) } } @@ -2251,17 +2306,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { func testMachineIDListSetDisallowedOldUnknownMachineIDs() throws { let description = tmpStoreDescription(name: "container.db") - let (container, _) = try establish(reload: false, store: description) - - container.moc.performAndWait { - let knownMachineMOs = container.containerMO.machines as? Set ?? Set() - - knownMachineMOs.forEach { - container.containerMO.removeFromMachines($0) - } - - try! container.moc.save() - } + let (container, _) = try establish(reload: false, contextID: OTDefaultContext, allowedMachineIDs: Set(), store: description) // and set the machine ID list to something that doesn't include 'aaa' XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["bbb", "ccc"], listDifference: true), "should be able to set allowed machine IDs") @@ -2280,7 +2325,7 @@ class TrustedPeersHelperUnitTests: XCTestCase { XCTAssertFalse(aaaMO.allowed, "allowed should no longer be a used field") // Pretend that aaa was added 49 hours ago - aaaMO.modified = Date(timeIntervalSinceNow: -60*60*49) + aaaMO.modified = Date(timeIntervalSinceNow: -60 * 60 * 49) try! container.moc.save() } @@ -2324,7 +2369,41 @@ class TrustedPeersHelperUnitTests: XCTestCase { try self.assert(container: container, allowedMachineIDs: Set(["aaa", "bbb", "ccc"]), disallowedMachineIDs: [], unknownMachineIDs: Set([unknownMachineID]), persistentStore: description, cuttlefish: self.cuttlefish) } - func testContainerAndModelConsistency() throws{ + func testMachineIDListHandlingInDemoAccounts() throws { + // Demo accounts have no machine IDs in their lists + let description = tmpStoreDescription(name: "container.db") + let (container, peerID1) = try establish(reload: false, contextID: OTDefaultContext, allowedMachineIDs: Set(), store: description) + + // And so we just don't write down any MIDs + try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // Even when joining... + let unknownMachineID = "not-on-list" + let (c2, peerID2) = try self.joinByVoucher(sponsor: container, + containerID: "second", + machineID: unknownMachineID, + machineIDs: Set(), + store: description) + try self.assert(container: c2, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // And the first container accepts the join... + let (_, cUpdateError) = container.updateSync(test: self) + XCTAssertNil(cUpdateError, "Should be able to update first container") + assertTrusts(context: container, peerIDs: [peerID1, peerID2]) + + // And still has nothing in its list... + try self.assert(container: container, allowedMachineIDs: Set([]), disallowedMachineIDs: [], unknownMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish) + + // Even after a full list set + XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: [], listDifference: false), "should be able to set allowed machine IDs") + 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 { let preTestContainerName = ContainerName(container: "testToCreatePrepareData", context: "context") let description = tmpStoreDescription(name: "container.db") @@ -2358,19 +2437,19 @@ class TrustedPeersHelperUnitTests: XCTestCase { containerMO.egoPeerStableInfoSig = stableInfoSig containerMO.egoPeerStableInfo = stableInfo let containerEgoStableInfo = TPPeerStableInfo(data: stableInfo!, sig: stableInfoSig!) - do{ + do { let peerKeys: OctagonSelfPeerKeys = try loadEgoKeysSync(peerID: containerMO.egoPeerID!) - let info3: TPPeerStableInfo = TPPeerStableInfo(clock: containerEgoStableInfo!.clock + 2, - policyVersion:containerEgoStableInfo!.policyVersion, - policyHash:containerEgoStableInfo!.policyHash, - policySecrets:containerEgoStableInfo!.policySecrets, - deviceName:containerEgoStableInfo!.deviceName, - serialNumber:containerEgoStableInfo!.serialNumber, - osVersion:containerEgoStableInfo!.osVersion, - signing:peerKeys.signingKey, - recoverySigningPubKey:containerEgoStableInfo!.recoverySigningPublicKey, - recoveryEncryptionPubKey:containerEgoStableInfo!.recoveryEncryptionPublicKey, - error:nil) + let info3 = TPPeerStableInfo(clock: containerEgoStableInfo!.clock + 2, + policyVersion: containerEgoStableInfo!.policyVersion, + policyHash: containerEgoStableInfo!.policyHash, + policySecrets: containerEgoStableInfo!.policySecrets, + deviceName: containerEgoStableInfo!.deviceName, + serialNumber: containerEgoStableInfo!.serialNumber, + osVersion: containerEgoStableInfo!.osVersion, + signing: peerKeys.signingKey, + recoverySigningPubKey: containerEgoStableInfo!.recoverySigningPublicKey, + recoveryEncryptionPubKey: containerEgoStableInfo!.recoveryEncryptionPublicKey, + error: nil) //setting the containerMO's ego stable info to an old clock containerMO.egoPeerStableInfo = containerEgoStableInfo!.data @@ -2406,4 +2485,34 @@ class TrustedPeersHelperUnitTests: XCTestCase { //after boot the clock should be updated to the one that was saved in the model XCTAssertEqual(stableInfoAfterBoot!.clock, 3, "clock should be updated to 3") } + + func testRetryableError() throws { + XCTAssertTrue(RetryingInvocable.retryableError(error: NSError(domain: NSURLErrorDomain, code: NSURLErrorTimedOut, userInfo: nil))) + XCTAssertFalse(RetryingInvocable.retryableError(error: NSError(domain: NSURLErrorDomain, code: NSURLErrorUnknown, userInfo: nil))) + XCTAssertTrue(RetryingInvocable.retryableError(error: NSError(domain: CKErrorDomain, code: CKError.networkFailure.rawValue, userInfo: nil))) + XCTAssertFalse(RetryingInvocable.retryableError(error: NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: nil))) + + let sub0 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalServerInternalError.rawValue, userInfo: nil) + let e0 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: sub0]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e0)) + + let sub1 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalGenericError.rawValue, userInfo: nil) + let e1 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: sub1]) + XCTAssertFalse(RetryingInvocable.retryableError(error: e1)) + + let cf2 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) + let int2 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf2]) + let e2 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int2]) + XCTAssertFalse(RetryingInvocable.retryableError(error: e2)) + + let cf3 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.retryableServerFailure.rawValue, userInfo: nil) + let int3 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf3]) + let e3 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int3]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e3)) + + let cf4 = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) + let int4 = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cf4]) + let e4 = NSError(domain: CKErrorDomain, code: CKError.serverRejectedRequest.rawValue, userInfo: [NSUnderlyingErrorKey: int4]) + XCTAssertTrue(RetryingInvocable.retryableError(error: e4)) + } } diff --git a/keychain/ckks/CKKS.m b/keychain/ckks/CKKS.m index 9c1e5ea1..934ff6a2 100644 --- a/keychain/ckks/CKKS.m +++ b/keychain/ckks/CKKS.m @@ -28,7 +28,7 @@ #endif #include -#include +#include "keychain/securityd/SecItemServer.h" #include #import diff --git a/keychain/ckks/CKKSAccountStateTracker.m b/keychain/ckks/CKKSAccountStateTracker.m index 34c411e5..05900dc0 100644 --- a/keychain/ckks/CKKSAccountStateTracker.m +++ b/keychain/ckks/CKKSAccountStateTracker.m @@ -211,7 +211,11 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status) // signals when this notify is Complete, including all downcalls. dispatch_semaphore_t finishedSema = dispatch_semaphore_create(0); + WEAKIFY(self); + [self.container accountInfoWithCompletionHandler:^(CKAccountInfo* ckAccountInfo, NSError * _Nullable error) { + STRONGIFY(self); + if(error) { secerror("ckksaccount: error getting account info: %@", error); dispatch_semaphore_signal(finishedSema); diff --git a/keychain/ckks/CKKSAnalytics.h b/keychain/ckks/CKKSAnalytics.h index ae6b6b9f..dd876eaf 100644 --- a/keychain/ckks/CKKSAnalytics.h +++ b/keychain/ckks/CKKSAnalytics.h @@ -46,12 +46,14 @@ extern NSString* const OctagonAnalyticsSOSStatus; extern NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin; extern NSString* const OctagonAnalyticsLastKeystateReady; extern NSString* const OctagonAnalyticsLastCoreFollowup; -extern NSString* const OctagonAnalyticsCoreFollowupStatus; extern NSString* const OctagonAnalyticsCoreFollowupFailureCount; extern NSString* const OctagonAnalyticsCoreFollowupLastFailureTime; extern NSString* const OctagonAnalyticsPrerecordPending; extern NSString* const OctagonAnalyticsCDPStateRun; +extern NSString* const CKKSAnalyticsLastCKKSPush; +extern NSString* const CKKSAnalyticsLastOctagonPush; + extern NSString* const OctagonAnalyticsKVSProvisioned; extern NSString* const OctagonAnalyticsKVSEnabled; extern NSString* const OctagonAnalyticsKeychainSyncProvisioned; @@ -118,6 +120,7 @@ extern CKKSAnalyticsFailableEvent* const OctagonEventUpgradePreapprovedJoinAfter extern CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher; /* inner: join with bottle */ +extern CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithBottle; extern CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle; /* inner: join with recovery key */ diff --git a/keychain/ckks/CKKSAnalytics.m b/keychain/ckks/CKKSAnalytics.m index 8b37272d..ce66283d 100644 --- a/keychain/ckks/CKKSAnalytics.m +++ b/keychain/ckks/CKKSAnalytics.m @@ -55,12 +55,15 @@ NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus"; NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ"; NSString* const OctagonAnalyticsLastKeystateReady = @"OALastKSR"; NSString* const OctagonAnalyticsLastCoreFollowup = @"OALastCFU"; -NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus"; +//NSString* const OctagonAnalyticsCoreFollowupStatus = @"OACFUStatus"; NSString* const OctagonAnalyticsCoreFollowupFailureCount = @"OACFUTFailureCount"; NSString* const OctagonAnalyticsCoreFollowupLastFailureTime = @"OACFULastFailureTime"; NSString* const OctagonAnalyticsPrerecordPending = @"OAPrerecordPending"; NSString* const OctagonAnalyticsCDPStateRun = @"OACDPStateRun"; +NSString* const CKKSAnalyticsLastCKKSPush = @"lastCKKSPush"; +NSString* const CKKSAnalyticsLastOctagonPush = @"lastOctagonPush"; + NSString* const OctagonAnalyticsKVSProvisioned = @"OADCKVSProvisioned"; NSString* const OctagonAnalyticsKVSEnabled = @"OADCKVSEnabled"; NSString* const OctagonAnalyticsKeychainSyncProvisioned = @"OADCKCSProvisioned"; @@ -117,6 +120,7 @@ CKKSAnalyticsFailableEvent* const OctagonEventUpgradePrepare = (CKKSAnalyticsFai CKKSAnalyticsFailableEvent* const OctagonEventJoinWithVoucher = (CKKSAnalyticsFailableEvent*)@"OctagonEventJoinWithVoucher"; +CKKSAnalyticsFailableEvent* const OctagonEventPreflightVouchWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventPreflightVouchWithBottle"; CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithBottle = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithBottle"; CKKSAnalyticsFailableEvent* const OctagonEventVoucherWithRecoveryKey = (CKKSAnalyticsFailableEvent*)@"OctagonEventVoucherWithRecoveryKey"; diff --git a/keychain/ckks/CKKSDeviceStateEntry.h b/keychain/ckks/CKKSDeviceStateEntry.h index 16230793..f542e185 100644 --- a/keychain/ckks/CKKSDeviceStateEntry.h +++ b/keychain/ckks/CKKSDeviceStateEntry.h @@ -26,7 +26,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #include #import diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h index 082ec101..763195b2 100644 --- a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h @@ -47,6 +47,15 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; /* Clients that register to use fetches */ @interface CKKSCloudKitFetchRequest : NSObject @property bool participateInFetch; + +// If true, you will receive YES in the resync parameter to your callback. +// You may also receive YES to your callback if a resync has been triggered for you. +// It does nothing else. Use as you see fit. +// Note: you will receive exactly one callback with moreComing=0 and resync=1 for each +// resync fetch. You may then receive further callbacks with resync=0 during the same fetch, +// if other clients keep needing fetches. +@property BOOL resync; + @property (nullable) CKServerChangeToken* changeToken; @end @@ -60,8 +69,9 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; - (void)changesFetched:(NSArray*)changedRecords deletedRecordIDs:(NSArray*)deleted - oldChangeToken:(CKServerChangeToken* _Nullable)oldChangeToken - newChangeToken:(CKServerChangeToken*)changeToken; + newChangeToken:(CKServerChangeToken*)changeToken + moreComing:(BOOL)moreComing + resync:(BOOL)resync; @end // I don't understand why recordType isn't part of record ID, but deletions come in as both things @@ -80,7 +90,6 @@ extern CKKSFetchBecause* const CKKSFetchBecauseResync; // Fetching everything currently in CloudKit and comparing to local copy @property bool resync; -@property NSDictionary>* clientMap; @property (nullable) NSMutableArray* fetchedZoneIDs; @property NSSet* fetchReasons; diff --git a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m index 1304cb87..9a03e976 100644 --- a/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m +++ b/keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m @@ -39,7 +39,7 @@ #import "keychain/analytics/SecMetrics.h" #import "NSError+UsefulConstructors.h" #import "CKKSPowerCollection.h" -#include +#include "keychain/securityd/SecItemServer.h" @implementation CKKSCloudKitFetchRequest @end @@ -60,14 +60,19 @@ @property CKDatabaseOperation* fetchRecordZoneChangesOperation; @property NSMutableDictionary* allClientOptions; +@property NSMutableDictionary>* clientMap; + @property CKOperationGroup* ckoperationGroup; @property (assign) NSUInteger fetchedItems; @property bool forceResync; @property bool moreComing; -// Holds the original change token that the client believes they have synced to -@property NSMutableDictionary* originalChangeTokens; +@property size_t totalModifications; +@property size_t totalDeletions; + +// A zoneID is in this set if we're attempting to resync them +@property NSMutableSet* resyncingZones; @property CKKSResultOperation* fetchCompletedOperation; @end @@ -93,11 +98,10 @@ _container = container; _fetchRecordZoneChangesOperationClass = fetchRecordZoneChangesOperationClass; - NSMutableDictionary* clientMap = [NSMutableDictionary dictionary]; + _clientMap = [NSMutableDictionary dictionary]; for(id client in clients) { - clientMap[client.zoneID] = client; + _clientMap[client.zoneID] = client; } - _clientMap = [clientMap copy]; _ckoperationGroup = ckoperationGroup; _forceResync = forceResync; @@ -107,7 +111,11 @@ _modifications = [[NSMutableDictionary alloc] init]; _deletions = [[NSMutableDictionary alloc] init]; _changeTokens = [[NSMutableDictionary alloc] init]; - _originalChangeTokens = [[NSMutableDictionary alloc] init]; + + _resyncingZones = [NSMutableSet set]; + + _totalModifications = 0; + _totalDeletions = 0; _fetchCompletedOperation = [CKKSResultOperation named:@"record-zone-changes-completed" withBlock:^{}]; @@ -140,13 +148,11 @@ } else { options.previousServerChangeToken = clientPreference.changeToken; } - - self.originalChangeTokens[clientZoneID] = options.previousServerChangeToken; } - //if(options.previousServerChangeToken == nil) { - // nilChangeTag = true; - //} + if(clientPreference.resync || self.forceResync) { + [self.resyncingZones addObject:clientZoneID]; + } self.allClientOptions[client.zoneID] = options; } @@ -242,6 +248,8 @@ ckksnotice("ckksfetch", recordZoneID, "Record zone fetch complete: changeToken=%@ clientChangeTokenData=%@ moreComing=%@ error=%@", serverChangeToken, clientChangeTokenData, moreComing ? @"YES" : @"NO", recordZoneError); + + [self sendChangesToClient:recordZoneID moreComing:moreComing]; }; // Called with overall operation success. As I understand it, this block will be called for every operation. @@ -253,6 +261,15 @@ return; } + // Count record changes per zone + NSMutableDictionary* recordChangesPerZone = [NSMutableDictionary dictionary]; + self.totalModifications += self.modifications.count; + self.totalDeletions += self.deletions.count; + + // All of these should have been delivered by recordZoneFetchCompletionBlock; throw them away + [self.modifications removeAllObjects]; + [self.deletions removeAllObjects]; + // If we were told that there were moreChanges coming for any zone, we'd like to fetch again. // This is true if we recieve no error or a network timeout. Any other error should cause a failure. if(self.moreComing && (operationError == nil || [CKKSReachabilityTracker isNetworkFailureError:operationError])) { @@ -264,9 +281,6 @@ if(operationError) { self.error = operationError; - } else { - secnotice("ckksfetch", "Advising clients of fetched changes"); - [self sendAllChangesToClients]; } secnotice("ckksfetch", "Record zone changes fetch complete: error=%@", operationError); @@ -274,10 +288,6 @@ [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventFetchAllChanges count:self.fetchedItems]; - // Count record changes per zone - NSMutableDictionary* recordChangesPerZone = [NSMutableDictionary dictionary]; - NSNumber* totalModifications = [NSNumber numberWithUnsignedLong:self.modifications.count]; - NSNumber* totalDeletions = [NSNumber numberWithUnsignedLong:self.deletions.count]; for(CKRecordID* recordID in self.modifications) { NSNumber* last = recordChangesPerZone[recordID.zoneID]; @@ -303,8 +313,8 @@ metric[@"fetch_error_domain"] = operationError.domain; metric[@"fetch_error_code"] = [NSNumber numberWithLong:operationError.code]; - metric[@"total_modifications"] = totalModifications; - metric[@"total_deletions"] = totalDeletions; + metric[@"total_modifications"] = @(self.totalModifications); + metric[@"total_deletions"] = @(self.totalDeletions); for(CKRecordZoneID* zoneID in recordChangesPerZone) { metric[zoneID.zoneName] = recordChangesPerZone[zoneID]; } @@ -316,8 +326,8 @@ metric2[@"fetch_error"] = operationError; - metric2[@"total_modifications"] = totalModifications; - metric2[@"total_deletions"] = totalDeletions; + metric2[@"total_modifications"] = @(self.totalModifications); + metric2[@"total_deletions"] = @(self.totalDeletions); for(CKRecordZoneID* zoneID in recordChangesPerZone) { metric2[zoneID.zoneName] = recordChangesPerZone[zoneID]; } @@ -341,12 +351,11 @@ } } - // Don't need these any more; save some memory - [self.modifications removeAllObjects]; - [self.deletions removeAllObjects]; - // Trigger the fake 'we're done' operation. [self runBeforeGroupFinished: self.fetchCompletedOperation]; + + // Drop strong pointer to clients + [self.clientMap removeAllObjects]; }; [self dependOnBeforeGroupFinished:self.fetchCompletedOperation]; @@ -354,14 +363,7 @@ [self.container.privateCloudDatabase addOperation:self.fetchRecordZoneChangesOperation]; } -- (void)sendAllChangesToClients -{ - for(CKRecordZoneID* clientZoneID in self.clientMap) { - [self sendChangesToClient:clientZoneID]; - } -} - -- (void)sendChangesToClient:(CKRecordZoneID*)recordZoneID +- (void)sendChangesToClient:(CKRecordZoneID*)recordZoneID moreComing:(BOOL)moreComing { id client = self.clientMap[recordZoneID]; if(!client) { @@ -391,14 +393,22 @@ } }]; - ckksnotice("ckksfetch", recordZoneID, "Delivering fetched changes: changed=%lu deleted=%lu", - (unsigned long)zoneModifications.count, (unsigned long)zoneDeletions.count); + BOOL resync = [self.resyncingZones containsObject:recordZoneID]; + + ckksnotice("ckksfetch", recordZoneID, "Delivering fetched changes: changed=%lu deleted=%lu moreComing=%lu resync=%u", + (unsigned long)zoneModifications.count, (unsigned long)zoneDeletions.count, (unsigned long)moreComing, resync); // Tell the client about these changes! [client changesFetched:zoneModifications deletedRecordIDs:zoneDeletions - oldChangeToken:self.originalChangeTokens[recordZoneID] - newChangeToken:self.changeTokens[recordZoneID]]; + newChangeToken:self.changeTokens[recordZoneID] + moreComing:moreComing + resync:resync]; + + if(resync && !moreComing) { + ckksnotice("ckksfetch", recordZoneID, "No more changes for zone; turning off resync bit"); + [self.resyncingZones removeObject:recordZoneID]; + } } - (void)cancel { diff --git a/keychain/ckks/CKKSIncomingQueueEntry.h b/keychain/ckks/CKKSIncomingQueueEntry.h index 991e9a59..8d425b21 100644 --- a/keychain/ckks/CKKSIncomingQueueEntry.h +++ b/keychain/ckks/CKKSIncomingQueueEntry.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSMirrorEntry.h" diff --git a/keychain/ckks/CKKSIncomingQueueEntry.m b/keychain/ckks/CKKSIncomingQueueEntry.m index 0d38c781..3bb5e78d 100644 --- a/keychain/ckks/CKKSIncomingQueueEntry.m +++ b/keychain/ckks/CKKSIncomingQueueEntry.m @@ -30,8 +30,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import #import "CKKSIncomingQueueEntry.h" diff --git a/keychain/ckks/CKKSIncomingQueueOperation.m b/keychain/ckks/CKKSIncomingQueueOperation.m index 2aed9402..f53425a1 100644 --- a/keychain/ckks/CKKSIncomingQueueOperation.m +++ b/keychain/ckks/CKKSIncomingQueueOperation.m @@ -33,8 +33,8 @@ #import "keychain/ckks/CKKSCurrentItemPointer.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include diff --git a/keychain/ckks/CKKSItem.h b/keychain/ckks/CKKSItem.h index 6cd0088d..75e0f601 100644 --- a/keychain/ckks/CKKSItem.h +++ b/keychain/ckks/CKKSItem.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSRecordHolder.h" diff --git a/keychain/ckks/CKKSItem.m b/keychain/ckks/CKKSItem.m index 144b04fc..445d4898 100644 --- a/keychain/ckks/CKKSItem.m +++ b/keychain/ckks/CKKSItem.m @@ -30,8 +30,8 @@ #import "CKKSSIV.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import #import diff --git a/keychain/ckks/CKKSItemEncrypter.h b/keychain/ckks/CKKSItemEncrypter.h index aa477698..0780da11 100644 --- a/keychain/ckks/CKKSItemEncrypter.h +++ b/keychain/ckks/CKKSItemEncrypter.h @@ -23,7 +23,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" @class CKKSItem; @class CKKSMirrorEntry; diff --git a/keychain/ckks/CKKSItemEncrypter.m b/keychain/ckks/CKKSItemEncrypter.m index 6327aa9f..90810cef 100644 --- a/keychain/ckks/CKKSItemEncrypter.m +++ b/keychain/ckks/CKKSItemEncrypter.m @@ -26,7 +26,7 @@ #import #import -#include +#include "keychain/securityd/SecItemSchema.h" #import "CKKSItemEncrypter.h" #import "CKKSKeychainView.h" diff --git a/keychain/ckks/CKKSKey.m b/keychain/ckks/CKKSKey.m index 8cfa8b41..10e88f36 100644 --- a/keychain/ckks/CKKSKey.m +++ b/keychain/ckks/CKKSKey.m @@ -28,7 +28,7 @@ #import "CKKSCurrentKeyPointer.h" #import "CKKSKey.h" #import "keychain/categories/NSError+UsefulConstructors.h" -#include +#include "keychain/securityd/SecItemSchema.h" #include #include #include "OSX/sec/Security/SecItemShim.h" diff --git a/keychain/ckks/CKKSKeychainView.h b/keychain/ckks/CKKSKeychainView.h index 37e28163..ac6e0339 100644 --- a/keychain/ckks/CKKSKeychainView.h +++ b/keychain/ckks/CKKSKeychainView.h @@ -31,7 +31,7 @@ #import "keychain/ckks/CKKSReachabilityTracker.h" #import "keychain/ckks/CloudKitDependencies.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKS.h" @@ -43,6 +43,7 @@ #import "keychain/ckks/CKKSNotifier.h" #import "keychain/ckks/CKKSOutgoingQueueOperation.h" #import "keychain/ckks/CKKSPeer.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/ckks/CKKSProcessReceivedKeysOperation.h" #import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h" #import "keychain/ckks/CKKSScanLocalItemsOperation.h" @@ -69,29 +70,6 @@ NS_ASSUME_NONNULL_BEGIN @class CKKSZoneChangeFetcher; @class CKKSCurrentKeySet; -@interface CKKSPeerProviderState : NSObject -@property NSString* peerProviderID; - -// The peer provider believes trust in this state is essential. Any subsystem using -// a peer provider state should fail and pause if this is YES and there are trust errors. -@property BOOL essential; - -@property (nonatomic, readonly, nullable) CKKSSelves* currentSelfPeers; -@property (nonatomic, readonly, nullable) NSError* currentSelfPeersError; -@property (nonatomic, readonly, nullable) NSSet>* currentTrustedPeers; -@property (nonatomic, readonly, nullable) NSSet* currentTrustedPeerIDs; -@property (nonatomic, readonly, nullable) NSError* currentTrustedPeersError; - -- (instancetype)initWithPeerProviderID:(NSString*)providerID - essential:(BOOL)essential - selfPeers:(CKKSSelves* _Nullable)selfPeers - selfPeersError:(NSError* _Nullable)selfPeersError - trustedPeers:(NSSet>* _Nullable)currentTrustedPeers - trustedPeersError:(NSError* _Nullable)trustedPeersError; - -+ (CKKSPeerProviderState*)noPeersState:(id)provider; -@end - @interface CKKSKeychainView : CKKSZone @@ -118,6 +96,10 @@ NS_ASSUME_NONNULL_BEGIN // If the key hierarchy isn't coming together, it might be because we're out of sync with cloudkit. // Use this to track if we've completed a full refetch, so fix-up operations can be done. @property bool keyStateMachineRefetched; + +// Set this to request a key state refetch (tests only) +@property bool keyStateFullRefetchRequested; + @property (nullable) CKKSEgoManifest* egoManifest; @property (nullable) CKKSManifest* latestManifest; @property (nullable) CKKSResultOperation* keyStateReadyDependency; diff --git a/keychain/ckks/CKKSKeychainView.m b/keychain/ckks/CKKSKeychainView.m index 35f32e7a..1bbb06cd 100644 --- a/keychain/ckks/CKKSKeychainView.m +++ b/keychain/ckks/CKKSKeychainView.m @@ -66,6 +66,7 @@ #import "keychain/ckks/CKKSTLKShareRecord.h" #import "keychain/ckks/CKKSHealTLKSharesOperation.h" #import "keychain/ckks/CKKSLocalSynchronizeOperation.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/categories/NSError+UsefulConstructors.h" #import "keychain/ot/OTConstants.h" @@ -76,10 +77,10 @@ #include #include #include -#include -#include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" #include #include #include "keychain/SecureObjectSync/SOSAccountTransaction.h" @@ -88,61 +89,9 @@ #include #if OCTAGON -@implementation CKKSPeerProviderState -- (instancetype)initWithPeerProviderID:(NSString*)providerID - essential:(BOOL)essential - selfPeers:(CKKSSelves* _Nullable)selfPeers - selfPeersError:(NSError* _Nullable)selfPeersError - trustedPeers:(NSSet>* _Nullable)currentTrustedPeers - trustedPeersError:(NSError* _Nullable)trustedPeersError -{ - if((self = [super init])) { - _peerProviderID = providerID; - _essential = essential; - _currentSelfPeers = selfPeers; - _currentSelfPeersError = selfPeersError; - _currentTrustedPeers = currentTrustedPeers; - _currentTrustedPeersError = trustedPeersError; - - if(_currentTrustedPeers) { - NSMutableSet* trustedPeerIDs = [NSMutableSet set]; - for(id peer in _currentTrustedPeers) { - [trustedPeerIDs addObject:peer.peerID]; - } - _currentTrustedPeerIDs = trustedPeerIDs; - } - } - return self; -} - -- (NSString*)description -{ - return [NSString stringWithFormat:@"", - self.peerProviderID, - self.currentSelfPeers, - self.currentSelfPeersError ?: @"", - self.currentTrustedPeers, - self.currentTrustedPeersError ?: @""]; -} - -+ (CKKSPeerProviderState*)noPeersState:(id)provider -{ - return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID - essential:provider.essential - selfPeers:nil - selfPeersError:[NSError errorWithDomain:CKKSErrorDomain - code:CKKSNoPeersAvailable - description:@"No current self peer available"] - trustedPeers:nil - trustedPeersError:[NSError errorWithDomain:CKKSErrorDomain - code:CKKSNoPeersAvailable - description:@"No current trusted peers available"]]; -} -@end @interface CKKSKeychainView() @property bool keyStateFetchRequested; -@property bool keyStateFullRefetchRequested; @property bool keyStateProcessRequested; @property bool trustedPeersSetChanged; @@ -171,6 +120,9 @@ // An extra queue for semaphore-waiting-based NSOperations @property NSOperationQueue* waitingQueue; +// Scratch space for resyncs +@property (nullable) NSMutableSet* resyncRecordsSeen; + // Make these readwrite @property NSArray>* currentPeerProviders; @property NSArray* currentTrustStates; @@ -222,6 +174,8 @@ _zoneChangeFetcher = fetcher; [fetcher registerClient:self]; + _resyncRecordsSeen = nil; + _notifierClass = cloudKitClassDependencies.notifierClass; _notifyViewChangedScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat: @"%@-notify-scheduler", self.zoneName] initialDelay:250*NSEC_PER_MSEC @@ -254,7 +208,7 @@ [center postNotificationName:@"com.apple.security.view-become-ready" object:nil - userInfo:@{ @"view" : self.zoneName } + userInfo:@{ @"view" : self.zoneName ?: @"unknown" } options:0]; }]; @@ -500,6 +454,7 @@ } // If it's been more than 24 hours since the last fetch, fetch and process everything. + // Or, if we think we were interrupted in the middle of fetching, fetch some more. // Otherwise, just kick off the local queue processing. NSDate* now = [NSDate date]; @@ -507,7 +462,9 @@ [offset setHour:-24]; NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0]; - if(ckse.lastFetchTime == nil || [ckse.lastFetchTime compare: deadline] == NSOrderedAscending) { + if(ckse.lastFetchTime == nil || + [ckse.lastFetchTime compare: deadline] == NSOrderedAscending || + ckse.moreRecordsInCloudKit) { initialProcess = [self fetchAndProcessCKChanges:CKKSFetchBecauseSecuritydRestart after:self.lastFixupOperation]; // Also, kick off a scan local items: it'll find any out-of-sync issues in the local keychain @@ -1026,28 +983,20 @@ CKKSZoneKeyState* nextState = nil; NSError* nextError = nil; - // Many of our decisions below will be based on what keys exist. Help them out. - CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; - NSError* localerror = nil; - NSArray* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror]; - NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; - - // We also are checking for OutgoingQueueEntries in the reencrypt state; this is a sign that our key hierarchy is out of date. - NSInteger outdatedOQEs = [CKKSOutgoingQueueEntry countByState:SecCKKSStateReencrypt zone:self.zoneID error:&localerror]; + // Any state that wants should fill this in; it'll be used at the end of this function as well + CKKSCurrentKeySet* keyset = nil; - SecADSetValueForScalarKey((__bridge CFStringRef) SecCKKSAggdViewKeyCount, [localKeys count]); +#if !defined(NDEBUG) + { + NSError* localerror = nil; + NSError* allKeysError = nil; + NSArray* allKeys = [CKKSKey allKeys:self.zoneID error:&allKeysError]; - if(localerror) { - ckkserror("ckkskey", self, "couldn't fetch keys and OQEs from local database, entering error state: %@", localerror); - self.keyHierarchyState = SecCKKSZoneKeyStateError; - self.keyHierarchyError = localerror; - [self _onqueueHandleKeyStateNonTransientDependency:nil]; - return; + if(localerror) { + ckkserror("ckkskey", self, "couldn't fetch all keys from local database, entering error state: %@", allKeysError); + } + ckksdebug("ckkskey", self, "All keys: %@", allKeys); } - -#if !defined(NDEBUG) - NSArray* allKeys = [CKKSKey allKeys:self.zoneID error:&localerror]; - ckksdebug("ckkskey", self, "All keys: %@", allKeys); #endif NSError* hierarchyError = nil; @@ -1122,6 +1071,17 @@ } } else if([state isEqualToString: SecCKKSZoneKeyStateReady]) { + NSError* localerror = nil; + NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; + + if(remoteKeys == nil || localerror) { + ckkserror("ckkskey", self, "couldn't fetch keys from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(self.keyStateProcessRequested || [remoteKeys count] > 0) { // We've either received some remote keys from the last fetch, or someone has requested a reprocess. ckksnotice("ckkskey", self, "Kicking off a key reprocess based on request:%d and remote key count %lu", self.keyStateProcessRequested, (unsigned long)[remoteKeys count]); @@ -1149,6 +1109,7 @@ if(!self.keyStateMachineOperation && !nextState) { // We think we're ready. Double check. + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; CKKSZoneKeyState* checkedstate = [self _onqueueEnsureKeyHierarchyHealth:keyset error:&hierarchyError]; if(![checkedstate isEqualToString:SecCKKSZoneKeyStateReady] || hierarchyError) { // Things is bad. Kick off a heal to fix things up. @@ -1181,6 +1142,7 @@ nextState = SecCKKSZoneKeyStateWaitForFixupOperation; } else { // Check if we have an existing key hierarchy in keyset + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; if(keyset.error && !([keyset.error.domain isEqual: @"securityd"] && keyset.error.code == errSecItemNotFound)) { ckkserror("ckkskey", self, "Error examining existing key hierarchy: %@", error); } @@ -1209,7 +1171,9 @@ } else if([state isEqualToString: SecCKKSZoneKeyStateNeedFullRefetch]) { ckksnotice("ckkskey", self, "Starting a key hierarchy full refetch"); - [self _onqueueKeyHierarchyRefetch]; + [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithObjects:CKKSFetchBecauseKeyHierarchy, CKKSFetchBecauseResync, nil]]; + self.keyStateMachineRefetched = true; + self.keyStateFullRefetchRequested = false; } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForFixupOperation]) { // We should enter 'initialized' when the fixup operation completes @@ -1227,6 +1191,21 @@ } else if([state isEqualToString: SecCKKSZoneKeyStateFetchComplete]) { // We've just completed a fetch of everything. Are there any remote keys? + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + + NSError* localerror = nil; + + NSArray* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror]; + NSArray* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror]; + + if(localKeys == nil || remoteKeys == nil || localerror) { + ckkserror("ckkskey", self, "couldn't fetch keys from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(remoteKeys.count > 0u) { // Process the keys we received. self.keyStateMachineOperation = [[CKKSProcessReceivedKeysStateMachineOperation alloc] initWithCKKSKeychainView: self]; @@ -1274,6 +1253,7 @@ if(self.keyStateProcessRequested) { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; if(keyset.currentTLKPointer.currentKeyUUID) { ckksnotice("ckkskey", self, "Received a nudge that our TLK records might be here (and there's some current TLK pointer)"); nextState = SecCKKSZoneKeyStateProcess; @@ -1306,6 +1286,8 @@ self.trustedPeersSetChanged = false; } else { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + // Should we nuke this zone? if(self.trustStatus == CKKSAccountStatusAvailable) { if([self _onqueueOtherDevicesReportHavingTLKs:keyset]) { @@ -1369,6 +1351,8 @@ } else { ckkserror("ckks", self, "asked to advance state machine to unknown state: %@", state); self.keyHierarchyState = state; + + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; [self _onqueueHandleKeyStateNonTransientDependency:keyset]; return; } @@ -1387,6 +1371,17 @@ } // If there are any OQEs waiting to be encrypted, launch an op to fix them + NSError* localerror = nil; + NSInteger outdatedOQEs = [CKKSOutgoingQueueEntry countByState:SecCKKSStateReencrypt zone:self.zoneID error:&localerror]; + + if(localerror) { + ckkserror("ckkskey", self, "couldn't fetch OQEs from local database, entering error state: %@", localerror); + self.keyHierarchyState = SecCKKSZoneKeyStateError; + self.keyHierarchyError = localerror; + [self _onqueueHandleKeyStateNonTransientDependency:nil]; + return; + } + if(outdatedOQEs > 0) { ckksnotice("ckksreencrypt", self, "Reencrypting outgoing items as the key hierarchy is ready"); CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:self.keyHierarchyOperationGroup]; @@ -1433,6 +1428,11 @@ } } + // If the keystate is non-transient, ensure we've loaded the keyset, and provide it to any waiters + // If it is transient, just call the handler anyway: it needs to set up the dependency + if(!CKKSKeyStateTransient(self.keyHierarchyState) && keyset == nil) { + keyset = [CKKSCurrentKeySet loadForZone:self.zoneID]; + } [self _onqueueHandleKeyStateNonTransientDependency:keyset]; } @@ -1992,31 +1992,11 @@ } - (void)_onqueueKeyHierarchyFetch { - dispatch_assert_queue(self.queue); - - WEAKIFY(self); - self.keyStateMachineOperation = [NSBlockOperation blockOperationWithBlock: ^{ - STRONGIFY(self); - if(!self) { - ckkserror("ckks", self, "received callback for released object"); - return; - } - [self.launch addEvent:@"fetch-complete"]; - - [self dispatchSyncWithAccountKeys: ^bool{ - [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; - return true; - }]; - }]; - self.keyStateMachineOperation.name = @"waiting-for-fetch"; - - NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetch: CKKSFetchBecauseKeyHierarchy]; - [self.keyStateMachineOperation addDependency: fetchOp]; - - self.keyStateFetchRequested = false; + [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithArray:@[CKKSFetchBecauseKeyHierarchy]]]; } -- (void)_onqueueKeyHierarchyRefetch { +- (void)_onqueueKeyHierarchyFetchForReasons:(NSSet*)reasons +{ dispatch_assert_queue(self.queue); WEAKIFY(self); @@ -2026,19 +2006,18 @@ ckkserror("ckks", self, "received callback for released object"); return; } + [self.launch addEvent:@"fetch-complete"]; [self dispatchSyncWithAccountKeys: ^bool{ [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil]; return true; }]; }]; - self.keyStateMachineOperation.name = @"waiting-for-refetch"; + self.keyStateMachineOperation.name = @"waiting-for-fetch"; - NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:[NSSet setWithObjects:CKKSFetchBecauseKeyHierarchy, CKKSFetchBecauseResync, nil]]; + NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:reasons]; [self.keyStateMachineOperation addDependency: fetchOp]; - self.keyStateMachineRefetched = true; - self.keyStateFullRefetchRequested = false; self.keyStateFetchRequested = false; } @@ -3649,48 +3628,31 @@ override:(bool)overridePeerProviders block:(bool (^)(void))block { - [SOSAccount performOnQuietAccountQueue: ^{ - NSArray>* actualPeerProviders = overridePeerProviders ? peerProviders : self.currentPeerProviders; - NSMutableArray* trustStates = [NSMutableArray array]; + NSArray>* actualPeerProviders = overridePeerProviders ? peerProviders : self.currentPeerProviders; + NSMutableArray* trustStates = [NSMutableArray array]; - for(id provider in actualPeerProviders) { - ckksnotice("ckks", self, "Fetching account keys for provider %@", provider); - - NSError* selfPeersError = nil; - CKKSSelves* currentSelfPeers = [provider fetchSelfPeers:&selfPeersError]; - - NSError* trustedPeersError = nil; - NSSet>* currentTrustedPeers = [provider fetchTrustedPeers:&trustedPeersError]; + for(id provider in actualPeerProviders) { + ckksnotice("ckks", self, "Fetching account keys for provider %@", provider); + [trustStates addObject:provider.currentState]; + } - [trustStates addObject:[[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID - essential:provider.essential - selfPeers:currentSelfPeers - selfPeersError:selfPeersError - trustedPeers:currentTrustedPeers - trustedPeersError:trustedPeersError]]; + [self dispatchSync:^bool{ + if(overridePeerProviders) { + self.currentPeerProviders = peerProviders; } + self.currentTrustStates = trustStates; - [self dispatchSync:^bool{ - if(overridePeerProviders) { - self.currentPeerProviders = peerProviders; - } - self.currentTrustStates = trustStates; - - __block bool result = false; - [SOSAccount performWhileHoldingAccountQueue:^{ // so any calls through SOS account will know they can perform their work without dispatching to the account queue, which we already hold - result = block(); - }]; + bool result = block(); - // Forget the peers; they might have class A key material - NSMutableArray* noTrustStates = [NSMutableArray array]; - for(id provider in peerProviders) { - (void)provider; - [noTrustStates addObject:[CKKSPeerProviderState noPeersState:provider]]; - } - self.currentTrustStates = noTrustStates; + // Forget the peers; they might have class A key material + NSMutableArray* noTrustStates = [NSMutableArray array]; + for(id provider in peerProviders) { + (void)provider; + [noTrustStates addObject:[CKKSPeerProviderState noPeersState:provider]]; + } + self.currentTrustStates = noTrustStates; - return result; - }]; + return result; }]; } @@ -3868,6 +3830,7 @@ // We want to return a nil change tag (to force a resync) ckksnotice("ckksfetch", self, "Beginning refetch"); request.changeToken = nil; + request.resync = true; } else { CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName]; if(!ckse) { @@ -3888,16 +3851,13 @@ - (void)changesFetched:(NSArray*)changedRecords deletedRecordIDs:(NSArray*)deletedRecords - oldChangeToken:(CKServerChangeToken*)oldChangeToken newChangeToken:(CKServerChangeToken*)newChangeToken + moreComing:(BOOL)moreComing + resync:(BOOL)resync { [self.launch addEvent:@"changes-fetched"]; [self dispatchSyncWithAccountKeys:^bool{ - // This is a resync if we already have a change token, but this fetch didn't have one - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - bool resync = ckse.changeToken && (oldChangeToken == nil); - for (CKRecord* record in changedRecords) { [self _onqueueCKRecordChanged:record resync:resync]; } @@ -3908,51 +3868,67 @@ NSError* error = nil; if(resync) { - // Scan through all CKMirrorEntries and determine if any exist that CloudKit didn't tell us about - ckksnotice("ckksresync", self, "Comparing local UUIDs against the CloudKit list"); - NSMutableArray* uuids = [[CKKSMirrorEntry allUUIDs:self.zoneID error:&error] mutableCopy]; - - for(NSString* uuid in uuids) { - CKRecord* record = nil; - CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:uuid zoneID:self.zoneID]; - for(CKRecord* r in changedRecords) { - if([r.recordID isEqual:recordID]) { - record = r; - break; - } - } + // If we're performing a resync, we need to keep track of everything that's actively in + // CloudKit during the fetch, (so that we can find anything that's on-disk and not in CloudKit). + // Please note that if, during a resync, the fetch errors, we won't be notified. If a record is in + // the first refetch but not the second, it'll be added to our set, and the second resync will not + // delete the record (which is a consistency violation, but only with actively changing records). + // A third resync should correctly delete that record. + + if(self.resyncRecordsSeen == nil) { + self.resyncRecordsSeen = [NSMutableSet set]; + } + for(CKRecord* r in changedRecords) { + [self.resyncRecordsSeen addObject:r.recordID.recordName]; + } - if(record) { - ckksnotice("ckksresync", self, "UUID %@ is still in CloudKit; carry on.", uuid); - } else { - CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:self.zoneID error:&error]; - if(error != nil) { - ckkserror("ckksresync", self, "Couldn't read an item from the database, but it used to be there: %@ %@", uuid, error); - continue; - } - if(!ckme) { - ckkserror("ckksresync", self, "Couldn't read ckme(%@) from database; continuing", uuid); - continue; - } + // Is there More Coming? If not, self.resyncRecordsSeen contains everything in CloudKit. Inspect for anything extra! + if(moreComing) { + ckksnotice("ckksresync", self, "In a resync, but there's More Coming. Waiting to scan for extra items."); - ckkserror("ckksresync", self, "BUG: Local item %@ not found in CloudKit, deleting", uuid); - [self _onqueueCKRecordDeleted:ckme.item.storedCKRecord.recordID recordType:ckme.item.storedCKRecord.recordType resync:resync]; + } else { + // Scan through all CKMirrorEntries and determine if any exist that CloudKit didn't tell us about + ckksnotice("ckksresync", self, "Comparing local UUIDs against the CloudKit list"); + NSMutableArray* uuids = [[CKKSMirrorEntry allUUIDs:self.zoneID error:&error] mutableCopy]; + + for(NSString* uuid in uuids) { + if([self.resyncRecordsSeen containsObject:uuid]) { + ckksnotice("ckksresync", self, "UUID %@ is still in CloudKit; carry on.", uuid); + } else { + CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:self.zoneID error:&error]; + if(error != nil) { + ckkserror("ckksresync", self, "Couldn't read an item from the database, but it used to be there: %@ %@", uuid, error); + continue; + } + if(!ckme) { + ckkserror("ckksresync", self, "Couldn't read ckme(%@) from database; continuing", uuid); + continue; + } + + ckkserror("ckksresync", self, "BUG: Local item %@ not found in CloudKit, deleting", uuid); + [self _onqueueCKRecordDeleted:ckme.item.storedCKRecord.recordID recordType:ckme.item.storedCKRecord.recordType resync:resync]; + } } + + // Now that we've inspected resyncRecordsSeen, reset it for the next time through + self.resyncRecordsSeen = nil; } } - error = nil; - CKKSZoneStateEntry* state = [CKKSZoneStateEntry state:self.zoneName]; state.lastFetchTime = [NSDate date]; // The last fetch happened right now! state.changeToken = newChangeToken; + state.moreRecordsInCloudKit = moreComing; [state saveToDatabase:&error]; if(error) { ckkserror("ckksfetch", self, "Couldn't save new server change token: %@", error); } - // Might as well kick off a IQO! - [self processIncomingQueue:false]; + if(!moreComing) { + // Might as well kick off a IQO! + [self processIncomingQueue:false]; + ckksnotice("ckksfetch", self, "Beginning incoming processing for %@", self.zoneID); + } ckksnotice("ckksfetch", self, "Finished processing changes for %@", self.zoneID); diff --git a/keychain/ckks/CKKSManifest.m b/keychain/ckks/CKKSManifest.m index 38ab0eb5..0d7f5562 100644 --- a/keychain/ckks/CKKSManifest.m +++ b/keychain/ckks/CKKSManifest.m @@ -29,8 +29,8 @@ #import "CKKSItem.h" #import "CKKSCurrentItemPointer.h" #import "utilities/der_plist.h" -#import -#import +#import "keychain/securityd/SOSCloudCircleServer.h" +#import "keychain/securityd/SecItemServer.h" #import #import #import diff --git a/keychain/ckks/CKKSMirrorEntry.h b/keychain/ckks/CKKSMirrorEntry.h index dcaf1fbe..17839f25 100644 --- a/keychain/ckks/CKKSMirrorEntry.h +++ b/keychain/ckks/CKKSMirrorEntry.h @@ -23,7 +23,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSSQLDatabaseObject.h" diff --git a/keychain/ckks/CKKSMirrorEntry.m b/keychain/ckks/CKKSMirrorEntry.m index e77c3043..59900f08 100644 --- a/keychain/ckks/CKKSMirrorEntry.m +++ b/keychain/ckks/CKKSMirrorEntry.m @@ -30,8 +30,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import diff --git a/keychain/ckks/CKKSNearFutureScheduler.h b/keychain/ckks/CKKSNearFutureScheduler.h index 44c3e9c3..e84f7f59 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.h +++ b/keychain/ckks/CKKSNearFutureScheduler.h @@ -62,6 +62,14 @@ NS_ASSUME_NONNULL_BEGIN dependencyDescriptionCode:(NSInteger)code block:(void (^_Nonnull)(void))futureBlock; +- (instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + expontialBackoff:(double)backoff + maximumDelay:(dispatch_time_t)maximumDelay + keepProcessAlive:(bool)keepProcessAlive + dependencyDescriptionCode:(NSInteger)code + block:(void (^_Nonnull)(void))futureBlock; + - (void)trigger; - (void)cancel; diff --git a/keychain/ckks/CKKSNearFutureScheduler.m b/keychain/ckks/CKKSNearFutureScheduler.m index 2b3fb6b0..815b2197 100644 --- a/keychain/ckks/CKKSNearFutureScheduler.m +++ b/keychain/ckks/CKKSNearFutureScheduler.m @@ -33,7 +33,11 @@ @interface CKKSNearFutureScheduler () @property NSString* name; @property dispatch_time_t initialDelay; -@property dispatch_time_t continuingDelay; + +@property dispatch_time_t currentDelay; +@property dispatch_time_t maximumDelay; + +@property double backoff; @property NSInteger operationDependencyDescriptionCode; @property CKKSResultOperation* operationDependency; @@ -72,13 +76,36 @@ keepProcessAlive:(bool)keepProcessAlive dependencyDescriptionCode:(NSInteger)code block:(void (^)(void))futureBlock +{ + // If the continuing delay is below the initial delay, use an exponential backoff of 1 + // We'll clamp the timer delay to continuing delay at use time. + return [self initWithName:name + initialDelay:initialDelay + expontialBackoff:MAX(initialDelay > 0 ? (continuingDelay / initialDelay) : 1, 1) + maximumDelay:continuingDelay + keepProcessAlive:keepProcessAlive + dependencyDescriptionCode:code + block:futureBlock]; +} + +- (instancetype)initWithName:(NSString*)name + initialDelay:(dispatch_time_t)initialDelay + expontialBackoff:(double)backoff + maximumDelay:(dispatch_time_t)maximumDelay + keepProcessAlive:(bool)keepProcessAlive +dependencyDescriptionCode:(NSInteger)code + block:(void (^_Nonnull)(void))futureBlock { if((self = [super init])) { _name = name; _queue = dispatch_queue_create([[NSString stringWithFormat:@"near-future-scheduler-%@",name] UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL); _initialDelay = initialDelay; - _continuingDelay = continuingDelay; + + _currentDelay = initialDelay; + _maximumDelay = maximumDelay; + _backoff = backoff; + _futureBlock = futureBlock; _liveRequest = false; @@ -98,7 +125,9 @@ { dispatch_sync(self.queue, ^{ self.initialDelay = initialDelay; - self.continuingDelay = continuingDelay; + self.currentDelay = self.initialDelay; + self.backoff = initialDelay > 0 ? ((double)continuingDelay) / initialDelay : 1; + self.maximumDelay = continuingDelay; }); } @@ -159,13 +188,26 @@ self.liveRequestReceived = [[CKKSCondition alloc] init]; self.transaction = nil; + // No current delay means that exponential backoff means nothing. Head straight for slowtown. + if(self.currentDelay == 0) { + self.currentDelay = self.maximumDelay; + } else { + // Modify the delay by the exponential backoff, unless that exceeds the maximum delay + self.currentDelay = MIN(self.currentDelay * self.backoff, self.maximumDelay); + } + dispatch_source_set_timer(self.timer, + dispatch_walltime(NULL, self.currentDelay), + self.currentDelay, + 50 * NSEC_PER_MSEC); + [self.operationQueue addOperation: dependency]; - self.predictedNextFireTime = [NSDate dateWithTimeIntervalSinceNow: (NSTimeInterval) ((double) self.continuingDelay) / (double) NSEC_PER_SEC]; + self.predictedNextFireTime = [NSDate dateWithTimeIntervalSinceNow: (NSTimeInterval) ((double) self.currentDelay) / (double) NSEC_PER_SEC]; } else { // The timer has fired with no requests to call the block. Cancel it. dispatch_source_cancel(self.timer); self.predictedNextFireTime = nil; + self.currentDelay = self.initialDelay; } } @@ -226,7 +268,7 @@ [self _onqueueTimerTick]; }); - dispatch_time_t actualDelay = self.initialDelay; + dispatch_time_t actualDelay = self.currentDelay; if(requestedDelay != DISPATCH_TIME_NOW) { actualDelay = MAX(actualDelay, requestedDelay); } @@ -234,9 +276,11 @@ actualDelay = MIN(actualDelay, maximumDelay); } + // Note: we pass initialDelay in as the timerInterval here. [-_onqueueTimerTick] is responsible for + // modifying the delay to be correct for the next time period. dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, actualDelay), - self.continuingDelay, + self.currentDelay, 50 * NSEC_PER_MSEC); dispatch_resume(self.timer); diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.h b/keychain/ckks/CKKSOutgoingQueueEntry.h index 05e6a00c..dd7b00d4 100644 --- a/keychain/ckks/CKKSOutgoingQueueEntry.h +++ b/keychain/ckks/CKKSOutgoingQueueEntry.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSItem.h" #import "CKKSMirrorEntry.h" diff --git a/keychain/ckks/CKKSOutgoingQueueEntry.m b/keychain/ckks/CKKSOutgoingQueueEntry.m index 7ebfd83d..4097edd9 100644 --- a/keychain/ckks/CKKSOutgoingQueueEntry.m +++ b/keychain/ckks/CKKSOutgoingQueueEntry.m @@ -30,8 +30,8 @@ #include #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON diff --git a/keychain/ckks/CKKSOutgoingQueueOperation.m b/keychain/ckks/CKKSOutgoingQueueOperation.m index 3cd1e853..c1d3810d 100644 --- a/keychain/ckks/CKKSOutgoingQueueOperation.m +++ b/keychain/ckks/CKKSOutgoingQueueOperation.m @@ -37,8 +37,8 @@ #import "CKKSAnalytics.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include #import "CKKSPowerCollection.h" diff --git a/keychain/ckks/CKKSPeer.h b/keychain/ckks/CKKSPeer.h index 1270faa5..2d05fc3f 100644 --- a/keychain/ckks/CKKSPeer.h +++ b/keychain/ckks/CKKSPeer.h @@ -57,29 +57,6 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithCurrent:(id)selfPeer allSelves:(NSSet>* _Nullable)allSelves; @end -// ==== Peer handler protocols ==== - -@protocol CKKSPeerUpdateListener; - -@protocol CKKSPeerProvider -@property (readonly) NSString* providerID; -@property BOOL essential; - -- (CKKSSelves* _Nullable)fetchSelfPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; -- (NSSet>* _Nullable)fetchTrustedPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; -// Trusted peers should include self peers - -- (void)registerForPeerChangeUpdates:(id)listener; -- (void)sendSelfPeerChangedUpdate; -- (void)sendTrustedPeerSetChangedUpdate; -@end - -// A CKKSPeerUpdateListener wants to be notified when a CKKSPeerProvider has new information -@protocol CKKSPeerUpdateListener -- (void)selfPeerChanged:(id _Nullable)provider; -- (void)trustedPeerSetChanged:(id _Nullable)provider; -@end - extern NSString* const CKKSSOSPeerPrefix; @interface CKKSActualPeer : NSObject diff --git a/keychain/ckks/CKKSPeerProvider.h b/keychain/ckks/CKKSPeerProvider.h new file mode 100644 index 00000000..6811e63c --- /dev/null +++ b/keychain/ckks/CKKSPeerProvider.h @@ -0,0 +1,69 @@ +#if OCTAGON + +#import +#import "keychain/ckks/CKKSPeer.h" + +NS_ASSUME_NONNULL_BEGIN + +@protocol CKKSPeerUpdateListener; +@class CKKSPeerProviderState; + +#pragma mark - CKKSPeerProvider protocol +@protocol CKKSPeerProvider +@property (readonly) NSString* providerID; +@property BOOL essential; + +- (CKKSSelves* _Nullable)fetchSelfPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; +- (NSSet>* _Nullable)fetchTrustedPeers:(NSError* _Nullable __autoreleasing* _Nullable)error; +// Trusted peers should include self peers + +- (void)registerForPeerChangeUpdates:(id)listener; +- (void)sendSelfPeerChangedUpdate; +- (void)sendTrustedPeerSetChangedUpdate; + +- (CKKSPeerProviderState*)currentState; +@end + +#pragma mark - CKKSPeerUpdateListener protocol +// A CKKSPeerUpdateListener wants to be notified when a CKKSPeerProvider has new information +@protocol CKKSPeerUpdateListener +- (void)selfPeerChanged:(id _Nullable)provider; +- (void)trustedPeerSetChanged:(id _Nullable)provider; +@end + + +#pragma mark - CKKSPeerProviderState + +@interface CKKSPeerProviderState : NSObject +@property NSString* peerProviderID; + +// The peer provider believes trust in this state is essential. Any subsystem using +// a peer provider state should fail and pause if this is YES and there are trust errors. +@property BOOL essential; + +@property (nonatomic, readonly, nullable) CKKSSelves* currentSelfPeers; +@property (nonatomic, readonly, nullable) NSError* currentSelfPeersError; +@property (nonatomic, readonly, nullable) NSSet>* currentTrustedPeers; +@property (nonatomic, readonly, nullable) NSSet* currentTrustedPeerIDs; +@property (nonatomic, readonly, nullable) NSError* currentTrustedPeersError; + +- (instancetype)initWithPeerProviderID:(NSString*)providerID + essential:(BOOL)essential + selfPeers:(CKKSSelves* _Nullable)selfPeers + selfPeersError:(NSError* _Nullable)selfPeersError + trustedPeers:(NSSet>* _Nullable)currentTrustedPeers + trustedPeersError:(NSError* _Nullable)trustedPeersError; + ++ (CKKSPeerProviderState*)noPeersState:(id)provider; + +// Intended for use in PeerProviders. Thread-safety is up to the PeerProvider. ++ (CKKSPeerProviderState*)createFromProvider:(id)provider; +@end + + + + +NS_ASSUME_NONNULL_END + + +#endif diff --git a/keychain/ckks/CKKSPeerProvider.m b/keychain/ckks/CKKSPeerProvider.m new file mode 100644 index 00000000..f773204d --- /dev/null +++ b/keychain/ckks/CKKSPeerProvider.m @@ -0,0 +1,76 @@ +#if OCTAGON +#import "keychain/ckks/CKKS.h" +#import "keychain/ckks/CKKSPeerProvider.h" +#import "keychain/categories/NSError+UsefulConstructors.h" + +@implementation CKKSPeerProviderState +- (instancetype)initWithPeerProviderID:(NSString*)providerID + essential:(BOOL)essential + selfPeers:(CKKSSelves* _Nullable)selfPeers + selfPeersError:(NSError* _Nullable)selfPeersError + trustedPeers:(NSSet>* _Nullable)currentTrustedPeers + trustedPeersError:(NSError* _Nullable)trustedPeersError +{ + if((self = [super init])) { + _peerProviderID = providerID; + _essential = essential; + _currentSelfPeers = selfPeers; + _currentSelfPeersError = selfPeersError; + _currentTrustedPeers = currentTrustedPeers; + _currentTrustedPeersError = trustedPeersError; + + if(_currentTrustedPeers) { + NSMutableSet* trustedPeerIDs = [NSMutableSet set]; + for(id peer in _currentTrustedPeers) { + [trustedPeerIDs addObject:peer.peerID]; + } + _currentTrustedPeerIDs = trustedPeerIDs; + } + } + return self; +} + +- (NSString*)description +{ + return [NSString stringWithFormat:@"", + self.peerProviderID, + self.currentSelfPeers, + self.currentSelfPeersError ?: @"", + self.currentTrustedPeers, + self.currentTrustedPeersError ?: @""]; +} + ++ (CKKSPeerProviderState*)noPeersState:(id)provider +{ + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID + essential:provider.essential + selfPeers:nil + selfPeersError:[NSError errorWithDomain:CKKSErrorDomain + code:CKKSNoPeersAvailable + description:@"No current self peer available"] + trustedPeers:nil + trustedPeersError:[NSError errorWithDomain:CKKSErrorDomain + code:CKKSNoPeersAvailable + description:@"No current trusted peers available"]]; +} + + ++ (CKKSPeerProviderState*)createFromProvider:(id)provider +{ + NSError* selfPeersError = nil; + CKKSSelves* currentSelfPeers = [provider fetchSelfPeers:&selfPeersError]; + + NSError* trustedPeersError = nil; + NSSet>* currentTrustedPeers = [provider fetchTrustedPeers:&trustedPeersError]; + + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:provider.providerID + essential:provider.essential + selfPeers:currentSelfPeers + selfPeersError:selfPeersError + trustedPeers:currentTrustedPeers + trustedPeersError:trustedPeersError]; +} +@end + +#endif + diff --git a/keychain/ckks/CKKSRecordHolder.h b/keychain/ckks/CKKSRecordHolder.h index 5c52de66..72d0eee3 100644 --- a/keychain/ckks/CKKSRecordHolder.h +++ b/keychain/ckks/CKKSRecordHolder.h @@ -24,7 +24,7 @@ #if OCTAGON #import -#include +#include "keychain/securityd/SecDbItem.h" #include #import "keychain/ckks/CKKSSQLDatabaseObject.h" diff --git a/keychain/ckks/CKKSRecordHolder.m b/keychain/ckks/CKKSRecordHolder.m index 6d424fa6..bb9db913 100644 --- a/keychain/ckks/CKKSRecordHolder.m +++ b/keychain/ckks/CKKSRecordHolder.m @@ -31,8 +31,8 @@ #import "CKKSSIV.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #import diff --git a/keychain/ckks/CKKSSQLDatabaseObject.h b/keychain/ckks/CKKSSQLDatabaseObject.h index 976404b5..85f6ad5c 100644 --- a/keychain/ckks/CKKSSQLDatabaseObject.h +++ b/keychain/ckks/CKKSSQLDatabaseObject.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #define CKKSNilToNSNull(obj) \ diff --git a/keychain/ckks/CKKSSQLDatabaseObject.m b/keychain/ckks/CKKSSQLDatabaseObject.m index 6313ac65..356424cc 100644 --- a/keychain/ckks/CKKSSQLDatabaseObject.m +++ b/keychain/ckks/CKKSSQLDatabaseObject.m @@ -23,7 +23,7 @@ #import #import "CKKSSQLDatabaseObject.h" -#include +#include "keychain/securityd/SecItemServer.h" #import "keychain/ckks/CKKS.h" #import "CKKSKeychainView.h" diff --git a/keychain/ckks/CKKSScanLocalItemsOperation.m b/keychain/ckks/CKKSScanLocalItemsOperation.m index 6c4fe803..7d285ad6 100644 --- a/keychain/ckks/CKKSScanLocalItemsOperation.m +++ b/keychain/ckks/CKKSScanLocalItemsOperation.m @@ -38,9 +38,9 @@ #import "CKKSPowerCollection.h" -#include -#include -#include +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include #import diff --git a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m index aeb57d81..00080ba2 100644 --- a/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m +++ b/keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m @@ -33,11 +33,11 @@ #import "keychain/categories/NSError+UsefulConstructors.h" #import "keychain/ot/ObjCImprovements.h" -#include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemDb.h" #include -#include +#include "keychain/securityd/SecDbQuery.h" #import @interface CKKSUpdateCurrentItemPointerOperation () diff --git a/keychain/ckks/CKKSViewManager.h b/keychain/ckks/CKKSViewManager.h index 82c8ac34..cd6ac8cd 100644 --- a/keychain/ckks/CKKSViewManager.h +++ b/keychain/ckks/CKKSViewManager.h @@ -26,7 +26,7 @@ #if OCTAGON -#include +#include "keychain/securityd/SecDbItem.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/OctagonAPSReceiver.h" #import "keychain/ckks/CKKSAccountStateTracker.h" @@ -141,6 +141,10 @@ NS_ASSUME_NONNULL_BEGIN - (void)notifyNewTLKsInKeychain; - (void)syncBackupAndNotifyAboutSync; +// allow user blocking operation to block on trust status trying to sort it-self out the +// first time after launch, only waits the the initial call +- (BOOL)waitForTrustReady; + // For testing - (void)setOverrideCKKSViewsFromPolicy:(BOOL)value; - (BOOL)useCKKSViewsFromPolicy; diff --git a/keychain/ckks/CKKSViewManager.m b/keychain/ckks/CKKSViewManager.m index 1db3c5df..8a226dfc 100644 --- a/keychain/ckks/CKKSViewManager.m +++ b/keychain/ckks/CKKSViewManager.m @@ -37,6 +37,7 @@ #import "keychain/analytics/SecEventMetric.h" #import "keychain/analytics/SecMetrics.h" +#import "keychain/ot/OTManager.h" #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTConstants.h" #import "keychain/ot/ObjCImprovements.h" @@ -45,9 +46,9 @@ #import "SecEntitlements.h" -#include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemSchema.h" #include #import @@ -157,6 +158,18 @@ NSSet* _viewList; return container; } +- (BOOL)waitForTrustReady { + static dispatch_once_t onceToken; + __block BOOL success = YES; + dispatch_once(&onceToken, ^{ + OTManager* manager = [OTManager manager]; + if (![manager waitForReady:OTCKContainerName context:OTDefaultContext wait:3*NSEC_PER_SEC]) { + success = NO; + } + }); + return success; +} + - (void)setupAnalytics { WEAKIFY(self); @@ -883,6 +896,7 @@ dispatch_once_t globalZoneStateQueueOnce; [self.accountTracker.ckdeviceIDInitialized wait:1*NSEC_PER_SEC]; NSString *deviceID = self.accountTracker.ckdeviceID; NSError *deviceIDError = self.accountTracker.ckdeviceIDError; + NSDate *lastCKKSPush = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastCKKSPush]; #define stringify(obj) CKKSNilToNSNull([obj description]) NSDictionary* global = @{ @@ -892,6 +906,7 @@ dispatch_once_t globalZoneStateQueueOnce; @"ckdeviceIDError": CKKSNilToNSNull(deviceIDError), @"lockstatetracker": stringify(self.lockStateTracker), @"cloudkitRetryAfter": stringify(self.zoneModifier.cloudkitRetryAfter), + @"lastCKKSPush": CKKSNilToNSNull(lastCKKSPush), }; [a addObject: global]; } @@ -918,6 +933,10 @@ dispatch_once_t globalZoneStateQueueOnce; } if(self.accountTracker.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) { + if (![self waitForTrustReady]) { + secerror("ckks status: Haven't yet figured out trust status"); + } + CKKSResultOperation* blockOp = [CKKSResultOperation named:@"wait-for-status" withBlock:^{}]; [blockOp timeout:8*NSEC_PER_SEC]; for(CKKSKeychainView* view in actualViews) { @@ -1028,6 +1047,11 @@ dispatch_once_t globalZoneStateQueueOnce; -(void)xpc24HrNotification { // XPC has poked us and said we should do some cleanup! + secnotice("ckks", "Received a 24hr notification from XPC"); + + if (![self waitForTrustReady]) { + secnotice("ckks", "Trust not ready, still going ahead"); + } [[CKKSAnalytics logger] dailyCoreAnalyticsMetrics:@"com.apple.security.CKKSHealthSummary"]; @@ -1038,7 +1062,6 @@ dispatch_once_t globalZoneStateQueueOnce; actualViews = self.views.allValues; } - secnotice("ckks", "Received a 24hr notification from XPC"); CKOperationGroup* group = [CKOperationGroup CKKSGroupWithName:@"periodic-device-state-update"]; for(CKKSKeychainView* view in actualViews) { ckksnotice("ckks", view, "Starting device state XPC update"); diff --git a/keychain/ckks/CKKSZoneChangeFetcher.h b/keychain/ckks/CKKSZoneChangeFetcher.h index 80cdc654..d1e60c14 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.h +++ b/keychain/ckks/CKKSZoneChangeFetcher.h @@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithContainer:(CKContainer*)container - fetchClass:(Class)fetchRecordsOperationClass + fetchClass:(Class)fetchRecordZoneChangesOperationClass reachabilityTracker:(CKKSReachabilityTracker *)reachabilityTracker; - (void)registerClient:(id)client; diff --git a/keychain/ckks/CKKSZoneChangeFetcher.m b/keychain/ckks/CKKSZoneChangeFetcher.m index 8b9fe2f5..0ec4cff4 100644 --- a/keychain/ckks/CKKSZoneChangeFetcher.m +++ b/keychain/ckks/CKKSZoneChangeFetcher.m @@ -52,7 +52,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- #pragma mark - CKKSZoneChangeFetchDependencyOperation @interface CKKSZoneChangeFetchDependencyOperation : CKKSResultOperation -@property CKKSZoneChangeFetcher* owner; +@property (weak) CKKSZoneChangeFetcher* owner; @property NSMutableArray* chainDependents; - (void)chainDependency:(CKKSZoneChangeFetchDependencyOperation*)newDependency; @end @@ -130,16 +130,17 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- _newRequests = false; - // If we're testing, for the initial delay, use 0.2 second. Otherwise, 2s. - dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 200 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); + // If we're testing, for the initial delay, use 0.25 second. Otherwise, 2s. + dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 250 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); - // If we're testing, for the continuing delay, use 2 second. Otherwise, 30s. - dispatch_time_t continuingDelay = (SecCKKSReduceRateLimiting() ? 2 * NSEC_PER_SEC : 30 * NSEC_PER_SEC); + // If we're testing, for the maximum delay, use 6 second. Otherwise, 2m. + dispatch_time_t maximumDelay = (SecCKKSReduceRateLimiting() ? 6 * NSEC_PER_SEC : 120 * NSEC_PER_SEC); WEAKIFY(self); _fetchScheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"zone-change-fetch-scheduler" initialDelay:initialDelay - continuingDelay:continuingDelay + expontialBackoff:2 + maximumDelay:maximumDelay keepProcessAlive:false dependencyDescriptionCode:CKKSResultDescriptionPendingZoneChangeFetchScheduling block:^{ @@ -308,25 +309,14 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more- dispatch_sync(self.queue, ^{ self.lastCKFetchError = fetchAllChanges.error; - if(!fetchAllChanges.error) { - if (attemptAnotherFetch) { - [dependency chainDependency:self.successfulFetchDependency]; - [self.operationQueue addOperation: dependency]; - - [self.currentFetchReasons unionSet:lastFetchReasons]; - [self.apnsPushes unionSet:lastAPNSPushes]; + if(fetchAllChanges.error == nil) { + // success! notify the listeners. + [self.operationQueue addOperation: dependency]; + self.currentFetch = nil; - self.newRequests = true; + // Did new people show up and want another fetch? + if(self.newRequests) { [self.fetchScheduler trigger]; - } else { - // success! notify the listeners. - [self.operationQueue addOperation: dependency]; - self.currentFetch = nil; - - // Did new people show up and want another fetch? - if(self.newRequests) { - [self.fetchScheduler trigger]; - } } } else { // The operation errored. Chain the dependency on the current one... diff --git a/keychain/ckks/CKKSZoneModifier.m b/keychain/ckks/CKKSZoneModifier.m index 66d5d134..d8afc74b 100644 --- a/keychain/ckks/CKKSZoneModifier.m +++ b/keychain/ckks/CKKSZoneModifier.m @@ -99,9 +99,11 @@ if(!self.pendingOperations) { CKKSResultOperation* zoneModificationOperationDependency = [CKKSResultOperation named:@"zone-modification" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) { + secnotice("ckkszonemodifier", "finished creating zones"); }]; CKKSResultOperation* zoneSubscriptionOperationDependency = [CKKSResultOperation named:@"zone-subscription" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) { + secnotice("ckkszonemodifier", "finished subscribing to zones"); }]; self.pendingOperations = [[CKKSZoneModifyOperations alloc] initWithZoneModificationOperation:zoneModificationOperationDependency @@ -244,6 +246,8 @@ - (CKDatabaseOperation* _Nullable)createModifySubscriptionsOperation:(CKKSZoneModifyOperations*)ops { + secnotice("ckkszonemodifier", "Attempting to subscribe to zones %@", ops.subscriptionsToSubscribe); + if(ops.subscriptionsToSubscribe.count == 0) { [self.operationQueue addOperation: ops.zoneSubscriptionOperation]; return nil; @@ -258,10 +262,6 @@ zoneSubscriptionOperation.database = self.database; zoneSubscriptionOperation.name = @"zone-subscription-operation"; - // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. - NSBlockOperation* zoneSubscriptionCompleteOperation = [[NSBlockOperation alloc] init]; - zoneSubscriptionCompleteOperation.name = @"zone-subscription-complete"; - WEAKIFY(self); zoneSubscriptionOperation.modifySubscriptionsCompletionBlock = ^(NSArray * _Nullable savedSubscriptions, NSArray * _Nullable deletedSubscriptionIDs, diff --git a/keychain/ckks/CKKSZoneStateEntry.h b/keychain/ckks/CKKSZoneStateEntry.h index fb44ce17..27213bca 100644 --- a/keychain/ckks/CKKSZoneStateEntry.h +++ b/keychain/ckks/CKKSZoneStateEntry.h @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include +#include "keychain/securityd/SecDbItem.h" #include #import "CKKSSQLDatabaseObject.h" @@ -55,6 +55,7 @@ NS_ASSUME_NONNULL_BEGIN @property bool ckzonesubscribed; @property (nullable, getter=getChangeToken, setter=setChangeToken:) CKServerChangeToken* changeToken; @property (nullable) NSData* encodedChangeToken; +@property BOOL moreRecordsInCloudKit; @property (nullable) NSDate* lastFetchTime; @property CKKSFixup lastFixup; @@ -71,6 +72,7 @@ NS_ASSUME_NONNULL_BEGIN zoneCreated:(bool)ckzonecreated zoneSubscribed:(bool)ckzonesubscribed changeToken:(NSData* _Nullable)changetoken + moreRecordsInCloudKit:(BOOL)moreRecords lastFetch:(NSDate* _Nullable)lastFetch lastFixup:(CKKSFixup)lastFixup encodedRateLimiter:(NSData* _Nullable)encodedRateLimiter; diff --git a/keychain/ckks/CKKSZoneStateEntry.m b/keychain/ckks/CKKSZoneStateEntry.m index bb03f474..f835d9ab 100644 --- a/keychain/ckks/CKKSZoneStateEntry.m +++ b/keychain/ckks/CKKSZoneStateEntry.m @@ -29,8 +29,8 @@ #import "CKKSKeychainView.h" #include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" #if OCTAGON @@ -46,6 +46,7 @@ zoneCreated:(bool)ckzonecreated zoneSubscribed:(bool)ckzonesubscribed changeToken:(NSData*)changetoken + moreRecordsInCloudKit:(BOOL)moreRecords lastFetch:(NSDate*)lastFetch lastFixup:(CKKSFixup)lastFixup encodedRateLimiter:(NSData*)encodedRateLimiter @@ -55,6 +56,7 @@ _ckzonecreated = ckzonecreated; _ckzonesubscribed = ckzonesubscribed; _encodedChangeToken = changetoken; + _moreRecordsInCloudKit = moreRecords; _lastFetchTime = lastFetch; _lastFixup = lastFixup; @@ -74,6 +76,7 @@ self.ckzonecreated == obj.ckzonecreated && self.ckzonesubscribed == obj.ckzonesubscribed && ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) && + self.moreRecordsInCloudKit == obj.moreRecordsInCloudKit && ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) && ((self.rateLimiter == nil && obj.rateLimiter == nil) || [self.rateLimiter isEqual: obj.rateLimiter]) && self.lastFixup == obj.lastFixup && @@ -93,6 +96,7 @@ zoneCreated:false zoneSubscribed:false changeToken:nil + moreRecordsInCloudKit:NO lastFetch:nil lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:nil]; @@ -147,7 +151,7 @@ } + (NSArray*) sqlColumns { - return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup"]; + return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup", @"morecoming"]; } - (NSDictionary*) whereClauseToFindSelf { @@ -164,6 +168,7 @@ @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil), @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]), @"lastFixup": [NSNumber numberWithLong:self.lastFixup], + @"morecoming": [NSNumber numberWithBool:self.moreRecordsInCloudKit], }; } @@ -172,6 +177,7 @@ zoneCreated:row[@"ckzonecreated"].asBOOL zoneSubscribed:row[@"ckzonesubscribed"].asBOOL changeToken:row[@"changetoken"].asBase64DecodedData + moreRecordsInCloudKit:row[@"morecoming"].asBOOL lastFetch:row[@"lastfetch"].asISO8601Date lastFixup:(CKKSFixup)row[@"lastFixup"].asNSInteger encodedRateLimiter:row[@"ratelimiter"].asBase64DecodedData diff --git a/keychain/ckks/CloudKitCategories.h b/keychain/ckks/CloudKitCategories.h index 45fad55a..2bf92f57 100644 --- a/keychain/ckks/CloudKitCategories.h +++ b/keychain/ckks/CloudKitCategories.h @@ -41,6 +41,7 @@ NS_ASSUME_NONNULL_BEGIN // 2) Every single suberror is either CKErrorServerRecordChanged or CKErrorUnknownItem - (bool)ckksIsCKErrorRecordChangedError; - (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishError; +- (NSTimeInterval)cuttlefishRetryAfter; @end // Ensure we don't print addresses @interface CKAccountInfo (CKKS) diff --git a/keychain/ckks/CloudKitCategories.m b/keychain/ckks/CloudKitCategories.m index ed46d93d..22f57597 100644 --- a/keychain/ckks/CloudKitCategories.m +++ b/keychain/ckks/CloudKitCategories.m @@ -54,30 +54,43 @@ return false; } -- (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishError +- (BOOL)isCuttlefishError:(CuttlefishErrorCode)cuttlefishErrorCode { NSError *error = self; - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - // This funny code is becase CodeOperation was not wrapping underlying errors with CKError, and then they fixed that in - // if you find this code, it probably time to always check for CKErrorDomain/CKErrorServerRejectedRequest - if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest && underlyingError) { - error = underlyingError; - } - - if([error.domain isEqualToString:CKInternalErrorDomain] && error.code == CKErrorInternalPluginError) { + if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest) { NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - if(underlyingError && - [underlyingError.domain isEqualToString:CuttlefishErrorDomain] && - underlyingError.code == cuttlefishError) { - return YES; + + if([underlyingError.domain isEqualToString:CKInternalErrorDomain] && underlyingError.code == CKErrorInternalPluginError) { + NSError* cuttlefishError = underlyingError.userInfo[NSUnderlyingErrorKey]; + + if([cuttlefishError.domain isEqualToString:CuttlefishErrorDomain] && cuttlefishError.code == cuttlefishErrorCode) { + return YES; + } } } return NO; } +- (NSTimeInterval)cuttlefishRetryAfter { + NSError *error = self; + + if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorServerRejectedRequest) { + NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; + if([underlyingError.domain isEqualToString:CKInternalErrorDomain] && underlyingError.code == CKErrorInternalPluginError) { + NSError* cuttlefishError = underlyingError.userInfo[NSUnderlyingErrorKey]; + if([cuttlefishError.domain isEqualToString:CuttlefishErrorDomain]) { + NSNumber* val = cuttlefishError.userInfo[CuttlefishErrorRetryAfterKey]; + if (val) { + return (NSTimeInterval)val.doubleValue; + } + } + } + } + return 0; +} @end diff --git a/keychain/ckks/NSOperationCategories.m b/keychain/ckks/NSOperationCategories.m index d69f47a6..b9ea9410 100644 --- a/keychain/ckks/NSOperationCategories.m +++ b/keychain/ckks/NSOperationCategories.m @@ -24,6 +24,7 @@ #import #import "keychain/ckks/NSOperationCategories.h" #import "keychain/ot/ObjCImprovements.h" +#import "utilities/debugging.h" @implementation NSOperation (CKKSUsefulPrintingOperation) - (NSString*)selfname { @@ -41,6 +42,9 @@ // don't depend on yourself continue; } +#if DEBUG + secnotice("ckks-operation", "adding dependency of %@ on %@", self, existingop); +#endif [self addDependency: existingop]; } [collection addObject:self]; diff --git a/keychain/ckks/OctagonAPSReceiver.h b/keychain/ckks/OctagonAPSReceiver.h index cf33ac99..5271338d 100644 --- a/keychain/ckks/OctagonAPSReceiver.h +++ b/keychain/ckks/OctagonAPSReceiver.h @@ -74,5 +74,9 @@ NS_ASSUME_NONNULL_BEGIN @end +@interface OctagonAPSReceiver (Testing) ++ (void)resetGlobalEnviornmentMap; +@end + NS_ASSUME_NONNULL_END #endif // OCTAGON diff --git a/keychain/ckks/OctagonAPSReceiver.m b/keychain/ckks/OctagonAPSReceiver.m index fbd0c175..10499da9 100644 --- a/keychain/ckks/OctagonAPSReceiver.m +++ b/keychain/ckks/OctagonAPSReceiver.m @@ -27,6 +27,7 @@ #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSCondition.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" +#import "keychain/ckks/CKKSAnalytics.h" #import "keychain/analytics/SecMetrics.h" #import "keychain/analytics/SecEventMetric.h" #import "keychain/ot/ObjCImprovements.h" @@ -79,18 +80,15 @@ + (instancetype)receiverForEnvironment:(NSString *)environmentName namedDelegatePort:(NSString*)namedDelegatePort - apsConnectionClass:(Class)apsConnectionClass { - static NSMutableDictionary* environmentMap = nil; - + apsConnectionClass:(Class)apsConnectionClass +{ if(environmentName == nil) { secnotice("octagonpush", "No push environment; not bringing up APS."); return nil; } @synchronized([self class]) { - if(environmentMap == nil) { - environmentMap = [[NSMutableDictionary alloc] init]; - } + NSMutableDictionary* environmentMap = [self synchronizedGlobalEnvironmentMap]; OctagonAPSReceiver* recv = [environmentMap valueForKey: environmentName]; @@ -103,6 +101,29 @@ } } ++ (void)resetGlobalEnviornmentMap +{ + @synchronized (self) { + [self resettableSynchronizedGlobalEnvironmentMap:YES]; + } +} + ++ (NSMutableDictionary*)synchronizedGlobalEnvironmentMap +{ + return [self resettableSynchronizedGlobalEnvironmentMap:NO]; +} + ++ (NSMutableDictionary*)resettableSynchronizedGlobalEnvironmentMap:(BOOL)reset +{ + static NSMutableDictionary* environmentMap = nil; + + if(environmentMap == nil || reset) { + environmentMap = [[NSMutableDictionary alloc] init]; + } + + return environmentMap; +} + + (dispatch_queue_t)apsDeliveryQueue { static dispatch_queue_t aps_dispatch_queue; static dispatch_once_t onceToken; @@ -113,7 +134,7 @@ } + (int64_t)stalePushTimeout { - return 5*60*NSEC_PER_MSEC; + return 5*60*NSEC_PER_SEC; } - (BOOL) haveStalePushes @@ -319,6 +340,7 @@ NSString* container = cfInfo[@"c"]; secnotice("octagonpush", "Received a cuttlefish push to container %@", container); + [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastOctagonPush]; if(container) { id receiver = [self.octagonContainerMap objectForKey:container]; @@ -350,6 +372,8 @@ rznotification.ckksPushTracingUUID = message.tracingUUID ? [[[NSUUID alloc] initWithUUIDBytes:message.tracingUUID.bytes] UUIDString] : nil; rznotification.ckksPushReceivedDate = [NSDate date]; + [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastCKKSPush]; + // Find receiever in map id recv = [self.zoneMap objectForKey:rznotification.recordZoneID.zoneName]; if(recv) { diff --git a/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m b/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m index 7420cd8f..1dc7249f 100644 --- a/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m +++ b/keychain/ckks/tests/CKKSAESSIVEncryptionTests.m @@ -33,7 +33,7 @@ #import "keychain/ckks/CKKSIncomingQueueEntry.h" #import "keychain/ckks/CKKSItemEncrypter.h" -#include +#include "keychain/securityd/SecItemServer.h" #include #include "OSX/sec/Security/SecItemShim.h" diff --git a/keychain/ckks/tests/CKKSAPSHandlingTests.m b/keychain/ckks/tests/CKKSAPSHandlingTests.m index 34b0a322..748de40c 100644 --- a/keychain/ckks/tests/CKKSAPSHandlingTests.m +++ b/keychain/ckks/tests/CKKSAPSHandlingTests.m @@ -287,7 +287,7 @@ - (int64_t)stalePushTimeoutShort { - return 10 * NSEC_PER_SEC; + return 4 * NSEC_PER_SEC; } - (void)testDropStalePushes { @@ -298,9 +298,10 @@ APSIncomingMessage* apsMessage = [CKKSAPSHandlingTests messageWithTracingEnabledForZoneID:pushTestZone]; - OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForEnvironment:self.apsEnvironment - namedDelegatePort:SecCKKSAPSNamedPort - apsConnectionClass:[FakeAPSConnection class]]; + // 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]]; XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver"); [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage]; @@ -308,12 +309,14 @@ XCTAssertEqual(apsReceiver.haveStalePushes, YES, "should have stale pushes"); XCTestExpectation *expection = [self expectationWithDescription:@"no push"]; - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, [self stalePushTimeoutShort] + 2), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ + 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]; } diff --git a/keychain/ckks/tests/CKKSCloudKitTests.m b/keychain/ckks/tests/CKKSCloudKitTests.m index e7586ea8..6add0637 100644 --- a/keychain/ckks/tests/CKKSCloudKitTests.m +++ b/keychain/ckks/tests/CKKSCloudKitTests.m @@ -27,9 +27,9 @@ #import #import -#import +#import "keychain/securityd/SecItemServer.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #import "keychain/ckks/CKKS.h" diff --git a/keychain/ckks/tests/CKKSFetchTests.m b/keychain/ckks/tests/CKKSFetchTests.m index 2a7a1adf..433a2b20 100644 --- a/keychain/ckks/tests/CKKSFetchTests.m +++ b/keychain/ckks/tests/CKKSFetchTests.m @@ -11,8 +11,10 @@ #import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSKeychainView.h" +#import "keychain/ckks/CKKSZoneStateEntry.h" #import "keychain/ckks/tests/MockCloudKit.h" +#import "keychain/ot/ObjCImprovements.h" @interface CloudKitKeychainFetchTests : CloudKitKeychainSyncingTestsBase @end @@ -188,6 +190,187 @@ [self findGenericPassword: @"account3" expecting:errSecSuccess]; } +- (void)testMoreComingWithFullFailure { + WEAKIFY(self); + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + // The fetch fails with partial results + ckzone.limitFetchTo = ck1; + ckzone.limitFetchError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:@{CKErrorRetryAfterKey : [NSNumber numberWithInt:4]}]; + + self.silentFetchesAllowed = false; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + return YES; + } runBeforeFinished:^{ + STRONGIFY(self); + // We want to fail with a full network failure error, but we explicitly don't want to set network reachability: + // CKKS won't send the fetch in that case. So... + [self.keychainZone failNextFetchWith:[NSError errorWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:NULL]]; + [self expectCKFetch]; + }]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + // Wait for both fetches.... + OCMVerifyAllWithDelay(self.mockDatabase, 20); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + // Potential race here: we need to start this expectation before CKKS issues the fetch. With a 4s delay, this should be safe. + + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + [self.reachabilityTracker setNetworkReachability:true]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + [self findGenericPassword: @"account2" expecting:errSecSuccess]; + [self findGenericPassword: @"account3" expecting:errSecSuccess]; +} + +- (void)testFetchOnRestartWithMoreComing { + [self putFakeKeyHierarchyInCloudKit: self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + + // Allow CKKS to fetch fully, then fake on-disk that it received MoreComing. + // (It's very hard to tear down the retry logic in-process) + self.silentFetchesAllowed = false; + [self expectCKFetch]; + + // Trigger a notification (with hilariously fake data) + [self.keychainView notifyZoneChange:nil]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + + // Now, edit the on-disk CKSE + [self.keychainView halt]; + + [self.keychainView dispatchSync: ^bool { + NSError* error = nil; + CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error]; + + XCTAssertNil(error, "no error pulling ckse from database"); + XCTAssertNotNil(ckse, "received a ckse"); + + ckse.moreRecordsInCloudKit = YES; + [ckse saveToDatabase: &error]; + XCTAssertNil(error, "no error saving to database"); + return true; + }]; + + // CKKS should, upon restart, kick off a fetch starting from the previous checkpoint + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.keychainView = [self.injectedManager restartZone:self.keychainZoneID.zoneName]; + [self.keychainView beginCloudKitOperation]; + [self beginSOSTrustedViewOperation:self.keychainView]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword: @"account0" expecting:errSecSuccess]; + [self findGenericPassword: @"account1" expecting:errSecSuccess]; + [self findGenericPassword: @"account2" expecting:errSecSuccess]; + [self findGenericPassword: @"account3" expecting:errSecSuccess]; +} + +- (void)testMoreComingAsFirstFetch { + [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self saveTLKMaterialToKeychain:self.keychainZoneID]; + + FakeCKZone* ckzone = self.zones[self.keychainZoneID]; + + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"account0"]]; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"account1"]]; + CKServerChangeToken* ck1 = ckzone.currentChangeToken; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"account2"]]; + [self.keychainZone addToZone: [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"account3"]]; + + ckzone.limitFetchTo = ck1; + + self.silentFetchesAllowed = false; + [self expectCKFetch]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; + [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + [self waitForCKModifications]; + + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self findGenericPassword:@"account0" expecting:errSecSuccess]; + [self findGenericPassword:@"account1" expecting:errSecSuccess]; + [self findGenericPassword:@"account2" expecting:errSecSuccess]; + [self findGenericPassword:@"account3" expecting:errSecSuccess]; +} + + @end #endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSMockOctagonAdapter.m b/keychain/ckks/tests/CKKSMockOctagonAdapter.m index 89c511b2..88d38640 100644 --- a/keychain/ckks/tests/CKKSMockOctagonAdapter.m +++ b/keychain/ckks/tests/CKKSMockOctagonAdapter.m @@ -128,6 +128,11 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + + @end #endif diff --git a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h index 85c47833..7fcff165 100644 --- a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h +++ b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.h @@ -19,6 +19,8 @@ NS_ASSUME_NONNULL_BEGIN @property CKKSSOSSelfPeer* selfPeer; @property NSMutableSet>* trustedPeers; +@property (nullable) void (^updateOctagonKeySetListener)(id); + - (instancetype)initWithSelfPeer:(CKKSSOSSelfPeer*)selfPeer trustedPeers:(NSSet>*)trustedPeers essential:(BOOL)essential; diff --git a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m index 03491e76..ec18e233 100644 --- a/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m +++ b/keychain/ckks/tests/CKKSMockSOSPresentAdapter.m @@ -102,6 +102,9 @@ } - (void)updateOctagonKeySetWithAccount:(nonnull id)currentSelfPeer error:(NSError *__autoreleasing _Nullable * _Nullable)error { + if(self.updateOctagonKeySetListener) { + self.updateOctagonKeySetListener(currentSelfPeer); + } return; } @@ -121,6 +124,10 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + - (NSSet>*)allPeers { // include the self peer, but as a CKKSSOSPeer object instead of a self peer diff --git a/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m index b5ae45f4..791dd625 100644 --- a/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m +++ b/keychain/ckks/tests/CKKSNearFutureSchedulerTests.m @@ -188,6 +188,122 @@ [self waitForExpectations: @[waitmore] timeout: 0.2]; } +- (void)testBlockMultiShotDelaysWithZeroInitialDelay { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (long delay expectation)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test" + initialDelay:0*NSEC_PER_MSEC + continuingDelay:600*NSEC_PER_MSEC + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + }]; + + [scheduler trigger]; + + // Watches can be very slow. We expect this to come back immediately, but give them a lot of slack.... + [self waitForExpectations: @[first] timeout:0.4]; + + [scheduler trigger]; + [scheduler trigger]; + [scheduler trigger]; + + // longdelay should NOT be fulfilled again within 0.3 seconds of the first run + [self waitForExpectations: @[longdelay] timeout:0.3]; + + // But second should be fulfilled in the first 1.0 seconds + [self waitForExpectations: @[second] timeout:0.6]; + + XCTestExpectation* waitmore = [self expectationWithDescription:@"waiting"]; + waitmore.inverted = YES; + [self waitForExpectations: @[waitmore] timeout: 0.2]; +} + +- (void)testBlockExponentialDelays { + XCTestExpectation *first = [self expectationWithDescription:@"FutureScheduler fired (one)"]; + first.assertForOverFulfill = NO; + + XCTestExpectation *longdelay = [self expectationWithDescription:@"FutureScheduler fired (twice in 1s)"]; + longdelay.inverted = YES; + longdelay.expectedFulfillmentCount = 2; + longdelay.assertForOverFulfill = NO; + + XCTestExpectation *second = [self expectationWithDescription:@"FutureScheduler fired (two)"]; + second.expectedFulfillmentCount = 2; + second.assertForOverFulfill = NO; + + XCTestExpectation *longdelay2 = [self expectationWithDescription:@"FutureScheduler fired (three in 2s)"]; + longdelay2.inverted = YES; + longdelay2.expectedFulfillmentCount = 3; + longdelay2.assertForOverFulfill = NO; + + XCTestExpectation *third = [self expectationWithDescription:@"FutureScheduler fired (three)"]; + third.expectedFulfillmentCount = 3; + third.assertForOverFulfill = NO; + + XCTestExpectation *final = [self expectationWithDescription:@"FutureScheduler fired (fourth)"]; + final.expectedFulfillmentCount = 4; + final.assertForOverFulfill = YES; + + CKKSNearFutureScheduler* scheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"test" + initialDelay:500*NSEC_PER_MSEC + expontialBackoff:2 + maximumDelay:30*NSEC_PER_SEC + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionNone + block:^{ + [first fulfill]; + [longdelay fulfill]; + [second fulfill]; + [longdelay2 fulfill]; + [third fulfill]; + [final fulfill]; + }]; + + [scheduler trigger]; + + // first should be fulfilled in the first 0.6 seconds + [self waitForExpectations: @[first] timeout:0.6]; + + [scheduler trigger]; + + // longdelay should NOT be fulfilled twice in the first 1.3-1.4 seconds + [self waitForExpectations: @[longdelay] timeout:0.8]; + + // But second should be fulfilled in the first 1.6 seconds + [self waitForExpectations: @[second] timeout:0.3]; + + [scheduler trigger]; + + // and longdelay2 should NOT be fulfilled three times in the first 2.3-2.4 seconds + [self waitForExpectations: @[longdelay2] timeout:0.9]; + + // But third should be fulfilled in the first 3.6 seconds + [self waitForExpectations: @[third] timeout:1.2]; + + // Wait out the 4s reset delay... + XCTestExpectation *reset = [self expectationWithDescription:@"reset"]; + reset.inverted = YES; + [self waitForExpectations: @[reset] timeout:4.2]; + + // and it should use a 0.5s delay after trigger + [scheduler trigger]; + + [self waitForExpectations: @[final] timeout:0.6]; +} + - (void)testBlockCancel { XCTestExpectation *cancelexpectation = [self expectationWithDescription:@"FutureScheduler fired (after cancel)"]; cancelexpectation.inverted = YES; diff --git a/keychain/ckks/tests/CKKSSQLTests.m b/keychain/ckks/tests/CKKSSQLTests.m index 76db6ebd..8bd89e46 100644 --- a/keychain/ckks/tests/CKKSSQLTests.m +++ b/keychain/ckks/tests/CKKSSQLTests.m @@ -35,7 +35,7 @@ #import "keychain/ckks/CKKSDeviceStateEntry.h" #import "keychain/ckks/CKKSRateLimiter.h" -#include +#include "keychain/securityd/SecItemServer.h" @interface CloudKitKeychainSQLTests : CloudKitMockXCTest @end @@ -226,6 +226,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:YES lastFetch:[NSDate date] lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:nil]; @@ -235,6 +236,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:YES lastFetch:zse.lastFetchTime lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:zse.encodedRateLimiter]; @@ -243,6 +245,7 @@ zoneCreated:true zoneSubscribed:true changeToken:[@"allnonsense" dataUsingEncoding:NSUTF8StringEncoding] + moreRecordsInCloudKit:NO lastFetch:zse.lastFetchTime lastFixup:CKKSCurrentFixupNumber encodedRateLimiter:zse.encodedRateLimiter]; diff --git a/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m index d96cb296..c75ef74c 100644 --- a/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m +++ b/keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m @@ -117,7 +117,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -504,7 +505,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -613,7 +615,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -687,7 +690,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -766,7 +770,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -852,7 +857,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; @@ -915,7 +921,8 @@ [self startCKKSSubsystem]; // Let things shake themselves out. - [self.keychainView waitForKeyHierarchyReadiness]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // Ensure there's no current pointer [self fetchCurrentPointerExpectingError:false]; diff --git a/keychain/ckks/tests/CKKSTests+MultiZone.m b/keychain/ckks/tests/CKKSTests+MultiZone.m index e121b309..f3179612 100644 --- a/keychain/ckks/tests/CKKSTests+MultiZone.m +++ b/keychain/ckks/tests/CKKSTests+MultiZone.m @@ -687,6 +687,86 @@ OCMVerifyAllWithDelay(self.mockDatabase, 20); } +- (void)testMultiZoneResync { + // Set up + [self putFakeKeyHierachiesInCloudKit]; + [self saveTLKsToKeychain]; + [self expectCKKSTLKSelfShareUploads]; + + // Put sample data in zones, and save off a change token for later fetch shenanigans + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D00" withAccount:@"manatee0"]]; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D01" withAccount:@"manatee1"]]; + CKServerChangeToken* manateeChangeToken1 = self.manateeZone.currentChangeToken; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D02" withAccount:@"manatee2"]]; + [self.manateeZone addToZone:[self createFakeRecord:self.manateeZoneID recordName:@"7B598D31-0000-0000-0000-5A507ACB2D03" withAccount:@"manatee3"]]; + + [self.healthZone addToZone:[self createFakeRecord:self.healthZoneID recordName:@"7B598D31-0000-0000-FFFF-5A507ACB2D00" withAccount:@"health0"]]; + [self.healthZone addToZone:[self createFakeRecord:self.healthZoneID recordName:@"7B598D31-0000-0000-FFFF-5A507ACB2D01" withAccount:@"health1"]]; + + [self startCKKSSubsystem]; + [self waitForKeyHierarchyReadinesses]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.manateeView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self.healthView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + [self findGenericPassword:@"manatee0" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee1" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee2" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee3" expecting:errSecSuccess]; + [self findGenericPassword:@"health0" expecting:errSecSuccess]; + [self findGenericPassword:@"health1" expecting:errSecSuccess]; + + // Now, we resync. But, the manatee zone comes down in two fetches + self.silentFetchesAllowed = false; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is a refetch + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.manateeZoneID].previousServerChangeToken; + if(changeToken == nil) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.manateeZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:manateeChangeToken1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.manateeZone.limitFetchTo = manateeChangeToken1; + + // Attempt to trigger simultaneous key state resyncs. This is a horrible hack... + [self.manateeView dispatchSyncWithAccountKeys:^bool { + self.manateeView.keyStateFullRefetchRequested = YES; + [self.manateeView _onqueueAdvanceKeyStateMachineToState:nil withError:nil]; + return true; + }]; + [self.healthView dispatchSyncWithAccountKeys:^bool { + self.healthView.keyStateFullRefetchRequested = YES; + [self.healthView _onqueueAdvanceKeyStateMachineToState:nil withError:nil]; + return true; + }]; + + OCMVerifyAllWithDelay(self.mockDatabase, 20); + + [self.manateeView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + [self.healthView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; + + // And all items should still exist + [self findGenericPassword:@"manatee0" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee1" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee2" expecting:errSecSuccess]; + [self findGenericPassword:@"manatee3" expecting:errSecSuccess]; + [self findGenericPassword:@"health0" expecting:errSecSuccess]; + [self findGenericPassword:@"health1" expecting:errSecSuccess]; +} + @end #endif // OCTAGON diff --git a/keychain/ckks/tests/CKKSTests.m b/keychain/ckks/tests/CKKSTests.m index 58bb0e16..8a057b6c 100644 --- a/keychain/ckks/tests/CKKSTests.m +++ b/keychain/ckks/tests/CKKSTests.m @@ -30,8 +30,8 @@ #import #include -#include -#include +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemServer.h" #include #include "keychain/SecureObjectSync/SOSInternal.h" @@ -500,6 +500,8 @@ NSString* account = @"account-delete-me"; [self startCKKSSubsystem]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'"); + [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]]; // We expect a single record to be uploaded. [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID]; @@ -1154,11 +1156,13 @@ // Now, another device comes along and creates the hierarchy; we download it; and it and sends us the TLK [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; + [self putFakeDeviceStatusInCloudKit:self.keychainZoneID]; [self.keychainView notifyZoneChange:nil]; [[self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished]; self.aksLockState = false; [self.lockStateTracker recheck]; + XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], @"Key state should end up in waitfortlk"); // After unlock, the TLK arrives [self expectCKKSTLKSelfShareUpload:self.keychainZoneID]; @@ -2096,6 +2100,23 @@ [self checkGenericPassword:@"newpassword" account:localDataChangedAccount]; SecCKKSEnable(); + // To make this more challenging, CK returns the refetch in multiple batches. This shouldn't affect the resync... + CKServerChangeToken* ck1 = self.keychainZone.currentChangeToken; + self.silentFetchesAllowed = false; + [self expectCKFetch]; + [self expectCKFetchWithFilter:^BOOL(FakeCKFetchRecordZoneChangesOperation * _Nonnull frzco) { + // Assert that the fetch is happening with the change token we paused at before + CKServerChangeToken* changeToken = frzco.configurationsByRecordZoneID[self.keychainZoneID].previousServerChangeToken; + if(changeToken && [changeToken isEqual:ck1]) { + return YES; + } else { + return NO; + } + } runBeforeFinished:^{}]; + + self.keychainZone.limitFetchTo = ck1; + self.keychainZone.limitFetchError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorNetworkFailure userInfo:@{CKErrorRetryAfterKey : [NSNumber numberWithInt:4]}]; + // The sixth record gets magically added to CloudKit, but CKKS has never heard of it // (emulates a lost record on the client, but that CloudKit already believes it's sent the record for) // Expected outcome: added to local keychain @@ -2118,6 +2139,8 @@ XCTAssertNil(resyncOperation.error, "No error during the resync operation"); + OCMVerifyAllWithDelay(self.mockDatabase, 20); + // Now do some checking. Remember, we don't know which record we corrupted, so use the parsed account variables to check. [self findGenericPassword: deleteAccount expecting: errSecSuccess]; diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h index e1d7ef68..933305d3 100644 --- a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h @@ -57,7 +57,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable) NSError* keychainFetchError; // A single trusted SOSPeer, but without any CKKS keys -@property CKKSSOSPeer* remoteSOSOnlyPeer; +@property (nullable) CKKSSOSPeer* remoteSOSOnlyPeer; // Set this to false after calling -setUp if you want to initialize the views yourself @property bool automaticallyBeginCKKSViewCloudKitOperation; diff --git a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m index 34477abf..3ea304a4 100644 --- a/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m +++ b/keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m @@ -28,8 +28,8 @@ #import "keychain/ckks/tests/CloudKitMockXCTest.h" #import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h" -#import -#import +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/SecItemDb.h" #import "keychain/ckks/CKKS.h" #import "keychain/ckks/CKKSKeychainView.h" @@ -145,16 +145,21 @@ } - (void)tearDown { - [self.mockCKKSKeychainBackedKey stopMocking]; - self.mockCKKSKeychainBackedKey = nil; - // Make sure the key state machine won't be poked after teardown for(CKKSKeychainView* view in self.ckksViews) { [view.pokeKeyStateMachineScheduler cancel]; } + [self.ckksViews removeAllObjects]; [super tearDown]; self.keys = nil; + + [self.mockCKKSKeychainBackedKey stopMocking]; + self.mockCKKSKeychainBackedKey = nil; + + [((id)self.accountMetaDataStore) stopMocking]; + + self.remoteSOSOnlyPeer = nil; } - (void)startCKKSSubsystem @@ -357,6 +362,9 @@ - (void)putFakeKeyHierarchyInCloudKit: (CKRecordZoneID*)zoneID { ZoneKeys* zonekeys = [self createFakeKeyHierarchy: zoneID oldTLK:nil]; XCTAssertNotNil(zonekeys, "failed to create fake key hierarchy for zoneID=%@", zoneID); + XCTAssertNil(zonekeys.error, "should have no error creating a zonekeys"); + + secnotice("fake-cloudkit", "new fake hierarchy: %@", zonekeys); FakeCKZone* zone = self.zones[zoneID]; XCTAssertNotNil(zone, "failed to find zone %@", zoneID); diff --git a/keychain/ckks/tests/CloudKitMockXCTest.m b/keychain/ckks/tests/CloudKitMockXCTest.m index f2caddc4..1eded344 100644 --- a/keychain/ckks/tests/CloudKitMockXCTest.m +++ b/keychain/ckks/tests/CloudKitMockXCTest.m @@ -32,18 +32,18 @@ #import #import -#include "securityd/Regressions/SecdTestKeychainUtilities.h" +#include "keychain/securityd/Regressions/SecdTestKeychainUtilities.h" #include -#include +#include "keychain/securityd/SecItemServer.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include #include @@ -124,6 +124,9 @@ self.apsEnvironment = @"fake APS push string"; + // Static variables are a scourge. Let's reset this one... + [OctagonAPSReceiver resetGlobalEnviornmentMap]; + self.mockDatabaseExceptionCatcher = OCMStrictClassMock([CKDatabase class]); self.mockDatabase = OCMStrictClassMock([CKDatabase class]); self.mockContainerExpectations = OCMStrictClassMock([CKContainer class]); @@ -321,6 +324,7 @@ OCMStub([self.mockCKKSViewManager defaultViewList]).andCall(self, @selector(managedViewList)); OCMStub([self.mockCKKSViewManager syncBackupAndNotifyAboutSync]); + OCMStub([self.mockCKKSViewManager waitForTrustReady]).andReturn(YES); self.injectedManager = self.mockCKKSViewManager; diff --git a/keychain/ckks/tests/MockCloudKit.m b/keychain/ckks/tests/MockCloudKit.m index cb56d641..a4172271 100644 --- a/keychain/ckks/tests/MockCloudKit.m +++ b/keychain/ckks/tests/MockCloudKit.m @@ -232,6 +232,7 @@ if(!fakezone) { // This is an error: the zone doesn't exist + ckksnotice("fakeck", subscription.zoneID, "failing subscription for missing zone"); self.subscriptionError = [[CKPrettyError alloc] initWithDomain:CKErrorDomain code:CKErrorPartialFailure userInfo:@{ @@ -243,6 +244,7 @@ }]; } else if(fakezone.subscriptionError) { + ckksnotice("fakeck", subscription.zoneID, "failing subscription with injected error %@", fakezone.subscriptionError); // Not the best way to do this, but it's an error // Needs fixing if you want to support multiple zone failures self.subscriptionError = fakezone.subscriptionError; @@ -250,6 +252,7 @@ // 'clear' the error fakezone.subscriptionError = nil; } else { + ckksnotice("fakeck", subscription.zoneID, "Successfully subscribed to zone"); if(!self.subscriptionsSaved) { self.subscriptionsSaved = [[NSMutableArray alloc] init]; } @@ -258,6 +261,7 @@ } for(NSString* subscriptionID in self.subscriptionIDsToDelete) { + secnotice("fakeck", "Successfully deleted subscription: %@", subscriptionID); if(!self.subscriptionIDsDeleted) { self.subscriptionIDsDeleted = [[NSMutableArray alloc] init]; } @@ -352,7 +356,7 @@ return; } - // Not precisely correct in the case of multiple zone fetches. However, we don't currently do that, so it'll work for now. + // Not precisely correct in the case of multiple zone fetches. NSError* mockError = [zone popFetchChangesError]; if(mockError) { self.fetchRecordZoneChangesCompletionBlock(mockError); @@ -678,6 +682,10 @@ dispatch_assert_queue(self.queue); CKRecord* record = [item CKRecordWithZoneID: zoneID]; + + secnotice("fake-cloudkit", "adding item to zone(%@): %@", zoneID.zoneName, item); + secnotice("fake-cloudkit", "new record: %@", record); + [self _onqueueAddToZone: record]; // Save off the etag diff --git a/keychain/ckksctl/ckksctl.m b/keychain/ckksctl/ckksctl.m index 7b200d99..bad4d21b 100644 --- a/keychain/ckksctl/ckksctl.m +++ b/keychain/ckksctl/ckksctl.m @@ -305,6 +305,7 @@ static void print_entry(id k, id v, int ind) NSString* ckdeviceIDError = pop(global, @"ckdeviceIDError", NSString); NSString* lockStateTracker = pop(global,@"lockstatetracker", NSString); NSString* retry = pop(global,@"cloudkitRetryAfter", NSString); + NSDate *lastCKKSPush = pop(global, @"lastCKKSPush", NSDate); printf("================================================================================\n\n"); printf("Global state:\n\n"); @@ -313,6 +314,7 @@ static void print_entry(id k, id v, int ind) printf("CK DeviceID: %s\n", [[ckdeviceID description] UTF8String]); printf("CK DeviceID Error: %s\n", [[ckdeviceIDError description] UTF8String]); printf("Lock state: %s\n", [[lockStateTracker description] UTF8String]); + printf("Last CKKS push: %s\n", [[lastCKKSPush description] UTF8String]); printf("\n"); } diff --git a/keychain/escrowrequest/tests/SecEscrowRequestTests.m b/keychain/escrowrequest/tests/SecEscrowRequestTests.m index 68dc2daf..d504c786 100644 --- a/keychain/escrowrequest/tests/SecEscrowRequestTests.m +++ b/keychain/escrowrequest/tests/SecEscrowRequestTests.m @@ -18,8 +18,8 @@ #include "keychain/ckks/CKKS.h" #include "keychain/ckks/CKKSLockStateTracker.h" -#include "securityd/SecItemServer.h" -#include "securityd/spi.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/spi.h" #include "utilities/SecFileLocations.h" #include "tests/secdmockaks/mockaks.h" diff --git a/keychain/SecAccessControl.h b/keychain/headers/SecAccessControl.h similarity index 100% rename from keychain/SecAccessControl.h rename to keychain/headers/SecAccessControl.h diff --git a/keychain/SecIdentity.h b/keychain/headers/SecIdentity.h similarity index 100% rename from keychain/SecIdentity.h rename to keychain/headers/SecIdentity.h diff --git a/keychain/SecIdentityPriv.h b/keychain/headers/SecIdentityPriv.h similarity index 100% rename from keychain/SecIdentityPriv.h rename to keychain/headers/SecIdentityPriv.h diff --git a/keychain/SecImportExport.h b/keychain/headers/SecImportExport.h similarity index 100% rename from keychain/SecImportExport.h rename to keychain/headers/SecImportExport.h diff --git a/keychain/SecImportExportPriv.h b/keychain/headers/SecImportExportPriv.h similarity index 100% rename from keychain/SecImportExportPriv.h rename to keychain/headers/SecImportExportPriv.h diff --git a/keychain/SecItem.h b/keychain/headers/SecItem.h similarity index 100% rename from keychain/SecItem.h rename to keychain/headers/SecItem.h diff --git a/keychain/SecItemPriv.h b/keychain/headers/SecItemPriv.h similarity index 100% rename from keychain/SecItemPriv.h rename to keychain/headers/SecItemPriv.h diff --git a/keychain/SecKey.h b/keychain/headers/SecKey.h similarity index 100% rename from keychain/SecKey.h rename to keychain/headers/SecKey.h diff --git a/keychain/SecKeyPriv.h b/keychain/headers/SecKeyPriv.h similarity index 100% rename from keychain/SecKeyPriv.h rename to keychain/headers/SecKeyPriv.h diff --git a/keychain/SecKeyProxy.h b/keychain/headers/SecKeyProxy.h similarity index 100% rename from keychain/SecKeyProxy.h rename to keychain/headers/SecKeyProxy.h diff --git a/keychain/SecSharedCredential.h b/keychain/headers/SecSharedCredential.h similarity index 100% rename from keychain/SecSharedCredential.h rename to keychain/headers/SecSharedCredential.h diff --git a/keychain/ot/OTPreflightInfo.h b/keychain/ot/CuttlefishXPCWrapper.h similarity index 59% rename from keychain/ot/OTPreflightInfo.h rename to keychain/ot/CuttlefishXPCWrapper.h index c39b0bf4..7d746def 100644 --- a/keychain/ot/OTPreflightInfo.h +++ b/keychain/ot/CuttlefishXPCWrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. + * Copyright (c) 2019 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,20 +21,24 @@ * @APPLE_LICENSE_HEADER_END@ */ -#if OCTAGON - -#ifndef OTPreflightInfo_h -#define OTPreflightInfo_h +#ifndef CuttlefishXPCWrapper_h +#define CuttlefishXPCWrapper_h #import +#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +// Wrapper around calling cuttlefish XPC calls that performs retries for generic +// XPC errors that warrant retrying. All operations are synchronous. -@interface OTPreflightInfo : NSObject +@interface CuttlefishXPCWrapper : NSObject +@property (readonly) id cuttlefishXPCConnection; -@property (nonatomic, strong) NSData* escrowedSigningSPKI; -@property (nonatomic, strong) NSString* bottleID; +- (instancetype) initWithCuttlefishXPCConnection: (id)cuttlefishXPCConnection; @end +NS_ASSUME_NONNULL_END -#endif /* OTPreflightInfo_h */ -#endif /* OCTAGON */ +#endif // CuttlefishXPCWrapper_h diff --git a/keychain/ot/CuttlefishXPCWrapper.m b/keychain/ot/CuttlefishXPCWrapper.m new file mode 100644 index 00000000..c531fb82 --- /dev/null +++ b/keychain/ot/CuttlefishXPCWrapper.m @@ -0,0 +1,844 @@ +/* + * 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 "keychain/ot/CuttlefishXPCWrapper.h" + +@implementation CuttlefishXPCWrapper +- (instancetype) initWithCuttlefishXPCConnection: (id)cuttlefishXPCConnection +{ + if ((self = [super init])) { + _cuttlefishXPCConnection = cuttlefishXPCConnection; + } + return self; +} + ++ (bool)retryable:(NSError *_Nonnull)error +{ + return error.domain == NSCocoaErrorDomain && error.code == NSXPCConnectionInterrupted; +} + +enum {NUM_RETRIES = 5}; + +- (void)pingWithReply:(void (^)(void))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); + } + ++i; + }] pingWithReply:reply]; + } while (retry); +} + +- (void)dumpWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSDictionary * _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; + }] dumpWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)departByDistrustingSelfWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(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(error); + } + ++i; + }] departByDistrustingSelfWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)distrustPeerIDsWithContainer:(NSString *)container + context:(NSString *)context + peerIDs:(NSSet*)peerIDs + reply:(void (^)(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(error); + } + ++i; + }] distrustPeerIDsWithContainer:container context:context peerIDs:peerIDs reply:reply]; + } while (retry); +} + +- (void)trustStatusWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(TrustedPeersHelperEgoPeerStatus *status, + NSError* _Nullable error))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; + }] trustStatusWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)resetWithContainer:(NSString *)container + context:(NSString *)context + resetReason:(CuttlefishResetReason)reason + reply:(void (^)(NSError * _Nullable error))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(error); + } + ++i; + }] resetWithContainer:container context:context resetReason:reason reply:reply]; + } while (retry); +} + +- (void)localResetWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSError * _Nullable error))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(error); + } + ++i; + }] localResetWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)setAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + allowedMachineIDs:(NSSet *)allowedMachineIDs + reply:(void (^)(BOOL listDifferences, NSError * _Nullable error))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(NO, error); + } + ++i; + }] setAllowedMachineIDsWithContainer:container context:context allowedMachineIDs:allowedMachineIDs reply:reply]; + } while (retry); +} + +- (void)addAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + machineIDs:(NSArray *)machineIDs + reply:(void (^)(NSError * _Nullable error))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(error); + } + ++i; + }] addAllowedMachineIDsWithContainer:container + context:context + machineIDs:machineIDs + reply:reply]; + } while (retry); +} + +- (void)removeAllowedMachineIDsWithContainer:(NSString *)container + context:(NSString *)context + machineIDs:(NSArray *)machineIDs + reply:(void (^)(NSError * _Nullable error))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(error); + } + ++i; + }] removeAllowedMachineIDsWithContainer:container context:context machineIDs:machineIDs reply:reply]; + } while (retry); +} + +- (void)fetchEgoEpochWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(unsigned long long epoch, + NSError * _Nullable error))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(0, error); + } + ++i; + }] fetchEgoEpochWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)prepareWithContainer:(NSString *)container + context:(NSString *)context + epoch:(unsigned long long)epoch + machineID:(NSString *)machineID + bottleSalt:(NSString *)bottleSalt + bottleID:(NSString *)bottleID + modelID:(NSString *)modelID + deviceName:(nullable NSString*)deviceName + serialNumber:(NSString *)serialNumber + osVersion:(NSString *)osVersion + policyVersion:(nullable NSNumber *)policyVersion + policySecrets:(nullable NSDictionary *)policySecrets + signingPrivKeyPersistentRef:(nullable NSData *)spkPr + encPrivKeyPersistentRef:(nullable NSData*)epkPr + reply:(void (^)(NSString * _Nullable peerID, + NSData * _Nullable permanentInfo, + NSData * _Nullable permanentInfoSig, + NSData * _Nullable stableInfo, + NSData * _Nullable stableInfoSig, + NSError * _Nullable error))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, nil, nil, nil, nil, error); + } + ++i; + }] prepareWithContainer:container context:context epoch:epoch machineID:machineID bottleSalt:bottleSalt bottleID:bottleID modelID:modelID deviceName:deviceName serialNumber:serialNumber osVersion:osVersion policyVersion:policyVersion policySecrets:policySecrets signingPrivKeyPersistentRef:spkPr encPrivKeyPersistentRef:epkPr reply:reply]; + } while (retry); +} + +- (void)establishWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)viewKeySets + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(nullable NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] establishWithContainer:container context:context ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)vouchWithContainer:(NSString *)container + context:(NSString *)context + peerID:(NSString *)peerID + permanentInfo:(NSData *)permanentInfo + permanentInfoSig:(NSData *)permanentInfoSig + stableInfo:(NSData *)stableInfo + stableInfoSig:(NSData *)stableInfoSig + ckksKeys:(NSArray *)viewKeySets + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] vouchWithContainer:container context:context peerID:peerID permanentInfo:permanentInfo permanentInfoSig:permanentInfoSig stableInfo:stableInfo stableInfoSig:stableInfoSig ckksKeys:viewKeySets reply:reply]; + } while (retry); +} + + +- (void)preflightVouchWithBottleWithContainer:(nonnull NSString *)container + context:(nonnull NSString *)context + bottleID:(nonnull NSString *)bottleID + reply:(nonnull void (^)(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; + }] preflightVouchWithBottleWithContainer:container + context:context + bottleID:bottleID + reply:reply]; + } while (retry); +} + +- (void)vouchWithBottleWithContainer:(NSString *)container + context:(NSString *)context + bottleID:(NSString*)bottleID + entropy:(NSData*)entropy + bottleSalt:(NSString*)bottleSalt + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] vouchWithBottleWithContainer:container context:context bottleID:bottleID entropy:entropy bottleSalt:bottleSalt tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)vouchWithRecoveryKeyWithContainer:(NSString *)container + context:(NSString *)context + recoveryKey:(NSString*)recoveryKey + salt:(NSString*)salt + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] vouchWithRecoveryKeyWithContainer:container context:context recoveryKey:recoveryKey salt:salt tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)joinWithContainer:(NSString *)container + context:(NSString *)context + voucherData:(NSData *)voucherData + voucherSig:(NSData *)voucherSig + ckksKeys:(NSArray *)viewKeySets + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] joinWithContainer:container context:context voucherData:voucherData voucherSig:voucherSig ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)preflightPreapprovedJoinWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(BOOL launchOkay, + NSError * _Nullable error))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(NO, error); + } + ++i; + }] preflightPreapprovedJoinWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)attemptPreapprovedJoinWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)ckksKeys + tlkShares:(NSArray *)tlkShares + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSString * _Nullable peerID, + NSArray* _Nullable keyHierarchyRecords, + NSError * _Nullable error))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, nil, error); + } + ++i; + }] attemptPreapprovedJoinWithContainer:container context:context ckksKeys:ckksKeys tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)updateWithContainer:(NSString *)container + context:(NSString *)context + deviceName:(nullable NSString *)deviceName + serialNumber:(nullable NSString *)serialNumber + osVersion:(nullable NSString *)osVersion + policyVersion:(nullable NSNumber *)policyVersion + policySecrets:(nullable NSDictionary *)policySecrets + reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState, NSError * _Nullable error))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; + }] updateWithContainer:container context:context deviceName:deviceName serialNumber:serialNumber osVersion:osVersion policyVersion:policyVersion policySecrets:policySecrets reply:reply]; + } while (retry); +} + +- (void)setPreapprovedKeysWithContainer:(NSString *)container + context:(NSString *)context + preapprovedKeys:(NSArray *)preapprovedKeys + reply:(void (^)(NSError * _Nullable error))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(error); + } + ++i; + }] setPreapprovedKeysWithContainer:container context:context preapprovedKeys:preapprovedKeys reply:reply]; + } while (retry); +} + +- (void)updateTLKsWithContainer:(NSString *)container + context:(NSString *)context + ckksKeys:(NSArray *)ckksKeys + tlkShares:(NSArray *)tlkShares + reply:(void (^)(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error))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; + }] updateTLKsWithContainer:container context:context ckksKeys:ckksKeys tlkShares:tlkShares reply:reply]; + } while (retry); +} + +- (void)fetchViableBottlesWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSArray* _Nullable sortedBottleIDs, NSArray* _Nullable sortedPartialBottleIDs, NSError* _Nullable error))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, nil, error); + } + ++i; + }] fetchViableBottlesWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchEscrowContentsWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSData* _Nullable entropy, + NSString* _Nullable bottleID, + NSData* _Nullable signingPublicKey, + NSError* _Nullable error))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, nil, nil, error); + } + ++i; + }] fetchEscrowContentsWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchPolicyDocumentsWithContainer:(NSString*)container + context:(NSString*)context + keys:(NSDictionary*)keys + reply:(void (^)(NSDictionary*>* _Nullable entries, + NSError * _Nullable error))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; + }] fetchPolicyDocumentsWithContainer:container context:context keys:keys reply:reply]; + } while (retry); +} + +- (void)fetchPolicyWithContainer:(NSString*)container + context:(NSString*)context + reply:(void (^)(TPPolicy * _Nullable policy, + NSError * _Nullable error))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; + }] fetchPolicyWithContainer:container context:context reply:reply]; + } while (retry); +} + + +- (void)validatePeersWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSDictionary * _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; + }] validatePeersWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)fetchTrustStateWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(TrustedPeersHelperPeerState* _Nullable selfPeerState, + NSArray* _Nullable trustedPeers, + NSError* _Nullable error))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, nil, error); + } + ++i; + }] fetchTrustStateWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)setRecoveryKeyWithContainer:(NSString *)container + context:(NSString *)context + recoveryKey:(NSString *)recoveryKey + salt:(NSString *)salt + ckksKeys:(NSArray *)ckksKeys + reply:(void (^)(NSError* _Nullable error))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(error); + } + ++i; + }] setRecoveryKeyWithContainer:container context:context recoveryKey:recoveryKey salt:salt ckksKeys:ckksKeys reply:reply]; + } while (retry); +} + +- (void)reportHealthWithContainer:(NSString *)container + context:(NSString *)context + stateMachineState:(NSString *)state + trustState:(NSString *)trustState + reply:(void (^)(NSError* _Nullable error))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(error); + } + ++i; + }] reportHealthWithContainer:container context:context stateMachineState:state trustState:trustState reply:reply]; + } while (retry); +} + +- (void)pushHealthInquiryWithContainer:(NSString *)container + context:(NSString *)context + reply:(void (^)(NSError* _Nullable error))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(error); + } + ++i; + }] pushHealthInquiryWithContainer:container context:context reply:reply]; + } while (retry); +} + +- (void)getViewsWithContainer:(NSString *)container + context:(NSString *)context + inViews:(NSArray*)inViews + reply:(void (^)(NSArray* _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; + }] getViewsWithContainer:container context:context inViews:inViews reply:reply]; + } while (retry); +} + +- (void)requestHealthCheckWithContainer:(NSString *)container + context:(NSString *)context + requiresEscrowCheck:(BOOL)requiresEscrowCheck + reply:(void (^)(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, 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(NO, NO, NO, error); + } + ++i; + }] requestHealthCheckWithContainer:container context:context requiresEscrowCheck:requiresEscrowCheck reply:reply]; + } while (retry); +} +@end diff --git a/keychain/ot/OTBottledPeer.h b/keychain/ot/OTBottledPeer.h deleted file mode 100644 index 3d84714c..00000000 --- a/keychain/ot/OTBottledPeer.h +++ /dev/null @@ -1,59 +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 OCTAGON -#import -#import - -#import "OTEscrowKeys.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTBottledPeer : NSObject - -@property (nonatomic, readonly) NSString* peerID; -@property (nonatomic, readonly) NSString* spID; -@property (nonatomic, readonly) SFECKeyPair* peerSigningKey; -@property (nonatomic, readonly) SFECKeyPair* peerEncryptionKey; -@property (nonatomic, readonly) NSData* data; - -// Given a peer's details including private key material, and -// the keys generated from the escrow secret, encrypt the peer private keys, -// make a bottled peer object and serialize it into data. -- (nullable instancetype) initWithPeerID:(NSString * _Nullable)peerID - spID:(NSString * _Nullable)spID - peerSigningKey:(SFECKeyPair *)peerSigningKey - peerEncryptionKey:(SFECKeyPair *)peerEncryptionKey - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -// Deserialize a bottle and decrypt the contents (peer keys) -// using the keys generated from the escrow secret. -- (nullable instancetype) initWithData:(NSData *)data - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END - -#endif diff --git a/keychain/ot/OTBottledPeer.m b/keychain/ot/OTBottledPeer.m deleted file mode 100644 index 69e07cf9..00000000 --- a/keychain/ot/OTBottledPeer.m +++ /dev/null @@ -1,205 +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 "OTBottledPeer.h" - -#if OCTAGON -#import -#import -#import -#import -#import - -#import - -#import -#import -#import - -#import - -#import - -#if 0 -#import "OTBottle.h" -#import "OTBottleContents.h" -#endif - -#import "OTDefines.h" -#import "OTPrivateKey.h" -#import "OTPrivateKey+SF.h" -#import "OTAuthenticatedCiphertext.h" -#import "OTAuthenticatedCiphertext+SF.h" - -@interface OTBottledPeer () - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) SFECKeyPair* peerEncryptionKey; -@property (nonatomic, strong) NSData* data; - -@end - -@implementation OTBottledPeer - -+ (SFAuthenticatedEncryptionOperation *) encryptionOperation -{ - SFAESKeySpecifier *keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256]; - return [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:keySpecifier]; -} - -// Given a peer's details including private key material, and -// the keys generated from the escrow secret, encrypt the peer private keys, -// make a bottled peer object and serialize it into data. -- (nullable instancetype) initWithPeerID:(NSString * _Nullable)peerID - spID:(NSString * _Nullable)spID - peerSigningKey:(SFECKeyPair *)peerSigningKey - peerEncryptionKey:(SFECKeyPair *)peerEncryptionKey - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - self = [super init]; - if (self) { -#if 0 - // Serialize the peer private keys into "contents" - OTBottleContents *contentsObj = [[OTBottleContents alloc] init]; - contentsObj.peerSigningPrivKey = [OTPrivateKey fromECKeyPair:peerSigningKey]; - contentsObj.peerEncryptionPrivKey = [OTPrivateKey fromECKeyPair:peerEncryptionKey]; - NSData *clearContentsData = contentsObj.data; - - // Encrypt the contents - SFAuthenticatedEncryptionOperation *op = [OTBottledPeer encryptionOperation]; - SFAuthenticatedCiphertext* cipher = [op encrypt:clearContentsData withKey:escrowKeys.symmetricKey error:error]; - if (!cipher) { - return nil; - } - - // Serialize the whole thing - OTBottle *obj = [[OTBottle alloc] init]; - obj.peerID = peerID; - obj.spID = spID; - obj.escrowedSigningSPKI = [escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]; - obj.escrowedEncryptionSPKI = [escrowKeys.encryptionKey.publicKey encodeSubjectPublicKeyInfo]; - obj.peerSigningSPKI = [peerSigningKey.publicKey encodeSubjectPublicKeyInfo]; - obj.peerEncryptionSPKI = [peerEncryptionKey.publicKey encodeSubjectPublicKeyInfo]; - obj.contents = [OTAuthenticatedCiphertext fromSFAuthenticatedCiphertext:cipher]; - - _peerID = [peerID copy]; - _spID = [spID copy]; - _peerSigningKey = peerSigningKey; - _peerEncryptionKey = peerEncryptionKey; - _data = obj.data; -#endif - } - return self; -} - -// Deserialize a bottle and decrypt the contents (peer keys) -// using the keys generated from the escrow secret. -- (nullable instancetype) initWithData:(NSData *)data - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - self = [super init]; - if (self) { -#if 0 - NSError* localError =nil; - // Deserialize the whole thing - OTBottle *obj = [[OTBottle alloc] initWithData:data]; - if (!obj) { - secerror("octagon: failed to deserialize data into OTBottle"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorDeserializationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}]; - } - return nil; - - - // Decrypt contents - SFAuthenticatedEncryptionOperation *op = [OTBottledPeer encryptionOperation]; - SFAuthenticatedCiphertext* ciphertext = [obj.contents asSFAuthenticatedCiphertext]; - NSData* clearContentsData = [op decrypt:ciphertext withKey:escrowKeys.symmetricKey error:&localError]; - if (!clearContentsData || clearContentsData.length == 0) { - secerror("octagon: could not decrypt bottle contents: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - - // Deserialize contents into private peer keys - OTBottleContents *contentsObj = [[OTBottleContents alloc] initWithData:clearContentsData]; - if (!contentsObj) { - secerror("octagon: could not deserialize bottle contents"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorDeserializationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle contents"}]; - } - return nil; - } - - _peerID = obj.peerID; - _spID = obj.spID; - if (self.keyType != OTPrivateKey_KeyType_EC_NIST_CURVES) { - return nil; - } - return [[SFECKeyPair alloc] initWithSecKey:[EscrowKeys createSecKey:self.keyData]]; - - _peerSigningKey = [contentsObj.peerSigningPrivKey asECKeyPair]; - _peerEncryptionKey = [contentsObj.peerEncryptionPrivKey asECKeyPair]; - if (!_peerSigningKey || !_peerEncryptionKey) { - secerror("octagon: could not get private EC keys from bottle contents"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to instantiate octagon peer keys"}]; - } - return nil; - } - _data = [data copy]; - - SFECPublicKey *peerSigningPubKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:obj.peerSigningSPKI]; - SFECPublicKey *peerEncryptionPubKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:obj.peerEncryptionSPKI]; - - // Check the private keys match the public keys - if (![_peerSigningKey.publicKey isEqual:peerSigningPubKey]) { - secerror("octagon: public and private peer signing keys do not match"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"public and private peer signing keys do not match"}]; - } - return nil; - } - if (![_peerEncryptionKey.publicKey isEqual:peerEncryptionPubKey]) { - secerror("octagon: public and private peer encryption keys do not match"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorPrivateKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"public and private peer encryption keys do not match"}]; - } - return nil; - } -#endif - } - return self; -} - -@end - -#endif - - diff --git a/keychain/ot/OTBottledPeerRecord.h b/keychain/ot/OTBottledPeerRecord.h deleted file mode 100644 index 18390f91..00000000 --- a/keychain/ot/OTBottledPeerRecord.h +++ /dev/null @@ -1,44 +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 OCTAGON - -#import - -@interface OTBottledPeerRecord : NSObject - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) NSData* bottle; -@property (nonatomic, strong) NSString* escrowRecordID; -@property (nonatomic, strong) NSData* escrowedSigningSPKI; -@property (nonatomic, strong) NSData* peerSigningSPKI; -@property (nonatomic, strong) NSData* signatureUsingEscrowKey; -@property (nonatomic, strong) NSData* signatureUsingPeerKey; -@property (nonatomic, strong) NSData* encodedRecord; -@property (nonatomic, readonly) NSString* recordName; -@property (nonatomic, strong) NSString* launched; - -+ (NSString*) constructRecordID:(NSString*)escrowRecordID escrowSigningSPKI:(NSData*)escrowSigningSPKI; - -@end -#endif diff --git a/keychain/ot/OTBottledPeerRecord.m b/keychain/ot/OTBottledPeerRecord.m deleted file mode 100644 index 5dd5f270..00000000 --- a/keychain/ot/OTBottledPeerRecord.m +++ /dev/null @@ -1,52 +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 OCTAGON -#import "OTBottledPeerRecord.h" -#import -#import -#import - -static NSString* OTCKRecordName = @"bp-"; - -@implementation OTBottledPeerRecord - --(NSString*) recordName -{ - return [OTBottledPeerRecord constructRecordID:self.escrowRecordID escrowSigningSPKI:self.escrowedSigningSPKI]; -} - -+ (NSString*) constructRecordID:(NSString*)escrowRecordID escrowSigningSPKI:(NSData*)escrowSigningSPKI -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [escrowSigningSPKI length], [escrowSigningSPKI bytes], [result mutableBytes]); - - NSString* hash = [result base64EncodedStringWithOptions:0]; - - return [NSString stringWithFormat:@"%@-spid:%@-%@", OTCKRecordName, escrowRecordID, hash]; -} - -@end -#endif diff --git a/keychain/ot/OTBottledPeerSigned.h b/keychain/ot/OTBottledPeerSigned.h deleted file mode 100644 index c21599e2..00000000 --- a/keychain/ot/OTBottledPeerSigned.h +++ /dev/null @@ -1,64 +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 OCTAGON -#import -#import "OTBottledPeer.h" -#import "OTBottledPeerRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTBottledPeerSigned : NSObject -@property (nonatomic, readonly) OTBottledPeer* bp; -@property (nonatomic, readonly) NSData* signatureUsingEscrowKey; -@property (nonatomic, readonly) NSData* signatureUsingPeerKey; -@property (nonatomic, readonly) NSData* escrowSigningSPKI; - -- (instancetype) init NS_UNAVAILABLE; - -// Create signatures -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - escrowedSigningKey:(SFECKeyPair *)escrowedSigningKey - peerSigningKey:(SFECKeyPair *)peerSigningKey - error:(NSError**)error; - -// Verify signatures, or return nil -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - signatureUsingEscrow:(NSData*)signatureUsingEscrow - signatureUsingPeerKey:(NSData*)signatureUsingPeerKey - escrowedSigningPubKey:(SFECPublicKey *)escrowedSigningPubKey - error:(NSError**)error; - -// Convenience wrapper, verifies signatures -- (nullable instancetype) initWithBottledPeerRecord:(OTBottledPeerRecord *)record - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error; - -- (OTBottledPeerRecord *)asRecord:(NSString*)escrowRecordID; -+ (BOOL) verifyBottleSignature:(NSData*)data signature:(NSData*)signature key:(_SFECPublicKey*) pubKey error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END - -#endif diff --git a/keychain/ot/OTBottledPeerSigned.m b/keychain/ot/OTBottledPeerSigned.m deleted file mode 100644 index eeef3d06..00000000 --- a/keychain/ot/OTBottledPeerSigned.m +++ /dev/null @@ -1,165 +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 OCTAGON -#import -#import "OTBottledPeer.h" -#import "OTBottledPeerSigned.h" -#import "OTIdentity.h" - -#import -#import -#import -#import -#import - -#import -#import -#import - -#include - -@interface OTBottledPeerSigned () -@property (nonatomic, strong) OTBottledPeer* bp; -@property (nonatomic, strong) NSData* signatureUsingEscrowKey; -@property (nonatomic, strong) NSData* signatureUsingPeerKey; -@property (nonatomic, strong) NSData* escrowSigningPublicKey; -@end - -@implementation OTBottledPeerSigned - -// Create signatures -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - escrowedSigningKey:(SFECKeyPair *)escrowedSigningKey - peerSigningKey:(SFECKeyPair *)peerSigningKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _bp = bp; - _escrowSigningSPKI = [escrowedSigningKey.publicKey encodeSubjectPublicKeyInfo]; - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - _signatureUsingEscrowKey = [xso sign:bp.data withKey:escrowedSigningKey error:error].signature; - if (!_signatureUsingEscrowKey) { - return nil; - } - _signatureUsingPeerKey = [xso sign:bp.data withKey:peerSigningKey error:error].signature; - if (!_signatureUsingPeerKey) { - return nil; - } - } - return self; -} - --(NSString*) escrowSigningPublicKeyHash -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [self.escrowSigningPublicKey length], [self.escrowSigningPublicKey bytes], [result mutableBytes]); - - return [result base64EncodedStringWithOptions:0]; -} - -// Verify signatures, or return nil -- (nullable instancetype) initWithBottledPeer:(OTBottledPeer*)bp - signatureUsingEscrow:(NSData*)signatureUsingEscrow - signatureUsingPeerKey:(NSData*)signatureUsingPeerKey - escrowedSigningPubKey:(SFECPublicKey *)escrowedSigningPubKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _bp = bp; - _escrowSigningSPKI = [escrowedSigningPubKey encodeSubjectPublicKeyInfo]; - _signatureUsingPeerKey = signatureUsingPeerKey; - _signatureUsingEscrowKey = signatureUsingEscrow; - _escrowSigningPublicKey = [escrowedSigningPubKey keyData]; - - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - - SFSignedData *escrowSigned = [[SFSignedData alloc] initWithData:bp.data signature:signatureUsingEscrow]; - if (![xso verify:escrowSigned withKey:escrowedSigningPubKey error:error]) { - return nil; - } - SFSignedData *peerSigned = [[SFSignedData alloc] initWithData:bp.data signature:signatureUsingPeerKey]; - if (![xso verify:peerSigned withKey:bp.peerSigningKey.publicKey error:error]) { - return nil; - } - //stuff restored keys in the keychain - [OTIdentity storeOctagonIdentityIntoKeychain:self.bp.peerSigningKey restoredEncryptionKey:self.bp.peerEncryptionKey escrowSigningPubKeyHash:self.escrowSigningPublicKeyHash restoredPeerID:self.bp.spID error:error]; - } - return self; -} - -+ (SFEC_X962SigningOperation*) signingOperation -{ - SFECKeySpecifier *keySpecifier = [[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]; - id digestOperation = [[SFSHA384DigestOperation alloc] init]; - return [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:keySpecifier digestOperation:digestOperation]; -} - -+ (BOOL) verifyBottleSignature:(NSData*)data signature:(NSData*)signature key:(_SFECPublicKey*) pubKey error:(NSError**)error -{ - SFEC_X962SigningOperation* xso = [OTBottledPeerSigned signingOperation]; - - SFSignedData *peerSigned = [[SFSignedData alloc] initWithData:data signature:signature]; - - return ([xso verify:peerSigned withKey:pubKey error:error] != nil); - -} - -- (nullable instancetype) initWithBottledPeerRecord:(OTBottledPeerRecord *)record - escrowKeys:(OTEscrowKeys *)escrowKeys - error:(NSError**)error -{ - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithData:record.bottle - escrowKeys:escrowKeys - error:error]; - if (!bp) { - return nil; - } - return [self initWithBottledPeer:bp - signatureUsingEscrow:record.signatureUsingEscrowKey - signatureUsingPeerKey:record.signatureUsingPeerKey - escrowedSigningPubKey:escrowKeys.signingKey.publicKey - error:error]; -} - -- (OTBottledPeerRecord *)asRecord:(NSString*)escrowRecordID -{ - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.spID = self.bp.spID; - rec.escrowRecordID = [escrowRecordID copy]; - rec.peerSigningSPKI = [self.bp.peerSigningKey.publicKey encodeSubjectPublicKeyInfo]; - rec.escrowedSigningSPKI = self.escrowSigningSPKI; - rec.bottle = self.bp.data; - rec.signatureUsingPeerKey = self.signatureUsingPeerKey; - rec.signatureUsingEscrowKey = self.signatureUsingEscrowKey; - rec.launched = @"NO"; - return rec; -} - -@end -#endif - diff --git a/keychain/ot/OTBottledPeerState.h b/keychain/ot/OTBottledPeerState.h deleted file mode 100644 index eb0ec436..00000000 --- a/keychain/ot/OTBottledPeerState.h +++ /dev/null @@ -1,59 +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 OCTAGON - -#ifndef OTBottledPeerState_h -#define OTBottledPeerState_h - -#import - -NS_ASSUME_NONNULL_BEGIN - -/* Bottled Peer States */ -@protocol SecOTBottledPeerState -@end -typedef NSString OTBottledPeerState; - -// Octagon Trust currently logged out -extern OTBottledPeerState* const SecOTBottledPeerStateLoggedOut; - -// Octagon Trust currently signed in -extern OTBottledPeerState* const SecOTBottledPeerStateSignedIn; - -// Octagon Trust: check bottle states -extern OTBottledPeerState* const SecOTBottledPeerStateInventoryCheck; - -// Octagon Trust: update bottles for current peerid with current octagon keys -extern OTBottledPeerState* const SecOTBottledPeerStateUpdateBottles; - -// Octagon Trust: bottles exist for the current octagon key set and have been writte to cloudkit -extern OTBottledPeerState* const SecOTBottledPeerStateCleanBottles; - -// Octagon Trust: bottles for current peerid have been updated and persited locally, but not commited to cloudkit -extern OTBottledPeerState* const SecOTBottledPeerStateDirtyBottles; - -NS_ASSUME_NONNULL_END - -#endif /* OTBottledPeerState_h */ -#endif diff --git a/keychain/ot/OTBottledPeerState.m b/keychain/ot/OTBottledPeerState.m deleted file mode 100644 index 3c697b2e..00000000 --- a/keychain/ot/OTBottledPeerState.m +++ /dev/null @@ -1,35 +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 OCTAGON - -#import "keychain/ot/OTBottledPeerState.h" - -OTBottledPeerState* const SecOTBottledPeerStateLoggedOut = (OTBottledPeerState*) @"loggedout"; -OTBottledPeerState* const SecOTBottledPeerStateSignedIn = (OTBottledPeerState*) @"signedin"; -OTBottledPeerState* const SecOTBottledPeerStateInventoryCheck = (OTBottledPeerState*) @"inventorycheck"; -OTBottledPeerState* const SecOTBottledPeerStateUpdateBottles = (OTBottledPeerState*) @"updatebottles"; -OTBottledPeerState* const SecOTBottledPeerStateCleanBottles = (OTBottledPeerState*) @"cleanbottles"; -OTBottledPeerState* const SecOTBottledPeerStateDirtyBottles = (OTBottledPeerState*) @"dirtybottles"; - -#endif diff --git a/keychain/ot/OTCheckHealthOperation.m b/keychain/ot/OTCheckHealthOperation.m index b1edee94..b76ce462 100644 --- a/keychain/ot/OTCheckHealthOperation.m +++ b/keychain/ot/OTCheckHealthOperation.m @@ -25,6 +25,7 @@ #import "keychain/ot/OTCheckHealthOperation.h" #import "keychain/ot/OTOperationDependencies.h" +#import "keychain/ot/OTStates.h" #import "keychain/ot/ObjCImprovements.h" #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import @@ -146,31 +147,40 @@ } WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-health: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - return; - - }] requestHealthCheckWithContainer:self.deps.containerName - context:self.deps.contextID - requiresEscrowCheck: [self checkIfPasscodeIsSetForDevice] - reply:^(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError *error) { - STRONGIFY(self); - if(error) { - secerror("octagon-health: error: %@", error); - self.error = error; - } else { - secnotice("octagon-health", "cuttlefish came back with these suggestions\n: post repair? %d\n, post escrow? %d\n, reset octagon? %d", postRepairCFU, postEscrowCFU, resetOctagon); - self.postEscrowCFU = postEscrowCFU; - self.postRepairCFU = postRepairCFU; - self.resetOctagon = resetOctagon; - - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishOp]; - }]; + [self.deps.cuttlefishXPCWrapper requestHealthCheckWithContainer:self.deps.containerName + context:self.deps.contextID + requiresEscrowCheck: [self checkIfPasscodeIsSetForDevice] + reply:^(BOOL postRepairCFU, BOOL postEscrowCFU, BOOL resetOctagon, NSError *error) { + STRONGIFY(self); + if(error) { + secerror("octagon-health: error: %@", error); + self.error = error; + + [self runBeforeGroupFinished:self.finishOp]; + return; + } else { + secnotice("octagon-health", "cuttlefish came back with these suggestions\n: post repair? %d\n, post escrow? %d\n, reset octagon? %d", postRepairCFU, postEscrowCFU, resetOctagon); + [self handleRepairSuggestions:postRepairCFU + postEscrowCFU:postEscrowCFU + resetOctagon:resetOctagon]; + } + }]; +} + +- (void)handleRepairSuggestions:(BOOL)postRepairCFU postEscrowCFU:(BOOL)postEscrowCFU resetOctagon:(BOOL)resetOctagon +{ + self.postEscrowCFU = postEscrowCFU; + self.postRepairCFU = postRepairCFU; + self.resetOctagon = resetOctagon; + + if (resetOctagon) { + secnotice("octagon-health", "Resetting Octagon as per Cuttlefish request"); + self.nextState = OctagonStateHealthCheckReset; + } else { + self.nextState = self.intendedState; + } + + [self runBeforeGroupFinished:self.finishOp]; } @end diff --git a/keychain/ot/OTClientStateMachine.m b/keychain/ot/OTClientStateMachine.m index 8570fa0d..32f8f044 100644 --- a/keychain/ot/OTClientStateMachine.m +++ b/keychain/ot/OTClientStateMachine.m @@ -41,7 +41,6 @@ #import "keychain/ot/ObjCImprovements.h" #import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTPrepareOperation.h" #import "keychain/ot/OTSOSAdapter.h" @@ -304,9 +303,11 @@ NSDictionary* OctagonClientStateMap(void) { reply:(void (^)(uint64_t epoch, NSError * _Nullable error))reply { - OTEpochOperation* pendingOp = [[OTEpochOperation alloc] initForCuttlefishContext:cuttlefishContext - intendedState:OctagonStateAcceptorAwaitingIdentity - errorState:OctagonStateAcceptorDone]; + OTEpochOperation* pendingOp = [[OTEpochOperation alloc] init:self.containerName + contextID:self.contextID + intendedState:OctagonStateAcceptorAwaitingIdentity + errorState:OctagonStateAcceptorDone + cuttlefishXPCWrapper:cuttlefishContext.cuttlefishXPCWrapper]; OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"rpcEpoch" sourceStates:[NSSet setWithArray:@[OctagonStateAcceptorBeginClientJoin]] diff --git a/keychain/ot/OTClientVoucherOperation.m b/keychain/ot/OTClientVoucherOperation.m index 0f3d4039..6257c0d2 100644 --- a/keychain/ot/OTClientVoucherOperation.m +++ b/keychain/ot/OTClientVoucherOperation.m @@ -96,34 +96,29 @@ secnotice("octagon", "vouching with %d keysets", (int)viewKeySets.count); - [[self.operationDependencies.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] vouchWithContainer:self.deviceInfo.containerName - context:self.deviceInfo.contextID - peerID:self.peerID - permanentInfo:self.permanentInfo - permanentInfoSig:self.permanentInfoSig - stableInfo:self.stableInfo - stableInfoSig:self.stableInfoSig - ckksKeys:viewKeySets - reply:^(NSData * _Nullable voucher, - NSData * _Nullable voucherSig, - NSError * _Nullable error) - { - if(error){ - secerror("octagon: Error preparing voucher: %@", error); - self.error = error; - }else{ - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.operationDependencies.cuttlefishXPCWrapper vouchWithContainer:self.deviceInfo.containerName + context:self.deviceInfo.contextID + peerID:self.peerID + permanentInfo:self.permanentInfo + permanentInfoSig:self.permanentInfoSig + stableInfo:self.stableInfo + stableInfoSig:self.stableInfoSig + ckksKeys:viewKeySets + reply:^(NSData * _Nullable voucher, + NSData * _Nullable voucherSig, + NSError * _Nullable error) + { + STRONGIFY(self); + if(error){ + secerror("octagon: Error preparing voucher: %@", error); + self.error = error; + }else{ + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTClique.h b/keychain/ot/OTClique.h index 4e8100cc..77217221 100644 --- a/keychain/ot/OTClique.h +++ b/keychain/ot/OTClique.h @@ -42,6 +42,7 @@ typedef NS_ENUM(NSInteger, CliqueStatus) { #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -62,7 +63,6 @@ extern NSString* kSecEntitlementPrivateOctagonEscrow; @property (nonatomic, copy) NSString* altDSID; @property (nonatomic, strong, nullable) SFSignInAnalytics* analytics; - // Use this to inject your own OTControl object. It must be configured as synchronous. @property (nullable, strong) OTControl* otControl; // Use this to inject your own SecureBackup object. It must conform to the OctagonEscrowRecoverer protocol. @@ -86,11 +86,6 @@ extern NSString* kSecEntitlementPrivateOctagonEscrow; @property (nonatomic, assign) BOOL useCachedAccountStatus; @end -typedef NSString* OTCliqueCFUType NS_STRING_ENUM; -extern OTCliqueCFUType OTCliqueCFTypeRepair; -extern OTCliqueCFUType OTCliqueCFTypePasscode; -extern OTCliqueCFUType OTCliqueCFTypeUpgrade; - typedef NSString* OTCliqueCDPContextType NS_STRING_ENUM; extern OTCliqueCDPContextType OTCliqueCDPContextTypeNone; extern OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn; @@ -130,7 +125,20 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; * @return clique, returns a new clique instance * @param error, error gets filled if something goes horribly wrong */ -+ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error; ++ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error __deprecated_msg("use newFriendsWithContextData:resetReason:error: instead"); + +/* * +* @abstract Establish a new clique, reset protected data +* Reset the clique +* Delete backups +* Delete all CKKS data +* +* @param ctx, context containing parameters to setup OTClique +* @param resetReason, a reason that drives cdp to perform a reset +* @return clique, returns a new clique instance +* @param error, error gets filled if something goes horribly wrong +*/ ++ (instancetype _Nullable)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error; /* * @abstract Perform a SecureBackup escrow/keychain recovery and attempt to use the information therein to join this account. @@ -236,7 +244,7 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error; -- (NSArray*)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error; +- (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error; - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews; @@ -248,7 +256,7 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode; password:(NSData*)userPassword error:(NSError *__autoreleasing*)error; -- (NSArray*)copyPeerPeerInfo:(NSError *__autoreleasing*)error; +- (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error; - (BOOL)peersHaveViewsEnabled:(NSArray*)viewNames error:(NSError *__autoreleasing*)error; diff --git a/keychain/ot/OTClique.m b/keychain/ot/OTClique.m index 918077d4..8a6c33b3 100644 --- a/keychain/ot/OTClique.m +++ b/keychain/ot/OTClique.m @@ -61,10 +61,6 @@ SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain); #pragma clang diagnostic pop #endif -OTCliqueCFUType OTCliqueCFTypeRepair = @"typeRepair"; -OTCliqueCFUType OTCliqueCFTypePasscode = @"typePasscode"; -OTCliqueCFUType OTCliqueCFTypeUpgrade = @"typeUpgrade"; - OTCliqueCDPContextType OTCliqueCDPContextTypeNone = @"cdpContextTypeNone"; OTCliqueCDPContextType OTCliqueCDPContextTypeSignIn = @"cdpContextTypeSignIn"; OTCliqueCDPContextType OTCliqueCDPContextTypeRepair = @"cdpContextTypeRepair"; @@ -172,7 +168,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) + (BOOL)platformSupportsSOS { - return OctagonPlatformSupportsSOS(); + return (OctagonPlatformSupportsSOS() && OctagonIsSOSFeatureEnabled()); } // defaults write com.apple.security.octagon enable -bool YES @@ -237,7 +233,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique", "cliqueMemberIdentifier(octagon) received %@", retPeerID); } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef error = NULL; SOSPeerInfoRef me = SOSCCCopyMyPeerInfo(&error); retPeerID = (NSString*)CFBridgingRelease(CFRetainSafe(SOSPeerInfoGetPeerID(me))); @@ -286,7 +282,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) return success; } -- (BOOL)resetAndEstablish:(NSError**)error +- (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error { secnotice("clique-resetandestablish", "resetAndEstablish started"); @@ -298,7 +294,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) __block BOOL success = NO; __block NSError* localError = nil; - [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID reply:^(NSError * _Nullable operationError) { + [control resetAndEstablish:nil context:self.ctx.context altDSID:self.ctx.altDSID resetReason:resetReason reply:^(NSError * _Nullable operationError) { if(operationError) { secnotice("clique-resetandestablish", "resetAndEstablish returned an error: %@", operationError); @@ -318,16 +314,21 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) #endif // OCTAGON + (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data error:(NSError * __autoreleasing *)error +{ + return [OTClique newFriendsWithContextData:data resetReason:CuttlefishResetReasonUserInitiatedReset error:error]; +} + ++ (OTClique*)newFriendsWithContextData:(OTConfigurationContext*)data resetReason:(CuttlefishResetReason)resetReason error:(NSError * __autoreleasing *)error { #if OCTAGON secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid); bool result = false; - + OTClique* clique = [[OTClique alloc] initWithContextData:data error:error]; if(OctagonIsEnabled()) { NSError* localError = nil; - [clique resetAndEstablish:&localError]; + [clique resetAndEstablish:resetReason error:&localError]; if(localError) { secnotice("clique-newfriends", "account reset failed: %@", localError); @@ -340,7 +341,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef resetError = NULL; NSData* analyticsData = nil; if(data.analytics) { @@ -394,7 +395,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(recoverError) { secnotice("clique-recovery", "sbd escrow recovery failed: %@", recoverError); - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { if(recoverError.code == 17 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) { /* XXX */ secnotice("clique-recovery", "Can't restore legacy backup with no keybag. Resetting SOS to offering"); CFErrorRef blowItAwayError = NULL; @@ -482,7 +483,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(shouldResetOctagon) { secnotice("clique-recovery", "bottle %@ is not valid, resetting octagon", bottleID); NSError* resetError = nil; - [clique resetAndEstablish:&resetError]; + [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError]; if(resetError) { secnotice("clique-recovery", "failed to reset octagon: %@", resetError); } else{ @@ -576,7 +577,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef circleStatusError = NULL; sosStatus = kSOSCCError; if(configuration.useCachedAccountStatus){ @@ -701,7 +702,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) }]; } - if(OctagonPlatformSupportsSOS() && sosIdentifiers.count > 0) { + if([OTClique platformSupportsSOS] && sosIdentifiers.count >0) { CFErrorRef removeFriendError = NULL; NSData* analyticsData = nil; @@ -764,7 +765,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) result = !localError; } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { NSData* analyticsData = nil; if(self.ctx.analytics) { @@ -831,7 +832,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) secnotice("clique", "Received %lu Octagon peers", (unsigned long)localPeers.count); } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef peerErrorRef = NULL; NSMutableDictionary* peerMapping = [NSMutableDictionary dictionary]; NSArray* arrayOfPeerRefs = CFBridgingRelease(SOSCCCopyPeerPeerInfo(&peerErrorRef)); @@ -862,36 +863,56 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error { secnotice("clique-recovery", "joinAfterRestore for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef restoreError = NULL; + if([OTClique platformSupportsSOS]) { + CFErrorRef restoreError = NULL; - bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError); - if (error) { - *error = (NSError*)CFBridgingRelease(restoreError); + bool res = SOSCCRequestToJoinCircleAfterRestore(&restoreError); + if (error) { + *error = (NSError*)CFBridgingRelease(restoreError); + } else { + CFBridgingRelease(restoreError); + } + secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided"); + return res; } else { - CFBridgingRelease(restoreError); + secnotice("clique-recovery", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"join after restore unimplemented"}]; + } + return NO; } - secnotice("clique-recovery", "joinAfterRestore complete: %d %@", res, error ? *error : @"no error pointer provided"); - return res; } - (BOOL)safariPasswordSyncingEnabled:(NSError **)error { secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef viewErrorRef = NULL; + if([OTClique platformSupportsSOS]) { + CFErrorRef viewErrorRef = NULL; - SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef); + SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewErrorRef); - BOOL viewMember = result == kSOSCCViewMember; - if (error) { - *error = (NSError*)CFBridgingRelease(viewErrorRef); - } else { - CFBridgingRelease(viewErrorRef); - } + BOOL viewMember = result == kSOSCCViewMember; + if (error) { + *error = (NSError*)CFBridgingRelease(viewErrorRef); + } else { + CFBridgingRelease(viewErrorRef); + } - secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO"); + secnotice("clique-safari", "safariPasswordSyncingEnabled complete: %@", viewMember ? @"YES" : @"NO"); - return viewMember; + return viewMember; + } else { + secnotice("clique-safari", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"safari password syncing enabled unimplemented"}]; + } + return NO; + } } - (BOOL)isLastFriend:(NSError **)error @@ -903,63 +924,89 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)waitForInitialSync:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "waitForInitialSync for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef initialSyncErrorRef = NULL; - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCWaitForInitialSyncWithAnalytics((__bridge CFDataRef)analyticsData, &initialSyncErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef initialSyncErrorRef = NULL; + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCWaitForInitialSyncWithAnalytics((__bridge CFDataRef)analyticsData, &initialSyncErrorRef); + }else{ + result = SOSCCWaitForInitialSync(&initialSyncErrorRef); + } }else{ result = SOSCCWaitForInitialSync(&initialSyncErrorRef); } - }else{ - result = SOSCCWaitForInitialSync(&initialSyncErrorRef); - } - - BOOL initialSyncResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(initialSyncErrorRef); + + BOOL initialSyncResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(initialSyncErrorRef); + } else { + CFBridgingRelease(initialSyncErrorRef); + } + secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided"); + return initialSyncResult; } else { - CFBridgingRelease(initialSyncErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"wait for initial sync unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "waitForInitialSync waited: %d %@", initialSyncResult, error ? *error : @"no error pointer provided"); - return initialSyncResult; } -- (NSArray*)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error +- (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "copyViewUnawarePeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL; - CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef); - NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil); - if (error) { - *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef copyViewUnawarePeerInfoErrorRef = NULL; + CFArrayRef peerListRef = SOSCCCopyViewUnawarePeerInfo(©ViewUnawarePeerInfoErrorRef); + + NSArray* peerList = (peerListRef ? (NSArray*)(CFBridgingRelease(peerListRef)) : nil); + if (error) { + *error = (NSError*)CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + } else { + CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + } + return peerList; } else { - CFBridgingRelease(copyViewUnawarePeerInfoErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NULL"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"copy view unaware peer info unimplemented"}]; + } + return nil; } - return peerList; } - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews { secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCViewSetWithAnalytics((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews, (__bridge CFDataRef)analyticsData); + if([OTClique platformSupportsSOS]) { + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCViewSetWithAnalytics((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews, (__bridge CFDataRef)analyticsData); + }else{ + result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); + } }else{ result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); } - }else{ - result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews); - } - BOOL viewSetResult = (result == true); - return viewSetResult; + BOOL viewSetResult = (result == true); + return viewSetResult; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + return NO; + } } - (BOOL)setUserCredentialsAndDSID:(NSString*)userLabel @@ -967,38 +1014,48 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "setUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef setCredentialsErrorRef = NULL; - bool result = false; - if(self.ctx.analytics){ - NSError* encodingError = nil; - NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; - if(!encodingError && analyticsData){ - result = SOSCCSetUserCredentialsAndDSIDWithAnalytics((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - (__bridge CFDataRef)analyticsData, - &setCredentialsErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef setCredentialsErrorRef = NULL; + bool result = false; + if(self.ctx.analytics){ + NSError* encodingError = nil; + NSData* analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError]; + if(!encodingError && analyticsData){ + result = SOSCCSetUserCredentialsAndDSIDWithAnalytics((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + (__bridge CFDataRef)analyticsData, + &setCredentialsErrorRef); + }else{ + result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + &setCredentialsErrorRef); + } }else{ result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, (__bridge CFDataRef)userPassword, (__bridge CFStringRef)self.ctx.dsid, &setCredentialsErrorRef); } - }else{ - result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - &setCredentialsErrorRef); - } - BOOL setCredentialsResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef); + BOOL setCredentialsResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(setCredentialsErrorRef); + } else { + CFBridgingRelease(setCredentialsErrorRef); + } + secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef); + return setCredentialsResult; } else { - CFBridgingRelease(setCredentialsErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"set user credentials unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef); - return setCredentialsResult; } - (BOOL)tryUserCredentialsAndDSID:(NSString*)userLabel @@ -1006,60 +1063,91 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "tryUserCredentialsAndDSID for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef tryCredentialsErrorRef = NULL; - bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel, - (__bridge CFDataRef)userPassword, - (__bridge CFStringRef)self.ctx.dsid, - &tryCredentialsErrorRef); - BOOL tryCredentialsResult = (result == true); - if (error) { - *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef tryCredentialsErrorRef = NULL; + bool result = SOSCCTryUserCredentialsAndDSID((__bridge CFStringRef)userLabel, + (__bridge CFDataRef)userPassword, + (__bridge CFStringRef)self.ctx.dsid, + &tryCredentialsErrorRef); + + BOOL tryCredentialsResult = (result == true); + if (error) { + *error = (NSError*)CFBridgingRelease(tryCredentialsErrorRef); + } else { + CFBridgingRelease(tryCredentialsErrorRef); + } + secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef); + return tryCredentialsResult; } else { - CFBridgingRelease(tryCredentialsErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"try user credentials unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "tryUserCredentialsAndDSID results: %d %@", tryCredentialsResult, tryCredentialsErrorRef); - return tryCredentialsResult; - } -- (NSArray*)copyPeerPeerInfo:(NSError *__autoreleasing*)error +- (NSArray* _Nullable)copyPeerPeerInfo:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "copyPeerPeerInfo for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef copyPeerErrorRef = NULL; - CFArrayRef result = SOSCCCopyPeerPeerInfo(©PeerErrorRef); - NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil); + if([OTClique platformSupportsSOS]) { + CFErrorRef copyPeerErrorRef = NULL; + CFArrayRef result = SOSCCCopyPeerPeerInfo(©PeerErrorRef); - if (error) { - *error = (NSError*)CFBridgingRelease(copyPeerErrorRef); - } else { - CFBridgingRelease(copyPeerErrorRef); - } - secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList); + NSArray* peerList = (result ? (NSArray*)(CFBridgingRelease(result)) : nil); - return peerList; + if (error) { + *error = (NSError*)CFBridgingRelease(copyPeerErrorRef); + } else { + CFBridgingRelease(copyPeerErrorRef); + } + secnotice("clique-legacy", "copyPeerPeerInfo results: %@", peerList); + return peerList; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"copy peer peer info unimplemented"}]; + } + return nil; + } } - (BOOL)peersHaveViewsEnabled:(NSArray*)viewNames error:(NSError *__autoreleasing*)error { secnotice("clique-legacy", "peersHaveViewsEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - CFErrorRef viewsEnabledErrorRef = NULL; - BOOL viewsEnabledResult = NO; - CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef); - if(result){ - viewsEnabledResult = CFBooleanGetValue(result); - } - if (error) { - *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef); + if([OTClique platformSupportsSOS]) { + CFErrorRef viewsEnabledErrorRef = NULL; + BOOL viewsEnabledResult = NO; + + CFBooleanRef result = SOSCCPeersHaveViewsEnabled((__bridge CFArrayRef)viewNames, &viewsEnabledErrorRef); + if(result){ + viewsEnabledResult = CFBooleanGetValue(result); + } + if (error) { + *error = (NSError*)CFBridgingRelease(viewsEnabledErrorRef); + } else { + CFBridgingRelease(viewsEnabledErrorRef); + } + secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO"); + + return viewsEnabledResult; } else { - CFBridgingRelease(viewsEnabledErrorRef); + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + if(error){ + *error = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + userInfo:@{NSLocalizedDescriptionKey: @"peers have views enabled unimplemented"}]; + } + return NO; } - secnotice("clique-legacy", "peersHaveViewsEnabled results: %@", viewsEnabledResult ? @"YES" : @"NO"); - - return viewsEnabledResult; } - (BOOL)requestToJoinCircle:(NSError *__autoreleasing*)error @@ -1072,7 +1160,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) if(OctagonIsEnabled()) { NSError* localError = nil; - [self resetAndEstablish:&localError]; + [self resetAndEstablish:CuttlefishResetReasonLegacyJoinCircle error:&localError]; if(localError) { secnotice("clique-legacy", "account reset failed: %@", localError); @@ -1092,7 +1180,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) } #endif // OCTAGON - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { NSData* analyticsData = nil; if(self.ctx.analytics){ NSError* encodingError = nil; @@ -1119,11 +1207,17 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) - (BOOL)accountUserKeyAvailable { secnotice("clique-legacy", "accountUserKeyAvailable for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID); - BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL); - if (canAuthenticate == NO) { - secnotice("clique-legacy", "Security requires credentials..."); + + if([OTClique platformSupportsSOS]) { + BOOL canAuthenticate = (BOOL)SOSCCCanAuthenticate(NULL); + if (canAuthenticate == NO) { + secnotice("clique-legacy", "Security requires credentials..."); + } + return canAuthenticate; + } else { + secnotice("clique-legacy", "SOS disabled for this platform, returning NO"); + return NO; } - return canAuthenticate; } // MARK: SBD interfaces @@ -1266,7 +1360,7 @@ CliqueStatus OTCliqueStatusFromString(NSString* str) reply(nil, retError); return; } - if(OctagonPlatformSupportsSOS()) { + if([OTClique platformSupportsSOS]) { CFErrorRef registerError = nil; if (!SecRKRegisterBackupPublicKey(rk, ®isterError)) { secerror("octagon-setrecoverykey, SecRKRegisterBackupPublicKey() failed: %@", registerError); diff --git a/keychain/ot/OTCloudStore.h b/keychain/ot/OTCloudStore.h deleted file mode 100644 index 4b6ecb29..00000000 --- a/keychain/ot/OTCloudStore.h +++ /dev/null @@ -1,83 +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@ - */ -#ifndef OTCloudStore_h -#define OTCloudStore_h - -#if OCTAGON -#import "keychain/ot/OTLocalStore.h" - -#import -#import - -#import "keychain/ckks/CKKSZone.h" -#import "keychain/ckks/CloudKitDependencies.h" -#import "keychain/ckks/CKKSCloudKitClassDependencies.h" -#import "keychain/ckks/CKKSCondition.h" -#import "keychain/ckks/CKKSZoneChangeFetcher.h" -#import "keychain/ckks/CKKSNotifier.h" -#import "keychain/ckks/CKKSSQLDatabaseObject.h" -#import "keychain/ckks/CKKSRecordHolder.h" -#import "keychain/ckks/CKKSZoneModifier.h" -#import "OTBottledPeerRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTCloudStore : CKKSZone - -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) NSString* containerName; -@property (nonatomic, readonly) CKRecordID* recordID; -@property (nonatomic, readonly) CKKSResultOperation* viewSetupOperation; -@property CKKSCondition* loggedIn; -@property CKKSCondition* loggedOut; - - -- (instancetype) initWithContainer:(CKContainer*) container - zoneName:(NSString*)zoneName - accountTracker:(nullable CKKSAccountStateTracker*)accountTracker - reachabilityTracker:(nullable CKKSReachabilityTracker*)reachabilityTracker - localStore:(OTLocalStore*)localStore - contextID:(NSString*)contextID - dsid:(NSString*)dsid - zoneModifier:(CKKSZoneModifier*)zoneModifier - cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies - operationQueue:(nullable NSOperationQueue *)operationQueue; - - -- (BOOL) uploadBottledPeerRecord:(OTBottledPeerRecord *)bprecord - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error; -- (BOOL) downloadBottledPeerRecord:(NSError**)error; -- (BOOL) removeBottledPeerRecordID:(CKRecordID*)recordID error:(NSError**)error; -- (nullable NSArray*) retrieveListOfEligibleEscrowRecordIDs:(NSError**)error; - -- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification; -- (void)handleCKLogin; -- (BOOL) performReset:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END -#endif -#endif /* OTCloudStore_h */ diff --git a/keychain/ot/OTCloudStore.m b/keychain/ot/OTCloudStore.m deleted file mode 100644 index 241b732a..00000000 --- a/keychain/ot/OTCloudStore.m +++ /dev/null @@ -1,764 +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 OCTAGON - -#import -#import -#import -#import - -#import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTCloudStore.h" -#import "keychain/ot/OTCloudStoreState.h" -#import "keychain/ckks/CKKSZoneStateEntry.h" -#import "keychain/ckks/CKKS.h" -#import "keychain/ot/OTDefines.h" -#import "keychain/ckks/CKKSReachabilityTracker.h" -#import - -#import "keychain/ckks/CKKSZoneModifier.h" - - -NS_ASSUME_NONNULL_BEGIN - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordBottle = @"bottle"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordEncodedRecord = @"encodedRecord"; - -/* Octagon Table Names */ -static NSString* const contextTable = @"context"; -static NSString* const peerTable = @"peer"; -static NSString* const bottledPeerTable = @"bp"; - -/* Octagon Trust Schemas */ -static NSString* const octagonZoneName = @"OctagonTrustZone"; - -/* Octagon Cloud Kit defines */ -static NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* OTCKRecordName = @"bp-"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTCloudStore () -@property (nonatomic, strong) NSString* dsid; -@property (nonatomic, strong) NSString* containerName; -@property (nonatomic, strong) CKModifyRecordsOperation* modifyRecordsOperation; -@property (nonatomic, strong) CKDatabaseOperation* fetchRecordZoneChangesOperation; -@property (nonatomic, strong) NSOperationQueue *operationQueue; -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) CKKSResultOperation* viewSetupOperation; -@property (nonatomic, strong) NSError* error; -@end - -@class OctagonAPSReceiver; - -@interface OTCloudStore() - -@property CKDatabaseOperation* zoneCreationOperation; -@property CKDatabaseOperation* zoneDeletionOperation; -@property CKDatabaseOperation* zoneSubscriptionOperation; - -@property NSOperation* accountLoggedInDependency; - -@property NSHashTable* accountOperations; -@end - -@implementation OTCloudStore - -- (instancetype) initWithContainer:(CKContainer*) container - zoneName:(NSString*)zoneName - accountTracker:(nullable CKKSAccountStateTracker*)accountTracker - reachabilityTracker:(nullable CKKSReachabilityTracker*)reachabilityTracker - localStore:(OTLocalStore*)localStore - contextID:(NSString*)contextID - dsid:(NSString*)dsid - zoneModifier:(CKKSZoneModifier*)zoneModifier - cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies - operationQueue:(nullable NSOperationQueue *)operationQueue -{ - - self = [super initWithContainer:container - zoneName:zoneName - accountTracker:accountTracker - reachabilityTracker:reachabilityTracker - zoneModifier:zoneModifier - cloudKitClassDependencies:cloudKitClassDependencies]; - - if(self){ - if (!operationQueue) { - operationQueue = [[NSOperationQueue alloc] init]; - } - _contextID = [contextID copy]; - _localStore = localStore; - _containerName = OTCKContainerName; - _dsid = [dsid copy]; - _operationQueue = operationQueue; - self.queue = dispatch_queue_create([[NSString stringWithFormat:@"OctagonTrustQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL); - [self beginCloudKitOperation]; - } - return self; - -} - --(CKKSResultOperation*) otFetchAndProcessUpdates -{ - CKKSResultOperation* fetchOp = [CKKSResultOperation named:@"fetch-and-process-updates-watcher" withBlock:^{}]; - - __weak __typeof(self) weakSelf = self; - - [self dispatchSync: ^bool{ - - OTCloudStoreState* state = [OTCloudStoreState state: self.zoneName]; - - CKFetchRecordZoneChangesConfiguration* options = [[CKFetchRecordZoneChangesConfiguration alloc] init]; - options.previousServerChangeToken = state.changeToken; - - self.fetchRecordZoneChangesOperation = [[[self.cloudKitClassDependencies.fetchRecordZoneChangesOperationClass class] alloc] initWithRecordZoneIDs:@[self.zoneID] configurationsByRecordZoneID:@{self.zoneID : options}]; - - self.fetchRecordZoneChangesOperation.recordChangedBlock = ^(CKRecord *record) { - secinfo("octagon", "CloudKit notification: record changed(%@): %@", [record recordType], record); - __strong __typeof(weakSelf) strongSelf = weakSelf; - - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - fetchOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - - return; - } - if ([record.recordType isEqualToString:OTCKRecordBottledPeerType]) { - NSError* localError = nil; - - //write to localStore - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.bottle = record[OTCKRecordBottle]; - rec.spID = record[OTCKRecordSPID]; - rec.escrowRecordID = record[OTCKRecordEscrowRecordID]; - rec.escrowedSigningSPKI = record[OTCKRecordEscrowSigningSPKI]; - rec.peerSigningSPKI = record[OTCKRecordPeerSigningSPKI]; - rec.signatureUsingEscrowKey = record[OTCKRecordSignatureFromEscrow]; - rec.signatureUsingPeerKey = record[OTCKRecordSignatureFromPeerKey]; - rec.encodedRecord = [strongSelf recordToData:record]; - rec.launched = @"YES"; - BOOL result = [strongSelf.localStore insertBottledPeerRecord:rec escrowRecordID:record[OTCKRecordEscrowRecordID] error:&localError]; - if(!result || localError){ - secerror("Could not write bottled peer record:%@ to database: %@", record.recordID.recordName, localError); - fetchOp.error = localError; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - - } - secnotice("octagon", "fetched changes: %@", record); - } - }; - - self.fetchRecordZoneChangesOperation.recordWithIDWasDeletedBlock = ^(CKRecordID *RecordID, NSString *recordType) { - secinfo("octagon", "CloudKit notification: deleted record(%@): %@", recordType, RecordID); - }; - - self.fetchRecordZoneChangesOperation.recordZoneChangeTokensUpdatedBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - NSError* error = nil; - OTCloudStoreState* state = [OTCloudStoreState state: strongSelf.zoneName]; - secdebug("octagon", "Received a new server change token: %@ %@", serverChangeToken, clientChangeTokenData); - state.changeToken = serverChangeToken; - - if(error) { - secerror("octagon: Couldn't save new server change token: %@", error); - fetchOp.error = error; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - }; - - // Completion blocks don't count for dependencies. Use this intermediate operation hack instead. - NSBlockOperation* recordZoneChangesCompletedOperation = [[NSBlockOperation alloc] init]; - self.fetchRecordZoneChangesOperation.recordZoneFetchCompletionBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, BOOL moreComing, NSError * recordZoneError) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - return; - } - if(recordZoneError) { - secerror("octagon: FetchRecordZoneChanges(%@) error: %@", strongSelf.zoneName, recordZoneError); - fetchOp.error = recordZoneError; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - - // TODO: fetch state here - if(serverChangeToken) { - NSError* error = nil; - secdebug("octagon", "Zone change fetch complete: received a new server change token: %@ %@", serverChangeToken, clientChangeTokenData); - state.changeToken = serverChangeToken; - if(error) { - secerror("octagon: Couldn't save new server change token: %@", error); - fetchOp.error = error; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - } - } - secdebug("octagon", "Record zone fetch complete: changeToken=%@ error=%@", serverChangeToken, recordZoneError); - - [strongSelf.operationQueue addOperation: recordZoneChangesCompletedOperation]; - [strongSelf.operationQueue addOperation: fetchOp]; - - }; - self.fetchRecordZoneChangesOperation.fetchRecordZoneChangesCompletionBlock = ^(NSError * _Nullable operationError) { - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - secnotice("octagon", "received callback for released object"); - fetchOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - fetchOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerFetchRecords; - return; - } - secnotice("octagon", "Record zone changes fetch complete: error=%@", operationError); - }; - return true; - }]; - [self.database addOperation: self.fetchRecordZoneChangesOperation]; - - return fetchOp; -} - - -- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification -{ - secnotice("octagon", "received notify zone change. notification: %@", notification); - - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to fetch changes error:%@", op.error); - } - else{ - secnotice("octagon", "downloaded bottled peer records"); - } -} - --(BOOL) downloadBottledPeerRecord:(NSError**)error -{ - secnotice("octagon", "downloadBottledPeerRecord"); - BOOL result = NO; - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to fetch changes error:%@", op.error); - if(error){ - *error = op.error; - } - } - else{ - result = YES; - secnotice("octagon", "downloaded bottled peer records"); - } - return result; -} - -- (nullable NSArray*) retrieveListOfEligibleEscrowRecordIDs:(NSError**)error -{ - NSError* localError = nil; - - NSMutableArray* recordIDs = [NSMutableArray array]; - - //fetch any recent changes first before gathering escrow record ids - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-fetch-and-process-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit fetch"); - [op addSuccessDependency: [self otFetchAndProcessUpdates]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secnotice("octagon", "failed to fetch changes error:%@", op.error); - } - - secnotice("octagon", "checking local store for bottles"); - - //check localstore for bottles - NSArray* localStoreBottledPeerRecords = [self.localStore readAllLocalBottledPeerRecords:&localError]; - if(!localStoreBottledPeerRecords) - { - secerror("octagon: local store contains no bottled peer entries: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - for(OTBottledPeerRecord* entry in localStoreBottledPeerRecords){ - NSString* escrowID = entry.escrowRecordID; - if(escrowID && ![recordIDs containsObject:escrowID]){ - [recordIDs addObject:escrowID]; - } - } - - return recordIDs; -} - --(CKRecord*) dataToRecord:(NSData*)encodedRecord -{ - NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedRecord error:nil]; - CKRecord* record = [[CKRecord alloc] initWithCoder:coder]; - [coder finishDecoding]; - return record; -} - --(NSData*) recordToData:(CKRecord*)record -{ - NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES]; - [record encodeWithCoder:archiver]; - [archiver finishEncoding]; - - return archiver.encodedData; -} - --( CKRecord* _Nullable ) CKRecordFromMirror:(CKRecordID*)recordID bpRecord:(OTBottledPeerRecord*)bprecord escrowRecordID:(NSString*)escrowRecordID error:(NSError**)error -{ - CKRecord* record = nil; - - OTBottledPeerRecord* recordFromDB = [self.localStore readLocalBottledPeerRecordWithRecordID:recordID.recordName error:error]; - if(recordFromDB && recordFromDB.encodedRecord != nil){ - record = [self dataToRecord:recordFromDB.encodedRecord]; - } - else{ - record = [[CKRecord alloc] initWithRecordType:OTCKRecordBottledPeerType recordID:recordID]; - } - - if(record == nil){ - secerror("octagon: failed to create cloud kit record"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"failed to create cloud kit record"}]; - } - return nil; - } - record[OTCKRecordPeerID] = bprecord.peerID; - record[OTCKRecordSPID] = bprecord.spID; - record[OTCKRecordEscrowSigningSPKI] = bprecord.escrowedSigningSPKI; - record[OTCKRecordPeerSigningSPKI] = bprecord.peerSigningSPKI; - record[OTCKRecordEscrowRecordID] = escrowRecordID; - record[OTCKRecordBottle] = bprecord.bottle; - record[OTCKRecordSignatureFromEscrow] = bprecord.signatureUsingEscrowKey; - record[OTCKRecordSignatureFromPeerKey] = bprecord.signatureUsingPeerKey; - - return record; -} - --(CKKSResultOperation*) modifyRecords:(NSArray*) recordsToSave deleteRecordIDs:(NSArray*) recordIDsToDelete -{ - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* modifyOp = [CKKSResultOperation named:@"modify-records-watcher" withBlock:^{}]; - - [self dispatchSync: ^bool{ - self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave recordIDsToDelete:recordIDsToDelete]; - - self.modifyRecordsOperation.atomic = YES; - self.modifyRecordsOperation.longLived = NO; // The keys are only in memory; mark this explicitly not long-lived - - // Currently done during buddy. User is waiting. - self.modifyRecordsOperation.configuration.automaticallyRetryNetworkFailures = NO; - self.modifyRecordsOperation.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary; - self.modifyRecordsOperation.configuration.isCloudKitSupportOperation = YES; - - self.modifyRecordsOperation.savePolicy = CKRecordSaveIfServerRecordUnchanged; - - self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) { - // These should all fail or succeed as one. Do the hard work in the records completion block. - if(!error) { - secnotice("octagon", "Successfully completed upload for %@", record.recordID.recordName); - - } else { - secerror("octagon: error on row: %@ %@", record.recordID.recordName, error); - modifyOp.error = error; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - [weakSelf.operationQueue addOperation:modifyOp]; - } - }; - self.modifyRecordsOperation.modifyRecordsCompletionBlock = ^(NSArray *savedRecords, NSArray *deletedRecordIDs, NSError *error) { - secnotice("octagon", "Completed trust update"); - __strong __typeof(weakSelf) strongSelf = weakSelf; - - if(error){ - modifyOp.error = error; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - secerror("octagon: received error from cloudkit: %@", error); - if([error.domain isEqualToString:CKErrorDomain] && (error.code == CKErrorPartialFailure)) { - NSMutableDictionary* failedRecords = error.userInfo[CKPartialErrorsByItemIDKey]; - ckksnotice("octagon", strongSelf, "failed records %@", failedRecords); - } - return; - } - if(!strongSelf) { - secerror("octagon: received callback for released object"); - modifyOp.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTCloudStore userInfo:@{NSLocalizedDescriptionKey: @"received callback for released object"}]; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - [strongSelf.operationQueue addOperation:modifyOp]; - return; - } - - if(savedRecords && [savedRecords count] > 0){ - for(CKRecord* record in savedRecords){ - NSError* localError = nil; - secnotice("octagon", "saving recordID: %@ changeToken:%@", record.recordID.recordName, record.recordChangeTag); - - //write to localStore - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.bottle = record[OTCKRecordBottle]; - rec.spID = record[OTCKRecordSPID]; - rec.escrowRecordID = record[OTCKRecordEscrowRecordID]; - rec.signatureUsingEscrowKey = record[OTCKRecordSignatureFromEscrow]; - rec.signatureUsingPeerKey = record[OTCKRecordSignatureFromPeerKey]; - rec.encodedRecord = [strongSelf recordToData:record]; - rec.launched = @"YES"; - rec.escrowedSigningSPKI = record[OTCKRecordEscrowSigningSPKI]; - rec.peerSigningSPKI = record[OTCKRecordPeerSigningSPKI]; - - BOOL result = [strongSelf.localStore insertBottledPeerRecord:rec escrowRecordID:record[OTCKRecordEscrowRecordID] error:&localError]; - - if(!result || localError){ - secerror("Could not write bottled peer record:%@ to database: %@", record.recordID.recordName, localError); - } - - if(localError){ - secerror("octagon: could not save to database: %@", localError); - modifyOp.error = localError; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - } - } - } - else if(deletedRecordIDs && [deletedRecordIDs count] >0){ - for(CKRecordID* recordID in deletedRecordIDs){ - secnotice("octagon", "removed recordID: %@", recordID); - NSError* localError = nil; - BOOL result = [strongSelf.localStore deleteBottledPeer:recordID.recordName error:&localError]; - if(!result){ - secerror("octagon: could not remove record id: %@, error:%@", recordID, localError); - modifyOp.error = localError; - modifyOp.descriptionErrorCode = CKKSResultDescriptionPendingBottledPeerModifyRecords; - } - } - } - [strongSelf.operationQueue addOperation:modifyOp]; - }; - return true; - }]; - - [self.database addOperation: self.modifyRecordsOperation]; - return modifyOp; -} - -- (BOOL) uploadBottledPeerRecord:(OTBottledPeerRecord *)bprecord - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error -{ - secnotice("octagon", "sending bottled peer to cloudkit"); - BOOL result = YES; - - CKRecordID* recordID = [[CKRecordID alloc] initWithRecordName:bprecord.recordName zoneID:self.zoneID]; - CKRecord *record = [self CKRecordFromMirror:recordID bpRecord:bprecord escrowRecordID:escrowRecordID error:error]; - - if(!record){ - return NO; - } - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-modify-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit ModifyRecords"); - [op addSuccessDependency: [self modifyRecords:@[ record ] deleteRecordIDs:@[]]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: failed to commit record changes error:%@", op.error); - if(error){ - *error = op.error; - } - return NO; - } - secnotice("octagon", "successfully uploaded record: %@", bprecord.recordName); - return result; -} - --(BOOL) removeBottledPeerRecordID:(CKRecordID*)recordID error:(NSError**)error -{ - secnotice("octagon", "removing bottled peer from cloudkit"); - BOOL result = YES; - - NSMutableArray* recordIDsToRemove = [[NSMutableArray alloc] init]; - [recordIDsToRemove addObject:recordID]; - - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-modify-changes" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit ModifyRecords"); - [op addSuccessDependency: [self modifyRecords:[NSMutableArray array] deleteRecordIDs:recordIDsToRemove]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(op.error != nil) { - secerror("octagon: ailed to commit record changes error:%@", op.error); - if(error){ - *error = op.error; - } - return NO; - } - - return result; -} - -- (void)_onqueueHandleCKLogin { - if(!SecCKKSIsEnabled()) { - ckksnotice("ckks", self, "Skipping CloudKit initialization due to disabled CKKS"); - return; - } - - dispatch_assert_queue(self.queue); - - __weak __typeof(self) weakSelf = self; - - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - [self handleCKLogin:ckse.ckzonecreated zoneSubscribed:ckse.ckzonesubscribed]; - - self.viewSetupOperation = [CKKSResultOperation operationWithBlock: ^{ - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - ckkserror("ckks", strongSelf, "received callback for released object"); - return; - } - - __block bool quit = false; - - [strongSelf dispatchSync: ^bool { - ckksnotice("octagon", strongSelf, "Zone setup progress: %@ %d %@ %d %@", - [CKKSAccountStateTracker stringFromAccountStatus:strongSelf.accountStatus], - strongSelf.zoneCreated, strongSelf.zoneCreatedError, strongSelf.zoneSubscribed, strongSelf.zoneSubscribedError); - - NSError* error = nil; - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: strongSelf.zoneName]; - ckse.ckzonecreated = strongSelf.zoneCreated; - ckse.ckzonesubscribed = strongSelf.zoneSubscribed; - - // Although, if the zone subscribed error says there's no zone, mark down that there's no zone - if(strongSelf.zoneSubscribedError && - [strongSelf.zoneSubscribedError.domain isEqualToString:CKErrorDomain] && strongSelf.zoneSubscribedError.code == CKErrorPartialFailure) { - NSError* subscriptionError = strongSelf.zoneSubscribedError.userInfo[CKPartialErrorsByItemIDKey][strongSelf.zoneID]; - if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) { - - ckkserror("octagon", strongSelf, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", strongSelf.zoneSubscribedError); - ckse.ckzonecreated = false; - } - } - - [ckse saveToDatabase: &error]; - if(error) { - ckkserror("octagon", strongSelf, "couldn't save zone creation status for %@: %@", strongSelf.zoneName, error); - } - - if(!strongSelf.zoneCreated || !strongSelf.zoneSubscribed || strongSelf.accountStatus != CKAccountStatusAvailable) { - // Something has gone very wrong. Error out and maybe retry. - quit = true; - - // Note that CKKSZone has probably called [handleLogout]; which means we have a key hierarchy reset queued up. Error here anyway. - NSError* realReason = strongSelf.zoneCreatedError ? strongSelf.zoneCreatedError : strongSelf.zoneSubscribedError; - strongSelf.viewSetupOperation.error = realReason; - - - return true; - } - - return true; - }]; - - if(quit) { - ckkserror("octagon", strongSelf, "Quitting setup."); - return; - } - }]; - self.viewSetupOperation.name = @"zone-setup"; - - [self.viewSetupOperation addNullableDependency: self.zoneSetupOperation]; - [self scheduleAccountStatusOperation: self.viewSetupOperation]; -} - -- (void)handleCKLogin -{ - ckksinfo("octagon", self, "received a notification of CK login"); - - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* login = [CKKSResultOperation named:@"octagon-login" withBlock:^{ - __strong __typeof(self) strongSelf = weakSelf; - - [strongSelf dispatchSync:^bool{ - strongSelf.accountStatus = CKKSAccountStatusAvailable; - [strongSelf _onqueueHandleCKLogin]; - return true; - }]; - }]; - - [self scheduleAccountStatusOperation:login]; -} - -- (bool)_onqueueResetLocalData: (NSError * __autoreleasing *) error { - dispatch_assert_queue(self.queue); - - NSError* localerror = nil; - bool setError = false; - - CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName]; - ckse.ckzonecreated = false; - ckse.ckzonesubscribed = false; - ckse.changeToken = NULL; - [ckse saveToDatabase: &localerror]; - if(localerror) { - ckkserror("ckks", self, "couldn't reset zone status for %@: %@", self.zoneName, localerror); - if(error && !setError) { - *error = localerror; setError = true; - } - } - - BOOL result = [_localStore removeAllBottledPeerRecords:&localerror]; - if(!result){ - *error = localerror; - secerror("octagon: failed to move all bottled peer entries for context: %@ error: %@", self.contextID, localerror); - } - return (localerror == nil && !setError); -} - --(CKKSResultOperation*) resetOctagonTrustZone:(NSError**)error -{ - // On a reset, we should cancel all existing operations - [self cancelAllOperations]; - CKKSResultOperation* reset = [super deleteCloudKitZoneOperation:nil]; - [self scheduleOperationWithoutDependencies:reset]; - - __weak __typeof(self) weakSelf = self; - CKKSGroupOperation* resetFollowUp = [[CKKSGroupOperation alloc] init]; - resetFollowUp.name = @"cloudkit-reset-follow-up-group"; - - [resetFollowUp runBeforeGroupFinished: [CKKSResultOperation named:@"cloudkit-reset-follow-up" withBlock: ^{ - __strong __typeof(weakSelf) strongSelf = weakSelf; - if(!strongSelf) { - ckkserror("octagon", strongSelf, "received callback for released object"); - return; - } - - if(!reset.error) { - ckksnotice("octagon", strongSelf, "Successfully deleted zone %@", strongSelf.zoneName); - __block NSError* error = nil; - - [strongSelf dispatchSync: ^bool{ - [strongSelf _onqueueResetLocalData: &error]; - return true; - }]; - } else { - // Shouldn't ever happen, since reset is a successDependency - ckkserror("ckks", strongSelf, "Couldn't reset zone %@: %@", strongSelf.zoneName, reset.error); - } - }]]; - - [resetFollowUp addSuccessDependency:reset]; - [self scheduleOperationWithoutDependencies:resetFollowUp]; - - return reset; -} - --(BOOL) performReset:(NSError**)error -{ - BOOL result = NO; - CKKSResultOperation* op = [CKKSResultOperation named:@"cloudkit-reset-zones-waiter" withBlock:^{}]; - - secnotice("octagon", "Beginning CloudKit reset for Octagon Trust"); - [op addSuccessDependency:[self resetOctagonTrustZone:error]]; - - [op timeout:(SecCKKSTestsEnabled() ? 2*NSEC_PER_SEC : 120*NSEC_PER_SEC)]; - [self.operationQueue addOperation: op]; - - [op waitUntilFinished]; - if(!op.error) { - secnotice("octagon", "Completed rpcResetCloudKit"); - __weak __typeof(self) weakSelf = self; - CKKSResultOperation* login = [CKKSResultOperation named:@"octagon-login" withBlock:^{ - __strong __typeof(self) strongSelf = weakSelf; - - [strongSelf dispatchSync:^bool{ - strongSelf.accountStatus = CKKSAccountStatusAvailable; - [strongSelf handleCKLogin:false zoneSubscribed:false]; - return true; - }]; - }]; - - [self.operationQueue addOperation:login]; - result = YES; - } else { - secnotice("octagon", "Completed rpcResetCloudKit with error: %@", op.error); - if(error){ - *error = op.error; - } - } - - return result; -} - -@end - -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTCloudStoreState.h b/keychain/ot/OTCloudStoreState.h deleted file mode 100644 index 915a3200..00000000 --- a/keychain/ot/OTCloudStoreState.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 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 OTCloudStoreState_h -#define OTCloudStoreState_h - -#if OCTAGON -#import "keychain/ckks/CKKSSQLDatabaseObject.h" - -@interface OTCloudStoreState : CKKSSQLDatabaseObject - -@property NSString* ckzone; -@property bool ckzonecreated; -@property bool ckzonesubscribed; -@property (getter=getChangeToken, setter=setChangeToken:) CKServerChangeToken* changeToken; -@property NSData* encodedChangeToken; -@property NSDate* lastFetchTime; - -+ (instancetype)state:(NSString*)ckzone; - -+ (instancetype)fromDatabase:(NSString*)ckzone error:(NSError* __autoreleasing*)error; -+ (instancetype)tryFromDatabase:(NSString*)ckzone error:(NSError* __autoreleasing*)error; - -- (instancetype)initWithCKZone:(NSString*)ckzone - zoneCreated:(bool)ckzonecreated - zoneSubscribed:(bool)ckzonesubscribed - changeToken:(NSData*)changetoken - lastFetch:(NSDate*)lastFetch; - -- (CKServerChangeToken*)getChangeToken; -- (void)setChangeToken:(CKServerChangeToken*)token; - -- (BOOL)isEqual:(id)object; -@end - -#endif -#endif /* OTCloudStoreState_h */ diff --git a/keychain/ot/OTCloudStoreState.m b/keychain/ot/OTCloudStoreState.m deleted file mode 100644 index 63b3ab74..00000000 --- a/keychain/ot/OTCloudStoreState.m +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 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@ - */ - -#include - -#import -#import - -#import "CKKSKeychainView.h" - -#include -#include -#include - -#if OCTAGON - -#import -#import "OTCloudStoreState.h" - -@implementation OTCloudStoreState - -- (instancetype)initWithCKZone:(NSString*)ckzone - zoneCreated:(bool)ckzonecreated - zoneSubscribed:(bool)ckzonesubscribed - changeToken:(NSData*)changetoken - lastFetch:(NSDate*)lastFetch -{ - if(self = [super init]) { - _ckzone = [ckzone copy]; - _ckzonecreated = ckzonecreated; - _ckzonesubscribed = ckzonesubscribed; - _encodedChangeToken = [changetoken copy]; - _lastFetchTime = [lastFetch copy]; - } - return self; -} - -- (BOOL)isEqual: (id) object { - if(![object isKindOfClass:[OTCloudStoreState class]]) { - return NO; - } - - OTCloudStoreState* obj = (OTCloudStoreState*) object; - - return ([self.ckzone isEqualToString: obj.ckzone] && - self.ckzonecreated == obj.ckzonecreated && - self.ckzonesubscribed == obj.ckzonesubscribed && - ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) && - ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) && - true) ? YES : NO; -} - -+ (instancetype) state: (NSString*) ckzone { - NSError* error = nil; - OTCloudStoreState* ret = [OTCloudStoreState tryFromDatabase:ckzone error:&error]; - - if(error) { - secerror("octagon: error fetching CKState(%@): %@", ckzone, error); - } - - if(!ret) { - ret = [[OTCloudStoreState alloc] initWithCKZone:ckzone - zoneCreated:false - zoneSubscribed:false - changeToken:nil - lastFetch:nil]; - } - return ret; -} - -- (CKServerChangeToken*) getChangeToken { - if(self.encodedChangeToken) { - NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.encodedChangeToken error:nil]; - return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey]; - } else { - return nil; - } -} - -- (void)setChangeToken: (CKServerChangeToken*) token { - self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil] : nil; -} - -#pragma mark - Database Operations - -+ (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { - return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; -} - -+ (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error { - return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error]; -} - -#pragma mark - CKKSSQLDatabaseObject methods - -+ (NSString*) sqlTable { - return @"ckstate"; -} - -+ (NSArray*) sqlColumns { - return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup"]; -} - -- (NSDictionary*) whereClauseToFindSelf { - return @{@"ckzone": self.ckzone}; -} - -- (NSDictionary*) sqlValues { - NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init]; - - return @{@"ckzone": self.ckzone, - @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated], - @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed], - @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]), - @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil), - }; -} - -+ (instancetype)fromDatabaseRow:(NSDictionary*)row { - return [[OTCloudStoreState alloc] initWithCKZone:row[@"ckzone"].asString - zoneCreated:row[@"ckzonecreated"].asBOOL - zoneSubscribed:row[@"ckzonesubscribed"].asBOOL - changeToken:row[@"changetoken"].asBase64DecodedData - lastFetch:row[@"lastfetch"].asISO8601Date - ]; -} - -@end - -#endif //OTCloudStoreState - diff --git a/keychain/ot/OTConstants.h b/keychain/ot/OTConstants.h index 3518f397..1b7ba2d2 100644 --- a/keychain/ot/OTConstants.h +++ b/keychain/ot/OTConstants.h @@ -61,6 +61,19 @@ void OctagonRecoveryKeySetIsEnabled(BOOL value); BOOL OctagonAuthoritativeTrustIsEnabled(void); void OctagonAuthoritativeTrustSetIsEnabled(BOOL value); +BOOL OctagonIsSOSFeatureEnabled(void); +void OctagonSetSOSFeatureEnabled(BOOL value); + +typedef NS_ENUM(NSInteger, CuttlefishResetReason) { + CuttlefishResetReasonUnknown = 0, + CuttlefishResetReasonUserInitiatedReset = 1, + CuttlefishResetReasonHealthCheck = 2, + CuttlefishResetReasonNoBottleDuringEscrowRecovery = 3, + CuttlefishResetReasonLegacyJoinCircle = 4, + CuttlefishResetReasonRecoveryKey = 5, + CuttlefishResetReasonTestGenerated = 6, +}; + #endif // __OBJC__ #endif /* OTConstants_h */ diff --git a/keychain/ot/OTConstants.m b/keychain/ot/OTConstants.m index 4368cc5c..9fbf29a3 100644 --- a/keychain/ot/OTConstants.m +++ b/keychain/ot/OTConstants.m @@ -55,6 +55,9 @@ static bool OctagonRecoveryKeyEnabledOverride = false; static bool OctagonAuthoritativeTrustEnabledOverrideSet = false; static bool OctagonAuthoritativeTrustEnabledOverride = false; +static bool OctagonSOSFeatureIsEnabledOverrideSet = false; +static bool OctagonSOSFeatureIsEnabledOverride = false; + bool OctagonIsEnabled(void) { if(OctagonEnabledOverrideSet) { @@ -183,3 +186,26 @@ void OctagonAuthoritativeTrustSetIsEnabled(BOOL value) OctagonAuthoritativeTrustEnabledOverrideSet = true; OctagonAuthoritativeTrustEnabledOverride = value; } + +BOOL OctagonIsSOSFeatureEnabled(void) +{ + if(OctagonSOSFeatureIsEnabledOverrideSet) { + secnotice("octagon", "SOS Feature is %@ (overridden)", OctagonSOSFeatureIsEnabledOverride ? @"enabled" : @"disabled"); + return OctagonSOSFeatureIsEnabledOverrideSet; + } + + static bool sosEnabled = true; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sosEnabled = os_feature_enabled(Security, EnableSecureObjectSync); + secnotice("octagon", "SOS Feature is %@ (via feature flags)", sosEnabled ? @"enabled" : @"disabled"); + }); + + return sosEnabled; +} + +void OctagonSetSOSFeatureEnabled(BOOL value) +{ + OctagonSOSFeatureIsEnabledOverrideSet = true; + OctagonSOSFeatureIsEnabledOverride = value; +} diff --git a/keychain/ot/OTContext.h b/keychain/ot/OTContext.h deleted file mode 100644 index 3f75b375..00000000 --- a/keychain/ot/OTContext.h +++ /dev/null @@ -1,83 +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 OCTAGON -#import -#import "OTLocalStore.h" -#import "OTCloudStore.h" -#import "OTEscrowKeys.h" -#import "OTIdentity.h" -#import "OTBottledPeer.h" -#import "OTBottledPeerSigned.h" -#import "OTRamping.h" -#import "OTDefines.h" -#import "OTPreflightInfo.h" -#import "keychain/ckks/CKKSLockStateTracker.h" - -NS_ASSUME_NONNULL_BEGIN - -@protocol OTContextIdentityProvider -- (nullable OTIdentity *) currentIdentity:(NSError**) error; -@end - - -@interface OTContext : NSObject - -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) OTCloudStore* cloudStore; - -@property (nonatomic, readonly) CKKSLockStateTracker* lockStateTracker; -@property (nonatomic, readonly) CKKSAccountStateTracker* accountTracker; -@property (nonatomic, readonly) CKKSReachabilityTracker *reachabilityTracker; - -- (nullable instancetype) initWithContextID:(NSString*)contextID - dsid:(NSString*)dsid - localStore:(OTLocalStore*)localStore - cloudStore:(nullable OTCloudStore*)cloudStore - identityProvider:(id )identityProvider - error:(NSError**)error; - -- (nullable OTBottledPeerSigned *) restoreFromEscrowRecordID:(NSString*)escrowRecordID - secret:(NSData*)secret - error:(NSError**)error; - -- (NSData* _Nullable) makeMeSomeEntropy:(int)requiredLength; -- (nullable OTPreflightInfo*) preflightBottledPeer:(NSString*)contextID - entropy:(NSData*)entropy - error:(NSError**)error; -- (BOOL)scrubBottledPeer:(NSString*)contextID - bottleID:(NSString*)bottleID - error:(NSError**)error; - --(BOOL)updateAllBottlesForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)newSigningKey - newEncryptionKey:(SFECKeyPair*)newEncryptionKey - error:(NSError**)error; - --(OctagonBottleCheckState)doesThisDeviceHaveABottle:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTContext.m b/keychain/ot/OTContext.m deleted file mode 100644 index ee9a3ed0..00000000 --- a/keychain/ot/OTContext.m +++ /dev/null @@ -1,633 +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 OCTAGON - -#import "OTContext.h" -#import - -#import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTDefines.h" - -#include -#include - -#import "keychain/ckks/CKKS.h" -#import "keychain/ckks/CKKSViewManager.h" -#import "keychain/ckks/CKKSAnalytics.h" - -#import - -NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* const kOTRampZoneName = @"metadata_zone"; - -@interface OTContext (lockstateTracker) -@end - -@interface OTContext () - -@property (nonatomic, strong) NSString* contextID; -@property (nonatomic, strong) NSString* contextName; -@property (nonatomic, strong) NSString* dsid; - -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) OTCloudStore* cloudStore; -@property (nonatomic, strong) NSData* changeToken; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSDate* egoPeerCreationDate; -@property (nonatomic, strong) dispatch_queue_t queue; -@property (nonatomic, weak) id identityProvider; - -@property (nonatomic, strong) CKKSAccountStateTracker* accountTracker; -@property (nonatomic, strong) CKKSLockStateTracker* lockStateTracker; -@property (nonatomic, strong) CKKSReachabilityTracker *reachabilityTracker; - -@end - -@implementation OTContext - --(CKContainer*)makeCKContainer:(NSString*)containerName { - CKContainer* container = [CKContainer containerWithIdentifier:containerName]; - container = [[CKContainer alloc] initWithContainerID: container.containerID]; - return container; -} - --(BOOL) isPrequeliteEnabled -{ - BOOL result = YES; - if([PQLConnection class] == nil) { - secerror("OT: prequelite appears to not be linked. Can't create OT objects."); - result = NO; - } - return result; -} - -- (nullable instancetype) initWithContextID:(NSString*)contextID - dsid:(NSString*)dsid - localStore:(OTLocalStore*)localStore - cloudStore:(nullable OTCloudStore*)cloudStore - identityProvider:(id )identityProvider - error:(NSError**)error -{ - if(![self isPrequeliteEnabled]){ - // We're running in the base build environment, which lacks a bunch of libraries. - // We don't support doing anything in this environment. Bye. - return nil; - } - - self = [super init]; - if (self) { - NSError* localError = nil; - _contextID = contextID; - _dsid = dsid; - _identityProvider = identityProvider; - _localStore = localStore; - - NSString* contextAndDSID = [NSString stringWithFormat:@"%@-%@", contextID, dsid]; - - CKContainer* container = [self makeCKContainer:OTCKContainerName]; - - _accountTracker = [CKKSViewManager manager].accountTracker; - _lockStateTracker = [CKKSViewManager manager].lockStateTracker; - _reachabilityTracker = [CKKSViewManager manager].reachabilityTracker; - - if(!cloudStore) { - _cloudStore = [[OTCloudStore alloc]initWithContainer:container - zoneName:OTCKZoneName - accountTracker:_accountTracker - reachabilityTracker:_reachabilityTracker - localStore:_localStore - contextID:contextID - dsid:dsid - zoneModifier:[CKKSViewManager manager].zoneModifier - cloudKitClassDependencies:[CKKSCloudKitClassDependencies forLiveCloudKit] - operationQueue:nil]; - } else{ - _cloudStore = cloudStore; - } - - OTContextRecord* localContextRecord = [_localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&localError]; - - if(localContextRecord == nil || localContextRecord.contextID == nil){ - localError = nil; - BOOL result = [_localStore initializeContextTable:contextID dsid:dsid error:&localError]; - if(!result || localError != nil){ - secerror("octagon: reading from database failed with error: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - localContextRecord = [_localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&localError]; - if(localContextRecord == nil || localError !=nil){ - secerror("octagon: reading from database failed with error: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - } - - _contextID = localContextRecord.contextID; - _contextName = localContextRecord.contextName; - _changeToken = localContextRecord.changeToken; - _egoPeerID = localContextRecord.egoPeerID; - _egoPeerCreationDate = localContextRecord.egoPeerCreationDate; - - _queue = dispatch_queue_create("com.apple.security.otcontext", DISPATCH_QUEUE_SERIAL); - } - return self; -} - -- (nullable OTBottledPeerSigned *) createBottledPeerRecordForIdentity:(OTIdentity *)identity - secret:(NSData*)secret - error:(NSError**)error -{ - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTEscrowKeys *escrowKeys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:self.dsid error:&localError]; - if (!escrowKeys || localError != nil) { - secerror("octagon: unable to derive escrow keys: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithPeerID:identity.peerID - spID:identity.spID - peerSigningKey:identity.peerSigningKey - peerEncryptionKey:identity.peerEncryptionKey - escrowKeys:escrowKeys - error:&localError]; - if (!bp || localError !=nil) { - secerror("octagon: unable to create a bottled peer: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - return [[OTBottledPeerSigned alloc] initWithBottledPeer:bp - escrowedSigningKey:escrowKeys.signingKey - peerSigningKey:identity.peerSigningKey - error:error]; -} - -- (NSData* _Nullable) makeMeSomeEntropy:(int)requiredLength -{ - NSMutableData* salt = [NSMutableData dataWithLength:requiredLength]; - if (salt == nil){ - return nil; - } - if (SecRandomCopyBytes(kSecRandomDefault, [salt length], [salt mutableBytes]) != 0){ - return nil; - } - return salt; -} - -- (nullable OTPreflightInfo*) preflightBottledPeer:(NSString*)contextID - entropy:(NSData*)entropy - error:(NSError**)error -{ - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTIdentity *identity = [self.identityProvider currentIdentity:&localError]; - if (!identity || localError != nil) { - secerror("octagon: unable to get current identity:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeerSigned* bps = [self createBottledPeerRecordForIdentity:identity - secret:entropy - error:&localError]; - if (!bps || localError != nil) { - secerror("octagon: failed to create bottled peer record: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - secnotice("octagon", "created bottled peer:%@", bps); - - OTBottledPeerRecord *bprec = [bps asRecord:identity.spID]; - - if (!identity.spID) { - secerror("octagon: cannot enroll without a spID"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorNoIdentity userInfo:@{NSLocalizedDescriptionKey: @"OTIdentity does not have an SOS peer id"}]; - } - return nil; - } - - OTPreflightInfo* info = [[OTPreflightInfo alloc]init]; - info.escrowedSigningSPKI = bprec.escrowedSigningSPKI; - - if(!info.escrowedSigningSPKI){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEscrowSigningSPKI userInfo:@{NSLocalizedDescriptionKey: @"Escrowed spinging SPKI is nil"}]; - } - secerror("octagon: Escrowed spinging SPKI is nil"); - return nil; - } - - info.bottleID = bprec.recordName; - if(!info.bottleID){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"BottleID is nil"}]; - } - secerror("octagon: BottleID is nil"); - return nil; - } - - //store record in localStore - BOOL result = [self.localStore insertBottledPeerRecord:bprec escrowRecordID:identity.spID error:&localError]; - if(!result || localError){ - secerror("octagon: could not persist the bottle record: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - return info; -} - -- (BOOL)scrubBottledPeer:(NSString*)contextID - bottleID:(NSString*)bottleID - error:(NSError**)error -{ - secnotice("octagon", "scrubBottledPeer"); - NSError* localError = nil; - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device is locked"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return YES; - } - - BOOL result = [self.localStore deleteBottledPeer:bottleID error:&localError]; - if(!result || localError != nil){ - secerror("octagon: could not remove record for bottleID %@, error:%@", bottleID, localError); - if (error) { - *error = localError; - } - } - return result; -} - -- (OTBottledPeerSigned *) restoreFromEscrowRecordID:(NSString*)escrowRecordID - secret:(NSData*)secret - error:(NSError**)error -{ - NSError *localError = nil; - - if(self.lockStateTracker.isLocked){ - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return nil; - } - - OTEscrowKeys *escrowKeys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:self.dsid error:&localError]; - if (!escrowKeys || localError != nil) { - secerror("unable to derive escrow keys: %@", localError); - if (error) { - *error = localError; - } - return nil; - } - - BOOL result = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(!result || localError){ - secerror("octagon: could not download bottled peer record:%@", localError); - if(error){ - *error = localError; - } - } - NSString* recordName = [OTBottledPeerRecord constructRecordID:escrowRecordID - escrowSigningSPKI:[escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]]; - OTBottledPeerRecord* rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&localError]; - - if (!rec) { - secerror("octagon: could not read bottled peer record:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:escrowKeys - error:&localError]; - if (!bps) { - secerror("octagon: could not unpack bottled peer:%@", localError); - if (error) { - *error = localError; - } - return nil; - } - - return bps; -} - --(BOOL)updateBottleForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)signingKey - newEncryptionKey:(SFECKeyPair*)encryptionKey - escrowKeySet:(OTEscrowKeys*)keySet - error:(NSError**)error -{ - NSError* localError = nil; - - //let's rebottle our bottles! - OTBottledPeer *bp = [[OTBottledPeer alloc] initWithPeerID:nil - spID:peerID - peerSigningKey:signingKey - peerEncryptionKey:encryptionKey - escrowKeys:keySet - error:&localError]; - if (!bp || localError !=nil) { - secerror("octagon: unable to create a bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - OTBottledPeerSigned* bpSigned = [[OTBottledPeerSigned alloc] initWithBottledPeer:bp - escrowedSigningKey:keySet.signingKey - peerSigningKey:signingKey - error:&localError]; - if(!bpSigned || localError){ - secerror("octagon: unable to create a signed bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - - OTBottledPeerRecord *newRecord = [bpSigned asRecord:peerID]; - - BOOL uploaded = [self.cloudStore uploadBottledPeerRecord:newRecord escrowRecordID:peerID error:&localError]; - if(!uploaded || localError){ - secerror("octagon: unable to upload bottled peer: %@", localError); - if (error) { - *error = localError; - } - return NO; - } - - return YES; -} - --(BOOL)updateAllBottlesForPeerID:(NSString*)peerID - newSigningKey:(SFECKeyPair*)newSigningKey - newEncryptionKey:(SFECKeyPair*)newEncryptionKey - error:(NSError**)error -{ - BOOL result = NO; - BOOL atLeastOneHasBeenUpdated = NO; - - NSError* localError = nil; - - SFECKeyPair *escrowSigningKey = nil; - SFECKeyPair *escrowEncryptionKey = nil; - SFAESKey *escrowSymmetricKey = nil; - - result = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(!result || localError){ - secnotice("octagon", "could not download bottles from cloudkit: %@", localError); - } - - secnotice("octagon", "checking local store for downloaded bottles"); - - NSArray* bottles = [self.localStore readLocalBottledPeerRecordsWithMatchingPeerID:peerID error:&localError]; - if(!bottles || localError){ - secnotice("octagon", "peer %@ enrolled 0 bottles", peerID); - if (error) { - *error = localError; - } - return result; - } - - //iterate through all the bottles and attempt to update all the bottles - for(OTBottledPeerRecord* bottle in bottles){ - - NSString* escrowSigningPubKeyHash = [OTEscrowKeys hashEscrowedSigningPublicKey:bottle.escrowedSigningSPKI]; - - BOOL foundKeys = [OTEscrowKeys findEscrowKeysForLabel:escrowSigningPubKeyHash - foundSigningKey:&escrowSigningKey - foundEncryptionKey:&escrowEncryptionKey - foundSymmetricKey:&escrowSymmetricKey - error:&localError]; - if(!foundKeys){ - secnotice("octagon", "found 0 persisted escrow keys for label: %@", escrowSigningPubKeyHash); - continue; - } - - OTEscrowKeys *retrievedKeySet = [[OTEscrowKeys alloc]initWithSigningKey:escrowSigningKey encryptionKey:escrowEncryptionKey symmetricKey:escrowSymmetricKey]; - - if(!retrievedKeySet){ - secnotice("octagon", "failed to create escrow keys"); - continue; - } - - BOOL updated = [self updateBottleForPeerID:peerID newSigningKey:newSigningKey newEncryptionKey:newEncryptionKey escrowKeySet:retrievedKeySet error:&localError]; - - if(!updated || localError){ - secnotice("octagon", "could not updated bottle for peerid: %@ for escrowed signing public key hash: %@", peerID, escrowSigningPubKeyHash); - }else{ - atLeastOneHasBeenUpdated = YES; - } - } - - if(!atLeastOneHasBeenUpdated){ - secerror("octagon: no bottles were updated for : %@", peerID); - result = NO; - - localError = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleUpdate userInfo:@{NSLocalizedDescriptionKey: @"bottle update failed, 0 bottles updated."}]; - if(error){ - *error = localError; - } - }else{ - result = YES; - secnotice("octagon", "bottles were updated for : %@", peerID); - } - return result; -} - --(BOOL)bottleExistsLocallyForIdentity:(OTIdentity*)identity - error:(NSError**)error -{ - NSError* localError = nil; - //read all the local bp records - NSArray* bottles = [self.localStore readLocalBottledPeerRecordsWithMatchingPeerID:identity.spID error:&localError]; - if(!bottles || [bottles count] == 0 || localError != nil){ - secerror("octagon: there are no eligible bottle peer records: %@", localError); - if(error){ - *error = localError; - } - return NO; - } - - BOOL hasBottle = NO; - //if check all the records if the peer signing public key matches the bottled one! - for(OTBottledPeerRecord* bottle in bottles){ - NSData* bottledSigningSPKIData = [[SFECPublicKey keyWithSubjectPublicKeyInfo:bottle.peerSigningSPKI] keyData]; - NSData* currentIdentitySPKIData = [identity.peerSigningKey.publicKey keyData]; - - //spIDs are the same AND check bottle signature - if([currentIdentitySPKIData isEqualToData:bottledSigningSPKIData] && - [OTBottledPeerSigned verifyBottleSignature:bottle.bottle - signature:bottle.signatureUsingPeerKey - key:identity.peerSigningKey.publicKey - error:error]){ - hasBottle = YES; - } - } - - - - return hasBottle; -} - --(BOOL)queryCloudKitForBottle:(OTIdentity*)identity - error:(NSError**)error -{ - NSError* localError = nil; - BOOL hasBottle = NO; - //attempt to pull down all the records, but continue checking local store even if this fails. - BOOL fetched = [self.cloudStore downloadBottledPeerRecord:&localError]; - if(fetched == NO || localError != nil){ //couldn't download bottles - secerror("octagon: 0 bottled peers downloaded: %@", localError); - if(error){ - *error = localError; - } - return NO; - }else{ //downloaded bottles, let's check local store - hasBottle = [self bottleExistsLocallyForIdentity:identity error:&localError]; - } - - if(error){ - *error = localError; - } - return hasBottle; -} - --(OctagonBottleCheckState) doesThisDeviceHaveABottle:(NSError**)error -{ - secnotice("octagon", "checking if device has enrolled a bottle"); - - if(self.lockStateTracker.isLocked){ - secnotice("octagon", "device locked, not checking for bottle"); - if(error){ - *error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain code:errSecInteractionNotAllowed userInfo:nil]; - } - return UNCLEAR; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - - if(self.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"iCloud account is logged out"}]; - } - secnotice("octagon", "not logged into an account"); - return UNCLEAR; - } - - NSError* localError = nil; - OctagonBottleCheckState bottleStatus = NOBOTTLE; - - //get our current identity - OTIdentity* identity = [self.identityProvider currentIdentity:&localError]; - - //if we get the locked error, return true so we don't prompt the user - if(localError && [_lockStateTracker isLockedError:localError]){ - secnotice("octagon", "attempting to perform bottle check while locked: %@", localError); - return UNCLEAR; - } - - if(!identity && localError != nil){ - secerror("octagon: do not have an identity: %@", localError); - if(error){ - *error = localError; - } - return NOBOTTLE; - } - - //check locally first - BOOL bottleExistsLocally = [self bottleExistsLocallyForIdentity:identity error:&localError]; - - //no bottle and we have no network - if(!bottleExistsLocally && !self.reachabilityTracker.currentReachability){ - secnotice("octagon", "no network, can't query"); - localError = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - if(error){ - *error = localError; - } - return UNCLEAR; - } - else if(!bottleExistsLocally){ - if([self queryCloudKitForBottle:identity error:&localError]){ - bottleStatus = BOTTLE; - } - }else if(bottleExistsLocally){ - bottleStatus = BOTTLE; - } - - if(bottleStatus == NOBOTTLE){ - localError = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoBottlePeerRecords - userInfo:@{NSLocalizedDescriptionKey: @"Peer does not have any bottled records"}]; - secerror("octagon: this device does not have any bottled peers: %@", localError); - if(error){ - *error = localError; - } - } - - return bottleStatus; -} - -@end -#endif diff --git a/keychain/ot/OTContextRecord.h b/keychain/ot/OTContextRecord.h deleted file mode 100644 index 48a5f5dc..00000000 --- a/keychain/ot/OTContextRecord.h +++ /dev/null @@ -1,56 +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@ - */ - - -#ifndef OTContextRecord_h -#define OTContextRecord_h - -#if OCTAGON - -#import - -NS_ASSUME_NONNULL_BEGIN - - -@interface OTContextRecord : NSObject - -@property (nonatomic, strong) NSString* contextID; -@property (nonatomic, strong) NSString* dsid; -@property (nonatomic, strong) NSString* contextName; -@property (nonatomic) BOOL zoneCreated; -@property (nonatomic) BOOL subscribedToChanges; -@property (nonatomic, strong) NSData* changeToken; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSDate* egoPeerCreationDate; -@property (nonatomic, strong) NSData* recoverySigningSPKI; -@property (nonatomic, strong) NSData* recoveryEncryptionSPKI; - - --(BOOL)isEqual:(OTContextRecord* _Nullable)record; - -@end - -NS_ASSUME_NONNULL_END - -#endif /* OCTAGON */ -#endif /* OTContextRecord_h */ diff --git a/keychain/ot/OTContextRecord.m b/keychain/ot/OTContextRecord.m deleted file mode 100644 index 09e9e371..00000000 --- a/keychain/ot/OTContextRecord.m +++ /dev/null @@ -1,40 +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 OCTAGON -#import "OTContextRecord.h" - -@implementation OTContextRecord - --(BOOL)isEqual:(OTContextRecord*)record -{ - return [self.contextID isEqualToString:record.contextID] && - [self.contextName isEqualToString:record.contextName] && - [self.dsid isEqualToString:record.dsid] && - [self.egoPeerID isEqualToString:record.egoPeerID] && - [self.recoverySigningSPKI isEqual:record.recoverySigningSPKI] && - [self.recoveryEncryptionSPKI isEqual:record.recoveryEncryptionSPKI]; -} -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/OTControl.h b/keychain/ot/OTControl.h index 1adc056c..6e8b48de 100644 --- a/keychain/ot/OTControl.h +++ b/keychain/ot/OTControl.h @@ -58,11 +58,16 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithConnection:(NSXPCConnection*)connection sync:(bool)sync; - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID - reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error))reply; -- (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply; -- (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply; -- (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply; -- (void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply; + reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error))reply + API_DEPRECATED("Use OTClique API", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)encryptionKey:(void (^)(NSData* result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)signingKey:(void (^)(NSData* result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)listOfRecords:(void (^)(NSArray* list, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); +- (void)reset:(void (^)(BOOL result, NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); - (void)signIn:(NSString*)dsid container:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply; - (void)signOut:(NSString* _Nullable)container context:(NSString*)contextID reply:(void (^)(NSError * _Nullable error))reply; @@ -72,7 +77,8 @@ NS_ASSUME_NONNULL_BEGIN ForEncryptionKey:(SFECKeyPair* _Nonnull)encryptionKey ForPeerID:(NSString*)peerID reply:(void (^)(BOOL result, - NSError* _Nullable error))reply; + NSError* _Nullable error))reply + API_DEPRECATED("No longer needed", macos(10.14, 10.15.1), ios(4, 17.2)); - (void)rpcEpochWithConfiguration:(OTJoiningConfiguration*)config reply:(void (^)(uint64_t epoch, @@ -155,12 +161,13 @@ NS_ASSUME_NONNULL_BEGIN - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply; - (void)establish:(NSString* _Nullable)container - context:(NSString*)context - altDSID:(NSString*)altDSID - reply:(void (^)(NSError* _Nullable error))reply; + context:(NSString*)context + altDSID:(NSString*)altDSID + reply:(void (^)(NSError* _Nullable error))reply; - (void)leaveClique:(NSString* _Nullable)container context:(NSString*)context diff --git a/keychain/ot/OTControl.m b/keychain/ot/OTControl.m index adc3df22..ce1d0965 100644 --- a/keychain/ot/OTControl.m +++ b/keychain/ot/OTControl.m @@ -333,11 +333,12 @@ - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply { [[self getConnection: ^(NSError* error) { reply(error); - }] resetAndEstablish:container context:context altDSID:altDSID reply:reply]; + }] resetAndEstablish:container context:context altDSID:altDSID resetReason:resetReason reply:reply]; } - (void)establish:(NSString* _Nullable)container diff --git a/keychain/ot/OTControlProtocol.h b/keychain/ot/OTControlProtocol.h index 458c9595..6af4bbef 100644 --- a/keychain/ot/OTControlProtocol.h +++ b/keychain/ot/OTControlProtocol.h @@ -27,7 +27,7 @@ #define SECURITY_OT_OTCONTROLPROTOCOL_H 1 #import - +#import @class SFECKeyPair; NS_ASSUME_NONNULL_BEGIN @@ -132,6 +132,7 @@ typedef void (^OTNextJoinCompleteBlock)(BOOL finished, NSData* _Nullable message - (void)resetAndEstablish:(NSString* _Nullable)container context:(NSString*)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError* _Nullable error))reply; - (void)establish:(NSString * _Nullable)container diff --git a/keychain/ot/OTControlProtocol.m b/keychain/ot/OTControlProtocol.m index 003f186a..f98ae502 100644 --- a/keychain/ot/OTControlProtocol.m +++ b/keychain/ot/OTControlProtocol.m @@ -66,6 +66,7 @@ NSXPCInterface* OTSetupControlProtocol(NSXPCInterface* interface) { [interface setClasses:errorClasses forSelector:@selector(postCDPFollowupResult:type:error:containerName:contextName:reply:) argumentIndex:2 ofReply:NO]; [interface setClasses:errorClasses forSelector:@selector(postCDPFollowupResult:type:error:containerName:contextName:reply:) argumentIndex:0 ofReply:YES]; [interface setClasses:errorClasses forSelector:@selector(tapToRadar:description:radar:reply:) argumentIndex:0 ofReply:YES]; + [interface setClasses:errorClasses forSelector:@selector(resetAndEstablish:context:altDSID:resetReason:reply:) argumentIndex:0 ofReply:YES]; #if __OBJC2__ diff --git a/keychain/ot/OTCuttlefishContext.h b/keychain/ot/OTCuttlefishContext.h index db45bada..4665950c 100644 --- a/keychain/ot/OTCuttlefishContext.h +++ b/keychain/ot/OTCuttlefishContext.h @@ -48,6 +48,7 @@ #import #import "keychain/ot/OTJoiningConfiguration.h" #import "keychain/ot/OTOperationDependencies.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" #import @@ -62,9 +63,10 @@ NS_ASSUME_NONNULL_BEGIN OTAuthKitAdapterNotifier, OctagonStateMachineEngine, CKKSCloudKitAccountStateListener, - CKKSPeerUpdateListener> + CKKSPeerUpdateListener, + OTDeviceInformationNameUpdateListener> -@property (readonly) id cuttlefishXPCConnection; +@property (readonly) CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property (readonly) OTFollowup *followupHandler; @property (readonly) NSString *containerName; @@ -78,6 +80,7 @@ NS_ASSUME_NONNULL_BEGIN @property (readonly) BOOL postedEscrowRepairCFU; @property (readonly) BOOL postedRecoveryKeyCFU; @property (nullable, nonatomic) CKKSNearFutureScheduler* apsRateLimiter; +@property (nullable, nonatomic) CKKSNearFutureScheduler* sosConsistencyRateLimiter; @property (readonly, nullable) CKKSViewManager* viewManager; @@ -104,6 +107,8 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)accountNoLongerAvailable:(NSError**)error; - (BOOL)idmsTrustLevelChanged:(NSError**)error; +- (void)deviceNameUpdated; + - (void)startOctagonStateMachine; - (void)handlePairingRestart:(OTJoiningConfiguration*)config; @@ -120,7 +125,7 @@ NS_ASSUME_NONNULL_BEGIN preapprovedKeys:(NSArray* _Nullable)preapprovedKeys reply:(void (^)(NSError * _Nullable error))reply; -- (void)rpcResetAndEstablish:(nonnull void (^)(NSError * _Nullable))reply; +- (void)rpcResetAndEstablish:(CuttlefishResetReason)resetReason reply:(nonnull void (^)(NSError * _Nullable))reply; - (void)localReset:(nonnull void (^)(NSError * _Nullable))reply; @@ -139,7 +144,7 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys reply:(void (^)(NSError * _Nullable error))reply; - (void)rpcRemoveFriendsInClique:(NSArray*)peerIDs - reply:(void (^)(NSError*))reply; + reply:(void (^)(NSError * _Nullable))reply; - (void)notifyContainerChange:(APSIncomingMessage* _Nullable)notification; - (void)notifyContainerChangeWithUserInfo:(NSDictionary*)userInfo; @@ -171,10 +176,13 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys - (void)attemptSOSUpgrade:(void (^)(NSError* _Nullable error))reply; -- (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply; +- (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply NS_SWIFT_NAME(waitForOctagonUpgrade(reply:)); - (void)clearPendingCFUFlags; +- (BOOL)waitForReady:(int64_t)timeOffset; + + // For testing. - (void)setPostedBool:(BOOL)posted; - (OTAccountMetadataClassC_AccountState)currentMemoizedAccountState; diff --git a/keychain/ot/OTCuttlefishContext.m b/keychain/ot/OTCuttlefishContext.m index b8fd2275..3ebe0853 100644 --- a/keychain/ot/OTCuttlefishContext.m +++ b/keychain/ot/OTCuttlefishContext.m @@ -50,7 +50,6 @@ #import "keychain/ot/OTStates.h" #import "keychain/ot/OTFollowup.h" #import "keychain/ot/OTAuthKitAdapter.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTConstants.h" #import "keychain/ot/OTOperationDependencies.h" #import "keychain/ot/OTClique.h" @@ -113,6 +112,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; NSData* _entropy; NSArray* _preapprovedKeys; NSString* _recoveryKey; + CuttlefishResetReason _resetReason; BOOL _skipRateLimitingCheck; } @@ -195,7 +195,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [_sosAdapter registerForPeerChangeUpdates:self]; _authKitAdapter = authKitAdapter; _deviceAdapter = deviceInformationAdapter; - _cuttlefishXPCConnection = cuttlefish; + [_deviceAdapter registerForDeviceNameUpdates:self]; + + _cuttlefishXPCWrapper = [[CuttlefishXPCWrapper alloc] initWithCuttlefishXPCConnection:cuttlefish]; _lockStateTracker = lockStateTracker; _accountStateTracker = accountStateTracker; @@ -222,7 +224,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (void)dealloc { // TODO: how to invalidate this? - //[self.cuttlefishXPCConnection invalidate]; + //[self.cuttlefishXPCWrapper invalidate]; } - (void)notifyTrustChanged:(OTAccountMetadataClassC_TrustState)trustState { @@ -264,82 +266,77 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (void)machinesAdded:(NSArray*)machineIDs altDSID:(NSString*)altDSID { WEAKIFY(self); - dispatch_sync(self.queue, ^{ - NSError* metadataError = nil; - OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore _onqueueLoadOrCreateAccountMetadata:&metadataError]; + NSError* metadataError = nil; + OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError]; - if(!accountMetadata || metadataError) { - secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); - [self requestTrustedDeviceListRefresh]; - return; - } + if(!accountMetadata || metadataError) { + // TODO: collect a sysdiagnose here if the error is not "device is in class D" + secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); + [self requestTrustedDeviceListRefresh]; + return; + } - if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { - secnotice("octagon-authkit", "Machines-added push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); - return; - } + if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { + secnotice("octagon-authkit", "Machines-added push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); + return; + } - secnotice("octagon-authkit", "adding machines for altDSID(%@): %@", altDSID, machineIDs); - - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon-authkit: Can't talk with TrustedPeersHelper: %@", error); - }] addAllowedMachineIDsWithContainer:self.containerName - context:self.contextID - machineIDs:machineIDs - reply:^(NSError* error) { - if (error) { - secerror("octagon-authkit: addAllow errored: %@", error); - STRONGIFY(self); - [self requestTrustedDeviceListRefresh]; - } else { - secnotice("octagon-authkit", "addAllow succeeded"); + secnotice("octagon-authkit", "adding machines for altDSID(%@): %@", altDSID, machineIDs); - OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification - conditions:OctagonPendingConditionsDeviceUnlocked]; - [self.stateMachine handlePendingFlag:pendingFlag]; - } - }]; - }); + [self.cuttlefishXPCWrapper addAllowedMachineIDsWithContainer:self.containerName + context:self.contextID + machineIDs:machineIDs + reply:^(NSError* error) { + STRONGIFY(self); + if (error) { + secerror("octagon-authkit: addAllow errored: %@", error); + [self requestTrustedDeviceListRefresh]; + } else { + secnotice("octagon-authkit", "addAllow succeeded"); + + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; + } + }]; } - (void)machinesRemoved:(NSArray*)machineIDs altDSID:(NSString*)altDSID { WEAKIFY(self); - dispatch_sync(self.queue, ^{ - NSError* metadataError = nil; - OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore _onqueueLoadOrCreateAccountMetadata:&metadataError]; - if(!accountMetadata || metadataError) { - secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); - [self requestTrustedDeviceListRefresh]; - return; - } + NSError* metadataError = nil; + OTAccountMetadataClassC* accountMetadata = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError]; - if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { - secnotice("octagon-authkit", "Machines-removed push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); - return; - } + if(!accountMetadata || metadataError) { + // TODO: collect a sysdiagnose here if the error is not "device is in class D" + secerror("octagon-authkit: Unable to load account metadata: %@", metadataError); + [self requestTrustedDeviceListRefresh]; + return; + } - secnotice("octagon-authkit", "removing machines for altDSID(%@): %@", altDSID, machineIDs); - - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon-authkit: Can't talk with TrustedPeersHelper: %@", error); - }] removeAllowedMachineIDsWithContainer:self.containerName - context:self.contextID - machineIDs:machineIDs - reply:^(NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon-authkit: removeAllow errored: %@", error); - } else { - secnotice("octagon-authkit", "removeAllow succeeded"); - } + if(!altDSID || ![accountMetadata.altDSID isEqualToString:altDSID]) { + secnotice("octagon-authkit", "Machines-removed push is for wrong altDSID (%@); current altDSID (%@)", altDSID, accountMetadata.altDSID); + return; + } - // We don't necessarily trust remove pushes; they could be delayed past when an add has occurred. - // Request that the full list be rechecked. - [self requestTrustedDeviceListRefresh]; - }]; - }); + secnotice("octagon-authkit", "removing machines for altDSID(%@): %@", altDSID, machineIDs); + + [self.cuttlefishXPCWrapper removeAllowedMachineIDsWithContainer:self.containerName + context:self.contextID + machineIDs:machineIDs + reply:^(NSError* _Nullable error) { + STRONGIFY(self); + if (error) { + secerror("octagon-authkit: removeAllow errored: %@", error); + } else { + secnotice("octagon-authkit", "removeAllow succeeded"); + } + + // We don't necessarily trust remove pushes; they could be delayed past when an add has occurred. + // Request that the full list be rechecked. + [self requestTrustedDeviceListRefresh]; + }]; } - (void)incompleteNotificationOfMachineIDListChange @@ -431,16 +428,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; - (BOOL)idmsTrustLevelChanged:(NSError**)error { - // Cool! If we believe there's no sufficient iCloud account, let's try checking again - CKKSResultOperation* checkHSA2 = [OctagonStateTransitionOperation named:[NSString stringWithFormat:@"%@", @"check-hsa2-status"] - entering:OctagonStateDetermineiCloudAccountState]; - - OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"check-hsa2-state" - sourceStates:[NSSet setWithArray: @[OctagonStateWaitForHSA2]] - serialQueue:self.queue - timeout:OctagonStateTransitionDefaultTimeout - transitionOp:checkHSA2]; - [self.stateMachine handleExternalRequest:request]; + [self.stateMachine handleFlag:OctagonFlagIDMSLevelChanged]; return YES; } @@ -512,7 +500,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; contextID:self.contextID intendedState:OctagonStateBecomeUntrusted errorState:OctagonStateError - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; NSMutableSet* sourceStates = [NSMutableSet setWithArray: OctagonStateMap().allKeys]; [self.stateMachine doSimpleStateMachineRPC:@"local-reset" op:pendingOp sourceStates:sourceStates reply:reply]; @@ -558,8 +546,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; reply:reply]; } -- (void)rpcResetAndEstablish:(nonnull void (^)(NSError * _Nullable))reply +- (void)rpcResetAndEstablish:(CuttlefishResetReason)resetReason reply:(nonnull void (^)(NSError * _Nullable))reply { + _resetReason = resetReason; + // The reset flow can split into an error-handling path halfway through; this is okay OctagonStateTransitionPath* path = [OctagonStateTransitionPath pathFromDictionary: @{ OctagonStateResetBecomeUntrusted: @{ @@ -587,7 +577,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } - (void)rpcRemoveFriendsInClique:(NSArray*)peerIDs - reply:(void (^)(NSError*))reply + reply:(void (^)(NSError * _Nullable))reply { OTRemovePeersOperation* op = [[OTRemovePeersOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady @@ -626,9 +616,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; sosAdapter:self.sosAdapter octagonAdapter:self.octagonAdapter authKitAdapter:self.authKitAdapter + deviceInfoAdapter:self.deviceAdapter viewManager:self.viewManager lockStateTracker:self.lockStateTracker - cuttlefishXPC:self.cuttlefishXPCConnection + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper escrowRequestClass:self.escrowRequestClass]; } @@ -682,6 +673,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } if([currentState isEqualToString:OctagonStateWaitForHSA2]) { + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + return [OctagonStateTransitionOperation named:@"hsa2-check" + entering:OctagonStateDetermineiCloudAccountState]; + } + secnotice("octagon", "Waiting for an HSA2 account"); return nil; } @@ -731,6 +728,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; if ([currentState isEqualToString:OctagonStatePostRepairCFU]) { return [self postRepairCFUAndBecomeUntrusted]; } + + if ([currentState isEqualToString:OctagonStateHealthCheckReset]) { + // A small violation of state machines... + _resetReason = CuttlefishResetReasonHealthCheck; + return [OctagonStateTransitionOperation named:@"begin-reset" + entering:OctagonStateResetBecomeUntrusted]; + } #pragma mark --- Watch Pairing States @@ -790,6 +794,11 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [OctagonStateTransitionOperation named:@"untrusted-update" entering:OctagonStateUntrustedUpdated]; } + + // We're untrusted; no need for the IDMS level flag anymore + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + } } if([currentState isEqualToString:OctagonStateUntrustedUpdated]) { @@ -864,11 +873,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; contextID:self.contextID intendedState:OctagonStateNoAccount errorState:OctagonStateNoAccount - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; } if([currentState isEqualToString:OctagonStateEnsureConsistency]) { - secnotice("octagon", "Ensuring consistency of things that might've changed"); if(self.sosAdapter.sosEnabled) { return [[OTEnsureOctagonKeyConsistency alloc] initWithDependencies:self.operationDependencies @@ -967,7 +975,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; OTUpdateTrustedDeviceListOperation* op = [[OTUpdateTrustedDeviceListOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateInitiatorJoin listUpdatesState:OctagonStateInitiatorJoin - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted retryFlag:nil]; return op; @@ -975,7 +983,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; OTJoinWithVoucherOperation* op = [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady ckksConflictState:OctagonStateInitiatorJoinCKKSReset - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted voucherData:_vouchData voucherSig:_vouchSig preapprovedKeys:_preapprovedKeys]; @@ -990,7 +998,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; return [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateBecomeReady ckksConflictState:OctagonStateBecomeUntrusted - errorState:OctagonStateError + errorState:OctagonStateBecomeUntrusted voucherData:_vouchData voucherSig:_vouchSig preapprovedKeys:_preapprovedKeys]; @@ -1001,9 +1009,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } else if([currentState isEqualToString:OctagonStateResetAndEstablish]) { return [[OTResetOperation alloc] init:self.containerName contextID:self.contextID + reason:_resetReason intendedState:OctagonStateResetAnyMissingTLKCKKSViews errorState:OctagonStateError - cuttlefishXPC:self.cuttlefishXPCConnection]; + cuttlefishXPCWrapper:self.cuttlefishXPCWrapper]; } else if([currentState isEqualToString:OctagonStateResetAnyMissingTLKCKKSViews]) { return [[OTResetCKKSZonesLackingTLKsOperation alloc] initWithDependencies:self.operationDependencies @@ -1070,17 +1079,25 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; sosNotPresentState:OctagonStateReady errorState:OctagonStateReady]; - } else if([currentState isEqualToString: OctagonStateAssistCKKSTLKUpload]) { + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUpload]) { return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies intendedState:OctagonStateReady + ckksConflictState:OctagonStateAssistCKKSTLKUploadCKKSReset errorState:OctagonStateReady]; - } else if([currentState isEqualToString:OctagonStateReady]) { - if([flags _onqueueContains:OctagonFlagPerformHealthCheck]) { - [flags _onqueueRemoveFlag:OctagonFlagPerformHealthCheck]; - return [self cuttlefishTrustEvaluation]; - } + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUploadCKKSReset]) { + return [[OTLocalCKKSResetOperation alloc] initWithDependencies:self.operationDependencies + intendedState:OctagonStateAssistCKKSTLKUploadAfterCKKSReset + errorState:OctagonStateBecomeReady]; + + } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUploadAfterCKKSReset]) { + // If CKKS fails again, just go to 'ready' + return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies + intendedState:OctagonStateReady + ckksConflictState:OctagonStateReady + errorState:OctagonStateReady]; + } else if([currentState isEqualToString:OctagonStateReady]) { if([flags _onqueueContains:OctagonFlagCKKSRequestsTLKUpload]) { [flags _onqueueRemoveFlag:OctagonFlagCKKSRequestsTLKUpload]; return [OctagonStateTransitionOperation named:@"ckks-assist" @@ -1117,6 +1134,29 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; } } + if([flags _onqueueContains:OctagonFlagAttemptSOSConsistency]) { + [flags _onqueueRemoveFlag:OctagonFlagAttemptSOSConsistency]; + if(self.sosAdapter.sosEnabled) { + secnotice("octagon", "Attempting SOS consistency checks"); + return [OctagonStateTransitionOperation named:@"attempt-sos-update-preapproval" + entering:OctagonStateEnsureConsistency]; + } else { + secnotice("octagon", "Someone would like us to check SOS consistency, but this platform doesn't support SOS."); + } + } + + if([flags _onqueueContains:OctagonFlagAccountIsAvailable]) { + // We're in ready--we already know the account is available + secnotice("octagon", "Removing 'account is available' flag"); + [flags _onqueueRemoveFlag:OctagonFlagAccountIsAvailable]; + } + + // We're ready; no need for the IDMS level flag anymore + if([flags _onqueueContains:OctagonFlagIDMSLevelChanged]) { + secnotice("octagon", "Removing 'IDMS level changed' flag"); + [flags _onqueueRemoveFlag:OctagonFlagIDMSLevelChanged]; + } + secnotice("octagon", "Entering state ready"); [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:OctagonAnalyticsLastKeystateReady]; [self.launchSequence launch]; @@ -1128,10 +1168,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; retryFlag:OctagonFlagCuttlefishNotification]; } else if ([currentState isEqualToString:OctagonStateError]) { - if([flags _onqueueContains:OctagonFlagPerformHealthCheck]) { - [flags _onqueueRemoveFlag:OctagonFlagPerformHealthCheck]; - return [self cuttlefishTrustEvaluation]; - } } return nil; @@ -1281,19 +1317,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; secnotice("octagon-health", "Not posting confirm passcode CFU, already pending a prerecord upload"); } } - if (op.resetOctagon) { - secnotice("octagon-health", "Resetting Octagon as per Cuttlefish request"); - // uh oh let's reset octagon.. - - [self rpcResetAndEstablish:^(NSError *error) { - if(error){ - secerror("octagon-health: failed to reset octagon: %@", error); - op.error = error; - } else { - secnotice("octagon-health", "successfully reset octagon"); - } - }]; - } }]; [callback addDependency:op]; [self.operationQueue addOperation: callback]; @@ -1673,9 +1696,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; NSString *trustState = OTAccountMetadataClassC_TrustStateAsString(self.currentMemoizedTrustState); OctagonState* currentState = [self.stateMachine waitForState:OctagonStateReady wait:3*NSEC_PER_SEC]; - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper, report is lost: %@", error); - }] reportHealthWithContainer:self.containerName context:self.contextID stateMachineState:currentState trustState:trustState reply:^(NSError * _Nullable error) { + [self.cuttlefishXPCWrapper reportHealthWithContainer:self.containerName context:self.contextID stateMachineState:currentState trustState:trustState reply:^(NSError * _Nullable error) { if (error) { secerror("octagon: health report is lost: %@", error); } @@ -1780,6 +1801,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.apsRateLimiter trigger]; } +- (BOOL)waitForReady:(int64_t)timeOffset +{ + OctagonState* currentState = [self.stateMachine waitForState:OctagonStateReady wait:timeOffset]; + return [currentState isEqualToString:OctagonStateReady]; + +} + - (OTAccountMetadataClassC_TrustState)currentMemoizedTrustState { NSError* localError = nil; @@ -1826,6 +1854,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.stateMachine handleFlag:OctagonFlagFetchAuthKitMachineIDList]; } +#pragma mark --- Device Info update handling + +- (void)deviceNameUpdated { + secnotice("octagon-devicename", "device name updated: %@", self.contextID); + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.stateMachine handlePendingFlag:pendingFlag]; +} + #pragma mark --- SOS update handling @@ -1844,13 +1881,28 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; secnotice("octagon-sos", "This platform doesn't support SOS. This is probably a bug?"); } - //OTUpdatePreapprovalsOperation* op = [[OTUpdatePreapprovalsOperation alloc] initWithDependencies:self.operationDependencies]; + if (self.sosConsistencyRateLimiter == nil) { + secnotice("octagon", "creating SOS consistency rate limiter"); + dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 200 * NSEC_PER_MSEC : 2 * NSEC_PER_SEC); + dispatch_time_t maximumDelay = (SecCKKSReduceRateLimiting() ? 10 * NSEC_PER_SEC : 30 * NSEC_PER_SEC); + + WEAKIFY(self); + + void (^block)(void) = ^{ + STRONGIFY(self); + [self.stateMachine handleFlag:OctagonFlagAttemptSOSConsistency]; + }; + + self.sosConsistencyRateLimiter = [[CKKSNearFutureScheduler alloc] initWithName:@"sos-consistency-ratelimiter" + initialDelay:initialDelay + expontialBackoff:2 + maximumDelay:maximumDelay + keepProcessAlive:false + dependencyDescriptionCode:CKKSResultDescriptionPendingZoneChangeFetchScheduling + block:block]; + } - [self.stateMachine doSimpleStateMachineRPC:@"update-sos-preapprovals" - op:[OctagonStateTransitionOperation named:@"sos-peers-changed" - entering:OctagonStateUpdateSOSPreapprovals] - sourceStates:[NSSet setWithObject:OctagonStateReady] - reply:^(NSError* error) {}]; + [self.sosConsistencyRateLimiter trigger]; } #pragma mark --- External Interfaces @@ -1975,17 +2027,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC; [self.stateMachine doWatchedStateMachineRPC:@"rpc-join-with-bottle" sourceStates:OctagonInAccountStates() path:path - reply:^(NSError *joinError) { - if(joinError) { - if([joinError isCuttlefishError: CuttlefishErrorResultGraphNotFullyReachable]){ - secnotice("octagon", "setting flag for cuttlefish health check"); - [self.stateMachine handleFlag:OctagonFlagPerformHealthCheck]; - } - reply(joinError); - } else { - reply(nil); - } - }]; + reply:reply]; } -(void)joinWithRecoveryKey:(NSString*)recoveryKey @@ -2164,21 +2206,20 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } result[@"CoreFollowUp"] = [self.followupHandler sysdiagnoseStatus]; + result[@"lastOctagonPush"] = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastOctagonPush]; + - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to dump state for status RPC: %@", error); - reply(nil, error); - }] dumpWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { - secnotice("octagon", "Finished dump for status RPC"); - if(dumpError) { - result[@"contextDumpError"] = dumpError; - } else { - result[@"contextDump"] = dump; - } - reply(result, nil); - }]; + [self.cuttlefishXPCWrapper dumpWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { + secnotice("octagon", "Finished dump for status RPC"); + if(dumpError) { + result[@"contextDumpError"] = dumpError; + } else { + result[@"contextDump"] = dump; + } + reply(result, nil); + }]; } - (void)rpcFetchEgoPeerID:(void (^)(NSString* peerID, NSError* error))reply @@ -2204,45 +2245,42 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to fetch peers: %@", error); - reply(nil, error); - }] dumpWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { - // Pull out our peers - if(dumpError) { - secnotice("octagon", "Unable to dump info: %@", dumpError); - reply(nil, dumpError); - return; - } - - NSDictionary* selfInfo = dump[@"self"]; - NSArray* peers = dump[@"peers"]; - NSArray* trustedPeerIDs = selfInfo[@"dynamicInfo"][@"included"]; - - NSMutableDictionary* peerMap = [NSMutableDictionary dictionary]; - - for(NSString* peerID in trustedPeerIDs) { - NSDictionary* peerMatchingID = nil; - - for(NSDictionary* peer in peers) { - if([peer[@"peerID"] isEqualToString:peerID]) { - peerMatchingID = peer; - break; - } - } + [self.cuttlefishXPCWrapper dumpWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable dump, NSError * _Nullable dumpError) { + // Pull out our peers + if(dumpError) { + secnotice("octagon", "Unable to dump info: %@", dumpError); + reply(nil, dumpError); + return; + } - if(!peerMatchingID) { - secerror("octagon: have a trusted peer ID without peer information: %@", peerID); - continue; - } + NSDictionary* selfInfo = dump[@"self"]; + NSArray* peers = dump[@"peers"]; + NSArray* trustedPeerIDs = selfInfo[@"dynamicInfo"][@"included"]; + + NSMutableDictionary* peerMap = [NSMutableDictionary dictionary]; + + for(NSString* peerID in trustedPeerIDs) { + NSDictionary* peerMatchingID = nil; + + for(NSDictionary* peer in peers) { + if([peer[@"peerID"] isEqualToString:peerID]) { + peerMatchingID = peer; + break; + } + } + + if(!peerMatchingID) { + secerror("octagon: have a trusted peer ID without peer information: %@", peerID); + continue; + } - peerMap[peerID] = peerMatchingID[@"stableInfo"][@"device_name"]; - } + peerMap[peerID] = peerMatchingID[@"stableInfo"][@"device_name"]; + } - reply(peerMap, nil); - }]; + reply(peerMap, nil); + }]; } - (void)rpcSetRecoveryKey:(NSString*)recoveryKey reply:(void (^)(NSError * _Nullable error))reply @@ -2319,26 +2357,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys return; } - NSXPCConnection* c = [self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *xpcError) { - localError = xpcError; - secnotice("octagon", "rpcTrustStatus: Failed to get XPC connection: %@", xpcError); - }]; - - if(localError){ - reply(CliqueStatusError, nil, nil, NO, localError); - return; - } __block NSString* peerID = nil; __block NSDictionary* peerModelCounts = nil; __block BOOL excluded = NO; __block CliqueStatus trustStatus = CliqueStatusError; - [c 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; - peerModelCounts = egoStatus.peerCountsByModelID; + peerModelCounts = egoStatus.viablePeerCountsByModelID; localError = xpcError; if(xpcError) { @@ -2394,21 +2423,18 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys } // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - reply(nil, nil, error); - }] fetchViableBottlesWithContainer:self.containerName - context:self.contextID - reply:^(NSArray* _Nullable sortedEscrowRecordIDs, NSArray* _Nullable sortedPartialEscrowRecordIDs, NSError * _Nullable error) { - if(error){ - secerror("octagon: error fetching all viable bottles: %@", error); - reply(nil, nil, error); - }else{ - secnotice("octagon", "fetched viable bottles: %@", sortedEscrowRecordIDs); - secnotice("octagon", "fetched partially viable bottles: %@", sortedPartialEscrowRecordIDs); - reply(sortedEscrowRecordIDs, sortedPartialEscrowRecordIDs, error); - } - }]; + [self.cuttlefishXPCWrapper fetchViableBottlesWithContainer:self.containerName + context:self.contextID + reply:^(NSArray* _Nullable sortedEscrowRecordIDs, NSArray* _Nullable sortedPartialEscrowRecordIDs, NSError * _Nullable error) { + if(error){ + secerror("octagon: error fetching all viable bottles: %@", error); + reply(nil, nil, error); + }else{ + secnotice("octagon", "fetched viable bottles: %@", sortedEscrowRecordIDs); + secnotice("octagon", "fetched partially viable bottles: %@", sortedPartialEscrowRecordIDs); + reply(sortedEscrowRecordIDs, sortedPartialEscrowRecordIDs, error); + } + }]; } - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy, @@ -2417,20 +2443,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys NSError* _Nullable error))reply { // As this isn't a state-modifying operation, we don't need to go through the state machine. - [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - reply(nil, nil, nil, error); - }] fetchEscrowContentsWithContainer:self.containerName - context:self.contextID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - if(error){ - secerror("octagon: error fetching escrow contents: %@", error); - reply(nil, nil, nil, error); - }else{ - secnotice("octagon", "fetched escrow contents for bottle: %@", bottleID); - reply(entropy, bottleID, signingPublicKey, error); - } - }]; + [self.cuttlefishXPCWrapper fetchEscrowContentsWithContainer:self.containerName + context:self.contextID + reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { + if(error){ + secerror("octagon: error fetching escrow contents: %@", error); + reply(nil, nil, nil, error); + }else{ + secnotice("octagon", "fetched escrow contents for bottle: %@", bottleID); + reply(entropy, bottleID, signingPublicKey, error); + } + }]; } - (void)rpcValidatePeers:(void (^)(NSDictionary* _Nullable result, NSError* _Nullable error))reply @@ -2447,20 +2470,17 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys return; } - [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secnotice("octagon", "Unable to validatePeers RPC: %@", error); - reply(nil, error); - }] validatePeersWithContainer:self.containerName - context:self.contextID - reply:^(NSDictionary * _Nullable validateData, NSError * _Nullable dumpError) { - secnotice("octagon", "Finished validatePeers for status RPC"); - if(dumpError) { - result[@"error"] = dumpError; - } else { - result[@"validate"] = validateData; - } - reply(result, nil); - }]; + [self.cuttlefishXPCWrapper validatePeersWithContainer:self.containerName + context:self.contextID + reply:^(NSDictionary * _Nullable validateData, NSError * _Nullable dumpError) { + secnotice("octagon", "Finished validatePeers for status RPC"); + if(dumpError) { + result[@"error"] = dumpError; + } else { + result[@"validate"] = validateData; + } + reply(result, nil); + }]; } @@ -2583,6 +2603,9 @@ preapprovedKeys:(NSArray* _Nullable)preapprovedKeys OctagonStateReady: [OctagonStateTransitionPathStep success], OctagonStateWaitForUnlock: [OctagonStateTransitionPathStep success], }, + // Cuttlefish can suggest we reset the world. Consider reaching here a success, + // instead of tracking the whole reset. + OctagonStateHealthCheckReset: [OctagonStateTransitionPathStep success], }, }, }, diff --git a/keychain/ot/OTDefines.h b/keychain/ot/OTDefines.h index 1313fda0..216d2614 100644 --- a/keychain/ot/OTDefines.h +++ b/keychain/ot/OTDefines.h @@ -37,73 +37,86 @@ extern NSString* const CuttlefishTrustZone; extern NSString* const CuttlefishErrorDomain; extern NSString* const TrustedPeersHelperErrorDomain; +extern NSString* const CuttlefishErrorRetryAfterKey; + /* Octagon Errors */ typedef enum { - OTErrorNoColumn = 1, - OTErrorKeyGeneration = 2, - OTErrorEmptySecret = 3, - OTErrorEmptyDSID = 4, + //OTErrorNoColumn = 1, + //OTErrorKeyGeneration = 2, + //OTErrorEmptySecret = 3, + //OTErrorEmptyDSID = 4, OTErrorNoIdentity = 5, - OTErrorRestoreFailed = 6, - OTErrorRestoredPeerEncryptionKeyFailure = 7, - OTErrorRestoredPeerSigningKeyFailure = 8, - OTErrorEntropyCreationFailure = 9, + //OTErrorRestoreFailed = 6, + //OTErrorRestoredPeerEncryptionKeyFailure = 7, + //OTErrorRestoredPeerSigningKeyFailure = 8, + //OTErrorEntropyCreationFailure = 9, OTErrorDeserializationFailure = 10, - OTErrorDecryptFailure = 11, - OTErrorPrivateKeyFailure = 12, - OTErrorEscrowSigningSPKI = 13, - OTErrorBottleID = 14, - OTErrorOTLocalStore = 15, - OTErrorOTCloudStore = 16, - OTErrorEmptyEscrowRecordID = 17, - OTErrorNoBottlePeerRecords = 18, - OTErrorCoreFollowUp = 19, + //OTErrorDecryptFailure = 11, + //OTErrorPrivateKeyFailure = 12, + //OTErrorEscrowSigningSPKI = 13, + //OTErrorBottleID = 14, + //OTErrorOTLocalStore = 15, + //OTErrorOTCloudStore = 16, + //OTErrorEmptyEscrowRecordID = 17, + //OTErrorNoBottlePeerRecords = 18, + //OTErrorCoreFollowUp = 19, OTErrorFeatureNotEnabled = 20, OTErrorCKCallback = 21, - OTErrorRampInit = 22, + //OTErrorRampInit = 22, OTErrorCKTimeOut = 23, OTErrorNoNetwork = 24, OTErrorNotSignedIn = 25, OTErrorRecordNotFound = 26, - OTErrorNoEscrowKeys = 27, - OTErrorBottleUpdate = 28, + //OTErrorNoEscrowKeys = 27, + //OTErrorBottleUpdate = 28, OTErrorNotSupported = 29, OTErrorUnexpectedStateTransition = 30, OTErrorNoSuchContext = 31, - OTErrorTimeout = 32, - OTErrorMasterKey = 33, - OTErrorNotTrusted = 34, + //OTErrorTimeout = 32, + //OTErrorMasterKey = 33, + //OTErrorNotTrusted = 34, OTErrorLimitedPeer = 35, - OTErrorNoOctagonKeysInSOS = 36, - OTErrorNeedsAuthentication = 37, + //OTErrorNoOctagonKeysInSOS = 36, + //OTErrorNeedsAuthentication = 37, OTErrorOctagonAdapter = 38, OTErrorSOSAdapter = 39, - OctagonErrorNoAccount = 40, + //OctagonErrorNoAccount = 40, + OTErrorRecoveryKeyMalformed = 41, } OctagonErrorCode; #define OTMasterSecretLength 72 -typedef enum { - OctagonSigningKey = 1, - OctagonEncryptionKey = 2 -} OctagonKeyType; - -typedef enum { - UNCLEAR = 0, - BOTTLE = 1, - NOBOTTLE = 2 -} OctagonBottleCheckState; - typedef NS_ENUM(NSInteger, TrustedPeersHelperErrorCode) { TrustedPeersHelperErrorNoPreparedIdentity = 1, TrustedPeersHelperErrorNoPeersPreapprovePreparedIdentity = 14, TrustedPeersHelperErrorCodeNotEnrolled = 34, }; +// See cuttlefish/CuttlefishService/Sources/CuttlefishService/CuttlefishError.swift typedef NS_ENUM(NSInteger, CuttlefishErrorCode) { + CuttlefishErrorEstablishFailed = 1001, + CuttlefishErrorJoinFailed = 1002, + CuttlefishErrorUpdateTrustFailed = 1004, + CuttlefishErrorInvalidChangeToken = 1005, + CuttlefishErrorMalformedRecord = 1006, CuttlefishErrorResultGraphNotFullyReachable = 1007, + CuttlefishErrorResultGraphHasNoPotentiallyTrustedPeers = 1008, + CuttlefishErrorResultGraphHasSplitKnowledge = 1009, + CuttlefishErrorResultGraphHasPeerWithNoSelf = 1010, + CuttlefishErrorInvalidEscrowProxyOperation = 1011, + CuttlefishErrorRecordWrongType = 1012, + CuttlefishErrorMissingMandatoryField = 1013, + CuttlefishErrorMalformedViewKeyHierarchy = 1014, + CuttlefishErrorUnknownView = 1015, + CuttlefishErrorEstablishPeerFailed = 1016, + CuttlefishErrorEstablishBottleFailed = 1017, + CuttlefishErrorChangeTokenExpired = 1018, CuttlefishErrorTransactionalFailure = 1019, + CuttlefishErrorSetRecoveryKeyFailed = 1020, + CuttlefishErrorRetryableServerFailure = 1021, + CuttlefishErrorPreflightGraphValidationError = 1022, CuttlefishErrorKeyHierarchyAlreadyExists = 1033, + CuttlefishErrorDuplicatePeerIdUnderConsideration = 1034, }; NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTDefines.m b/keychain/ot/OTDefines.m index 76302f65..0aa95a36 100644 --- a/keychain/ot/OTDefines.m +++ b/keychain/ot/OTDefines.m @@ -33,3 +33,5 @@ NSString* OTCKContainerName = @"com.apple.security.keychain"; NSString* const CuttlefishTrustZone = @"CuttlefishTrustZone"; NSString* const CuttlefishErrorDomain = @"CuttlefishError"; NSString* const TrustedPeersHelperErrorDomain = @"com.apple.security.trustedpeers.container"; + +NSString* const CuttlefishErrorRetryAfterKey = @"retryafter"; diff --git a/keychain/ot/OTDeviceInformationAdapter.h b/keychain/ot/OTDeviceInformationAdapter.h index f2c26f54..43279916 100644 --- a/keychain/ot/OTDeviceInformationAdapter.h +++ b/keychain/ot/OTDeviceInformationAdapter.h @@ -3,6 +3,10 @@ NS_ASSUME_NONNULL_BEGIN +@protocol OTDeviceInformationNameUpdateListener +- (void)deviceNameUpdated; +@end + @protocol OTDeviceInformationAdapter /* Returns a string like "iPhone3,5" */ @@ -17,6 +21,9 @@ NS_ASSUME_NONNULL_BEGIN /* Returns the serial number as a string. */ - (NSString*)serialNumber; +/* register for deviceName updates */ +- (void)registerForDeviceNameUpdates:(id)listener; + @end @interface OTDeviceInformationActualAdapter : NSObject diff --git a/keychain/ot/OTDeviceInformationAdapter.m b/keychain/ot/OTDeviceInformationAdapter.m index 4fa6e072..acd71ebe 100644 --- a/keychain/ot/OTDeviceInformationAdapter.m +++ b/keychain/ot/OTDeviceInformationAdapter.m @@ -1,4 +1,6 @@ -#import "OTDeviceInformationAdapter.h" +#import "keychain/ot/OTDeviceInformationAdapter.h" +#import "keychain/ot/OTConstants.h" +#import "keychain/ckks/CKKSListenerCollection.h" #import "keychain/ckks/CKKS.h" #include @@ -12,8 +14,22 @@ #include #endif +static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *context); + +@interface OTDeviceInformationActualAdapter () +@property CKKSListenerCollection>* deviceNameUpdateListeners; +@property (assign) SCDynamicStoreRef store; +@end + @implementation OTDeviceInformationActualAdapter +- (void)dealloc { + if (self.store) { + CFRelease(self.store); + self.store = NULL; + } +} + - (NSString*)modelID { static NSString *hwModel = nil; @@ -57,6 +73,18 @@ } } +- (void)registerForDeviceNameUpdates:(id)listener +{ + // Octagon only uses the device name on internal releases. + // Therefore, if this is not an internal release, don't bother registering clients--they don't need the update. + if (SecIsInternalRelease()) { + @synchronized (self) { + [self setupDeviceNameListener]; + [self.deviceNameUpdateListeners registerListener:listener]; + } + } +} + - (NSString*)osVersion { return SecCKKSHostOSVersion(); @@ -97,5 +125,38 @@ #endif + +- (void)setupDeviceNameListener { + if (self.deviceNameUpdateListeners == nil) { + self.deviceNameUpdateListeners = [[CKKSListenerCollection alloc] initWithName:@"OTDeviceInformationActualAdapter"]; + + CFStringRef computerKey = SCDynamicStoreKeyCreateComputerName(NULL); + if (computerKey == NULL) { + return; + } + NSArray *keys = @[ (__bridge NSString *)computerKey]; + CFRelease(computerKey); + + SCDynamicStoreContext context = { .info = (void *)(__bridge CFTypeRef)self }; + self.store = SCDynamicStoreCreate(NULL, CFSTR("OTDeviceInformationActualAdapter"), updateDeviceNameChanges, &context); + if (self.store == NULL) { + return; + } + + SCDynamicStoreSetNotificationKeys(self.store, (__bridge CFArrayRef)keys, NULL); + SCDynamicStoreSetDispatchQueue(self.store, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + } +} + @end +static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, void *info) +{ + secnotice("octagon", "Notified that the device name has changed"); + OTDeviceInformationActualAdapter *adapter = (__bridge id)info; + + [adapter.deviceNameUpdateListeners iterateListeners:^void(id object){ + [object deviceNameUpdated]; + }]; +} + diff --git a/keychain/ot/OTEnsureOctagonKeyConsistency.m b/keychain/ot/OTEnsureOctagonKeyConsistency.m index 985ee0a8..bb86a39c 100644 --- a/keychain/ot/OTEnsureOctagonKeyConsistency.m +++ b/keychain/ot/OTEnsureOctagonKeyConsistency.m @@ -39,7 +39,7 @@ #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ot/ObjCImprovements.h" -#import +#import "keychain/securityd/SOSCloudCircleServer.h" @interface OTEnsureOctagonKeyConsistency () @property OTOperationDependencies* deps; @@ -64,7 +64,7 @@ - (void)groupStart { - secnotice("octagon-sos", "Beginning ensuring Octagon keys are the same between "); + secnotice("octagon-sos", "Beginning ensuring Octagon keys are set properly in SOS"); self.finishOp = [[NSOperation alloc] init]; [self dependOnBeforeGroupFinished:self.finishOp]; @@ -99,7 +99,7 @@ NSError* fetchSelfPeersError = nil; CKKSSelves *selfPeers = [octagonAdapter fetchSelfPeers:&fetchSelfPeersError]; - if(fetchSelfPeersError) { + if((!selfPeers) || fetchSelfPeersError) { secnotice("octagon", "failed to retrieve self peers: %@", fetchSelfPeersError); self.error = fetchSelfPeersError; [self runBeforeGroupFinished:self.finishOp]; diff --git a/keychain/ot/OTEpochOperation.h b/keychain/ot/OTEpochOperation.h index 8180f4d2..b474f6af 100644 --- a/keychain/ot/OTEpochOperation.h +++ b/keychain/ot/OTEpochOperation.h @@ -27,19 +27,19 @@ #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" @class OTCuttlefishContext; NS_ASSUME_NONNULL_BEGIN @interface OTEpochOperation : CKKSGroupOperation -@property OctagonState* nextState; -- (instancetype)init NS_UNAVAILABLE; -- (instancetype)initForCuttlefishContext:(OTCuttlefishContext*)context - intendedState:(OctagonState*)intendedState - errorState:(OctagonState*)errorState; -@property (weak) OTCuttlefishContext* cuttlefishContext; +- (instancetype)init:(NSString*)containerName + contextID:(NSString*)contextID + intendedState:(OctagonState*)intendedState + errorState:(OctagonState*)errorState +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; @property (nonatomic) uint64_t epoch; diff --git a/keychain/ot/OTEpochOperation.m b/keychain/ot/OTEpochOperation.m index 6d74b5bf..de28fd39 100644 --- a/keychain/ot/OTEpochOperation.m +++ b/keychain/ot/OTEpochOperation.m @@ -31,17 +31,29 @@ #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ot/ObjCImprovements.h" +@interface OTEpochOperation () +@property NSString* containerName; +@property NSString* contextID; +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; +@end + @implementation OTEpochOperation @synthesize intendedState = _intendedState; +@synthesize nextState = _nextState; -- (instancetype)initForCuttlefishContext:(OTCuttlefishContext*)context - intendedState:(OctagonState*)intendedState - errorState:(OctagonState*)errorState +- (instancetype)init:(NSString*)containerName + contextID:(NSString*)contextID + intendedState:(OctagonState*)intendedState + errorState:(OctagonState*)errorState +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; _nextState = errorState; - self.cuttlefishContext = context; + + _containerName = containerName; + _contextID = contextID; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; } return self; } @@ -53,30 +65,20 @@ NSOperation* finishOp = [[NSOperation alloc] init]; [self dependOnBeforeGroupFinished:finishOp]; - OTCuttlefishContext* strongCuttlefishContext = self.cuttlefishContext; - WEAKIFY(self); - - [[strongCuttlefishContext.cuttlefishXPCConnection remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:finishOp]; - - }] fetchEgoEpochWithContainer:strongCuttlefishContext.containerName - context:strongCuttlefishContext.contextID - reply:^(uint64_t epoch, NSError* _Nullable error) { - STRONGIFY(self); - if(error) { - secerror("octagon: Error getting epoch: %@", error); - self.error = error; - } else { - self.epoch = epoch; - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:finishOp]; - - }]; + [self.cuttlefishXPCWrapper fetchEgoEpochWithContainer:self.containerName + context:self.contextID + reply:^(uint64_t epoch, NSError* _Nullable error) { + STRONGIFY(self); + if(error) { + secerror("octagon: Error getting epoch: %@", error); + self.error = error; + } else { + self.epoch = epoch; + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:finishOp]; + }]; } @end diff --git a/keychain/ot/OTEscrowKeys.h b/keychain/ot/OTEscrowKeys.h deleted file mode 100644 index bf6b8802..00000000 --- a/keychain/ot/OTEscrowKeys.h +++ /dev/null @@ -1,74 +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@ - */ - -#ifndef OTEscrow_h -#define OTEscrow_h -#if OCTAGON - -#import -#import -NS_ASSUME_NONNULL_BEGIN - -typedef enum { - kOTEscrowKeySigning = 1, - kOTEscrowKeyEncryption = 2, - kOTEscrowKeySymmetric = 3, -} escrowKeyType; - -@interface OTEscrowKeys : NSObject - -@property (nonatomic, readonly) SFECKeyPair* encryptionKey; -@property (nonatomic, readonly) SFECKeyPair* signingKey; -@property (nonatomic, readonly) SFAESKey* symmetricKey; - -@property (nonatomic, readonly) NSData* secret; -@property (nonatomic, readonly) NSString* dsid; - --(instancetype) init NS_UNAVAILABLE; - -- (nullable instancetype) initWithSecret:(NSData*)secret - dsid:(NSString*)dsid - error:(NSError* __autoreleasing *)error; - -- (nullable instancetype) initWithSigningKey:(SFECKeyPair*)signingKey - encryptionKey:(SFECKeyPair*)encryptionKey - symmetricKey:(SFAESKey*)symmetricKey; - -+ (SecKeyRef) createSecKey:(NSData*)keyData; -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error; -+ (BOOL)findEscrowKeysForLabel:(NSString*)label - foundSigningKey:(SFECKeyPair*_Nonnull*_Nullable)signingKey - foundEncryptionKey:(SFECKeyPair*_Nonnull*_Nullable)encryptionKey - foundSymmetricKey:(SFAESKey*_Nonnull*_Nullable)symmetricKey - error:(NSError**)error; -+ (NSString*) hashEscrowedSigningPublicKey:(NSData*)keyData; - -+ (NSData* _Nullable) generateEscrowKey:(escrowKeyType)keyType - masterSecret:(NSData*)masterSecret - dsid:(NSString *)dsid - error:(NSError**)error; - -@end -NS_ASSUME_NONNULL_END -#endif -#endif /* OTEscrow_h */ diff --git a/keychain/ot/OTEscrowKeys.m b/keychain/ot/OTEscrowKeys.m deleted file mode 100644 index 75e2ebf3..00000000 --- a/keychain/ot/OTEscrowKeys.m +++ /dev/null @@ -1,417 +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 OCTAGON - -#import "OTEscrowKeys.h" - -#import -#include -#include -#import -#import -#import - -#import -#import -#import -#import -#import - -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTConstants.h" -#import -#import -#import - -#import -#import -#import - -static uint8_t escrowedSigningPrivKey[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'i', 'g', 'n', 'i', 'n', 'g', ' ', 'P', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y'}; -static uint8_t escrowedEncryptionPrivKey[] = { 'E', 's', 'c', 'r', 'o', 'w', ' ','E', 'n', 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', ' ', 'P', 'r', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y' }; -static uint8_t escrowedSymmetric[] = {'E', 's', 'c', 'r', 'o', 'w', ' ', 'S', 'y', 'm', 'm', 'e', 't', 'r', 'i','c',' ', 'K', 'e', 'y' }; - -#define OT_ESCROW_SIGNING_HKDF_SIZE 56 -#define OT_ESCROW_ENCRYPTION_HKDF_SIZE 56 -#define OT_ESCROW_SYMMETRIC_HKDF_SIZE 32 - -@interface OTEscrowKeys () -@property (nonatomic, strong) SFECKeyPair* encryptionKey; -@property (nonatomic, strong) SFECKeyPair* signingKey; -@property (nonatomic, strong) SFAESKey* symmetricKey; -@property (nonatomic, strong) NSData* secret; -@property (nonatomic, strong) NSString* dsid; -@end - -@implementation OTEscrowKeys - -- (nullable instancetype) initWithSecret:(NSData*)secret - dsid:(NSString*)dsid - error:(NSError* __autoreleasing *)error -{ - self = [super init]; - if (self) { - NSError* localError = nil; - - if([secret length] == 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptySecret userInfo:@{NSLocalizedDescriptionKey: @"entropy/secret is nil"}]; - } - return nil; - } - _secret = [secret copy]; - - if([dsid length] == 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyDSID userInfo:@{NSLocalizedDescriptionKey: @"dsid is nil"}]; - } - return nil; - } - _dsid = [dsid copy]; - - NSData *data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _signingKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]]; - if(!_signingKey){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC signing key"}]; - } - return nil; - } - data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _encryptionKey = [[SFECKeyPair alloc] initWithSecKey:[OTEscrowKeys createSecKey:data]]; - if(!_encryptionKey){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:@{NSLocalizedDescriptionKey: @"failed to create EC encryption key"}]; - } - return nil; - } - data = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:secret dsid:self.dsid error:&localError]; - if (!data) { - if(error){ - *error = localError; - } - return nil; - } - _symmetricKey = [[SFAESKey alloc] initWithData:data specifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:&localError]; - if (!_symmetricKey) { - if(error){ - *error = localError; - } - return nil; - } - NSString* escrowSigningPubKeyHash = [OTEscrowKeys hashEscrowedSigningPublicKey:[[_signingKey publicKey] encodeSubjectPublicKeyInfo]]; - BOOL result = [OTEscrowKeys storeEscrowedSigningKeyPair:[_signingKey keyData] label:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - result = [OTEscrowKeys storeEscrowedEncryptionKeyPair:[_encryptionKey keyData] label:escrowSigningPubKeyHash error:error]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - result = [OTEscrowKeys storeEscrowedSymmetricKey:[_symmetricKey keyData] label:escrowSigningPubKeyHash error:error]; - if(!result || localError){ - secerror("octagon: could not store escrowed signing SPKI in keychain: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - } - return self; -} - -- (nullable instancetype) initWithSigningKey:(SFECKeyPair*)signingKey - encryptionKey:(SFECKeyPair*)encryptionKey - symmetricKey:(SFAESKey*)symmetricKey -{ - self = [super init]; - if(self){ - _signingKey = signingKey; - _encryptionKey = encryptionKey; - _symmetricKey = symmetricKey; - } - return self; -} - -+ (NSData* _Nullable) generateEscrowKey:(escrowKeyType)keyType - masterSecret:(NSData*)masterSecret - dsid:(NSString *)dsid - error:(NSError**)error -{ - NSUInteger keyLength = 0; - const void *info = nil; - size_t infoLength = 0; - NSMutableData* derivedKey = NULL; - - switch(keyType) - { - case kOTEscrowKeySymmetric: - keyLength = OT_ESCROW_SYMMETRIC_HKDF_SIZE; - info = escrowedSymmetric; - infoLength = sizeof(escrowedSymmetric); - break; - case kOTEscrowKeyEncryption: - keyLength = OT_ESCROW_ENCRYPTION_HKDF_SIZE; - info = escrowedEncryptionPrivKey; - infoLength = sizeof(escrowedEncryptionPrivKey); - break; - case kOTEscrowKeySigning: - keyLength = OT_ESCROW_SIGNING_HKDF_SIZE; - info = escrowedSigningPrivKey; - infoLength = sizeof(escrowedSigningPrivKey); - break; - default: - break; - } - - ccec_const_cp_t cp = ccec_cp_384(); - int status = 0; - - ccec_full_ctx_decl_cp(cp, fullKey); - - derivedKey = [NSMutableData dataWithLength:keyLength]; - status = cchkdf(ccsha384_di(), - [masterSecret length], [masterSecret bytes], - strlen([dsid UTF8String]),[dsid UTF8String], - infoLength, info, - keyLength, [derivedKey mutableBytes]); - - - if (status != 0) { - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:nil]; - } - secerror("octagon: could not generate seed for signing keys"); - return nil; - } - if(keyType == kOTEscrowKeySymmetric){ - return derivedKey; - } - else if(keyType == kOTEscrowKeyEncryption || keyType == kOTEscrowKeySigning){ - - status = ccec_generate_key_deterministic(cp, - [derivedKey length], [derivedKey mutableBytes], - ccDRBGGetRngState(), - CCEC_GENKEY_DETERMINISTIC_FIPS, - fullKey); - if(status != 0){ - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorKeyGeneration userInfo:nil]; - } - secerror("octagon: could not generate signing keys"); - return nil; - } - - size_t space = ccec_x963_export_size(true, ccec_ctx_pub(fullKey)); - NSMutableData* key = [[NSMutableData alloc]initWithLength:space]; - ccec_x963_export(true, [key mutableBytes], fullKey); - derivedKey = key; - } - return derivedKey; -} - -+ (SecKeyRef) createSecKey:(NSData*)keyData -{ - NSDictionary *keyAttributes = @{ - (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate, - (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC, - }; - - SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)keyData, (__bridge CFDictionaryRef)keyAttributes, NULL); - return key; -} - -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error -{ - BOOL result = NO; - - CFTypeRef results = NULL; - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results); - - NSError* localerror = nil; - - if(status == errSecDuplicateItem || status == errSecSuccess) { - result = YES; - } else { - localerror = [NSError errorWithDomain:@"securityd" - code:status - userInfo:nil]; - } - if(status != errSecSuccess) { - CFReleaseNull(results); - - if(error) { - *error = localerror; - } - } - - return result; -} - -+(NSString*) hashEscrowedSigningPublicKey:(NSData*)keyData -{ - const struct ccdigest_info *di = ccsha384_di(); - NSMutableData* result = [[NSMutableData alloc] initWithLength:ccsha384_di()->output_size]; - - ccdigest(di, [keyData length], [keyData bytes], [result mutableBytes]); - - NSString* hash = [result base64EncodedStringWithOptions:0]; - return hash; -} - -+ (BOOL)storeEscrowedEncryptionKeyPair:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrLabel : label, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Encryption Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (BOOL)storeEscrowedSigningKeyPair:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Signing Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecAttrLabel : label, - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (BOOL)storeEscrowedSymmetricKey:(NSData*)keyData label:(NSString*)label error:(NSError**)error -{ - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecAttrApplicationLabel : [[NSString stringWithFormat:@"Escrowed Symmetric Key-%@", [NSUUID UUID].UUIDString] dataUsingEncoding:NSUTF8StringEncoding], - (id)kSecAttrLabel : label, - (id)kSecValueData : keyData, - }; - return [OTEscrowKeys setKeyMaterialInKeychain:query error:error]; -} - -+ (NSArray*)retrieveEscrowKeysFromKeychain:(NSString* _Nonnull)label error:(NSError**)error -{ - NSError* localError = nil; - NSArray* keySet = nil; - - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecAttrLabel: label, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnData : @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - }; - - CFTypeRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - - if(status != errSecSuccess || result == nil) { - secnotice("octagon", "no set of escrow keys for escrowed signing public key hash: %@", label); - localError = [NSError errorWithDomain:@"securityd" code:status userInfo:@{NSLocalizedDescriptionKey: @"no escrow key set for label"}]; - if(error){ - *error = localError; - } - } - - if(result && isArray(result)){ - secnotice("octagon", "found set of escrow keys for escrowed signing public key hash: %@", label); - keySet = (__bridge_transfer NSArray*)result; - } - - return keySet; -} - -+ (BOOL)findEscrowKeysForLabel:(NSString*)label foundSigningKey:(SFECKeyPair**)signingKey foundEncryptionKey:(SFECKeyPair**)encryptionKey foundSymmetricKey:(SFAESKey**)symmetricKey error:(NSError**)error -{ - BOOL result = NO; - NSError* localError = nil; - - NSArray* keySet = [OTEscrowKeys retrieveEscrowKeysFromKeychain:label error:&localError]; - - for(NSDictionary* item in keySet){ - - NSString* keyType = [[NSString alloc] initWithData:item[(id)kSecAttrApplicationLabel] encoding:NSUTF8StringEncoding]; - - if([keyType containsString:@"Symmetric"]){ - *symmetricKey = [[SFAESKey alloc] initWithData:item[(id)kSecValueData] specifier:[[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256] error:&localError]; - }else if([keyType containsString:@"Encryption"]){ - SecKeyRef encryptionSecKey = [OTEscrowKeys createSecKey:item[(id)kSecValueData]]; - *encryptionKey = [[SFECKeyPair alloc] initWithSecKey:encryptionSecKey]; - CFReleaseNull(encryptionSecKey); - }else if([keyType containsString:@"Signing"]){ - SecKeyRef signingSecKey = [OTEscrowKeys createSecKey:item[(id)kSecValueData]]; - *signingKey = [[SFECKeyPair alloc] initWithSecKey:signingSecKey]; - CFReleaseNull(signingSecKey); - }else{ - secnotice("octagon", "unknown keychain item"); - } - } - if(*signingKey != nil && *encryptionKey != nil && *symmetricKey != nil){ - secnotice("octagon", "found escrow keys"); - result = YES; - }else{ - secerror("octagon: no matching escrow keys"); - } - - return result; -} - -@end -#endif diff --git a/keychain/ot/OTEstablishOperation.m b/keychain/ot/OTEstablishOperation.m index e9719e3d..cfb4a621 100644 --- a/keychain/ot/OTEstablishOperation.m +++ b/keychain/ot/OTEstablishOperation.m @@ -117,58 +117,51 @@ } secnotice("octagon-ckks", "Beginning establish with keys: %@", viewKeySets); - [[self.operationDependencies.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventEstablishIdentity withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] establishWithContainer:self.operationDependencies.containerName - context:self.operationDependencies.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:publicSigningSPKIs - reply:^(NSString * _Nullable peerID, NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventEstablishIdentity hardFailure:true result:error]; - if(error) { - secerror("octagon: Error calling establish: %@", error); + [self.operationDependencies.cuttlefishXPCWrapper establishWithContainer:self.operationDependencies.containerName + context:self.operationDependencies.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:publicSigningSPKIs + reply:^(NSString * _Nullable peerID, NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + + [[CKKSAnalytics logger] logResultForEvent:OctagonEventEstablishIdentity hardFailure:true result:error]; + if(error) { + secerror("octagon: Error calling establish: %@", error); + + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else { + self.error = error; + } + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); - self.nextState = self.ckksConflictState; + self.peerID = peerID; + + NSError* localError = nil; + BOOL persisted = [self.operationDependencies.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist results: %@", localError); + self.error = localError; } else { - self.error = error; + self.nextState = self.intendedState; } - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - self.peerID = peerID; - - NSError* localError = nil; - BOOL persisted = [self.operationDependencies.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist results: %@", localError); - self.error = localError; - } else { - self.nextState = self.intendedState; - } - - // Tell CKKS about our shiny new records! - for (id key in self.operationDependencies.viewManager.views) { - CKKSKeychainView* view = self.operationDependencies.viewManager.views[key]; - secnotice("octagon-ckks", "Providing records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + // Tell CKKS about our shiny new records! + for (id key in self.operationDependencies.viewManager.views) { + CKKSKeychainView* view = self.operationDependencies.viewManager.views[key]; + secnotice("octagon-ckks", "Providing records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTFetchViewsOperation.m b/keychain/ot/OTFetchViewsOperation.m index f041885c..cbe4e56a 100644 --- a/keychain/ot/OTFetchViewsOperation.m +++ b/keychain/ot/OTFetchViewsOperation.m @@ -59,47 +59,37 @@ if ([self.ckm useCKKSViewsFromPolicy]) { WEAKIFY(self); - NSXPCConnection* proxy = [self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [self.deps.cuttlefishXPCWrapper fetchPolicyWithContainer:self.deps.containerName context:self.deps.contextID reply:^(TPPolicy* _Nullable policy, NSError* _Nullable error) { STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventFetchViews withAttributes:nil]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - }]; - if (proxy) { - [proxy fetchPolicyWithContainer:self.deps.containerName context:self.deps.contextID reply:^(TPPolicy* _Nullable policy, NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon: failed to retrieve policy: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - if (policy == nil) { - secerror("octagon: no policy returned"); - } - self.policy = policy; - WEAKIFY(self); - NSArray* sosViews = [sosViewList allObjects]; - [proxy getViewsWithContainer:self.deps.containerName context:self.deps.contextID inViews:sosViews reply:^(NSArray* _Nullable outViews, NSError* _Nullable error) { - STRONGIFY(self); - if (error) { - secerror("octagon: failed to retrieve list of views: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + if (error) { + secerror("octagon: failed to retrieve policy: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + if (policy == nil) { + secerror("octagon: no policy returned"); + } + self.policy = policy; + NSArray* sosViews = [sosViewList allObjects]; + [self.deps.cuttlefishXPCWrapper getViewsWithContainer:self.deps.containerName context:self.deps.contextID inViews:sosViews reply:^(NSArray* _Nullable outViews, NSError* _Nullable error) { + STRONGIFY(self); + if (error) { + secerror("octagon: failed to retrieve list of views: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error]; + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + if (outViews == nil) { + secerror("octagon: bad results from getviews"); } else { - if (outViews == nil) { - secerror("octagon: bad results from getviews"); - } else { - self.viewList = [NSSet setWithArray:outViews]; - } - [self complete]; + self.viewList = [NSSet setWithArray:outViews]; } - }]; - } - }]; - } + [self complete]; + } + }]; + } + }]; } else { [self complete]; } diff --git a/keychain/ot/OTFollowup.h b/keychain/ot/OTFollowup.h index f7aea060..e6f738ca 100644 --- a/keychain/ot/OTFollowup.h +++ b/keychain/ot/OTFollowup.h @@ -38,13 +38,7 @@ typedef NS_ENUM(uint8_t, OTFollowupContextType) { OTFollowupContextTypeStateRepair, OTFollowupContextTypeOfflinePasscodeChange, }; - -typedef NS_ENUM(uint8_t, OTFollowupStatus) { - OTFollowupStatusIdle = 0, - OTFollowupStatusSuccess = 1, - OTFollowupStatusFailed = 2, - OTFollowupStatusPending = 3, -}; +NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType); @protocol OctagonFollowUpControllerProtocol - (BOOL)postFollowUpWithContext:(CDPFollowUpContext *)context error:(NSError **)error; @@ -54,7 +48,6 @@ typedef NS_ENUM(uint8_t, OTFollowupStatus) { @end @interface OTFollowup : NSObject -@property (readonly) OTFollowupStatus followupStatus; - (id)initWithFollowupController:(id)cdpFollowupController; - (BOOL)postFollowUp:(OTFollowupContextType)contextType diff --git a/keychain/ot/OTFollowup.m b/keychain/ot/OTFollowup.m index ad73b695..419f399c 100644 --- a/keychain/ot/OTFollowup.m +++ b/keychain/ot/OTFollowup.m @@ -30,8 +30,6 @@ #define HAVE_COREFOLLOW_UP 1 #endif -#undef HAVE_COREFOLLOW_UP // XXX - #import #import @@ -39,6 +37,20 @@ static NSString * const kOTFollowupEventCompleteKey = @"OTFollowupContextType"; +NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType) +{ + switch(contextType) { + case OTFollowupContextTypeNone: + return @"none"; + case OTFollowupContextTypeRecoveryKeyRepair: + return @"recovery key"; + case OTFollowupContextTypeStateRepair: + return @"repair"; + case OTFollowupContextTypeOfflinePasscodeChange: + return @"offline passcode change"; + } +} + @interface OTFollowup() @property id cdpd; @property NSTimeInterval previousFollowupEnd; diff --git a/keychain/ot/OTIdentity.h b/keychain/ot/OTIdentity.h deleted file mode 100644 index 487cf7c2..00000000 --- a/keychain/ot/OTIdentity.h +++ /dev/null @@ -1,58 +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 OCTAGON - -#include -NS_ASSUME_NONNULL_BEGIN - -@interface OTIdentity : NSObject - -@property (nonatomic, readonly) NSString* peerID; -@property (nonatomic, readonly) NSString* spID; -@property (nonatomic, readonly) SFECKeyPair* peerSigningKey; -@property (nonatomic, readonly) SFECKeyPair* peerEncryptionKey; - - -- (instancetype) initWithPeerID:(nullable NSString*)peerID - spID:(nullable NSString*)spID - peerSigningKey:(SFECKeyPair*)peerSigningKey - peerEncryptionkey:(SFECKeyPair*)peerEncryptionKey - error:(NSError**)error; - -+ (nullable instancetype) currentIdentityFromSOS:(NSError**)error; - --(BOOL)isEqual:(OTIdentity* _Nullable)identity; - - -+(BOOL) storeOctagonIdentityIntoKeychain:(_SFECKeyPair *)restoredSigningKey - restoredEncryptionKey:(_SFECKeyPair *)restoredEncryptionKey - escrowSigningPubKeyHash:(NSString *)escrowSigningPubKeyHash - restoredPeerID:(NSString *)peerID - error:(NSError**)error; - -@end - -NS_ASSUME_NONNULL_END -#endif - diff --git a/keychain/ot/OTIdentity.m b/keychain/ot/OTIdentity.m deleted file mode 100644 index 616a2576..00000000 --- a/keychain/ot/OTIdentity.m +++ /dev/null @@ -1,214 +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 OCTAGON - -#import "OTIdentity.h" - -#import -#import -#import "keychain/ot/OTDefines.h" - -#import "keychain/SecureObjectSync/SOSAccountTransaction.h" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" -#import "keychain/SecureObjectSync/SOSAccount.h" -#pragma clang diagnostic pop - -@interface OTIdentity () - -@property (nonatomic, strong) NSString* peerID; -@property (nonatomic, strong) NSString* spID; -@property (nonatomic, strong) SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) SFECKeyPair* peerEncryptionKey; - -@end - -@implementation OTIdentity - -- (instancetype) initWithPeerID:(nullable NSString*)peerID - spID:(nullable NSString*)spID - peerSigningKey:(SFECKeyPair*)peerSigningKey - peerEncryptionkey:(SFECKeyPair*)peerEncryptionKey - error:(NSError**)error -{ - self = [super init]; - if (self) { - _peerID = peerID; - _spID = spID; - _peerSigningKey = peerSigningKey; - _peerEncryptionKey = peerEncryptionKey; - } - return self; -} - -+ (nullable instancetype) currentIdentityFromSOS:(NSError**)error -{ - CFErrorRef circleCheckError = NULL; - SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(&circleCheckError); - if(circleStatus != kSOSCCInCircle){ - if(circleCheckError){ - secerror("octagon: cannot retrieve octagon keys from SOS, not in circle, error: %@", circleCheckError); - if(error){ - *error = (__bridge NSError*)circleCheckError; - } - } - secerror("octagon: current circle status: %d",circleStatus); - return nil; - } - __block NSString* sosPeerID = nil; - __block NSError* sosPeerIDError = nil; - - SOSCCPerformWithPeerID(^(CFStringRef peerID, CFErrorRef error) { - sosPeerID = (__bridge NSString *)(peerID); - if(error){ - secerror("octagon: retrieving sos peer id error: %@", error); - sosPeerIDError = CFBridgingRelease(error); - } - }); - - if(sosPeerID == nil || sosPeerIDError != nil){ - secerror("octagon: cannot retrieve peer id from SOS, error: %@", sosPeerIDError); - if(error){ - *error = sosPeerIDError; - } - return nil; - } - - __block SFECKeyPair *peerEncryptionKey; - __block SFECKeyPair *peerSigningKey; - __block NSError* localError = nil; - - SOSCCPerformWithAllOctagonKeys(^(SecKeyRef octagonEncryptionKey, SecKeyRef octagonSigningKey, CFErrorRef cferror) { - if(cferror) { - localError = (__bridge NSError*)cferror; - return; - } - if (!cferror && octagonEncryptionKey && octagonSigningKey) { - peerSigningKey = [[SFECKeyPair alloc] initWithSecKey:octagonSigningKey]; - peerEncryptionKey = [[SFECKeyPair alloc] initWithSecKey:octagonEncryptionKey]; - - } - }); - - if(!peerEncryptionKey || !peerSigningKey || localError != nil){ - secerror("octagon: failed to retrieve octagon keys from sos: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - return [[OTIdentity alloc] initWithPeerID:nil - spID:sosPeerID - peerSigningKey:peerSigningKey - peerEncryptionkey:peerEncryptionKey - error:error]; -} - --(BOOL)isEqual:(OTIdentity*)identity -{ - return [self.peerID isEqualToString:identity.peerID] && - [self.spID isEqualToString:identity.spID] && - [self.peerSigningKey isEqual:identity.peerSigningKey] && - [self.peerEncryptionKey isEqual:identity.peerEncryptionKey]; -} - -+ (BOOL) setKeyMaterialInKeychain:(NSDictionary*)query error:(NSError* __autoreleasing *)error -{ - BOOL result = NO; - - CFTypeRef results = NULL; - OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &results); - - NSError* localerror = nil; - - if(status == errSecDuplicateItem || status == errSecSuccess) { - result = YES; - } else { - localerror = [NSError errorWithDomain:@"securityd" - code:status - userInfo:nil]; - } - if(status != errSecSuccess) { - CFReleaseNull(results); - - if(error) { - *error = localerror; - } - } - - return result; -} - -+ (BOOL)storeOtagonKey:(NSData*)keyData - octagonKeyType:(OctagonKeyType)octagonKeyType - restoredPeerID:(NSString*)restoredPeerID - escrowSigningPubKeyHash:(NSString*)escrowSigningPubKeyHash - error:(NSError**)error -{ - NSNumber *keyType = [[NSNumber alloc]initWithInt:octagonKeyType]; - - NSDictionary* query = @{ - (id)kSecClass : (id)kSecClassInternetPassword, - (id)kSecAttrAccessible: (id)kSecAttrAccessibleWhenUnlocked, - (id)kSecUseDataProtectionKeychain : @YES, - (id)kSecAttrLabel : escrowSigningPubKeyHash, - (id)kSecAttrAccount : restoredPeerID, - (id)kSecAttrType : keyType, - (id)kSecAttrServer : (octagonKeyType == 1) ? @"Octagon Signing Key" : @"Octagon Encryption Key", - (id)kSecAttrAccessGroup: @"com.apple.security.ckks", - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecValueData : keyData, - }; - return [OTIdentity setKeyMaterialInKeychain:query error:error]; - -} - -+(BOOL) storeOctagonIdentityIntoKeychain:(_SFECKeyPair *)restoredSigningKey - restoredEncryptionKey:(_SFECKeyPair *)restoredEncryptionKey - escrowSigningPubKeyHash:(NSString *)escrowSigningPubKeyHash - restoredPeerID:(NSString *)peerID - error:(NSError**)error -{ - NSError* localError = nil; - - BOOL result = [OTIdentity storeOtagonKey:[restoredSigningKey keyData] octagonKeyType:OctagonSigningKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store octagon signing key in keychain:%@", localError); - if(error){ - *error = localError; - } - return NO; - } - result = [OTIdentity storeOtagonKey:[restoredEncryptionKey keyData] octagonKeyType:OctagonEncryptionKey restoredPeerID:peerID escrowSigningPubKeyHash:escrowSigningPubKeyHash error:&localError]; - if(!result || localError){ - secerror("octagon: could not store octagon encryption key in keychain:%@", localError); - if(error){ - *error = localError; - } - return NO; - } - return result; -} - -@end -#endif diff --git a/keychain/ot/OTJoinWithVoucherOperation.m b/keychain/ot/OTJoinWithVoucherOperation.m index b8fba538..f68765d5 100644 --- a/keychain/ot/OTJoinWithVoucherOperation.m +++ b/keychain/ot/OTJoinWithVoucherOperation.m @@ -43,10 +43,6 @@ @property OctagonState* ckksConflictState; @property NSOperation* finishedOp; -@property int retries; -@property int maxRetries; -@property int delay; -@property CKKSNearFutureScheduler* retrySched; @end @implementation OTJoinWithVoucherOperation @@ -64,10 +60,6 @@ if((self = [super init])) { _deps = dependencies; - _retries = 0; - _maxRetries = 5; - _delay = 1; - _intendedState = intendedState; _nextState = errorState; _ckksConflictState = ckksConflictState; @@ -102,107 +94,62 @@ [self runBeforeGroupFinished:proceedWithKeys]; } -- (BOOL)isRetryable:(NSError* _Nonnull)error { - return [error isCuttlefishError:CuttlefishErrorTransactionalFailure]; -} - -- (int)retryDelay:(NSError* _Nonnull)error { - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - int ret = self->_delay; - if (underlyingError) { - id tmp = underlyingError.userInfo[@"retryafter"]; - if ([tmp isKindOfClass:[NSNumber class]]) { - ret = [(NSNumber*)tmp intValue]; - } - } - ret = MAX(MIN(ret, 32), self->_delay); - self->_delay *= 2; - return ret; -} - - (void)proceedWithKeys:(NSArray*)viewKeySets pendingTLKShares:(NSArray*)pendingTLKShares { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] joinWithContainer:self.deps.containerName - context:self.deps.contextID - voucherData:self.voucherData - voucherSig:self.voucherSig - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:self.preapprovedKeys - reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { - if(error){ - secerror("octagon: Error joining with voucher: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; - - if (self.retries < self.maxRetries && [self isRetryable:error]) { - ++self.retries; - if (!self.retrySched) { - self.retrySched = [[CKKSNearFutureScheduler alloc] initWithName:@"cuttlefish-join-retry" - delay:1*NSEC_PER_SEC - keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"vouch-with-keys" - withBlock:^{ - STRONGIFY(self); - secnotice("octagon", "retrying (%d/%d) join", self.retries, self->_maxRetries); - [self proceedWithKeys:viewKeySets - pendingTLKShares:pendingTLKShares]; - }]; - STRONGIFY(self); - [self runBeforeGroupFinished:proceedWithKeys]; - }]; + [self.deps.cuttlefishXPCWrapper joinWithContainer:self.deps.containerName + context:self.deps.contextID + voucherData:self.voucherData + voucherSig:self.voucherSig + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:self.preapprovedKeys + reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + if(error){ + secerror("octagon: Error joining with voucher: %@", error); + [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventJoinWithVoucher withAttributes:NULL]; + + // IF this is a CKKS conflict error, don't retry + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; going to state '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else if ([error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { + secnotice("octagon", "requesting cuttlefish health check"); + self.nextState = OctagonStateCuttlefishTrustCheck; + self.error = error; + } else { + self.error = error; } - int delay_s = [self retryDelay:error]; - [self.retrySched waitUntil:delay_s*NSEC_PER_SEC]; - [self.retrySched trigger]; - return; - } - - // IF this is a CKKS conflict error, don't retry - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; going to state '%@'", self.ckksConflictState); - self.nextState = self.ckksConflictState; - } else { - self.error = error; - } - } else { - self.peerID = peerID; - - [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventJoinWithVoucher]; - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist results: %@", localError); - self.error = localError; } else { - secerror("octagon: join successful"); - self.nextState = self.intendedState; - } + self.peerID = peerID; + + [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventJoinWithVoucher]; + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist results: %@", localError); + self.error = localError; + } else { + secerror("octagon: join successful"); + self.nextState = self.intendedState; + } - // Tell CKKS about our shiny new records! - for (id key in self.deps.viewManager.views) { - CKKSKeychainView* view = self.deps.viewManager.views[key]; - secnotice("octagon-ckks", "Providing join() records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; + // Tell CKKS about our shiny new records! + for (id key in self.deps.viewManager.views) { + CKKSKeychainView* view = self.deps.viewManager.views[key]; + secnotice("octagon-ckks", "Providing join() records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } } - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLeaveCliqueOperation.m b/keychain/ot/OTLeaveCliqueOperation.m index e61e9b2f..af8ad2eb 100644 --- a/keychain/ot/OTLeaveCliqueOperation.m +++ b/keychain/ot/OTLeaveCliqueOperation.m @@ -58,34 +58,28 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper departByDistrustingSelfWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to depart for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); + self.error = error; + } else { + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistNewTrustState:OTAccountMetadataClassC_TrustState_UNTRUSTED + error:&localError]; + if(!persisted || localError) { + secerror("octagon: unable to persist clique departure: %@", localError); + self.error = localError; + } else { + secnotice("octagon", "Successfully departed clique"); + self.nextState = self.intendedState; + } + } - }] departByDistrustingSelfWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to depart for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); - self.error = error; - } else { - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistNewTrustState:OTAccountMetadataClassC_TrustState_UNTRUSTED - error:&localError]; - if(!persisted || localError) { - secerror("octagon: unable to persist clique departure: %@", localError); - self.error = localError; - } else { - secnotice("octagon", "Successfully departed clique"); - self.nextState = self.intendedState; - } - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLocalCuttlefishReset.h b/keychain/ot/OTLocalCuttlefishReset.h index 9e1b59bf..90011df7 100644 --- a/keychain/ot/OTLocalCuttlefishReset.h +++ b/keychain/ot/OTLocalCuttlefishReset.h @@ -27,6 +27,7 @@ #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" NS_ASSUME_NONNULL_BEGIN @@ -36,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN contextID:(NSString*)contextID intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC; +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTLocalCuttlefishReset.m b/keychain/ot/OTLocalCuttlefishReset.m index 91a49b21..30cd3608 100644 --- a/keychain/ot/OTLocalCuttlefishReset.m +++ b/keychain/ot/OTLocalCuttlefishReset.m @@ -32,8 +32,7 @@ @interface OTLocalResetOperation () @property NSString* containerName; @property NSString* contextID; -@property id cuttlefishXPC; - +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property NSOperation* finishedOp; @end @@ -45,7 +44,7 @@ contextID:(NSString*)contextID intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; @@ -53,7 +52,7 @@ _containerName = containerName; _contextID = contextID; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; } return self; } @@ -66,26 +65,20 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] localResetWithContainer:self.containerName - context:self.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.containerName, self.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully reset local cuttlefish"); - self.nextState = self.intendedState; - } + [self.cuttlefishXPCWrapper localResetWithContainer:self.containerName + context:self.contextID + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.containerName, self.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully reset local cuttlefish"); + self.nextState = self.intendedState; + } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTLocalStore.h b/keychain/ot/OTLocalStore.h deleted file mode 100644 index 74c4fa09..00000000 --- a/keychain/ot/OTLocalStore.h +++ /dev/null @@ -1,77 +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@ - */ - -#ifndef OTLocalStore_h -#define OTLocalStore_h -#if OCTAGON - -#import -#import -#import -#import "keychain/ot/OTBottledPeerRecord.h" -#import "keychain/ot/OTContextRecord.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface OTLocalStore : NSObject - -@property (nonatomic, readonly) NSString* dbPath; -@property (nonatomic, readonly) PQLConnection* pDB; -@property (nonatomic, readonly) dispatch_queue_t serialQ; -@property (nonatomic, readonly) NSString* contextID; -@property (nonatomic, readonly) NSString* dsid; -@property (nonatomic, readonly) sqlite3* _db; - --(instancetype) initWithContextID:(NSString*)contextID dsid:(NSString*)dsid path:(nullable NSString*)path error:(NSError**)error; - --(BOOL)isProposedColumnNameInTable:(NSString*)proposedColumnName tableName:(NSString*)tableName; - -// OT Context Record routines --(BOOL)initializeContextTable:(NSString*)contextID dsid:(NSString*)dsid error:(NSError**)error; --(OTContextRecord* _Nullable)readLocalContextRecordForContextIDAndDSID:(NSString*)contextAndDSID error:(NSError**)error; --(BOOL)insertLocalContextRecord:(NSDictionary*)attributes error:(NSError**)error; --(BOOL)updateLocalContextRecordRowWithContextID:(NSString*)contextIDAndDSID columnName:(NSString*)columnName newValue:(void*)newValue error:(NSError**)error; --(BOOL)deleteLocalContext:(NSString*)contextIDAndDSID error:(NSError**)error; --(BOOL) deleteAllContexts:(NSError**)error; - -//OT Bottled Peer routines -- (nullable OTBottledPeerRecord *)readLocalBottledPeerRecordWithRecordID:(NSString *)recordID - error:(NSError**)error; -- (nullable NSArray*) readAllLocalBottledPeerRecords:(NSError**)error; --(BOOL)deleteBottledPeer:(NSString*) recordID error:(NSError**)error; --(BOOL) deleteBottledPeersForContextAndDSID:(NSString*)contextIDAndDSID - error:(NSError**)error; --(BOOL)removeAllBottledPeerRecords:(NSError**)error; --(BOOL)insertBottledPeerRecord:(OTBottledPeerRecord *)bp - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error; -- (nullable NSArray*) readLocalBottledPeerRecordsWithMatchingPeerID:(NSString*)peerID error:(NSError**)error; - -// generic DB routines --(BOOL)openDBWithError:(NSError**)error; --(BOOL)closeDBWithError:(NSError**)error;; --(BOOL)createDirectoryAtPath:(NSString*)path error:(NSError **)error; -@end -NS_ASSUME_NONNULL_END -#endif -#endif /* OTLocalStore_h */ diff --git a/keychain/ot/OTLocalStore.m b/keychain/ot/OTLocalStore.m deleted file mode 100644 index e859c337..00000000 --- a/keychain/ot/OTLocalStore.m +++ /dev/null @@ -1,684 +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 OCTAGON - -#import -#import -#import -#import -#include -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTConstants.h" -#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR -#include -#else -#include -#endif - -#import "OTLocalStore.h" -#import "OTBottledPeerSigned.h" - -static NSString* const contextSchema = @"create table if not exists context (contextIDAndDSID text primary key, contextID text, accountDSID text, contextName text, zoneCreated boolean, subscribedToChanges boolean, changeToken blob, egoPeerID text, egoPeerCreationDate date, recoverySigningSPKI text, recoveryEncryptionSPKI text);"; - -static NSString* const bottledPeerSchema = @"create table if not exists bp (bottledPeerRecordID text primary key, contextIDAndDSID text, escrowRecordID text, peerID text, spID text, bottle text, escrowSigningSPKI text, peerSigningSPKI text, signatureUsingEscrow text, signatureUsingPeerKey text, encodedRecord text, launched text);"; - -static const NSInteger user_version = 0; - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextAndDSID = @"contextIDAndDSID"; -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordBottle = @"bottle"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordEncodedRecord = @"encodedRecord"; -static NSString* OTCKRecordLaunched = @"launched"; - -/* Octagon Table Names */ -static NSString* const contextTable = @"context"; -static NSString* const peerTable = @"peer"; -static NSString* const bottledPeerTable = @"bp"; - -/* Octagon Trust Schemas */ -static NSString* const octagonZoctagonErrorDomainoneName = @"OctagonTrustZone"; - -/* Octagon Cloud Kit defines */ -static NSString* OTCKZoneName = @"OctagonTrust"; -static NSString* OTCKRecordName = @"bp-"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -static NSArray* _Nullable selectAll(PQLResultSet *rs, Class class) -{ - NSMutableArray *arr = [NSMutableArray array]; - for (id o in [rs enumerateObjectsOfClass:class]) { - [arr addObject:o]; - } - if (rs.error) { - return nil; - } - return arr; -} -#define selectArrays(db, sql, ...) \ -selectAll([db fetch:sql, ##__VA_ARGS__], [NSArray class]) - -#define selectDictionaries(db, sql, ...) \ -selectAll([db fetch:sql, ##__VA_ARGS__], [NSDictionary class]) - - -@interface NSDictionary (PQLResultSetInitializer) -@end -@implementation NSDictionary (PQLResultSetInitializer) -- (instancetype)initFromPQLResultSet:(PQLResultSet *)rs - error:(NSError **)error -{ - NSUInteger cols = rs.columns; - NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithCapacity:cols]; - - for (NSUInteger i = 0; i < cols; i++) { - id obj = rs[i]; - if (obj) { - dict[[rs columnNameAtIndex:(int)i]] = obj; - } - } - - return [self initWithDictionary:dict]; -} -@end - - -@implementation OTLocalStore - --(instancetype) initWithContextID:(NSString*)contextID dsid:(NSString*)dsid path:(nullable NSString*)path error:(NSError**)error -{ - self = [super init]; - if(self){ - if (!path) { - NSURL* urlPath = (__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"otdb.db"); - path = [urlPath path]; - } - _dbPath = [path copy]; - _pDB = [[PQLConnection alloc] init]; - _contextID = [contextID copy]; - _dsid = [dsid copy]; - _serialQ = dispatch_queue_create("com.apple.security.ot.db", DISPATCH_QUEUE_SERIAL); - - NSError* localError = nil; - if(![self openDBWithError:&localError]) - { - secerror("octagon: could not open db: %@", localError); - if(error){ - *error = localError; - } - return nil; - } - } - return self; -} - -- (BOOL) createDirectoryAtPath:(NSString*)path error:(NSError **)error -{ - BOOL success = YES; - NSError *localError; - NSFileManager *fileManager = [NSFileManager defaultManager]; - - if (![fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&localError]) { - if (![localError.domain isEqualToString:NSCocoaErrorDomain] || localError.code != NSFileWriteFileExistsError) { - success = NO; - if(error){ - *error = localError; - } - } - } - -#if TARGET_OS_IPHONE - if (success) { - NSDictionary *attributes = [fileManager attributesOfItemAtPath:path error:&localError]; - if (![attributes[NSFileProtectionKey] isEqualToString:NSFileProtectionCompleteUntilFirstUserAuthentication]) { - [fileManager setAttributes:@{ NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication } - ofItemAtPath:path error:&localError]; - } - } -#endif - if (!success) { - if (error) *error = localError; - } - return success; -} - --(BOOL)openDBWithError:(NSError**)error -{ - BOOL result = NO; - NSError *localError = nil; - - if(!(result = [_pDB openAtURL:[NSURL URLWithString:_dbPath] sharedCache:NO error:&localError])){ - secerror("octagon: could not open db: %@", localError); - if(error){ - *error = localError; - } - return NO; - } - if(![_pDB execute:bottledPeerSchema]){ - secerror("octagon: could not create bottled peer schema"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEntropyCreationFailure userInfo:@{NSLocalizedDescriptionKey: @"could not create bottled peer schema"}]; - } - result = NO; - } - if(![_pDB execute:contextSchema]){ - secerror("octagon: could not create contextschema"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not create context schema"}]; - } - result = NO; - } - if(![_pDB setupPragmas]){ - secerror("octagon: could not set up db pragmas"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not set up db pragmas"}]; - } - result = NO; - } - if(![_pDB setUserVersion:user_version]){ - secerror("octagon: could not set version"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"could not set version"}]; - } - result = NO; - } - return result; -} - --(BOOL)closeDBWithError:(NSError**)error -{ - BOOL result = NO; - NSError *localError = nil; - - if(!(result =[_pDB close:&localError])){ - secerror("octagon: could not close db: %@", localError); - if(error){ - *error = localError; - } - } - return result; -} - --(BOOL)isProposedColumnNameInTable:(NSString*)proposedColumnName tableName:(NSString*)tableName -{ - BOOL result = NO; - - if([tableName isEqualToString:contextTable]) - { - if([proposedColumnName isEqualToString:OTCKRecordContextAndDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordContextID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordContextName]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordZoneCreated]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSubscribedToChanges]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordChangeToken]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEgoPeerID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEgoPeerCreationDate]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecoverySigningSPKI]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecoveryEncryptionSPKI]){ - result = YES; - } - else{ - secerror("octagon: column name unknown: %@", proposedColumnName); - } - } - else if([tableName isEqualToString:peerTable]){ //not using yet! - result = NO; - secerror("octagon: not using this table yet!"); - } - else if([tableName isEqualToString:bottledPeerTable]) - { - if([proposedColumnName isEqualToString:OTCKRecordContextAndDSID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordRecordID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEscrowRecordID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSPID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordPeerID]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordBottle]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSignatureFromEscrow]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordSignatureFromPeerKey]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEncodedRecord]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordLaunched]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordPeerSigningSPKI]){ - result = YES; - } - else if([proposedColumnName isEqualToString:OTCKRecordEscrowSigningSPKI]){ - result = YES; - } - else{ - secerror("octagon: column name unknown: %@", proposedColumnName); - } - } - else{ - secerror("octagon: table name unknown: %@", tableName); - } - return result; -} - -///// -// Local Context Record -///// --(OTContextRecord* _Nullable)readLocalContextRecordForContextIDAndDSID:(NSString*)contextAndDSID error:(NSError**)error -{ - OTContextRecord* record = [[OTContextRecord alloc]init]; - NSDictionary* attributes = nil; - NSArray *selectArray = nil; - - selectArray = selectDictionaries(_pDB, @"SELECT * from context WHERE contextIDAndDSID == %@;", PQLName(contextAndDSID)); - if(selectArray && [selectArray count] > 0){ - attributes = [selectArray objectAtIndex:0]; - } - if(attributes && [attributes count] > 0){ - record.contextID = attributes[OTCKRecordContextID]; - record.dsid = attributes[OTCKRecordDSID]; - record.contextName = attributes[OTCKRecordContextName]; - record.zoneCreated = (BOOL)attributes[OTCKRecordZoneCreated]; - record.subscribedToChanges = (BOOL)attributes[OTCKRecordSubscribedToChanges]; - record.changeToken = attributes[OTCKRecordChangeToken]; - record.egoPeerID = attributes[OTCKRecordEgoPeerID]; - record.egoPeerCreationDate = attributes[OTCKRecordEgoPeerCreationDate]; - record.recoverySigningSPKI = dataFromBase64(attributes[OTCKRecordRecoverySigningSPKI]); - record.recoveryEncryptionSPKI = dataFromBase64(attributes[OTCKRecordRecoveryEncryptionSPKI]); - } - else{ - secerror("octagon: no context attributes found"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"no context attributes found"}]; - } - } - - return record; -} - --(BOOL)initializeContextTable:(NSString*)contextID dsid:(NSString*)dsid error:(NSError**)error -{ - BOOL result = NO; - NSError* localError = nil; - NSString* contextName = nil; -#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR - contextName = (__bridge_transfer NSString *)MGCopyAnswer(kMGQUserAssignedDeviceName, NULL); -#else - contextName = (__bridge_transfer NSString *)SCDynamicStoreCopyComputerName(NULL, NULL); -#endif - - NSDictionary *contextAttributes = @{ - OTCKRecordContextAndDSID : [NSString stringWithFormat:@"%@-%@", contextID, dsid], - OTCKRecordContextID : contextID, - OTCKRecordDSID : dsid, - OTCKRecordContextName : contextName, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"ego peer id", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [NSData data], - OTCKRecordRecoveryEncryptionSPKI : [NSData data]}; - - result = [self insertLocalContextRecord:contextAttributes error:&localError]; - if(!result || localError != nil){ - secerror("octagon: context table init failed: %@", localError); - if(error){ - *error = localError; - } - } - return result; -} - --(BOOL)insertLocalContextRecord:(NSDictionary*)attributes error:(NSError**)error -{ - BOOL result = NO; - - NSString* dsidAndContext = [NSString stringWithFormat:@"%@-%@", attributes[OTCKRecordContextID], attributes[OTCKRecordDSID]]; - result = [_pDB execute:@"insert into context (contextIDAndDSID, contextID, accountDSID, contextName, zoneCreated, subscribedToChanges, changeToken, egoPeerID, egoPeerCreationDate, recoverySigningSPKI, recoveryEncryptionSPKI) values (%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@)", - dsidAndContext, attributes[OTCKRecordContextID], attributes[OTCKRecordDSID], attributes[OTCKRecordContextName], attributes[OTCKRecordZoneCreated], - attributes[OTCKRecordSubscribedToChanges], attributes[OTCKRecordChangeToken], - attributes[OTCKRecordEgoPeerID], attributes[OTCKRecordEgoPeerCreationDate], - [attributes[OTCKRecordRecoverySigningSPKI] base64EncodedStringWithOptions:0], [attributes[OTCKRecordRecoveryEncryptionSPKI] base64EncodedStringWithOptions:0]]; - - - if(_pDB.lastError){ - secerror("octagon: failed to insert local context: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL)updateLocalContextRecordRowWithContextID:(NSString*)contextIDAndDSID columnName:(NSString*)columnName newValue:(void*)newValue error:(NSError**)error -{ - BOOL result = NO; - if([self isProposedColumnNameInTable:columnName tableName:contextTable]){ - result = [_pDB execute:@"update context set %@ = %@ where contextIDAndDSID == %@", - PQLName(columnName), newValue, PQLName(_contextID)]; - if(!result && error){ - secerror("octagon: error updating table: %@", _pDB.lastError); - *error = _pDB.lastError; - } - } - else{ - secerror("octagon: failed to update local context record: %@", _pDB.lastError); - - if(error != nil){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorNoColumn userInfo:nil]; - } - } - return result; -} - --(BOOL) deleteLocalContext:(NSString*)contextIDAndDSID error:(NSError**)error -{ - BOOL result = NO; - secnotice("octagon", "deleting local context: %@", contextIDAndDSID); - - result = [_pDB execute:@"delete from context where contextIDAndDSID == %@", - PQLName(contextIDAndDSID)]; - - if(!result){ - secerror("octagon: error updating table: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteAllContexts:(NSError**)error -{ - BOOL result = NO; - secnotice("octagon", "deleting all local context"); - - result = [_pDB execute:@"delete from context"]; - - if(!result){ - secerror("octagon: error updating table: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - -///// -// Local Bottled Peer Record -///// - -- (BOOL) insertBottledPeerRecord:(OTBottledPeerRecord *)rec - escrowRecordID:(NSString *)escrowRecordID - error:(NSError**)error -{ - BOOL result; - - result = [_pDB execute:@"insert or replace into bp (bottledPeerRecordID, contextIDAndDSID, escrowRecordID, peerID, spID, bottle, escrowSigningSPKI, peerSigningSPKI, signatureUsingEscrow, signatureUsingPeerKey, encodedRecord, launched) values (%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@,%@)", - rec.recordName, - [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], - escrowRecordID, - rec.peerID, - rec.spID, - [rec.bottle base64EncodedStringWithOptions:0], - [rec.escrowedSigningSPKI base64EncodedStringWithOptions:0], - [rec.peerSigningSPKI base64EncodedStringWithOptions:0], - [rec.signatureUsingEscrowKey base64EncodedStringWithOptions:0], - [rec.signatureUsingPeerKey base64EncodedStringWithOptions:0], - [rec.encodedRecord base64EncodedStringWithOptions:0], - rec.launched]; - - if (!result) { - secerror("octagon: error inserting bottled peer record: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) removeAllBottledPeerRecords:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid]]; - - if (!result) { - secerror("octagon: error removing bottled peer records: %@", _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteBottledPeer:(NSString*) recordID - error:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@ AND bottledPeerRecordID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], recordID]; - - if (!result) { - secerror("octagon: error removing bottled peer record:%@, error: %@", recordID, _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - --(BOOL) deleteBottledPeersForContextAndDSID:(NSString*) contextIDAndDSID - error:(NSError**)error -{ - BOOL result = NO; - - result = [_pDB execute:@"DELETE from bp WHERE contextIDAndDSID == %@;", contextIDAndDSID]; - - if (!result) { - secerror("octagon: error removing bottled peer record:%@, error: %@", contextIDAndDSID, _pDB.lastError); - if(error){ - *error = _pDB.lastError; - } - } - return result; -} - -- (nullable OTBottledPeerRecord *)readLocalBottledPeerRecordWithRecordID:(NSString *)recordID - error:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp WHERE contextIDAndDSID == %@ AND bottledPeerRecordID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid], recordID); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entry for %@", recordID); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] > 1) { - secerror("octagon: error multiple records exist in local store for %@", recordID); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"error multiple records exist in local store"}]; - } - return nil; - } - else if([selectArray count] == 0){ - secerror("octagon: record does not exist: %@", recordID); - return nil; - } - NSDictionary *attributes = [selectArray objectAtIndex:0]; - - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.escrowRecordID = attributes[OTCKRecordEscrowRecordID]; - rec.peerID = attributes[OTCKRecordPeerID]; - rec.spID = attributes[OTCKRecordSPID]; - rec.bottle = dataFromBase64(attributes[OTCKRecordBottle]); - rec.escrowedSigningSPKI = dataFromBase64(attributes[OTCKRecordEscrowSigningSPKI]); - rec.peerSigningSPKI = dataFromBase64(attributes[OTCKRecordPeerSigningSPKI]); - rec.signatureUsingEscrowKey = dataFromBase64(attributes[OTCKRecordSignatureFromEscrow]); - rec.signatureUsingPeerKey = dataFromBase64(attributes[OTCKRecordSignatureFromPeerKey]); - rec.encodedRecord = dataFromBase64(attributes[OTCKRecordEncodedRecord]); - rec.launched = attributes[OTCKRecordLaunched]; - return rec; -} - -- (NSMutableArray*) convertResultsToBottles:(NSArray*) selectArray -{ - NSMutableArray *arrayOfBottleRecords = [NSMutableArray array]; - for(NSDictionary* bottle in selectArray){ - OTBottledPeerRecord *rec = [[OTBottledPeerRecord alloc] init]; - rec.escrowRecordID = bottle[OTCKRecordEscrowRecordID]; - rec.peerID = bottle[OTCKRecordPeerID]; - rec.spID = bottle[OTCKRecordSPID]; - rec.bottle = dataFromBase64(bottle[OTCKRecordBottle]); - rec.escrowedSigningSPKI = dataFromBase64(bottle[OTCKRecordEscrowSigningSPKI]); - rec.peerSigningSPKI = dataFromBase64(bottle[OTCKRecordPeerSigningSPKI]); - rec.signatureUsingEscrowKey = dataFromBase64(bottle[OTCKRecordSignatureFromEscrow]); - rec.signatureUsingPeerKey = dataFromBase64(bottle[OTCKRecordSignatureFromPeerKey]); - rec.encodedRecord = dataFromBase64(bottle[OTCKRecordEncodedRecord]); - rec.launched = bottle[OTCKRecordLaunched]; - - [arrayOfBottleRecords addObject:rec]; - } - return arrayOfBottleRecords; -} - -- (nullable NSArray*) readAllLocalBottledPeerRecords:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp where contextIDAndDSID == %@;", [NSString stringWithFormat:@"%@-%@", self.contextID, self.dsid]); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entries"); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] == 0) { - secerror("octagon: there are no bottled peer entries in local store"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"there are no bottled peer entries in local store"}]; - } - return nil; - } - - return [self convertResultsToBottles:selectArray]; -} - -- (nullable NSArray*) readLocalBottledPeerRecordsWithMatchingPeerID:(NSString*)peerID error:(NSError**)error -{ - NSArray *selectArray; - - selectArray = selectDictionaries(_pDB, @"SELECT * from bp where spID == %@;", peerID); - if (!selectArray) { - if (error) { - secerror("octagon: failed to read local store entries"); - *error = self.pDB.lastError; - } - return nil; - } - if ([selectArray count] == 0) { - secerror("octagon: there are no bottled peer entries in local store"); - if(error){ - *error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOTLocalStore userInfo:@{NSLocalizedDescriptionKey: @"there are no bottled peer entries in local store"}]; - } - return nil; - } - - return [self convertResultsToBottles:selectArray]; -} - -static NSData * _Nullable dataFromBase64(NSString * _Nullable base64) -{ - if (base64 && [base64 length] > 0) { - return [[NSData alloc] initWithBase64EncodedString:base64 options:0]; - } - return nil; -} - -@end -#endif diff --git a/keychain/ot/OTManager.h b/keychain/ot/OTManager.h index e5eee25d..88a1820f 100644 --- a/keychain/ot/OTManager.h +++ b/keychain/ot/OTManager.h @@ -27,7 +27,7 @@ #if OCTAGON #import "Analytics/SFAnalytics.h" #import "keychain/ot/OTManager.h" -#import "keychain/ot/OTContext.h" +#import "keychain/ot/OTRamping.h" #import "keychain/ot/OTFollowup.h" #import "keychain/ot/OTControlProtocol.h" #import "keychain/ot/OTSOSAdapter.h" @@ -36,7 +36,7 @@ #import "keychain/ot/OTCuttlefishAccountStateHolder.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" #import "keychain/ckks/CKKSAccountStateTracker.h" -#include +#include "keychain/securityd/SecDbItem.h" #import NS_ASSUME_NONNULL_BEGIN @@ -48,39 +48,31 @@ NS_ASSUME_NONNULL_BEGIN @interface OTManager : NSObject -@property (nonatomic, readonly) NSDate *lastPostedCoreFollowUp; @property (nonatomic, readonly) CKKSLockStateTracker* lockStateTracker; @property id accountStateTracker; --(instancetype)init; - --(instancetype) initWithContext:(OTContext* _Nullable)context - localStore:(OTLocalStore* _Nullable)localStore - enroll:(OTRamp* _Nullable)enroll - restore:(OTRamp* _Nullable)restore - cfu:(OTRamp* _Nullable)cfu - cfuScheduler:(CKKSNearFutureScheduler* _Nullable)cfuScheduler - sosAdapter:(id)sosAdapter - authKitAdapter:(id)authKitAdapter - deviceInformationAdapter:(id)deviceInformationAdapter - apsConnectionClass:(Class)apsConnectionClass - escrowRequestClass:(Class)escrowRequestClass - loggerClass:(Class _Nullable)loggerClass - lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker - accountStateTracker:(id)accountStateTracker - cuttlefishXPCConnection:(id _Nullable)cuttlefishXPCConnection - cdpd:(id)cdpd; +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithSOSAdapter:(id)sosAdapter + authKitAdapter:(id)authKitAdapter + deviceInformationAdapter:(id)deviceInformationAdapter + apsConnectionClass:(Class)apsConnectionClass + escrowRequestClass:(Class)escrowRequestClass + loggerClass:(Class _Nullable)loggerClass + lockStateTracker:(CKKSLockStateTracker* _Nullable)lockStateTracker + accountStateTracker:(id)accountStateTracker + cuttlefishXPCConnection:(id _Nullable)cuttlefishXPCConnection + cdpd:(id)cdpd; // Call this to start up the state machinery - (void)initializeOctagon; -- (void) moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context; +- (BOOL)waitForReady:(NSString* _Nullable)containerName context:(NSString*)context wait:(int64_t)wait; +- (void)moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context; + (instancetype _Nullable)manager; + (instancetype _Nullable)resetManager:(bool)reset to:(OTManager* _Nullable)obj; - (void)xpc24HrNotification:(NSString* _Nullable)containerName context:(NSString*)context skipRateLimitingCheck:(BOOL)skipRateLimitingCheck reply:(void (^)(NSError *error))reply; --(BOOL)scheduledCloudKitRampCheck:(NSError**)error; - - (OTCuttlefishContext*)contextForContainerName:(NSString* _Nullable)containerName contextID:(NSString*)contextID sosAdapter:(id)sosAdapter diff --git a/keychain/ot/OTManager.m b/keychain/ot/OTManager.m index 4e6f4461..323919c1 100644 --- a/keychain/ot/OTManager.m +++ b/keychain/ot/OTManager.m @@ -32,13 +32,11 @@ #import "keychain/ot/OTControlProtocol.h" #import "keychain/ot/OTControl.h" #import "keychain/ot/OTClique.h" -#import "keychain/ot/OTContext.h" #import "keychain/ot/OTManager.h" #import "keychain/ot/OTDefines.h" #import "keychain/ot/OTRamping.h" #import "keychain/ot/OT.h" #import "keychain/ot/OTConstants.h" -#import "keychain/ot/OTBottledPeerState.h" #import "keychain/ot/OTCuttlefishContext.h" #import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTStates.h" @@ -102,19 +100,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; @end #endif -@interface OTManager () +@interface OTManager () @property NSXPCListener *listener; -@property (nonatomic, strong) OTContext* context; -@property (nonatomic, strong) OTLocalStore *localStore; -@property (nonatomic, strong) OTRamp *enrollRamp; -@property (nonatomic, strong) OTRamp *restoreRamp; -@property (nonatomic, strong) OTRamp *cfuRamp; + @property (nonatomic, strong) OTRamp *gbmidRamp; @property (nonatomic, strong) OTRamp *gbserialRamp; @property (nonatomic, strong) OTRamp *gbAgeRamp; -@property (nonatomic, strong) CKKSNearFutureScheduler *cfuScheduler; -@property (nonatomic, strong) NSDate *lastPostedCoreFollowUp; -@property (nonatomic, strong) OTBottledPeerState *bottleState; @property (nonatomic, strong) CKKSLockStateTracker *lockStateTracker; @property (nonatomic, strong) id cdpd; @@ -142,82 +133,45 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; @synthesize authKitAdapter = _authKitAdapter; @synthesize deviceInformationAdapter = _deviceInformationAdapter; --(instancetype)init +- (instancetype)init { - OTLocalStore* localStore = nil; - OTContext* context = nil; - - NSString* dsid = [self askAccountsForDSID]; - if(dsid){ - localStore = [[OTLocalStore alloc]initWithContextID:OTDefaultContext dsid:dsid path:nil error:nil]; - context = [[OTContext alloc]initWithContextID:OTDefaultContext dsid:dsid localStore:self.localStore cloudStore:nil identityProvider:self error:nil]; - } - //initialize our scheduler - CKKSNearFutureScheduler *cfuScheduler = [[CKKSNearFutureScheduler alloc] initWithName:@"scheduling-cfu" initialDelay:NUM_NSECS_IN_24_HRS continuingDelay:NUM_NSECS_IN_24_HRS keepProcessAlive:true dependencyDescriptionCode:CKKSResultDescriptionNone block:^{ - secnotice("octagon", "running scheduled cfu block"); - NSError* error = nil; - [self scheduledCloudKitRampCheck:&error]; - }]; - - //initialize our ramp objects - [self initRamps]; - // Under Octagon, the sos adatper is not considered essential. id sosAdapter = (OctagonPlatformSupportsSOS() ? [[OTSOSActualAdapter alloc] initAsEssential:NO] : [[OTSOSMissingAdapter alloc] init]); - return [self initWithContext:context - localStore:localStore - enroll:self.enrollRamp - restore:self.restoreRamp - cfu:self.cfuRamp - cfuScheduler:cfuScheduler - sosAdapter:sosAdapter - authKitAdapter:[[OTAuthKitActualAdapter alloc] init] - deviceInformationAdapter:[[OTDeviceInformationActualAdapter alloc] init] - apsConnectionClass:[APSConnection class] - escrowRequestClass:[EscrowRequestServer class] // Use the server class here to skip the XPC layer - loggerClass:[CKKSAnalytics class] - lockStateTracker:[CKKSLockStateTracker globalTracker] - // The use of CKKS's account tracker here is an inversion, and will be fixed with CKKS-for-all when we - // have Octagon own the CKKS objects - accountStateTracker:[CKKSViewManager manager].accountTracker - cuttlefishXPCConnection:nil - cdpd:[[CDPFollowUpController alloc] init]]; -} - --(instancetype) initWithContext:(OTContext*)context - localStore:(OTLocalStore*)localStore - enroll:(OTRamp*)enroll - restore:(OTRamp*)restore - cfu:(OTRamp*)cfu - cfuScheduler:(CKKSNearFutureScheduler*)cfuScheduler - sosAdapter:(id)sosAdapter - authKitAdapter:(id)authKitAdapter - deviceInformationAdapter:(id)deviceInformationAdapter - apsConnectionClass:(Class)apsConnectionClass - escrowRequestClass:(Class)escrowRequestClass - loggerClass:(Class)loggerClass - lockStateTracker:(CKKSLockStateTracker*)lockStateTracker - accountStateTracker:(id)accountStateTracker - cuttlefishXPCConnection:(id)cuttlefishXPCConnection - cdpd:(id)cdpd + return [self initWithSOSAdapter:sosAdapter + authKitAdapter:[[OTAuthKitActualAdapter alloc] init] + deviceInformationAdapter:[[OTDeviceInformationActualAdapter alloc] init] + apsConnectionClass:[APSConnection class] + escrowRequestClass:[EscrowRequestServer class] // Use the server class here to skip the XPC layer + loggerClass:[CKKSAnalytics class] + lockStateTracker:[CKKSLockStateTracker globalTracker] + // The use of CKKS's account tracker here is an inversion, and will be fixed with CKKS-for-all when we + // have Octagon own the CKKS objects + accountStateTracker:[CKKSViewManager manager].accountTracker + cuttlefishXPCConnection:nil + cdpd:[[CDPFollowUpController alloc] init]]; +} + +-(instancetype)initWithSOSAdapter:(id)sosAdapter + authKitAdapter:(id)authKitAdapter + deviceInformationAdapter:(id)deviceInformationAdapter + apsConnectionClass:(Class)apsConnectionClass + escrowRequestClass:(Class)escrowRequestClass + loggerClass:(Class)loggerClass + lockStateTracker:(CKKSLockStateTracker*)lockStateTracker + accountStateTracker:(id)accountStateTracker + cuttlefishXPCConnection:(id)cuttlefishXPCConnection + cdpd:(id)cdpd { - self = [super init]; - if(self){ - self.context = context; - self.localStore = localStore; - self.cfuRamp = cfu; - self.enrollRamp = enroll; - self.restoreRamp = restore; + if((self = [super init])) { _sosAdapter = sosAdapter; _authKitAdapter = authKitAdapter; _deviceInformationAdapter = deviceInformationAdapter; _loggerClass = loggerClass; _lockStateTracker = lockStateTracker; _accountStateTracker = accountStateTracker; - self.cfuScheduler = cfuScheduler; _sosEnabledForPlatform = OctagonPlatformSupportsSOS(); _cuttlefishXPCConnection = cuttlefishXPCConnection; @@ -258,6 +212,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; } } +- (BOOL)waitForReady:(NSString* _Nullable)containerName context:(NSString*)context wait:(int64_t)wait +{ + OTCuttlefishContext* c = [self contextForContainerName:containerName contextID:context]; + return [c waitForReady:wait]; +} + - (void) moveToCheckTrustedStateForContainer:(NSString* _Nullable)containerName context:(NSString*)context { OTCuttlefishContext* c = [self contextForContainerName:containerName @@ -324,10 +284,8 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; return manager; } --(BOOL) initRamps +- (void)ensureRampsInitialized { - BOOL initResult = NO; - CKContainer* container = [CKKSViewManager manager].container; CKDatabase* database = [container privateCloudDatabase]; CKRecordZoneID* zoneID = [[CKRecordZoneID alloc] initWithZoneName:kOTRampZoneName ownerName:CKCurrentUserDefaultName]; @@ -336,104 +294,41 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; CKKSReachabilityTracker *reachabilityTracker = [CKKSViewManager manager].reachabilityTracker; CKKSLockStateTracker *lockStateTracker = [CKKSViewManager manager].lockStateTracker; - self.cfuRamp = [[OTRamp alloc]initWithRecordName:kOTRampForCFURecordName - localSettingName:@"cfu" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.enrollRamp = [[OTRamp alloc]initWithRecordName:kOTRampForEnrollmentRecordName - localSettingName:@"enroll" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - - self.restoreRamp = [[OTRamp alloc]initWithRecordName:kOTRampForRestoreRecordName - localSettingName:@"restore" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbmidRamp = [[OTRamp alloc]initWithRecordName:kOTRampForGhostBustMIDName - localSettingName:@"ghostBustMID" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbserialRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustSerialName - localSettingName:@"ghostBustSerial" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - self.gbAgeRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustAgeName - localSettingName:@"ghostBustAge" - container:container - database:database - zoneID:zoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; - - if(self.cfuRamp && self.enrollRamp && self.restoreRamp && self.gbmidRamp && self.gbserialRamp && self.gbAgeRamp){ - initResult = YES; - } - return initResult; -} - --(BOOL) initializeManagerPropertiesForContext:(NSString*)dsid error:(NSError**)error -{ - NSError *localError = nil; - BOOL initialized = YES; - - if(dsid == nil){ - dsid = [self askAccountsForDSID]; - } - - //create local store - self.localStore = [[OTLocalStore alloc] initWithContextID:OTDefaultContext dsid:dsid path:nil error:&localError]; - if(!self.localStore){ - secerror("octagon: could not create localStore: %@", localError); - initialized = NO; - } - - //create context - self.context = [[OTContext alloc]initWithContextID:OTDefaultContext dsid:dsid localStore:self.localStore cloudStore:nil identityProvider:self error:&localError]; - if(!self.context){ - secerror("octagon: could not create context: %@", localError); - self.localStore = nil; - initialized = NO; - } - - //just in case, init the ramp objects - [self initRamps]; - - if(localError && error){ - *error = localError; + if(!self.gbmidRamp) { + self.gbmidRamp = [[OTRamp alloc]initWithRecordName:kOTRampForGhostBustMIDName + localSettingName:@"ghostBustMID" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; + } + + if(!self.gbserialRamp) { + self.gbserialRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustSerialName + localSettingName:@"ghostBustSerial" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; + } + + if(!self.gbAgeRamp) { + self.gbAgeRamp = [[OTRamp alloc]initWithRecordName:kOTRampForghostBustAgeName + localSettingName:@"ghostBustAge" + container:container + database:database + zoneID:zoneID + accountTracker:accountTracker + lockStateTracker:lockStateTracker + reachabilityTracker:reachabilityTracker + fetchRecordRecordsOperationClass:[CKFetchRecordsOperation class]]; } - return initialized; } //// @@ -513,90 +408,10 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; NSError* _Nullable error))reply { secnotice("octagon", "handleIdentityChangeForSigningKey: %@", peerID); - NSError* error = nil; - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(NO,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(NO,error); - return; - - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(NO,error); - return; - } - - CKKSAnalytics* logger = [CKKSAnalytics logger]; - SFAnalyticsActivityTracker *tracker = [logger logSystemMetricsForActivityNamed:CKKSActivityOctagonUpdateBottle withAction:nil]; - - [tracker start]; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(NO,error); - [tracker cancel]; - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - //got an error from ramp check, we should log it - if(error){ - [logger logRecoverableError:error - forEvent:OctagonEventRamp - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"ramp check for updating bottle" - }]; - } - - if(!isFeatureOn){ //the feature is off for this device - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - [tracker cancel]; - reply(NO, error); - return; - } - - BOOL updated = [self.context updateAllBottlesForPeerID:peerID newSigningKey:peerSigningKey newEncryptionKey:encryptionKey error:&error]; - - if(!updated || error != nil) { - secerror("octagon: failed to update bottles for %@, error: %@", peerID, error); - [logger logUnrecoverableError:error forEvent:OctagonEventUpdateBottle withAttributes:@{ OctagonEventAttributeFailureReason : @"failed to update bottles"}]; - [tracker cancel]; - reply(NO, error); - return; - } - - [tracker stop]; - [logger logSuccessForEventNamed:OctagonEventUpdateBottle]; - - secnotice("octagon", "handleIdentityChangeForSigningKey completed, updated bottles for: %@", peerID); - - reply(YES, error); + reply(NO, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)preflightBottledPeer:(NSString*)contextID @@ -607,45 +422,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; NSError* _Nullable error))reply { secnotice("octagon", "preflightBottledPeer: %@ %@", contextID, dsid); - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:dsid error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,nil,nil,error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ //feature is off for this device - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(nil, nil, nil, error); - return; - } - - NSData* entropy = [self.context makeMeSomeEntropy:OTMasterSecretLength]; - if(!entropy){ - secerror("octagon: entropy creation failed: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEntropyCreationFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to create entropy"}]; - reply(nil, nil, nil, error); - return; - } - - OTPreflightInfo* result = [self.context preflightBottledPeer:contextID entropy:entropy error:&error]; - if(!result || error){ - secerror("octagon: preflight failed: %@", error); - reply(nil, nil, nil, error); - return; - } - - secnotice("octagon", "preflightBottledPeer completed, created: %@", result.bottleID); - - reply(entropy, result.bottleID, result.escrowedSigningSPKI, error); + reply(nil, + nil, + nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)launchBottledPeer:(NSString*)contextID @@ -653,156 +435,28 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; reply:(void (^ _Nullable)(NSError* _Nullable error))reply { secnotice("octagon", "launchBottledPeer"); - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - reply(error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(error); - return; - } - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:bottleID error:&error]; - if(!bprecord || error){ - secerror("octagon: could not retrieve record for: %@, error: %@", bottleID, error); - reply(error); - return; - } - BOOL result = [self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error]; - if(!result || error){ - secerror("octagon: could not upload record for bottleID %@, error: %@", bottleID, error); - reply(error); - return; - } - - secnotice("octagon", "successfully launched: %@", bprecord.recordName); - - reply(error); + reply([NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID reply:(void (^)(NSData* signingKeyData, NSData* encryptionKeyData, NSError *))reply { - //check if configuration zone allows restore - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:dsid error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,nil,error); - return; - } - } - - BOOL isFeatureOn = [self.restoreRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(nil, nil, error); - return; - } - - if(!escrowRecordID || [escrowRecordID length] == 0){ - secerror("octagon: missing escrowRecordID"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyEscrowRecordID userInfo:@{NSLocalizedDescriptionKey: @"Escrow Record ID is empty or missing"}]; - - reply(nil, nil, error); - return; - } - if(!dsid || [dsid length] == 0){ - secerror("octagon: missing dsid"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptyDSID userInfo:@{NSLocalizedDescriptionKey: @"DSID is empty or missing"}]; - reply(nil, nil, error); - return; - } - if(!secret || [secret length] == 0){ - secerror("octagon: missing secret"); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorEmptySecret userInfo:@{NSLocalizedDescriptionKey: @"Secret is empty or missing"}]; - reply(nil, nil, error); - return; - } - - OTBottledPeerSigned *bps = [_context restoreFromEscrowRecordID:escrowRecordID secret:secret error:&error]; - if(!bps || error != nil){ - secerror("octagon: failed to restore bottled peer: %@", error); - reply(nil, nil, error); - return; - } - - SFECKeyPair *encryptionKey = bps.bp.peerEncryptionKey; - SFPublicKey *encryptionPublicKey = encryptionKey.publicKey; - NSData* encryptionKeyData = encryptionPublicKey.keyData;// FIXME - - if(!encryptionKeyData){ - secerror("octagon: restored octagon encryption key is nil: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRestoredPeerEncryptionKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to retrieve restored Octagon Peer Encryption Key"}]; - reply(nil,nil,error); - return; - } - - SFECKeyPair *signingKey = bps.bp.peerSigningKey; - SFPublicKey *signingKeyPublicKey = signingKey.publicKey; - NSData* signingKeyData = signingKeyPublicKey.keyData;// FIXME - - if(!signingKeyData){ - secerror("octagon: restored octagon signing key is nil: %@", error); - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRestoredPeerSigningKeyFailure userInfo:@{NSLocalizedDescriptionKey: @"Failed to retrieve restored Octagon Peer Signing Key"}]; - reply(nil,nil,error); - return; - } - - secnotice("octagon", "restored bottled peer: %@", escrowRecordID); - - reply(signingKeyData, encryptionKeyData, error); + secnotice("octagon", "restore"); + reply(nil, + nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)scrubBottledPeer:(NSString*)contextID bottleID:(NSString*)bottleID reply:(void (^ _Nullable)(NSError* _Nullable error))reply { - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - reply(error); - return; - } - } - - BOOL isFeatureOn = [self.enrollRamp checkRampStateWithError:&error]; - - if(!isFeatureOn){ - secnotice("octagon", "bottled peers is not on"); - if(!error){ - error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorFeatureNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"Feature not enabled"}]; - } - reply(error); - return; - } - - BOOL result = [self.context scrubBottledPeer:contextID bottleID:bottleID error:&error]; - if(!result || error){ - secerror("octagon: could not scrub record for bottleID %@, error: %@", bottleID, error); - reply(error); - return; - } - - secnotice("octagon", "scrubbed bottled peer: %@", bottleID); - - reply(error); + reply([NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } //// @@ -811,243 +465,34 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; -(void)reset:(void (^)(BOOL result, NSError *))reply { - NSError* error = nil; - - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(NO,error); - return; - } - } - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(NO,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(NO,error); - return; - - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(NO,error); - return; - } - - NSError* bottledPeerError = nil; - - BOOL result = [_context.cloudStore performReset:&bottledPeerError]; - if(!result || bottledPeerError != nil){ - secerror("octagon: resetting octagon trust zone failed: %@", bottledPeerError); - } - - NSString* contextAndDSID = [NSString stringWithFormat:@"%@-%@", self.context.contextID, self.context.dsid]; - - result = [self.localStore deleteBottledPeersForContextAndDSID:contextAndDSID error:&bottledPeerError]; - if(!result){ - secerror("octagon: could not delete bottle peer records: %@: %@", self.context.contextID, bottledPeerError); - } - - reply(result, bottledPeerError); + reply(NO, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)listOfEligibleBottledPeerRecords:(void (^)(NSArray* listOfRecords, NSError * _Nullable))reply { - NSError* error = nil; - if(!self.context || !self.localStore){ - if(![self initializeManagerPropertiesForContext:nil error:&error]){ - secerror("octagon: could not init manager obejcts: %@", error); - reply(nil,error); - return; - } - } - - if(self.context.lockStateTracker.isLocked){ - secnotice("octagon","device is locked! can't check ramp state"); - error = [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain - code:errSecInteractionNotAllowed - userInfo:@{NSLocalizedDescriptionKey: @"device is locked"}]; - - reply(nil,error); - return; - } - - // Wait until the account tracker has had a chance to figure out the state - [self.context.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]; - if(self.context.accountTracker.currentCKAccountInfo.accountStatus != CKAccountStatusAvailable){ - secnotice("octagon","not signed in! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNotSignedIn - userInfo:@{NSLocalizedDescriptionKey: @"not signed in"}]; - reply(nil,error); - return; - } - if(!self.context.reachabilityTracker.currentReachability){ - secnotice("octagon","no network! can't check ramp state"); - error = [NSError errorWithDomain:OctagonErrorDomain - code:OTErrorNoNetwork - userInfo:@{NSLocalizedDescriptionKey: @"no network"}]; - reply(nil,error); - return; - } - - NSArray* list = [_context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - if(!list || error !=nil){ - secerror("octagon: there are not eligible bottle peer records: %@", error); - reply(nil,error); - return; - } - reply(list, error); + reply(@[], + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)octagonEncryptionPublicKey:(void (^)(NSData* encryptionKey, NSError *))reply { - __block NSData *encryptionKey = NULL; - __block NSError* localError = nil; - - SOSCCPerformWithOctagonEncryptionPublicKey(^(SecKeyRef octagonPrivKey, CFErrorRef error) { - CFDataRef key; - SecKeyCopyPublicBytes(octagonPrivKey, &key); - encryptionKey = CFBridgingRelease(key); - if(error){ - localError = (__bridge NSError*)error; - } - }); - if(!encryptionKey || localError != nil){ - reply(nil, localError); - secerror("octagon: retrieving the octagon encryption public key failed: %@", localError); - return; - } - reply(encryptionKey, localError); + reply(nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } -(void)octagonSigningPublicKey:(void (^)(NSData* encryptionKey, NSError *))reply { - __block NSData *signingKey = NULL; - __block NSError* localError = nil; - - SOSCCPerformWithOctagonSigningPublicKey(^(SecKeyRef octagonPrivKey, CFErrorRef error) { - CFDataRef key; - SecKeyCopyPublicBytes(octagonPrivKey, &key); - signingKey = CFBridgingRelease(key); - if(error){ - localError = (__bridge NSError*)error; - } - }); - if(!signingKey || localError != nil){ - reply(nil, localError); - secerror("octagon: retrieving the octagon signing public key failed: %@", localError); - return; - } - reply(signingKey, localError); -} - -//// -// MARK: OT Helpers -//// - --(BOOL)scheduledCloudKitRampCheck:(NSError**)error -{ - secnotice("octagon", "scheduling a CloudKit ramping check"); - NSError* localError = nil; - BOOL cancelScheduler = YES; - - CKKSAnalytics* logger = [CKKSAnalytics logger]; - - if(self.cfuRamp){ - BOOL canCFU = [self.cfuRamp checkRampStateWithError:&localError]; - - if(localError){ - secerror("octagon: checking ramp state for CFU error'd: %@", localError); - [logger logUnrecoverableError:localError forEvent:OctagonEventRamp withAttributes:@{ - OctagonEventAttributeFailureReason : @"ramp check failed", - }]; - } - - if(canCFU){ - secnotice("octagon", "CFU is enabled, checking if this device has a bottle"); - OctagonBottleCheckState bottleStatus = [self.context doesThisDeviceHaveABottle:&localError]; - - if(bottleStatus == NOBOTTLE){ - //time to post a follow up! - secnotice("octagon", "device does not have a bottle, posting a follow up"); - if(!SecCKKSTestsEnabled()){ - //40347954 removing cfu invocations until we can add CDP without creating a cycle. - //[self.context postFollowUp]; - secnotice("octagon", "would have posted a follow up"); - } - NSInteger timeDiff = -1; - - NSDate *currentDate = [NSDate date]; - if(self.lastPostedCoreFollowUp){ - timeDiff = [currentDate timeIntervalSinceDate:self.lastPostedCoreFollowUp]; - } - - //log how long we last posted a followup, if any - [logger logRecoverableError:localError - forEvent:OctagonEventCoreFollowUp - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"No bottle for peer", - OctagonEventAttributeTimeSinceLastPostedFollowUp: [NSNumber numberWithInteger:timeDiff], - }]; - - self.lastPostedCoreFollowUp = currentDate; - //if the followup failed or succeeded, we should continue the scheduler until we have a bottle. - cancelScheduler = NO; - }else if(bottleStatus == BOTTLE){ - secnotice("octagon", "device has a bottle"); - [logger logSuccessForEventNamed:OctagonEventBottleCheck]; - } - - if(localError){ - [logger logRecoverableError:localError - forEvent:OctagonEventBottleCheck - zoneName:kOTRampZoneName - withAttributes:@{ - OctagonEventAttributeFailureReason : @"bottle check", - }]; - } - } - } - if(cancelScheduler == NO){ - secnotice("octagon", "requesting bottle check again"); - [self.cfuScheduler trigger]; - } - - if(error && localError){ - *error = localError; - } - return cancelScheduler; -} - --(void)scheduleCFUForFuture -{ - secnotice("octagon", "scheduling a query to cloudkit to see if this device can post a core follow up"); - - [self.cfuScheduler trigger]; -} - -- (nullable OTIdentity *) currentIdentity:(NSError**)error -{ - return [OTIdentity currentIdentityFromSOS:error]; + reply(nil, + [NSError errorWithDomain:(__bridge NSString*)kSecErrorDomain + code:errSecUnimplemented + userInfo:nil]); } - (void)setCuttlefishXPCConnection:(id)cuttlefishXPCConnection @@ -1298,13 +743,14 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; - (void)resetAndEstablish:(NSString *)container context:(NSString *)context altDSID:(NSString*)altDSID + resetReason:(CuttlefishResetReason)resetReason reply:(void (^)(NSError * _Nullable))reply { SFAnalyticsActivityTracker *tracker = [[self.loggerClass logger] startLogSystemMetricsForActivityNamed:OctagonActivityResetAndEstablish]; OTCuttlefishContext* cfshContext = [self contextForContainerName:container contextID:context]; [cfshContext startOctagonStateMachine]; - [cfshContext rpcResetAndEstablish:^(NSError* resetAndEstablishError) { + [cfshContext rpcResetAndEstablish:resetReason reply:^(NSError* resetAndEstablishError) { [tracker stopWithEvent:OctagonEventResetAndEstablish result:resetAndEstablishError]; reply(resetAndEstablishError); }]; @@ -1497,14 +943,17 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; //// -(BOOL) ghostbustByMidEnabled { + [self ensureRampsInitialized]; return [self.gbmidRamp checkRampStateWithError:nil]; } -(BOOL) ghostbustBySerialEnabled { + [self ensureRampsInitialized]; return [self.gbserialRamp checkRampStateWithError:nil]; } -(BOOL) ghostbustByAgeEnabled { + [self ensureRampsInitialized]; return [self.gbAgeRamp checkRampStateWithError:nil]; } @@ -1553,10 +1002,10 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; // 3. Users in a bad state who have acted on the CFU will have no pending CFU, but will have CFU failures. // // We also record the time window between the last followup completion and invocation. - OTFollowup *followupHandler = cuttlefishContext.followupHandler; NSDate* dateOfLastFollowup = [[CKKSAnalytics logger] datePropertyForKey: OctagonAnalyticsLastCoreFollowup]; values[OctagonAnalyticsLastCoreFollowup] = @([CKKSAnalytics fuzzyDaysSinceDate:dateOfLastFollowup]); - values[OctagonAnalyticsCoreFollowupStatus] = @(followupHandler.followupStatus); + // We used to report this, but it was never set + //values[OctagonAnalyticsCoreFollowupStatus] = @(followupHandler.followupStatus); for (NSString *type in [self cdpContextTypes]) { NSString *metricName = [NSString stringWithFormat:@"%@%@", OctagonAnalyticsCDPStateRun, type]; @@ -1643,17 +1092,22 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; } CFErrorRef validateError = NULL; - bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, CFBridgingRetain(recoveryKey), &validateError); + bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, (__bridge CFStringRef)recoveryKey, &validateError); if (!res) { + NSError *validateErrorWrapper = nil; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = @"malformed recovery key"; + if(validateError) { + userInfo[NSUnderlyingErrorKey] = CFBridgingRelease(validateError); + } + + validateErrorWrapper = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRecoveryKeyMalformed userInfo:userInfo]; + secerror("recovery failed validation with error:%@", validateError); - NSError *validateErrorWrapper = (__bridge_transfer NSError *)validateError; [tracker stopWithEvent:OctagonEventSetRecoveryKeyValidationFailed result:validateErrorWrapper]; - - if (validateErrorWrapper) { - reply(validateErrorWrapper); - return; - } + reply(validateErrorWrapper); + return; } OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID]; @@ -1676,17 +1130,22 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; SFAnalyticsActivityTracker *tracker = [[self.loggerClass logger] startLogSystemMetricsForActivityNamed:OctagonActivityJoinWithRecoveryKey]; CFErrorRef validateError = NULL; - bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, CFBridgingRetain(recoveryKey), &validateError); + bool res = SecPasswordValidatePasswordFormat(kSecPasswordTypeiCloudRecoveryKey, (__bridge CFStringRef)recoveryKey, &validateError); if (!res) { + NSError *validateErrorWrapper = nil; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = @"malformed recovery key"; + if(validateError) { + userInfo[NSUnderlyingErrorKey] = CFBridgingRelease(validateError); + } + + validateErrorWrapper = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorRecoveryKeyMalformed userInfo:userInfo]; + secerror("recovery failed validation with error:%@", validateError); - NSError *validateErrorWrapper = (__bridge_transfer NSError *)validateError; [tracker stopWithEvent:OctagonEventJoinRecoveryKeyValidationFailed result:validateErrorWrapper]; - - if (validateErrorWrapper) { - reply(validateErrorWrapper); - return; - } + reply(validateErrorWrapper); + return; } OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID]; @@ -1699,7 +1158,7 @@ static NSString* const kOTRampZoneName = @"metadata_zone"; secerror("octagon, recovery key is not enrolled in octagon, resetting octagon circle"); [[self.loggerClass logger] logResultForEvent:OctagonEventJoinRecoveryKeyCircleReset hardFailure:NO result:error]; - [cfshContext rpcResetAndEstablish:^(NSError *resetError) { + [cfshContext rpcResetAndEstablish:CuttlefishResetReasonRecoveryKey reply:^(NSError *resetError) { if (resetError) { secerror("octagon, failed to reset octagon"); [tracker stopWithEvent:OctagonEventJoinRecoveryKeyCircleResetFailed result:resetError]; diff --git a/keychain/ot/OTOperationDependencies.h b/keychain/ot/OTOperationDependencies.h index bd569114..e9e5aeb6 100644 --- a/keychain/ot/OTOperationDependencies.h +++ b/keychain/ot/OTOperationDependencies.h @@ -1,10 +1,12 @@ #import +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/ot/OctagonStateMachine.h" #import "keychain/ot/OTSOSAdapter.h" #import "keychain/ot/OTAuthKitAdapter.h" #import "keychain/ot/OTCuttlefishAccountStateHolder.h" +#import "keychain/ot/OTDeviceInformationAdapter.h" #import "keychain/ckks/CKKSViewManager.h" #import "keychain/ckks/CKKSNearFutureScheduler.h" #import "keychain/escrowrequest/Framework/SecEscrowRequest.h" @@ -23,7 +25,8 @@ NS_ASSUME_NONNULL_BEGIN @property id sosAdapter; @property (nullable) id octagonAdapter; @property id authKitAdapter; -@property id cuttlefishXPC; +@property id deviceInformationAdapter; +@property (readonly) CuttlefishXPCWrapper* cuttlefishXPCWrapper; @property CKKSViewManager* viewManager; @property CKKSLockStateTracker* lockStateTracker; @property Class escrowRequestClass; @@ -35,9 +38,10 @@ NS_ASSUME_NONNULL_BEGIN sosAdapter:(id)sosAdapter octagonAdapter:(id _Nullable)octagonAdapter authKitAdapter:(id)authKitAdapter + deviceInfoAdapter:(id)deviceInfoAdapter viewManager:(CKKSViewManager*)viewManager lockStateTracker:(CKKSLockStateTracker *)lockStateTracker - cuttlefishXPC:(id)cuttlefishXPC + cuttlefishXPCWrapper:(CuttlefishXPCWrapper *)cuttlefishXPCWrapper escrowRequestClass:(Class)escrowRequestClass; @end diff --git a/keychain/ot/OTOperationDependencies.m b/keychain/ot/OTOperationDependencies.m index 058217a0..a1ec5c20 100644 --- a/keychain/ot/OTOperationDependencies.m +++ b/keychain/ot/OTOperationDependencies.m @@ -9,9 +9,10 @@ sosAdapter:(id)sosAdapter octagonAdapter:(id _Nullable)octagonAdapter authKitAdapter:(id)authKitAdapter + deviceInfoAdapter:(id)deviceInfoAdapter viewManager:(CKKSViewManager*)viewManager lockStateTracker:(CKKSLockStateTracker*)lockStateTracker - cuttlefishXPC:(id)cuttlefishXPC + cuttlefishXPCWrapper:(CuttlefishXPCWrapper *)cuttlefishXPCWrapper escrowRequestClass:(Class)escrowRequestClass { if((self = [super init])) { @@ -22,9 +23,10 @@ _sosAdapter = sosAdapter; _octagonAdapter = octagonAdapter; _authKitAdapter = authKitAdapter; + _deviceInformationAdapter = deviceInfoAdapter; _viewManager = viewManager; _lockStateTracker = lockStateTracker; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; _escrowRequestClass = escrowRequestClass; } return self; diff --git a/keychain/ot/OTPreflightInfo.m b/keychain/ot/OTPreflightInfo.m deleted file mode 100644 index 539856d4..00000000 --- a/keychain/ot/OTPreflightInfo.m +++ /dev/null @@ -1,32 +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 OCTAGON - -#import "OTPreflightInfo.h" - -@implementation OTPreflightInfo - -@end - -#endif diff --git a/keychain/ot/OTPrepareOperation.m b/keychain/ot/OTPrepareOperation.m index 7c9f1b98..b2e5dd96 100644 --- a/keychain/ot/OTPrepareOperation.m +++ b/keychain/ot/OTPrepareOperation.m @@ -128,66 +128,59 @@ secerror("octagon: failed to save 'attempted join' state: %@", persistError); } - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:OctagonEventPrepareIdentity withAttributes:nil]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] prepareWithContainer:self.deps.containerName - context:self.deps.contextID - epoch:self.epoch - machineID:self.deviceInfo.machineID - bottleSalt:bottleSalt - bottleID:[NSUUID UUID].UUIDString - modelID:self.deviceInfo.modelID - deviceName:self.deviceInfo.deviceName - serialNumber:self.deviceInfo.serialNumber - osVersion:self.deviceInfo.osVersion - policyVersion:nil - policySecrets:nil -signingPrivKeyPersistentRef:signingKeyPersistRef - encPrivKeyPersistentRef:encryptionKeyPersistRef - reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error]; - if(error) { - secerror("octagon: Error preparing identity: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - secnotice("octagon", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); - self.peerID = peerID; - self.permanentInfo = permanentInfo; - self.permanentInfoSig = permanentInfoSig; - self.stableInfo = stableInfo; - self.stableInfoSig = stableInfoSig; - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistNewEgoPeerID:peerID error:&localError]; - if(!persisted || localError) { - secnotice("octagon", "Couldn't persist peer ID: %@", localError); - self.error = localError; - [self runBeforeGroupFinished:self.finishedOp]; - } else { - WEAKIFY(self); - - CKKSResultOperation *doneOp = [CKKSResultOperation named:@"ot-prepare" - withBlock:^{ - STRONGIFY(self); - self.nextState = self.intendedState; - }]; - - OTFetchViewsOperation *fetchViewsOp = [[OTFetchViewsOperation alloc] initWithDependencies:self.deps]; - [self runBeforeGroupFinished:fetchViewsOp]; - [doneOp addDependency:fetchViewsOp]; - [self runBeforeGroupFinished:doneOp]; - [self.finishedOp addDependency:doneOp]; - [self runBeforeGroupFinished:self.finishedOp]; - } - } - }]; + [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName + context:self.deps.contextID + epoch:self.epoch + machineID:self.deviceInfo.machineID + bottleSalt:bottleSalt + bottleID:[NSUUID UUID].UUIDString + modelID:self.deviceInfo.modelID + deviceName:self.deviceInfo.deviceName + serialNumber:self.deviceInfo.serialNumber + osVersion:self.deviceInfo.osVersion + policyVersion:nil + policySecrets:nil + signingPrivKeyPersistentRef:signingKeyPersistRef + encPrivKeyPersistentRef:encryptionKeyPersistRef + reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error]; + if(error) { + secerror("octagon: Error preparing identity: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + secnotice("octagon", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); + self.peerID = peerID; + self.permanentInfo = permanentInfo; + self.permanentInfoSig = permanentInfoSig; + self.stableInfo = stableInfo; + self.stableInfoSig = stableInfoSig; + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistNewEgoPeerID:peerID error:&localError]; + if(!persisted || localError) { + secnotice("octagon", "Couldn't persist peer ID: %@", localError); + self.error = localError; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + WEAKIFY(self); + + CKKSResultOperation *doneOp = [CKKSResultOperation named:@"ot-prepare" + withBlock:^{ + STRONGIFY(self); + self.nextState = self.intendedState; + }]; + + OTFetchViewsOperation *fetchViewsOp = [[OTFetchViewsOperation alloc] initWithDependencies:self.deps]; + [self runBeforeGroupFinished:fetchViewsOp]; + [doneOp addDependency:fetchViewsOp]; + [self runBeforeGroupFinished:doneOp]; + [self.finishedOp addDependency:doneOp]; + [self runBeforeGroupFinished:self.finishedOp]; + } + } + }]; } @end diff --git a/keychain/ot/OTRemovePeersOperation.m b/keychain/ot/OTRemovePeersOperation.m index 72cbe6ef..231e9b17 100644 --- a/keychain/ot/OTRemovePeersOperation.m +++ b/keychain/ot/OTRemovePeersOperation.m @@ -62,26 +62,20 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] distrustPeerIDsWithContainer:self.deps.containerName - context:self.deps.contextID - peerIDs:self.peerIDs - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - if(error) { - secnotice("octagon", "Unable to remove peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully removed peers"); - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper distrustPeerIDsWithContainer:self.deps.containerName + context:self.deps.contextID + peerIDs:self.peerIDs + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + if(error) { + secnotice("octagon", "Unable to remove peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully removed peers"); + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTResetOperation.h b/keychain/ot/OTResetOperation.h index c331aa90..33379393 100644 --- a/keychain/ot/OTResetOperation.h +++ b/keychain/ot/OTResetOperation.h @@ -26,18 +26,22 @@ #import #import "keychain/ckks/CKKSGroupOperation.h" #import "keychain/ot/OctagonStateMachineHelpers.h" +#import "keychain/ot/CuttlefishXPCWrapper.h" #import "keychain/ot/OTAuthKitAdapter.h" - +#import "keychain/ot/OTConstants.h" NS_ASSUME_NONNULL_BEGIN @interface OTResetOperation : CKKSGroupOperation - (instancetype)init:(NSString*)containerName contextID:(NSString*)contextID + reason:(CuttlefishResetReason)reason intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC; +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper; + +@property CuttlefishResetReason resetReason; @end NS_ASSUME_NONNULL_END diff --git a/keychain/ot/OTResetOperation.m b/keychain/ot/OTResetOperation.m index 79eb5dfe..49140e45 100644 --- a/keychain/ot/OTResetOperation.m +++ b/keychain/ot/OTResetOperation.m @@ -30,7 +30,7 @@ @interface OTResetOperation () @property NSString* containerName; @property NSString* contextID; -@property id cuttlefishXPC; +@property CuttlefishXPCWrapper* cuttlefishXPCWrapper; // Since we're making callback based async calls, use this operation trick to hold off the ending of this operation @property NSOperation* finishedOp; @@ -42,9 +42,10 @@ - (instancetype)init:(NSString*)containerName contextID:(NSString*)contextID + reason:(CuttlefishResetReason)reason intendedState:(OctagonState*)intendedState errorState:(OctagonState*)errorState - cuttlefishXPC:(id)cuttlefishXPC +cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper { if((self = [super init])) { _intendedState = intendedState; @@ -52,7 +53,8 @@ _containerName = containerName; _contextID = contextID; - _cuttlefishXPC = cuttlefishXPC; + _cuttlefishXPCWrapper = cuttlefishXPCWrapper; + _resetReason = reason; } return self; } @@ -65,29 +67,23 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; WEAKIFY(self); - [[self.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventReset withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.cuttlefishXPCWrapper resetWithContainer:self.containerName + context:self.contextID + resetReason:self.resetReason + reply:^(NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventReset hardFailure:true result:error]; + + if(error) { + secnotice("octagon", "Unable to reset for (%@,%@): %@", self.containerName, self.contextID, error); + self.error = error; + } else { + secnotice("octagon", "Successfully reset Octagon"); + self.nextState = self.intendedState; + } - }] resetWithContainer:self.containerName - context:self.contextID - reply:^(NSError * _Nullable error) { - STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventReset hardFailure:true result:error]; - - if(error) { - secnotice("octagon", "Unable to reset for (%@,%@): %@", self.containerName, self.contextID, error); - self.error = error; - } else { - secnotice("octagon", "Successfully reset Octagon"); - self.nextState = self.intendedState; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSOSAdapter.h b/keychain/ot/OTSOSAdapter.h index f8adfb8b..dddda03b 100644 --- a/keychain/ot/OTSOSAdapter.h +++ b/keychain/ot/OTSOSAdapter.h @@ -1,6 +1,7 @@ #if OCTAGON #import "keychain/ckks/CKKSPeer.h" +#import "keychain/ckks/CKKSPeerProvider.h" #import "keychain/ot/OTDefines.h" #import "keychain/SecureObjectSync/SOSCloudCircle.h" diff --git a/keychain/ot/OTSOSAdapter.m b/keychain/ot/OTSOSAdapter.m index 41b65403..69ed211f 100644 --- a/keychain/ot/OTSOSAdapter.m +++ b/keychain/ot/OTSOSAdapter.m @@ -7,7 +7,7 @@ #import "keychain/SecureObjectSync/SOSCloudCircleInternal.h" #include "keychain/SecureObjectSync/SOSViews.h" -#import "OSX/sec/securityd/SOSCloudCircleServer.h" +#import "keychain/securityd/SOSCloudCircleServer.h" #import "OSX/utilities/SecCFWrappers.h" #import "keychain/categories/NSError+UsefulConstructors.h" @@ -282,6 +282,27 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + __block CKKSPeerProviderState* result = nil; + + [SOSAccount performOnQuietAccountQueue: ^{ + NSError* selfPeersError = nil; + CKKSSelves* currentSelfPeers = [self fetchSelfPeers:&selfPeersError]; + + NSError* trustedPeersError = nil; + NSSet>* currentTrustedPeers = [self fetchTrustedPeers:&trustedPeersError]; + + result = [[CKKSPeerProviderState alloc] initWithPeerProviderID:self.providerID + essential:self.essential + selfPeers:currentSelfPeers + selfPeersError:selfPeersError + trustedPeers:currentTrustedPeers + trustedPeersError:trustedPeersError]; + }]; + + return result; +} + + (NSArray*)peerPublicSigningKeySPKIs:(NSSet>* _Nullable)peerSet { NSMutableArray* publicSigningSPKIs = [NSMutableArray array]; @@ -373,6 +394,19 @@ // no op } +- (nonnull CKKSPeerProviderState *)currentState { + NSError* unimplementedError = [NSError errorWithDomain:NSOSStatusErrorDomain + code:errSecUnimplemented + description:@"SOS unsupported on this platform"]; + return [[CKKSPeerProviderState alloc] initWithPeerProviderID:self.providerID + essential:self.essential + selfPeers:nil + selfPeersError:unimplementedError + trustedPeers:nil + trustedPeersError:unimplementedError]; +} + + @end #endif // OCTAGON diff --git a/keychain/ot/OTSOSUpdatePreapprovalsOperation.m b/keychain/ot/OTSOSUpdatePreapprovalsOperation.m index e388dfbf..7abf6522 100644 --- a/keychain/ot/OTSOSUpdatePreapprovalsOperation.m +++ b/keychain/ot/OTSOSUpdatePreapprovalsOperation.m @@ -59,10 +59,11 @@ // Is this a very scary error? bool fatal = false; - NSTimeInterval ckdelay = CKRetryAfterSecondsForError(self.error); - NSTimeInterval delay = 30; - if(ckdelay != 0) { - delay = ckdelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = 30; } if([self.error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { @@ -98,26 +99,20 @@ NSArray* publicSigningSPKIs = [OTSOSActualAdapter peerPublicSigningKeySPKIs:peerSet]; secnotice("octagon-sos", "Updating SOS preapproved keys to %@", publicSigningSPKIs); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, update of preapproved keys is lost: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] setPreapprovedKeysWithContainer:self.deps.containerName - context:self.deps.contextID - preapprovedKeys:publicSigningSPKIs - reply:^(NSError* error) { - STRONGIFY(self); - if(error) { - secerror("octagon-sos: unable to update preapproved keys: %@", error); - self.error = error; - } else { - secnotice("octagon-sos", "Updated SOS preapproved keys"); - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper setPreapprovedKeysWithContainer:self.deps.containerName + context:self.deps.contextID + preapprovedKeys:publicSigningSPKIs + reply:^(NSError* error) { + STRONGIFY(self); + if(error) { + secerror("octagon-sos: unable to update preapproved keys: %@", error); + self.error = error; + } else { + secnotice("octagon-sos", "Updated SOS preapproved keys"); + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSOSUpgradeOperation.m b/keychain/ot/OTSOSUpgradeOperation.m index 3df7a768..fad75dd8 100644 --- a/keychain/ot/OTSOSUpgradeOperation.m +++ b/keychain/ot/OTSOSUpgradeOperation.m @@ -97,6 +97,13 @@ return; } + // Now that we have some non-error SOS status, write down that we attempted an SOS Upgrade. + NSError* persistError = nil; + BOOL persisted = [self.deps.stateHolder persistOctagonJoinAttempt:OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED error:&persistError]; + if(!persisted || persistError) { + secerror("octagon: failed to save 'attempted join' state: %@", persistError); + } + if(sosCircleStatus != kSOSCCInCircle) { secnotice("octagon-sos", "Device is not in SOS circle (state: %@), quitting SOS upgrade", SOSAccountGetSOSCCStatusString(sosCircleStatus)); self.nextState = OctagonStateBecomeUntrusted; @@ -133,10 +140,11 @@ // Is this a very scary error? bool fatal = false; - NSTimeInterval ckdelay = CKRetryAfterSecondsForError(self.error); - NSTimeInterval delay = 30; - if(ckdelay != 0) { - delay = ckdelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = 30; } if([self.error isCuttlefishError:CuttlefishErrorResultGraphNotFullyReachable]) { @@ -176,92 +184,73 @@ } } - NSError* persistError = nil; - BOOL persisted = [self.deps.stateHolder persistOctagonJoinAttempt:OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED error:&persistError]; - if(!persisted || persistError) { - secerror("octagon: failed to save 'attempted join' state: %@", persistError); - } + [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName + context:self.deps.contextID + epoch:self.deviceInfo.epoch + machineID:self.deviceInfo.machineID + bottleSalt:bottleSalt + bottleID:[NSUUID UUID].UUIDString + modelID:self.deviceInfo.modelID + deviceName:self.deviceInfo.deviceName + serialNumber:self.self.deviceInfo.serialNumber + osVersion:self.deviceInfo.osVersion + policyVersion:nil + policySecrets:nil + signingPrivKeyPersistentRef:signingKeyPersistRef + encPrivKeyPersistentRef:encryptionKeyPersistRef + reply:^(NSString * _Nullable peerID, + NSData * _Nullable permanentInfo, + NSData * _Nullable permanentInfoSig, + NSData * _Nullable stableInfo, + NSData * _Nullable stableInfoSig, + NSError * _Nullable error) { + STRONGIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePrepare hardFailure:true result:error]; - }] prepareWithContainer:self.deps.containerName - context:self.deps.contextID - epoch:self.deviceInfo.epoch - machineID:self.deviceInfo.machineID - bottleSalt:bottleSalt - bottleID:[NSUUID UUID].UUIDString - modelID:self.deviceInfo.modelID - deviceName:self.deviceInfo.deviceName - serialNumber:self.self.deviceInfo.serialNumber - osVersion:self.deviceInfo.osVersion - policyVersion:nil - policySecrets:nil -signingPrivKeyPersistentRef:signingKeyPersistRef - encPrivKeyPersistentRef:encryptionKeyPersistRef - reply:^(NSString * _Nullable peerID, - NSData * _Nullable permanentInfo, - NSData * _Nullable permanentInfoSig, - NSData * _Nullable stableInfo, - NSData * _Nullable stableInfoSig, - NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePrepare hardFailure:true result:error]; - - if(error) { - secerror("octagon-sos: Error preparing identity: %@", error); - self.error = error; - [self handlePrepareErrors:error nextExpectedState:OctagonStateBecomeUntrusted]; - - [self runBeforeGroupFinished:self.finishedOp]; - } else { - secnotice("octagon-sos", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); - - [self afterPrepare]; - } + if(error) { + secerror("octagon-sos: Error preparing identity: %@", error); + self.error = error; + [self handlePrepareErrors:error nextExpectedState:OctagonStateBecomeUntrusted]; - }]; + [self runBeforeGroupFinished:self.finishedOp]; + } else { + secnotice("octagon-sos", "Prepared: %@ %@ %@", peerID, permanentInfo, permanentInfoSig); + + [self afterPrepare]; + } + + }]; } - (void)afterPrepare { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] preflightPreapprovedJoinWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(BOOL launchOkay, NSError * _Nullable error) { - STRONGIFY(self); + [self.deps.cuttlefishXPCWrapper preflightPreapprovedJoinWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(BOOL launchOkay, NSError * _Nullable error) { + STRONGIFY(self); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; - if(error) { - secerror("octagon-sos: preflightPreapprovedJoin failed: %@", error); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error]; + if(error) { + secerror("octagon-sos: preflightPreapprovedJoin failed: %@", error); - self.error = error; - self.nextState = OctagonStateBecomeUntrusted; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } + self.error = error; + self.nextState = OctagonStateBecomeUntrusted; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - if(!launchOkay) { - secnotice("octagon-sos", "TPH believes a preapprovedJoin will fail; aborting."); - self.nextState = OctagonStateBecomeUntrusted; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } + if(!launchOkay) { + secnotice("octagon-sos", "TPH believes a preapprovedJoin will fail; aborting."); + self.nextState = OctagonStateBecomeUntrusted; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } - secnotice("octagon-sos", "TPH believes a preapprovedJoin might succeed; continuing."); - [self afterPreflight]; - }]; + secnotice("octagon-sos", "TPH believes a preapprovedJoin might succeed; continuing."); + [self afterPreflight]; + }]; } - (void)afterPreflight @@ -369,66 +358,59 @@ signingPrivKeyPersistentRef:signingKeyPersistRef secnotice("octagon-sos", "Beginning SOS upgrade with %d key sets and %d SOS peers", (int)viewKeySets.count, (int)peerSet.count); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSilentEscrow hardFailure:true result:error]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper attemptPreapprovedJoinWithContainer:self.deps.containerName + context:self.deps.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + preapprovedKeys:publicSigningSPKIs + reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); - }] attemptPreapprovedJoinWithContainer:self.deps.containerName - context:self.deps.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - preapprovedKeys:publicSigningSPKIs - reply:^(NSString * _Nullable peerID, NSArray* keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreapprovedJoin hardFailure:true result:error]; - if(error) { - secerror("octagon-sos: attemptPreapprovedJoin failed: %@", error); - - if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { - secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; requesting reset"); - self.nextState = self.ckksConflictState; - } else { - self.error = error; - self.nextState = OctagonStateBecomeUntrusted; - } - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - [self requestSilentEscrowUpdate]; - - secerror("octagon-sos: attemptPreapprovedJoin succeded"); - - NSError* localError = nil; - BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { - metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; - metadata.peerID = peerID; - return metadata; - } error:&localError]; - - if(!persisted || localError) { - secnotice("octagon-sos", "Couldn't persist results: %@", localError); - self.error = localError; - self.nextState = OctagonStateError; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - self.nextState = self.intendedState; - - // Tell CKKS about our shiny new records! - for (id key in self.deps.viewManager.views) { - CKKSKeychainView* view = self.deps.viewManager.views[key]; - secnotice("octagon-ckks", "Providing ck records (from sos upgrade) to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreapprovedJoin hardFailure:true result:error]; + if(error) { + secerror("octagon-sos: attemptPreapprovedJoin failed: %@", error); + + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; requesting reset"); + self.nextState = self.ckksConflictState; + } else { + self.error = error; + self.nextState = OctagonStateBecomeUntrusted; + } + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + [self requestSilentEscrowUpdate]; + + secerror("octagon-sos: attemptPreapprovedJoin succeded"); + + NSError* localError = nil; + BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) { + metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED; + metadata.peerID = peerID; + return metadata; + } error:&localError]; + + if(!persisted || localError) { + secnotice("octagon-sos", "Couldn't persist results: %@", localError); + self.error = localError; + self.nextState = OctagonStateError; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + self.nextState = self.intendedState; + + // Tell CKKS about our shiny new records! + for (id key in self.deps.viewManager.views) { + CKKSKeychainView* view = self.deps.viewManager.views[key]; + secnotice("octagon-ckks", "Providing ck records (from sos upgrade) to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTSetRecoveryKeyOperation.m b/keychain/ot/OTSetRecoveryKeyOperation.m index e066172c..b83cbefa 100644 --- a/keychain/ot/OTSetRecoveryKeyOperation.m +++ b/keychain/ot/OTSetRecoveryKeyOperation.m @@ -93,29 +93,23 @@ { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventRecoveryKey withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - - }] setRecoveryKeyWithContainer:self.deps.containerName - context:self.deps.contextID - recoveryKey:self.recoveryKey - salt:salt - ckksKeys:viewKeySets - reply:^(NSError * _Nullable setError) { - if(setError){ - [[CKKSAnalytics logger] logResultForEvent:OctagonEventSetRecoveryKey hardFailure:true result:setError]; - secerror("octagon: Error setting recovery key: %@", setError); - self.error = setError; - [self runBeforeGroupFinished:self.finishOp]; - } else { - secnotice("octagon", "successfully set recovery key"); - [self runBeforeGroupFinished:self.finishOp]; - } - }]; + [self.deps.cuttlefishXPCWrapper setRecoveryKeyWithContainer:self.deps.containerName + context:self.deps.contextID + recoveryKey:self.recoveryKey + salt:salt + ckksKeys:viewKeySets + reply:^(NSError * _Nullable setError) { + STRONGIFY(self); + if(setError){ + [[CKKSAnalytics logger] logResultForEvent:OctagonEventSetRecoveryKey hardFailure:true result:setError]; + secerror("octagon: Error setting recovery key: %@", setError); + self.error = setError; + [self runBeforeGroupFinished:self.finishOp]; + } else { + secnotice("octagon", "successfully set recovery key"); + [self runBeforeGroupFinished:self.finishOp]; + } + }]; } @end diff --git a/keychain/ot/OTStates.h b/keychain/ot/OTStates.h index 279e7434..5133b381 100644 --- a/keychain/ot/OTStates.h +++ b/keychain/ot/OTStates.h @@ -100,6 +100,7 @@ extern OctagonState* const OctagonStateSecurityTrustCheck; extern OctagonState* const OctagonStateTPHTrustCheck; extern OctagonState* const OctagonStateCuttlefishTrustCheck; extern OctagonState* const OctagonStatePostRepairCFU; +extern OctagonState* const OctagonStateHealthCheckReset; // End of account reset state flow @@ -124,6 +125,8 @@ extern OctagonState* const OctagonStateDetermineiCloudAccountState; // CKKS sometimes needs an assist. These states are supposed to handle those cases extern OctagonState* const OctagonStateAssistCKKSTLKUpload; +extern OctagonState* const OctagonStateAssistCKKSTLKUploadCKKSReset; +extern OctagonState* const OctagonStateAssistCKKSTLKUploadAfterCKKSReset; // Call out to otpaird (KCPairing via IDS), then proceed to BecomeUntrusted extern OctagonState* const OctagonStateStartCompanionPairing; @@ -146,6 +149,8 @@ NSSet* OctagonInAccountStates(void); NSSet* OctagonHealthSourceStates(void); ////// State machine flags +extern OctagonFlag* const OctagonFlagIDMSLevelChanged; + extern OctagonFlag* const OctagonFlagEgoPeerPreapproved; extern OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload; @@ -161,8 +166,7 @@ extern OctagonFlag* const OctagonFlagAttemptSOSUpgrade; extern OctagonFlag* const OctagonFlagUnlocked; extern OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals; - -extern OctagonFlag* const OctagonFlagPerformHealthCheck; +extern OctagonFlag* const OctagonFlagAttemptSOSConsistency; extern OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation; diff --git a/keychain/ot/OTStates.m b/keychain/ot/OTStates.m index 448c356d..18e42299 100644 --- a/keychain/ot/OTStates.m +++ b/keychain/ot/OTStates.m @@ -99,12 +99,15 @@ OctagonState* const OctagonStateTPHTrustCheck = (OctagonState*) @"tph_trust_chec OctagonState* const OctagonStateCuttlefishTrustCheck = (OctagonState*) @"cuttlefish_trust_check"; OctagonState* const OctagonStatePostRepairCFU = (OctagonState*) @"post_repair_cfu"; OctagonState* const OctagonStateSecurityTrustCheck = (OctagonState*) @"security_trust_check"; +OctagonState* const OctagonStateHealthCheckReset = (OctagonState*) @"health_check_reset"; /* signout */ OctagonState* const OctagonStateNoAccountDoReset = (OctagonState*) @"no_account_do_reset"; OctagonState* const OctagonStateWaitForUnlock = (OctagonState*) @"wait_for_unlock"; OctagonState* const OctagonStateAssistCKKSTLKUpload = (OctagonState*) @"assist_ckks_tlk_upload"; +OctagonState* const OctagonStateAssistCKKSTLKUploadCKKSReset = (OctagonState*) @"assist_ckks_tlk_upload_ckks_reset"; +OctagonState* const OctagonStateAssistCKKSTLKUploadAfterCKKSReset = (OctagonState*) @"assist_ckks_tlk_upload_after_ckks_reset"; /* escrow */ OctagonState* const OctagonStateEscrowTriggerUpdate = (OctagonState*) @"escrow-trigger-update"; @@ -175,6 +178,9 @@ NSDictionary* OctagonStateMap(void) { OctagonStateInitiatorJoinCKKSReset: @47U, OctagonStateInitiatorJoinAfterCKKSReset: @48U, OctagonStateHSA2HealthCheck: @49U, + OctagonStateHealthCheckReset: @50U, + OctagonStateAssistCKKSTLKUploadCKKSReset: @51U, + OctagonStateAssistCKKSTLKUploadAfterCKKSReset: @52U, }; }); return map; @@ -190,7 +196,6 @@ NSDictionary* OctagonStateInverseMap(void) { return backwardMap; } -// This mistakenly includes OctagonStateWaitForHSA2, which should not be considered an "In Account" state. NSSet* OctagonInAccountStates(void) { static NSSet* s = nil; @@ -206,6 +211,7 @@ NSSet* OctagonInAccountStates(void) [sourceStates removeObject:OctagonStateDetermineiCloudAccountState]; [sourceStates removeObject:OctagonStateWaitingForCloudKitAccount]; [sourceStates removeObject:OctagonStateCloudKitNewlyAvailable]; + [sourceStates removeObject:OctagonStateWaitForHSA2]; s = sourceStates; }); @@ -231,6 +237,7 @@ NSSet* OctagonHealthSourceStates(void) } // Flags +OctagonFlag* const OctagonFlagIDMSLevelChanged = (OctagonFlag*) @"idms_level"; OctagonFlag* const OctagonFlagEgoPeerPreapproved = (OctagonFlag*) @"preapproved"; OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload = (OctagonFlag*) @"tlk_upload_needed"; OctagonFlag* const OctagonFlagCuttlefishNotification = (OctagonFlag*) @"recd_push"; @@ -239,6 +246,6 @@ OctagonFlag* const OctagonFlagAttemptSOSUpgrade = (OctagonFlag*)@"attempt_sos_up OctagonFlag* const OctagonFlagFetchAuthKitMachineIDList = (OctagonFlag*)@"attempt_machine_id_list"; OctagonFlag* const OctagonFlagUnlocked = (OctagonFlag*)@"unlocked"; OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals = (OctagonFlag*)@"attempt_sos_update_preapprovals"; -OctagonFlag* const OctagonFlagPerformHealthCheck = (OctagonFlag*)@"perform_health_check"; +OctagonFlag* const OctagonFlagAttemptSOSConsistency = (OctagonFlag*)@"attempt_sos_consistency"; OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation = (OctagonFlag*)@"escrowrequest_inform_cloudservices"; #endif // OCTAGON diff --git a/keychain/ot/OTUpdateTPHOperation.m b/keychain/ot/OTUpdateTPHOperation.m index d87e9be7..5a24b829 100644 --- a/keychain/ot/OTUpdateTPHOperation.m +++ b/keychain/ot/OTUpdateTPHOperation.m @@ -67,9 +67,6 @@ pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag conditions:OctagonPendingConditionsDeviceUnlocked]; fatal = false; - } else if ([self.error isCuttlefishError:CuttlefishErrorTransactionalFailure]) { - secnotice("octagon", "Transaction failure in cuttlefishm, retrying: %@", self.error); - fatal = false; } else { // more CloudKit errors should trigger a retry here secnotice("octagon", "Error is currently unknown, aborting: %@", self.error); @@ -78,7 +75,13 @@ if(!fatal) { if(!pendingFlag) { NSTimeInterval baseDelay = SecCKKSTestsEnabled() ? 2 : 30; - NSTimeInterval delay = CKRetryAfterSecondsForError(self.error) ?: baseDelay; + NSTimeInterval ckDelay = CKRetryAfterSecondsForError(self.error); + NSTimeInterval cuttlefishDelay = [self.error cuttlefishRetryAfter]; + NSTimeInterval delay = MAX(ckDelay, cuttlefishDelay); + if (delay == 0) { + delay = baseDelay; + } + pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag delayInSeconds:delay]; } @@ -91,62 +94,56 @@ [self dependOnBeforeGroupFinished:self.finishedOp]; - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, update is lost: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] updateWithContainer:self.deps.containerName - context:self.deps.contextID - deviceName:nil - serialNumber:nil - osVersion:nil - policyVersion:nil - policySecrets:nil - reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) { - STRONGIFY(self); - if(error || !peerState) { - secerror("octagon: update errored: %@", error); - self.error = error; - - // On an error, for now, go back to the intended state - // Octagon: handle lock state errors in update() - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - secnotice("octagon", "update complete: %@", peerState); - - if(peerState.identityIsPreapproved) { - secnotice("octagon-sos", "Self peer is now preapproved!"); - [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved]; - } - if (peerState.memberChanges) { - secnotice("octagon", "Member list changed"); - [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate]; - } - - if (peerState.unknownMachineIDsPresent) { - secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch"); - [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList]; - } - - if(peerState.peerStatus & TPPeerStatusExcluded) { - secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID); - self.nextState = OctagonStateBecomeUntrusted; - - } else if(peerState.peerStatus & TPPeerStatusUnknown) { - secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID); - self.nextState = OctagonStateBecomeUntrusted; - - } else { - self.nextState = self.intendedState; - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName + context:self.deps.contextID + deviceName:self.deps.deviceInformationAdapter.deviceName + serialNumber:self.deps.deviceInformationAdapter.serialNumber + osVersion:self.deps.deviceInformationAdapter.osVersion + policyVersion:nil + policySecrets:nil + reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) { + STRONGIFY(self); + if(error || !peerState) { + secerror("octagon: update errored: %@", error); + self.error = error; + + // On an error, for now, go back to the intended state + // Octagon: handle lock state errors in update() + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "update complete: %@", peerState); + + if(peerState.identityIsPreapproved) { + secnotice("octagon-sos", "Self peer is now preapproved!"); + [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved]; + } + if (peerState.memberChanges) { + secnotice("octagon", "Member list changed"); + [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate]; + } + + if (peerState.unknownMachineIDsPresent) { + secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch"); + [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList]; + } + + if(peerState.peerStatus & TPPeerStatusExcluded) { + secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID); + self.nextState = OctagonStateBecomeUntrusted; + + } else if(peerState.peerStatus & TPPeerStatusUnknown) { + secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID); + self.nextState = OctagonStateBecomeUntrusted; + + } else { + self.nextState = self.intendedState; + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTUpdateTrustedDeviceListOperation.m b/keychain/ot/OTUpdateTrustedDeviceListOperation.m index 814fab55..5f8a8763 100644 --- a/keychain/ot/OTUpdateTrustedDeviceListOperation.m +++ b/keychain/ot/OTUpdateTrustedDeviceListOperation.m @@ -111,38 +111,29 @@ - (void)afterAuthKitFetch:(NSSet*)allowedMachineIDs { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-sos: Can't talk with TrustedPeersHelper: %@", error); - if (self.logForUpgrade) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; - } - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] setAllowedMachineIDsWithContainer:self.deps.containerName - context:self.deps.contextID - allowedMachineIDs:allowedMachineIDs - reply:^(BOOL listDifferences, NSError * _Nullable error) { - STRONGIFY(self); - - if (self.logForUpgrade) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; - } - if(error) { - secnotice("octagon-authkit", "Unable to save machineID allow-list: %@", error); - self.error = error; - } else { - secnotice("octagon-authkit", "Successfully saved machineID allow-list (%@ change)", listDifferences ? @"some" : @"no"); - if(listDifferences) { - self.nextState = self.stateIfListUpdates; - } else { - self.nextState = self.intendedState; - } - } - - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper setAllowedMachineIDsWithContainer:self.deps.containerName + context:self.deps.contextID + allowedMachineIDs:allowedMachineIDs + reply:^(BOOL listDifferences, NSError * _Nullable error) { + STRONGIFY(self); + + if (self.logForUpgrade) { + [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradeSetAllowList hardFailure:true result:error]; + } + if(error) { + secnotice("octagon-authkit", "Unable to save machineID allow-list: %@", error); + self.error = error; + } else { + secnotice("octagon-authkit", "Successfully saved machineID allow-list (%@ change)", listDifferences ? @"some" : @"no"); + if(listDifferences) { + self.nextState = self.stateIfListUpdates; + } else { + self.nextState = self.intendedState; + } + } + + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTUploadNewCKKSTLKsOperation.h b/keychain/ot/OTUploadNewCKKSTLKsOperation.h index f59562bb..3feeab6a 100644 --- a/keychain/ot/OTUploadNewCKKSTLKsOperation.h +++ b/keychain/ot/OTUploadNewCKKSTLKsOperation.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies intendedState:(OctagonState*)intendedState + ckksConflictState:(OctagonState*)ckksConflictState errorState:(OctagonState*)errorState; @property OctagonState* nextState; diff --git a/keychain/ot/OTUploadNewCKKSTLKsOperation.m b/keychain/ot/OTUploadNewCKKSTLKsOperation.m index 069a433b..f5430804 100644 --- a/keychain/ot/OTUploadNewCKKSTLKsOperation.m +++ b/keychain/ot/OTUploadNewCKKSTLKsOperation.m @@ -19,11 +19,9 @@ @interface OTUploadNewCKKSTLKsOperation () @property OTOperationDependencies* deps; +@property OctagonState* ckksConflictState; + @property NSOperation* finishedOp; -@property int retries; -@property int maxRetries; -@property int delay; -@property CKKSNearFutureScheduler* retrySched; @end @implementation OTUploadNewCKKSTLKsOperation @@ -31,16 +29,14 @@ - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies intendedState:(OctagonState*)intendedState + ckksConflictState:(OctagonState*)ckksConflictState errorState:(OctagonState*)errorState { if((self = [super init])) { _deps = dependencies; - _retries = 0; - _maxRetries = 5; - _delay = 1; - _intendedState = intendedState; + _ckksConflictState = ckksConflictState; _nextState = errorState; } return self; @@ -91,24 +87,6 @@ [self runBeforeGroupFinished:proceedWithKeys]; } -- (BOOL)isRetryable:(NSError* _Nonnull)error { - return [error isCuttlefishError:CuttlefishErrorTransactionalFailure]; -} - -- (int)retryDelay:(NSError* _Nonnull)error { - NSError* underlyingError = error.userInfo[NSUnderlyingErrorKey]; - int ret = self->_delay; - if (underlyingError) { - id tmp = underlyingError.userInfo[@"retryafter"]; - if ([tmp isKindOfClass:[NSNumber class]]) { - ret = [(NSNumber*)tmp intValue]; - } - } - ret = MAX(MIN(ret, 32), self->_delay); - self->_delay *= 2; - return ret; -} - - (void)proceedWithKeys:(NSArray*)viewKeySets pendingTLKShares:(NSArray*)pendingTLKShares viewsToUpload:(NSSet*)viewsToUpload @@ -116,59 +94,32 @@ WEAKIFY(self); secnotice("octagon-ckks", "Beginning tlk upload with keys: %@", viewKeySets); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon-ckks: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventEstablishIdentity withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] updateTLKsWithContainer:self.deps.containerName - context:self.deps.contextID - ckksKeys:viewKeySets - tlkShares:pendingTLKShares - reply:^(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { - STRONGIFY(self); - - if(error) { - secerror("octagon: Error calling tlk upload: %@", error); - if (self.retries < self.maxRetries && [self isRetryable:error]) { - ++self.retries; - if (!self.retrySched) { - self.retrySched = [[CKKSNearFutureScheduler alloc] initWithName:@"cuttlefish-updatetlk-retry" - delay:1*NSEC_PER_SEC - keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - CKKSResultOperation* retryOp = [CKKSResultOperation named:@"retry-updatetlk" - withBlock:^{ - STRONGIFY(self); - secnotice("octagon", "retrying (%d/%d) updateTLKs", self.retries, self->_maxRetries); - [self proceedWithKeys:viewKeySets pendingTLKShares:pendingTLKShares viewsToUpload:viewsToUpload]; - }]; - STRONGIFY(self); - [self runBeforeGroupFinished:retryOp]; - }]; - } - int delay_s = [self retryDelay:error]; - [self.retrySched waitUntil:delay_s*NSEC_PER_SEC]; - [self.retrySched trigger]; - return; - } - self.error = error; - - } else { - - // Tell CKKS about our shiny new records! - for(CKKSKeychainView* view in viewsToUpload) { - secnotice("octagon-ckks", "Providing records to %@", view); - [view receiveTLKUploadRecords: keyHierarchyRecords]; - } - - self.nextState = self.intendedState; - } - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [self.deps.cuttlefishXPCWrapper updateTLKsWithContainer:self.deps.containerName + context:self.deps.contextID + ckksKeys:viewKeySets + tlkShares:pendingTLKShares + reply:^(NSArray* _Nullable keyHierarchyRecords, NSError * _Nullable error) { + STRONGIFY(self); + + if(error) { + if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) { + secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState); + self.nextState = self.ckksConflictState; + } else { + secerror("octagon: Error calling tlk upload: %@", error); + self.error = error; + } + } else { + // Tell CKKS about our shiny new records! + for(CKKSKeychainView* view in viewsToUpload) { + secnotice("octagon-ckks", "Providing records to %@", view); + [view receiveTLKUploadRecords: keyHierarchyRecords]; + } + + self.nextState = self.intendedState; + } + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTVouchWithBottleOperation.m b/keychain/ot/OTVouchWithBottleOperation.m index eb9b31c6..c96ba590 100644 --- a/keychain/ot/OTVouchWithBottleOperation.m +++ b/keychain/ot/OTVouchWithBottleOperation.m @@ -71,9 +71,10 @@ if(self.bottleSalt != nil) { secnotice("octagon", "using passed in altdsid, altdsid is: %@", self.bottleSalt); } else{ - if(self.deps.authKitAdapter.primaryiCloudAccountAltDSID){ - secnotice("octagon", "using auth kit adapter, altdsid is: %@", self.deps.authKitAdapter.primaryiCloudAccountAltDSID); - self.bottleSalt = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + NSString* altDSID = self.deps.authKitAdapter.primaryiCloudAccountAltDSID; + if(altDSID){ + secnotice("octagon", "fetched altdsid is: %@", altDSID); + self.bottleSalt = altDSID; } else { NSError* accountError = nil; @@ -107,38 +108,65 @@ - (void)proceedWithKeys:(NSArray*)viewKeySets tlkShares:(NSArray*)tlkShares { + // Preflight the vouch: this will tell us the peerID of the recovering peer. + // Then, filter the tlkShares array to include only tlks sent to that peer. WEAKIFY(self); - - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { + [self.deps.cuttlefishXPCWrapper preflightVouchWithBottleWithContainer:self.deps.containerName + context:self.deps.contextID + bottleID:self.bottleID + reply:^(NSString * _Nullable peerID, NSError * _Nullable error) { STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventVoucherWithBottle withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] vouchWithBottleWithContainer:self.deps.containerName - context:self.deps.contextID - bottleID:self.bottleID - entropy:self.entropy - bottleSalt:self.bottleSalt - tlkShares:tlkShares - reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { - [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithBottle hardFailure:true result:error]; - - if(error){ - secerror("octagon: Error preparing voucher using bottle: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - return; - } - - secnotice("octagon", "Received bottle voucher"); - - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishedOp]; - }]; + [[CKKSAnalytics logger] logResultForEvent:OctagonEventPreflightVouchWithBottle hardFailure:true result:error]; + + if(error){ + secerror("octagon: Error preflighting voucher using bottle: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "Bottle %@ is for peerID %@", self.bottleID, peerID); + + NSMutableArray* filteredTLKShares = [NSMutableArray array]; + for(CKKSTLKShare* share in tlkShares) { + // If we didn't get a peerID, just pass every tlkshare and hope for the best + if(peerID == nil || [share.receiverPeerID isEqualToString:peerID]) { + [filteredTLKShares addObject:share]; + } + } + + [self proceedWithKeys:viewKeySets filteredTLKShares:filteredTLKShares]; + }]; +} + +- (void)proceedWithKeys:(NSArray*)viewKeySets filteredTLKShares:(NSArray*)tlkShares +{ + WEAKIFY(self); + + [self.deps.cuttlefishXPCWrapper vouchWithBottleWithContainer:self.deps.containerName + context:self.deps.contextID + bottleID:self.bottleID + entropy:self.entropy + bottleSalt:self.bottleSalt + tlkShares:tlkShares + reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { + STRONGIFY(self); + [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithBottle hardFailure:true result:error]; + + if(error){ + secerror("octagon: Error preparing voucher using bottle: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishedOp]; + return; + } + + secnotice("octagon", "Received bottle voucher"); + + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishedOp]; + }]; } @end diff --git a/keychain/ot/OTVouchWithRecoveryKeyOperation.m b/keychain/ot/OTVouchWithRecoveryKeyOperation.m index b4fc0bc9..cded9242 100644 --- a/keychain/ot/OTVouchWithRecoveryKeyOperation.m +++ b/keychain/ot/OTVouchWithRecoveryKeyOperation.m @@ -108,31 +108,25 @@ { WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - [[CKKSAnalytics logger] logRecoverableError:error forEvent:OctagonEventVoucherWithBottle withAttributes:NULL]; - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - - }] vouchWithRecoveryKeyWithContainer:self.deps.containerName - context:self.deps.contextID - recoveryKey:self.recoveryKey - salt:salt - tlkShares:tlkShares - reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { - if(error){ - [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithRecoveryKey hardFailure:true result:error]; - secerror("octagon: Error preparing voucher using recovery key: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishOp]; - return; - } - self.voucher = voucher; - self.voucherSig = voucherSig; - self.nextState = self.intendedState; - [self runBeforeGroupFinished:self.finishOp]; - }]; + [self.deps.cuttlefishXPCWrapper vouchWithRecoveryKeyWithContainer:self.deps.containerName + context:self.deps.contextID + recoveryKey:self.recoveryKey + salt:salt + tlkShares:tlkShares + reply:^(NSData * _Nullable voucher, NSData * _Nullable voucherSig, NSError * _Nullable error) { + STRONGIFY(self); + if(error){ + [[CKKSAnalytics logger] logResultForEvent:OctagonEventVoucherWithRecoveryKey hardFailure:true result:error]; + secerror("octagon: Error preparing voucher using recovery key: %@", error); + self.error = error; + [self runBeforeGroupFinished:self.finishOp]; + return; + } + self.voucher = voucher; + self.voucherSig = voucherSig; + self.nextState = self.intendedState; + [self runBeforeGroupFinished:self.finishOp]; + }]; } @end diff --git a/keychain/ot/OctagonCKKSPeerAdapter.m b/keychain/ot/OctagonCKKSPeerAdapter.m index 3aacf713..2aac36d8 100644 --- a/keychain/ot/OctagonCKKSPeerAdapter.m +++ b/keychain/ot/OctagonCKKSPeerAdapter.m @@ -181,38 +181,34 @@ __block NSMutableSet> * peers = nil; WEAKIFY(self); - [[self.deps.cuttlefishXPC synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - secerror("octagon: Can't talk with TrustedPeersHelper: %@", error); - localerror = error; - - }] fetchTrustStateWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, - NSArray * _Nullable trustedPeers, - NSError * _Nullable operror) { - STRONGIFY(self); - if(operror) { - secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror); - localerror = operror; - - } else { - peers = [NSMutableSet set]; - - // Turn these peers into CKKSPeers - for(TrustedPeersHelperPeer* peer in trustedPeers) { - SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI]; - SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI]; - - CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID - encryptionPublicKey:encryptionKey - signingPublicKey:signingKey - viewList:peer.viewList]; - secnotice("octagon", "Have trusted peer %@", ckkspeer); - - [peers addObject:ckkspeer]; - } - } - }]; + [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, + NSArray * _Nullable trustedPeers, + NSError * _Nullable operror) { + STRONGIFY(self); + if(operror) { + secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror); + localerror = operror; + + } else { + peers = [NSMutableSet set]; + + // Turn these peers into CKKSPeers + for(TrustedPeersHelperPeer* peer in trustedPeers) { + SFECPublicKey* signingKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.signingSPKI]; + SFECPublicKey* encryptionKey = [SFECPublicKey keyWithSubjectPublicKeyInfo:peer.encryptionSPKI]; + + CKKSActualPeer* ckkspeer = [[CKKSActualPeer alloc] initWithPeerID:peer.peerID + encryptionPublicKey:encryptionKey + signingPublicKey:signingKey + viewList:peer.viewList]; + secnotice("octagon", "Have trusted peer %@", ckkspeer); + + [peers addObject:ckkspeer]; + } + } + }]; if(error && localerror) { *error = localerror; @@ -237,6 +233,11 @@ }]; } +- (nonnull CKKSPeerProviderState *)currentState { + return [CKKSPeerProviderState createFromProvider:self]; +} + + @end #endif // OCTAGON diff --git a/keychain/ot/OctagonCheckTrustStateOperation.m b/keychain/ot/OctagonCheckTrustStateOperation.m index 0e05403c..9fe406bf 100644 --- a/keychain/ot/OctagonCheckTrustStateOperation.m +++ b/keychain/ot/OctagonCheckTrustStateOperation.m @@ -45,28 +45,22 @@ // Make sure we're in agreement with TPH about _which_ peer ID we should have WEAKIFY(self); - [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) { - STRONGIFY(self); - secerror("octagon: Can't talk with TrustedPeersHelper, can't ensure check trust state: %@", error); - self.error = error; - [self runBeforeGroupFinished:self.finishedOp]; - - }] fetchTrustStateWithContainer:self.deps.containerName - context:self.deps.contextID - reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, - NSArray * _Nullable trustedPeers, - NSError * _Nullable error) { - STRONGIFY(self); - if(error || !selfPeerState || !trustedPeers) { - secerror("octagon: TPH was unable to determine current peer state: %@", error); - self.error = error; - self.nextState = OctagonStateError; - [self runBeforeGroupFinished:self.finishedOp]; + [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName + context:self.deps.contextID + reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState, + NSArray * _Nullable trustedPeers, + NSError * _Nullable error) { + STRONGIFY(self); + if(error || !selfPeerState || !trustedPeers) { + secerror("octagon: TPH was unable to determine current peer state: %@", error); + self.error = error; + self.nextState = OctagonStateError; + [self runBeforeGroupFinished:self.finishedOp]; - } else { - [self afterTPHTrustState:selfPeerState trustedPeers:trustedPeers]; - } - }]; + } else { + [self afterTPHTrustState:selfPeerState trustedPeers:trustedPeers]; + } + }]; } - (void)afterTPHTrustState:(TrustedPeersHelperPeerState*)peerState @@ -169,6 +163,17 @@ secnotice("octagon-consistency", "Saved new account metadata"); } + // See if we possibly should do an update because peer data in Octagon + // is different from local state, ie we upgraded + if (peerState.osVersion) { + NSString *osVersion = self.deps.deviceInformationAdapter.osVersion; + if (osVersion && ![osVersion isEqualToString:peerState.osVersion]) { + OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagCuttlefishNotification + conditions:OctagonPendingConditionsDeviceUnlocked]; + [self.deps.flagHandler handlePendingFlag:pendingFlag]; + } + } + // And determine where to go from here! if(currentAccountMetadata.peerID && currentAccountMetadata.trustState == OTAccountMetadataClassC_TrustState_TRUSTED) { @@ -178,19 +183,10 @@ } else if(self.deps.sosAdapter.sosEnabled && currentAccountMetadata.trustState != OTAccountMetadataClassC_TrustState_TRUSTED && OctagonPerformSOSUpgrade()) { - secnotice("octagon", "Have iCloud account but not trusted in Octagon yet; inspecting SOS status: %@", + secnotice("octagon", "Have iCloud account but not trusted in Octagon yet: %@; attempting SOS upgrade", [currentAccountMetadata trustStateAsString:currentAccountMetadata.trustState]); - NSError* circleError = nil; - SOSCCStatus sosStatus = [self.deps.sosAdapter circleStatus:&circleError]; - - if(sosStatus == kSOSCCInCircle) { - secnotice("octagon", "SOS status is 'trusted'; requesting SOS upgrade"); - [self.deps.flagHandler handleFlag:OctagonFlagAttemptSOSUpgrade]; - } else { - secnotice("octagon", "SOS status is %d (error: %@)", (int)sosStatus, circleError); - } - self.nextState = OctagonStateBecomeUntrusted; + self.nextState = OctagonStateAttemptSOSUpgrade; } else if(currentAccountMetadata.trustState != OTAccountMetadataClassC_TrustState_TRUSTED) { secnotice("octagon", "Have iCloud account but not trusted in Octagon (%@)", diff --git a/keychain/ot/tests/OTBottledPeerTLK.m b/keychain/ot/tests/OTBottledPeerTLK.m deleted file mode 100644 index 9a88281f..00000000 --- a/keychain/ot/tests/OTBottledPeerTLK.m +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2017 Apple Inc. All Rights Reserved. - * - * @APPLEself.LICENSEself.HEADERself.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. - * - * @APPLEself.LICENSEself.HEADERself.END@ - */ - -#if OCTAGON - -#import "OTTestsBase.h" - -@interface BottledPeerRestoreTLKTests : OTTestsBase -@property CKKSSOSSelfPeer* remotePeer1; -@property CKKSSOSPeer* remotePeer2; -@property CKKSSOSSelfPeer* untrustedPeer; - -@end - -@implementation BottledPeerRestoreTLKTests - -- (void)setUp -{ - [super setUp]; - - //set up a bottled peer and stick it in localStore - NSError* error = nil; - - self.remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:self.sosPeerID - encryptionKey:self.peerEncryptionKey - signingKey:self.peerSigningKey]; - - [self.currentPeers addObject:self.remotePeer1]; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - OTBottledPeerRecord* record = [bpSigned asRecord:[self currentIdentity:&error].spID]; - self.recordName = record.recordName; - - OTIdentity* identity = [self currentIdentity:&error]; - [self.localStore insertBottledPeerRecord:record escrowRecordID:identity.spID error:&error]; - - self.remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote-peer1" - encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] - signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]]; - - self.remotePeer2 = [[CKKSSOSPeer alloc] initWithSOSPeerID:@"remote-peer2" - encryptionPublicKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]].publicKey - signingPublicKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]].publicKey]; - - // Local SOS trusts these peers - [self.currentPeers addObject:self.remotePeer1]; - [self.currentPeers addObject:self.remotePeer2]; - - self.untrustedPeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"untrusted-peer" - encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]] - signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]]; -} - -- (void)tearDown -{ - _remotePeer1 = nil; - _remotePeer2 = nil; - _untrustedPeer = nil; - [super tearDown]; -} - --(void) testTLKSharingWithRestoredBottledPeer -{ - NSError* error = nil; - - OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:self.recordName error:&error]; - XCTAssertNotNil(rec, @"rec should not be nil: %@", error); - XCTAssertNil(error, @"error should be nil: %@", error); - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:self.escrowKeys - error:&error]; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bps, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); - - - CKKSSelves* selves = [[CKKSViewManager manager] fetchSelfPeers:&error]; - XCTAssertNotNil(selves, @"selves should not be nil: %@", error); - - XCTAssertTrue([selves.allSelves count] == 2, @"should have 2 selves"); - NSArray *arrayOfSelves = [selves.allSelves allObjects]; - XCTAssertNotNil(arrayOfSelves, @"arrayOfSelves should not be nil: %@", error); - - CKKSSOSSelfPeer *ourRestoredPeer = [arrayOfSelves objectAtIndex:0]; - if([ourRestoredPeer.peerID isEqualToString:@"spid-local-peer"]){ - ourRestoredPeer = [arrayOfSelves objectAtIndex:1]; - } - - XCTAssertTrue([ourRestoredPeer.peerID containsString:self.sosPeerID], @"peer ids should match!"); - XCTAssertTrue([ourRestoredPeer.signingKey isEqual:self.peerSigningKey], @"signing keys should match"); - XCTAssertTrue([ourRestoredPeer.encryptionKey isEqual:self.peerEncryptionKey], @"encryption keys should match"); - - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - [self putFakeDeviceStatusInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - // The CKKS subsystem should not try to write anything to the CloudKit database, but it should enter waitfortlk - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "Key state should become waitfortlk"); - - // peer1 arrives to save the day - // The CKKS subsystem should accept the keys, and share the TLK back to itself - [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID]; - - [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:ourRestoredPeer zoneID:self.keychainZoneID]; - [self.keychainView notifyZoneChange:nil]; - [self.keychainView waitForFetchAndIncomingQueueProcessing]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready"); - - // We expect a single record to be uploaded for each key class - [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, 8); - - [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID - checkItem: [self checkClassABlock:self.keychainZoneID message:@"Object was encrypted under class A key in hierarchy"]]; - [self addGenericPassword:@"asdf" - account:@"account-class-A" - viewHint:nil - access:(id)kSecAttrAccessibleWhenUnlocked - expecting:errSecSuccess - message:@"Adding class A item"]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); -} - -- (nullable OTIdentity *)currentIdentity:(NSError * _Nullable __autoreleasing * _Nullable)error { - return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif diff --git a/keychain/ot/tests/OTBottledPeerTests.m b/keychain/ot/tests/OTBottledPeerTests.m deleted file mode 100644 index 20cdbe42..00000000 --- a/keychain/ot/tests/OTBottledPeerTests.m +++ /dev/null @@ -1,149 +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 OCTAGON - -#import -#import -#import -#import "OTTestsBase.h" -#import -#import -#import -#import -#import - -#import "keychain/ot/OTBottledPeer.h" -#import "keychain/ot/OTBottledPeerSigned.h" - -#import "keychain/ckks/CKKS.h" - -static NSString* const testDSID = @"123456789"; - -@interface UnitTestOTBottledPeer : OTTestsBase - -@end - -@implementation UnitTestOTBottledPeer - -- (void)setUp -{ - [super setUp]; - self.continueAfterFailure = NO; - NSError* error = nil; - - self.sosPeerID = @"spID"; - self.egoPeerID = @"egoPeerID"; - self.peerSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.peerEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void)testBottledPeerCreation -{ - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"bottled peer should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - -} - --(void)testSignedBottledPeerCreation -{ - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(bpSigned, @"bottled peer signed should not be nil"); - -} - --(void)testCreatingBottledPeerFromRecord -{ - NSError* error = nil; - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - OTBottledPeerRecord* record = [bpSigned asRecord:@"escrowRecordID"]; - OTBottledPeerSigned *bpRestored = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:record escrowKeys:self.escrowKeys error:&error]; - XCTAssertNotNil(bpRestored, @"bottled peer signed should not be nil"); -} - --(void)testRestoringBottledPeerSigned -{ - NSError* error = nil; - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - - SFECKeySpecifier *keySpecifier = [[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]; - id digestOperation = [[SFSHA384DigestOperation alloc] init]; - SFEC_X962SigningOperation* xso = [[SFEC_X962SigningOperation alloc] initWithKeySpecifier:keySpecifier digestOperation:digestOperation]; - - NSData* signatureUsingEscrow = [xso sign:bp.data withKey:self.escrowKeys.signingKey error:&error].signature; - XCTAssertNil(error, @"error should not be nil"); - - NSData* signatureUsingPeerKey = [xso sign:bp.data withKey:self.peerSigningKey error:&error].signature; - XCTAssertNil(error, @"error should not be nil"); - - XCTAssertNotNil(signatureUsingEscrow, @"signature using escrow signing key should not be nil"); - XCTAssertNotNil(signatureUsingPeerKey, @"signature using peer signing key should not be nil"); - - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp signatureUsingEscrow:signatureUsingEscrow signatureUsingPeerKey:signatureUsingPeerKey escrowedSigningPubKey:[self.escrowKeys.signingKey publicKey] error:&error]; - - XCTAssertNotNil(bpSigned, @"bottled peer signed should not be nil"); - - bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp signatureUsingEscrow:[NSData data] signatureUsingPeerKey:[NSData data] escrowedSigningPubKey:[self.escrowKeys.signingKey publicKey] error:&error]; - - XCTAssertNil(bpSigned, @"bottled peer signed should be nil"); - XCTAssertNotNil(error, @"error should not be nil"); - -} - -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m b/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m deleted file mode 100644 index bb762dc1..00000000 --- a/keychain/ot/tests/OTBottledPeerUpdateBottlesTests.m +++ /dev/null @@ -1,324 +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 OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" -#import "keychain/ot/OTConstants.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTUpdateBottlesTests : OTTestsBase - -@end - -@implementation OTUpdateBottlesTests - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. -} - -- (void)tearDown { - [super tearDown]; -} - --(void)testUpdatingExistingBottle -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottle SPI should fire"]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating identity SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result, "result should be YES"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void)testUpdatingNonExistentBottles -{ - self.spiBlockExpectation = [self expectationWithDescription:@"updating identity SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertFalse(result, "result should be NO"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void)testUpdatingBottleMissingKeys -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - NSError *localError = nil; - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottle SPI should fire"]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - //delete escrow keys - OTEscrowKeys* keySet = [[OTEscrowKeys alloc] initWithSecret:localEntropy dsid:testDSID error:&localError]; - XCTAssertNotNil(keySet, "keySet should not be nil"); - XCTAssertNil(localError, "localError should be nil"); - - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecReturnAttributes: @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - } mutableCopy]; - - OSStatus status = SecItemDelete((__bridge CFDictionaryRef)query); - XCTAssertEqual(status, 0, @"status should be 0"); - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating bottle SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertFalse(result, "result should be NO"); - XCTAssertNotNil(error, "error should not be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void)testUpdatingMultipleBottlesForSamePeer -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - __block NSData* localEntropy1 = nil; - __block NSString* localBottleID1 = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy1 = entropy; - localBottleID1 = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launching bottle SPI should fire"]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID1 reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - __block NSData* localEntropy2 = nil; - __block NSString* localBottleID2 = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight SPI should fire"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy2 = entropy; - localBottleID2 = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launching bottle SPI should fire"]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID2 reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForCKModifications]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - self.spiBlockExpectation = [self expectationWithDescription:@"updating bottle SPI should fire"]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result, "result should be YES"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); -} - - -@end - -#endif - diff --git a/keychain/ot/tests/OTCliqueTests.m b/keychain/ot/tests/OTCliqueTests.m deleted file mode 100644 index 69b7d9c7..00000000 --- a/keychain/ot/tests/OTCliqueTests.m +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2018 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -#import -#import "OTClique.h" -#import -#import - -@interface CliqueUnitTests : XCTestCase -@property (nonatomic, strong) OTClique* testClique; -@property (nonatomic, strong) OTConfigurationContext* testData; -@property (nonatomic, copy) NSString* testContextName; -@property (nonatomic, copy) NSString* testDSID; -@property (nonatomic, copy) NSString* testAltDSID; -@property (nonatomic, strong) SFSignInAnalytics *analytics; -@property (nonatomic, strong) XCTestExpectation *spiBlockExpectation; - -@end - -@implementation CliqueUnitTests - -- (void)setUp -{ - NSError *error = NULL; - - [super setUp]; - self.continueAfterFailure = NO; - _testDSID = @"123456789"; - _testContextName = @"contextName"; - _testAltDSID = @"testAltDSID"; - _testData = [[OTConfigurationContext alloc]init]; - _testData.context = _testContextName; - _testData.dsid = _testDSID; - _testData.altDSID = _testAltDSID; - _testData.analytics = _analytics; - - _analytics = [[SFSignInAnalytics alloc]initWithSignInUUID:[NSUUID UUID].UUIDString category:@"com.apple.cdp" eventName:@"signed in"]; - XCTAssertNotNil(_analytics, "sign in analytics object should not be nil"); - - _testClique = [[OTClique alloc]initWithContextData:_testData error:&error]; - XCTAssertNotNil(_testClique, "clique should not be nil: %@", error); -} - -- (void)tearDown -{ - _analytics = nil; - _testClique = nil; - - [super tearDown]; -} - - --(void) testCliqueStatus -{ - NSError *error = NULL; - CliqueStatus clique = [_testClique fetchCliqueStatus:&error]; - XCTAssertTrue(clique == CliqueStatusIn || clique == CliqueStatusError, "circle status should be in circle"); - XCTAssertTrue(error == nil || [error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be nil"); -} - --(void) testCachedCliqueStatus -{ - NSError *error = NULL; -#pragma clang push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CliqueStatus clique = [_testClique cachedCliqueStatus:YES error:&error]; -#pragma clang pop - XCTAssertTrue(clique == CliqueStatusIn || clique == CliqueStatusError, "circle status should be in circle"); - XCTAssertTrue(error == nil || [error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be nil"); -} - -- (void) testMakeNewFriends -{ - NSError *error = NULL; - OTConfigurationContext* newData = [[OTConfigurationContext alloc]init]; - newData.context = _testContextName; - newData.dsid = _testDSID; - newData.altDSID = _testAltDSID; - newData.analytics = _analytics; - - OTClique* clique = [OTClique newFriendsWithContextData:newData error:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertNil(clique, "clique should be nil"); - } - else{ - XCTAssertNotNil(clique, "new clique should be nil"); - XCTAssertNil(error, "error should be nil"); - } -} - -- (void) testRemoveFriendFromClique -{ - NSError *error = NULL; - CFErrorRef validPeerError = NULL; - CFArrayRef peerList = SOSCCCopyValidPeerPeerInfo(&validPeerError); - if(validPeerError){ - BOOL result = [_testClique removeFriendsInClique:@[@""] error:&error]; - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertFalse(result, "should have returned NO, attempting to remove friends when not valid in the circle"); - }else{ - BOOL result = [_testClique removeFriendsInClique:@[@""] error:&error]; - XCTAssertFalse(result, "should have returned NO, we passed an empty list"); - } - CFReleaseNull(peerList); -} - -- (void) testLeaveClique -{ - NSError *error = NULL; - BOOL result = [_testClique leaveClique:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:NSMachErrorDomain], "error should be kern return error"); - XCTAssertFalse(result, "result should be NO"); - }else{ - XCTAssertNil(error, "error should be nil"); - } -} - -- (void) testListFriendIDs -{ - NSError *error = NULL; - NSDictionary *friends = [_testClique peerDeviceNamesByPeerID:&error]; - if(error){ - XCTAssertEqual([friends count], 0, "friends should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(friends, "friends should not be nil"); - } -} - -- (void) testWaitForInitialSync -{ - NSError *error = NULL; - BOOL result = [_testClique waitForInitialSync:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "wait for initial sync should succeed"); - } -} - -- (void) testCopyViewUnawarePeerInfo -{ - NSError *error = NULL; - NSArray* result = [_testClique copyViewUnawarePeerInfo:&error]; - if(error){ - XCTAssertNil(result, "result should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(result, "copy view unaware peer info should return an array of peer infos"); - } -} - -- (void) testSetUserCredentialsAndDSID -{ - NSError *error = NULL; - - BOOL result = [_testClique setUserCredentialsAndDSID:[NSString string] password:[NSData data] error:&error]; - if(error) { - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] || [error.domain isEqualToString:@"SyncedDefaults"] , "error should be from sos or KVS"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -- (void) testTryUserCredentialsAndDSID -{ - NSError *error = NULL; - - BOOL result = [_testClique tryUserCredentialsAndDSID:[NSString string] password:[NSData data] error:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -- (void) testCopyPeerPeerInfo -{ - NSError *error = NULL; - - NSArray* result = [_testClique copyPeerPeerInfo:&error]; - if(error){ - XCTAssertNil(result, "result should be nil"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertNotNil(result, "result should not be nil"); - } -} - -- (void) testPeersHaveViewsEnabled -{ - NSError *error = NULL; - - BOOL result = [_testClique peersHaveViewsEnabled:[NSArray array] error:&error]; - if(error){ - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - } - XCTAssertFalse(result, "result should be NO"); -} -- (void) testRequestToJoinCircle -{ - NSError *error = NULL; - - BOOL result = [_testClique requestToJoinCircle:&error]; - if(error){ - XCTAssertFalse(result, "result should be NO"); - XCTAssertTrue([error.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain], "error should be from sos"); - }else{ - XCTAssertTrue(result, "result should be YES"); - } -} - -@end diff --git a/keychain/ot/tests/OTCloudStoreTests.m b/keychain/ot/tests/OTCloudStoreTests.m deleted file mode 100644 index 3b60a1b9..00000000 --- a/keychain/ot/tests/OTCloudStoreTests.m +++ /dev/null @@ -1,295 +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 OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; - -@interface OTCloudStoreUnitTests : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation OTCloudStoreUnitTests - - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; - self.fakeBottledPeerRecord = [[OTBottledPeerRecord alloc] init]; - self.fakeBottledPeerRecord.bottle = [@"bottled peer data" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.signatureUsingEscrowKey = [@"bottled peer escrow sig" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.signatureUsingPeerKey = [@"bottled peer peer sig" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.peerID = @"peer id"; - self.fakeBottledPeerRecord.spID = @"sos peer id"; - self.fakeBottledPeerRecord.escrowRecordID = @"escrowRecordID"; - self.fakeBottledPeerRecord.escrowedSigningSPKI = [@"escrowedSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - self.fakeBottledPeerRecord.peerSigningSPKI = [@"peerSigningSPKI" dataUsingEncoding:NSUTF8StringEncoding]; -} - -- (void)tearDown { - self.zones = nil; - self.operationQueue = nil; - - [super tearDown]; -} - -- (void)testWriteSameBottledPeerTwiceToFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; -} - -- (void)testWriteBottledPeerToFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; -} - -- (void)testWriteMultipleBottledPeersToSAMEFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error], @"should create bottled peer record"); - - [self waitForCKModifications]; - - XCTAssertNil(error, "error should be nil"); - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - } -} - -- (void)testWriteBottledPeersToDifferentFakeRecord { - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionary]; - - recordDictionary[OTCKRecordBottledPeerType] = [[NSNumber alloc] initWithInt:1]; - - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - NSString *escrowID = [NSString stringWithFormat:@"bp-sospeer%d-hash", i]; - self.fakeBottledPeerRecord.escrowRecordID = escrowID; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord escrowRecordID:escrowID error:&error], @"should create bottled peer record"); - [self waitForCKModifications]; - - XCTAssertNil(error, "error should be nil"); - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - } - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 10, @"should have 1 record"); -} - - -- (void)testReadBottledPeerRecordFromCloudKit { - NSError *error = nil; - [self startCKKSSubsystem]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self.otFakeZone addToZone:newRecord]; - - [self.cloudStore notifyZoneChange:nil]; - - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have 1 record"); -} - --(void) testOTCloudStoreDownloadBP{ - NSError* error = nil; - [self startCKKSSubsystem]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self.otFakeZone addToZone:newRecord]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); - XCTAssertNil(error, "error should be nil"); -} - --(void) testOTCloudStoreDownloadMultipleBP{ - NSError* error = nil; - [self startCKKSSubsystem]; - - for(int i = 0; i < 10; i++){ - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = [NSString stringWithFormat:@"escrowRecordID%d", i]; - [self.otFakeZone addToZone:newRecord]; - } - [self waitForCKModifications]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)10, @"should have 1 record"); -} - --(void) testOTCloudStoreUploadMultipleToSameRecord{ - NSError* error = nil; - [self startCKKSSubsystem]; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - for(int i = 0; i < 10; i++){ - [self.otFakeZone addToZone:newRecord]; - } - [self waitForCKModifications]; - - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - - XCTAssertNil(error, "error should be nil"); - XCTAssertEqual([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); -} - --(void) testRemoveRecordIDs{ - - [self startCKKSSubsystem]; - NSError *error = nil; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - [self expectCKFetch]; - - [self.otFakeZone addToZone:newRecord]; - [self waitForCKModifications]; - - [self.cloudStore notifyZoneChange:nil]; - [self waitForCKModifications]; - - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record"); - - [self expectCKFetch]; - XCTAssertTrue([self.cloudStore downloadBottledPeerRecord:&error] == YES, @"downloading records should succeed:%@", error); - XCTAssertNil(error, @"error should be nil"); - [self waitForCKModifications]; -} - --(void) testFetchTimeout -{ - [self startCKKSSubsystem]; - - NSError* error = nil; - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType zoneID:self.otZoneID]; - newRecord[OTCKRecordEscrowRecordID] = @"escrowRecordID"; - - [self holdCloudKitFetches]; - - [self.cloudStore downloadBottledPeerRecord:&error]; - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-fetch-and-process-changes)) timed out waiting to start for []"], "expecting timed out error"); -} - --(void) testModifyRecordsTimeout -{ - NSError* error = nil; - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready"); - - [self holdCloudKitModifications]; - - [self.cloudStore uploadBottledPeerRecord:self.fakeBottledPeerRecord - escrowRecordID:self.fakeBottledPeerRecord.escrowRecordID error:&error]; - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertTrue([(NSString*)error.userInfo[@"NSLocalizedDescription"] isEqualToString:@"Operation(CKKSResultOperation(cloudkit-modify-changes)) timed out waiting to start for []"], "expecting timed out error"); - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self releaseCloudKitModificationHold]; - [self waitForCKModifications]; -} - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTContextTests.m b/keychain/ot/tests/OTContextTests.m deleted file mode 100644 index b1b65f3c..00000000 --- a/keychain/ot/tests/OTContextTests.m +++ /dev/null @@ -1,240 +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 OCTAGON - -#import -#import -#import - -#import "OTTestsBase.h" - -static NSString* const testContextID = @"Foo"; -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface UnitTestOTContext : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation UnitTestOTContext - -- (void)setUp -{ - [super setUp]; - self.continueAfterFailure = NO; -} - -- (void)tearDown -{ - self.zones = nil; - self.operationQueue = nil; - [super tearDown]; -} - --(void) testEnroll -{ - NSError* error = nil; - - NSString* escrowRecordID = [self currentIdentity:&error].spID; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error); - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info:%@", error); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:escrowRecordID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - XCTAssertEqual( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count], (unsigned long)1, @"should have 1 record"); -} - --(void) testEnrollAndRestore -{ - NSError* error = nil; - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - - NSString* escrowRecordID = [self currentIdentity:&error].spID; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(escrowRecordID, @"escrowRecordID should not be nil: %@", error); - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - XCTAssertTrue([self.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:bprecord.escrowRecordID error:&error], @"should create bottled peer record"); - XCTAssertNil(error, "error should be nil"); - [self waitForCKModifications]; - - [self releaseCloudKitFetchHold]; - - OTBottledPeerSigned* bp = [self.context restoreFromEscrowRecordID:escrowRecordID secret:self.secret error:&error]; - [self waitForCKModifications]; - - XCTAssertTrue( [[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] == 1, @"should have 1 record"); - [self waitForCKModifications]; - - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bp, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bp.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bp.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); -} - --(void)testEnrollAndRestoreFromCloudKit -{ - NSError* error = nil; - [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - XCTAssertTrue([[self.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error] count] > 0, @"should have multiple records"); - OTIdentity *identity = [self currentIdentity:&error]; - - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(self.escrowKeys, @"escrow keys should not be nil: %@", error); - - NSString* recordName = [OTBottledPeerRecord constructRecordID:identity.spID escrowSigningSPKI:[self.escrowKeys.signingKey.publicKey encodeSubjectPublicKeyInfo]]; - - OTBottledPeerRecord *rec = [self.localStore readLocalBottledPeerRecordWithRecordID:recordName error:&error]; - - XCTAssertNotNil(rec.signatureUsingEscrowKey, @"signatureUsingEscrow should not be nil: %@", error); - - XCTAssertNotNil(rec.signatureUsingPeerKey, @"signatureUsingPeerKey should not be nil: %@", error); - - XCTAssertNotNil(rec.bottle, @"bottle should not be nil: %@", error); - - - OTBottledPeerSigned *bps = [[OTBottledPeerSigned alloc] initWithBottledPeerRecord:rec - escrowKeys:self.escrowKeys - error:&error]; - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(bps, @"signed bottled peer should not be nil: %@", error); - XCTAssertTrue([bps.bp.peerEncryptionKey isEqual:self.peerEncryptionKey], @"enrolled and restored peer encryption keys should match"); - XCTAssertTrue([bps.bp.peerSigningKey isEqual:self.peerSigningKey], @"enrolled and restored peer signing keys should match"); -} - --(void) testScrubbing -{ - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"escrowRecordID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - XCTAssertTrue([self.context scrubBottledPeer:testContextID bottleID:info.bottleID error:&error], @"scrubbing bottled peer should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - XCTAssertTrue([list count] == 0, @"there should be 0 records in localstore"); -} - --(void) testGettingListOfRecordIDS -{ - NSError* error = nil; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - [self expectAddedCKModifyRecords:recordDictionary holdFetch:YES]; - [self startCKKSSubsystem]; - - OTPreflightInfo* info = nil; - XCTAssertNotNil(info = [self.context preflightBottledPeer:testContextID entropy:self.secret error:&error], @"preflight sould return info"); - XCTAssertNil(error, @"error should be nil: %@", error); - XCTAssertNotNil(info, @"preflight info should not be nil: %@", error); - XCTAssertNotNil(info.bottleID, @"bottleID should not be nil: %@", error); - XCTAssertNotNil(info.escrowedSigningSPKI, @"signingPubKey should be nil: %@", error); - - OTBottledPeerRecord* bprecord = [self.localStore readLocalBottledPeerRecordWithRecordID:info.bottleID error:&error]; - XCTAssertNotNil(bprecord, @"bprecord should not be nil: %@", error); - - XCTAssertTrue([self.context.cloudStore uploadBottledPeerRecord:bprecord escrowRecordID:info.bottleID error:&error], @"launch should succeed"); - XCTAssertNil(error, @"error should be nil: %@", error); - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - NSArray* list = [self.context.cloudStore retrieveListOfEligibleEscrowRecordIDs:&error]; - XCTAssertNotNil(list, @"list should not be nil"); - XCTAssertTrue([list count] > 0, @"list of escrow record ids should not be empty"); -} - -- (nullable OTIdentity *)currentIdentity:(NSError**)error { - - return [[OTIdentity alloc]initWithPeerID:@"ego peer id" spID:@"sos peer id" peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif - diff --git a/keychain/ot/tests/OTCuttlefishContextTests.m b/keychain/ot/tests/OTCuttlefishContextTests.m deleted file mode 100644 index 5c31a4e6..00000000 --- a/keychain/ot/tests/OTCuttlefishContextTests.m +++ /dev/null @@ -1,103 +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 OCTAGON - -#import -#import -#import -#import -#import "OTTestsBase.h" -#import "OTSOSAdapter.h" - -@interface OTCuttlefishContextTests : OTTestsBase -@end - -@implementation OTCuttlefishContextTests - -- (void)setUp -{ - [super setUp]; -} - -- (void)tearDown -{ - [super tearDown]; -} - -- (void)testStateMachineInitialization { - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateMachineNotStarted] wait:10*NSEC_PER_SEC], "State machine should enter 'not started'"); - - [self.cuttlefishContext startOctagonStateMachine]; - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateInitializing] wait:10*NSEC_PER_SEC], "State machine should enter 'initializing'"); - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateUntrusted] wait:10*NSEC_PER_SEC], "State machine should enter 'signedout'"); -} - -- (void)testPrepare { - [self.cuttlefishContext startOctagonStateMachine]; - - XCTAssertEqual(0, [self.cuttlefishContext.stateConditions[OctagonStateUntrusted] wait:10*NSEC_PER_SEC], "State machine should enter 'signedout'"); - - XCTestExpectation* rpcCallbackOccurs = [self expectationWithDescription:@"rpcPrepare callback occurs"]; - [self.cuttlefishContext prepareForApplicant:0 reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - XCTAssertNil(error, "Should be no error calling 'prepare'"); - - XCTAssertNotNil(peerID, "Prepare should have returned a peerID"); - XCTAssertNotNil(permanentInfo, "Prepare should have returned a permanentInfo"); - XCTAssertNotNil(permanentInfoSig, "Prepare should have returned a permanentInfoSig"); - XCTAssertNotNil(stableInfo, "Prepare should have returned a stableInfo"); - XCTAssertNotNil(stableInfoSig, "Prepare should have returned a stableInfoSig"); - - [rpcCallbackOccurs fulfill]; - }]; - - [self waitForExpectations:@[rpcCallbackOccurs] timeout:10]; - -} - -- (void)testPrepareTimeoutIfStateMachineUnstarted { - - XCTestExpectation* rpcCallbackOccurs = [self expectationWithDescription:@"rpcPrepare callback occurs"]; - [self.cuttlefishContext prepareForApplicant:0 reply:^(NSString * _Nullable peerID, NSData * _Nullable permanentInfo, NSData * _Nullable permanentInfoSig, NSData * _Nullable stableInfo, NSData * _Nullable stableInfoSig, NSError * _Nullable error) { - XCTAssertNotNil(error, "Should be an error calling 'prepare'"); - XCTAssertEqualObjects(error.domain, CKKSResultErrorDomain, "Error domain should be CKKSResultErrorDomain"); - XCTAssertEqual(error.code, CKKSResultTimedOut, "Error result should be CKKSResultTimedOut"); - - - XCTAssertNil(peerID, "Prepare should not have returned a peerID"); - XCTAssertNil(permanentInfo, "Prepare should not have returned a permanentInfo"); - XCTAssertNil(permanentInfoSig, "Prepare should not have returned a permanentInfoSig"); - XCTAssertNil(stableInfo, "Prepare should not have returned a stableInfo"); - XCTAssertNil(stableInfoSig, "Prepare should not have returned a stableInfoSig"); - - [rpcCallbackOccurs fulfill]; - }]; - - [self waitForExpectations:@[rpcCallbackOccurs] timeout:10]; -} - -@end -#endif diff --git a/keychain/ot/tests/OTEscrowKeyTests.m b/keychain/ot/tests/OTEscrowKeyTests.m deleted file mode 100644 index 44cf9961..00000000 --- a/keychain/ot/tests/OTEscrowKeyTests.m +++ /dev/null @@ -1,192 +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 OCTAGON - -#import -#import -#import -#import "keychain/ot/OTEscrowKeys.h" -#import "keychain/ckks/CKKS.h" -#import "OTTestsBase.h" - -static NSString* const testDSID = @"123456789"; - -static const uint8_t signingKey_384[] = { - 0x04, 0xe4, 0x1b, 0x3e, 0x88, 0x81, 0x9f, 0x3b, 0x80, 0xd0, 0x28, 0x1c, - 0xd9, 0x07, 0xa0, 0x8c, 0xa1, 0x89, 0xa8, 0x3b, 0x69, 0x91, 0x17, 0xa7, - 0x1f, 0x00, 0x31, 0x91, 0x82, 0x89, 0x1f, 0x5c, 0x44, 0x2d, 0xd6, 0xa8, - 0x22, 0x1f, 0x22, 0x7d, 0x27, 0x21, 0xf2, 0xc9, 0x75, 0xf2, 0xda, 0x41, - 0x61, 0x55, 0x29, 0x11, 0xf7, 0x71, 0xcf, 0x66, 0x52, 0x2a, 0x27, 0xfe, - 0x77, 0x1e, 0xd4, 0x3d, 0xfb, 0xbc, 0x59, 0xe4, 0xed, 0xa4, 0x79, 0x2a, - 0x9b, 0x73, 0x3e, 0xf4, 0xf4, 0xe3, 0xaf, 0xf2, 0x8d, 0x34, 0x90, 0x92, - 0x47, 0x53, 0xd0, 0x34, 0x1e, 0x49, 0x87, 0xeb, 0x11, 0x89, 0x0f, 0x9c, - 0xa4, 0x99, 0xe8, 0x4f, 0x39, 0xbe, 0x21, 0x94, 0x88, 0xba, 0x4c, 0xa5, - 0x6a, 0x60, 0x1c, 0x2f, 0x77, 0x80, 0xd2, 0x73, 0x14, 0x33, 0x46, 0x5c, - 0xda, 0xee, 0x13, 0x8a, 0x3a, 0xdb, 0x4e, 0x05, 0x4d, 0x0f, 0x6d, 0x96, - 0xcd, 0x28, 0xab, 0x52, 0x4c, 0x12, 0x2b, 0x79, 0x80, 0xfe, 0x9a, 0xe4, - 0xf4 -}; - -static const uint8_t encryptionKey_384[] = { - 0x04, 0x99, 0xf9, 0x9a, 0x9b, 0x48, 0xe2, 0xf8, 0x69, 0xd3, 0xf9, 0x60, - 0xa0, 0xf4, 0x86, 0xda, 0xb3, 0x35, 0x3d, 0x97, 0x7d, 0xc3, 0xf4, 0x13, - 0x24, 0x78, 0x06, 0x10, 0xd5, 0x46, 0x55, 0x7a, 0x8a, 0x4d, 0x80, 0x0d, - 0x71, 0x19, 0x46, 0x4b, 0x15, 0x93, 0x36, 0xb0, 0xf4, 0x6e, 0x41, 0x30, - 0x09, 0x55, 0x25, 0x3b, 0x06, 0xdd, 0xf8, 0x85, 0xdc, 0xf2, 0x0b, 0xc7, - 0x33, 0x21, 0x99, 0x3c, 0x79, 0xa6, 0xb1, 0x0f, 0xf0, 0x55, 0xfa, 0xe8, - 0x6d, 0x3f, 0x0d, 0x57, 0x21, 0x08, 0xd2, 0x7e, 0x73, 0x4a, 0xe7, 0x4a, - 0xb3, 0xdf, 0xed, 0x86, 0x06, 0xa6, 0xf2, 0x03, 0xe6, 0x20, 0xd4, 0x82, - 0x39, 0x29, 0xcf, 0x6d, 0x76, 0x3e, 0x9a, 0xaa, 0x29, 0x4f, 0x33, 0x84, - 0x5a, 0x38, 0x50, 0x35, 0xca, 0x3f, 0x69, 0x92, 0xb1, 0xb3, 0x8b, 0x26, - 0x2b, 0xb5, 0xd6, 0x25, 0xcf, 0x2d, 0x18, 0xc4, 0x5e, 0x24, 0x34, 0xc5, - 0xcc, 0x83, 0x2f, 0xff, 0x08, 0x85, 0x0f, 0x89, 0xb5, 0xb1, 0xc1, 0x17, - 0x2a -}; - -static const uint8_t symmetricKey_384[] = { - 0x31, 0xf1, 0xe3, 0x7b, 0x76, 0x3f, 0x99, 0x65, 0x74, 0xab, 0xe8, 0x2b, - 0x8f, 0x06, 0x78, 0x57, 0x1b, 0xaa, 0x07, 0xb3, 0xab, 0x79, 0x81, 0xcb, - 0xc5, 0x89, 0x1e, 0x78, 0x28, 0x8d, 0x8e, 0x36 -}; - -@interface UnitTestEscrowKeys : OTTestsBase - -@end - -@implementation UnitTestEscrowKeys - -- (void)setUp -{ - [super setUp]; - NSError *error = nil; - - self.continueAfterFailure = NO; - NSString* secretString = @"I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - - self.secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; - - XCTAssertNil(error, @"error should be initialized"); - XCTAssertNotNil(self.escrowKeys, @"escrow keys should be initialized"); -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void) testEscrowKeyAllocations -{ - XCTAssertNotNil(self.escrowKeys.symmetricKey, @"escrowed symmetric key pair should not be nil"); - XCTAssertNotNil(self.escrowKeys.secret, @"escrowed secret should not be nil"); - XCTAssertNotNil(self.escrowKeys.dsid, @"account dsid should not be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"escrowed signing key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"escrowed encryption key should not be nil"); -} --(void) testEscrowKeyTestVectors -{ - NSError* error = nil; - - //test vectors - NSData* testv1 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:self.secret dsid:testDSID error:&error]; - NSData* signingFromBytes = [[NSData alloc] initWithBytes:signingKey_384 length:sizeof(signingKey_384)]; - XCTAssertTrue([testv1 isEqualToData:signingFromBytes], @"signing keys should match"); - - NSData* testv2 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:self.secret dsid:testDSID error:&error]; - NSData* encryptionFromBytes = [[NSData alloc] initWithBytes:encryptionKey_384 length:sizeof(encryptionKey_384)]; - XCTAssertTrue([testv2 isEqualToData:encryptionFromBytes], @"encryption keys should match"); - - NSData* testv3 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:self.secret dsid:testDSID error:&error]; - NSData* symmetricKeyFromBytes = [[NSData alloc]initWithBytes:symmetricKey_384 length:sizeof(symmetricKey_384)]; - XCTAssertTrue([testv3 isEqualToData:symmetricKeyFromBytes], @"symmetric keys should match"); - - NSString* newSecretString = @"I'm f secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - NSData* newSecret = [[NSData alloc]initWithBytes:[newSecretString UTF8String] length:[newSecretString length]]; - - NSData* testv4 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySigning masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv4 isEqualToData:signingFromBytes], @"signing keys should not match"); - - NSData* testv5 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeyEncryption masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv5 isEqualToData:encryptionFromBytes], @"encryption keys should not match"); - - NSData* testv6 = [OTEscrowKeys generateEscrowKey:kOTEscrowKeySymmetric masterSecret:newSecret dsid:testDSID error:&error]; - XCTAssertFalse([testv6 isEqualToData:symmetricKeyFromBytes], @"symmetric keys should not match"); -} - --(void) testEmptyArguments -{ - NSError* error = nil; - OTEscrowKeys* newSet = [[OTEscrowKeys alloc] initWithSecret:[NSData data] dsid:testDSID error:&error]; - XCTAssertNotNil(error, @"error should be initialized"); - XCTAssertNil(newSet, @"escrow keys should not be initialized"); - - newSet = [[OTEscrowKeys alloc] initWithSecret:self.secret dsid:[NSString string] error:&error]; - XCTAssertNotNil(error, @"error should be initialized"); - XCTAssertNil(newSet, @"escrow keys should not be initialized"); -} - --(void) testEscrowKeyLoadingAndStoringInKeychain -{ - NSError* error = nil; - NSString* secretString = @"secret"; - NSData* secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - - OTEscrowKeys* keys = [[OTEscrowKeys alloc] initWithSecret:secret dsid:@"dsid-123456789" error:&error]; - XCTAssertNotNil(keys, @"keys should not be nil"); - XCTAssertNil(error, "error should be nil"); - - NSString* label = [OTEscrowKeys hashEscrowedSigningPublicKey:[[keys.signingKey publicKey] encodeSubjectPublicKeyInfo]]; - NSMutableDictionary* query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecAttrLabel: label, - (id)kSecReturnAttributes: @YES, - (id)kSecReturnData : @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - (id)kSecMatchLimit : (id)kSecMatchLimitAll, - } mutableCopy]; - - CFTypeRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result); - XCTAssertNotNil((__bridge NSDictionary*)result, @"result not be nil"); - XCTAssertEqual(CFDictionaryGetCount(result), 3, @"should be 3 entries"); - - XCTAssertEqual(status, 0, @"status should be 0"); - - query = [@{ - (id)kSecClass : (id)kSecClassKey, - (id)kSecAttrAccessGroup : @"com.apple.security.ckks", - (id)kSecReturnAttributes: @YES, - (id)kSecAttrSynchronizable : (id)kCFBooleanFalse, - } mutableCopy]; - - status = SecItemDelete((__bridge CFDictionaryRef)query); - XCTAssertEqual(status, 0, @"status should be 0"); -} - - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTLocalStoreTests.m b/keychain/ot/tests/OTLocalStoreTests.m deleted file mode 100644 index 10adeedd..00000000 --- a/keychain/ot/tests/OTLocalStoreTests.m +++ /dev/null @@ -1,266 +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 OCTAGON - -#import "OTTestsBase.h" - -/* Octagon Trust Local Context Record Constants */ -static NSString* OTCKRecordContextID = @"contextID"; -static NSString* OTCKRecordDSID = @"accountDSID"; -static NSString* OTCKRecordContextName = @"contextName"; -static NSString* OTCKRecordZoneCreated = @"zoneCreated"; -static NSString* OTCKRecordSubscribedToChanges = @"subscribedToChanges"; -static NSString* OTCKRecordChangeToken = @"changeToken"; -static NSString* OTCKRecordEgoPeerID = @"egoPeerID"; -static NSString* OTCKRecordEgoPeerCreationDate = @"egoPeerCreationDate"; -static NSString* OTCKRecordRecoverySigningSPKI = @"recoverySigningSPKI"; -static NSString* OTCKRecordRecoveryEncryptionSPKI = @"recoveryEncryptionSPKI"; -static NSString* OTCKRecordBottledPeerTableEntry = @"bottledPeer"; - -/* Octagon Trust Local Peer Record */ -static NSString* OTCKRecordPeerID = @"peerID"; -static NSString* OTCKRecordPermanentInfo = @"permanentInfo"; -static NSString* OTCKRecordStableInfo = @"stableInfo"; -static NSString* OTCKRecordDynamicInfo = @"dynamicInfo"; -static NSString* OTCKRecordRecoveryVoucher = @"recoveryVoucher"; -static NSString* OTCKRecordIsEgoPeer = @"isEgoPeer"; - -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey"; -static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordBottle = @"bottle"; - -static NSString* const testDSID = @"123456789"; - -@interface UnitTestOTLocalStore : OTTestsBase -@end - -@implementation UnitTestOTLocalStore - -- (void)setUp -{ - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)tearDown -{ - [super tearDown]; -} - --(void)testDBConnection -{ - NSError* error = nil; - - XCTAssertTrue([self.localStore closeDBWithError:&error], @"failed attempt at closing the db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore openDBWithError:&error], @"could not open db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore closeDBWithError:&error], @"failed attempt at closing the db"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore openDBWithError:&error], @"could not open db"); - XCTAssertNil(error, @"error should be nil:%@", error); -} - --(void) testDBLocalContextRetrieval -{ - NSString* contextAndDSID = [NSString stringWithFormat:@"testContextRetreival-%@", testDSID]; - _SFECKeyPair *recoverySigningPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - _SFECKeyPair *recoveryEncryptionPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - NSError* error = nil; - NSDictionary *attributes = @{ - OTCKRecordContextID : @"testContextRetreival", - OTCKRecordDSID : testDSID, - OTCKRecordContextName : @"newFoo", - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], - OTCKRecordRecoveryEncryptionSPKI :[[recoveryEncryptionPublicKey publicKey] keyData]}; - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTContextRecord* record = [self.localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&error]; - XCTAssertNotNil(record, @"fetching attributes returned nil"); - XCTAssertNotNil(record.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(record.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(record.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(record.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(record.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(record.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(record.recoverySigningSPKI, @"fetching attributes returned nil"); - - XCTAssertNil(error, @"failed to read local context for test local store"); - - OTContextRecord* recordToTestEquality = [[OTContextRecord alloc]init]; - recordToTestEquality.contextName = @"newFoo"; - recordToTestEquality.contextID = @"testContextRetreival"; - recordToTestEquality.dsid = testDSID; - recordToTestEquality.contextName = @"newFoo"; - recordToTestEquality.egoPeerID = @"OctagonPeerID"; - recordToTestEquality.recoveryEncryptionSPKI = [[recoveryEncryptionPublicKey publicKey] keyData]; - recordToTestEquality.recoverySigningSPKI = [[recoverySigningPublicKey publicKey] keyData]; - - OTContextRecord* recordFromDB = [self.localStore readLocalContextRecordForContextIDAndDSID:contextAndDSID error:&error]; - XCTAssertTrue([recordFromDB isEqual:recordToTestEquality], @"OTContext should be equal"); -} - --(void) testDBMultipleContexts -{ - NSError* error = nil; - NSString* newFooContextAndDSID = [NSString stringWithFormat:@"newFoo-%@", testDSID]; - - _SFECKeyPair *recoverySigningPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - _SFECKeyPair *recoveryEncryptionPublicKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - NSDictionary *attributes = @{ - OTCKRecordContextID : @"newFoo", - OTCKRecordContextName : @"newFoo", - OTCKRecordDSID : testDSID, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], // FIXME not SPKI - OTCKRecordRecoveryEncryptionSPKI : [[recoveryEncryptionPublicKey publicKey] keyData]}; - - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - NSString* foo2ContextAndDSID = [NSString stringWithFormat:@"Foo2-%@", testDSID]; - attributes = @{ - OTCKRecordContextID : @"Foo2", - OTCKRecordContextName : @"Foo2", - OTCKRecordDSID : testDSID, - OTCKRecordZoneCreated : @(NO), - OTCKRecordSubscribedToChanges : @(NO), - OTCKRecordChangeToken : [NSData data], - OTCKRecordEgoPeerID : @"OctagonPeerID2", - OTCKRecordEgoPeerCreationDate : [NSDate date], - OTCKRecordRecoverySigningSPKI : [[recoverySigningPublicKey publicKey] keyData], // FIXME not SPKI - OTCKRecordRecoveryEncryptionSPKI :[[recoveryEncryptionPublicKey publicKey] keyData]}; - - XCTAssertTrue([self.localStore insertLocalContextRecord:attributes error:&error], @"inserting new context failed"); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTContextRecord* recordNewFoo = [self.localStore readLocalContextRecordForContextIDAndDSID:newFooContextAndDSID error:&error]; - - XCTAssertNotNil(recordNewFoo, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(recordNewFoo.recoverySigningSPKI, @"fetching attributes returned nil"); - - XCTAssertNil(error, @"failed to read local context for test local store"); - - OTContextRecord* recordFoo2 = [self.localStore readLocalContextRecordForContextIDAndDSID:foo2ContextAndDSID error:&error]; - - XCTAssertNotNil(recordFoo2, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.contextID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.contextName, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.dsid, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.egoPeerCreationDate, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.egoPeerID, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.recoveryEncryptionSPKI, @"fetching attributes returned nil"); - XCTAssertNotNil(recordFoo2.recoverySigningSPKI, @"fetching attributes returned nil"); - XCTAssertNil(error, @"failed to read local context for test local store"); - -} - --(void) testRowUpdates -{ - NSError* error = nil; - NSString* escrowRecordID = @"escrow record 1"; - NSString* escrowRecordID2 = @"escrow record 2"; - NSString* escrowRecordID3 = @"escrow record 3"; - - OTBottledPeerRecord* record = [[OTBottledPeerRecord alloc]init]; - OTBottledPeerRecord* record2 = [[OTBottledPeerRecord alloc]init]; - OTBottledPeerRecord* record3 = [[OTBottledPeerRecord alloc]init]; - - record.escrowRecordID = escrowRecordID; - record2.escrowRecordID = escrowRecordID2; - record3.escrowRecordID = escrowRecordID3; - - record.escrowedSigningSPKI = [@"escrowedSigingSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - record2.escrowedSigningSPKI = [@"escrowedSigingSPI" dataUsingEncoding:NSUTF8StringEncoding]; - record3.escrowedSigningSPKI = [@"escrowedSigingSPKI" dataUsingEncoding:NSUTF8StringEncoding]; - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record escrowRecordID:escrowRecordID error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record2 escrowRecordID:escrowRecordID2 error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore insertBottledPeerRecord:record3 escrowRecordID:escrowRecordID3 error:&error]); - XCTAssertNil(error, @"error should be nil:%@", error); - - - OTBottledPeerRecord *bp = [self.localStore readLocalBottledPeerRecordWithRecordID:record.recordName error:&error]; - XCTAssertNotNil(bp); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTBottledPeerRecord *bp2 = [self.localStore readLocalBottledPeerRecordWithRecordID:record2.recordName error:&error]; - XCTAssertNotNil(bp2); - XCTAssertNil(error, @"error should be nil:%@", error); - - OTBottledPeerRecord *bp3 = [self.localStore readLocalBottledPeerRecordWithRecordID:record3.recordName error:&error]; - XCTAssertNotNil(bp3); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordContextName newValue:(void*)@"SuperSuperFoo" error:&error], @"could not update column:%@ with value:%@", OTCKRecordContextName, @"SuperSuperFoo"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordEgoPeerID newValue:(void*)@"NewPeerID" error:&error], @"could not update column:%@ with value:%@", OTCKRecordEgoPeerID, @"NewPeerID"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertTrue([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:OTCKRecordRecoverySigningSPKI newValue:(void*)[[NSData alloc]initWithBase64EncodedString:@"I'm a string" options:NSDataBase64DecodingIgnoreUnknownCharacters] error:&error], @"could not update column:%@ with value:%@", OTCKRecordContextName, @"NewPeerID"); - XCTAssertNil(error, @"error should be nil:%@", error); - - XCTAssertFalse([self.localStore updateLocalContextRecordRowWithContextID:self.localStore.contextID columnName:@"ColumnName" newValue:(void*)@"value" error:&error], @"could not update column:%@ with value:%@", @"ColumnName", @"value"); - XCTAssertNotNil(error, @"error should not be nil: %@", error); -} - -@end - -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTLockStateNetworkingTests.m b/keychain/ot/tests/OTLockStateNetworkingTests.m deleted file mode 100644 index 5ddc0120..00000000 --- a/keychain/ot/tests/OTLockStateNetworkingTests.m +++ /dev/null @@ -1,675 +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 OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; -/* Octagon Trust BottledPeerSchema */ -static NSString* OTCKRecordEscrowRecordID = @"escrowRecordID"; -static NSString* OTCKRecordRecordID = @"bottledPeerRecordID"; -static NSString* OTCKRecordSPID = @"spID"; -static NSString* OTCKRecordEscrowSigningSPKI = @"escrowSigningSPKI"; -static NSString* OTCKRecordPeerSigningSPKI = @"peerSigningSPKI"; -static NSString* OTCKRecordEscrowSigningPubKey = @"escrowSigningPubKey"; -static NSString* OTCKRecordPeerSigningPubKey = @"peerSigningPubKey"; -static NSString* OTCKRecordSignatureFromEscrow = @"signatureUsingEscrow"; -static NSString* OTCKRecordSignatureFromPeerKey = @"signatureUsingPeerKey"; -static NSString* OTCKRecordBottle = @"bottle"; - -static NSString* OTCKRecordPeerID = @"peerID"; - -@interface OTLockStateNetworkingTests : OTTestsBase -@property (nonatomic, strong) OTBottledPeerRecord* fakeBottledPeerRecord; -@end - -@implementation OTLockStateNetworkingTests - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - NSError* error = nil; - - OTBottledPeer *bp = [[OTBottledPeer alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionKey:self.peerEncryptionKey escrowKeys:self.escrowKeys error:&error]; - - XCTAssertNotNil(bp, @"plaintext should not be nil"); - XCTAssertNil(error, @"error should be nil"); - XCTAssertNotNil(self.escrowKeys.signingKey, @"signing public key should not be nil"); - XCTAssertNotNil(self.escrowKeys.encryptionKey, @"encryption public key should not be nil"); - - OTBottledPeerSigned *bpSigned = [[OTBottledPeerSigned alloc]initWithBottledPeer:bp escrowedSigningKey:self.escrowKeys.signingKey peerSigningKey:self.peerSigningKey error:&error]; - - self.fakeBottledPeerRecord = [bpSigned asRecord:self.sosPeerID]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - -} - -- (void)tearDown { - - [super tearDown]; -} - -//Bottle Check tests - --(void) testGrabbingBottleLocallyCheckPerfectConditions -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"]; - - [self expectAddedCKModifyRecords:@{OTCKRecordBottledPeerType: @1} holdFetch:NO]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSError* localError = nil; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle"); - XCTAssertNil(localError, "error should be nil"); -} - --(void) testGrabbingBottleFromCloudKitCheckPerfectConditions -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - CKRecord* newRecord = [[CKRecord alloc]initWithRecordType:OTCKRecordBottledPeerType]; - newRecord[OTCKRecordPeerID] = self.fakeBottledPeerRecord.peerID; - newRecord[OTCKRecordSPID] = @"spID"; - newRecord[OTCKRecordEscrowSigningSPKI] = self.fakeBottledPeerRecord.escrowedSigningSPKI; - newRecord[OTCKRecordPeerSigningSPKI] = self.fakeBottledPeerRecord.peerSigningSPKI; - newRecord[OTCKRecordEscrowRecordID] = self.fakeBottledPeerRecord.escrowRecordID; - newRecord[OTCKRecordBottle] = self.fakeBottledPeerRecord.bottle; - newRecord[OTCKRecordSignatureFromEscrow] = self.fakeBottledPeerRecord.signatureUsingEscrowKey; - newRecord[OTCKRecordSignatureFromPeerKey] = self.fakeBottledPeerRecord.signatureUsingPeerKey; - - [self.otFakeZone addToZone:newRecord]; - - [self startCKKSSubsystem]; - - NSError* localError = nil; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&localError] == BOTTLE, @"should have a bottle"); - XCTAssertNil(localError, "error should be nil"); -} - --(void) testBottleCheckWhenLocked -{ - NSError* error = nil; - self.aksLockState = true; - [self.lockStateTracker recheck]; - [self setUpRampRecordsInCloudKitWithFeatureOff]; - - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - - XCTAssertNotNil(error, "error should not be nil"); - XCTAssertEqual(error.code, -25308, @"error should be interaction not allowed"); -} - --(void) testBottleCheckWithNoNetwork -{ - NSError* error = nil; - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned no network error"); -} - --(void) testBottleCheckWhenNotSignedIn -{ - NSError* error = nil; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - XCTAssertTrue([self.context doesThisDeviceHaveABottle:&error] == UNCLEAR, @"bottle check should return unclear"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); -} - -//Bottle Update tests --(void)testBottleUpdateNotSignedIn -{ - self.spiBlockExpectation = [self expectationWithDescription:@"handle identity change spis fired"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - [self.spiBlockExpectation fulfill]; - XCTAssertTrue(result == NO, @"should return NO"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testBottleUpdateWithNoNetwork -{ - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error"); - }]; -} - --(void) testBottleUpdateWhenLocked -{ - self.aksLockState = true; - [self.lockStateTracker recheck]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error"); - }]; -} - -//Preflight tests --(void)testPreflightNotSignedIn -{ - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, @"should have returned not signed in error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testPreflightWithNoNetwork -{ - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, @"should have returned OTErrorNoNetwork in error"); - }]; - -} - --(void) testPreflightWhenLocked -{ - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should not be nil"); - XCTAssertNil(bottleID, "bottle id should not be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, @"should have returned errSecInteractionNotAllowed in error"); - }]; -} - -//Launch Bottle tests --(void)testLaunchNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Scrub tests --(void)testScrubNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testScrubWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testScrubWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Restore tests --(void)testRestoreNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusNoAccount; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - -} - --(void) testRestoreWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.accountStatus = CKAccountStatusAvailable; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testRestoreWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); - }]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - -//Generic Ramp tests --(void)testEnrollRampNotSignedIn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.accountStatus = CKAccountStatusNoAccount; - [self startCKKSSubsystem]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, OTErrorNotSignedIn, "should return a OTErrorNotSignedIn error"); - -} - --(void) testEnrollRampWithNoNetwork -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.accountStatus = CKAccountStatusAvailable; - [self startCKKSSubsystem]; - - [self.reachabilityTracker setNetworkReachability:false]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, OTErrorNoNetwork, "should return a OTErrorNoNetwork error"); -} - --(void) testEnrollRampWhenLocked -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - NSInteger retryAfter = 0; - - self.aksLockState = true; - [self.lockStateTracker recheck]; - - [self.enroll checkRampState:&retryAfter networkBehavior:CKOperationDiscretionaryNetworkBehaviorNonDiscretionary error:&error]; - - XCTAssertEqual(error.code, errSecInteractionNotAllowed, "should return a errSecInteractionNotAllowed error"); -} - --(void) testTimeBetweenCFUAttempts -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - NSError* error = nil; - - [self startCKKSSubsystem]; - - [self.manager scheduledCloudKitRampCheck:&error]; - XCTAssertNotNil(error, "Should have had an error scheduling a ramp check"); - XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'"); - XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted"); - NSDate* firstTime = self.manager.lastPostedCoreFollowUp; - - sleep(2); - error = nil; - - [self.manager scheduledCloudKitRampCheck:&error]; - XCTAssertNotNil(error, "Should have had an error scheduling a ramp check"); - XCTAssertEqual(error.code, OTErrorNoBottlePeerRecords, "Error should be 'no bottled peer records'"); - XCTAssertNotNil(self.manager.lastPostedCoreFollowUp, "core followup should have been posted"); - NSDate* secondTime = self.manager.lastPostedCoreFollowUp; - - XCTAssertTrue([secondTime timeIntervalSinceDate:firstTime] >= 2, "time difference should be slightly more than 2 seconds"); -} - -@end -#endif diff --git a/keychain/ot/tests/OTRampingTests.m b/keychain/ot/tests/OTRampingTests.m deleted file mode 100644 index 63e76f81..00000000 --- a/keychain/ot/tests/OTRampingTests.m +++ /dev/null @@ -1,474 +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 OCTAGON - -#import - -#import -#import - -#import "OTTestsBase.h" -#import "keychain/ot/OTConstants.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testDSID = @"123456789"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@interface OTRampingUnitTests : OTTestsBase - -@end - -@implementation OTRampingUnitTests - -- (void)setUp { - [super setUp]; - self.continueAfterFailure = NO; -} - -- (void)tearDown { - [super tearDown]; -} - --(void) testPreflightWithFeatureOnOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - -} - --(void) testBottleUpdateWithFeatureOnOn -{ - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - - [self startCKKSSubsystem]; - - //create a bottle - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - //launch it - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self releaseCloudKitFetchHold]; - - [self expectCKFetch]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertNil(error, "error should be nil"); - }]; -} - --(void) testLaunchWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"launch bottled peer fired"]; - - NSMutableDictionary* recordDictionary = [NSMutableDictionary dictionaryWithObjectsAndKeys:[[NSNumber alloc] initWithInt:1], OTCKRecordBottledPeerType, nil]; - - [self expectAddedCKModifyRecords:recordDictionary holdFetch:NO]; - - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testRestoreWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSData* localEntropy = nil; - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localEntropy = entropy; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSData* localSigningKeyData = nil; - __block NSData* localEncryptionKeyData = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:localEntropy - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - localSigningKeyData = signingKeyData; - localEncryptionKeyData = encryptionKeyData; - XCTAssertNotNil(signingKeyData, "Signing key data should not be nil"); - XCTAssertNotNil(encryptionKeyData, "encryption key data should not be nil"); - XCTAssertNil(error, "error should not be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - NSError* localError = nil; - - OTIdentity *ourSelf = [self currentIdentity:&localError]; - XCTAssertTrue([localSigningKeyData isEqualToData:[ourSelf.peerSigningKey.publicKey keyData]], @"signing keys should be equal!"); - XCTAssertTrue([localEncryptionKeyData isEqualToData:[ourSelf.peerEncryptionKey.publicKey keyData]], @"signing keys should be equal!"); -} - --(void) testScrubWithRampOn -{ - [self setUpRampRecordsInCloudKitWithFeatureOn]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSString* localBottleID = nil; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - localBottleID = bottleID; - XCTAssertNotNil(entropy, "entropy should not be nil"); - XCTAssertNotNil(bottleID, "bottle id should not be nil"); - XCTAssertNotNil(signingPublicKey, "signing pub key should not be nil"); - XCTAssertNil(error, "error should be nil"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - self.spiBlockExpectation = [self expectationWithDescription:@"scrub scheduler fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(error, "error should be nil"); - }]; - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - NSError* localError = nil; - NSArray* bottles = [self.localStore readAllLocalBottledPeerRecords:&localError]; - XCTAssertNotNil(localError, "error should not be nil"); - XCTAssertTrue([bottles count] == 0, "should be 0 bottles"); -} - --(void) testPreflightWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testBottleUpdateWithFeatureOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - SFECKeyPair* newSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - SFECKeyPair* newEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - - //update bottle - [self.otControl handleIdentityChangeForSigningKey:newSigningKey - ForEncryptionKey:newEncryptionKey - ForPeerID:self.sosPeerID - reply:^(BOOL result, NSError* _Nullable error){ - XCTAssertNotNil(error, "error should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - -} - --(void) testPreflightWithRecordNotThere -{ - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertNotNil(error, "should not be nil"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testLaunchWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer fired"]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - - self.spiBlockExpectation = [self expectationWithDescription:@"launch SPI fired"]; - - NSString* localBottleID = @"random bottle id"; - [self.otControl launchBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} --(void) testRestoreWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"restore SPI fired"]; - - [self.otControl restore:testContextID - dsid:testDSID - secret:self.secret - escrowRecordID:self.sosPeerID - reply:^(NSData* signingKeyData, NSData* encryptionKeyData, NSError* _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(signingKeyData, "Signing key data should be nil"); - XCTAssertNil(encryptionKeyData, "encryption key data should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; -} - --(void) testScrubWithRampOff -{ - [self setUpRampRecordsInCloudKitWithFeatureOff]; - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - self.spiBlockExpectation = [self expectationWithDescription:@"preflight bottled peer SPI fired"]; - - [self.otControl preflightBottledPeer:testContextID - dsid:testDSID - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertNil(entropy, "entropy should be nil"); - XCTAssertNil(bottleID, "bottle id should be nil"); - XCTAssertNil(signingPublicKey, "signing pub key should be nil"); - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - __block NSString* localBottleID = @"random bottle id"; - self.spiBlockExpectation = [self expectationWithDescription:@"scrub bottled peer SPI fired"]; - - [self.otControl scrubBottledPeer:testContextID bottleID:localBottleID reply:^(NSError * _Nullable error) { - [self.spiBlockExpectation fulfill]; - XCTAssertEqual(error.code, OTErrorFeatureNotEnabled, "should return a OTErrorFeatureNotEnabled error"); - }]; - - [self waitForCKModifications]; - OCMVerifyAllWithDelay(self.mockDatabase, 8); - [self waitForExpectationsWithTimeout:1.0 handler:nil]; - - [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test. - [self startCKKSSubsystem]; - - XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:4*NSEC_PER_SEC], @"Key state should have arrived at ready"); -} - --(void) testRampFetchTimeout -{ - [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; - [self putSelfTLKSharesInCloudKit:self.keychainZoneID]; - [self startCKKSSubsystem]; - - __block NSError* localError = nil; - - [self holdCloudKitFetches]; - - [self.otControl preflightBottledPeer:OTDefaultContext - dsid:@"dsid" - reply:^(NSData * _Nullable entropy, NSString * _Nullable bottleID, NSData * _Nullable signingPublicKey, NSError * _Nullable error) { - localError = error; - XCTAssertNil(entropy, "shouldn't return any entropy"); - XCTAssertNil(bottleID, "shouldn't return a bottle ID"); - XCTAssertNil(signingPublicKey, "shouldn't return a signingPublicKey"); - XCTAssertEqual(error.code, OTErrorCKTimeOut, "should return a OTErrorCKTimeout error"); - }]; -} - --(void)testCFUWithRampOn -{ - NSError* localError = nil; - - [self setUpRampRecordsInCloudKitWithFeatureOn]; - - [self startCKKSSubsystem]; - - XCTAssertTrue([self.cfu checkRampStateWithError:&localError], @"should be true"); - XCTAssertNil(localError, "Should not have gotten an error checking ramp state (and getting true)"); -} - --(void)testCFUWithRampOff -{ - NSError* localError = nil; - [self setUpRampRecordsInCloudKitWithFeatureOff]; - - [self startCKKSSubsystem]; - - XCTAssertFalse([self.cfu checkRampStateWithError:&localError], @"should be false"); - XCTAssertNil(localError, "Should not have gotten an error checking ramp state (and getting false)"); -} - --(void)testCFUWithNonExistentRampRecord -{ - NSError* localError = nil; - - [self startCKKSSubsystem]; - - XCTAssertFalse([self.cfu checkRampStateWithError:&localError], @"should be false"); - XCTAssertNotNil(localError, "Should have gotten an error checking ramp state (and getting false)"); - XCTAssertEqual(localError.code, OTErrorRecordNotFound, "Error should be 'record not found'"); -} - -@end - -#endif /* OCTAGON */ - diff --git a/keychain/ot/tests/OTTestsBase.h b/keychain/ot/tests/OTTestsBase.h deleted file mode 100644 index 6c5a3e0c..00000000 --- a/keychain/ot/tests/OTTestsBase.h +++ /dev/null @@ -1,117 +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 OCTAGON - -#ifndef OTTestsBase_h -#define OTTestsBase_h - -#import -#import -#import -#import "keychain/ot/OTContext.h" -#import "keychain/ot/OTJoiningConfiguration.h" -#import "keychain/ot/OTEscrowKeys.h" -#import "keychain/ot/OTDefines.h" -#import "keychain/ot/OTControl.h" -#import "keychain/ot/OTManager.h" -#import "keychain/ot/OTClique.h" -#import "keychain/ot/OTCuttlefishContext.h" -#import "keychain/ot/OTClientStateMachine.h" -#import "KeychainCircle/KCJoiningRequestSession+Internal.h" -#import "KeychainCircle/KCJoiningAcceptSession+Internal.h" -#import "KeychainCircle/KCJoiningSession.h" - -#import -#import -#import -#import -#include "keychain/SecureObjectSync/SOSPeerInfoInternal.h" - -#import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" -#import "keychain/ckks/tests/CloudKitMockXCTest.h" -#import "keychain/ckks/tests/MockCloudKit.h" -#import "keychain/ckks/tests/CKKSTests.h" -#import "keychain/ckks/CKKS.h" -#import "keychain/ckks/CKKSViewManager.h" - -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface OTTestsBase : CloudKitKeychainSyncingTestsBase -@property id otControl; -@property id otControlAcceptor; - - -@property OTManager* manager; -@property OTManager* managerForAcceptor; - -@property (nonatomic, strong) OTCloudStore* cloudStore; -@property (nonatomic, strong) OTLocalStore* localStore; -@property (nonatomic, strong) FakeCKZone* otFakeZone; -@property (nonatomic, strong) CKRecordZoneID* otZoneID; -@property (nonatomic, strong) OTContext* context; -@property (nonatomic, strong) _SFECKeyPair* peerSigningKey; -@property (nonatomic, strong) _SFECKeyPair* peerEncryptionKey; -@property (nonatomic, strong) NSData* secret; -@property (nonatomic, strong) NSString* recordName; -@property (nonatomic, strong) NSString* egoPeerID; -@property (nonatomic, strong) NSString* sosPeerID; -@property (nonatomic, strong) OTEscrowKeys* escrowKeys; - -// Manager-owned cuttlefish context -@property OTCuttlefishContext* cuttlefishContext; - -@property (nonatomic, strong) FakeCKZone* rampZone; -@property (nonatomic, strong) CKRecord *enrollRampRecord; -@property (nonatomic, strong) CKRecord *restoreRampRecord; -@property (nonatomic, strong) CKRecord *cfuRampRecord; - -@property (nonatomic, strong) OTRamp *enroll; -@property (nonatomic, strong) OTRamp *restore; -@property (nonatomic, strong) OTRamp *cfu; -@property (nonatomic, strong) CKKSNearFutureScheduler* scheduler; -@property (nonatomic, strong) XCTestExpectation *expectation; -@property (nonatomic, strong) XCTestExpectation *spiBlockExpectation; - -@property (nonatomic, strong) CKRecordZoneID* rampZoneID; - -- (OTRamp*)fakeRamp:(NSString*)recordName - featureName:(NSString*)featureName - accountTracker:(CKKSAccountStateTracker*)accountTracker - lockStateStracker:(CKKSLockStateTracker*)lockStateTracker -reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker; - --(void) expectAddedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch; --(void) expectDeletedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch; --(void) setUpRampRecordsInCloudKitWithFeatureOn; --(void) setUpRampRecordsInCloudKitWithFeatureOff; - -@end -NS_ASSUME_NONNULL_END - -#endif /* OTTestsBase_h */ -#endif /* OCTAGON */ diff --git a/keychain/ot/tests/OTTestsBase.m b/keychain/ot/tests/OTTestsBase.m deleted file mode 100644 index 6c85dbf7..00000000 --- a/keychain/ot/tests/OTTestsBase.m +++ /dev/null @@ -1,326 +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 OCTAGON - -#import "OTTestsBase.h" -#import "keychain/ot/OTSOSAdapter.h" - -static NSString* const testContextID = @"Foo"; -static NSString* const testContextForAcceptor = @"Acceptor"; - -static NSString* const testDSID = @"123456789"; - -static int _test_num = 0; -static NSString* _path; -static NSString* _dbPath; - -static NSString* OTCKZoneName = @"OctagonTrust"; - -static NSString* const kOTRampZoneName = @"metadata_zone"; -static NSString* const kOTRampForEnrollmentRecordName = @"metadata_rampstate_enroll"; -static NSString* const kOTRampForRestoreRecordName = @"metadata_rampstate_restore"; -static NSString* const kOTRampForCFURecordName = @"metadata_rampstate_cfu"; - -static NSString* kFeatureAllowedKey = @"FeatureAllowed"; -static NSString* kFeaturePromotedKey = @"FeaturePromoted"; -static NSString* kFeatureVisibleKey = @"FeatureVisible"; -static NSString* kRetryAfterKey = @"RetryAfter"; -static NSString* kRampPriorityKey = @"RampPriority"; - -static NSString* OTCKRecordBottledPeerType = @"OTBottledPeer"; - -@implementation OTTestsBase - -// Override our base class --(NSSet*)managedViewList { - return [NSSet setWithObject:@"keychain"]; -} - -+ (void)setUp { - SecCKKSEnable(); - SecCKKSResetSyncing(); - [super setUp]; -} - -- (void)setUp -{ - [super setUp]; - - self.continueAfterFailure = NO; - NSError* error = nil; - - _path = @"/tmp/ottrusttests"; - _dbPath = [_path stringByAppendingFormat:@"/ottest.db.%d",_test_num++]; - - XCTAssertTrue([[NSFileManager defaultManager] createDirectoryAtPath:_path withIntermediateDirectories:YES attributes:nil error:nil], @"directory created!"); - self.localStore = [[OTLocalStore alloc]initWithContextID:testContextID dsid:testDSID path:_dbPath error:&error]; - XCTAssertNil(error, "error should be nil"); - - self.cloudStore = [[OTCloudStore alloc] initWithContainer:self.mockContainer - zoneName:OTCKZoneName - accountTracker:self.mockAccountStateTracker - reachabilityTracker:self.mockReachabilityTracker - localStore:self.localStore - contextID:testContextID - dsid:testDSID - fetchRecordZoneChangesOperationClass:self.mockFakeCKFetchRecordZoneChangesOperation - fetchRecordsOperationClass:self.mockFakeCKFetchRecordZoneChangesOperation - queryOperationClass:self.mockFakeCKQueryOperation - modifySubscriptionsOperationClass:self.mockFakeCKModifySubscriptionsOperation - modifyRecordZonesOperationClass:self.mockFakeCKFetchRecordsOperation - apsConnectionClass:self.mockFakeCKModifySubscriptionsOperation - operationQueue:nil]; - - NSString* secretString = @"I'm a secretI'm a secretI'm a secretI'm a secretI'm a secretI'm a secret"; - self.secret = [[NSData alloc]initWithBytes:[secretString UTF8String] length:[secretString length]]; - - self.context = [[OTContext alloc]initWithContextID:testContextID dsid:testDSID localStore:self.localStore cloudStore:self.cloudStore identityProvider:self error:&error]; - XCTAssertNil(error, "error should be nil"); - - self.sosPeerID = @"spID"; - self.egoPeerID = @"egoPeerID"; - self.peerSigningKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.peerEncryptionKey = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]; - self.escrowKeys = [[OTEscrowKeys alloc]initWithSecret:self.secret dsid:testDSID error:&error]; - - XCTAssertNotNil(self.context, @"context not initialized"); - - self.otZoneID = [[CKRecordZoneID alloc] initWithZoneName:OTCKZoneName ownerName:CKCurrentUserDefaultName]; - - XCTAssertNotNil(self.otZoneID, @"cloudkit record zone id is not initialized"); - - self.otFakeZone = [[FakeCKZone alloc] initZone: self.otZoneID]; - XCTAssertNotNil(self.otFakeZone, @"fake ot zone is not initialized"); - - self.zones[self.otZoneID] = self.otFakeZone; - XCTAssertNotNil(self.zones, @"ot zones set is not initialized"); - - self.rampZoneID = [[CKRecordZoneID alloc] initWithZoneName:kOTRampZoneName ownerName:CKCurrentUserDefaultName]; - self.rampZone = [[FakeCKZone alloc]initZone:self.rampZoneID]; - self.zones[self.rampZoneID] = self.rampZone; - - self.cfu = [self fakeRamp:kOTRampForCFURecordName - featureName:@"FAKE-cfu" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - self.enroll = [self fakeRamp:kOTRampForEnrollmentRecordName - featureName:@"FAKE-enroll" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - self.restore = [self fakeRamp:kOTRampForRestoreRecordName - featureName:@"FAKE-restore" - accountTracker:self.accountStateTracker - lockStateStracker:self.lockStateTracker - reachabilityTracker:self.reachabilityTracker]; - - self.scheduler = [[CKKSNearFutureScheduler alloc] initWithName: @"test" delay:50*NSEC_PER_MSEC keepProcessAlive:true - dependencyDescriptionCode:CKKSResultDescriptionNone - block:^{ - [self.expectation fulfill]; - }]; - self.manager = [[OTManager alloc] initWithContext:self.context - localStore:self.localStore - enroll:self.enroll - restore:self.restore - cfu:self.cfu - cfuScheduler:self.scheduler - sosAdapter:[[OTSOSActualAdapter alloc] init] - authKitAdapter:[[OTAuthKitActualAdapter alloc] init] - apsConnectionClass:[FakeAPSConnection class]]; - [OTManager resetManager:true to:self.manager]; - - self.cuttlefishContext = [self.manager contextForContainerName:OTCKContainerName - contextID:OTDefaultContext]; - - id mockConnection = OCMPartialMock([[NSXPCConnection alloc] init]); - OCMStub([mockConnection remoteObjectProxyWithErrorHandler:[OCMArg any]]).andCall(self, @selector(manager)); - self.otControl = [[OTControl alloc] initWithConnection:mockConnection sync:true]; - XCTAssertNotNil(self.otControl, "Should have received control object"); - - [self.reachabilityTracker setNetworkReachability:true]; - [self.context.reachabilityTracker recheck]; - [self.cfu.reachabilityTracker recheck]; - [self.enroll.reachabilityTracker recheck]; - [self.restore.reachabilityTracker recheck]; -} - - -- (void)tearDown -{ - NSError *error = nil; - - [_localStore removeAllBottledPeerRecords:&error]; - [_localStore deleteAllContexts:&error]; - - _context = nil; - _cloudStore = nil; - _localStore = nil; - _escrowKeys = nil; - _peerSigningKey = nil; - _peerEncryptionKey = nil; - _otFakeZone = nil; - _otZoneID = nil; - - _rampZone = nil; - _rampZoneID = nil; - _cfuRampRecord = nil; - _enrollRampRecord = nil; - _restoreRampRecord = nil; - _scheduler = nil; - - [super tearDown]; -} - -- (OTRamp*)fakeRamp:(NSString*)recordName - featureName:(NSString*)featureName - accountTracker:(CKKSAccountStateTracker*)accountTracker - lockStateStracker:(CKKSLockStateTracker*)lockStateTracker -reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker -{ - - OTRamp* ramp = [[OTRamp alloc]initWithRecordName:recordName - featureName:featureName - container:self.mockContainer - database:self.mockDatabase - zoneID:self.rampZoneID - accountTracker:accountTracker - lockStateTracker:lockStateTracker - reachabilityTracker:reachabilityTracker - fetchRecordRecordsOperationClass:self.mockFakeCKFetchRecordsOperation]; - - return ramp; -} - --(void) setUpRampRecordsInCloudKitWithFeatureOff -{ - CKRecordID* enrollRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForEnrollmentRecordName zoneID:self.rampZoneID]; - self.enrollRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:enrollRecordID]; - self.enrollRampRecord[kFeatureAllowedKey] = @NO; - self.enrollRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.enrollRampRecord[kFeatureVisibleKey] = @NO; - self.enrollRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* restoreRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForRestoreRecordName zoneID:self.rampZoneID]; - self.restoreRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:restoreRecordID]; - self.restoreRampRecord[kFeatureAllowedKey] = @NO; - self.restoreRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.restoreRampRecord[kFeatureVisibleKey] = @NO; - self.restoreRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* cfuRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForCFURecordName zoneID:self.rampZoneID]; - self.cfuRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForCFURecordName recordID:cfuRecordID]; - self.cfuRampRecord[kFeatureAllowedKey] = @NO; - self.cfuRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.cfuRampRecord[kFeatureVisibleKey] = @NO; - self.cfuRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - [self.rampZone addToZone:self.enrollRampRecord]; - [self.rampZone addToZone:self.restoreRampRecord]; - [self.rampZone addToZone:self.cfuRampRecord]; -} - --(void) setUpRampRecordsInCloudKitWithFeatureOn -{ - CKRecordID* enrollRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForEnrollmentRecordName zoneID:self.rampZoneID]; - self.enrollRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:enrollRecordID]; - self.enrollRampRecord[kFeatureAllowedKey] = @YES; - self.enrollRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.enrollRampRecord[kFeatureVisibleKey] = @YES; - self.enrollRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* restoreRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForRestoreRecordName zoneID:self.rampZoneID]; - self.restoreRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForEnrollmentRecordName recordID:restoreRecordID]; - self.restoreRampRecord[kFeatureAllowedKey] = @YES; - self.restoreRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.restoreRampRecord[kFeatureVisibleKey] = @YES; - self.restoreRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - CKRecordID* cfuRecordID = [[CKRecordID alloc] initWithRecordName:kOTRampForCFURecordName zoneID:self.rampZoneID]; - self.cfuRampRecord = [[CKRecord alloc] initWithRecordType:kOTRampForCFURecordName recordID:cfuRecordID]; - self.cfuRampRecord[kFeatureAllowedKey] = @YES; - self.cfuRampRecord[kFeaturePromotedKey] = @NO; //always false right now - self.cfuRampRecord[kFeatureVisibleKey] = @YES; - self.cfuRampRecord[kRetryAfterKey] = [[NSNumber alloc]initWithInt:3600]; - - [self.rampZone addToZone:self.enrollRampRecord]; - [self.rampZone addToZone:self.restoreRampRecord]; - [self.rampZone addToZone:self.cfuRampRecord]; -} - - --(void)expectAddedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch -{ - __weak __typeof(self) weakSelf = self; - - [self expectCKModifyRecords:records - deletedRecordTypeCounts:nil - zoneID:self.otZoneID - checkModifiedRecord:^BOOL (CKRecord* record){ - if([record.recordType isEqualToString: OTCKRecordBottledPeerType]) { - return YES; - } else { //not a Bottled Peer Record Type - return NO; - } - } - runAfterModification:^{ - __strong __typeof(self) strongSelf = weakSelf; - if(shouldHoldTheFetch){ - [strongSelf holdCloudKitFetches]; - } - - } - ]; -} - --(void)expectDeletedCKModifyRecords:(NSDictionary*)records holdFetch:(BOOL)shouldHoldTheFetch -{ - __weak __typeof(self) weakSelf = self; - - [self expectCKModifyRecords:[NSMutableDictionary dictionary] - deletedRecordTypeCounts:records - zoneID:self.otZoneID - checkModifiedRecord:^BOOL (CKRecord* record){ - if([record.recordType isEqualToString: OTCKRecordBottledPeerType]) { - return YES; - } else { //not a Bottled Peer Record Type - return NO; - } - } - runAfterModification:^{ - __strong __typeof(self) strongSelf = weakSelf; - if(shouldHoldTheFetch){ - [strongSelf holdCloudKitFetches]; - } - } - ]; -} - -- (nullable OTIdentity *)currentIdentity:(NSError * _Nullable __autoreleasing * _Nullable)error { - return [[OTIdentity alloc]initWithPeerID:self.egoPeerID spID:self.sosPeerID peerSigningKey:self.peerSigningKey peerEncryptionkey:self.peerEncryptionKey error:error]; -} - -@end -#endif diff --git a/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift b/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift index ed7f96f1..0b457d23 100644 --- a/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift +++ b/keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift @@ -160,7 +160,7 @@ class OctagonAccountMetadataClassCPersistenceTests: CloudKitKeychainSyncingMockX state.trustState = .TRUSTED XCTAssertNoThrow(try state.saveToKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext), "saving to the keychain should work") - let deleted:Bool = try OTAccountMetadataClassC.deleteFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext) + let deleted: Bool = try OTAccountMetadataClassC.deleteFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext) XCTAssertTrue(deleted, "deleteFromKeychain should return true") XCTAssertThrowsError(try OTAccountMetadataClassC.loadFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext)) } diff --git a/keychain/ot/tests/octagon/OctagonTestMocks.swift b/keychain/ot/tests/octagon/OctagonTestMocks.swift index 61050145..a9d31759 100644 --- a/keychain/ot/tests/octagon/OctagonTestMocks.swift +++ b/keychain/ot/tests/octagon/OctagonTestMocks.swift @@ -2,29 +2,45 @@ import Foundation class OTMockSecureBackup: NSObject, OctagonEscrowRecovererPrococol { - let bottleID : String - let entropy : Data + let bottleID: String? + let entropy: Data? - init(bottleID: String, entropy: Data) { + init(bottleID: String?, entropy: Data?) { self.bottleID = bottleID self.entropy = entropy super.init() } - func recover(withInfo info: [AnyHashable : Any]!, + func recover(withInfo info: [AnyHashable: Any]!, results: AutoreleasingUnsafeMutablePointer!) -> Error! { - results.pointee = [ - "bottleID": self.bottleID, - "bottleValid": "valid", - "EscrowServiceEscrowData" : ["BottledPeerEntropy": entropy], - ] + if self.bottleID == nil && self.entropy == nil { + results.pointee = [ + "bottleValid": "invalid", + ] + } else if self.bottleID == nil && self.entropy != nil { + results.pointee = [ + "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy], + "bottleValid": "invalid", + ] + } else if self.bottleID != nil && self.entropy == nil { + results.pointee = [ + "bottleID": self.bottleID!, + "bottleValid": "invalid", + ] + } else { //entropy and bottleID must exist, so its a good bottle. + results.pointee = [ + "bottleID": self.bottleID!, + "bottleValid": "valid", + "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy], + ] + } return nil } } class OTMockFollowUpController: NSObject, OctagonFollowUpControllerProtocol { - var postedFollowUp : Bool = false + var postedFollowUp: Bool = false override init() { super.init() diff --git a/keychain/ot/tests/octagon/OctagonTests+CKKS.swift b/keychain/ot/tests/octagon/OctagonTests+CKKS.swift index 40299eab..d088ab71 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CKKS.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CKKS.swift @@ -16,7 +16,7 @@ class OctagonCKKSTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -48,7 +48,7 @@ class OctagonCKKSTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") diff --git a/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift b/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift index 8d4c26c4..5a43ca54 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift @@ -127,6 +127,8 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + // On CK account sign-out, Octagon should go back to 'wait for cloudkit account' self.accountStatus = .noAccount self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() @@ -167,11 +169,61 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) - // On CK account sign-out, Octagon should go back to 'wait for cloudkit account' + // On CK account sign-out, Octagon should stay in 'wait for hsa2': if there's no HSA2, we don't actually care about the CK account status + self.accountStatus = .noAccount + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + + // On sign-out, octagon should go back to 'no account' + self.mockAuthKit.altDSID = nil + XCTAssertNoThrow(try self.cuttlefishContext.accountNoLongerAvailable(), "sign-out shouldn't error") + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + } + + func testSAtoHSA2PromotionWithoutCloudKit() throws { + self.startCKAccountStatusMock() + + // Device is signed out + self.mockAuthKit.altDSID = nil + self.mockAuthKit.hsa2 = false + self.accountStatus = .noAccount self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + // With no account, Octagon should go directly into 'NoAccount' + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) + + // Account signs in as SA. + let newAltDSID = UUID().uuidString + self.mockAuthKit.altDSID = newAltDSID + + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(newAltDSID), "Sign-in shouldn't error") + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + // Account promotes to HSA2 + self.mockAuthKit.hsa2 = true + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + + // Octagon should go into 'waitforcloudkit' self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitingForCloudKitAccount, within: 10 * NSEC_PER_SEC) + self.assertAccountAvailable(context: self.cuttlefishContext) + + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + + // On CK account sign-in, Octagon should race to 'untrusted' + self.accountStatus = .available + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // On sign-out, octagon should go back to 'no account' self.mockAuthKit.altDSID = nil @@ -179,6 +231,47 @@ class OctagonCloudKitAccountTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) self.assertNoAccount(context: self.cuttlefishContext) + // But CKKS is listening for the CK account removal, not the accountNoLongerAvailable call + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + self.accountStatus = .noAccount + self.accountStateTracker.notifyCKAccountStatusChangeAndWaitForSignal() + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) + } + + func testAPIFailureWhenSA() throws { + self.startCKAccountStatusMock() + + // Account is present, but SA + self.mockAuthKit.hsa2 = false + + XCTAssertNoThrow(try self.cuttlefishContext.idmsTrustLevelChanged(), "Notification of IDMS trust level shouldn't error") + XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(self.mockAuthKit.altDSID!), "Sign-in shouldn't error") + + self.cuttlefishContext.startOctagonStateMachine() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + self.assertNoAccount(context: self.cuttlefishContext) + + // Calling OTClique API should error (eventually) + self.cuttlefishContext.stateMachine.setWatcherTimeout(4 * NSEC_PER_SEC) + XCTAssertThrowsError(try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated), "establishing new friends in an SA account should error") + + // And octagon should still believe everything is terrible + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC) + XCTAssertEqual(self.cuttlefishContext.currentMemoizedTrustState(), .UNKNOWN, "Trust state should be unknown") + + let statusexpectation = self.expectation(description: "trust status returns") + let configuration = OTOperationConfiguration() + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in + XCTAssertEqual(.noCloudKitAccount, egoStatus, "cliqueStatus should be 'no cloudkit account'") + statusexpectation.fulfill() + } + self.wait(for: [statusexpectation], timeout: 10) + + self.assertNoAccount(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC) } } diff --git a/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift b/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift index 87e68aba..c2692037 100644 --- a/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift +++ b/keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift @@ -1,4 +1,3 @@ - #if OCTAGON class OctagonCoreFollowUpTests: OctagonTestsBase { @@ -54,16 +53,19 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } func testAttemptedJoinNotAttemptedStateSOSEnabled() throws { self.startCKAccountStatusMock() + self.mockSOSAdapter.sosEnabled = true + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + // Prepare an identity, then pretend like securityd thought it was in the right account let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -110,9 +112,72 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) // CKKS should be waiting for assistance - assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Since SOS isn't around to help, Octagon should post a CFU + #if os(tvOS) + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV (due to having no peers to join)") + #else + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS can't help") + #endif + } + + func testAttemptedJoinNotAttemptedStateSOSError() throws { + self.startCKAccountStatusMock() + + self.mockSOSAdapter.sosEnabled = true + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCError) + + // Prepare an identity, then pretend like securityd thought it was in the right account + let containerName = OTCKContainerName + let contextName = OTDefaultContext + + var selfPeerID: String? + let prepareExpectation = self.expectation(description: "prepare callback occurs") + tphClient.prepare(withContainer: containerName, + context: contextName, + epoch: 0, + machineID: "asdf", + bottleSalt: "123456789", + bottleID: UUID().uuidString, + modelID: "asdf", + deviceName: "asdf", + serialNumber: "1234", + osVersion: "asdf", + policyVersion: nil, + policySecrets: nil, + signingPrivKeyPersistentRef: nil, + encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in + XCTAssertNil(error, "Should be no error preparing identity") + XCTAssertNotNil(peerID, "Should be a peer ID") + XCTAssertNotNil(permanentInfo, "Should have a permenent info") + XCTAssertNotNil(permanentInfoSig, "Should have a permanent info signature") + XCTAssertNotNil(stableInfo, "Should have a stable info") + XCTAssertNotNil(stableInfoSig, "Should have a stable info signature") + selfPeerID = peerID + + prepareExpectation.fulfill() + } + self.wait(for: [prepareExpectation], timeout: 10) + + let account = OTAccountMetadataClassC()! + account.peerID = selfPeerID + account.icloudAccountState = .ACCOUNT_AVAILABLE + account.trustState = .TRUSTED + account.attemptedJoin = .NOTATTEMPTED + + XCTAssertNoThrow(try account.saveToKeychain(forContainer: containerName, contextID: contextName), "Should be no error saving fake account metadata") + + OctagonInitialize() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "should NOT have posted an repair CFU"); + // CKKS should be waiting for assistance + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Since SOS is in 'error', octagon shouldn't post until SOS can say y/n + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "should NOT have posted an repair CFU") } func testAttemptedJoinNotAttemptedStateSOSDisabled() throws { @@ -130,10 +195,10 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS is disabled"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS is disabled") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } @@ -189,10 +254,10 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) #if !os(tvOS) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU") #else // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") #endif } @@ -208,7 +273,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") // Now, an iphone appears! let iphone = self.manager.context(forContainerName: OTCKContainerName, @@ -221,7 +286,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { iphone.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - iphone.rpcResetAndEstablish() { resetError in + iphone.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -231,7 +296,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { // The TV should now post a CFU, as there's an iphone that can repair it self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU"); + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU") } func testDontPostCFUWhenApprovalIncapablePeerJoins() throws { @@ -245,7 +310,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) // Apple TV should not post a CFU, as there's no peers to join - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") // Now, a mac appears! macs cannot fix apple TVs. let mac = self.manager.context(forContainerName: OTCKContainerName, @@ -258,7 +323,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { mac.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - mac.rpcResetAndEstablish() { resetError in + mac.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -268,9 +333,96 @@ class OctagonCoreFollowUpTests: OctagonTestsBase { // The TV should not post a CFU, as there's still no iPhone to repair it self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU; no devices present can repair it"); + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU; no devices present can repair it") + } + + func testDontPostCFUWhenCapablePeersAreUntrusted() throws { + self.startCKAccountStatusMock() + // Octagon only examines the JoinState if SOS is enabled + self.mockSOSAdapter.sosEnabled = false + + // An iPhone establishes some octagon state, then untrusts itself + // This is techinically an invalid situation, since Cuttlefish should have rejected the untrust, but it should trigger the condition we're interested in + + let iphone = self.manager.context(forContainerName: OTCKContainerName, + contextID: "firstPhone", + sosAdapter: self.mockSOSAdapter, + authKitAdapter: self.mockAuthKit2, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + iphone.startOctagonStateMachine() + + let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") + iphone.rpcResetAndEstablish(.testGenerated) { resetError in + XCTAssertNil(resetError, "should be no error resetting and establishing") + resetAndEstablishExpectation.fulfill() + } + self.wait(for: [resetAndEstablishExpectation], timeout: 10) + + let iphonePeerID = try iphone.accountMetadataStore.loadOrCreateAccountMetadata().peerID! + + let leaveExpectation = self.expectation(description: "rpcLeaveClique returns") + iphone.rpcLeaveClique { leaveError in + XCTAssertNil(leaveError, "Should be no error leaving") + leaveExpectation.fulfill() + } + self.wait(for: [leaveExpectation], timeout: 10) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: iphonePeerID, opinion: .excludes, target: iphonePeerID)), + "iphone should distrust itself") + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + // Ensure that the aTV has fetched properly + self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext) + + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + // Apple TV should not post a CFU, as the only iPhone around is untrusted + XCTAssertFalse(self.cuttlefishContext.postedRepairCFU, "appleTV should not have posted a repair CFU") + + // Another iPhone resets the world + let iphone2 = self.manager.context(forContainerName: OTCKContainerName, + contextID: "firstPhone", + sosAdapter: self.mockSOSAdapter, + authKitAdapter: self.mockAuthKit3, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + iphone2.startOctagonStateMachine() + + let resetAndEstablishExpectation2 = self.expectation(description: "resetAndEstablishExpectation returns") + iphone2.rpcResetAndEstablish(.testGenerated) { resetError in + XCTAssertNil(resetError, "should be no error resetting and establishing") + resetAndEstablishExpectation2.fulfill() + } + self.wait(for: [resetAndEstablishExpectation2], timeout: 10) + + // The aTV is notified, and now posts a CFU + self.sendContainerChangeWaitForUntrustedFetch(context: self.cuttlefishContext) + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "appleTV should have posted a repair CFU") } #endif + + func testPostCFUAfterSOSUpgradeFails() throws { + self.startCKAccountStatusMock() + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC) + + #if os(tvOS) + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV (due to having no peers to join)") + #else + XCTAssertTrue(self.cuttlefishContext.postedRepairCFU, "should have posted an repair CFU, as SOS can't help") + #endif + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift index f601b5f6..3fa30c28 100644 --- a/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift +++ b/keychain/ot/tests/octagon/OctagonTests+DeviceList.swift @@ -17,10 +17,10 @@ class OctagonDeviceListTests: OctagonTestsBase { let expectFail = self.expectation(description: "expect to fail") do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNil(clique, "Clique should be nil") } catch { - expectFail.fulfill(); + expectFail.fulfill() } self.wait(for: [expectFail], timeout: 10) @@ -41,7 +41,7 @@ class OctagonDeviceListTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -148,7 +148,6 @@ class OctagonDeviceListTests: OctagonTestsBase { "peer 1 should distrust peer 2 after update") } - func testTrustPeerWhenMissingFromDeviceList() throws { self.startCKAccountStatusMock() @@ -394,9 +393,9 @@ class OctagonDeviceListTests: OctagonTestsBase { // Peer 2 is not on Peer 1's machine ID list yet self.mockAuthKit.otherDevices.remove(self.mockAuthKit2.currentMachineID) - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() let joiningContext = self.makeInitiatorContext(contextID: "joiner", authKitAdapter: self.mockAuthKit2) - let _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) + _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) // Now, add peer2 to the machineID list, but don't send peer1 a notification about the IDMS change self.mockAuthKit.otherDevices.insert(self.mockAuthKit2.currentMachineID) @@ -415,7 +414,7 @@ class OctagonDeviceListTests: OctagonTestsBase { // At this time, peer1 should trust peer2, but it should _not_ have fetched the AuthKit list, // because peer2 is still within the 48 hour grace period. peer1 is hoping for a push to arrive. - XCTAssertNotEqual(condition.wait(2*NSEC_PER_SEC), 0, "Octagon should not fetch the authkit machine ID list") + XCTAssertNotEqual(condition.wait(2 * NSEC_PER_SEC), 0, "Octagon should not fetch the authkit machine ID list") let peer2MIDSet = Set([self.mockAuthKit2.currentMachineID]) self.assertMIDList(context: self.cuttlefishContext, allowed: self.mockAuthKit.currentDeviceList().subtracting(peer2MIDSet), @@ -429,7 +428,7 @@ class OctagonDeviceListTests: OctagonTestsBase { if machinemo.machineID == self.mockAuthKit2.currentMachineID { foundPeer2 = true // - machinemo.modified = Date(timeIntervalSinceNow: -60*60*TimeInterval(72)) + machinemo.modified = Date(timeIntervalSinceNow: -60 * 60 * TimeInterval(72)) XCTAssertEqual(machinemo.status, Int64(TPMachineIDStatus.unknown.rawValue), "peer2's MID entry should be 'unknown'") } } @@ -441,7 +440,7 @@ class OctagonDeviceListTests: OctagonTestsBase { self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - XCTAssertEqual(condition.wait(10*NSEC_PER_SEC), 0, "Octagon should fetch the authkit machine ID list") + XCTAssertEqual(condition.wait(10 * NSEC_PER_SEC), 0, "Octagon should fetch the authkit machine ID list") self.assertMIDList(context: self.cuttlefishContext, allowed: self.mockAuthKit.currentDeviceList()) } @@ -501,7 +500,7 @@ class OctagonDeviceListTests: OctagonTestsBase { sleep(1) XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have 0 pending flags") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) - + self.wait(for: [updateTrustExpectation], timeout: 10) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) diff --git a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift index bba5d235..e838a1af 100644 --- a/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift +++ b/keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift @@ -1,4 +1,3 @@ - #if OCTAGON class OctagonErrorHandlingTests: OctagonTestsBase { @@ -17,7 +16,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { userInfo: [:]) } - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() self.wait(for: [establishExpectation], timeout: 10) } @@ -26,7 +25,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { let establishExpectation = self.expectation(description: "establishExpectation") - var t0: Date = Date.distantPast + var t0 = Date.distantPast self.fakeCuttlefishServer.establishListener = { [unowned self] request in self.fakeCuttlefishServer.establishListener = nil @@ -36,12 +35,40 @@ class OctagonErrorHandlingTests: OctagonTestsBase { return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .retryableServerFailure) } - let _ = self.assertResetAndBecomeTrustedInDefaultContext() + _ = self.assertResetAndBecomeTrustedInDefaultContext() self.wait(for: [establishExpectation], timeout: 10) let t1 = Date() let d = t0.distance(to: t1) XCTAssertGreaterThanOrEqual(d, 4) - XCTAssertLessThanOrEqual(d, 6) + // Let slower devices have a few extra seconds: we expect this after 5s, but sometimes they need a bit. + XCTAssertLessThanOrEqual(d, 8) + } + + func testRecoverFromTransactionalErrorDuringJoinWithVoucher() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + var t0 = Date.distantPast + + let joinExpectation = self.expectation(description: "joinExpectation") + self.fakeCuttlefishServer.joinListener = { [unowned self] _ in + self.fakeCuttlefishServer.joinListener = nil + joinExpectation.fulfill() + + t0 = Date() + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) + } + + let joiningContext = self.makeInitiatorContext(contextID: "joiner", authKitAdapter: self.mockAuthKit2) + _ = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext) + + self.wait(for: [joinExpectation], timeout: 10) + let t1 = Date() + let d = t0.distance(to: t1) + XCTAssertGreaterThanOrEqual(d, 4) + // Let slower devices have a few extra seconds: we expect this after 5s, but sometimes they need a bit. + XCTAssertLessThanOrEqual(d, 8) } func testReceiveUpdateWhileUntrustedAndLocked() { @@ -66,7 +93,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -123,7 +150,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -134,9 +161,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertConsidersSelfTrusted(context: self.cuttlefishContext) self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext) - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.sendContainerChange(context: self.cuttlefishContext) @@ -155,7 +182,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -169,9 +196,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.aksLockState = true self.lockStateTracker.recheck() - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.sendContainerChange(context: self.cuttlefishContext) @@ -202,7 +229,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -215,18 +242,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase { let pre = self.fakeCuttlefishServer.fetchChangesCalledCount - - let cuttlefishError = NSError(domain:CuttlefishErrorDomain, - code:CuttlefishErrorCode.transactionalFailure.rawValue, - userInfo:nil) - let ckInternalError = NSError(domain:CKInternalErrorDomain, - code:CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo:[NSUnderlyingErrorKey: cuttlefishError]) - let ckError = NSError(domain:CKErrorDomain, - code:CKError.serverRejectedRequest.rawValue, - userInfo:[NSUnderlyingErrorKey: ckInternalError]) - - + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) @@ -242,7 +258,6 @@ class OctagonErrorHandlingTests: OctagonTestsBase { XCTAssertEqual(post, pre + 2, "should have fetched two times, the first response would have been a transaction error") } - func testPreapprovedPushWhileLocked() throws { // Peer 1 becomes SOS+Octagon self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) @@ -344,9 +359,9 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() - let clique : OTClique + let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -376,7 +391,6 @@ class OctagonErrorHandlingTests: OctagonTestsBase { machineID: "b-machine-id", otherDevices: [self.mockAuthKit.currentMachineID]) - let bRestoreContext = self.manager.context(forContainerName: OTCKContainerName, contextID: bNewOTCliqueContext.context!, sosAdapter: OTSOSMissingAdapter(), @@ -435,6 +449,68 @@ class OctagonErrorHandlingTests: OctagonTestsBase { self.wait(for: [updateTrustExpectation], timeout: 30) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } + + func testCKKSResetRecoverFromCKKSConflict() throws { + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) + // But do NOT add them to the keychain + + // CKKS should get stuck in waitfortlk + self.startCKAccountStatusMock() + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + do { + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + } + + // Now, we should be in 'ready', and CKKS should be stuck + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) + + // Now, CKKS decides to reset the world, but a conflict occurs on hierarchy upload + self.silentZoneDeletesAllowed = true + var tlkUUIDs : [CKRecordZone.ID:String] = [:] + + self.silentFetchesAllowed = false + self.expectCKFetchAndRun(beforeFinished: { + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) + self.silentFetchesAllowed = true + + // Use the commented version below when multi-zone support is readded to the tets + tlkUUIDs[self.manateeZoneID!] = (self.keys![self.manateeZoneID!] as? ZoneKeys)?.tlk?.uuid + /* + for zoneID in self.ckksZones { + tlkUUIDs[zoneID as! CKRecordZone.ID] = (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid + } + */ + }) + + let resetExepctation = self.expectation(description: "reset callback is called") + self.cuttlefishContext.viewManager!.rpcResetCloudKit(nil, reason: "unit-test") { + error in + XCTAssertNil(error, "should be no error resetting cloudkit") + resetExepctation.fulfill() + } + + // Deletions should occur, then the fetches, then get stuck (as we don't have the TLK) + self.wait(for: [resetExepctation], timeout: 10) + self.verifyDatabaseMocks() + + // all subCKKSes should get stuck in waitfortlk + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + XCTAssertEqual(tlkUUIDs.count, self.ckksZones.count, "Should have the right number of conflicted TLKs") + for (zoneID,tlkUUID) in tlkUUIDs { + XCTAssertEqual(tlkUUID, (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid, "TLK should match conflicted version") + } + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift b/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift index 184b0dfc..64a4006f 100644 --- a/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift +++ b/keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift @@ -25,7 +25,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -104,7 +104,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -171,7 +171,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -229,7 +229,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -262,8 +262,8 @@ // The first peer will upload TLKs for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() self.assertTrusts(context: self.cuttlefishContext, includedPeerIDCount: 2, excludedPeerIDCount: 0) @@ -293,7 +293,7 @@ self.assertTrusts(context: differentDevice, includedPeerIDCount: 2, excludedPeerIDCount: 1) // Then, if by some strange miracle the original peer is still around, it should bail (as it's now untrusted) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext, states: [OctagonStateUntrusted]) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) self.assertTrusts(context: self.cuttlefishContext, includedPeerIDCount: 0, excludedPeerIDCount: 1) } @@ -307,7 +307,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -363,7 +363,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -415,7 +415,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -463,10 +463,10 @@ // We will upload a new TLK for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) bottleIDs = try OTClique.findOptimalBottleIDs(withContextData: self.otcliqueContext) XCTAssertNotNil(bottleIDs.preferredBottleIDs, "preferredBottleIDs should not be nil") XCTAssertEqual(bottleIDs.preferredBottleIDs.count, 2, "preferredBottleIDs should have 2 bottle") @@ -478,7 +478,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -536,10 +536,10 @@ // We will upload a new TLK for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) bottleIDs = try OTClique.findOptimalBottleIDs(withContextData: self.otcliqueContext) XCTAssertNotNil(bottleIDs.preferredBottleIDs, "preferredBottleIDs should not be nil") @@ -591,7 +591,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) @@ -677,7 +677,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -717,7 +717,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -756,7 +756,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -796,7 +796,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -832,7 +832,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -858,7 +858,6 @@ // To get into the state we need, we need to introduce peer B and C. C should then distrust A, whose bottle it used // B shouldn't have an opinion of C. - let bNewOTCliqueContext = OTConfigurationContext() bNewOTCliqueContext.context = "restoreB" bNewOTCliqueContext.dsid = self.otcliqueContext.dsid @@ -982,7 +981,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1042,7 +1041,6 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - //now call fetchviablebottles, we should get the uncached version let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles") @@ -1068,7 +1066,6 @@ fetchViableExpectation.fulfill() } self.wait(for: [fetchViableExpectation], timeout: 10) - //now call fetchviablebottles, we should get the cached version let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles") @@ -1110,7 +1107,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1140,7 +1137,6 @@ // Note: CKKS will want to upload a TLKShare for its self self.expectCKModifyKeyRecords(0, currentKeyPointerRecords: 0, tlkShareRecords: 1, zoneID: self.manateeZoneID) - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") self.cuttlefishContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.otcliqueContext.altDSID) { error in XCTAssertNil(error, "error should be nil") @@ -1171,7 +1167,6 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - //now call fetchviablebottles, we should get the uncached version let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles") @@ -1238,7 +1233,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1268,7 +1263,6 @@ // Note: CKKS will want to upload a TLKShare for its self self.expectCKModifyKeyRecords(0, currentKeyPointerRecords: 0, tlkShareRecords: 1, zoneID: self.manateeZoneID) - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") self.cuttlefishContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.otcliqueContext.altDSID) { error in XCTAssertNil(error, "error should be nil") @@ -1302,7 +1296,7 @@ self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let bottles:[Bottle] = self.fakeCuttlefishServer.state.bottles + let bottles: [Bottle] = self.fakeCuttlefishServer.state.bottles var bottleToExclude: String? bottles.forEach { bottle in if bottle.peerID == egoPeerID { diff --git a/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift b/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift index 9d00a5ce..e1fd51bd 100644 --- a/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift +++ b/keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift @@ -10,27 +10,27 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.startCKAccountStatusMock() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - + let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") throw error } - + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) XCTAssertEqual(2, accountState.trustState.rawValue, "saved account should be trusted") } catch { XCTFail("error loading account state: \(error)") } - + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in XCTAssertNil(error, "error should be nil") @@ -47,7 +47,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { dumpCallback.fulfill() } self.wait(for: [dumpCallback], timeout: 10) - + self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } @@ -68,11 +68,18 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) + #if os(tvOS) XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, false, "Should not have posted a CFU on aTV") + #else + XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, true, "Should have posted a CFU (due to being untrusted)") + #endif self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + // Reset flag for remainder of test + self.cuttlefishContext.setPostedBool(false) + // Set the "have I attempted to join" bit; TVs should still not CFU, but other devices should try! self.cuttlefishContext.accountMetadataStore.persistOctagonJoinAttempt(.ATTEMPTED) @@ -89,7 +96,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { XCTAssertEqual(self.cuttlefishContext.postedRepairCFU, true, "Should have posted a CFU") #endif } - + func testHealthCheckSecurityDStateNOTTrusted() throws { let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -101,17 +108,17 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") throw error } - + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + //now let's ruin account state, and say we are untrusted do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) @@ -121,14 +128,14 @@ class OctagonHealthCheckTests: OctagonTestsBase { } catch { XCTFail("error loading account state: \(error)") } - + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNil(error, "error should be nil") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) - + self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: cuttlefishContext) @@ -146,11 +153,11 @@ class OctagonHealthCheckTests: OctagonTestsBase { dumpCallback.fulfill() } self.wait(for: [dumpCallback], timeout: 10) - + self.verifyDatabaseMocks() self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } - + func testHealthCheckTrustedPeersHelperStateNOTTrusted() throws { let containerName = OTCKContainerName let contextName = OTDefaultContext @@ -162,7 +169,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -172,21 +179,21 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - + do { let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) XCTAssertEqual(2, accountState.trustState.rawValue, "Saved account state should be trusted") } catch { XCTFail("error loading account state: \(error)") } - + var healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNil(error, "error should be nil") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) - + // now lets completely wipe cuttlefish state let resetCallback = self.expectation(description: "resetCallback callback occurs") self.tphClient.localReset(withContainer: containerName, context: contextName) { error in @@ -194,7 +201,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { resetCallback.fulfill() } self.wait(for: [resetCallback], timeout: 10) - + healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") cuttlefishContext.checkOctagonHealth(false) { error in XCTAssertNotNil(error, "error should not be nil") @@ -220,7 +227,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -269,22 +276,22 @@ class OctagonHealthCheckTests: OctagonTestsBase { func testCuttlefishResponseNoAction() throws { self.fakeCuttlefishServer.returnNoActionResponse = true let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertFalse(self.otFollowUpController.postedFollowUp, "should not have posted a CFU"); - XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted a CFU"); + XCTAssertFalse(self.otFollowUpController.postedFollowUp, "should not have posted a CFU") + XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted a CFU") } func testCuttlefishResponseRepairAccount() throws { self.fakeCuttlefishServer.returnRepairAccountResponse = true let (_, _) = try responseTestsSetup() - XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU"); + XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU") } func testCuttlefishResponseRepairEscrow() throws { self.fakeCuttlefishServer.returnRepairEscrowResponse = true OTMockSecEscrowRequest.self.populateStatuses = false let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU"); - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, true, "should have posted an escrow CFU"); + XCTAssertTrue(self.otFollowUpController.postedFollowUp, "should have posted a CFU") + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, true, "should have posted an escrow CFU") } func testCuttlefishResponseResetOctagon() throws { @@ -315,12 +322,11 @@ class OctagonHealthCheckTests: OctagonTestsBase { } func testCuttlefishResponseError() throws { - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.changeTokenExpired.rawValue, userInfo: nil) - self.fakeCuttlefishServer.returnRepairErrorResponse = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + self.fakeCuttlefishServer.returnRepairErrorResponse = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired) let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted an account repair CFU"); - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should not have posted an escrow repair CFU"); + XCTAssertEqual(cuttlefishContext.postedRepairCFU, false, "should not have posted an account repair CFU") + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should not have posted an escrow repair CFU") } func testHealthCheckBeforeStateMachineStarts() throws { @@ -328,19 +334,19 @@ class OctagonHealthCheckTests: OctagonTestsBase { let containerName = OTCKContainerName let cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: contextName) - cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in XCTAssertNotNil(error, "Should be an error calling 'healthCheck'") XCTAssertEqual(error!._domain, CKKSResultErrorDomain, "Error domain should be CKKSResultErrorDomain") - XCTAssertEqual(error!._code , CKKSResultTimedOut, "Error result should be CKKSResultTimedOut") + XCTAssertEqual(error!._code, CKKSResultTimedOut, "Error result should be CKKSResultTimedOut") healthCheckCallback.fulfill() } self.wait(for: [healthCheckCallback], timeout: 10) self.startCKAccountStatusMock() - cuttlefishContext.stateMachine.setWatcherTimeout(60*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(60 * NSEC_PER_SEC) cuttlefishContext.startOctagonStateMachine() @@ -353,7 +359,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { otcliqueContext.altDSID = self.mockAuthKit.altDSID! otcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: otcliqueContext) + clique = try OTClique.newFriends(withContextData: otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -405,7 +411,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -454,10 +460,9 @@ class OctagonHealthCheckTests: OctagonTestsBase { } self.wait(for: [healthCheckCallback], timeout: 10) - let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -505,7 +510,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) let cuttlefishContext = self.manager.context(forContainerName: containerName, contextID: contextName) - cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in @@ -530,7 +535,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -583,7 +588,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -709,7 +714,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -745,9 +750,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { } self.wait(for: [fetchViableExpectation], timeout: 10) - let userInfo: Dictionary = ["NSLocalizedDescription" : "Reachability validation failed, graph is not reachable"] - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.resultGraphNotFullyReachable.rawValue, userInfo: userInfo) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .resultGraphNotFullyReachable) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) let joinListenerExpectation = self.expectation(description: "joinWithVoucherExpectation callback occurs") @@ -773,13 +776,15 @@ class OctagonHealthCheckTests: OctagonTestsBase { self.wait(for: [healthExpectation], timeout: 100) self.fakeCuttlefishServer.joinListener = nil self.fakeCuttlefishServer.healthListener = nil + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) } func testCuttlefishDontPostEscrowCFUDueToPendingPrecord() throws { self.fakeCuttlefishServer.returnRepairEscrowResponse = true OTMockSecEscrowRequest.self.populateStatuses = true let (cuttlefishContext, _) = try responseTestsSetup() - XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should NOT have posted an escrow CFU"); + XCTAssertEqual(cuttlefishContext.postedEscrowRepairCFU, false, "should NOT have posted an escrow CFU") } func testHealthCheckWhileLocked() throws { @@ -793,7 +798,7 @@ class OctagonHealthCheckTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { diff --git a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift index 397a9354..0bf2b04c 100644 --- a/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift +++ b/keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift @@ -5,7 +5,6 @@ super.setUp() } - func testSetRecoveryKey() throws { self.startCKAccountStatusMock() self.manager.setSOSEnabledForPlatformFlag(false) @@ -17,7 +16,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -51,7 +50,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -157,7 +156,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -210,7 +209,7 @@ // The first peer will upload TLKs for the new peer self.assertAllCKKSViewsUpload(tlkShares: 1) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() let stableInfoCheckDumpCallback = self.expectation(description: "stableInfoCheckDumpCallback callback occurs") @@ -272,7 +271,7 @@ self.verifyDatabaseMocks() - self.sendContainerChangeWaitForFetchForState(context: thirdPeerContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: thirdPeerContext) let thirdPeerStableInfoCheckDumpCallback = self.expectation(description: "thirdPeerStableInfoCheckDumpCallback callback occurs") self.tphClient.dump(withContainer: OTCKContainerName, context: thirdPeerContextID) { dump, _ in @@ -325,7 +324,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit2.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -354,14 +353,14 @@ } self.wait(for: [createRecoveryExpectation], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: establishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: establishContext) let recoveryContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) recoveryContext.startOctagonStateMachine() self.assertEnters(context: recoveryContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: recoveryContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: recoveryContext) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs") recoveryContext.join(withRecoveryKey: recoveryKey) { error in @@ -441,7 +440,7 @@ bottlerotcliqueContext.altDSID = self.mockAuthKit2.altDSID! bottlerotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext) + clique = try OTClique.newFriends(withContextData: bottlerotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -464,7 +463,7 @@ } self.wait(for: [createRecoveryExpectation], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: establishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: establishContext) self.silentFetchesAllowed = false self.expectCKFetchAndRun(beforeFinished: { @@ -477,7 +476,7 @@ recoveryContext.startOctagonStateMachine() self.assertEnters(context: recoveryContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.sendContainerChangeWaitForFetchForState(context: recoveryContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: recoveryContext) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs") recoveryContext.join(withRecoveryKey: recoveryKey) { error in @@ -502,7 +501,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -537,7 +536,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -580,7 +579,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -652,8 +651,8 @@ } self.wait(for: [setRecoveryKeyExpectationAgain], timeout: 10) - self.sendContainerChangeWaitForFetchForState(context: initiatorContext, state: OctagonStateReady) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) + self.sendContainerChangeWaitForFetch(context: initiatorContext) + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) var initiatorRecoverySigningKey: Data? var initiatorRecoveryEncryptionKey: Data? @@ -736,7 +735,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -775,7 +774,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -858,7 +857,7 @@ self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") - TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey:recoveryKey!) { error in + TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in XCTAssertNil(error, "error should be nil") joinWithRecoveryKeyExpectation.fulfill() } @@ -897,7 +896,7 @@ self.manager.setSOSEnabledForPlatformFlag(false) self.startCKAccountStatusMock() - + self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) @@ -905,7 +904,7 @@ let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -948,7 +947,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -994,7 +993,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1023,7 +1022,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1062,7 +1061,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1098,7 +1097,7 @@ recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! recoverykeyotcliqueContext.otControl = self.otControl do { - clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") } catch { @@ -1144,7 +1143,7 @@ let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) newGuyContext.startOctagonStateMachine() - self.sendContainerChangeWaitForFetchForState(context: newGuyContext, state: OctagonStateUntrusted) + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) self.manager.setSOSEnabledForPlatformFlag(true) let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") @@ -1155,5 +1154,77 @@ } self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) } + + func testMalformedRecoveryKey() throws { + OctagonRecoveryKeySetIsEnabled(true) + self.manager.setSOSEnabledForPlatformFlag(false) + self.startCKAccountStatusMock() + + let establishContextID = "establish-context-id" + let establishContext = self.createEstablishContext(contextID: establishContextID) + + establishContext.startOctagonStateMachine() + self.assertEnters(context: establishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = establishContextID + recoverykeyotcliqueContext.dsid = "1234" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + + self.assertEnters(context: establishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: establishContext) + + // Fake that this peer also created some TLKShares for itself + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + try self.putSelfTLKShareInCloudKit(context: establishContext, zoneID: self.manateeZoneID) + + self.assertSelfTLKSharesInCloudKit(context: establishContext) + + let recoveryKey = "malformedRecoveryKey" + 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") + XCTAssertEqual((error! as NSError).code, 41, "error code should be 41/malformed recovery key") + XCTAssertEqual((error! as NSError).domain, "com.apple.security.octagon", "error code domain should be com.apple.security.octagon") + createKeyExpectation.fulfill() + } + self.wait(for: [createKeyExpectation], timeout: 10) + + let newCliqueContext = OTConfigurationContext() + newCliqueContext.context = OTDefaultContext + newCliqueContext.dsid = self.otcliqueContext.dsid + newCliqueContext.altDSID = self.mockAuthKit.altDSID! + newCliqueContext.otControl = self.otControl + + let newGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + newGuyContext.startOctagonStateMachine() + + self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext) + + self.manager.setSOSEnabledForPlatformFlag(true) + let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") + + OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in + XCTAssertNotNil(error, "error should NOT be nil") + XCTAssertEqual((error! as NSError).code, 41, "error code should be 41/malformed recovery key") + XCTAssertEqual((error! as NSError).domain, "com.apple.security.octagon", "error code domain should be com.apple.security.octagon") + joinWithRecoveryKeyExpectation.fulfill() + } + self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+Reset.swift b/keychain/ot/tests/octagon/OctagonTests+Reset.swift index cb8120ae..562d6270 100644 --- a/keychain/ot/tests/octagon/OctagonTests+Reset.swift +++ b/keychain/ot/tests/octagon/OctagonTests+Reset.swift @@ -9,7 +9,7 @@ class OctagonResetTests: OctagonTestsBase { _ = try self.cuttlefishContext.accountAvailable("13453464") - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -23,7 +23,7 @@ class OctagonResetTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -39,7 +39,7 @@ class OctagonResetTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") } @@ -66,7 +66,8 @@ class OctagonResetTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -96,7 +97,7 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -123,7 +124,8 @@ class OctagonResetTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -136,14 +138,14 @@ class OctagonResetTests: OctagonTestsBase { // CKKS should have all gone into waitfortrust during that time for condition in waitfortrusts { - XCTAssertEqual(0, condition.wait(10*NSEC_PER_MSEC), "CKKS should have entered waitfortrust") + XCTAssertEqual(0, condition.wait(10 * NSEC_PER_MSEC), "CKKS should have entered waitfortrust") } } func testOctagonResetAlsoResetsCKKSViewsMissingTLKs() { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -155,14 +157,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys") @@ -173,7 +175,7 @@ class OctagonResetTests: OctagonTestsBase { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) - (self.zones![self.manateeZoneID]! as! FakeCKZone).currentDatabase.allValues.forEach { record in + (self.zones![self.manateeZoneID!]! as! FakeCKZone).currentDatabase.allValues.forEach { record in let r = record as! CKRecord if(r.recordType == SecCKRecordDeviceStateType) { r.creationDate = NSDate.distantPast @@ -181,7 +183,7 @@ class OctagonResetTests: OctagonTestsBase { } } - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -192,14 +194,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys") @@ -210,7 +212,7 @@ class OctagonResetTests: OctagonTestsBase { self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) self.putFakeDeviceStatus(inCloudKit: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -221,14 +223,14 @@ class OctagonResetTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys") @@ -237,9 +239,9 @@ class OctagonResetTests: OctagonTestsBase { func testOctagonResetWithTLKsDoesNotResetCKKS() { // CKKS has the keys keys self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - self.saveTLKMaterial(toKeychain:self.manateeZoneID) + self.saveTLKMaterial(toKeychain: self.manateeZoneID) - let zoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(zoneKeys, "Should have some zone keys") XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set") @@ -248,7 +250,7 @@ class OctagonResetTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) } catch { XCTFail("failed to make new friends: \(error)") } @@ -256,7 +258,7 @@ class OctagonResetTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) - let laterZoneKeys = self.keys![self.manateeZoneID] as? ZoneKeys + let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys XCTAssertNotNil(laterZoneKeys, "Should have some zone keys") XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset") XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys") @@ -278,15 +280,10 @@ class OctagonResetTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: CuttlefishErrorCode.establishFailed.rawValue, - userInfo: nil)]) - + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .establishFailed) } - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in resetExpectation.fulfill() XCTAssertNotNil(resetError, "should error resetting and establishing") } @@ -296,6 +293,294 @@ class OctagonResetTests: OctagonTestsBase { self.verifyDatabaseMocks() } + func testResetReasonUnknown() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.unknown.rawValue, "reset reason should be unknown") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + self.cuttlefishContext.rpcResetAndEstablish(.unknown) { resetError in + establishAndResetExpectation.fulfill() + XCTAssertNil(resetError, "should not error resetting and establishing") + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonUserInitiatedReset() throws { + // Make sure if establish fail we end up in untrusted instead of error + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.userInitiatedReset.rawValue, "reset reason should be user initiated reset") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = OTDefaultContext + recoverykeyotcliqueContext.dsid = "13453464" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .userInitiatedReset) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + establishAndResetExpectation.fulfill() + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonRecoveryKey() throws { + // Make sure if establish fail we end up in untrusted instead of error + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.recoveryKey.rawValue, "reset reason should be recovery key") + return nil + } + + let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String + XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil") + + let newCliqueContext = OTConfigurationContext() + newCliqueContext.context = OTDefaultContext + newCliqueContext.dsid = self.otcliqueContext.dsid + newCliqueContext.altDSID = self.mockAuthKit.altDSID! + newCliqueContext.otControl = self.otControl + + let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs") + TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in + XCTAssertNil(error, "error should be nil") + joinWithRecoveryKeyExpectation.fulfill() + } + self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10) + self.wait(for: [resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } + + func testResetReasonNoValidBottle() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let initiatorContext = self.manager.context(forContainerName: OTCKContainerName, + contextID: "restoreContext", + sosAdapter: OTSOSMissingAdapter(), + authKitAdapter: self.mockAuthKit2, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter()) + + initiatorContext.startOctagonStateMachine() + let newOTCliqueContext = OTConfigurationContext() + newOTCliqueContext.context = OTDefaultContext + newOTCliqueContext.dsid = self.otcliqueContext.dsid + newOTCliqueContext.altDSID = self.otcliqueContext.altDSID + newOTCliqueContext.otControl = self.otcliqueContext.otControl + newOTCliqueContext.sbd = OTMockSecureBackup(bottleID: nil, entropy: nil) + + let resetExpectation = self.expectation(description: "resetExpectation callback occurs") + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.noBottleDuringEscrowRecovery.rawValue, "reset reason should be no bottle during escrow recovery") + return nil + } + + let newClique: OTClique + do { + newClique = try OTClique.performEscrowRecovery(withContextData: newOTCliqueContext, escrowArguments: [:]) + XCTAssertNotNil(newClique, "newClique should not be nil") + } catch { + XCTFail("Shouldn't have errored recovering: \(error)") + throw error + } + self.wait(for: [resetExpectation], timeout: 10) + + } + + func testResetReasonHealthCheck() throws { + + let containerName = OTCKContainerName + let contextName = OTDefaultContext + + self.cuttlefishContext.startOctagonStateMachine() + self.startCKAccountStatusMock() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let clique: OTClique + do { + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + do { + let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName) + XCTAssertEqual(2, accountState.trustState.rawValue, "saved account should be trusted") + } catch { + XCTFail("error loading account state: \(error)") + } + + // Reset any CFUs we've done so far + self.otFollowUpController.postedFollowUp = false + + let resetExpectation = self.expectation(description: "resetExpectation callback occurs") + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.healthCheck.rawValue, "reset reason should be health check") + return nil + } + self.fakeCuttlefishServer.returnResetOctagonResponse = true + self.aksLockState = false + self.lockStateTracker.recheck() + + let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs") + self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in + XCTAssertNil(error, "error should be nil") + healthCheckCallback.fulfill() + } + self.wait(for: [healthCheckCallback, resetExpectation], timeout: 10) + + assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + let dumpCallback = self.expectation(description: "dumpCallback callback occurs") + self.tphClient.dump(withContainer: containerName, context: contextName) { + dump, _ in + XCTAssertNotNil(dump, "dump should not be nil") + let egoSelf = dump!["self"] as? Dictionary + XCTAssertNotNil(egoSelf, "egoSelf should not be nil") + dumpCallback.fulfill() + } + self.wait(for: [dumpCallback], timeout: 10) + + self.verifyDatabaseMocks() + self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testResetReasonLegacyJoinCircle() throws { + self.cuttlefishContext.startOctagonStateMachine() + self.startCKAccountStatusMock() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + let clique: OTClique + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = OTDefaultContext + recoverykeyotcliqueContext.dsid = "13453464" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call") + establishAndResetExpectation.fulfill() + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + self.wait(for: [establishAndResetExpectation], timeout: 10) + + 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") + return nil + } + + do { + _ = try clique.requestToJoinCircle() + } catch { + XCTFail("Shouldn't have errored requesting to join circle: \(error)") + throw error + } + self.wait(for: [resetExpectation], timeout: 10) + } + + func testResetReasonTestGenerated() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + + _ = try self.cuttlefishContext.accountAvailable("13453464") + + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.testGenerated.rawValue, "reset reason should be test generated") + return nil + } + + let establishAndResetExpectation = self.expectation(description: "resetExpectation") + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in + establishAndResetExpectation.fulfill() + XCTAssertNil(resetError, "should not error resetting and establishing") + } + self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests+SOS.swift b/keychain/ot/tests/octagon/OctagonTests+SOS.swift index c470baae..67a55f23 100644 --- a/keychain/ot/tests/octagon/OctagonTests+SOS.swift +++ b/keychain/ot/tests/octagon/OctagonTests+SOS.swift @@ -179,6 +179,118 @@ class OctagonSOSTests: OctagonTestsBase { assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) } + func testSOSPerformOctagonKeyConsistencyOnCircleChange() throws { + self.startCKAccountStatusMock() + + // Octagon establishes its identity before SOS joins + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + + self.assertResetAndBecomeTrustedInDefaultContext() + + let peerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID() + XCTAssertNotNil(peerID, "Should have a peer ID") + + // Now, SOS arrives + let updateExpectation = self.expectation(description: "Octagon should inform SOS of its keys") + self.mockSOSAdapter.updateOctagonKeySetListener = { _ in + // Don't currently check the key set at all here + updateExpectation.fulfill() + } + + // CKKS will upload itself new shares (for the newly trusted SOS self peer) + self.assertAllCKKSViewsUpload(tlkShares: 1) + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) + // Note: this should probably be sendSelfPeerChangedUpdate, but we don't have great fidelity around which peer + // actually changed. So, just use this channel for now + self.mockSOSAdapter.sendTrustedPeerSetChangedUpdate() + + self.wait(for: [updateExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + } + + func testDisablingSOSFeatureFlag() throws { + self.startCKAccountStatusMock() + OctagonSetSOSFeatureEnabled(false) + let recoverykeyotcliqueContext = OTConfigurationContext() + recoverykeyotcliqueContext.context = "recoveryContext" + recoverykeyotcliqueContext.dsid = "1234" + recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID! + recoverykeyotcliqueContext.otControl = self.otControl + + var clique: OTClique + do { + clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + throw error + } + do{ + try clique.joinAfterRestore() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.isLastFriend() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.safariPasswordSyncingEnabled() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.waitForInitialSync() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + clique.viewSet(Set(), disabledViews: Set()) + + do{ + try clique.setUserCredentialsAndDSID("", password: Data()) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.tryUserCredentialsAndDSID("", password: Data()) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.peersHaveViewsEnabled([""]) + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + do{ + try clique.requestToJoinCircle() + } catch { + XCTAssertNotNil(error, "error should not be nil") + } + + clique.accountUserKeyAvailable() + + do{ + _ = try clique.copyViewUnawarePeerInfo() + }catch{ + XCTAssertNotNil(error, "error should not be nil") + } + do { + _ = try clique.copyPeerPeerInfo() + }catch{ + XCTAssertNotNil(error, "error should not be nil") + } + } } #endif diff --git a/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift b/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift index 007a3a95..f1a10e25 100644 --- a/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift +++ b/keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift @@ -96,9 +96,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) self.startCKAccountStatusMock() - self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain:CKErrorDomain, - code:CKError.networkUnavailable.rawValue, - userInfo:[CKErrorRetryAfterKey: 2])) + self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain, + code: CKError.networkUnavailable.rawValue, + userInfo: [CKErrorRetryAfterKey: 2])) self.cuttlefishContext.startOctagonStateMachine() @@ -160,7 +160,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain:CKErrorDomain, code:CKError.networkUnavailable.rawValue, userInfo:[CKErrorRetryAfterKey: 2]) + return CKPrettyError(domain: CKErrorDomain, code: CKError.networkUnavailable.rawValue, userInfo: [CKErrorRetryAfterKey: 2]) } self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -194,12 +194,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.fakeCuttlefishServer.establishListener = nil establishExpectation.fulfill() - return CKPrettyError(domain: CKInternalErrorDomain, - code: CKInternalErrorCode.errorInternalPluginError.rawValue, - userInfo: [CKErrorRetryAfterKey: 2, - NSUnderlyingErrorKey: NSError(domain: CuttlefishErrorDomain, - code: CuttlefishErrorCode.resultGraphNotFullyReachable.rawValue, - userInfo: nil)]) + return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .resultGraphNotFullyReachable, retryAfter: 2) } self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -231,7 +226,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: peer2, state: OctagonStateReady, within: 100 * NSEC_PER_SEC) - // Now we arrive, and attempt to SOS join let sosUpgradeStateCondition = self.cuttlefishContext.stateMachine.stateConditions[OctagonStateAttemptSOSUpgrade] as! CKKSCondition self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -350,8 +344,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { // Right now, peer2 has just upgraded after peer1. It should trust peer1, and both should implictly trust each other XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") - XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -439,7 +431,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } - func testSOSJoinUponNotificationOfPreapprovalRetry() throws { // Peer 1 becomes SOS+Octagon self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) @@ -508,7 +499,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { } updateTrustExpectation1.fulfill() - return CKPrettyError(domain:CKErrorDomain, code:CKError.networkUnavailable.rawValue, userInfo:[CKErrorRetryAfterKey: 2]) + return CKPrettyError(domain: CKErrorDomain, code: CKError.networkUnavailable.rawValue, userInfo: [CKErrorRetryAfterKey: 2]) } self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer) @@ -631,7 +622,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") + "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -752,7 +743,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) let upgradeExpectation = self.expectation(description: "waitForOctagonUpgrade") - self.manager.wait(forOctagonUpgrade:OTCKContainerName, context: self.otcliqueContext.context ?? "defaultContext") { error in + self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: self.otcliqueContext.context ?? "defaultContext") { error in XCTAssertNil(error, "operation should not fail") upgradeExpectation.fulfill() } @@ -774,7 +765,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -860,14 +851,18 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), - "peer 2 should trust peer 1 by preapproval") + "peer 2 should trust peer 1") XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), "peer 1 should trust peer 2 by preapproval") XCTAssertFalse(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), "peer 1 should not trust peer 2 (as it hasn't responded to peer2's upgradeJoin yet)") // Now, tell peer1 about the change + // The first peer will upload TLKs for the new peer + self.assertAllCKKSViewsUpload(tlkShares: 1) self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() // Peer1 should trust peer2 now, since it upgraded it from implicitly explicitly trusted XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)), @@ -878,7 +873,15 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { var bottleID: String = "" //now try restoring bottles - let newGuyUsingBottle = self.manager.context(forContainerName: OTCKContainerName, contextID: "NewGuyUsingBottle") + let mockNoSOS = CKKSMockSOSPresentAdapter(selfPeer: self.createSOSPeer(peerID: "peer3ID"), trustedPeers: Set(), essential: false) + mockNoSOS.circleStatus = SOSCCStatus(kSOSCCNotInCircle) + let newGuyUsingBottle = self.manager.context(forContainerName: OTCKContainerName, + contextID: "NewGuyUsingBottle", + sosAdapter: mockNoSOS, + authKitAdapter: self.mockAuthKit3, + lockStateTracker: self.lockStateTracker, + accountStateTracker: self.accountStateTracker, + deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone-3", serialNumber: "456", osVersion: "iOS (fake version)")) let peer2AltDSID = try peer2.accountMetadataStore.loadOrCreateAccountMetadata().altDSID newGuyUsingBottle.startOctagonStateMachine() @@ -896,14 +899,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertNotNil(peer2AltDSID, "should have a dsid for peer2") - self.sendContainerChange(context: peer2) - - // The first peer will upload TLKs for the new peer - self.assertAllCKKSViewsUpload(tlkShares: 1) - self.sendContainerChangeWaitForFetchForState(context: self.cuttlefishContext, state: OctagonStateReady) - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) - self.verifyDatabaseMocks() - let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs") newGuyUsingBottle.join(withBottle: bottleID, entropy: entropy, bottleSalt: peer2AltDSID!) { error in XCTAssertNil(error, "error should be nil") @@ -912,6 +907,14 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [joinWithBottleExpectation], timeout: 10) self.assertEnters(context: newGuyUsingBottle, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + let newGuyPeerID = try newGuyUsingBottle.accountMetadataStore.getEgoPeerID() + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: newGuyPeerID)), + "newPeer should trust itself after bottle restore") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: peer1ID)), + "newPeer should trust peer 1 after bottle restore") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: newGuyPeerID, opinion: .trusts, target: peer2ID)), + "newPeer should trust peer 2 after bottle restore") + let gonnaFailContext = self.manager.context(forContainerName: OTCKContainerName, contextID: "gonnaFailContext") gonnaFailContext.startOctagonStateMachine() let joinWithBottleFailExpectation = self.expectation(description: "joinWithBottleFail callback occurs") @@ -922,7 +925,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [joinWithBottleFailExpectation], timeout: 10) self.assertEnters(context: gonnaFailContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext, isLocked: false) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) } func testSOSPeerUpdatePreapprovesNewPeer() throws { @@ -1105,7 +1110,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { } let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish") - self.cuttlefishContext.rpcResetAndEstablish() { error in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { error in XCTAssertNil(error, "Should be no error performing a reset and establish") resetAndEstablishExpectation.fulfill() } @@ -1166,7 +1171,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { self.wait(for: [dumpExpectation], timeout: 10) let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish") - self.cuttlefishContext.rpcResetAndEstablish() { error in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { error in XCTAssertNil(error, "Should be no error performing a reset and establish") resetAndEstablishExpectation.fulfill() } @@ -1211,9 +1216,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { XCTAssertTrue(OctagonPerformSOSUpgrade(), "SOS upgrade should be on") - self.mockAuthKit.machineIDFetchErrors.append(NSError(domain:AKAppleIDAuthenticationErrorDomain, - code:AKAppleIDAuthenticationError.authenticationErrorCannotFindServer.rawValue, - userInfo:nil)) + self.mockAuthKit.machineIDFetchErrors.append(NSError(domain: AKAppleIDAuthenticationErrorDomain, + code: AKAppleIDAuthenticationError.authenticationErrorCannotFindServer.rawValue, + userInfo: nil)) // Octagon should decide it is quite sad. self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) @@ -1236,8 +1241,8 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { OctagonSetPlatformSupportsSOS(true) - var clique : OTClique? - XCTAssertNoThrow(clique = try OTClique.init(contextData: self.otcliqueContext)) + var clique: OTClique? + XCTAssertNoThrow(clique = try OTClique(contextData: self.otcliqueContext)) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertNoThrow(try clique!.waitForOctagonUpgrade(), "Upgrading should pass") @@ -1255,14 +1260,123 @@ class OctagonSOSUpgradeTests: OctagonTestsBase { OctagonSetPlatformSupportsSOS(true) - var clique : OTClique? - XCTAssertNoThrow(clique = try OTClique.init(contextData: self.otcliqueContext)) + var clique: OTClique? + XCTAssertNoThrow(clique = try OTClique(contextData: self.otcliqueContext)) XCTAssertNotNil(clique, "Clique should not be nil") XCTAssertThrowsError(try clique!.waitForOctagonUpgrade(), "Upgrading should fail") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) } + + func testSOSDoNotJoinByPreapprovalMultipleTimes() throws { + self.startCKAccountStatusMock() + + // First, peer 1 establishes, preapproving both peer2 and peer3. Then, peer2 and peer3 join and harmonize. + // Peer1 is never told about the follow-on joins. + // Then, the test can begin. + + self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle) + + let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID") + let peer3SOSMockPeer = self.createSOSPeer(peerID: "peer3ID") + + self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer) + self.mockSOSAdapter.trustedPeers.add(peer3SOSMockPeer) + + // Due to how everything is shaking out, SOS TLKShares will be uploaded in a second transaction after Octagon uploads its TLKShares + // This isn't great: Octagon: upload SOS TLKShares alongside initial key hierarchy + self.assertAllCKKSViewsUpload(tlkShares: 3) + + self.cuttlefishContext.startOctagonStateMachine() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + let peer1ID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID() + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + // peer2 + let peer2mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer2SOSMockPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) + let peer2 = self.makeInitiatorContext(contextID: "peer2", authKitAdapter: self.mockAuthKit2, sosAdapter: peer2mockSOS) + + peer2.startOctagonStateMachine() + self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer2) + let peer2ID = try peer2.accountMetadataStore.getEgoPeerID() + + // peer3 + let peer3mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer3SOSMockPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) + let peer3 = self.makeInitiatorContext(contextID: "peer3", authKitAdapter: self.mockAuthKit3, sosAdapter: peer3mockSOS) + + peer3.startOctagonStateMachine() + self.assertEnters(context: peer3, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer3) + let peer3ID = try peer3.accountMetadataStore.getEgoPeerID() + + // Now, tell peer2 about peer3's join + self.sendContainerChangeWaitForFetch(context: peer2) + + // Peer 1 should preapprove both peers. + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), + "peer 1 should trust peer 2 by preapproval") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trustsByPreapproval, target: peer2ID)), + "peer 1 should trust peer 3 by preapproval") + + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)), + "peer 2 should trust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer3ID)), + "peer 2 should trust peer 3") + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .trusts, target: peer1ID)), + "peer 3 should trust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .trusts, target: peer2ID)), + "peer 3 should trust peer 2") + + // Now, the test can begin. Peer2 decides it rules the world. + let removalExpectation = self.expectation(description: "removal occurs") + peer2.rpcRemoveFriends(inClique: [peer1ID, peer3ID]) { removeError in + XCTAssertNil(removeError, "Should be no error removing peer1 and peer3") + removalExpectation.fulfill() + } + self.wait(for: [removalExpectation], timeout: 5) + self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: peer2) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .excludes, target: peer1ID)), + "peer 2 should distrust peer 1") + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .excludes, target: peer3ID)), + "peer 2 should distrust peer 3") + + // And we notify peer3 about this, and it should become sad + self.sendContainerChangeWaitForFetchForStates(context: peer3, states: [OctagonStateReadyUpdated, OctagonStateUntrusted]) + self.assertEnters(context: peer3, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: peer3) + + XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer3ID, opinion: .excludes, target: peer3ID)), + "peer 3 should distrust peer 3") + + // And if peer3 decides to reupgrade, but it shouldn't: there's no potentially-trusted peer that preapproves it + let upgradeExpectation = self.expectation(description: "sosUpgrade call returns") + peer3.attemptSOSUpgrade() { error in + XCTAssertNotNil(error, "should be an error performing an SOS upgrade (the second time)") + upgradeExpectation.fulfill() + } + self.wait(for: [upgradeExpectation], timeout: 5) + + // And peer3 remains untrusted + self.assertEnters(context: peer3, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfUntrusted(context: peer3) + + // And "wait for upgrade" does something reasonable too + let upgradeWaitExpectation = self.expectation(description: "sosWaitForUpgrade call returns") + peer3.waitForOctagonUpgrade() { error in + XCTAssertNotNil(error, "should be an error waiting for an SOS upgrade (the second time)") + upgradeWaitExpectation.fulfill() + } + self.wait(for: [upgradeWaitExpectation], timeout: 5) + } } #endif // OCTAGON diff --git a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h index 6c83e44d..086a45bc 100644 --- a/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h +++ b/keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h @@ -8,7 +8,9 @@ #import #import -#import +#import "KeychainCircle/KCJoiningSession.h" +#import "KeychainCircle/KCJoiningRequestSession+Internal.h" +#import "KeychainCircle/KCJoiningAcceptSession+Internal.h" #import #import @@ -17,8 +19,8 @@ #import "utilities/SecCFError.h" -#import "securityd/SecItemServer.h" -#import "securityd/spi.h" +#import "keychain/securityd/SecItemServer.h" +#import "keychain/securityd/spi.h" #import #import "keychain/ckks/CKKS.h" @@ -35,6 +37,8 @@ #import "keychain/ot/OTClique.h" #import "keychain/ot/OTControl.h" #import "keychain/ot/OTControlProtocol.h" +#import "keychain/ot/OTManager.h" +#import "keychain/ot/OTClientStateMachine.h" #import "keychain/ot/OTSOSAdapter.h" #import "keychain/ot/OTConstants.h" @@ -45,7 +49,7 @@ #import "keychain/ot/OTDeviceInformationAdapter.h" -#import "keychain/ot/tests/OTTestsBase.h" +#import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h" #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h" #import "keychain/ckks/CKKSKeychainBackedKey.h" diff --git a/keychain/ot/tests/octagon/OctagonTests.swift b/keychain/ot/tests/octagon/OctagonTests.swift index 2a0b2611..0fa46d15 100644 --- a/keychain/ot/tests/octagon/OctagonTests.swift +++ b/keychain/ot/tests/octagon/OctagonTests.swift @@ -18,10 +18,10 @@ class FakeCuttlefishInvocableCreator: ContainerNameToCuttlefishInvocable { } class OTMockDeviceInfoAdapter: OTDeviceInformationAdapter { - let mockModelID: String - let mockDeviceName: String? - let mockOsVersion: String - let mockSerialNumber: String + var mockModelID: String + var mockDeviceName: String? + var mockOsVersion: String + var mockSerialNumber: String init(modelID: String, deviceName: String?, serialNumber: String, osVersion: String) { self.mockModelID = modelID @@ -45,35 +45,11 @@ class OTMockDeviceInfoAdapter: OTDeviceInformationAdapter { func serialNumber() -> String { return self.mockSerialNumber } -} - -class OTMockDeviceInfoAdapterFakeSerial: OTDeviceInformationAdapter -{ - let mockSerialNumber: String - let actualAdapter: OTDeviceInformationActualAdapter - - init() { - mockSerialNumber = NSUUID().uuidString - actualAdapter = OTDeviceInformationActualAdapter() - } - func modelID() -> String { - return self.actualAdapter.modelID() - } - - func deviceName() -> String? { - return self.actualAdapter.deviceName() - } - - func osVersion() -> String { - return self.actualAdapter.osVersion() - } - func serialNumber() -> String { - return self.mockSerialNumber + func register(forDeviceNameUpdates listener: OTDeviceInformationNameUpdateListener) { } } - class OTMockAuthKitAdapter: OTAuthKitAdapter { // A nil altDSID means 'no authkit account' var altDSID: String? @@ -219,15 +195,14 @@ class OTMockSecEscrowRequest: NSObject, SecEscrowRequestable { NotificationCenter.default.post(name: OTMockEscrowRequestNotification, object: nil) } - func fetchStatuses() throws -> [AnyHashable : Any] { + func fetchStatuses() throws -> [AnyHashable: Any] { return statuses } func pendingEscrowUpload(_ error: NSErrorPointer) -> Bool { if statuses["uuid"] == SecEscrowRequestPendingCertificate { return true - } - else { + } else { return false } } @@ -256,6 +231,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { var mockAuthKit2: OTMockAuthKitAdapter! var mockAuthKit3: OTMockAuthKitAdapter! + var mockDeviceInfo: OTMockDeviceInfoAdapter! + var otControl: OTControl! var otXPCProxy: ProxyXPCConnection! var otControlEntitlementBearer: FakeOTControlEntitlementBearer! @@ -275,10 +252,6 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { securityd_init_local_spi() } - func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapterFakeSerial() - } - override func setUp() { // Set the global bool to TRUE OctagonSetIsEnabled(true) @@ -291,6 +264,12 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { // Each test is responsible for initialization, to allow for pre-test setup OctagonSetShouldPerformInitialization(false) + let actualDeviceAdapter = OTDeviceInformationActualAdapter() + self.mockDeviceInfo = OTMockDeviceInfoAdapter(modelID: actualDeviceAdapter.modelID(), + deviceName: actualDeviceAdapter.deviceName(), + serialNumber: NSUUID().uuidString, + osVersion: actualDeviceAdapter.osVersion()) + super.setUp() // Octagon must initialize the views @@ -308,7 +287,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { #endif self.zones!.removeAllObjects() - self.zones![self.manateeZoneID] = FakeCKZone(zone: self.manateeZoneID) + self.zones![self.manateeZoneID!] = FakeCKZone(zone: self.manateeZoneID!) // Asserting a type on self.zones seems to duplicate the dictionary, but not deep-copy the contents // We'll use them as NSMutableDictionaries, I guess @@ -333,17 +312,11 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.mockSOSAdapter.essential = false let tphInterface = TrustedPeersHelperSetupProtocol(NSXPCInterface(with: TrustedPeersHelperProtocol.self)) - self.tphXPCProxy = ProxyXPCConnection(self.tphClient, interface: tphInterface) - - self.manager = OTManager(context: nil, - localStore: nil, - enroll: nil, - restore: nil, - cfu: nil, - cfuScheduler: nil, - sosAdapter: self.mockSOSAdapter, + self.tphXPCProxy = ProxyXPCConnection(self.tphClient!, interface: tphInterface) + + self.manager = OTManager(sosAdapter: self.mockSOSAdapter, authKitAdapter: self.mockAuthKit, - deviceInformationAdapter: deviceInformationAdapter(), + deviceInformationAdapter: self.mockDeviceInfo, apsConnectionClass: FakeAPSConnection.self, escrowRequestClass: OTMockSecEscrowRequest.self, loggerClass: OTMockLogger.self, @@ -359,7 +332,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.otControlEntitlementBearer = FakeOTControlEntitlementBearer() self.otControlEntitlementChecker = OctagonXPCEntitlementChecker.create(with: self.manager, entitlementBearer: self.otControlEntitlementBearer) - self.otXPCProxy = ProxyXPCConnection(self.otControlEntitlementChecker, interface: OTSetupControlProtocol(NSXPCInterface(with: OTControlProtocol.self))) + self.otXPCProxy = ProxyXPCConnection(self.otControlEntitlementChecker!, interface: OTSetupControlProtocol(NSXPCInterface(with: OTControlProtocol.self))) self.otControl = OTControl(connection: self.otXPCProxy.connection(), sync: true) self.otControlCLI = OTControlCLI(otControl: self.otControl) @@ -373,7 +346,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { override func tearDown() { let statusExpectation = self.expectation(description: "status callback occurs") - self.cuttlefishContext.rpcStatus() { _, _ in + self.cuttlefishContext.rpcStatus { _, _ in statusExpectation.fulfill() } self.wait(for: [statusExpectation], timeout: 10) @@ -388,7 +361,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { // Stop all of CKKS self.injectedManager!.haltAll() - XCTAssertTrue(self.manager.allContextsPause(10*NSEC_PER_SEC), "All cuttlefish contexts should pause") + XCTAssertTrue(self.manager.allContextsPause(10 * NSEC_PER_SEC), "All cuttlefish contexts should pause") super.tearDown() } @@ -450,8 +423,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, _ in XCTAssertEqual(egoStatus, .in, "Self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a peerID") XCTAssertEqual(isLocked, isLocked, "should be \(isLocked)") @@ -466,9 +439,9 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { let cachedStatusexpectation = self.expectation(description: "(cached) trust status returns") let configuration = OTOperationConfiguration() configuration.useCachedAccountStatus = true - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ in XCTAssertEqual(egoStatus, .in, "Cached self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a (cached) peerID") cachedStatusexpectation.fulfill() @@ -482,12 +455,12 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { cliqueConfiguration.otControl = self.otControl let otclique = try! OTClique(contextData: cliqueConfiguration) - let status = otclique.cachedCliqueStatus(true, error: nil) + let status = otclique.fetchStatus(nil) XCTAssertEqual(status, .in, "OTClique API should return (trusted)") configuration.useCachedAccountStatus = false let statusexpectation = self.expectation(description: "(cached) trust status returns") - context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ in XCTAssertEqual(egoStatus, .in, "Self peer (for \(context)) should be trusted") XCTAssertNotNil(egoPeerID, "Should have a peerID") statusexpectation.fulfill() @@ -499,8 +472,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { XCTAssertEqual(context.currentMemoizedTrustState(), .UNTRUSTED, "Trust state (for \(context)) should be untrusted") let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC - self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, error in + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC + context.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in // TODO: separate 'untrusted' and 'no trusted peers for account yet' XCTAssertTrue([.notIn, .absent].contains(egoStatus), "Self peer (for \(context)) should be distrusted or absent") statusexpectation.fulfill() @@ -508,13 +481,17 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.wait(for: [statusexpectation], timeout: 10) } + func assertAccountAvailable(context: OTCuttlefishContext) { + XCTAssertEqual(context.currentMemoizedAccountState(), .ACCOUNT_AVAILABLE, "Account state (for \(context)) should be 'available''") + } + func assertNoAccount(context: OTCuttlefishContext) { XCTAssertEqual(context.currentMemoizedAccountState(), .NO_ACCOUNT, "Account state (for \(context)) should be no account") } func assertTrusts(context: OTCuttlefishContext, includedPeerIDCount: Int, excludedPeerIDCount: Int) { let dumpCallback = self.expectation(description: "dump callback occurs") - self.tphClient.dumpEgoPeer(withContainer: context.containerName, context: context.contextID) { peerID, permanentInfo, stableInfo, dynamicInfo, error in + self.tphClient.dumpEgoPeer(withContainer: context.containerName, context: context.contextID) { _, _, _, dynamicInfo, error in XCTAssertNil(error, "should be no error") XCTAssertNotNil(dynamicInfo, "Should be a dynamic info") XCTAssertEqual(dynamicInfo!.includedPeerIDs.count, includedPeerIDCount, "should be \(includedPeerIDCount) included peer ids") @@ -563,7 +540,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { func resetAllCKKSViews() { let resetExpectation = self.expectation(description: "rpcResetCloudKit callback occurs") - self.injectedManager!.rpcResetCloudKit(nil, reason:"octagon=unit-test") { error in + self.injectedManager!.rpcResetCloudKit(nil, reason: "octagon=unit-test") { error in XCTAssertNil(error, "Error should be nil?") resetExpectation.fulfill() } @@ -638,7 +615,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { kSecAttrDescription: label, kSecReturnAttributes: true, kSecReturnData: true, - kSecAttrSynchronizable: kCFBooleanFalse, + kSecAttrSynchronizable: false, kSecMatchLimit: kSecMatchLimitOne, ] @@ -688,7 +665,6 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { ]) } - func sendContainerChangeWaitForFetch(context: OTCuttlefishContext) { self.sendContainerChangeWaitForFetchForStates(context: context, states: [OctagonStateReadyUpdated, OctagonStateReady]) } @@ -697,12 +673,14 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { self.sendContainerChangeWaitForFetchForStates(context: context, states: [OctagonStateUntrustedUpdated, OctagonStateUntrusted]) } - func sendContainerChangeWaitForFetchForState(context: OTCuttlefishContext, state: String) { - return self.sendContainerChangeWaitForFetchForStates(context: context, states: [state]) - } - + // Please ensure that the first state in this list is not the state that the context is currently in func sendContainerChangeWaitForFetchForStates(context: OTCuttlefishContext, states: [String]) { + // Pull the first state out before sending the notification + let firstState = states.first! + let firstCondition = (context.stateMachine.stateConditions[firstState] as! CKKSCondition) + let updateTrustExpectation = self.expectation(description: "fetchChanges") + self.fakeCuttlefishServer.fetchChangesListener = { request in self.fakeCuttlefishServer.fetchChangesListener = nil updateTrustExpectation.fulfill() @@ -710,7 +688,10 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { } context.notifyContainerChange(nil) self.wait(for: [updateTrustExpectation], timeout: 10) - for state in states { + + // Wait for the previously acquired first state, then wait for each in turn + XCTAssertEqual(0, firstCondition.wait(10 * NSEC_PER_SEC), "State machine should enter '\(String(describing: firstState))'") + for state in states.dropFirst() { self.assertEnters(context: context, state: state, within: 10 * NSEC_PER_SEC) } } @@ -729,7 +710,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { func makeInitiatorDeviceInfoAdapter() -> OTMockDeviceInfoAdapter { // Note that the type of your initiator changes based on the platform you're currently on - return OTMockDeviceInfoAdapter(modelID: self.deviceInformationAdapter().modelID(), + return OTMockDeviceInfoAdapter(modelID: self.mockDeviceInfo.modelID(), deviceName: "test-device-2", serialNumber: "456", osVersion: "iSomething (fake version)") @@ -740,22 +721,26 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { } func makeInitiatorContext(contextID: String, authKitAdapter: OTAuthKitAdapter) -> OTCuttlefishContext { + return self.makeInitiatorContext(contextID: contextID, authKitAdapter: authKitAdapter, sosAdapter: self.mockSOSAdapter) + } + + func makeInitiatorContext(contextID: String, authKitAdapter: OTAuthKitAdapter, sosAdapter: OTSOSAdapter) -> OTCuttlefishContext { // Note that the type of your initiator changes based on the platform you're currently on return self.manager.context(forContainerName: OTCKContainerName, contextID: contextID, - sosAdapter: self.mockSOSAdapter, + sosAdapter: sosAdapter, authKitAdapter: authKitAdapter, lockStateTracker: self.lockStateTracker, accountStateTracker: self.accountStateTracker, deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter()) } - func assertResetAndBecomeTrustedInDefaultContext() -> String { + @discardableResult func assertResetAndBecomeTrustedInDefaultContext() -> String { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -802,6 +787,18 @@ class OctagonTestsBase: CloudKitKeychainSyncingTestsBase { return "failed" } } + + func assertSelfOSVersion(_ osVersion: String) { + + let statusExpectation = self.expectation(description: "status callback occurs") + self.tphClient.dumpEgoPeer(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID, reply: { _, _, stableInfo, _, error in + XCTAssertNil(error, "should be no error dumping ego peer") + XCTAssertEqual(stableInfo?.osVersion, osVersion, "os version should be as required") + statusExpectation.fulfill() + }) + + self.wait(for: [statusExpectation], timeout: 2) + } } class OctagonTests: OctagonTestsBase { @@ -913,7 +910,8 @@ class OctagonTests: OctagonTestsBase { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -934,7 +932,7 @@ class OctagonTests: OctagonTestsBase { func testLoadToNoAccount() throws { // No CloudKit account, either - self.accountStatus = .noAccount; + self.accountStatus = .noAccount self.startCKAccountStatusMock() // With no identity and AuthKit reporting no iCloud account, Octagon should go directly into 'no account' @@ -1105,7 +1103,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1125,6 +1123,41 @@ class OctagonTests: OctagonTestsBase { // TODO: add a CKKS item } + func testNewFriendsWithResetReasonForEmptyAccount() throws { + self.startCKAccountStatusMock() + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) + let resetExpectation = self.expectation(description: "resetExpectation") + + self.fakeCuttlefishServer.resetListener = { request in + self.fakeCuttlefishServer.resetListener = nil + resetExpectation.fulfill() + XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.testGenerated.rawValue, "reset reason should be unknown") + return nil + } + + do { + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) + XCTAssertNotNil(clique, "Clique should not be nil") + } catch { + XCTFail("Shouldn't have errored making new friends: \(error)") + } + + self.wait(for: [resetExpectation], timeout: 10) + + // 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... + assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) + self.verifyDatabaseMocks() + + self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) + } + func testCliqueStatusWhileLocked() throws { self.startCKAccountStatusMock() @@ -1132,7 +1165,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1154,20 +1187,18 @@ class OctagonTests: OctagonTestsBase { self.assertConsidersSelfTrusted(context: self.cuttlefishContext, isLocked: false) } - func testDeviceFetchRetry() throws { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.sendContainerChange(context: self.cuttlefishContext) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1187,29 +1218,28 @@ class OctagonTests: OctagonTestsBase { self.startCKAccountStatusMock() self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.fakeCuttlefishServer.nextFetchErrors.append(ckError) self.cuttlefishContext.notifyContainerChange(nil) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") } // Now, we should be in 'ready' - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 20 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext) self.cuttlefishContext.notifyContainerChange(nil) - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 20 * NSEC_PER_SEC) } func testNewFriendsForEmptyAccountReturnsMoreChanges() throws { @@ -1221,7 +1251,7 @@ class OctagonTests: OctagonTestsBase { self.fakeCuttlefishServer.nextEstablishReturnsMoreChanges = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1240,7 +1270,7 @@ class OctagonTests: OctagonTestsBase { } func testNewFriendsForEmptyAccountWithoutTLKsResetsZones() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) // But do NOT add them to the keychain // CKKS+Octagon should reset the zones and be ready @@ -1254,7 +1284,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1270,7 +1300,7 @@ class OctagonTests: OctagonTestsBase { } func testUploadTLKsRetry() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) // But do NOT add them to the keychain // CKKS+Octagon should reset the zones and be ready @@ -1284,7 +1314,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1294,8 +1324,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) self.assertConsidersSelfTrusted(context: self.cuttlefishContext) - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) // and all subCKKSes should enter ready (eventually) @@ -1314,9 +1343,8 @@ class OctagonTests: OctagonTestsBase { self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1333,8 +1361,7 @@ class OctagonTests: OctagonTestsBase { self.resetAllCKKSViews() - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) self.fakeCuttlefishServer.nextUpdateTrustErrors.append(ckError) @@ -1344,17 +1371,16 @@ class OctagonTests: OctagonTestsBase { // these should be failures assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKUpload, within: 10 * NSEC_PER_SEC) - self.cuttlefishContext.rpcStatus() { _, _ in - return - } + self.cuttlefishContext.rpcStatus { _, _ in + } self.verifyDatabaseMocks() XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(60 * NSEC_PER_SEC), "Main cuttlefish context should quiesce before the test ends") } func testNewFriendsForEmptyAccountWithTLKs() throws { - self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID) - self.saveTLKMaterial(toKeychain: self.manateeZoneID) + self.putFakeKeyHierarchy(inCloudKit: self.manateeZoneID!) + self.saveTLKMaterial(toKeychain: self.manateeZoneID!) self.startCKAccountStatusMock() @@ -1370,7 +1396,7 @@ class OctagonTests: OctagonTestsBase { self.silentZoneDeletesAllowed = true do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1394,7 +1420,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1440,7 +1466,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1458,7 +1484,7 @@ class OctagonTests: OctagonTestsBase { let query: [CFString: Any] = [ kSecClass: kSecClassKey, kSecAttrAccessGroup: "com.apple.security.egoIdentities", - kSecUseDataProtectionKeychain: kCFBooleanTrue, + kSecUseDataProtectionKeychain: true, ] let status = SecItemDelete(query as CFDictionary) @@ -1479,7 +1505,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1518,7 +1544,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1554,7 +1580,7 @@ class OctagonTests: OctagonTestsBase { // If CloudKit isn't returning our calls, we should still return something reasonable... let statusexpectation = self.expectation(description: "trust status returns") let configuration = OTOperationConfiguration() - configuration.timeoutWaitForCKAccount = 500*NSEC_PER_MSEC + configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in XCTAssertTrue([.absent].contains(egoStatus), "Self peer should be in the 'absent' state") statusexpectation.fulfill() @@ -1584,7 +1610,7 @@ class OctagonTests: OctagonTestsBase { // Now become ready do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1630,7 +1656,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique? do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1669,7 +1695,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1699,7 +1725,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1785,7 +1811,7 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1807,6 +1833,13 @@ class OctagonTests: OctagonTestsBase { XCTFail("Error thrown: \(error)") } + let peer2DeviceName = "peer2-asdf" + + let peer2DeviceAdapter = OTMockDeviceInfoAdapter(modelID: "AppleTV5,3", + deviceName: peer2DeviceName, + serialNumber: "peer2-asdf", + osVersion: "tvOS (fake version)") + // Now, fake up a voucher for the second peer using TPH let peer2ContextID = "asdf" let peer2 = self.manager.context(forContainerName: OTCKContainerName, @@ -1815,12 +1848,11 @@ class OctagonTests: OctagonTestsBase { authKitAdapter: self.mockAuthKit2, lockStateTracker: self.lockStateTracker, accountStateTracker: self.accountStateTracker, - deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) + deviceInformationAdapter: peer2DeviceAdapter) self.setAllowListToCurrentAuthKit(container: OTCKContainerName, context: peer2ContextID) var peer2ID: String! - let peer2DeviceName = "peer2-asdf" let joinExpectation = self.expectation(description: "join callback occurs") self.tphClient.prepare(withContainer: OTCKContainerName, context: peer2ContextID, @@ -1828,10 +1860,10 @@ class OctagonTests: OctagonTestsBase { machineID: self.mockAuthKit2.currentMachineID, bottleSalt: "123456789", bottleID: UUID().uuidString, - modelID: "AppleTV5,3", - deviceName: peer2DeviceName, - serialNumber: "1234", - osVersion: "something", + modelID: peer2DeviceAdapter.modelID(), + deviceName: peer2DeviceAdapter.deviceName(), + serialNumber: peer2DeviceAdapter.serialNumber(), + osVersion: peer2DeviceAdapter.osVersion(), policyVersion: nil, policySecrets: nil, signingPrivKeyPersistentRef: nil, @@ -1929,7 +1961,7 @@ class OctagonTests: OctagonTestsBase { self.mockAuthKit.altDSID = "1234" let signinExpectation = self.expectation(description: "sign in returns") - self.otControl.sign(in: "1234", container: nil, context:OTDefaultContext) { error in + self.otControl.sign(in: "1234", container: nil, context: OTDefaultContext) { error in XCTAssertNil(error, "error should be nil") signinExpectation.fulfill() } @@ -1945,7 +1977,7 @@ class OctagonTests: OctagonTestsBase { do { let absentClique = try OTClique(contextData: self.otcliqueContext) - let absentStatus = absentClique.cachedCliqueStatus(true, error: nil) + let absentStatus = absentClique.fetchStatus(nil) XCTAssertEqual(absentStatus, CliqueStatus.absent, "clique should return Absent") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -1957,10 +1989,10 @@ class OctagonTests: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") - let status = clique.cachedCliqueStatus(true, error: nil) + let status = clique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.in, "clique should return In") } catch { @@ -1975,7 +2007,7 @@ class OctagonTests: OctagonTestsBase { // Technically, it's a server-side cuttlefish error for the last signed-in peer to leave. But, for now, just go for it. XCTAssertNoThrow(try clique.leave(), "Should be no error departing clique") self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) - let status = clique.cachedCliqueStatus(true, error: nil) + let status = clique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.notIn, "clique should return Not In") let newOTCliqueContext = OTConfigurationContext() @@ -1986,11 +2018,11 @@ class OctagonTests: OctagonTestsBase { let newClique: OTClique do { - newClique = try OTClique.newFriends(withContextData: newOTCliqueContext) + newClique = try OTClique.newFriends(withContextData: newOTCliqueContext, resetReason: .testGenerated) XCTAssertNotNil(newClique, "newClique should not be nil") OctagonSetPlatformSupportsSOS(true) - let status = newClique.cachedCliqueStatus(true, error: nil) + let status = newClique.fetchStatus(nil) XCTAssertEqual(status, CliqueStatus.in, "clique should return In") } catch { @@ -2010,7 +2042,7 @@ class OctagonTests: OctagonTestsBase { json: false) do { - _ = try OTClique.newFriends(withContextData: self.otcliqueContext) + _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) } catch { XCTFail("failed to make new friends: \(error)") @@ -2030,7 +2062,7 @@ class OctagonTests: OctagonTestsBase { // Run initialization, like the real secd will do OctagonInitialize() - self.cuttlefishContext.stateMachine.setWatcherTimeout(2*NSEC_PER_SEC); + self.cuttlefishContext.stateMachine.setWatcherTimeout(2 * NSEC_PER_SEC) self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC) XCTAssertTrue(self.cuttlefishContext.stateMachine.isPaused(), "State machine should be stopped") @@ -2075,7 +2107,7 @@ class OctagonTests: OctagonTestsBase { // and now cause the watcher to fail... let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns") - self.cuttlefishContext.rpcResetAndEstablish() { resetError in + self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "should be no error resetting and establishing") resetAndEstablishExpectation.fulfill() } @@ -2089,14 +2121,14 @@ class OctagonTests: OctagonTestsBase { func testLeaveCliqueAndPostCFU() throws { self.startCKAccountStatusMock() - + OctagonAuthoritativeTrustSetIsEnabled(true) self.cuttlefishContext.startOctagonStateMachine() self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2116,7 +2148,7 @@ class OctagonTests: OctagonTestsBase { let cfuExpectation = self.expectation(description: "cfu callback occurs") self.cuttlefishContext.setPostedBool(false) - self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary() { status, posted, egoPeerID, error in + self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary { _, posted, _, error in #if !os(tvOS) XCTAssertTrue(posted, "posted should be true") #else @@ -2127,7 +2159,7 @@ class OctagonTests: OctagonTestsBase { } self.wait(for: [cfuExpectation], timeout: 10) } - + func testDeviceLockedDuringAccountRetrieval() throws { self.startCKAccountStatusMock() @@ -2163,7 +2195,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2182,7 +2214,6 @@ class OctagonTests: OctagonTestsBase { self.fakeCuttlefishServer.deleteAllPeers() self.sendContainerChange(context: self.cuttlefishContext) - self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) } @@ -2192,7 +2223,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2238,7 +2269,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2265,7 +2296,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2321,7 +2352,8 @@ class OctagonTests: OctagonTestsBase { handler: nil) self.manager.resetAndEstablish(containerName, context: contextName, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -2334,6 +2366,138 @@ class OctagonTests: OctagonTestsBase { self.wait(for: [trustedNotification], timeout: 2) } + func testDeviceNameNotifications() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let newDeviceName = "new-name-testDeviceNameNotifications" + self.mockDeviceInfo.mockDeviceName = newDeviceName + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.deviceName, newDeviceName, "name should be updated") + updateTrustExpectation.fulfill() + + return nil + } + + self.cuttlefishContext.deviceNameUpdated() + self.wait(for: [updateTrustExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + let statusExpectation = self.expectation(description: "status callback occurs") + self.tphClient.dumpEgoPeer(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID, reply: { _, _, stableInfo, _, error in + XCTAssertNil(error, "should be no error dumping ego peer") + XCTAssertEqual(stableInfo?.deviceName, newDeviceName, "device name should be updated") + statusExpectation.fulfill() + }) + self.wait(for: [statusExpectation], timeout: 2) + + // Receiving a push shouldn't cause another update to be sent + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testUpdateDeviceOSVersionOnRestart() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let differentVersion = "iOS (different version)" + self.mockDeviceInfo.mockOsVersion = differentVersion + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.osVersion, differentVersion, "version should be updated") + + updateTrustExpectation.fulfill() + return nil + } + + self.aksLockState = true + self.lockStateTracker.recheck() + + // re-start + self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC) + + self.aksLockState = false + self.lockStateTracker.recheck() + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + + self.wait(for: [updateTrustExpectation], timeout: 10) + + // Double check that version + self.assertSelfOSVersion(differentVersion) + + // Second restart should not trigger an update + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + // re-start + self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext) + + self.cuttlefishContext.startOctagonStateMachine() + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + + func testUpdateDeviceOSVersionOnContainerUpdate() throws { + self.startCKAccountStatusMock() + + self.assertResetAndBecomeTrustedInDefaultContext() + + let differentVersion = "iOS (different version)" + self.mockDeviceInfo.mockOsVersion = differentVersion + + let updateTrustExpectation = self.expectation(description: "updateTrust") + self.fakeCuttlefishServer.updateListener = { request in + XCTAssertTrue(request.hasStableInfoAndSig, "updateTrust request should have a stableInfo info") + let newStableInfo = TPPeerStableInfo(data: request.stableInfoAndSig.peerStableInfo, sig: request.stableInfoAndSig.sig) + XCTAssertNotNil(newStableInfo, "should be able to make a stableInfo info from protobuf") + XCTAssertEqual(newStableInfo?.osVersion, differentVersion, "version should be updated") + + updateTrustExpectation.fulfill() + return nil + } + self.cuttlefishContext.notifyContainerChange(nil) + self.wait(for: [updateTrustExpectation], timeout: 10) + + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + self.assertConsidersSelfTrusted(context: self.cuttlefishContext) + + self.assertSelfOSVersion(differentVersion) + + // Receiving a push shouldn't cause another update to be sent + self.fakeCuttlefishServer.updateListener = { request in + XCTFail("Shouldn't have received another updateTrust") + return nil + } + + self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext) + self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) + } + func testAPSRateLimiter() throws { let untrustedNotification = XCTDarwinNotificationExpectation(notificationName: octagonNotificationName) @@ -2392,7 +2556,8 @@ class OctagonTests: OctagonTestsBase { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.manager.resetAndEstablish(OTCKContainerName, context: OTDefaultContext, - altDSID: "new altDSID") { resetError in + altDSID: "new altDSID", + resetReason: .testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -2432,7 +2597,7 @@ class OctagonTests: OctagonTestsBase { self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC) do { - let clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2472,7 +2637,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2571,7 +2736,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { let clique: OTClique do { - clique = try OTClique.newFriends(withContextData: self.otcliqueContext) + clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated) XCTAssertNotNil(clique, "Clique should not be nil") } catch { XCTFail("Shouldn't have errored making new friends: \(error)") @@ -2672,14 +2837,14 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase { self.fakeCuttlefishServer.updateListener = nil self.sendAllCKKSTrustedPeersChanged() - self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10*NSEC_PER_SEC) + self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC) self.verifyDatabaseMocks() } } } } -class OctagonTestsOverrideModelTV: OctagonTestsOverrideModelBase { +class OctagonTestsOverrideModletV: OctagonTestsOverrideModelBase { // If this test is running on a TV, we will send TLKs, since we're using the LimitedPeersAllowed view #if !os(tvOS) let sendTLKsToAllPeers = false @@ -2687,20 +2852,25 @@ class OctagonTestsOverrideModelTV: OctagonTestsOverrideModelBase { let sendTLKsToAllPeers = true #endif - override func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapter(modelID: "AppleTV5,3", deviceName: "intro-TV", serialNumber: "456", osVersion: "iOS (whatever TV version)") + override func setUp() { + super.setUp() + + self.mockDeviceInfo.mockModelID = "AppleTV5,3" + self.mockDeviceInfo.mockDeviceName = "intro-TV" + self.mockDeviceInfo.mockSerialNumber = "456" + self.mockDeviceInfo.mockOsVersion = "iOS (whatever TV version)" } func testVoucherFromTV() throws { try self._testVouchers(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: false, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers), ]) } func testJoinFromTV() throws { try self._testJoin(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: false, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: false, sendTLKs: sendTLKsToAllPeers), ]) } } @@ -2711,20 +2881,25 @@ class OctagonTestsOverrideModelMac: OctagonTestsOverrideModelBase { let sendTLKsToAllPeers = true #endif - override func deviceInformationAdapter() -> OTDeviceInformationAdapter { - return OTMockDeviceInfoAdapter(modelID: "Mac17", deviceName: "macbook", serialNumber: "456", osVersion: "OSX 11") + override func setUp() { + super.setUp() + + self.mockDeviceInfo.mockModelID = "Mac17" + self.mockDeviceInfo.mockDeviceName = "macbook" + self.mockDeviceInfo.mockSerialNumber = "456" + self.mockDeviceInfo.mockOsVersion = "OSX 11" } func testVoucherFromMac() throws { try self._testVouchers(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: true, sendTLKs: sendTLKsToAllPeers), - TestCase(model: "Watch17", success: true, sendTLKs: sendTLKsToAllPeers)]) + TestCase(model: "Watch17", success: true, sendTLKs: sendTLKsToAllPeers), ]) } func testJoinFromMac() throws { try self._testJoin(expectations: [TestCase(model: "AppleTV5,3", success: true, sendTLKs: sendTLKsToAllPeers), TestCase(model: "MacFoo", success: true, sendTLKs: true), - TestCase(model: "Watch17", success: true, sendTLKs: true)]) + TestCase(model: "Watch17", success: true, sendTLKs: true), ]) } } diff --git a/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift b/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift index 364e8117..a972b584 100644 --- a/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift +++ b/keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift @@ -13,7 +13,7 @@ class ProxyXPCConnection: NSObject, NSXPCListenerDelegate { self.listener = NSXPCListener.anonymous() super.init() - self.listener.delegate = self; + self.listener.delegate = self self.listener.resume() } diff --git a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift index 3e4d1147..1103b6a9 100644 --- a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift +++ b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift @@ -3,9 +3,9 @@ extension OctagonPairingTests { func assertSOSSuccess() { - XCTAssertNotNil(self.fcInitiator?.accountPrivateKey ?? nil, "no accountPrivateKey in fcInitiator"); - XCTAssertNotNil(self.fcAcceptor?.accountPrivateKey ?? nil, "no accountPrivateKey in fcAcceptor"); - XCTAssert(CFEqualSafe(self.fcInitiator.accountPrivateKey, self.fcAcceptor.accountPrivateKey), "no accountPrivateKey not same in both"); + XCTAssertNotNil(self.fcInitiator?.accountPrivateKey, "no accountPrivateKey in fcInitiator") + XCTAssertNotNil(self.fcAcceptor?.accountPrivateKey, "no accountPrivateKey in fcAcceptor") + XCTAssert(CFEqualSafe(self.fcInitiator.accountPrivateKey, self.fcAcceptor.accountPrivateKey), "no accountPrivateKey not same in both") XCTAssert(SOSCircleHasPeer(self.circle, self.fcInitiator.peerInfo(), nil), "HasPeer 1") // XCTAssert(SOSCircleHasPeer(self.circle, self.fcAcceptor.peerInfo(), nil), "HasPeer 2") @@ -205,8 +205,7 @@ extension OctagonPairingTests { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) /* calling Join */ - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) @@ -321,8 +320,10 @@ extension OctagonPairingTests { self.assertConsidersSelfUntrusted(context: self.cuttlefishContext) /* calling Join */ - let cuttlefishError = NSError(domain: CuttlefishErrorDomain, code: CuttlefishErrorCode.transactionalFailure.rawValue, userInfo: nil) - let ckError = NSError(domain: CKInternalErrorDomain, code: CKInternalErrorCode.errorInternalPluginError.rawValue, userInfo: [NSUnderlyingErrorKey: cuttlefishError]) + let ckError = FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .transactionalFailure) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) + self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) self.fakeCuttlefishServer.nextJoinErrors.append(ckError) @@ -336,7 +337,7 @@ extension OctagonPairingTests { XCTAssertNotNil(error, "error should be set") rpcJoinCallbackOccurs.fulfill() } - self.wait(for: [rpcJoinCallbackOccurs], timeout: 64) + self.wait(for: [rpcJoinCallbackOccurs], timeout: 35) } func testJoinWithCKKSConflict() { @@ -639,7 +640,7 @@ extension OctagonPairingTests { self.startCKAccountStatusMock() let rpcCallbackOccurs = self.expectation(description: "rpcPrepare callback occurs") - self.initiatorPairingConfig.timeout = Int64(2*NSEC_PER_SEC) + self.initiatorPairingConfig.timeout = Int64(2 * NSEC_PER_SEC) self.cuttlefishContext.rpcPrepareIdentityAsApplicant(with: self.initiatorPairingConfig, epoch: 1) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, error in XCTAssertNotNil(error, "Should be an error calling 'prepare'") @@ -714,7 +715,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -729,7 +729,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -858,7 +857,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -873,7 +871,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1000,7 +997,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1015,7 +1011,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1106,7 +1101,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1121,7 +1115,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1349,7 +1342,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1421,7 +1413,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1436,7 +1427,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1506,7 +1496,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - /* INITIATOR SECOND RTT PREPARE*/ var initiatorSecondPacket = Data() let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") @@ -1521,7 +1510,6 @@ extension OctagonPairingTests { self.wait(for: [secondInitiatorCallback], timeout: 10) - /* ACCEPTOR SECOND RTT */ var acceptorSecondPacket = Data() let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") @@ -1574,7 +1562,7 @@ extension OctagonPairingTests { acceptor.startOctagonStateMachine() let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") - acceptor.rpcResetAndEstablish() { resetError in + acceptor.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } @@ -1585,145 +1573,7 @@ extension OctagonPairingTests { self.assertConsidersSelfTrusted(context: acceptor) XCTAssertEqual(self.fakeCuttlefishServer.state.bottles.count, 1, "should be 1 bottles") } - /* TODO: FIX ME!!!! - func testOctagonUpgradeAfterReceivingSOSCCCircleChangedNotification() throws { - OctagonSetPlatformSupportsSOS(true) - OctagonSetIsEnabled(false) - OctagonAuthoritativeTrustSetIsEnabled(true) - OctagonSetSOSUpgrade(true) - self.startCKAccountStatusMock() - - self.manager.initializeOctagon() - - let (acceptor, initiator) = self.setupPairingEndpoints(withPairNumber: "1", initiatorContextID: OTDefaultContext, acceptorContextID: self.contextForAcceptor, initiatorUniqueID: self.initiatorName, acceptorUniqueID: "acceptor-2") - - XCTAssertNotNil(acceptor, "acceptor should not be nil") - XCTAssertNotNil(initiator, "initiator should not be nil") - - /* INITIATOR FIRST RTT JOINING MESSAGE*/ - var initiatorFirstPacket = Data() - let firstInitiatorCallback = self.expectation(description: "firstInitiatorCallback callback occurs") - - initiator.exchangePacket(nil) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorFirstPacket = packet! - firstInitiatorCallback.fulfill() - } - - self.wait(for: [firstInitiatorCallback], timeout: 10) - - /* ACCEPTOR FIRST RTT EPOCH*/ - var acceptorFirstPacket = Data() - let firstAcceptorCallback = self.expectation(description: "firstAcceptorCallback callback occurs") - - acceptor.exchangePacket(initiatorFirstPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorFirstPacket = packet! - firstAcceptorCallback.fulfill() - } - self.wait(for: [firstAcceptorCallback], timeout: 10) - - - /* INITIATOR SECOND RTT PREPARE*/ - var initiatorSecondPacket = Data() - let secondInitiatorCallback = self.expectation(description: "secondInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorFirstPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorSecondPacket = packet! - secondInitiatorCallback.fulfill() - } - - self.wait(for: [secondInitiatorCallback], timeout: 10) - - - try self.circleAndSOS() - - /* ACCEPTOR SECOND RTT */ - var acceptorSecondPacket = Data() - let SecondAcceptorCallback = self.expectation(description: "SecondAcceptorCallback callback occurs") - acceptor.exchangePacket(initiatorSecondPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorSecondPacket = packet! - SecondAcceptorCallback.fulfill() - } - self.wait(for: [SecondAcceptorCallback], timeout: 10) - XCTAssertNotNil(acceptorSecondPacket, "acceptor second packet should not be nil") - - /* INITIATOR THIRD STEP*/ - var initiatorThirdPacket: Data? - let thirdInitiatorCallback = self.expectation(description: "thirdInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorSecondPacket) { complete, packet, error in - XCTAssertFalse(complete, "should be false") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - initiatorThirdPacket = packet! - thirdInitiatorCallback.fulfill() - } - self.wait(for: [thirdInitiatorCallback], timeout: 10) - XCTAssertNotNil(initiatorThirdPacket, "acceptor second packet should not be nil") - - /* ACCEPTOR THIRD RTT */ - var acceptorThirdPacket = Data() - let ThirdAcceptorCallback = self.expectation(description: "ThirdAcceptorCallback callback occurs") - - acceptor.exchangePacket(initiatorSecondPacket) { complete, packet, error in - XCTAssertTrue(complete, "should be true") - XCTAssertNotNil(packet, "packet should not be nil") - XCTAssertNil(error, "error should be nil") - acceptorThirdPacket = packet! - ThirdAcceptorCallback.fulfill() - } - self.wait(for: [ThirdAcceptorCallback], timeout: 10) - XCTAssertNotNil(acceptorThirdPacket, "acceptor third packet should not be nil") - - /* INITIATOR Fourth STEP*/ - let fourthInitiatorCallback = self.expectation(description: "fourthInitiatorCallback callback occurs") - - initiator.exchangePacket(acceptorThirdPacket) { complete, packet, error in - XCTAssertTrue(complete, "should be true") - XCTAssertNil(packet, "packet should be nil") - XCTAssertNil(error, "error should be nil") - fourthInitiatorCallback.fulfill() - } - self.wait(for: [fourthInitiatorCallback], timeout: 10) - - let peerInfo: SOSPeerInfoRef = SOSFullPeerInfoGetPeerInfo(self.fcInitiator.fullPeerInfo) - let encryptionKey = _SFECKeyPair.init(secKey: self.fcInitiator.octagonEncryptionKey) - let signingKey = _SFECKeyPair.init(secKey: self.fcInitiator.octagonSigningKey) - let peerID: NSString = (SOSPeerInfoGetPeerID(peerInfo) .takeUnretainedValue() as NSString) - let initiatorSOSPeer = CKKSSOSSelfPeer(sosPeerID: peerID as String, - encryptionKey: encryptionKey, - signingKey: signingKey) - self.mockSOSAdapter.trustedPeers.add(initiatorSOSPeer) - - let mockSOS = CKKSMockSOSPresentAdapter(selfPeer: initiatorSOSPeer, trustedPeers: self.mockSOSAdapter.allPeers(), essential: false) - mockSOS.circleStatus = SOSCCStatus(kSOSCCInCircle) - let initiatorContext = self.manager.context(forContainerName: OTCKContainerName, - contextID: OTDefaultContext, - sosAdapter: mockSOS, - authKitAdapter: self.mockAuthKit2, - lockStateTracker: self.lockStateTracker, - accountStateTracker: self.accountStateTracker, - deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)")) - - self.manager.moveToCheckTrustedState(forContainer: OTCKContainerName, context: OTDefaultContext) - - //test circle changed notification fired - self.assertEnters(context: initiatorContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC) - self.verifyDatabaseMocks() - } -*/ func testProximitySetupUsingCliqueAcceptorResolvesVersionToSOSOnly() { self.startCKAccountStatusMock() @@ -1787,7 +1637,6 @@ extension OctagonPairingTests { } self.wait(for: [firstAcceptorCallback], timeout: 10) - initiator.setSessionSupportsOctagonForTesting(false) /* INITIATOR SECOND RTT PREPARE*/ diff --git a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift index deb56286..ea84fc76 100644 --- a/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift +++ b/keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift @@ -78,6 +78,7 @@ class KCJoiningRequestTestDelegate: NSObject, KCJoiningRequestSecretDelegate, KC } class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate { + var secrets: Array = [] var currentSecret: Int = 0 var retriesLeft: Int = 0 @@ -157,7 +158,7 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo } } - func circleGetInitialSyncViews(_ error: NSErrorPointer) -> Data { + func circleGetInitialSyncViews(_ flags: SOSInitialSyncFlags, error: NSErrorPointer) -> Data { return Data() } } @@ -206,7 +207,7 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo func getAcceptorInCircle() { let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs") self.cuttlefishContextForAcceptor.startOctagonStateMachine() - self.cuttlefishContextForAcceptor.rpcResetAndEstablish() { resetError in + self.cuttlefishContextForAcceptor.rpcResetAndEstablish(.testGenerated) { resetError in XCTAssertNil(resetError, "Should be no error calling resetAndEstablish") resetAndEstablishExpectation.fulfill() } diff --git a/keychain/otctl/OTControlCLI.m b/keychain/otctl/OTControlCLI.m index ac949dff..5fa418c4 100644 --- a/keychain/otctl/OTControlCLI.m +++ b/keychain/otctl/OTControlCLI.m @@ -184,6 +184,7 @@ static void print_json(NSDictionary* dict) [self.control resetAndEstablish:container context:contextID altDSID:altDSID + resetReason:CuttlefishResetReasonUserInitiatedReset reply:^(NSError* _Nullable error) { if(error) { printf("Error resetting: %s\n", [[error description] UTF8String]); diff --git a/keychain/otpaird/OTPairingConstants.h b/keychain/otpaird/OTPairingConstants.h index e5de4f7f..309ee32a 100644 --- a/keychain/otpaird/OTPairingConstants.h +++ b/keychain/otpaird/OTPairingConstants.h @@ -38,3 +38,5 @@ enum { #define OTPairingXPCActivityInterval XPC_ACTIVITY_INTERVAL_1_HOUR #define OTPairingXPCActivityPoke "com.apple.security.otpaird.poke" + +#define OTPairingXPCEventIDSDeviceState "ids-device-state" diff --git a/keychain/otpaird/OTPairingService.h b/keychain/otpaird/OTPairingService.h index 61c41c56..0cd8b1d7 100644 --- a/keychain/otpaird/OTPairingService.h +++ b/keychain/otpaird/OTPairingService.h @@ -5,6 +5,8 @@ typedef void (^OTPairingCompletionHandler)(bool success, NSError *error); @interface OTPairingService : NSObject +@property (readonly) NSString *pairedDeviceNotificationName; + + (instancetype)sharedService; #if TARGET_OS_WATCH diff --git a/keychain/otpaird/OTPairingService.m b/keychain/otpaird/OTPairingService.m index 22f1bbeb..c1b70852 100644 --- a/keychain/otpaird/OTPairingService.m +++ b/keychain/otpaird/OTPairingService.m @@ -60,6 +60,18 @@ return self; } +- (NSString *)pairedDeviceNotificationName +{ + NSString *result = nil; + for (IDSDevice *device in self.service.devices) { + if (device.isDefaultPairedDevice) { + result = [NSString stringWithFormat:@"ids-device-state-%@", device.uniqueIDOverride]; + break; + } + } + return result; +} + #if TARGET_OS_WATCH - (void)initiatePairingWithCompletion:(OTPairingCompletionHandler)completionHandler { @@ -174,6 +186,12 @@ NSString *responseIdentifier; os_log(OS_LOG_DEFAULT, "exchangePacket: complete=%d responsePacket=%@ channelError=%@", complete, responsePacket, channelError); + + if (self.session == nil) { + os_log(OS_LOG_DEFAULT, "pairing session went away, dropping exchangePacket response"); + return; + } + if (channelError != nil) { #if TARGET_OS_IOS NSError *cleansedError = [SecXPCHelper cleanseErrorForXPC:channelError]; diff --git a/keychain/otpaird/main.m b/keychain/otpaird/main.m index ec1ed214..02246c11 100644 --- a/keychain/otpaird/main.m +++ b/keychain/otpaird/main.m @@ -3,7 +3,6 @@ #import #import #if TARGET_OS_WATCH -#import #import #endif /* TARGET_OS_WATCH */ @@ -12,9 +11,11 @@ #if TARGET_OS_WATCH static void create_xpc_listener(xpc_handler_t handler); -static bool should_retry(NSError *error); +static void handle_pairing_result(bool success, NSError *error); static void pairing_retry_register(bool checkin); static void pairing_retry_unregister(void); +static void ids_retry_init(void); +static void ids_retry_enable(bool); #endif /* TARGET_OS_WATCH */ int @@ -30,6 +31,8 @@ main() /* Check in; handle a possibly-pending retry. */ pairing_retry_register(true); + ids_retry_init(); + create_xpc_listener(^(xpc_object_t message) { xpc_object_t reply; @@ -55,10 +58,7 @@ main() connection = xpc_dictionary_get_remote_connection(reply); xpc_connection_send_message(connection, reply); - // Retry on failure - unless we were already in - if (!success && should_retry(error)) { - pairing_retry_register(false); - } + handle_pairing_result(success, error); }]; }); #endif /* TARGET_OS_WATCH */ @@ -98,26 +98,51 @@ create_xpc_listener(xpc_handler_t handler) xpc_connection_activate(listener); } -static bool -should_retry(NSError *error) +static void +handle_pairing_result(bool success, NSError *error) { - bool retry; - - if ([error.domain isEqualToString:OTPairingErrorDomain]) { - switch (error.code) { - case OTPairingErrorTypeAlreadyIn: - case OTPairingErrorTypeBusy: - retry = false; - break; - default: - retry = true; - break; - } + bool actual_success = false; + bool standard_retry = false; + bool ids_retry = false; + + if (success) { + actual_success = true; } else { - retry = true; + if ([error.domain isEqualToString:OTPairingErrorDomain]) { + switch (error.code) { + /* AlreadyIn: Treat like success; unregister all retries. */ + case OTPairingErrorTypeAlreadyIn: + actual_success = true; + break; + /* Busy: In progress. Do nothing, leave any configured retries. */ + case OTPairingErrorTypeBusy: + break; + /* IDS error. Set up IDS retry _and_ standard retry. */ + case OTPairingErrorTypeIDS: + standard_retry = true; + ids_retry = true; + break; + /* Other error, standard retry. */ + default: + standard_retry = true; + break; + } + } else { + standard_retry = true; + } } - return retry; + if (actual_success) { + pairing_retry_unregister(); + ids_retry_enable(false); + } else { + if (standard_retry) { + pairing_retry_register(false); + } + if (ids_retry) { + ids_retry_enable(true); + } + } } static void @@ -164,4 +189,53 @@ pairing_retry_unregister(void) { xpc_activity_unregister(OTPairingXPCActivityIdentifier); } + +static void +ids_retry_init(void) +{ + xpc_set_event_stream_handler("com.apple.notifyd.matching", dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t event) { + const char *name; + uint64_t state; + + name = xpc_dictionary_get_string(event, XPC_EVENT_KEY_NAME); + if (strcmp(name, OTPairingXPCEventIDSDeviceState) != 0) { + return; + } + + state = xpc_dictionary_get_uint64(event, "_State"); + if ((state & kIDSDeviceStatePropertiesIsNearby) && (state & kIDSDeviceStatePropertiesIsConnected)) { + OTPairingService *service = [OTPairingService sharedService]; + os_log(OS_LOG_DEFAULT, "IDS paired device is connected, retrying"); + [service initiatePairingWithCompletion:^(bool success, NSError *error) { + if (success) { + os_log(OS_LOG_DEFAULT, "IDS notification retry succeeded"); + } else { + os_log(OS_LOG_DEFAULT, "IDS notification retry failed: %@", error); + } + handle_pairing_result(success, error); + }]; + } + }); +} + +static void +ids_retry_enable(bool enable) +{ + const char *notification; + xpc_object_t dict; + + @autoreleasepool { + if (enable) { + notification = [OTPairingService sharedService].pairedDeviceNotificationName.UTF8String; + if (notification != NULL) { + dict = xpc_dictionary_create(NULL, NULL, 0); + xpc_dictionary_set_string(dict, "Notification", notification); + } + } else { + dict = NULL; + } + + xpc_set_event("com.apple.notifyd.matching", OTPairingXPCEventIDSDeviceState, dict); + } +} #endif /* TARGET_OS_WATCH */ diff --git a/OSX/sec/securityd/CheckV12DevEnabled.h b/keychain/securityd/CheckV12DevEnabled.h similarity index 100% rename from OSX/sec/securityd/CheckV12DevEnabled.h rename to keychain/securityd/CheckV12DevEnabled.h diff --git a/OSX/sec/securityd/CheckV12DevEnabled.m b/keychain/securityd/CheckV12DevEnabled.m similarity index 100% rename from OSX/sec/securityd/CheckV12DevEnabled.m rename to keychain/securityd/CheckV12DevEnabled.m diff --git a/OSX/sec/securityd/Info-macOS.plist b/keychain/securityd/Info-macOS.plist similarity index 100% rename from OSX/sec/securityd/Info-macOS.plist rename to keychain/securityd/Info-macOS.plist diff --git a/OSX/sec/securityd/PolicyReporter.h b/keychain/securityd/PolicyReporter.h similarity index 100% rename from OSX/sec/securityd/PolicyReporter.h rename to keychain/securityd/PolicyReporter.h diff --git a/OSX/sec/securityd/PolicyReporter.m b/keychain/securityd/PolicyReporter.m similarity index 100% rename from OSX/sec/securityd/PolicyReporter.m rename to keychain/securityd/PolicyReporter.m diff --git a/OSX/sec/securityd/Regressions/SOSAccountTesting.h b/keychain/securityd/Regressions/SOSAccountTesting.h similarity index 100% rename from OSX/sec/securityd/Regressions/SOSAccountTesting.h rename to keychain/securityd/Regressions/SOSAccountTesting.h diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.h b/keychain/securityd/Regressions/SOSTransportTestTransports.h similarity index 100% rename from OSX/sec/securityd/Regressions/SOSTransportTestTransports.h rename to keychain/securityd/Regressions/SOSTransportTestTransports.h diff --git a/OSX/sec/securityd/Regressions/SOSTransportTestTransports.m b/keychain/securityd/Regressions/SOSTransportTestTransports.m similarity index 100% rename from OSX/sec/securityd/Regressions/SOSTransportTestTransports.m rename to keychain/securityd/Regressions/SOSTransportTestTransports.m diff --git a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c b/keychain/securityd/Regressions/SecdTestKeychainUtilities.c similarity index 98% rename from OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c rename to keychain/securityd/Regressions/SecdTestKeychainUtilities.c index ae4e9877..b5700649 100644 --- a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.c +++ b/keychain/securityd/Regressions/SecdTestKeychainUtilities.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include diff --git a/OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h b/keychain/securityd/Regressions/SecdTestKeychainUtilities.h similarity index 100% rename from OSX/sec/securityd/Regressions/SecdTestKeychainUtilities.h rename to keychain/securityd/Regressions/SecdTestKeychainUtilities.h diff --git a/OSX/sec/securityd/Regressions/ios6_1_keychain_2_db.h b/keychain/securityd/Regressions/ios6_1_keychain_2_db.h similarity index 100% rename from OSX/sec/securityd/Regressions/ios6_1_keychain_2_db.h rename to keychain/securityd/Regressions/ios6_1_keychain_2_db.h diff --git a/OSX/sec/securityd/Regressions/ios8-inet-keychain-2.h b/keychain/securityd/Regressions/ios8-inet-keychain-2.h similarity index 100% rename from OSX/sec/securityd/Regressions/ios8-inet-keychain-2.h rename to keychain/securityd/Regressions/ios8-inet-keychain-2.h diff --git a/OSX/sec/securityd/Regressions/sd-10-policytree.m b/keychain/securityd/Regressions/sd-10-policytree.m similarity index 98% rename from OSX/sec/securityd/Regressions/sd-10-policytree.m rename to keychain/securityd/Regressions/sd-10-policytree.m index 682f8305..43a435a5 100644 --- a/OSX/sec/securityd/Regressions/sd-10-policytree.m +++ b/keychain/securityd/Regressions/sd-10-policytree.m @@ -2,7 +2,7 @@ * Copyright (c) 2009,2012 Apple Inc. All Rights Reserved. */ -#include +#include "trust/trustd/policytree.h" #include #include diff --git a/OSX/sec/securityd/Regressions/secd-01-items.m b/keychain/securityd/Regressions/secd-01-items.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-01-items.m rename to keychain/securityd/Regressions/secd-01-items.m index ffd19e82..a84b48b5 100644 --- a/OSX/sec/securityd/Regressions/secd-01-items.m +++ b/keychain/securityd/Regressions/secd-01-items.m @@ -25,8 +25,8 @@ #include "secd_regressions.h" -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m b/keychain/securityd/Regressions/secd-02-upgrade-while-locked.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m rename to keychain/securityd/Regressions/secd-02-upgrade-while-locked.m index e6e17a34..e57931b1 100644 --- a/OSX/sec/securityd/Regressions/secd-02-upgrade-while-locked.m +++ b/keychain/securityd/Regressions/secd-02-upgrade-while-locked.m @@ -24,14 +24,14 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #include #include #include -#include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" #include diff --git a/OSX/sec/securityd/Regressions/secd-03-corrupted-items.m b/keychain/securityd/Regressions/secd-03-corrupted-items.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-03-corrupted-items.m rename to keychain/securityd/Regressions/secd-03-corrupted-items.m index a8b81f52..7addd192 100644 --- a/OSX/sec/securityd/Regressions/secd-03-corrupted-items.m +++ b/keychain/securityd/Regressions/secd-03-corrupted-items.m @@ -24,14 +24,14 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #include #include #include -#include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" #include diff --git a/OSX/sec/securityd/Regressions/secd-04-corrupted-items.m b/keychain/securityd/Regressions/secd-04-corrupted-items.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-04-corrupted-items.m rename to keychain/securityd/Regressions/secd-04-corrupted-items.m index 1e5d3aac..2c7db55c 100644 --- a/OSX/sec/securityd/Regressions/secd-04-corrupted-items.m +++ b/keychain/securityd/Regressions/secd-04-corrupted-items.m @@ -24,13 +24,13 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #include #include -#include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecItemServer.h" #include diff --git a/OSX/sec/securityd/Regressions/secd-05-corrupted-items.m b/keychain/securityd/Regressions/secd-05-corrupted-items.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-05-corrupted-items.m rename to keychain/securityd/Regressions/secd-05-corrupted-items.m index 756ddb70..7e190934 100644 --- a/OSX/sec/securityd/Regressions/secd-05-corrupted-items.m +++ b/keychain/securityd/Regressions/secd-05-corrupted-items.m @@ -32,13 +32,13 @@ #import "secd_regressions.h" #import -#import +#import "keychain/securityd/SecDbItem.h" #import #import #import #import -#import +#import "keychain/securityd/SecItemServer.h" #import diff --git a/OSX/sec/securityd/Regressions/secd-100-initialsync.m b/keychain/securityd/Regressions/secd-100-initialsync.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-100-initialsync.m rename to keychain/securityd/Regressions/secd-100-initialsync.m index ed92a2f4..64557741 100644 --- a/OSX/sec/securityd/Regressions/secd-100-initialsync.m +++ b/keychain/securityd/Regressions/secd-100-initialsync.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-130-other-peer-views.m b/keychain/securityd/Regressions/secd-130-other-peer-views.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-130-other-peer-views.m rename to keychain/securityd/Regressions/secd-130-other-peer-views.m diff --git a/OSX/sec/securityd/Regressions/secd-154-engine-backoff.m b/keychain/securityd/Regressions/secd-154-engine-backoff.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-154-engine-backoff.m rename to keychain/securityd/Regressions/secd-154-engine-backoff.m diff --git a/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m b/keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m rename to keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m index 17404974..446afdce 100644 --- a/OSX/sec/securityd/Regressions/secd-155-otr-negotiation-monitor.m +++ b/keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m @@ -31,7 +31,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" #import "SOSTransportTestTransports.h" diff --git a/OSX/sec/securityd/Regressions/secd-156-timers.m b/keychain/securityd/Regressions/secd-156-timers.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-156-timers.m rename to keychain/securityd/Regressions/secd-156-timers.m index e5c49050..f63e2dd2 100644 --- a/OSX/sec/securityd/Regressions/secd-156-timers.m +++ b/keychain/securityd/Regressions/secd-156-timers.m @@ -15,7 +15,7 @@ #include "secd_regressions.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m b/keychain/securityd/Regressions/secd-20-keychain_upgrade.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m rename to keychain/securityd/Regressions/secd-20-keychain_upgrade.m index 8987682f..5bb2d5f2 100644 --- a/OSX/sec/securityd/Regressions/secd-20-keychain_upgrade.m +++ b/keychain/securityd/Regressions/secd-20-keychain_upgrade.m @@ -37,7 +37,7 @@ #import #import #import -#import +#import "keychain/securityd/SecItemServer.h" #import diff --git a/OSX/sec/securityd/Regressions/secd-200-logstate.m b/keychain/securityd/Regressions/secd-200-logstate.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-200-logstate.m rename to keychain/securityd/Regressions/secd-200-logstate.m index 4fe18f6b..55d926f9 100644 --- a/OSX/sec/securityd/Regressions/secd-200-logstate.m +++ b/keychain/securityd/Regressions/secd-200-logstate.m @@ -51,7 +51,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-201-coders.m b/keychain/securityd/Regressions/secd-201-coders.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-201-coders.m rename to keychain/securityd/Regressions/secd-201-coders.m index 692150be..d851ca17 100644 --- a/OSX/sec/securityd/Regressions/secd-201-coders.m +++ b/keychain/securityd/Regressions/secd-201-coders.m @@ -53,7 +53,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-202-recoverykey.m b/keychain/securityd/Regressions/secd-202-recoverykey.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-202-recoverykey.m rename to keychain/securityd/Regressions/secd-202-recoverykey.m diff --git a/OSX/sec/securityd/Regressions/secd-21-transmogrify.m b/keychain/securityd/Regressions/secd-21-transmogrify.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-21-transmogrify.m rename to keychain/securityd/Regressions/secd-21-transmogrify.m index a62a93c5..26b900f9 100644 --- a/OSX/sec/securityd/Regressions/secd-21-transmogrify.m +++ b/keychain/securityd/Regressions/secd-21-transmogrify.m @@ -37,7 +37,7 @@ #import #import #import -#import +#import "keychain/securityd/SecItemServer.h" #import diff --git a/OSX/sec/securityd/Regressions/secd-210-keyinterest.m b/keychain/securityd/Regressions/secd-210-keyinterest.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-210-keyinterest.m rename to keychain/securityd/Regressions/secd-210-keyinterest.m diff --git a/OSX/sec/securityd/Regressions/secd-230-keybagtable.m b/keychain/securityd/Regressions/secd-230-keybagtable.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-230-keybagtable.m rename to keychain/securityd/Regressions/secd-230-keybagtable.m index 0803a8d9..38107987 100644 --- a/OSX/sec/securityd/Regressions/secd-230-keybagtable.m +++ b/keychain/securityd/Regressions/secd-230-keybagtable.m @@ -24,13 +24,13 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include diff --git a/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m b/keychain/securityd/Regressions/secd-30-keychain-upgrade.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m rename to keychain/securityd/Regressions/secd-30-keychain-upgrade.m index bdf2dcc9..fef6e75d 100644 --- a/OSX/sec/securityd/Regressions/secd-30-keychain-upgrade.m +++ b/keychain/securityd/Regressions/secd-30-keychain-upgrade.m @@ -70,7 +70,7 @@ const char *create_db_sql = #include "SecdTestKeychainUtilities.h" -#include +#include "keychain/securityd/SecItemServer.h" #include /* Test basic add delete update copy matching stuff. */ diff --git a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m b/keychain/securityd/Regressions/secd-31-keychain-unreadable.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m rename to keychain/securityd/Regressions/secd-31-keychain-unreadable.m index 3ff7543a..d0f07f5e 100644 --- a/OSX/sec/securityd/Regressions/secd-31-keychain-unreadable.m +++ b/keychain/securityd/Regressions/secd-31-keychain-unreadable.m @@ -37,7 +37,7 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" #include "SecdTestKeychainUtilities.h" diff --git a/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m b/keychain/securityd/Regressions/secd-32-restore-bad-backup.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m rename to keychain/securityd/Regressions/secd-32-restore-bad-backup.m index b3b547ea..6e2f4754 100644 --- a/OSX/sec/securityd/Regressions/secd-32-restore-bad-backup.m +++ b/keychain/securityd/Regressions/secd-32-restore-bad-backup.m @@ -38,7 +38,7 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" #include "SecdTestKeychainUtilities.h" diff --git a/OSX/sec/securityd/Regressions/secd-33-keychain-backup.m b/keychain/securityd/Regressions/secd-33-keychain-backup.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-33-keychain-backup.m rename to keychain/securityd/Regressions/secd-33-keychain-backup.m index 30146b07..ead14bdd 100644 --- a/OSX/sec/securityd/Regressions/secd-33-keychain-backup.m +++ b/keychain/securityd/Regressions/secd-33-keychain-backup.m @@ -24,7 +24,7 @@ #include -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include diff --git a/OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m b/keychain/securityd/Regressions/secd-33-keychain-ctk.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-33-keychain-ctk.m rename to keychain/securityd/Regressions/secd-33-keychain-ctk.m diff --git a/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m b/keychain/securityd/Regressions/secd-34-backup-der-parse.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m rename to keychain/securityd/Regressions/secd-34-backup-der-parse.m index e860ca41..352b832d 100644 --- a/OSX/sec/securityd/Regressions/secd-34-backup-der-parse.m +++ b/keychain/securityd/Regressions/secd-34-backup-der-parse.m @@ -38,7 +38,7 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" #include "SecdTestKeychainUtilities.h" diff --git a/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m b/keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m rename to keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m index 56368e54..71c789f8 100644 --- a/OSX/sec/securityd/Regressions/secd-35-keychain-migrate-inet.m +++ b/keychain/securityd/Regressions/secd-35-keychain-migrate-inet.m @@ -24,13 +24,13 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecDbItem.h" #include #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include diff --git a/OSX/sec/securityd/Regressions/secd-36-ks-encrypt.m b/keychain/securityd/Regressions/secd-36-ks-encrypt.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-36-ks-encrypt.m rename to keychain/securityd/Regressions/secd-36-ks-encrypt.m diff --git a/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m b/keychain/securityd/Regressions/secd-37-pairing-initial-sync.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m rename to keychain/securityd/Regressions/secd-37-pairing-initial-sync.m index 7ac6d8ac..1e2d001d 100644 --- a/OSX/sec/securityd/Regressions/secd-37-pairing-initial-sync.m +++ b/keychain/securityd/Regressions/secd-37-pairing-initial-sync.m @@ -38,7 +38,7 @@ #include "secd_regressions.h" -#include +#include "keychain/securityd/SecItemServer.h" #include "SecdTestKeychainUtilities.h" diff --git a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m b/keychain/securityd/Regressions/secd-40-cc-gestalt.m similarity index 96% rename from OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m rename to keychain/securityd/Regressions/secd-40-cc-gestalt.m index 4b3d21d5..8bfd1ef6 100644 --- a/OSX/sec/securityd/Regressions/secd-40-cc-gestalt.m +++ b/keychain/securityd/Regressions/secd-40-cc-gestalt.m @@ -23,7 +23,7 @@ -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include "secd_regressions.h" diff --git a/OSX/sec/securityd/Regressions/secd-49-manifests.m b/keychain/securityd/Regressions/secd-49-manifests.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-49-manifests.m rename to keychain/securityd/Regressions/secd-49-manifests.m index fe098739..e12ff1be 100644 --- a/OSX/sec/securityd/Regressions/secd-49-manifests.m +++ b/keychain/securityd/Regressions/secd-49-manifests.m @@ -31,7 +31,7 @@ #include #include #include "keychain/SecureObjectSync/SOSDigestVector.h" -#include +#include "keychain/securityd/SecDbItem.h" #include static int kTestTestCount = 68; diff --git a/OSX/sec/securityd/Regressions/secd-50-account.m b/keychain/securityd/Regressions/secd-50-account.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-50-account.m rename to keychain/securityd/Regressions/secd-50-account.m index 097b3990..70ff2f44 100644 --- a/OSX/sec/securityd/Regressions/secd-50-account.m +++ b/keychain/securityd/Regressions/secd-50-account.m @@ -41,7 +41,7 @@ #include "SOSRegressionUtilities.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-50-message.m b/keychain/securityd/Regressions/secd-50-message.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-50-message.m rename to keychain/securityd/Regressions/secd-50-message.m index 0fa120bc..67f198c1 100644 --- a/OSX/sec/securityd/Regressions/secd-50-message.m +++ b/keychain/securityd/Regressions/secd-50-message.m @@ -30,7 +30,7 @@ #include #include #include "keychain/SecureObjectSync/SOSDigestVector.h" -#include +#include "keychain/securityd/SecDbItem.h" static void testNullMessage(uint64_t msgid) { diff --git a/OSX/sec/securityd/Regressions/secd-51-account-inflate.m b/keychain/securityd/Regressions/secd-51-account-inflate.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-51-account-inflate.m rename to keychain/securityd/Regressions/secd-51-account-inflate.m index c50f219d..08ee55e8 100644 --- a/OSX/sec/securityd/Regressions/secd-51-account-inflate.m +++ b/keychain/securityd/Regressions/secd-51-account-inflate.m @@ -40,7 +40,7 @@ #include "SOSRegressionUtilities.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-52-account-changed.m b/keychain/securityd/Regressions/secd-52-account-changed.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-52-account-changed.m rename to keychain/securityd/Regressions/secd-52-account-changed.m index 214c0ab6..37b1cf8b 100644 --- a/OSX/sec/securityd/Regressions/secd-52-account-changed.m +++ b/keychain/securityd/Regressions/secd-52-account-changed.m @@ -41,7 +41,7 @@ #include "SOSRegressionUtilities.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m b/keychain/securityd/Regressions/secd-52-offering-gencount-reset.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m rename to keychain/securityd/Regressions/secd-52-offering-gencount-reset.m index 22a15018..bb2f6a74 100644 --- a/OSX/sec/securityd/Regressions/secd-52-offering-gencount-reset.m +++ b/keychain/securityd/Regressions/secd-52-offering-gencount-reset.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-55-account-circle.m b/keychain/securityd/Regressions/secd-55-account-circle.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-55-account-circle.m rename to keychain/securityd/Regressions/secd-55-account-circle.m index 9e91f032..d8035f97 100644 --- a/OSX/sec/securityd/Regressions/secd-55-account-circle.m +++ b/keychain/securityd/Regressions/secd-55-account-circle.m @@ -47,7 +47,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m b/keychain/securityd/Regressions/secd-55-account-incompatibility.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m rename to keychain/securityd/Regressions/secd-55-account-incompatibility.m index fcb6b210..da6aabca 100644 --- a/OSX/sec/securityd/Regressions/secd-55-account-incompatibility.m +++ b/keychain/securityd/Regressions/secd-55-account-incompatibility.m @@ -47,7 +47,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-56-account-apply.m b/keychain/securityd/Regressions/secd-56-account-apply.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-56-account-apply.m rename to keychain/securityd/Regressions/secd-56-account-apply.m index 7e12348f..50748a08 100644 --- a/OSX/sec/securityd/Regressions/secd-56-account-apply.m +++ b/keychain/securityd/Regressions/secd-56-account-apply.m @@ -45,7 +45,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m b/keychain/securityd/Regressions/secd-57-1-account-last-standing.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m rename to keychain/securityd/Regressions/secd-57-1-account-last-standing.m index ba45cf74..d455b327 100644 --- a/OSX/sec/securityd/Regressions/secd-57-1-account-last-standing.m +++ b/keychain/securityd/Regressions/secd-57-1-account-last-standing.m @@ -50,7 +50,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-57-account-leave.m b/keychain/securityd/Regressions/secd-57-account-leave.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-57-account-leave.m rename to keychain/securityd/Regressions/secd-57-account-leave.m index 4c9b0732..6e1710d1 100644 --- a/OSX/sec/securityd/Regressions/secd-57-account-leave.m +++ b/keychain/securityd/Regressions/secd-57-account-leave.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-58-password-change.m b/keychain/securityd/Regressions/secd-58-password-change.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-58-password-change.m rename to keychain/securityd/Regressions/secd-58-password-change.m index ca235fbb..3135d5b7 100644 --- a/OSX/sec/securityd/Regressions/secd-58-password-change.m +++ b/keychain/securityd/Regressions/secd-58-password-change.m @@ -45,7 +45,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" #include "SecdTestKeychainUtilities.h" diff --git a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m b/keychain/securityd/Regressions/secd-59-account-cleanup.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-59-account-cleanup.m rename to keychain/securityd/Regressions/secd-59-account-cleanup.m index 380ae6ab..dcdb0699 100644 --- a/OSX/sec/securityd/Regressions/secd-59-account-cleanup.m +++ b/keychain/securityd/Regressions/secd-59-account-cleanup.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m b/keychain/securityd/Regressions/secd-60-account-cloud-identity.m similarity index 97% rename from OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m rename to keychain/securityd/Regressions/secd-60-account-cloud-identity.m index cdccf871..3fbb31d2 100644 --- a/OSX/sec/securityd/Regressions/secd-60-account-cloud-identity.m +++ b/keychain/securityd/Regressions/secd-60-account-cloud-identity.m @@ -46,15 +46,12 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" #include "SecdTestKeychainUtilities.h" -static int kTestTestCount = 111; - -#if FIX_ICLOUD_IDENTITY_AS_SET_CRED_SIDE_EFFECT static bool purgeICloudIdentity(SOSAccount* account) { bool retval = false; @@ -65,8 +62,6 @@ static bool purgeICloudIdentity(SOSAccount* account) { return retval; } -#endif - static void tests(void) { CFErrorRef error = NULL; @@ -155,7 +150,6 @@ static void tests(void) accounts_agree_internal("Carole's in", bob_account, alice_account, false); accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); -#if FIX_ICLOUD_IDENTITY_AS_SET_CRED_SIDE_EFFECT /* Break iCloud identity FPI in all peers */ ok(purgeICloudIdentity(alice_account), "remove iCloud private key"); @@ -165,13 +159,17 @@ static void tests(void) ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error); CFReleaseNull(error); - - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); + + // fix this as if the timed event had triggered in handleUpdateCircles + bool fixedIdentities = [alice_account.trust fixICloudIdentities:alice_account circle:alice_account.trust.trustedCircle]; + ok(fixedIdentities, "failed to fix icloud identity"); + + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 1, "updates"); ok([carole_account.trust leaveCircle:carole_account err:&error], "Carol Leaves again"); CFReleaseNull(error); - is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 2, "updates"); + is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carole_account, NULL), 4, "updates"); /*----- join - join after restore -----*/ @@ -196,7 +194,7 @@ static void tests(void) accounts_agree_internal("Carole's in", bob_account, alice_account, false); accounts_agree_internal("Carole's in - 2", bob_account, carole_account, false); -#endif + //join after piggybacking the icloud identity?? CFMutableArrayRef identityArray = SOSAccountCopyiCloudIdentities(alice_account); @@ -288,7 +286,7 @@ static void tests(void) int secd_60_account_cloud_identity(int argc, char *const *argv) { - plan_tests(kTestTestCount); + plan_tests(159); secd_test_setup_temp_keychain(__FUNCTION__, NULL); diff --git a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m b/keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m rename to keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m index c6cb5cc7..ac6b75c1 100644 --- a/OSX/sec/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m +++ b/keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m @@ -45,7 +45,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-62-account-backup.m b/keychain/securityd/Regressions/secd-62-account-backup.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-62-account-backup.m rename to keychain/securityd/Regressions/secd-62-account-backup.m index 2875ef20..8205fdd9 100644 --- a/OSX/sec/securityd/Regressions/secd-62-account-backup.m +++ b/keychain/securityd/Regressions/secd-62-account-backup.m @@ -51,7 +51,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #if !TARGET_OS_SIMULATOR #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m b/keychain/securityd/Regressions/secd-63-account-resurrection.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-63-account-resurrection.m rename to keychain/securityd/Regressions/secd-63-account-resurrection.m index c1ccc9ea..5e0ef6d0 100644 --- a/OSX/sec/securityd/Regressions/secd-63-account-resurrection.m +++ b/keychain/securityd/Regressions/secd-63-account-resurrection.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-64-circlereset.m b/keychain/securityd/Regressions/secd-64-circlereset.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-64-circlereset.m rename to keychain/securityd/Regressions/secd-64-circlereset.m index 74f8cf9a..6c905c29 100644 --- a/OSX/sec/securityd/Regressions/secd-64-circlereset.m +++ b/keychain/securityd/Regressions/secd-64-circlereset.m @@ -30,7 +30,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m b/keychain/securityd/Regressions/secd-65-account-retirement-reset.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m rename to keychain/securityd/Regressions/secd-65-account-retirement-reset.m index 520cb8cd..a406f2ab 100644 --- a/OSX/sec/securityd/Regressions/secd-65-account-retirement-reset.m +++ b/keychain/securityd/Regressions/secd-65-account-retirement-reset.m @@ -46,7 +46,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-66-account-recovery.m b/keychain/securityd/Regressions/secd-66-account-recovery.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-66-account-recovery.m rename to keychain/securityd/Regressions/secd-66-account-recovery.m index e8df91f4..60664cb8 100644 --- a/OSX/sec/securityd/Regressions/secd-66-account-recovery.m +++ b/keychain/securityd/Regressions/secd-66-account-recovery.m @@ -59,7 +59,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #if TARGET_OS_SIMULATOR diff --git a/OSX/sec/securityd/Regressions/secd-668-ghosts.m b/keychain/securityd/Regressions/secd-668-ghosts.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-668-ghosts.m rename to keychain/securityd/Regressions/secd-668-ghosts.m diff --git a/OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m b/keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-67-prefixedKeyIDs.m rename to keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m b/keychain/securityd/Regressions/secd-70-engine-corrupt.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m rename to keychain/securityd/Regressions/secd-70-engine-corrupt.m index cf7fba71..a229bcaa 100644 --- a/OSX/sec/securityd/Regressions/secd-70-engine-corrupt.m +++ b/keychain/securityd/Regressions/secd-70-engine-corrupt.m @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" #include #include #include diff --git a/OSX/sec/securityd/Regressions/secd-70-engine-smash.m b/keychain/securityd/Regressions/secd-70-engine-smash.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-70-engine-smash.m rename to keychain/securityd/Regressions/secd-70-engine-smash.m diff --git a/OSX/sec/securityd/Regressions/secd-70-engine.m b/keychain/securityd/Regressions/secd-70-engine.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-70-engine.m rename to keychain/securityd/Regressions/secd-70-engine.m index eba7cb04..87ac71fd 100644 --- a/OSX/sec/securityd/Regressions/secd-70-engine.m +++ b/keychain/securityd/Regressions/secd-70-engine.m @@ -35,8 +35,8 @@ #include #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" #include #include #include diff --git a/OSX/sec/securityd/Regressions/secd-70-otr-remote.m b/keychain/securityd/Regressions/secd-70-otr-remote.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-70-otr-remote.m rename to keychain/securityd/Regressions/secd-70-otr-remote.m diff --git a/OSX/sec/securityd/Regressions/secd-71-engine-save-sample1.h b/keychain/securityd/Regressions/secd-71-engine-save-sample1.h similarity index 100% rename from OSX/sec/securityd/Regressions/secd-71-engine-save-sample1.h rename to keychain/securityd/Regressions/secd-71-engine-save-sample1.h diff --git a/OSX/sec/securityd/Regressions/secd-71-engine-save.m b/keychain/securityd/Regressions/secd-71-engine-save.m similarity index 98% rename from OSX/sec/securityd/Regressions/secd-71-engine-save.m rename to keychain/securityd/Regressions/secd-71-engine-save.m index 1de658be..1f9eabf1 100644 --- a/OSX/sec/securityd/Regressions/secd-71-engine-save.m +++ b/keychain/securityd/Regressions/secd-71-engine-save.m @@ -35,8 +35,8 @@ #include #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDataSource.h" #include #include #include diff --git a/OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m b/keychain/securityd/Regressions/secd-74-engine-beer-servers.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-74-engine-beer-servers.m rename to keychain/securityd/Regressions/secd-74-engine-beer-servers.m diff --git a/OSX/sec/securityd/Regressions/secd-75-engine-views.m b/keychain/securityd/Regressions/secd-75-engine-views.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-75-engine-views.m rename to keychain/securityd/Regressions/secd-75-engine-views.m diff --git a/OSX/sec/securityd/Regressions/secd-76-idstransport.m b/keychain/securityd/Regressions/secd-76-idstransport.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-76-idstransport.m rename to keychain/securityd/Regressions/secd-76-idstransport.m diff --git a/OSX/sec/securityd/Regressions/secd-80-views-alwayson.m b/keychain/securityd/Regressions/secd-80-views-alwayson.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-80-views-alwayson.m rename to keychain/securityd/Regressions/secd-80-views-alwayson.m diff --git a/OSX/sec/securityd/Regressions/secd-80-views-basic.m b/keychain/securityd/Regressions/secd-80-views-basic.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-80-views-basic.m rename to keychain/securityd/Regressions/secd-80-views-basic.m index b628d575..db10961b 100644 --- a/OSX/sec/securityd/Regressions/secd-80-views-basic.m +++ b/keychain/securityd/Regressions/secd-80-views-basic.m @@ -51,7 +51,7 @@ #include "SOSRegressionUtilities.h" #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SecdTestKeychainUtilities.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m b/keychain/securityd/Regressions/secd-81-item-acl-stress.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m rename to keychain/securityd/Regressions/secd-81-item-acl-stress.m index b5c60442..59d4d9a9 100644 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl-stress.m +++ b/keychain/securityd/Regressions/secd-81-item-acl-stress.m @@ -20,7 +20,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include "secd_regressions.h" diff --git a/OSX/sec/securityd/Regressions/secd-81-item-acl.m b/keychain/securityd/Regressions/secd-81-item-acl.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-81-item-acl.m rename to keychain/securityd/Regressions/secd-81-item-acl.m index c51a8aed..30eddba5 100644 --- a/OSX/sec/securityd/Regressions/secd-81-item-acl.m +++ b/keychain/securityd/Regressions/secd-81-item-acl.m @@ -20,7 +20,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include "secd_regressions.h" diff --git a/OSX/sec/securityd/Regressions/secd-82-persistent-ref.m b/keychain/securityd/Regressions/secd-82-persistent-ref.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-82-persistent-ref.m rename to keychain/securityd/Regressions/secd-82-persistent-ref.m diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-policy.m b/keychain/securityd/Regressions/secd-83-item-match-policy.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-83-item-match-policy.m rename to keychain/securityd/Regressions/secd-83-item-match-policy.m diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-trusted.m b/keychain/securityd/Regressions/secd-83-item-match-trusted.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-83-item-match-trusted.m rename to keychain/securityd/Regressions/secd-83-item-match-trusted.m diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match-valid-on-date.m b/keychain/securityd/Regressions/secd-83-item-match-valid-on-date.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd-83-item-match-valid-on-date.m rename to keychain/securityd/Regressions/secd-83-item-match-valid-on-date.m diff --git a/OSX/sec/securityd/Regressions/secd-83-item-match.h b/keychain/securityd/Regressions/secd-83-item-match.h similarity index 100% rename from OSX/sec/securityd/Regressions/secd-83-item-match.h rename to keychain/securityd/Regressions/secd-83-item-match.h diff --git a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m b/keychain/securityd/Regressions/secd-95-escrow-persistence.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m rename to keychain/securityd/Regressions/secd-95-escrow-persistence.m index c2d4cdda..80c23aea 100644 --- a/OSX/sec/securityd/Regressions/secd-95-escrow-persistence.m +++ b/keychain/securityd/Regressions/secd-95-escrow-persistence.m @@ -43,7 +43,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m b/keychain/securityd/Regressions/secd60-account-cloud-exposure.m similarity index 99% rename from OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m rename to keychain/securityd/Regressions/secd60-account-cloud-exposure.m index 0eca1b36..a9979d44 100644 --- a/OSX/sec/securityd/Regressions/secd60-account-cloud-exposure.m +++ b/keychain/securityd/Regressions/secd60-account-cloud-exposure.m @@ -52,7 +52,7 @@ #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountTesting.h" diff --git a/OSX/sec/securityd/Regressions/secd_77_ids_messaging.m b/keychain/securityd/Regressions/secd_77_ids_messaging.m similarity index 100% rename from OSX/sec/securityd/Regressions/secd_77_ids_messaging.m rename to keychain/securityd/Regressions/secd_77_ids_messaging.m diff --git a/OSX/sec/securityd/Regressions/secd_regressions.h b/keychain/securityd/Regressions/secd_regressions.h similarity index 100% rename from OSX/sec/securityd/Regressions/secd_regressions.h rename to keychain/securityd/Regressions/secd_regressions.h diff --git a/OSX/sec/securityd/Regressions/securityd_regressions.h b/keychain/securityd/Regressions/securityd_regressions.h similarity index 100% rename from OSX/sec/securityd/Regressions/securityd_regressions.h rename to keychain/securityd/Regressions/securityd_regressions.h diff --git a/OSX/sec/securityd/SFKeychainControlManager.h b/keychain/securityd/SFKeychainControlManager.h similarity index 100% rename from OSX/sec/securityd/SFKeychainControlManager.h rename to keychain/securityd/SFKeychainControlManager.h diff --git a/OSX/sec/securityd/SFKeychainControlManager.m b/keychain/securityd/SFKeychainControlManager.m similarity index 100% rename from OSX/sec/securityd/SFKeychainControlManager.m rename to keychain/securityd/SFKeychainControlManager.m diff --git a/OSX/sec/securityd/SFKeychainServer.h b/keychain/securityd/SFKeychainServer.h similarity index 100% rename from OSX/sec/securityd/SFKeychainServer.h rename to keychain/securityd/SFKeychainServer.h diff --git a/OSX/sec/securityd/SFKeychainServer.m b/keychain/securityd/SFKeychainServer.m similarity index 100% rename from OSX/sec/securityd/SFKeychainServer.m rename to keychain/securityd/SFKeychainServer.m diff --git a/OSX/sec/securityd/SOSCloudCircleServer.h b/keychain/securityd/SOSCloudCircleServer.h similarity index 99% rename from OSX/sec/securityd/SOSCloudCircleServer.h rename to keychain/securityd/SOSCloudCircleServer.h index 581c87b0..6c363684 100644 --- a/OSX/sec/securityd/SOSCloudCircleServer.h +++ b/keychain/securityd/SOSCloudCircleServer.h @@ -176,7 +176,7 @@ CFDictionaryRef SOSCCCopyBackupInformation_Server(CFErrorRef *error); SOSPeerInfoRef SOSCCCopyApplication_Server(CFErrorRef *error); CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef *error); bool SOSCCJoinWithCircleJoiningBlob_Server(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error); -CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error); +CFDataRef SOSCCCopyInitialSyncData_Server(uint32_t flags, CFErrorRef *error); bool SOSCCCleanupKVSKeys_Server(CFErrorRef *error); bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error); diff --git a/OSX/sec/securityd/SOSCloudCircleServer.m b/keychain/securityd/SOSCloudCircleServer.m similarity index 99% rename from OSX/sec/securityd/SOSCloudCircleServer.m rename to keychain/securityd/SOSCloudCircleServer.m index dafc9991..ef07ff98 100644 --- a/OSX/sec/securityd/SOSCloudCircleServer.m +++ b/keychain/securityd/SOSCloudCircleServer.m @@ -28,7 +28,7 @@ #import "keychain/SecureObjectSync/SOSAccountTransaction.h" -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include @@ -77,14 +77,14 @@ #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include #include #include -#include +#include "keychain/securityd/SecDbKeychainItem.h" #include #include @@ -672,17 +672,20 @@ static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOS __block SOSAccountGhostBustingOptions gbOptions = 0; // Avoid mutual deadlock for just checking date. - SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT); - if(tmpAccount && [tmpAccount isInCircle:(NULL)]) { + // Check to see if we're InCircle using the client API - will read cached value if available; otherwise it'll do the round trip and lock appropriately + SOSCCStatus circleStatus = SOSCCThisDeviceIsInCircle(NULL); + if(circleStatus == kSOSCCInCircle) { + // Only need the account object to check settings + SOSAccount *tmpAccount = GetSharedAccount(FOR_EXISTING_ACCOUNT); if(tmpAccount.settings) { ghostbustnow = [tmpAccount ghostBustCheckDate]; } + // Get ramp settings from the Cloud if(ghostbustnow) { gbOptions = [SOSAccount ghostBustGetRampSettings]; } } - #endif do_with_account(^(SOSAccountTransaction* txn) { @@ -2141,7 +2144,7 @@ void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) { } void SOSCCRequestSyncWithBackupPeer(CFStringRef backupPeerId) { - os_activity_initiate("CloudCircle RequestSyncWithPeersList", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { + os_activity_initiate("CloudCircle SOSCCRequestSyncWithBackupPeer", OS_ACTIVITY_FLAG_DEFAULT, ^(void) { CFArrayRef empty = CFArrayCreateForCFTypes(kCFAllocatorDefault, NULL); CFArrayRef backupPeerList = CFArrayCreateForCFTypes(kCFAllocatorDefault, backupPeerId, NULL); @@ -2215,10 +2218,10 @@ CFDataRef SOSCCCopyCircleJoiningBlob_Server(SOSPeerInfoRef applicant, CFErrorRef return pbblob; } -CFDataRef SOSCCCopyInitialSyncData_Server(CFErrorRef *error) { +CFDataRef SOSCCCopyInitialSyncData_Server(SOSInitialSyncFlags flags, CFErrorRef *error) { __block CFDataRef pbblob = NULL; do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) { - pbblob = SOSAccountCopyInitialSyncData(txn.account, error); + pbblob = SOSAccountCopyInitialSyncData(txn.account, flags, error); return pbblob != NULL; }); return pbblob; diff --git a/OSX/sec/securityd/SecAKSObjCWrappers.h b/keychain/securityd/SecAKSObjCWrappers.h similarity index 100% rename from OSX/sec/securityd/SecAKSObjCWrappers.h rename to keychain/securityd/SecAKSObjCWrappers.h diff --git a/OSX/sec/securityd/SecAKSObjCWrappers.m b/keychain/securityd/SecAKSObjCWrappers.m similarity index 100% rename from OSX/sec/securityd/SecAKSObjCWrappers.m rename to keychain/securityd/SecAKSObjCWrappers.m diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto b/keychain/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto rename to keychain/securityd/SecDbBackupManager-protobufs/SecDbBackupRecoverySet.proto diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.h diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBag.m diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.h diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupBagIdentity.m diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.h diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupKeyClassSigningKey.m diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.h diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupMetadataClassKey.m diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.h diff --git a/OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m b/keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m rename to keychain/securityd/SecDbBackupManager-protobufs/generated_source/SecDbBackupRecoverySet.m diff --git a/OSX/sec/securityd/SecDbBackupManager.h b/keychain/securityd/SecDbBackupManager.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager.h rename to keychain/securityd/SecDbBackupManager.h diff --git a/OSX/sec/securityd/SecDbBackupManager.m b/keychain/securityd/SecDbBackupManager.m similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager.m rename to keychain/securityd/SecDbBackupManager.m diff --git a/OSX/sec/securityd/SecDbBackupManager_Internal.h b/keychain/securityd/SecDbBackupManager_Internal.h similarity index 100% rename from OSX/sec/securityd/SecDbBackupManager_Internal.h rename to keychain/securityd/SecDbBackupManager_Internal.h diff --git a/OSX/sec/securityd/SecDbItem.c b/keychain/securityd/SecDbItem.c similarity index 99% rename from OSX/sec/securityd/SecDbItem.c rename to keychain/securityd/SecDbItem.c index 167e95d5..5b63b41a 100644 --- a/OSX/sec/securityd/SecDbItem.c +++ b/keychain/securityd/SecDbItem.c @@ -32,9 +32,9 @@ #undef SHAREDWEBCREDENTIALS #endif -#include -#include -#include +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemDb.h" #include #include #include @@ -48,7 +48,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemSchema.h" #include diff --git a/OSX/sec/securityd/SecDbItem.h b/keychain/securityd/SecDbItem.h similarity index 99% rename from OSX/sec/securityd/SecDbItem.h rename to keychain/securityd/SecDbItem.h index 8b38586b..586b8c00 100644 --- a/OSX/sec/securityd/SecDbItem.h +++ b/keychain/securityd/SecDbItem.h @@ -37,7 +37,7 @@ #include "utilities/SecCFError.h" #include "utilities/SecCFWrappers.h" #include "utilities/SecDb.h" -#include "securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecKeybagSupport.h" #include #include diff --git a/OSX/sec/securityd/SecDbKeychainItem.h b/keychain/securityd/SecDbKeychainItem.h similarity index 96% rename from OSX/sec/securityd/SecDbKeychainItem.h rename to keychain/securityd/SecDbKeychainItem.h index 1cb4bfca..ce889868 100644 --- a/OSX/sec/securityd/SecDbKeychainItem.h +++ b/keychain/securityd/SecDbKeychainItem.h @@ -28,9 +28,9 @@ #ifndef _SECURITYD_SECKEYCHAINITEM_H_ #define _SECURITYD_SECKEYCHAINITEM_H_ -#include -#include -#include +#include "keychain/securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecDbQuery.h" __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecDbKeychainItem.m b/keychain/securityd/SecDbKeychainItem.m similarity index 99% rename from OSX/sec/securityd/SecDbKeychainItem.m rename to keychain/securityd/SecDbKeychainItem.m index 54c5cf04..7e52fc36 100644 --- a/OSX/sec/securityd/SecDbKeychainItem.m +++ b/keychain/securityd/SecDbKeychainItem.m @@ -27,12 +27,12 @@ passwords.) */ -#include +#include "keychain/securityd/SecDbKeychainItem.h" #import "SecInternalReleasePriv.h" -#include -#include -#include +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SecItemDb.h" #include #include #include @@ -54,7 +54,7 @@ #include #include #include -#include +#include "keychain/securityd/spi.h" #endif /* USE_KEYSTORE */ diff --git a/OSX/sec/securityd/SecDbKeychainItemV7.h b/keychain/securityd/SecDbKeychainItemV7.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainItemV7.h rename to keychain/securityd/SecDbKeychainItemV7.h diff --git a/OSX/sec/securityd/SecDbKeychainItemV7.m b/keychain/securityd/SecDbKeychainItemV7.m similarity index 100% rename from OSX/sec/securityd/SecDbKeychainItemV7.m rename to keychain/securityd/SecDbKeychainItemV7.m diff --git a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.h b/keychain/securityd/SecDbKeychainMetadataKeyStore.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainMetadataKeyStore.h rename to keychain/securityd/SecDbKeychainMetadataKeyStore.h diff --git a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m b/keychain/securityd/SecDbKeychainMetadataKeyStore.m similarity index 94% rename from OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m rename to keychain/securityd/SecDbKeychainMetadataKeyStore.m index d406a1b1..9a366661 100644 --- a/OSX/sec/securityd/SecDbKeychainMetadataKeyStore.m +++ b/keychain/securityd/SecDbKeychainMetadataKeyStore.m @@ -209,7 +209,9 @@ static void initializeSharedMetadataStoreQueue(void) { key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&nsErrorLocal]; if(!key) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted, but didn't become a key: %@", keyclass, nsErrorLocal); + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted, but didn't become a key: %@", keyclass, nsErrorLocal); + } } if (actualKeyclass == 0) { @@ -232,7 +234,11 @@ static void initializeSharedMetadataStoreQueue(void) { key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&retryError]; if(!key) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) decrypted using keyrolled keyclass %d, but didn't become a key: %@", keyclass, keyrolledKeyclass, retryError); + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), + "Metadata class key (%d) decrypted using keyrolled keyclass %d, but didn't become a key: %@", + keyclass, keyrolledKeyclass, retryError); + } nsErrorLocal = retryError; } } @@ -274,7 +280,9 @@ static void initializeSharedMetadataStoreQueue(void) { // If this error is errSecDecode, then it's failed authentication and likely will forever. Other errors are scary. metadataKeyDoesntAuthenticate = [nsErrorLocal.domain isEqualToString:NSOSStatusErrorDomain] && nsErrorLocal.code == errSecDecode; if(metadataKeyDoesntAuthenticate) { - os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal); + if (__security_simulatecrash_enabled()) { + os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal); + } } } } diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto rename to keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedAKSWrappedKey.proto diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto rename to keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedItemV7.proto diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto rename to keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadata.proto diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto rename to keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedSecretData.proto diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.h diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedAKSWrappedKey.m diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.h diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedItemV7.m diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.h diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadata.m diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.h diff --git a/OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m similarity index 100% rename from OSX/sec/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m rename to keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedSecretData.m diff --git a/OSX/sec/securityd/SecDbQuery.c b/keychain/securityd/SecDbQuery.c similarity index 99% rename from OSX/sec/securityd/SecDbQuery.c rename to keychain/securityd/SecDbQuery.c index ae67d53a..88d72177 100644 --- a/OSX/sec/securityd/SecDbQuery.c +++ b/keychain/securityd/SecDbQuery.c @@ -28,12 +28,12 @@ passwords.) */ -#include +#include "keychain/securityd/SecDbQuery.h" -#include -#include -#include -#include +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/spi.h" #include #include #include diff --git a/OSX/sec/securityd/SecDbQuery.h b/keychain/securityd/SecDbQuery.h similarity index 98% rename from OSX/sec/securityd/SecDbQuery.h rename to keychain/securityd/SecDbQuery.h index dc132a0e..820090bf 100644 --- a/OSX/sec/securityd/SecDbQuery.h +++ b/keychain/securityd/SecDbQuery.h @@ -28,8 +28,8 @@ #ifndef _SECURITYD_SECDBQUERY_H_ #define _SECURITYD_SECDBQUERY_H_ -#include "securityd/SecKeybagSupport.h" -#include "securityd/SecDbItem.h" +#include "keychain/securityd/SecKeybagSupport.h" +#include "keychain/securityd/SecDbItem.h" __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecItemBackupServer.c b/keychain/securityd/SecItemBackupServer.c similarity index 97% rename from OSX/sec/securityd/SecItemBackupServer.c rename to keychain/securityd/SecItemBackupServer.c index 476b3bd9..78591837 100644 --- a/OSX/sec/securityd/SecItemBackupServer.c +++ b/keychain/securityd/SecItemBackupServer.c @@ -21,15 +21,15 @@ * @APPLE_LICENSE_HEADER_END@ */ -#include -#include +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" #include "keychain/SecureObjectSync/SOSEnginePriv.h" #include "keychain/SecureObjectSync/SOSPeer.h" #include #include #include -#include +#include "keychain/securityd/SecDbItem.h" #include static bool withDataSourceAndEngine(CFErrorRef *error, void (^action)(SOSDataSourceRef ds, SOSEngineRef engine)) { diff --git a/OSX/sec/securityd/SecItemBackupServer.h b/keychain/securityd/SecItemBackupServer.h similarity index 100% rename from OSX/sec/securityd/SecItemBackupServer.h rename to keychain/securityd/SecItemBackupServer.h diff --git a/OSX/sec/securityd/SecItemDataSource.c b/keychain/securityd/SecItemDataSource.c similarity index 98% rename from OSX/sec/securityd/SecItemDataSource.c rename to keychain/securityd/SecItemDataSource.c index 4984c375..1845b5bb 100644 --- a/OSX/sec/securityd/SecItemDataSource.c +++ b/keychain/securityd/SecItemDataSource.c @@ -27,13 +27,13 @@ passwords.) */ -#include +#include "keychain/securityd/SecItemDataSource.h" -#include -#include -#include -#include -#include +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecDbItem.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SOSCloudCircleServer.h" #include "keychain/SecureObjectSync/SOSDigestVector.h" #include "keychain/SecureObjectSync/SOSEngine.h" #include @@ -857,14 +857,6 @@ static void SecItemDataSourceFactoryDispose(SOSDataSourceFactoryRef factory) // Nothing to do here. } -static void SecItemDataSourceFactoryCircleChanged(SOSDataSourceFactoryRef factory, CFStringRef myPeerID, CFArrayRef trustedPeerIDs, CFArrayRef untrustedPeerIDs) { - CFStringRef dsName = SOSDataSourceFactoryCopyName(factory); - SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(factory, dsName, NULL); - if (engine) - SOSEngineCircleChanged(engine, myPeerID, trustedPeerIDs, untrustedPeerIDs); - CFReleaseSafe(dsName); -} - // Fire up the SOSEngines so they can static bool SOSDataSourceFactoryStartYourEngines(SOSDataSourceFactoryRef factory) { #if OCTAGON @@ -893,7 +885,6 @@ static SOSDataSourceFactoryRef SecItemDataSourceFactoryCreate(SecDbRef db) { dsf->factory.copy_name = SecItemDataSourceFactoryCopyName; dsf->factory.create_datasource = SecItemDataSourceFactoryCopyDataSource; dsf->factory.release = SecItemDataSourceFactoryDispose; - dsf->factory.circle_changed = SecItemDataSourceFactoryCircleChanged; dsf->dsCache = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); dsf->queue = dispatch_queue_create("dsf queue", DISPATCH_QUEUE_SERIAL); diff --git a/OSX/sec/securityd/SecItemDataSource.h b/keychain/securityd/SecItemDataSource.h similarity index 100% rename from OSX/sec/securityd/SecItemDataSource.h rename to keychain/securityd/SecItemDataSource.h diff --git a/OSX/sec/securityd/SecItemDb.c b/keychain/securityd/SecItemDb.c similarity index 99% rename from OSX/sec/securityd/SecItemDb.c rename to keychain/securityd/SecItemDb.c index 865202cc..c5258625 100644 --- a/OSX/sec/securityd/SecItemDb.c +++ b/keychain/securityd/SecItemDb.c @@ -33,24 +33,26 @@ #undef SHAREDWEBCREDENTIALS #endif -#include +#include "keychain/securityd/SecItemDb.h" #include -#include -#include -#include +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SecItemSchema.h" +#include "keychain/securityd/SecItemServer.h" #include #include #include #include #include #include -#include +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include #include #include -#include "sec_action.h" + +#include "utilities/SecABC.h" +#include "utilities/sec_action.h" #include "keychain/ckks/CKKS.h" @@ -1613,7 +1615,13 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) { secdebug("item", "Skipping akpu item for backup"); } else { // Probably failed to decrypt sysbound item. Should never be an akpu item in backup. secerror("Encountered akpu item we cannot export (filter %d), skipping. %@", c->filter, localError); - // TODO: Find out who is doing this somehow and make them not do this + CFDictionaryRef payload = NULL; + CFTypeRef agrp = CFDictionaryGetValue(allAttributes, CFSTR("agrp")); + if (agrp) { + payload = CFDictionaryCreateForCFTypes(NULL, CFSTR("agrp"), agrp, NULL); + } + SecABCTrigger(CFSTR("keychain"), CFSTR("invalid-akpu+sysbound"), NULL, payload); + CFReleaseNull(payload); } // We expect akpu items to be inaccessible when the device is locked. CFReleaseNull(localError); diff --git a/OSX/sec/securityd/SecItemDb.h b/keychain/securityd/SecItemDb.h similarity index 99% rename from OSX/sec/securityd/SecItemDb.h rename to keychain/securityd/SecItemDb.h index 9cb34658..3a07bb65 100644 --- a/OSX/sec/securityd/SecItemDb.h +++ b/keychain/securityd/SecItemDb.h @@ -28,7 +28,7 @@ #ifndef _SECURITYD_SECITEMDB_H_ #define _SECURITYD_SECITEMDB_H_ -#include +#include "keychain/securityd/SecDbQuery.h" struct SecurityClient; diff --git a/OSX/sec/securityd/SecItemSchema.c b/keychain/securityd/SecItemSchema.c similarity index 98% rename from OSX/sec/securityd/SecItemSchema.c rename to keychain/securityd/SecItemSchema.c index 5b5b7dce..9a58ef42 100644 --- a/OSX/sec/securityd/SecItemSchema.c +++ b/keychain/securityd/SecItemSchema.c @@ -28,7 +28,7 @@ */ #include "SecItemSchema.h" -#include +#include "keychain/securityd/SecDbKeychainItem.h" #include #include "CheckV12DevEnabled.h" @@ -243,6 +243,8 @@ SECDB_ATTR(v11_2actualKeyclass, "actualKeyclass", String, SecDbFlags( ,L, , , , SECDB_ATTR(v11_5octagonpeerid, "octagonpeerid", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); SECDB_ATTR(v11_5octagonStatus, "octagonstatus", String, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); +SECDB_ATTR(v11_6moreComing, "morecoming", Number, SecDbFlags( ,L, , , , , , , , , , , , , , ), NULL, NULL); + SECDB_ATTR(v12_backupUUIDPrimary, "backupUUID", UUID, SecDbFlags(P,L,I, , , , , , , , , ,N, , , ), NULL, NULL); SECDB_ATTR(v12_backupUUID, "backupUUID", UUID, SecDbFlags( ,L,I, , , , , , , , ,E, , , , ), NULL, NULL); SECDB_ATTR(v12_backupBag, "backupbag", Blob, SecDbFlags( ,L, , , , , , , , , , ,N, , , ), NULL, NULL); @@ -489,6 +491,22 @@ const SecDbClass v12_keys_class = { } }; +const SecDbClass v11_6_ckstate_class = { + .name = CFSTR("ckstate"), + .itemclass = false, + .attrs = { + &v10ckzone, + &v10ckzonecreated, + &v10ckzonesubscribed, + &v10lastfetchtime, + &v10changetoken, + &v10ratelimiter, + &v10_4lastFixup, + &v11_6moreComing, + 0 + } +}; + const SecDbClass v11_5_ckdevicestate_class = { .name = CFSTR("ckdevicestate"), .itemclass = false, @@ -1230,7 +1248,7 @@ const SecDbSchema v12_0_schema = { &v10_0_sync_key_class, &v10_1_ckmirror_class, &v10_0_current_key_class, - &v10_4_ckstate_class, + &v11_6_ckstate_class, &v10_0_item_backup_class, &v10_0_backup_keybag_class, &v10_2_ckmanifest_class, @@ -1251,6 +1269,41 @@ const SecDbSchema v12_0_schema = { } }; +/* + * Version 11.6 (Add 'moreComing' field to zone state) + */ +const SecDbSchema v11_6_schema = { + .majorVersion = 11, + .minorVersion = 6, + .classes = { + &v10_1_genp_class, + &v10_1_inet_class, + &v10_1_cert_class, + &v10_1_keys_class, + &v10_0_tversion_class, + &v10_2_outgoing_queue_class, + &v10_2_incoming_queue_class, + &v10_0_sync_key_class, + &v10_1_ckmirror_class, + &v10_0_current_key_class, + &v11_6_ckstate_class, + &v10_0_item_backup_class, + &v10_0_backup_keybag_class, + &v10_2_ckmanifest_class, + &v10_2_pending_manifest_class, + &v10_1_ckmanifest_leaf_class, + &v10_1_backup_keyarchive_class, + &v10_1_current_keyarchive_class, + &v10_1_current_archived_keys_class, + &v10_1_pending_manifest_leaf_class, + &v10_4_current_item_class, + &v11_5_ckdevicestate_class, + &v10_5_tlkshare_class, + &v11_2_metadatakeys_class, + 0 + } +}; + /* * Version 11.5 (Add octagon fields to device state) */ @@ -2867,6 +2920,7 @@ SecDbSchema const * const * kc_schemas = NULL; const SecDbSchema *v10_kc_schemas_dev[] = { &v12_0_schema, + &v11_6_schema, &v11_5_schema, &v11_4_schema, &v11_3_schema, @@ -2889,6 +2943,7 @@ const SecDbSchema *v10_kc_schemas_dev[] = { }; const SecDbSchema *v10_kc_schemas[] = { + &v11_6_schema, &v11_5_schema, &v11_4_schema, &v11_3_schema, diff --git a/OSX/sec/securityd/SecItemSchema.h b/keychain/securityd/SecItemSchema.h similarity index 98% rename from OSX/sec/securityd/SecItemSchema.h rename to keychain/securityd/SecItemSchema.h index 637553f7..adbcd3fc 100644 --- a/OSX/sec/securityd/SecItemSchema.h +++ b/keychain/securityd/SecItemSchema.h @@ -28,7 +28,7 @@ #ifndef _SECURITYD_SECITEMSCHEMA_H_ #define _SECURITYD_SECITEMSCHEMA_H_ -#include +#include "keychain/securityd/SecDbItem.h" __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecItemServer.c b/keychain/securityd/SecItemServer.c similarity index 99% rename from OSX/sec/securityd/SecItemServer.c rename to keychain/securityd/SecItemServer.c index 79cde4cb..039b8252 100644 --- a/OSX/sec/securityd/SecItemServer.c +++ b/keychain/securityd/SecItemServer.c @@ -33,19 +33,19 @@ #undef SHAREDWEBCREDENTIALS #endif -#include +#include "keychain/securityd/SecItemServer.h" #include -#include -#include -#include +#include "keychain/securityd/SecItemDataSource.h" +#include "keychain/securityd/SecItemDb.h" +#include "keychain/securityd/SecItemSchema.h" #include -#include -#include +#include "keychain/securityd/SecDbKeychainItem.h" +#include "keychain/securityd/SOSCloudCircleServer.h" #include #include #include -#include +#include "keychain/securityd/SecDbBackupManager.h" #import "keychain/SecureObjectSync/SOSChangeTracker.h" #include "keychain/SecureObjectSync/SOSDigestVector.h" #include "keychain/SecureObjectSync/SOSEngine.h" @@ -2990,7 +2990,7 @@ cleanup: CF_RETURNS_RETAINED CFDataRef _SecServerKeychainCreateBackup(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef *error) { - __block CFDataRef backup; + __block CFDataRef backup = NULL; kc_with_dbt(false, error, ^bool (SecDbConnectionRef dbt) { LKABackupReportStart(!!keybag, !!passcode, emcs); diff --git a/OSX/sec/securityd/SecItemServer.h b/keychain/securityd/SecItemServer.h similarity index 99% rename from OSX/sec/securityd/SecItemServer.h rename to keychain/securityd/SecItemServer.h index 7b550e49..91fcda27 100644 --- a/OSX/sec/securityd/SecItemServer.h +++ b/keychain/securityd/SecItemServer.h @@ -32,7 +32,7 @@ #include #include "keychain/SecureObjectSync/SOSCircle.h" -#include "securityd/SecDbQuery.h" +#include "keychain/securityd/SecDbQuery.h" #include "utilities/SecDb.h" #include #include "sec/ipc/securityd_client.h" diff --git a/OSX/sec/securityd/SecKeybagSupport.c b/keychain/securityd/SecKeybagSupport.c similarity index 96% rename from OSX/sec/securityd/SecKeybagSupport.c rename to keychain/securityd/SecKeybagSupport.c index d9c80487..d526c73f 100644 --- a/OSX/sec/securityd/SecKeybagSupport.c +++ b/keychain/securityd/SecKeybagSupport.c @@ -27,10 +27,10 @@ passwords.) */ -#include +#include "keychain/securityd/SecKeybagSupport.h" #include -#include +#include "keychain/securityd/SecItemServer.h" #if USE_KEYSTORE #include @@ -394,14 +394,16 @@ out: } const void* ks_ref_key_get_external_data(keybag_handle_t keybag, CFDataRef key_data, aks_ref_key_t *ref_key, size_t *external_data_len, CFErrorRef *error) { - const void* result = NULL; - int aks_return = kAKSReturnSuccess; - require_noerr_action_quiet(aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key), out, - SecError(errSecNotAvailable, error, CFSTR("aks_ref_key: %x failed to '%s' item (bag: %"PRId32")"), aks_return, "create ref key with blob", keybag)); - result = aks_ref_key_get_external_data(*ref_key, external_data_len); - -out: - return result; + int aks_return = aks_ref_key_create_with_blob(keybag, CFDataGetBytePtr(key_data), CFDataGetLength(key_data), ref_key); + if (aks_return == kAKSReturnBadArgument) { + SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob because bad data (bag: %"PRId32")"), keybag); + return NULL; + // As of this writing the only other error code is kAKSReturnInternalError but we don't want to rely on that + } else if (aks_return != kAKSReturnSuccess) { + SecError(errSecDecode, error, CFSTR("aks_ref_key: failed to create ref key with blob: %x (bag: %"PRId32")"), aks_return, keybag); + return NULL; + } + return aks_ref_key_get_external_data(*ref_key, external_data_len); } #endif diff --git a/OSX/sec/securityd/SecKeybagSupport.h b/keychain/securityd/SecKeybagSupport.h similarity index 100% rename from OSX/sec/securityd/SecKeybagSupport.h rename to keychain/securityd/SecKeybagSupport.h diff --git a/OSX/sec/securityd/SecLogSettingsServer.h b/keychain/securityd/SecLogSettingsServer.h similarity index 100% rename from OSX/sec/securityd/SecLogSettingsServer.h rename to keychain/securityd/SecLogSettingsServer.h diff --git a/OSX/sec/securityd/SecLogSettingsServer.m b/keychain/securityd/SecLogSettingsServer.m similarity index 95% rename from OSX/sec/securityd/SecLogSettingsServer.m rename to keychain/securityd/SecLogSettingsServer.m index fd15022f..4a15049c 100644 --- a/OSX/sec/securityd/SecLogSettingsServer.m +++ b/keychain/securityd/SecLogSettingsServer.m @@ -4,7 +4,7 @@ // // -#include +#include "keychain/securityd/SecLogSettingsServer.h" #include "keychain/SecureObjectSync/SOSAccountPriv.h" #include #include diff --git a/OSX/sec/securityd/SecOTRRemote.h b/keychain/securityd/SecOTRRemote.h similarity index 100% rename from OSX/sec/securityd/SecOTRRemote.h rename to keychain/securityd/SecOTRRemote.h diff --git a/OSX/sec/securityd/SecOTRRemote.m b/keychain/securityd/SecOTRRemote.m similarity index 98% rename from OSX/sec/securityd/SecOTRRemote.m rename to keychain/securityd/SecOTRRemote.m index 29c85ee7..cef0caf1 100644 --- a/OSX/sec/securityd/SecOTRRemote.m +++ b/keychain/securityd/SecOTRRemote.m @@ -26,8 +26,8 @@ #include "SecOTRRemote.h" #include #include -#include -#include +#include "keychain/securityd/SecItemServer.h" +#include "keychain/securityd/SOSCloudCircleServer.h" #include "SOSAccountPriv.h" diff --git a/OSX/sec/securityd/com.apple.secd.sb b/keychain/securityd/com.apple.secd.sb similarity index 98% rename from OSX/sec/securityd/com.apple.secd.sb rename to keychain/securityd/com.apple.secd.sb index fd9e6476..21f50f45 100644 --- a/OSX/sec/securityd/com.apple.secd.sb +++ b/keychain/securityd/com.apple.secd.sb @@ -55,6 +55,7 @@ (global-name "com.apple.cloudd") (global-name "com.apple.apsd") (global-name "com.apple.analyticsd") + (global-name "com.apple.symptom_diagnostics") (global-name "com.apple.ak.anisette.xpc") (global-name "com.apple.corefollowup.agent") (global-name "com.apple.windowserver.active") diff --git a/OSX/sec/securityd/entitlements.plist b/keychain/securityd/entitlements.plist similarity index 98% rename from OSX/sec/securityd/entitlements.plist rename to keychain/securityd/entitlements.plist index 5f8eecff..02625012 100644 --- a/OSX/sec/securityd/entitlements.plist +++ b/keychain/securityd/entitlements.plist @@ -90,5 +90,7 @@ com.apple.security.network.client + com.apple.symptom_diagnostics.report + diff --git a/OSX/sec/securityd/iCloudTrace.c b/keychain/securityd/iCloudTrace.c similarity index 96% rename from OSX/sec/securityd/iCloudTrace.c rename to keychain/securityd/iCloudTrace.c index 6ac75cfd..9d00ef33 100644 --- a/OSX/sec/securityd/iCloudTrace.c +++ b/keychain/securityd/iCloudTrace.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include "keychain/securityd/SecItemServer.h" #include #include #if TARGET_OS_OSX diff --git a/OSX/sec/securityd/iCloudTrace.h b/keychain/securityd/iCloudTrace.h similarity index 100% rename from OSX/sec/securityd/iCloudTrace.h rename to keychain/securityd/iCloudTrace.h diff --git a/OSX/sec/securityd/spi.c b/keychain/securityd/spi.c similarity index 96% rename from OSX/sec/securityd/spi.c rename to keychain/securityd/spi.c index 04fbc37a..80b10d3f 100644 --- a/OSX/sec/securityd/spi.c +++ b/keychain/securityd/spi.c @@ -30,24 +30,24 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wfour-char-constants" -#include "securityd/spi.h" +#include "keychain/securityd/spi.h" #include "ipc/SecdWatchdog.h" #include "ipc/server_security_helpers.h" #include "ipc/securityd_client.h" -#include "securityd/SecItemBackupServer.h" -#include "securityd/SecItemServer.h" +#include "keychain/securityd/SecItemBackupServer.h" +#include "keychain/securityd/SecItemServer.h" #include #include #include -#include "securityd/SOSCloudCircleServer.h" -#include "securityd/SecOTRRemote.h" -#include "securityd/SecLogSettingsServer.h" +#include "keychain/securityd/SOSCloudCircleServer.h" +#include "keychain/securityd/SecOTRRemote.h" +#include "keychain/securityd/SecLogSettingsServer.h" #include #include "utilities/iOSforOSX.h" #include "utilities/SecFileLocations.h" -#include "OTATrustUtilities.h" -#include "../../trustd/trustd_spi.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/trustd_spi.h" #pragma clang diagnostic pop diff --git a/OSX/sec/securityd/spi.h b/keychain/securityd/spi.h similarity index 100% rename from OSX/sec/securityd/spi.h rename to keychain/securityd/spi.h diff --git a/keychain/tpctl/main.swift b/keychain/tpctl/main.swift index 4ea34015..4f20f4b7 100644 --- a/keychain/tpctl/main.swift +++ b/keychain/tpctl/main.swift @@ -652,7 +652,7 @@ for command in commands { case .reset: os_log("resetting (%@, %@)", log: tplogDebug, type: .default, container, context) - tpHelper.reset(withContainer: container, context: context) { error in + tpHelper.reset(withContainer: container, context: context, resetReason: .userInitiatedReset) { error in guard error == nil else { print("Error during reset:", error!) return diff --git a/libsecurity_smime/lib/cmssiginfo.c b/libsecurity_smime/lib/cmssiginfo.c index 18ab6d45..c0d70ea9 100644 --- a/libsecurity_smime/lib/cmssiginfo.c +++ b/libsecurity_smime/lib/cmssiginfo.c @@ -62,6 +62,8 @@ #include #include +#include + #define HIDIGIT(v) (((v) / 10) + '0') #define LODIGIT(v) (((v) % 10) + '0') @@ -77,61 +79,18 @@ static OSStatus DER_UTCTimeToCFDate(const SecAsn1Item * utcTime, CFAbsoluteTime *date) { - char *string = (char *)utcTime->Data; - int year, month, mday, hour, minute, second, hourOff, minOff; - - /* Verify time is formatted properly and capture information */ - second = 0; - hourOff = 0; - minOff = 0; - CAPTURE(year,string+0,loser); - if (year < 50) { - /* ASSUME that year # is in the 2000's, not the 1900's */ - year += 2000; - } else { - year += 1900; - } - CAPTURE(month,string+2,loser); - if ((month == 0) || (month > 12)) goto loser; - CAPTURE(mday,string+4,loser); - if ((mday == 0) || (mday > 31)) goto loser; - CAPTURE(hour,string+6,loser); - if (hour > 23) goto loser; - CAPTURE(minute,string+8,loser); - if (minute > 59) goto loser; - if (ISDIGIT(string[10])) { - CAPTURE(second,string+10,loser); - if (second > 59) goto loser; - string += 2; - } - if (string[10] == '+') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - } else if (string[10] == '-') { - CAPTURE(hourOff,string+11,loser); - if (hourOff > 23) goto loser; - hourOff = -hourOff; - CAPTURE(minOff,string+13,loser); - if (minOff > 59) goto loser; - minOff = -minOff; - } else if (string[10] != 'Z') { - goto loser; + CFErrorRef error = NULL; + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + CFAbsoluteTime result = SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME, utcTime->Data, utcTime->Length, &error); + if (error) { + CFReleaseNull(error); + return SECFailure; } - if (hourOff == 0 && minOff == 0) { - *date = CFAbsoluteTimeForGregorianZuluMoment(year, month, mday, hour, minute, second); - } else { - CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, (hourOff * 60 + minOff) * 60); - *date = CFAbsoluteTimeForGregorianMoment(tz, year, month, mday, hour, minute, second); - CFReleaseSafe(tz); + if (date) { + *date = result; } - return SECSuccess; - -loser: - return SECFailure; } static OSStatus @@ -141,20 +100,24 @@ DER_CFDateToUTCTime(CFAbsoluteTime date, SecAsn1Item * utcTime) utcTime->Length = 13; utcTime->Data = d = PORT_Alloc(13); - if (!utcTime->Data) - return SECFailure; + if (!utcTime->Data) { + return SECFailure; + } __block int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; __block bool result; SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) { result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, date, "yMdHms", &year, &month, &day, &hour, &minute, &second); }); - if (!result) + if (!result) { return SECFailure; + } - /* UTC time does not handle the years before 1950 */ - if (year < 1950) + /* UTC time does not handle the years before 1950 or after 2049 */ + /* CMS attributes don't correctly encode/decode times (always use UTCTime) */ + if (year < 1950 || year > 2049) { return SECFailure; + } /* remove the century since it's added to the year by the CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */ diff --git a/secdtests/main.m b/secdtests/main.m index 822f2429..67e14ff3 100644 --- a/secdtests/main.m +++ b/secdtests/main.m @@ -16,7 +16,7 @@ #include "keychain/ckks/CKKS.h" -#include +#include "keychain/securityd/spi.h" int main(int argc, char * const *argv) { diff --git a/secdtests/testlist.h b/secdtests/testlist.h index 65e1aef4..8294cc74 100644 --- a/secdtests/testlist.h +++ b/secdtests/testlist.h @@ -1,2 +1,2 @@ /* Don't preent multiple inclusions of this file */ -#include +#include "keychain/securityd/Regressions/secd_regressions.h" diff --git a/secdxctests/KeychainAPITests.m b/secdxctests/KeychainAPITests.m index d2cdeec2..5c54545b 100644 --- a/secdxctests/KeychainAPITests.m +++ b/secdxctests/KeychainAPITests.m @@ -164,6 +164,8 @@ static void SecDbTestCorruptionHandler(void) } - (void)testCorruptionHandler { + __security_simulatecrash_enable(false); + SecDbCorruptionExitHandler = SecDbTestCorruptionHandler; sema = dispatch_semaphore_create(0); @@ -204,6 +206,8 @@ static void SecDbTestCorruptionHandler(void) } - (void)testRecoverFromCorruption { + __security_simulatecrash_enable(false); + // Setup does a reset, but that doesn't create the db yet so let's sneak in first __block struct stat before = {}; WithPathInKeychainDirectory(CFSTR("keychain-2.db"), ^(const char *filename) { diff --git a/secdxctests/KeychainCryptoTests.m b/secdxctests/KeychainCryptoTests.m index 1cd6e95e..bdf33b1b 100644 --- a/secdxctests/KeychainCryptoTests.m +++ b/secdxctests/KeychainCryptoTests.m @@ -430,6 +430,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testKeychainCorruptionAddOverCorruptedEntry { + __security_simulatecrash_enable(false); + CFTypeRef foundItem = NULL; NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding], @@ -460,6 +462,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testKeychainCorruptionUpdateCorruptedEntry { + __security_simulatecrash_enable(false); + CFTypeRef foundItem = NULL; NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword, (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding], @@ -594,6 +598,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) { - (void)testRecoverFromBadMetadataKey { + __security_simulatecrash_enable(false); + // Disable caching, so we can change AKS encrypt/decrypt id mockSecDbKeychainMetadataKeyStore = OCMClassMock([SecDbKeychainMetadataKeyStore class]); OCMStub([mockSecDbKeychainMetadataKeyStore cachingEnabled]).andReturn(false); diff --git a/secdxctests/KeychainXCTest.m b/secdxctests/KeychainXCTest.m index d763f70b..bab2a47c 100644 --- a/secdxctests/KeychainXCTest.m +++ b/secdxctests/KeychainXCTest.m @@ -132,6 +132,8 @@ - (void)setUp { + __security_simulatecrash_enable(true); + [super setUp]; self.lockState = LockStateUnlocked; diff --git a/securityd/etc/com.apple.securityd.sb b/securityd/etc/com.apple.securityd.sb index a6145ad0..c91b48fb 100644 --- a/securityd/etc/com.apple.securityd.sb +++ b/securityd/etc/com.apple.securityd.sb @@ -6,20 +6,20 @@ ;;; (version 1) -(allow (with report) default) -(allow (with report) file-map-executable process-info* nvram*) -(allow (with report) dynamic-code-generation) - +(deny default) +(deny file-map-executable process-info* nvram*) +(deny dynamic-code-generation) (deny mach-priv-host-port) (import "system.sb") (import "com.apple.corefoundation.sb") (corefoundation) -(allow file-read-metadata) -;; We inspect all the binaries -(allow file-read* - (subpath "/")) +;; We inspect all the binaries, +;; resolve symlinks, realpath(3), and equivalents, +;; read preference files in-process +(allow file-read*) + (allow file-write* (subpath "/private/var/db/mds")) (allow file-ioctl (literal "/dev/auditsessions")) diff --git a/sslViewer/sslEcdsa.cpp b/sslViewer/sslEcdsa.cpp index cb231ba5..b45ae859 100644 --- a/sslViewer/sslEcdsa.cpp +++ b/sslViewer/sslEcdsa.cpp @@ -27,7 +27,7 @@ #include #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif diff --git a/sslViewer/sslServer.cpp b/sslViewer/sslServer.cpp index 33b2bb64..fefc0898 100644 --- a/sslViewer/sslServer.cpp +++ b/sslViewer/sslServer.cpp @@ -48,7 +48,7 @@ #include "SecurityTool/sharedTool/print_cert.h" #if NO_SERVER -#include +#include "keychain/securityd/spi.h" #endif /* Set true when PR-3074739 is merged to TOT */ diff --git a/tests/SecDbBackupTests/SecDbBackupTests.m b/tests/SecDbBackupTests/SecDbBackupTests.m index 6c51b3d9..cb8d0e72 100644 --- a/tests/SecDbBackupTests/SecDbBackupTests.m +++ b/tests/SecDbBackupTests/SecDbBackupTests.m @@ -6,7 +6,7 @@ // #import -#import "securityd/SecDbBackupManager.h" +#import "keychain/securityd/SecDbBackupManager.h" #if !SECDB_BACKUPS_ENABLED @@ -18,7 +18,7 @@ #else // SECDB_BACKUPS_ENABLED -#import "securityd/SecDbBackupManager_Internal.h" +#import "keychain/securityd/SecDbBackupManager_Internal.h" #import "CKKS.h" #import diff --git a/tests/TrustTests/DaemonTests/LoggingServerTests.m b/tests/TrustTests/DaemonTests/LoggingServerTests.m index a577e8ee..6f7b6f53 100644 --- a/tests/TrustTests/DaemonTests/LoggingServerTests.m +++ b/tests/TrustTests/DaemonTests/LoggingServerTests.m @@ -8,7 +8,7 @@ #include #import -#import "../../../OSX/sec/securityd/SecTrustLoggingServer.h" +#import "trust/trustd/SecTrustLoggingServer.h" @interface LoggingServerTests : XCTestCase @end diff --git a/tests/TrustTests/EvaluationTests/CTTests.m b/tests/TrustTests/EvaluationTests/CTTests.m index d7e1fc91..7d058ee7 100644 --- a/tests/TrustTests/EvaluationTests/CTTests.m +++ b/tests/TrustTests/EvaluationTests/CTTests.m @@ -31,7 +31,7 @@ #include #include #include -#include +#include "trust/trustd/OTATrustUtilities.h" #if !TARGET_OS_BRIDGE #import @@ -1739,9 +1739,9 @@ errOut: CFReleaseNull(trust); } -// test apple subCA after date without CT passes +// test apple subCA after date without CT fails - (void) testAppleSubCAException { - SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, livability = NULL; + SecCertificateRef geoTrustRoot = NULL, appleISTCA8G1 = NULL, deprecatedSSLServer = NULL; SecTrustRef trust = NULL; SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("bbasile-test.scv.apple.com")); NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:576000000.0]; // April 3, 2019 at 9:00:00 AM PDT @@ -1751,16 +1751,48 @@ errOut: errOut, fail("failed to create geotrust root")); require_action(appleISTCA8G1 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA8G1"], errOut, fail("failed to create apple IST CA")); - require_action(livability = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"deprecatedSSLServer"], + require_action(deprecatedSSLServer = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"deprecatedSSLServer"], errOut, fail("failed to create deprecated SSL Server cert")); - certs = @[ (__bridge id)livability, (__bridge id)appleISTCA8G1 ]; + certs = @[ (__bridge id)deprecatedSSLServer, (__bridge id)appleISTCA8G1 ]; enforcement_anchors = @[ (__bridge id)geoTrustRoot ]; require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); - ok(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert failed"); +#if !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert passed"); +#endif + +errOut: + CFReleaseNull(geoTrustRoot); + CFReleaseNull(appleISTCA8G1); + CFReleaseNull(deprecatedSSLServer); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + +- (void) testBasejumper { + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, deprecatedSSLServer = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("basejumper.apple.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:576000000.0]; // April 3, 2019 at 9:00:00 AM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot"], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA2_Baltimore"], + errOut, fail("failed to create apple IST CA")); + require_action(deprecatedSSLServer = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"basejumper"], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)deprecatedSSLServer, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper cert failed"); #if !TARGET_OS_BRIDGE // bridgeOS doesn't ever enforce CT @@ -1768,7 +1800,7 @@ errOut: CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanTrue, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert succeeded with allowlist disabled"); + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper succeeded with allowlist disabled"); CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanFalse, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); @@ -1776,20 +1808,20 @@ errOut: CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistApple"), kCFBooleanTrue, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "apple public post-flag-date non-CT cert succeeded with Apple allowlist disabled"); + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "non-CT basejumper succeeded with Apple allowlist disabled"); CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistApple"), kCFBooleanFalse, CFSTR("com.apple.security")); CFPreferencesAppSynchronize(CFSTR("com.apple.security")); #endif // !TARGET_OS_BRIDGE errOut: - CFReleaseNull(geoTrustRoot); - CFReleaseNull(appleISTCA8G1); - CFReleaseNull(livability); + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(deprecatedSSLServer); CFReleaseNull(policy); CFReleaseNull(trust); } -// test google subCA after date without CT passes +// test google subCA after date without CT fails - (void) testGoogleSubCAException { SecCertificateRef globalSignRoot = NULL, googleIAG3 = NULL, google = NULL; SecTrustRef trust = NULL; @@ -1810,26 +1842,9 @@ errOut: require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); - ok(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert failed"); - #if !TARGET_OS_BRIDGE - // bridgeOS doesn't ever enforce CT - // Test with generic CT allowlist disable - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanTrue, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert succeeded with allowlist disabled"); - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlist"), kCFBooleanFalse, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - - // Test with Google allowlist disable - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistGoogle"), kCFBooleanTrue, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); - SecTrustSetNeedsEvaluation(trust); - XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert succeeded with Goole allowlist disabled"); - CFPreferencesSetAppValue(CFSTR("DisableCTAllowlistGoogle"), kCFBooleanFalse, CFSTR("com.apple.security")); - CFPreferencesAppSynchronize(CFSTR("com.apple.security")); -#endif // !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "google public post-flag-date non-CT cert passed"); +#endif errOut: CFReleaseNull(globalSignRoot); @@ -1838,4 +1853,45 @@ errOut: CFReleaseNull(policy); CFReleaseNull(trust); } + +// If pinning is disabled, pinned hostnames should continue to be exempt from CT +- (void) testSystemwidePinningDisable { + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, pinnedNonCT = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("iphonesubmissions.apple.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:580000000.0]; // May 19, 2019 at 4:06:40 PM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot"], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"AppleISTCA2_Baltimore"], + errOut, fail("failed to create apple IST CA")); + require_action(pinnedNonCT = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"iphonesubmissions"], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)pinnedNonCT, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs")); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "pinned non-CT cert failed"); + + // Test with pinning disabled + [defaults setBool:YES forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + SecTrustSetNeedsEvaluation(trust); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "pinned non-CT failed with pinning disabled"); + [defaults setBool:NO forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + +errOut: + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(pinnedNonCT); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + @end diff --git a/tests/TrustTests/EvaluationTests/PolicyTests.m b/tests/TrustTests/EvaluationTests/PolicyTests.m index 121f7414..e844ab74 100644 --- a/tests/TrustTests/EvaluationTests/PolicyTests.m +++ b/tests/TrustTests/EvaluationTests/PolicyTests.m @@ -54,6 +54,7 @@ #include #include #include +#include #import "TrustEvaluationTestCase.h" #include "../TestMacroConversions.h" @@ -96,4 +97,49 @@ const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies- }]; } +- (void)testPinningDisable +{ + SecCertificateRef baltimoreRoot = NULL, appleISTCA2 = NULL, pinnedNonCT = NULL; + SecTrustRef trust = NULL; + SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("caldav.icloud.com")); + NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:580000000.0]; // May 19, 2019 at 4:06:40 PM PDT + NSArray *certs = nil, *enforcement_anchors = nil; + NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.apple.security"]; + + require_action(baltimoreRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"BaltimoreCyberTrustRoot" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create geotrust root")); + require_action(appleISTCA2 = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"AppleISTCA2G1-Baltimore" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create apple IST CA")); + require_action(pinnedNonCT = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"caldav" + subdirectory:(NSString *)kSecTrustTestPinningPolicyResources], + errOut, fail("failed to create deprecated SSL Server cert")); + + certs = @[ (__bridge id)pinnedNonCT, (__bridge id)appleISTCA2 ]; + enforcement_anchors = @[ (__bridge id)baltimoreRoot ]; + require_noerr_action(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), errOut, fail("failed to create trust")); + require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date")); + require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforcement_anchors), errOut, fail("failed to set anchors")); + require_noerr_action(SecTrustSetPinningPolicyName(trust, kSecPolicyNameAppleAMPService), errOut, fail("failed to set policy name")); +#if !TARGET_OS_BRIDGE + XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "pinning against wrong profile succeeded"); +#endif + + // Test with pinning disabled + [defaults setBool:YES forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + SecTrustSetNeedsEvaluation(trust); + XCTAssert(SecTrustEvaluateWithError(trust, NULL), "failed to disable pinning"); + [defaults setBool:NO forKey:@"AppleServerAuthenticationNoPinning"]; + [defaults synchronize]; + +errOut: + CFReleaseNull(baltimoreRoot); + CFReleaseNull(appleISTCA2); + CFReleaseNull(pinnedNonCT); + CFReleaseNull(policy); + CFReleaseNull(trust); +} + @end diff --git a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h index 00311bcd..14836b9f 100644 --- a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h +++ b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h @@ -29,22 +29,28 @@ #include #include "../TrustEvaluationTestHelpers.h" +NS_ASSUME_NONNULL_BEGIN + @interface TrustEvaluationTestCase : XCTestCase -- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef _Nonnull)cert trustSettings:(id _Nonnull)trustSettings; // returns a persistent ref for call to removeTrustSettings, takes a dictionary or array of trust settings -- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef _Nonnull)cert; // returns a persistent ref for call to removeTrustSettings -- (void)removeTrustSettingsForCert:(SecCertificateRef _Nonnull)cert persistentRef:(id _Nullable)persistentRef; -- (void)setTestRootAsSystem:(const uint8_t* _Nonnull)sha256hash; // this is expected to be a 32-byte array +- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef)cert trustSettings:(id)trustSettings; // returns a persistent ref for call to removeTrustSettings, takes a dictionary or array of trust settings +- (id _Nullable)addTrustSettingsForCert:(SecCertificateRef)cert; // returns a persistent ref for call to removeTrustSettings +- (void)removeTrustSettingsForCert:(SecCertificateRef)cert persistentRef:(id _Nullable)persistentRef; +- (void)setTestRootAsSystem:(const uint8_t*)sha256hash; // this is expected to be a 32-byte array - (void)removeTestRootAsSystem; // ported from regressionBase -- (void)runCertificateTestForDirectory:(SecPolicyRef _Nonnull)policy subDirectory:(NSString * _Nonnull)resourceSubDirectory verifyDate:(NSDate* _Nonnull)date; +- (void)runCertificateTestForDirectory:(SecPolicyRef)policy subDirectory:(NSString *)resourceSubDirectory verifyDate:(NSDate*)date; + +- (id _Nullable) CF_RETURNS_RETAINED SecCertificateCreateFromResource:(NSString * )name subdirectory:(NSString *)dir; @end /* Use this interface to get a SecCertificateRef that has the same CFTypeID * as used by the Security framework */ CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * _Nonnull der_bytes, CFIndex der_length); +SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * der_bytes, CFIndex der_length); CF_RETURNS_RETAINED _Nullable -SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef _Nonnull cert); +SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef cert); + +NS_ASSUME_NONNULL_END #endif /* _TRUSTTESTS_EVALUATION_TESTCASE_H_ */ diff --git a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m index 72596ab5..76dfe001 100644 --- a/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m +++ b/tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m @@ -22,7 +22,7 @@ * */ #import -#include "OSX/trustd/trustd_spi.h" +#include "trust/trustd/trustd_spi.h" #include #include #include @@ -171,14 +171,24 @@ const CFStringRef kTestSystemRootKey = CFSTR("TestSystemRoot"); CFPreferencesAppSynchronize(kSecurityPreferencesDomain); } +- (id _Nullable) CF_RETURNS_RETAINED SecCertificateCreateFromResource:(NSString *)name + subdirectory:(NSString *)dir +{ + NSURL *url = [[NSBundle bundleForClass:[self class]] URLForResource:name withExtension:@".cer" + subdirectory:dir]; + NSData *certData = [NSData dataWithContentsOfURL:url]; + SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef)certData); + return (__bridge id)cert; +} + /* MARK: run test methods from regressionBase */ - (void)runOneLeafTest:(SecPolicyRef)policy - anchors:(NSArray *)anchors - intermediates:(NSArray *)intermediates - leafPath:(NSString *)path - expectedResult:(bool)expectedResult - expectations:(NSObject *)expectations - verifyDate:(NSDate *)date + anchors:(NSArray *)anchors + intermediates:(NSArray *)intermediates + leafPath:(NSString *)path + expectedResult:(bool)expectedResult + expectations:(NSObject *)expectations + verifyDate:(NSDate *)date { NSString* fileName = [path lastPathComponent]; NSString *reason = NULL; diff --git a/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m b/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m index 8e8e0b70..2e5c8dea 100644 --- a/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m +++ b/tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m @@ -32,7 +32,7 @@ #include #include "OSX/sec/Security/SecFramework.h" #include "OSX/utilities/SecCFWrappers.h" -#include +#include "trust/trustd/OTATrustUtilities.h" #include #include #include diff --git a/tests/secdmockaks/mockaksKeychain.m b/tests/secdmockaks/mockaksKeychain.m index 120d8fa0..27662ddd 100644 --- a/tests/secdmockaks/mockaksKeychain.m +++ b/tests/secdmockaks/mockaksKeychain.m @@ -136,6 +136,9 @@ - (void)testSecItemServerDeleteAll { + [self addAccessGroup:@"com.apple.bluetooth"]; + [self addAccessGroup:@"lockdown-identities"]; + // BT root key, should not be deleted NSMutableDictionary* bt = [@{ (id)kSecClass : (id)kSecClassGenericPassword, diff --git a/tests/secdmockaks/mockaksxcbase.h b/tests/secdmockaks/mockaksxcbase.h index 63ec0791..0ca77a31 100644 --- a/tests/secdmockaks/mockaksxcbase.h +++ b/tests/secdmockaks/mockaksxcbase.h @@ -14,6 +14,8 @@ - (NSString*)createKeychainDirectoryWithSubPath:(NSString*)subpath; +- (void)addAccessGroup:(NSString *)accessGroup; + @end #endif /* mockaksxcbase_h */ diff --git a/tests/secdmockaks/mockaksxcbase.m b/tests/secdmockaks/mockaksxcbase.m index 3d111f3e..22dfdc0a 100644 --- a/tests/secdmockaks/mockaksxcbase.m +++ b/tests/secdmockaks/mockaksxcbase.m @@ -11,6 +11,7 @@ #import "SecItemPriv.h" #import "SecItemServer.h" #import "spi.h" +#include #import #import #import @@ -23,12 +24,21 @@ NSString* homeDirUUID; +@interface mockaksxcbase () +@property NSArray* originalAccessGroups; +@property NSMutableArray* currentAccessGroups; +@end + + @implementation mockaksxcbase + (void)setUp { [super setUp]; + securityd_init_local_spi(); + securityd_init(NULL); + SecCKKSDisable(); /* * Disable all of SOS syncing since that triggers retains of database @@ -43,6 +53,12 @@ NSString* homeDirUUID; homeDirUUID = [[NSUUID UUID] UUIDString]; } +- (void)addAccessGroup:(NSString *)accessGroup +{ + [self.currentAccessGroups addObject:accessGroup]; + SecAccessGroupsSetCurrent((__bridge CFArrayRef)self.currentAccessGroups); +} + - (NSString*)createKeychainDirectoryWithSubPath:(NSString*)suffix { NSError* error; @@ -62,6 +78,8 @@ NSString* homeDirUUID; - (void)setUp { [super setUp]; + self.originalAccessGroups = (__bridge NSArray *)SecAccessGroupsGetCurrent(); + self.currentAccessGroups = [self.originalAccessGroups mutableCopy]; NSString* testName = [self.name componentsSeparatedByString:@" "][1]; testName = [testName stringByReplacingOccurrencesOfString:@"]" withString:@""]; @@ -71,20 +89,24 @@ NSString* homeDirUUID; [self createKeychainDirectory]; SetCustomHomeURLString((__bridge CFStringRef) self.testHomeDirectory); - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - securityd_init(NULL); - }); SecKeychainDbReset(NULL); // Actually load the database. kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { return false; }); } +- (void)tearDown +{ + SecAccessGroupsSetCurrent((__bridge CFArrayRef)self.originalAccessGroups); + [super tearDown]; +} + + (void)tearDown { SetCustomHomeURLString(NULL); SecKeychainDbReset(NULL); } + + @end diff --git a/trust/SecCertificate.h b/trust/headers/SecCertificate.h similarity index 100% rename from trust/SecCertificate.h rename to trust/headers/SecCertificate.h diff --git a/trust/SecCertificatePriv.h b/trust/headers/SecCertificatePriv.h similarity index 95% rename from trust/SecCertificatePriv.h rename to trust/headers/SecCertificatePriv.h index 3fa2fe4e..086f48ac 100644 --- a/trust/SecCertificatePriv.h +++ b/trust/headers/SecCertificatePriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2004,2006-2017 Apple Inc. All Rights Reserved. + * Copyright (c) 2002-2004,2006-2019 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -339,16 +340,33 @@ SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificate /*! @function SecCertificateCopyProperties - @abstract Return a property array for this trust certificate. + @abstract Return a property array for this certificate. @param certificate A reference to the certificate to evaluate. - @result A property array. It is the caller's responsability to CFRelease + @result A property array. It is the caller's responsibility to CFRelease the returned array when it is no longer needed. - See SecTrustCopySummaryPropertiesAtIndex on how to intepret this array. - Unlike that function call this function returns a detailed description - of the certificate in question. + See SecTrustCopySummaryPropertiesAtIndex on how to interpret this array. + Unlike that function, this function returns a detailed description of the + certificate. Note that localized description strings are returned by default. + Use SecCertificateCopyLocalizedProperties if your code needs to explicitly + specify whether the strings are localized. */ CFArrayRef SecCertificateCopyProperties(SecCertificateRef certificate); +/*! + @function SecCertificateCopyLocalizedProperties + @abstract Return a property array for this certificate. + @param certificate A reference to the certificate to evaluate. + @param localized A value which specifies whether string properties + are localized. If false, description strings will not be localized. + @result A property array. It is the caller's responsibility to CFRelease + the returned array when it is no longer needed. + See SecTrustCopySummaryPropertiesAtIndex on how to interpret this array. + Unlike that function, this function returns a detailed description of the + certificate. + */ +CFArrayRef SecCertificateCopyLocalizedProperties(SecCertificateRef certificate, Boolean localized) + API_AVAILABLE(macos(10.15.1), ios(13.2), watchos(6.1), tvos(13.1)); + /* Returns an array of CFDataRefs for all embedded SCTs */ CFArrayRef SecCertificateCopySignedCertificateTimestamps(SecCertificateRef certificate) __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_9_0); @@ -443,6 +461,8 @@ CFStringRef SecCertificateCopyComponentType(SecCertificateRef certificate) bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate, CFAbsoluteTime *time, CFErrorRef * CF_RETURNS_RETAINED error); +CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, const uint8_t *bytes, size_t length, CFErrorRef *error); + /* * Legacy functions (OS X only) */ diff --git a/trust/SecCertificateRequest.h b/trust/headers/SecCertificateRequest.h similarity index 100% rename from trust/SecCertificateRequest.h rename to trust/headers/SecCertificateRequest.h diff --git a/trust/SecPolicy.h b/trust/headers/SecPolicy.h similarity index 100% rename from trust/SecPolicy.h rename to trust/headers/SecPolicy.h diff --git a/trust/SecPolicyPriv.h b/trust/headers/SecPolicyPriv.h similarity index 99% rename from trust/SecPolicyPriv.h rename to trust/headers/SecPolicyPriv.h index 360e7faa..781fb65f 100644 --- a/trust/SecPolicyPriv.h +++ b/trust/headers/SecPolicyPriv.h @@ -208,6 +208,7 @@ extern const CFStringRef kSecPolicyAppleLegacySSL @constant kSecPolicyNameAppleParsecService @constant kSecPolicyNameAppleAMPService @constant kSecPolicyNameAppleSiriService + @constant kSecPolicyNameAppleHomeAppClipUploadService */ extern const CFStringRef kSecPolicyNameAppleAST2Service __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0); @@ -241,6 +242,8 @@ extern const CFStringRef kSecPolicyNameAppleAMPService API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); extern const CFStringRef kSecPolicyNameAppleSiriService API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0)); +extern const CFStringRef kSecPolicyNameAppleHomeAppClipUploadService + API_AVAILABLE(macos(10.15.1), ios(13.2), watchos(6.1), tvos(13.1)); /*! @enum Policy Value Constants diff --git a/trust/SecTrust.h b/trust/headers/SecTrust.h similarity index 100% rename from trust/SecTrust.h rename to trust/headers/SecTrust.h diff --git a/trust/SecTrustPriv.h b/trust/headers/SecTrustPriv.h similarity index 100% rename from trust/SecTrustPriv.h rename to trust/headers/SecTrustPriv.h diff --git a/trust/SecTrustSettings.h b/trust/headers/SecTrustSettings.h similarity index 100% rename from trust/SecTrustSettings.h rename to trust/headers/SecTrustSettings.h diff --git a/trust/SecTrustSettingsPriv.h b/trust/headers/SecTrustSettingsPriv.h similarity index 100% rename from trust/SecTrustSettingsPriv.h rename to trust/headers/SecTrustSettingsPriv.h diff --git a/trust/oids.h b/trust/headers/oids.h similarity index 100% rename from trust/oids.h rename to trust/headers/oids.h diff --git a/OSX/sec/securityd/OTATrustUtilities.h b/trust/trustd/OTATrustUtilities.h similarity index 100% rename from OSX/sec/securityd/OTATrustUtilities.h rename to trust/trustd/OTATrustUtilities.h diff --git a/OSX/sec/securityd/OTATrustUtilities.m b/trust/trustd/OTATrustUtilities.m similarity index 99% rename from OSX/sec/securityd/OTATrustUtilities.m rename to trust/trustd/OTATrustUtilities.m index c9510aa0..f3e59709 100644 --- a/OSX/sec/securityd/OTATrustUtilities.m +++ b/trust/trustd/OTATrustUtilities.m @@ -53,7 +53,7 @@ #include #include #include -#include +#include "trust/trustd/SecPinningDb.h" #import #if !TARGET_OS_BRIDGE @@ -62,7 +62,7 @@ #include #include #include -#import +#import "trust/trustd/SecTrustLoggingServer.h" #endif #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR diff --git a/OSX/sec/securityd/SecCAIssuerCache.c b/trust/trustd/SecCAIssuerCache.c similarity index 99% rename from OSX/sec/securityd/SecCAIssuerCache.c rename to trust/trustd/SecCAIssuerCache.c index 5921de5b..70175d40 100644 --- a/OSX/sec/securityd/SecCAIssuerCache.c +++ b/trust/trustd/SecCAIssuerCache.c @@ -26,8 +26,8 @@ * SecCAIssuerCache.c - securityd */ -#include -#include +#include "trust/trustd/SecCAIssuerCache.h" +#include "trust/trustd/SecTrustLoggingServer.h" #include #include #include diff --git a/OSX/sec/securityd/SecCAIssuerCache.h b/trust/trustd/SecCAIssuerCache.h similarity index 97% rename from OSX/sec/securityd/SecCAIssuerCache.h rename to trust/trustd/SecCAIssuerCache.h index 152035d8..e82ba1d8 100644 --- a/OSX/sec/securityd/SecCAIssuerCache.h +++ b/trust/trustd/SecCAIssuerCache.h @@ -31,7 +31,7 @@ #ifndef _SECURITY_SECCAISSUERCACHE_H_ #define _SECURITY_SECCAISSUERCACHE_H_ -#include +#include "trust/trustd/SecCAIssuerRequest.h" #include #include #include diff --git a/OSX/sec/securityd/SecCAIssuerRequest.h b/trust/trustd/SecCAIssuerRequest.h similarity index 100% rename from OSX/sec/securityd/SecCAIssuerRequest.h rename to trust/trustd/SecCAIssuerRequest.h diff --git a/OSX/sec/securityd/SecCAIssuerRequest.m b/trust/trustd/SecCAIssuerRequest.m similarity index 99% rename from OSX/sec/securityd/SecCAIssuerRequest.m rename to trust/trustd/SecCAIssuerRequest.m index b7b31d41..b38d91cd 100644 --- a/OSX/sec/securityd/SecCAIssuerRequest.m +++ b/trust/trustd/SecCAIssuerRequest.m @@ -37,8 +37,8 @@ #include #include #include -#include -#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/TrustURLSessionDelegate.h" #include #include diff --git a/OSX/sec/securityd/SecCertificateServer.c b/trust/trustd/SecCertificateServer.c similarity index 99% rename from OSX/sec/securityd/SecCertificateServer.c rename to trust/trustd/SecCertificateServer.c index 39e8ee37..6ddca031 100644 --- a/OSX/sec/securityd/SecCertificateServer.c +++ b/trust/trustd/SecCertificateServer.c @@ -43,10 +43,10 @@ #include #include -#include -#include -#include -#include +#include "trust/trustd/policytree.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecRevocationServer.h" // MARK: - // MARK: SecCertificateVC diff --git a/OSX/sec/securityd/SecCertificateServer.h b/trust/trustd/SecCertificateServer.h similarity index 99% rename from OSX/sec/securityd/SecCertificateServer.h rename to trust/trustd/SecCertificateServer.h index 96b3b44b..91486de4 100644 --- a/OSX/sec/securityd/SecCertificateServer.h +++ b/trust/trustd/SecCertificateServer.h @@ -34,7 +34,7 @@ #include -#include "securityd/policytree.h" +#include "trust/trustd/policytree.h" typedef struct SecCertificateVC *SecCertificateVCRef; diff --git a/OSX/sec/securityd/SecCertificateSource.c b/trust/trustd/SecCertificateSource.c similarity index 99% rename from OSX/sec/securityd/SecCertificateSource.c rename to trust/trustd/SecCertificateSource.c index 26464069..1c7932e7 100644 --- a/OSX/sec/securityd/SecCertificateSource.c +++ b/trust/trustd/SecCertificateSource.c @@ -40,10 +40,10 @@ #include #include -#include -#include -#include -#include +#include "trust/trustd/SecTrustServer.h" +#include "keychain/securityd/SecItemServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecCAIssuerRequest.h" #include "OTATrustUtilities.h" #include "SecCertificateSource.h" diff --git a/OSX/sec/securityd/SecCertificateSource.h b/trust/trustd/SecCertificateSource.h similarity index 100% rename from OSX/sec/securityd/SecCertificateSource.h rename to trust/trustd/SecCertificateSource.h diff --git a/OSX/sec/securityd/SecOCSPCache.c b/trust/trustd/SecOCSPCache.c similarity index 99% rename from OSX/sec/securityd/SecOCSPCache.c rename to trust/trustd/SecOCSPCache.c index 5c221b71..c16d9e21 100644 --- a/OSX/sec/securityd/SecOCSPCache.c +++ b/trust/trustd/SecOCSPCache.c @@ -27,8 +27,8 @@ #include #include -#include -#include +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecTrustLoggingServer.h" #include #include #include diff --git a/OSX/sec/securityd/SecOCSPCache.h b/trust/trustd/SecOCSPCache.h similarity index 99% rename from OSX/sec/securityd/SecOCSPCache.h rename to trust/trustd/SecOCSPCache.h index 39a9744c..6fef3f36 100644 --- a/OSX/sec/securityd/SecOCSPCache.h +++ b/trust/trustd/SecOCSPCache.h @@ -31,8 +31,8 @@ #ifndef _SECURITY_SECOCSPCACHE_H_ #define _SECURITY_SECOCSPCACHE_H_ -#include "securityd/SecOCSPRequest.h" -#include "securityd/SecOCSPResponse.h" +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" #include __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecOCSPRequest.c b/trust/trustd/SecOCSPRequest.c similarity index 99% rename from OSX/sec/securityd/SecOCSPRequest.c rename to trust/trustd/SecOCSPRequest.c index d7081b83..2e9578b5 100644 --- a/OSX/sec/securityd/SecOCSPRequest.c +++ b/trust/trustd/SecOCSPRequest.c @@ -25,7 +25,7 @@ * SecOCSPRequest.c - Trust policies dealing with certificate revocation. */ -#include +#include "trust/trustd/SecOCSPRequest.h" #include #include #include diff --git a/OSX/sec/securityd/SecOCSPRequest.h b/trust/trustd/SecOCSPRequest.h similarity index 100% rename from OSX/sec/securityd/SecOCSPRequest.h rename to trust/trustd/SecOCSPRequest.h diff --git a/OSX/sec/securityd/SecOCSPResponse.c b/trust/trustd/SecOCSPResponse.c similarity index 99% rename from OSX/sec/securityd/SecOCSPResponse.c rename to trust/trustd/SecOCSPResponse.c index 2a38dfab..0d1995a6 100644 --- a/OSX/sec/securityd/SecOCSPResponse.c +++ b/trust/trustd/SecOCSPResponse.c @@ -25,7 +25,7 @@ * SecOCSPResponse.c - Wrapper to decode ocsp responses. */ -#include +#include "trust/trustd/SecOCSPResponse.h" #include #include diff --git a/OSX/sec/securityd/SecOCSPResponse.h b/trust/trustd/SecOCSPResponse.h similarity index 99% rename from OSX/sec/securityd/SecOCSPResponse.h rename to trust/trustd/SecOCSPResponse.h index 0398c438..91eec797 100644 --- a/OSX/sec/securityd/SecOCSPResponse.h +++ b/trust/trustd/SecOCSPResponse.h @@ -34,7 +34,7 @@ #include #include #include -#include "securityd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPRequest.h" #include __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecPinningDb.h b/trust/trustd/SecPinningDb.h similarity index 100% rename from OSX/sec/securityd/SecPinningDb.h rename to trust/trustd/SecPinningDb.h diff --git a/OSX/sec/securityd/SecPinningDb.m b/trust/trustd/SecPinningDb.m similarity index 96% rename from OSX/sec/securityd/SecPinningDb.m rename to trust/trustd/SecPinningDb.m index b0308ccb..a62b9256 100644 --- a/OSX/sec/securityd/SecPinningDb.m +++ b/trust/trustd/SecPinningDb.m @@ -44,9 +44,9 @@ #import -#import -#import -#import +#import "trust/trustd/OTATrustUtilities.h" +#import "trust/trustd/SecPinningDb.h" +#import "trust/trustd/SecTrustLoggingServer.h" #include "utilities/debugging.h" #include "utilities/sqlutils.h" @@ -567,13 +567,16 @@ static void verify_create_path(const char *path) NSDictionary *resultDictionary = [cacheEntry objectForKey:regex]; /* Check the policyName for no-pinning settings */ - if ([self isPinningDisabled:resultDictionary[(__bridge NSString *)kSecPinningDbKeyPolicyName]]) { - continue; - } - /* Return the pinning rules */ if (results) { - *results = resultDictionary; + /* Check the no-pinning settings to determine whether to use the rules */ + NSString *policyName = resultDictionary[(__bridge NSString *)kSecPinningDbKeyPolicyName]; + if ([self isPinningDisabled:policyName]) { + *results = @{ (__bridge NSString*)kSecPinningDbKeyRules:@[@{}], + (__bridge NSString*)kSecPinningDbKeyPolicyName:policyName}; + } else { + *results = resultDictionary; + } } } } @@ -621,11 +624,6 @@ static void verify_create_path(const char *path) if (!_queue) { (void)[self init]; } if (!_db) { [self initializedDb]; } - /* Check for general no-pinning setting */ - if ([self isPinningDisabled:nil]) { - return nil; - } - /* parse the domain into suffix and 1st label */ NSRange firstDot = [domain rangeOfString:@"."]; if (firstDot.location == NSNotFound) { return nil; } // Probably not a legitimate domain name @@ -688,11 +686,6 @@ static void verify_create_path(const char *path) } secinfo("SecPinningDb", "found matching rule in DB for %@.%@", firstLabel, suffix); - /* Check the policyName for no-pinning settings */ - if ([self isPinningDisabled:policyNameStr]) { - return; - } - /* Add return data * @@@ Assumes there is only one rule with matching suffix/label pairs. */ [resultRules addObjectsFromArray:(NSArray *)policies]; @@ -723,9 +716,16 @@ static void verify_create_path(const char *path) /* Return results if found */ if ([resultRules count] > 0) { - NSDictionary *results = @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, - (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; - return results; + /* Check for general no-pinning setting and return empty rules. We want to still return a + * a policy name so that requirements that don't apply to pinned domains continue to not + * apply. */ + if ([self isPinningDisabled:resultName]) { + return @{ (__bridge NSString*)kSecPinningDbKeyRules:@[@{}], + (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; + } + + return @{(__bridge NSString*)kSecPinningDbKeyRules:resultRules, + (__bridge NSString*)kSecPinningDbKeyPolicyName:resultName}; } return nil; } diff --git a/OSX/sec/securityd/SecPolicyServer.c b/trust/trustd/SecPolicyServer.c similarity index 97% rename from OSX/sec/securityd/SecPolicyServer.c rename to trust/trustd/SecPolicyServer.c index 03775ed2..d17d3bbd 100644 --- a/OSX/sec/securityd/SecPolicyServer.c +++ b/trust/trustd/SecPolicyServer.c @@ -25,12 +25,12 @@ * SecPolicyServer.c - Engine for evaluating certificate paths against trust policies. */ -#include +#include "trust/trustd/SecPolicyServer.h" #include #include #include -#include -#include +#include "trust/trustd/policytree.h" +#include "trust/trustd/nameconstraints.h" #include #include #include @@ -54,13 +54,13 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecRevocationServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include "trust/trustd/SecOCSPResponse.h" +#include "trust/trustd/SecTrustStoreServer.h" #include #include #include @@ -2330,60 +2330,27 @@ static bool is_ct_excepted(SecPVCRef pvc) { return result; } -/* some Apple servers not getting certs with embedded SCTs - * some Google apps have their own TLS stacks and aren't passing us TLS SCTs */ -static bool is_ct_allowlisted_ca(SecCertificatePathVCRef path) { - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlist"), CFSTR("com.apple.security"), NULL)) { +/* some Apple servers not getting certs with embedded SCTs */ +static bool is_ct_allowlisted_cert(SecCertificateRef leaf) { + if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlist"), CFSTR("com.apple.security"), NULL) || + CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistApple"), CFSTR("com.apple.security"), NULL)) { return false; } - /* subject:/CN=Apple IST CA 8 - G1/OU=Certification Authority/O=Apple Inc./C=US */ - /* issuer :/C=US/O=GeoTrust Inc./OU=(c) 2007 GeoTrust Inc. - For authorized use only/CN=GeoTrust Primary Certification Authority - G2 */ - static const uint8_t appleISTCA8G1_spkiSHA256[] = { - 0xe2, 0x4f, 0x8e, 0x8c, 0x21, 0x85, 0xda, 0x2f, 0x5e, 0x88, 0xd4, 0x57, 0x9e, 0x81, 0x7c, 0x47, - 0xbf, 0x6e, 0xaf, 0xbc, 0x85, 0x05, 0xf0, 0xf9, 0x60, 0xfd, 0x5a, 0x0d, 0xf4, 0x47, 0x3a, 0xd3 - }; - - /* subject:/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */ - /* issuer :/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA */ - static const uint8_t appleISTCA2G1_spkiSHA256[] = { - 0xb5, 0xcf, 0x82, 0xd4, 0x7e, 0xf9, 0x82, 0x3f, 0x9a, 0xa7, 0x8f, 0x12, 0x31, 0x86, 0xc5, 0x2e, - 0x88, 0x79, 0xea, 0x84, 0xb0, 0xf8, 0x22, 0xc9, 0x1d, 0x83, 0xe0, 0x42, 0x79, 0xb7, 0x8f, 0xd5 - }; - - /* subject:/C=US/O=Google Trust Services/CN=Google Internet Authority G3 */ - /* issuer :/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign */ - static const uint8_t googleIAG3_spkiSHA256[] = { - 0x7f, 0xc3, 0x67, 0x10, 0x56, 0x71, 0x43, 0x81, 0x31, 0x14, 0xe8, 0x52, 0x37, 0xb1, 0x22, 0x15, - 0x6b, 0x62, 0xb9, 0xd6, 0x50, 0x54, 0x3d, 0xa8, 0x63, 0xad, 0x2e, 0x6a, 0xe5, 0x7f, 0x9f, 0xbf + /* subject:/CN=basejumper.apple.com/OU=management:idms.group.110621/O=Apple Inc./ST=California/C=US */ + /* issuer :/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */ + static const uint8_t basejumper_hash[] = { + 0x23, 0x32, 0x0b, 0x5a, 0x24, 0xd8, 0x4d, 0x27, 0x8c, 0x43, 0xc9, 0xed, 0x22, 0xed, 0x87, 0xb7, + 0xc5, 0x51, 0x43, 0x55, 0xa9, 0x84, 0x79, 0x5a, 0x77, 0xb9, 0xad, 0x0f, 0x88, 0x14, 0x61, 0xac, }; bool result = false; - for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) { - SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX); - - bool allowlistAppleCAs = true, allowlistGoogleCA = true; - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistApple"), CFSTR("com.apple.security"), NULL)) { - allowlistAppleCAs = false; - } - if (CFPreferencesGetAppBooleanValue(CFSTR("DisableCTAllowlistGoogle"), CFSTR("com.apple.security"), NULL)) { - allowlistGoogleCA = false; - } - - CFDataRef caSPKIHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca); - const uint8_t *dp = CFDataGetBytePtr(caSPKIHash); - if (dp && allowlistAppleCAs && (!memcmp(appleISTCA8G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH) || - !memcmp(appleISTCA2G1_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH))) { - result = true; - } - if (dp && allowlistGoogleCA && !memcmp(googleIAG3_spkiSHA256, dp, CC_SHA256_DIGEST_LENGTH)) { - result = true; - } - CFReleaseNull(caSPKIHash); - if (result) { - break; - } + CFDataRef leaf_fingerprint = SecCertificateCopySHA256Digest(leaf); + const uint8_t *dp = CFDataGetBytePtr(leaf_fingerprint); + if (dp && !memcmp(basejumper_hash, dp, CC_SHA256_DIGEST_LENGTH)) { + result = true; } + CFReleaseNull(leaf_fingerprint); return result; } @@ -2421,7 +2388,7 @@ static void SecPolicyCheckSystemTrustedCTRequired(SecPVCRef pvc) { require_quiet(SecPathBuilderIsAnchored(pvc->builder), out); require_quiet((SecCertificateSourceContains(kSecSystemAnchorSource, root) && appleAnchorSource && !SecCertificateSourceContains(appleAnchorSource, root) && - !is_ct_allowlisted_ca(path)) || + !is_ct_allowlisted_cert(leaf)) || is_configured_test_system_root(root, CFSTR("TestCTRequiredSystemRoot")), out); if (!SecCertificatePathVCIsCT(path) && !is_ct_excepted(pvc)) { @@ -2568,7 +2535,7 @@ void SecPolicyServerInitialize(void) { #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \ __PC_ADD_CHECK_##LEAFCHECK(NAME) \ __PC_ADD_CHECK_##PATHCHECK(NAME) -#include "../Security/SecPolicyChecks.list" +#include "OSX/sec/Security/SecPolicyChecks.list" /* Some of these don't follow the naming conventions but are in the Pinning DB. * fix policy check constant values */ @@ -2807,7 +2774,7 @@ static SecTrustResultType trust_result_for_key(CFStringRef key) { if (__PC_TYPE_MEMBER_##TRUSTRESULT && CFEqual(key,CFSTR(#NAME))) { \ result = __TRUSTRESULT_##TRUSTRESULT; \ } -#include "../Security/SecPolicyChecks.list" +#include "OSX/sec/Security/SecPolicyChecks.list" return result; } diff --git a/OSX/sec/securityd/SecPolicyServer.h b/trust/trustd/SecPolicyServer.h similarity index 97% rename from OSX/sec/securityd/SecPolicyServer.h rename to trust/trustd/SecPolicyServer.h index 5c58babb..fbeebb82 100644 --- a/OSX/sec/securityd/SecPolicyServer.h +++ b/trust/trustd/SecPolicyServer.h @@ -34,8 +34,8 @@ #include "Security/SecPolicyInternal.h" #include -#include "securityd/SecTrustServer.h" -#include "securityd/SecCertificateServer.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecCertificateServer.h" __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecRevocationDb.c b/trust/trustd/SecRevocationDb.c similarity index 99% rename from OSX/sec/securityd/SecRevocationDb.c rename to trust/trustd/SecRevocationDb.c index 2e29051c..92f9ae42 100644 --- a/OSX/sec/securityd/SecRevocationDb.c +++ b/trust/trustd/SecRevocationDb.c @@ -26,10 +26,10 @@ * SecRevocationDb.c */ -#include -#include -#include -#include +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/SecRevocationNetworking.h" +#include "trust/trustd/SecTrustLoggingServer.h" #include #include #include diff --git a/OSX/sec/securityd/SecRevocationDb.h b/trust/trustd/SecRevocationDb.h similarity index 100% rename from OSX/sec/securityd/SecRevocationDb.h rename to trust/trustd/SecRevocationDb.h diff --git a/OSX/sec/securityd/SecRevocationNetworking.h b/trust/trustd/SecRevocationNetworking.h similarity index 96% rename from OSX/sec/securityd/SecRevocationNetworking.h rename to trust/trustd/SecRevocationNetworking.h index 8c36345d..e642f193 100644 --- a/OSX/sec/securityd/SecRevocationNetworking.h +++ b/trust/trustd/SecRevocationNetworking.h @@ -26,7 +26,7 @@ #define _SECURITY_SECREVOCATIONNETWORKING_H_ #import -#import +#import "trust/trustd/SecRevocationServer.h" bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version); bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert); diff --git a/OSX/sec/securityd/SecRevocationNetworking.m b/trust/trustd/SecRevocationNetworking.m similarity index 100% rename from OSX/sec/securityd/SecRevocationNetworking.m rename to trust/trustd/SecRevocationNetworking.m diff --git a/OSX/sec/securityd/SecRevocationServer.c b/trust/trustd/SecRevocationServer.c similarity index 99% rename from OSX/sec/securityd/SecRevocationServer.c rename to trust/trustd/SecRevocationServer.c index b81b047e..266bdba3 100644 --- a/OSX/sec/securityd/SecRevocationServer.c +++ b/trust/trustd/SecRevocationServer.c @@ -39,16 +39,16 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecRevocationNetworking.h" + +#include "trust/trustd/SecRevocationServer.h" // MARK: SecORVCRef /******************************************************** diff --git a/OSX/sec/securityd/SecRevocationServer.h b/trust/trustd/SecRevocationServer.h similarity index 95% rename from OSX/sec/securityd/SecRevocationServer.h rename to trust/trustd/SecRevocationServer.h index d6400167..b3f7a090 100644 --- a/OSX/sec/securityd/SecRevocationServer.h +++ b/trust/trustd/SecRevocationServer.h @@ -30,10 +30,10 @@ #ifndef _SECURITY_SECREVOCATIONSERVER_H_ #define _SECURITY_SECREVOCATIONSERVER_H_ -#include -#include -#include -#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecOCSPRequest.h" +#include "trust/trustd/SecOCSPResponse.h" typedef struct OpaqueSecORVC *SecORVCRef; diff --git a/OSX/sec/securityd/SecTrustExceptionResetCount.h b/trust/trustd/SecTrustExceptionResetCount.h similarity index 100% rename from OSX/sec/securityd/SecTrustExceptionResetCount.h rename to trust/trustd/SecTrustExceptionResetCount.h diff --git a/OSX/sec/securityd/SecTrustExceptionResetCount.m b/trust/trustd/SecTrustExceptionResetCount.m similarity index 100% rename from OSX/sec/securityd/SecTrustExceptionResetCount.m rename to trust/trustd/SecTrustExceptionResetCount.m diff --git a/OSX/sec/securityd/SecTrustLoggingServer.h b/trust/trustd/SecTrustLoggingServer.h similarity index 100% rename from OSX/sec/securityd/SecTrustLoggingServer.h rename to trust/trustd/SecTrustLoggingServer.h diff --git a/OSX/sec/securityd/SecTrustLoggingServer.m b/trust/trustd/SecTrustLoggingServer.m similarity index 100% rename from OSX/sec/securityd/SecTrustLoggingServer.m rename to trust/trustd/SecTrustLoggingServer.m diff --git a/OSX/sec/securityd/SecTrustServer.c b/trust/trustd/SecTrustServer.c similarity index 99% rename from OSX/sec/securityd/SecTrustServer.c rename to trust/trustd/SecTrustServer.c index 476fc887..1227f246 100644 --- a/OSX/sec/securityd/SecTrustServer.c +++ b/trust/trustd/SecTrustServer.c @@ -25,13 +25,13 @@ * */ -#include -#include -#include -#include -#include -#include -#include +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecCertificateSource.h" +#include "trust/trustd/SecRevocationServer.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecPinningDb.h" #include #include diff --git a/OSX/sec/securityd/SecTrustServer.h b/trust/trustd/SecTrustServer.h similarity index 98% rename from OSX/sec/securityd/SecTrustServer.h rename to trust/trustd/SecTrustServer.h index 02983bae..531ba549 100644 --- a/OSX/sec/securityd/SecTrustServer.h +++ b/trust/trustd/SecTrustServer.h @@ -32,8 +32,8 @@ #include #include /* For errSecWaitForCallback. */ -#include "securityd/SecCertificateServer.h" -#include "securityd/SecCertificateSource.h" +#include "trust/trustd/SecCertificateServer.h" +#include "trust/trustd/SecCertificateSource.h" #include __BEGIN_DECLS diff --git a/OSX/sec/securityd/SecTrustStoreServer.c b/trust/trustd/SecTrustStoreServer.c similarity index 99% rename from OSX/sec/securityd/SecTrustStoreServer.c rename to trust/trustd/SecTrustStoreServer.c index aaa6bf0b..88de9d23 100644 --- a/OSX/sec/securityd/SecTrustStoreServer.c +++ b/trust/trustd/SecTrustStoreServer.c @@ -46,13 +46,13 @@ #include #include #include -#include +#include "trust/trustd/SecTrustStoreServer.h" #include "utilities/sqlutils.h" #include "utilities/SecDb.h" #include #include "utilities/SecFileLocations.h" #include -#include +#include "trust/trustd/SecTrustLoggingServer.h" #include #include #include diff --git a/OSX/sec/securityd/SecTrustStoreServer.h b/trust/trustd/SecTrustStoreServer.h similarity index 100% rename from OSX/sec/securityd/SecTrustStoreServer.h rename to trust/trustd/SecTrustStoreServer.h diff --git a/OSX/sec/securityd/SecTrustStoreServer.m b/trust/trustd/SecTrustStoreServer.m similarity index 100% rename from OSX/sec/securityd/SecTrustStoreServer.m rename to trust/trustd/SecTrustStoreServer.m diff --git a/OSX/sec/securityd/TrustURLSessionDelegate.h b/trust/trustd/TrustURLSessionDelegate.h similarity index 100% rename from OSX/sec/securityd/TrustURLSessionDelegate.h rename to trust/trustd/TrustURLSessionDelegate.h diff --git a/OSX/sec/securityd/TrustURLSessionDelegate.m b/trust/trustd/TrustURLSessionDelegate.m similarity index 100% rename from OSX/sec/securityd/TrustURLSessionDelegate.m rename to trust/trustd/TrustURLSessionDelegate.m diff --git a/OSX/trustd/com.apple.trustd.asl b/trust/trustd/com.apple.trustd.asl similarity index 100% rename from OSX/trustd/com.apple.trustd.asl rename to trust/trustd/com.apple.trustd.asl diff --git a/OSX/trustd/iOS/AppleCorporateRootCA.cer b/trust/trustd/iOS/AppleCorporateRootCA.cer similarity index 100% rename from OSX/trustd/iOS/AppleCorporateRootCA.cer rename to trust/trustd/iOS/AppleCorporateRootCA.cer diff --git a/OSX/trustd/iOS/AppleCorporateRootCA2.cer b/trust/trustd/iOS/AppleCorporateRootCA2.cer similarity index 100% rename from OSX/trustd/iOS/AppleCorporateRootCA2.cer rename to trust/trustd/iOS/AppleCorporateRootCA2.cer diff --git a/OSX/trustd/iOS/com.apple.trustd.plist b/trust/trustd/iOS/com.apple.trustd.plist similarity index 100% rename from OSX/trustd/iOS/com.apple.trustd.plist rename to trust/trustd/iOS/com.apple.trustd.plist diff --git a/OSX/trustd/iOS/entitlements.plist b/trust/trustd/iOS/entitlements.plist similarity index 100% rename from OSX/trustd/iOS/entitlements.plist rename to trust/trustd/iOS/entitlements.plist diff --git a/OSX/trustd/macOS/SecTrustOSXEntryPoints.h b/trust/trustd/macOS/SecTrustOSXEntryPoints.h similarity index 100% rename from OSX/trustd/macOS/SecTrustOSXEntryPoints.h rename to trust/trustd/macOS/SecTrustOSXEntryPoints.h diff --git a/OSX/trustd/macOS/com.apple.trustd.agent.plist b/trust/trustd/macOS/com.apple.trustd.agent.plist similarity index 100% rename from OSX/trustd/macOS/com.apple.trustd.agent.plist rename to trust/trustd/macOS/com.apple.trustd.agent.plist diff --git a/OSX/trustd/macOS/com.apple.trustd.plist b/trust/trustd/macOS/com.apple.trustd.plist similarity index 100% rename from OSX/trustd/macOS/com.apple.trustd.plist rename to trust/trustd/macOS/com.apple.trustd.plist diff --git a/OSX/trustd/macOS/com.apple.trustd.sb b/trust/trustd/macOS/com.apple.trustd.sb similarity index 100% rename from OSX/trustd/macOS/com.apple.trustd.sb rename to trust/trustd/macOS/com.apple.trustd.sb diff --git a/OSX/trustd/macOS/entitlements.plist b/trust/trustd/macOS/entitlements.plist similarity index 100% rename from OSX/trustd/macOS/entitlements.plist rename to trust/trustd/macOS/entitlements.plist diff --git a/OSX/trustd/macOS/trustd.8 b/trust/trustd/macOS/trustd.8 similarity index 100% rename from OSX/trustd/macOS/trustd.8 rename to trust/trustd/macOS/trustd.8 diff --git a/OSX/sec/securityd/nameconstraints.c b/trust/trustd/nameconstraints.c similarity index 99% rename from OSX/sec/securityd/nameconstraints.c rename to trust/trustd/nameconstraints.c index e025fd64..fb89ff2c 100644 --- a/OSX/sec/securityd/nameconstraints.c +++ b/trust/trustd/nameconstraints.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include "trust/trustd/SecPolicyServer.h" #include #include diff --git a/OSX/sec/securityd/nameconstraints.h b/trust/trustd/nameconstraints.h similarity index 100% rename from OSX/sec/securityd/nameconstraints.h rename to trust/trustd/nameconstraints.h diff --git a/OSX/sec/securityd/personalization.c b/trust/trustd/personalization.c similarity index 100% rename from OSX/sec/securityd/personalization.c rename to trust/trustd/personalization.c diff --git a/OSX/sec/securityd/personalization.h b/trust/trustd/personalization.h similarity index 100% rename from OSX/sec/securityd/personalization.h rename to trust/trustd/personalization.h diff --git a/OSX/sec/securityd/policytree.c b/trust/trustd/policytree.c similarity index 100% rename from OSX/sec/securityd/policytree.c rename to trust/trustd/policytree.c diff --git a/OSX/sec/securityd/policytree.h b/trust/trustd/policytree.h similarity index 100% rename from OSX/sec/securityd/policytree.h rename to trust/trustd/policytree.h diff --git a/OSX/trustd/trustd-Info.plist b/trust/trustd/trustd-Info.plist similarity index 100% rename from OSX/trustd/trustd-Info.plist rename to trust/trustd/trustd-Info.plist diff --git a/OSX/trustd/trustd-Prefix.pch b/trust/trustd/trustd-Prefix.pch similarity index 100% rename from OSX/trustd/trustd-Prefix.pch rename to trust/trustd/trustd-Prefix.pch diff --git a/OSX/trustd/trustd.c b/trust/trustd/trustd.c similarity index 98% rename from OSX/trustd/trustd.c rename to trust/trustd/trustd.c index 898a2c40..02e9808a 100644 --- a/OSX/trustd/trustd.c +++ b/trust/trustd/trustd.c @@ -49,22 +49,22 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecPinningDb.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecTrustServer.h" +#include "keychain/securityd/spi.h" +#include "trust/trustd/SecTrustLoggingServer.h" #if TARGET_OS_IPHONE -#include +#include "trust/trustd/SecTrustExceptionResetCount.h" #endif #if TARGET_OS_OSX #include #include -#include +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" #endif #include "OTATrustUtilities.h" diff --git a/OSX/trustd/trustd_spi.c b/trust/trustd/trustd_spi.c similarity index 88% rename from OSX/trustd/trustd_spi.c rename to trust/trustd/trustd_spi.c index 4a9082ab..0ed05260 100644 --- a/OSX/trustd/trustd_spi.c +++ b/trust/trustd/trustd_spi.c @@ -27,22 +27,22 @@ #include "../utilities/SecFileLocations.h" #include "../sec/ipc/securityd_client.h" -#include "../sec/securityd/SecPolicyServer.h" -#include "../sec/securityd/SecTrustServer.h" -#include "../sec/securityd/SecTrustStoreServer.h" -#include "../sec/securityd/SecOCSPCache.h" -#include "../sec/securityd/OTATrustUtilities.h" -#include "../sec/securityd/SecTrustLoggingServer.h" -#include "../sec/securityd/SecRevocationDb.h" -#include "../sec/securityd/SecPinningDb.h" +#include "trust/trustd/SecPolicyServer.h" +#include "trust/trustd/SecTrustServer.h" +#include "trust/trustd/SecTrustStoreServer.h" +#include "trust/trustd/SecOCSPCache.h" +#include "trust/trustd/OTATrustUtilities.h" +#include "trust/trustd/SecTrustLoggingServer.h" +#include "trust/trustd/SecRevocationDb.h" +#include "trust/trustd/SecPinningDb.h" #include "trustd_spi.h" #if TARGET_OS_OSX -#include +#include "trust/trustd/macOS/SecTrustOSXEntryPoints.h" #endif #if TARGET_OS_IPHONE -#include +#include "trust/trustd/SecTrustExceptionResetCount.h" #endif #endif // LIBTRUSTD diff --git a/OSX/trustd/trustd_spi.h b/trust/trustd/trustd_spi.h similarity index 100% rename from OSX/trustd/trustd_spi.h rename to trust/trustd/trustd_spi.h diff --git a/xcconfig/PlatformFeatures.xcconfig b/xcconfig/PlatformFeatures.xcconfig index 6ad07118..17f372c2 100644 --- a/xcconfig/PlatformFeatures.xcconfig +++ b/xcconfig/PlatformFeatures.xcconfig @@ -1,6 +1,4 @@ -#include "xcconfig/PlatformLibraries.xcconfig" - PLATFORM_STR = "unknown" PLATFORM_STR[sdk=macosx*] = "macOS" PLATFORM_STR[sdk=iphoneos*] = "iphone" @@ -40,3 +38,14 @@ SHAREDWEBCREDENTIALS_ON[sdk=bridgeos*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=watch*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=appletv*] = 0 SHAREDWEBCREDENTIALS_ON[sdk=macos*] = 0 + +ABC_BUGCAPTURE_ON[sdk=iphoneos*] = 1 +ABC_BUGCAPTURE_ON[sdk=iphonesimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=watchos*] = 1 +ABC_BUGCAPTURE_ON[sdk=watchsimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=appletvos*] = 1 +ABC_BUGCAPTURE_ON[sdk=appletvsimulator*] = 0 +ABC_BUGCAPTURE_ON[sdk=macos*] = 1 +ABC_BUGCAPTURE_ON[sdk=bridgeos*] = 0 + +#include "xcconfig/PlatformLibraries.xcconfig" diff --git a/xcconfig/PlatformLibraries.xcconfig b/xcconfig/PlatformLibraries.xcconfig index 76271036..8c2490e6 100644 --- a/xcconfig/PlatformLibraries.xcconfig +++ b/xcconfig/PlatformLibraries.xcconfig @@ -1,6 +1,4 @@ -OTHER_LDFLAGS_AOSKIT_FRAMEWORK[sdk=macosx*] = -weak_framework AOSAccounts -weak_framework AOSAccountsLite - OTHER_LDFLAGS_MOCK_AKS_LIBRARY = -laks_mock -framework SecurityFoundation OTHER_LDFLAGS_AKS_LIBRARY[sdk=macosx*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphoneos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness @@ -110,6 +108,7 @@ OTHER_LDFLAGS_CrashReporterSupport[sdk=appletv*] = OTHER_LDFLAGS_OCMOCK = -framework OCMock OTHER_LDFLAGS_OCMOCK[sdk=bridgeos*] = -// NanoRegistry exists on other platforms, but in this case we only need it on watch -OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY[sdk=watchsimulator*] = -framework NanoRegistry -OTHER_LDFLAGS_NANOREGISTRY_WATCH_ONLY[sdk=watchos*] = -framework NanoRegistry +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_1 = -weak_framework SymptomDiagnosticReporter +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_0 = +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_ = +OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER = $(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_$(ABC_BUGCAPTURE_ON)) diff --git a/xcconfig/Security.xcconfig b/xcconfig/Security.xcconfig index bc0c2d58..c4dd5a07 100644 --- a/xcconfig/Security.xcconfig +++ b/xcconfig/Security.xcconfig @@ -17,7 +17,7 @@ LIBRARY_SEARCH_PATHS = $(inherited) $(SDKROOT)/usr/local/lib/security_libDER // Note that the 'Settings' view in Xcode will display the wrong values for platform-dependent settings // Refer to the actual build command for final computed value -GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 OCTAGON=$(OCTAGON_ON) TRUSTEDPEERS=$(TRUSTEDPEERS_ON) SECUREOBJECTSYNC=$(SECUREOBJECTSYNC_ON) SHAREDWEBCREDENTIALS=$(SHAREDWEBCREDENTIALS_ON) PLATFORM=$(PLATFORM_STR) SECURITY_BUILD_VERSION="\"$(SECURITY_BUILD_VERSION)\"" $(GCC_PREPROCESSOR_DEFINITIONS) +GCC_PREPROCESSOR_DEFINITIONS = __KEYCHAINCORE__=1 CORECRYPTO_DONOT_USE_TRANSPARENT_UNION=1 OCTAGON=$(OCTAGON_ON) TRUSTEDPEERS=$(TRUSTEDPEERS_ON) SECUREOBJECTSYNC=$(SECUREOBJECTSYNC_ON) SHAREDWEBCREDENTIALS=$(SHAREDWEBCREDENTIALS_ON) PLATFORM=$(PLATFORM_STR) SECURITY_BUILD_VERSION="\"$(SECURITY_BUILD_VERSION)\"" $(GCC_PREPROCESSOR_DEFINITIONS) ABC_BUGCAPTURE=$(ABC_BUGCAPTURE_ON) SECURITY_FUZZER_BASE_DIR = /AppleInternal/CoreOS/Fuzzers/Security @@ -42,7 +42,7 @@ OTHER_TAPI_FLAGS_SECURITY_FRAMEWORK = --verify-api-error-as-warning -D SECURITY_ SECURITY_XCTEST_DIRECTORY = /AppleInternal/XCTests/com.apple.security // If you expect to be a 'securityd', use these flags -OTHER_LDFLAGS_FOR_SECURITYD = -framework TrustedPeers $(OTHER_LDFLAGS_COREFOLLOWUP) -lnetwork +OTHER_LDFLAGS_FOR_SECURITYD = -framework TrustedPeers $(OTHER_LDFLAGS_COREFOLLOWUP) -lnetwork $(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER) // Hack for runtime path for OCMock, add to your xctest bundle and embedd OCMock.framework OCMOCK_RUNTIME_SEARCH_PATH = $(inherited) @executable_path/Frameworks @loader_path/Frameworks diff --git a/xcconfig/swift_binary.xcconfig b/xcconfig/swift_binary.xcconfig index e20a890f..a968320e 100644 --- a/xcconfig/swift_binary.xcconfig +++ b/xcconfig/swift_binary.xcconfig @@ -15,4 +15,4 @@ CLANG_ENABLE_MODULES = NO OCTAGON_FLAG_1 = -D OCTAGON OTHER_SWIFT_FLAGS = $(OCTAGON_FLAG_$(OCTAGON_ON)) -SWIFT_VERSION=4.2 +SWIFT_VERSION=5 -- 2.45.2