]> git.saurik.com Git - apple/security.git/commitdiff
Security-59754.41.1.tar.gz macos-1101 v59754.41.1
authorApple <opensource@apple.com>
Thu, 19 Nov 2020 01:06:38 +0000 (01:06 +0000)
committerApple <opensource@apple.com>
Thu, 19 Nov 2020 01:06:38 +0000 (01:06 +0000)
1428 files changed:
.swiftlint.yml
Analytics/Clients/LocalKeychainAnalytics.h
Analytics/Clients/LocalKeychainAnalytics.m
Analytics/Clients/SOSAnalytics.h
Analytics/SFAnalytics.h
Analytics/SFAnalytics.m
Analytics/SFAnalytics.plist
Analytics/SFAnalyticsDefines.h
Analytics/SFAnalyticsSQLiteStore.h
Analytics/SQLite/SFSQLite.m
CMS/CMSDecoder.h
CMS/CMSEncoder.h
CMS/CMSPrivate.h
CMS/SecCmsBase.h
CMS/SecCmsContentInfo.h
CMS/SecCmsDecoder.h
CMS/SecCmsDigestContext.h
CMS/SecCmsDigestedData.h
CMS/SecCmsEncoder.h
CMS/SecCmsMessage.h
CMS/SecCmsRecipientInfo.h
CMS/SecCmsSignedData.h
CMS/SecCmsSignerInfo.h
CircleJoinRequested/Applicant.m
CircleJoinRequested/CircleJoinRequested.m
KVSKeychainSyncingProxy/CKDAKSLockMonitor.m
KVSKeychainSyncingProxy/CKDKVSProxy.m
KVSKeychainSyncingProxy/CKDKVSStore.h
KVSKeychainSyncingProxy/CKDKVSStore.m
KVSKeychainSyncingProxy/CKDStore.h
KVSKeychainSyncingProxy/XPCNotificationDispatcher.m
KVSKeychainSyncingProxy/cloudkeychainproxy.m
KeychainCircle/KCAESGCMDuplexSession.m
KeychainCircle/KCError.h
KeychainCircle/KCJoiningAcceptSession.m
KeychainCircle/KCJoiningMessages.h
KeychainCircle/KCJoiningMessages.m
KeychainCircle/KCJoiningRequestCircleSession.m
KeychainCircle/KCJoiningRequestSecretSession.m
KeychainCircle/KCSRPContext.m
KeychainCircle/PairingChannel.m
KeychainCircle/Tests/FakeSOSControl.m
KeychainCircle/Tests/KCJoiningSessionTest.m
KeychainCircle/Tests/KCParing.plist
KeychainCircle/Tests/KCSRPTests.m
KeychainCircle/Tests/KCTLKRequestTest.m
KeychainCircle/Tests/KeychainCircle.plist
KeychainEntitledTestApp_ios/AppDelegate.h [deleted file]
KeychainEntitledTestApp_ios/AppDelegate.m [deleted file]
KeychainEntitledTestApp_ios/Assets.xcassets/AppIcon.appiconset/Contents.json [deleted file]
KeychainEntitledTestApp_ios/Info.plist [deleted file]
KeychainEntitledTestApp_ios/ViewController.h [deleted file]
KeychainEntitledTestApp_ios/ViewController.m [deleted file]
KeychainEntitledTestApp_ios/main.m [deleted file]
KeychainEntitledTestApp_mac/AppDelegate.h [deleted file]
KeychainEntitledTestApp_mac/AppDelegate.m [deleted file]
KeychainEntitledTestApp_mac/Assets.xcassets/AppIcon.appiconset/Contents.json [deleted file]
KeychainEntitledTestApp_mac/Info.plist [deleted file]
KeychainEntitledTestApp_mac/ViewController.h [deleted file]
KeychainEntitledTestApp_mac/ViewController.m [deleted file]
KeychainEntitledTestApp_mac/main.m [deleted file]
KeychainSyncAccountNotification/KeychainSyncAccountNotification.m
Modules/OctagonTrust.modulemap [new file with mode: 0644]
Modules/Security.iOS.modulemap
Modules/Security.macOS.modulemap
Modules/Security.macOS.private.modulemap
OSX/Breadcrumb/README [deleted file]
OSX/Breadcrumb/SecBreadcrumb.c [deleted file]
OSX/Breadcrumb/SecBreadcrumb.h [deleted file]
OSX/Breadcrumb/bc-10-knife-on-bread.m [deleted file]
OSX/Breadcrumb/breadcrumb_regressions.h [deleted file]
OSX/Keychain Circle Notification/Keychain Circle Notification.8
OSX/Keychain/KDCirclePeer.m
OSX/Keychain/KDSecCircle.m
OSX/Modules [deleted symlink]
OSX/SecurityTestsOSX/SecurityTests-Entitlements.plist
OSX/SecurityTestsOSX/testlist.h
OSX/authd/PreloginUserDb.h [new file with mode: 0644]
OSX/authd/PreloginUserDb.m [new file with mode: 0644]
OSX/authd/authd-Entitlements.plist
OSX/authd/authd_private.h
OSX/authd/authdb.c
OSX/authd/authitems.c
OSX/authd/authorization.plist
OSX/authd/authtoken.c
OSX/authd/authutilities.c
OSX/authd/authutilities.h
OSX/authd/com.apple.authd.sb
OSX/authd/crc.h
OSX/authd/credential.c
OSX/authd/credential.h
OSX/authd/engine.c
OSX/authd/engine.h
OSX/authd/main.c
OSX/authd/process.c
OSX/authd/rule.c
OSX/authd/rule.h
OSX/authd/server.c
OSX/authd/server.h
OSX/authd/session.c
OSX/authd/tests/authdtestlist.h
OSX/authd/tests/authdtests.m
OSX/config/lib.xcconfig
OSX/config/security_framework_macos.xcconfig
OSX/config/security_macos.xcconfig
OSX/include/security_asn1 [deleted symlink]
OSX/include/security_cdsa_client [deleted symlink]
OSX/include/security_cdsa_plugin [deleted symlink]
OSX/include/security_cdsa_utilities [deleted symlink]
OSX/include/security_cdsa_utils [deleted symlink]
OSX/include/security_codesigning [deleted symlink]
OSX/include/security_comcryption [deleted symlink]
OSX/include/security_cryptkit [deleted symlink]
OSX/include/security_filedb [deleted symlink]
OSX/include/security_keychain [deleted symlink]
OSX/include/security_ocspd [deleted symlink]
OSX/include/security_pkcs12 [deleted symlink]
OSX/include/security_smime [deleted symlink]
OSX/include/security_utilities [deleted symlink]
OSX/include/securityd_client [deleted symlink]
OSX/lib/en.lproj/InfoPlist.strings
OSX/lib/en.lproj/authorization.buttons.strings
OSX/lib/en.lproj/authorization.dfr.prompts.strings
OSX/lib/en.lproj/authorization.prompts.strings
OSX/lib/framework.sb [deleted file]
OSX/libsecurity_apple_csp/lib/DH_keys.cpp
OSX/libsecurity_apple_csp/lib/DH_utils.cpp
OSX/libsecurity_apple_csp/lib/FEEAsymmetricContext.cpp
OSX/libsecurity_apple_csp/lib/FEECSPUtils.cpp
OSX/libsecurity_apple_csp/lib/FEEKeys.cpp
OSX/libsecurity_apple_csp/lib/FEESignatureObject.cpp
OSX/libsecurity_apple_csp/lib/RSA_DSA_keys.cpp
OSX/libsecurity_apple_csp/lib/RSA_DSA_signature.cpp
OSX/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp
OSX/libsecurity_apple_csp/lib/RSA_asymmetric.cpp
OSX/libsecurity_apple_csp/lib/pkcs12Derive.cpp
OSX/libsecurity_apple_csp/lib/pkcs8.cpp
OSX/libsecurity_apple_csp/open_ssl/bn/bn_asm.c
OSX/libsecurity_apple_csp/open_ssl/bn/bn_ctx.c
OSX/libsecurity_apple_csp/open_ssl/bn/bn_exp.c
OSX/libsecurity_apple_csp/open_ssl/bn/bn_lcl.h
OSX/libsecurity_apple_csp/open_ssl/opensslUtils/opensslAsn1.cpp
OSX/libsecurity_apple_csp/open_ssl/rsa/rsa_saos.c
OSX/libsecurity_apple_csp/open_ssl/rsa/rsa_sign.c
OSX/libsecurity_apple_cspdl/lib/SSCSPSession.cpp
OSX/libsecurity_apple_cspdl/lib/SSContext.cpp
OSX/libsecurity_apple_x509_cl/lib/CLCertExtensions.cpp
OSX/libsecurity_apple_x509_cl/lib/clNssUtils.cpp
OSX/libsecurity_apple_x509_cl/lib/clNssUtils.h
OSX/libsecurity_apple_x509_tp/lib/ocspRequest.cpp
OSX/libsecurity_apple_x509_tp/lib/tpCertGroup.cpp
OSX/libsecurity_apple_x509_tp/lib/tpCredRequest.cpp
OSX/libsecurity_apple_x509_tp/lib/tpOcspCache.cpp
OSX/libsecurity_apple_x509_tp/lib/tpPolicies.cpp
OSX/libsecurity_apple_x509_tp/lib/tpTime.c
OSX/libsecurity_asn1/lib/SecNssCoder.cpp
OSX/libsecurity_asn1/lib/X509Templates.c
OSX/libsecurity_asn1/lib/nameTemplates.c
OSX/libsecurity_asn1/lib/ocspTemplates.c
OSX/libsecurity_asn1/lib/plarena.c
OSX/libsecurity_asn1/lib/prlog.h
OSX/libsecurity_asn1/lib/secasn1d.c
OSX/libsecurity_asn1/security_asn1 [deleted symlink]
OSX/libsecurity_authorization/lib/Authorization.c
OSX/libsecurity_authorization/lib/Authorization.cpp
OSX/libsecurity_authorization/lib/Authorization.h
OSX/libsecurity_authorization/lib/AuthorizationPlugin.h
OSX/libsecurity_authorization/lib/AuthorizationPriv.h
OSX/libsecurity_authorization/lib/AuthorizationTagsPriv.h
OSX/libsecurity_authorization/lib/trampolineClient.cpp
OSX/libsecurity_cdsa_client/lib/cssmclient.cpp
OSX/libsecurity_cdsa_client/lib/cssmclient.h
OSX/libsecurity_cdsa_plugin/lib/ACabstractsession.cpp
OSX/libsecurity_cdsa_plugin/lib/CLabstractsession.cpp
OSX/libsecurity_cdsa_plugin/lib/CSPabstractsession.cpp
OSX/libsecurity_cdsa_plugin/lib/DLabstractsession.cpp
OSX/libsecurity_cdsa_plugin/lib/DLsession.cpp
OSX/libsecurity_cdsa_plugin/lib/DLsession.h
OSX/libsecurity_cdsa_plugin/lib/Database.cpp
OSX/libsecurity_cdsa_plugin/lib/DatabaseSession.cpp
OSX/libsecurity_cdsa_plugin/lib/TPabstractsession.cpp
OSX/libsecurity_cdsa_plugin/lib/csputilities.cpp
OSX/libsecurity_cdsa_plugin/lib/cssmplugin.cpp
OSX/libsecurity_cdsa_plugin/lib/pluginsession.cpp
OSX/libsecurity_cdsa_plugin/lib/pluginsession.h
OSX/libsecurity_cdsa_plugin/lib/pluginspi.h
OSX/libsecurity_cdsa_utilities/lib/acl_comment.cpp
OSX/libsecurity_cdsa_utilities/lib/acl_process.cpp
OSX/libsecurity_cdsa_utilities/lib/acl_threshold.cpp
OSX/libsecurity_cdsa_utilities/lib/context.h
OSX/libsecurity_cdsa_utilities/lib/cssmalloc.cpp
OSX/libsecurity_cdsa_utilities/lib/cssmalloc.h
OSX/libsecurity_cdsa_utilities/lib/cssmbridge.h
OSX/libsecurity_cdsa_utilities/lib/cssmdata.cpp
OSX/libsecurity_cdsa_utilities/lib/cssmdata.h
OSX/libsecurity_cdsa_utilities/lib/cssmdb.h
OSX/libsecurity_cdsa_utilities/lib/cssmerrors.cpp
OSX/libsecurity_cdsa_utilities/lib/cssmerrors.h
OSX/libsecurity_cdsa_utilities/lib/cssmlist.cpp
OSX/libsecurity_cdsa_utilities/lib/cssmlist.h
OSX/libsecurity_cdsa_utilities/lib/cssmpods.cpp
OSX/libsecurity_cdsa_utilities/lib/cssmpods.h
OSX/libsecurity_cms/lib/CMSUtils.h
OSX/libsecurity_codesigning/CodeSigningHelper/main.c
OSX/libsecurity_codesigning/CodeSigningHelper/main.cpp
OSX/libsecurity_codesigning/antlr2/antlr/ANTLRException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/CharStreamException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/CharStreamIOException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/IOException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/MismatchedCharException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/MismatchedTokenException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/NoViableAltException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/NoViableAltForCharException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/RecognitionException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/SemanticException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/TokenStreamException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/TokenStreamIOException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/TokenStreamRecognitionException.hpp
OSX/libsecurity_codesigning/antlr2/antlr/TokenStreamRetryException.hpp
OSX/libsecurity_codesigning/antlr2/src/TokenStreamRewriteEngine.cpp
OSX/libsecurity_codesigning/lib/CSCommon.h
OSX/libsecurity_codesigning/lib/Code.cpp
OSX/libsecurity_codesigning/lib/Code.h
OSX/libsecurity_codesigning/lib/CodeSigner.cpp
OSX/libsecurity_codesigning/lib/CodeSigner.h
OSX/libsecurity_codesigning/lib/Requirements.cpp
OSX/libsecurity_codesigning/lib/Requirements.h
OSX/libsecurity_codesigning/lib/SecAssessment.cpp
OSX/libsecurity_codesigning/lib/SecCode.cpp
OSX/libsecurity_codesigning/lib/SecCode.h
OSX/libsecurity_codesigning/lib/SecCodePriv.h
OSX/libsecurity_codesigning/lib/SecCodeSigner.h
OSX/libsecurity_codesigning/lib/SecStaticCode.cpp
OSX/libsecurity_codesigning/lib/SecStaticCode.h
OSX/libsecurity_codesigning/lib/StaticCode.cpp
OSX/libsecurity_codesigning/lib/StaticCode.h
OSX/libsecurity_codesigning/lib/bundlediskrep.cpp
OSX/libsecurity_codesigning/lib/codedirectory.cpp
OSX/libsecurity_codesigning/lib/cserror.cpp
OSX/libsecurity_codesigning/lib/cserror.h
OSX/libsecurity_codesigning/lib/cskernel.cpp
OSX/libsecurity_codesigning/lib/csprocess.h
OSX/libsecurity_codesigning/lib/csutilities.cpp
OSX/libsecurity_codesigning/lib/csutilities.h
OSX/libsecurity_codesigning/lib/dirscanner.cpp
OSX/libsecurity_codesigning/lib/machorep.cpp
OSX/libsecurity_codesigning/lib/machorep.h
OSX/libsecurity_codesigning/lib/notarization.cpp
OSX/libsecurity_codesigning/lib/notarization.h
OSX/libsecurity_codesigning/lib/piddiskrep.cpp
OSX/libsecurity_codesigning/lib/reqinterp.cpp
OSX/libsecurity_codesigning/lib/reqinterp.h
OSX/libsecurity_codesigning/lib/signer.cpp
OSX/libsecurity_codesigning/lib/signer.h
OSX/libsecurity_codesigning/lib/signerutils.h
OSX/libsecurity_codesigning/lib/xpcengine.cpp
OSX/libsecurity_cryptkit/lib/CryptKitDER.cpp
OSX/libsecurity_cryptkit/lib/CurveParamDocs/schoof.c
OSX/libsecurity_cryptkit/lib/CurveParamDocs/schoofs.c
OSX/libsecurity_cryptkit/lib/feeFEED.c
OSX/libsecurity_cssm/lib/attachment.cpp
OSX/libsecurity_cssm/lib/cssm.cpp
OSX/libsecurity_cssm/lib/cssmcontext.h
OSX/libsecurity_cssm/lib/cssmerr.h
OSX/libsecurity_cssm/lib/module.cpp
OSX/libsecurity_cssm/lib/transition.cpp
OSX/libsecurity_filedb/lib/AppleDatabase.cpp
OSX/libsecurity_filedb/lib/AppleDatabase.h
OSX/libsecurity_filedb/lib/AtomicFile.cpp
OSX/libsecurity_filedb/lib/AtomicFile.h
OSX/libsecurity_filedb/lib/DbIndex.cpp
OSX/libsecurity_filedb/lib/ReadWriteSection.cpp
OSX/libsecurity_filedb/lib/ReadWriteSection.h
OSX/libsecurity_keychain/Security [deleted symlink]
OSX/libsecurity_keychain/lib/CertificateValues.cpp
OSX/libsecurity_keychain/lib/CertificateValues.h
OSX/libsecurity_keychain/lib/DLDBListCFPref.cpp
OSX/libsecurity_keychain/lib/ExtendedAttribute.cpp
OSX/libsecurity_keychain/lib/ExtendedAttribute.h
OSX/libsecurity_keychain/lib/Identity.cpp
OSX/libsecurity_keychain/lib/Identity.h
OSX/libsecurity_keychain/lib/IdentityCursor.cpp
OSX/libsecurity_keychain/lib/IdentityCursor.h
OSX/libsecurity_keychain/lib/Item.cpp
OSX/libsecurity_keychain/lib/Item.h
OSX/libsecurity_keychain/lib/KCCursor.cpp
OSX/libsecurity_keychain/lib/KCCursor.h
OSX/libsecurity_keychain/lib/KeyItem.cpp
OSX/libsecurity_keychain/lib/KeyItem.h
OSX/libsecurity_keychain/lib/Keychains.h
OSX/libsecurity_keychain/lib/LegacyAPICounts.h [new file with mode: 0644]
OSX/libsecurity_keychain/lib/LegacyAPICounts.m [new file with mode: 0644]
OSX/libsecurity_keychain/lib/Password.cpp
OSX/libsecurity_keychain/lib/Password.h
OSX/libsecurity_keychain/lib/Policies.cpp
OSX/libsecurity_keychain/lib/Policies.h
OSX/libsecurity_keychain/lib/PolicyCursor.cpp
OSX/libsecurity_keychain/lib/PolicyCursor.h
OSX/libsecurity_keychain/lib/SecACL.cpp
OSX/libsecurity_keychain/lib/SecAccess.cpp
OSX/libsecurity_keychain/lib/SecAccess.h
OSX/libsecurity_keychain/lib/SecAccessPriv.h
OSX/libsecurity_keychain/lib/SecBase.cpp
OSX/libsecurity_keychain/lib/SecBridge.h
OSX/libsecurity_keychain/lib/SecCertificate.cpp
OSX/libsecurity_keychain/lib/SecCertificateBundle.cpp [deleted file]
OSX/libsecurity_keychain/lib/SecCertificateBundle.h [deleted file]
OSX/libsecurity_keychain/lib/SecExport.cpp
OSX/libsecurity_keychain/lib/SecIdentity.cpp
OSX/libsecurity_keychain/lib/SecIdentitySearch.cpp
OSX/libsecurity_keychain/lib/SecImportExportPem.cpp
OSX/libsecurity_keychain/lib/SecImportExportPkcs8.cpp
OSX/libsecurity_keychain/lib/SecItem.cpp
OSX/libsecurity_keychain/lib/SecItemConstants.c
OSX/libsecurity_keychain/lib/SecKey.cpp
OSX/libsecurity_keychain/lib/SecKeychain.cpp
OSX/libsecurity_keychain/lib/SecKeychain.h
OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp [deleted file]
OSX/libsecurity_keychain/lib/SecKeychainItem.cpp
OSX/libsecurity_keychain/lib/SecKeychainItem.h
OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.cpp
OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.h
OSX/libsecurity_keychain/lib/SecKeychainItemPriv.h
OSX/libsecurity_keychain/lib/SecKeychainPriv.h
OSX/libsecurity_keychain/lib/SecKeychainSearch.cpp
OSX/libsecurity_keychain/lib/SecKeychainSearch.h
OSX/libsecurity_keychain/lib/SecPassword.cpp
OSX/libsecurity_keychain/lib/SecPassword.h
OSX/libsecurity_keychain/lib/SecPolicy.cpp
OSX/libsecurity_keychain/lib/SecPolicySearch.cpp
OSX/libsecurity_keychain/lib/SecTrustOSXEntryPoints.cpp
OSX/libsecurity_keychain/lib/SecTrustSettings.cpp
OSX/libsecurity_keychain/lib/SecTrustedApplication.cpp
OSX/libsecurity_keychain/lib/SecTrustedApplication.h
OSX/libsecurity_keychain/lib/SecTrustedApplicationPriv.h
OSX/libsecurity_keychain/lib/SecWrappedKeys.cpp
OSX/libsecurity_keychain/lib/StorageManager.cpp
OSX/libsecurity_keychain/lib/TrustAdditions.cpp
OSX/libsecurity_keychain/lib/TrustRevocation.cpp
OSX/libsecurity_keychain/lib/TrustSettings.cpp
OSX/libsecurity_keychain/lib/TrustSettings.h
OSX/libsecurity_keychain/lib/TrustSettingsUtils.cpp
OSX/libsecurity_keychain/regressions/kc-key-helpers.h
OSX/libsecurity_keychain/xpc-tsa/timestampclient.m
OSX/libsecurity_manifest/lib/AppleManifest.cpp
OSX/libsecurity_manifest/lib/Manifest.cpp
OSX/libsecurity_manifest/lib/Manifest.h
OSX/libsecurity_manifest/lib/SecureDownloadInternal.c
OSX/libsecurity_mds/lib/MDSSession.cpp
OSX/libsecurity_mds/lib/MDSSession.h
OSX/libsecurity_mds/lib/mdsapi.cpp
OSX/libsecurity_ocspd/client/ocspdClient.cpp
OSX/libsecurity_pkcs12/lib/pkcs12BagAttrs.cpp
OSX/libsecurity_pkcs12/lib/pkcs12SafeBag.cpp
OSX/libsecurity_sd_cspdl/lib/SDCSPSession.cpp
OSX/libsecurity_sd_cspdl/lib/SDContext.cpp
OSX/libsecurity_smime/lib/cert.c
OSX/libsecurity_smime/lib/cmsdigest.c
OSX/libsecurity_smime/lib/cmssiginfo.c
OSX/libsecurity_smime/lib/tsaSupport.c
OSX/libsecurity_smime/lib/tsaTemplates.c
OSX/libsecurity_smime/regressions/cms-01-basic.c
OSX/libsecurity_smime/regressions/cms-01-basic.h
OSX/libsecurity_ssl/Security [deleted symlink]
OSX/libsecurity_ssl/lib/CipherSuite.h
OSX/libsecurity_ssl/lib/SSLRecordInternal.c
OSX/libsecurity_ssl/lib/SecureTransportPriv.h
OSX/libsecurity_ssl/lib/sslCipherSpecs.c
OSX/libsecurity_ssl/lib/sslContext.c
OSX/libsecurity_ssl/lib/sslCrypto.c
OSX/libsecurity_ssl/lib/sslKeychain.c
OSX/libsecurity_ssl/lib/sslRecord.c
OSX/libsecurity_ssl/lib/sslTransport.c
OSX/libsecurity_ssl/lib/tlsCallbacks.c
OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+falsestart.m
OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+sessionstate.m
OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+tls12.m
OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_ios.xctestplan [new file with mode: 0644]
OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_macos.xctestplan [new file with mode: 0644]
OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransport_iosTests.plist
OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransport_macosTests.plist
OSX/libsecurity_ssl/regressions/ssl-50-server.c
OSX/libsecurity_ssl/regressions/ssl-51-state.c
OSX/libsecurity_ssl/security_ssl [deleted symlink]
OSX/libsecurity_transform/lib/SecDecodeTransform.h
OSX/libsecurity_transform/lib/SecDigestTransform.h
OSX/libsecurity_transform/lib/SecEncodeTransform.h
OSX/libsecurity_transform/lib/SecEncryptTransform.h
OSX/libsecurity_transform/lib/SecSignVerifyTransform.c
OSX/libsecurity_transform/lib/SecSignVerifyTransform.h
OSX/libsecurity_transform/lib/Transform.cpp
OSX/libsecurity_transform/misc/speed-test.mm
OSX/libsecurity_translocate/lib/SecTranslocate.cpp
OSX/libsecurity_translocate/lib/SecTranslocate.h
OSX/libsecurity_translocate/lib/SecTranslocateClient.cpp
OSX/libsecurity_translocate/lib/SecTranslocateClient.hpp
OSX/libsecurity_translocate/lib/SecTranslocateEnumUtils.hpp [new file with mode: 0644]
OSX/libsecurity_translocate/lib/SecTranslocateInterface.hpp
OSX/libsecurity_translocate/lib/SecTranslocateServer.cpp
OSX/libsecurity_translocate/lib/SecTranslocateServer.hpp
OSX/libsecurity_translocate/lib/SecTranslocateShared.cpp
OSX/libsecurity_translocate/lib/SecTranslocateShared.hpp
OSX/libsecurity_translocate/lib/SecTranslocateUtilities.hpp
OSX/libsecurity_translocate/lib/SecTranslocateXPCServer.cpp
OSX/libsecurity_utilities/lib/alloc.cpp
OSX/libsecurity_utilities/lib/alloc.h
OSX/libsecurity_utilities/lib/cfclass.cpp
OSX/libsecurity_utilities/lib/cfclass.h
OSX/libsecurity_utilities/lib/cfmunge.cpp
OSX/libsecurity_utilities/lib/daemon.cpp
OSX/libsecurity_utilities/lib/daemon.h
OSX/libsecurity_utilities/lib/debugging_internal.cpp
OSX/libsecurity_utilities/lib/errors.cpp
OSX/libsecurity_utilities/lib/errors.h
OSX/libsecurity_utilities/lib/globalizer.cpp
OSX/libsecurity_utilities/lib/globalizer.h
OSX/libsecurity_utilities/lib/mach++.cpp
OSX/libsecurity_utilities/lib/mach++.h
OSX/libsecurity_utilities/lib/macho++.cpp
OSX/libsecurity_utilities/lib/macho++.h
OSX/libsecurity_utilities/lib/muscle++.cpp
OSX/libsecurity_utilities/lib/muscle++.h
OSX/libsecurity_utilities/lib/pcsc++.cpp
OSX/libsecurity_utilities/lib/pcsc++.h
OSX/libsecurity_utilities/lib/refcount.h
OSX/libsecurity_utilities/lib/seccfobject.cpp
OSX/libsecurity_utilities/lib/seccfobject.h
OSX/libsecurity_utilities/lib/simpleprefs.cpp
OSX/libsecurity_utilities/lib/sqlite++.h
OSX/libsecurity_utilities/lib/superblob.h
OSX/libsecurity_utilities/lib/trackingallocator.cpp
OSX/libsecurity_utilities/lib/trackingallocator.h
OSX/libsecurity_utilities/lib/unix++.h
OSX/libsecurity_utilities/lib/unixchild.cpp
OSX/libsecurity_utilities/lib/utilities.h
OSX/libsecurity_utilities/lib/utility_config.h
OSX/libsecurityd/lib/sec_xdr.c
OSX/libsecurityd/lib/sec_xdr_array.c
OSX/libsecurityd/lib/sec_xdr_reference.c
OSX/libsecurityd/lib/xdr_auth.c
OSX/libsecurityd/lib/xdr_cssm.c
OSX/macos_tapi_hacks.h
OSX/regressions/test/testenv.h
OSX/regressions/test/testenv.m
OSX/regressions/test/testmore.h
OSX/sec/Security/AppleExternalRootCertificates.h [new file with mode: 0644]
OSX/sec/Security/Regressions/otr/otr-00-identity.c
OSX/sec/Security/Regressions/secitem/si-21-sectrust-asr.c
OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c [deleted file]
OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-24-sectrust-itms.c
OSX/sec/Security/Regressions/secitem/si-26-sectrust-copyproperties.c
OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m [deleted file]
OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.h
OSX/sec/Security/Regressions/secitem/si-32-sectrust-pinning-required.m
OSX/sec/Security/Regressions/secitem/si-34-cms-timestamp.m
OSX/sec/Security/Regressions/secitem/si-66-smime.c
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/Global Trustee.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/addons.mozilla.org.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.live.com.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.skype.com.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.1.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.2.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/mail.google.com.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/www.google.com.cer.h [deleted file]
OSX/sec/Security/Regressions/secitem/si-74-OTAPKISigner.c [deleted file]
OSX/sec/Security/Regressions/secitem/si-82-token-ag.c
OSX/sec/Security/Regressions/secitem/si-84-sectrust-allowlist.m [deleted file]
OSX/sec/Security/Regressions/secitem/si-95-cms-basic.c
OSX/sec/Security/Regressions/secitem/si-95-cms-basic.h
OSX/sec/Security/Regressions/secitem/si_77_SecAccessControl.c
OSX/sec/Security/Regressions/vmdh/vmdh-41-example.c
OSX/sec/Security/Regressions/vmdh/vmdh-42-example2.c
OSX/sec/Security/SecAccessControl.m
OSX/sec/Security/SecBase64.c
OSX/sec/Security/SecCTKKey.m
OSX/sec/Security/SecCertificate.c
OSX/sec/Security/SecCertificateInternal.h
OSX/sec/Security/SecCertificateRequest.c
OSX/sec/Security/SecDH.c
OSX/sec/Security/SecECKey.m
OSX/sec/Security/SecExports.exp-in
OSX/sec/Security/SecFramework.c
OSX/sec/Security/SecFramework.h
OSX/sec/Security/SecFrameworkStrings.h
OSX/sec/Security/SecItem.c
OSX/sec/Security/SecItem.m
OSX/sec/Security/SecItemBackup.c
OSX/sec/Security/SecItemBackup.h
OSX/sec/Security/SecItemConstants.c
OSX/sec/Security/SecItemInternal.h
OSX/sec/Security/SecItemRateLimit.h [new file with mode: 0644]
OSX/sec/Security/SecItemRateLimit.m [new file with mode: 0644]
OSX/sec/Security/SecItemRateLimit_tests.h [new file with mode: 0644]
OSX/sec/Security/SecItemShim.h
OSX/sec/Security/SecKey.m
OSX/sec/Security/SecKeyAdaptors.m
OSX/sec/Security/SecKeyProxy.m
OSX/sec/Security/SecOTR.h
OSX/sec/Security/SecOTRDHKey.c
OSX/sec/Security/SecOTRFullIdentity.c
OSX/sec/Security/SecOTRIdentityPriv.h
OSX/sec/Security/SecOTRPacketData.h
OSX/sec/Security/SecOTRPublicIdentity.c
OSX/sec/Security/SecOTRSession.c
OSX/sec/Security/SecOTRSession.h
OSX/sec/Security/SecPolicy.c
OSX/sec/Security/SecPolicy.list
OSX/sec/Security/SecPolicyChecks.list
OSX/sec/Security/SecPolicyLeafCallbacks.c
OSX/sec/Security/SecRSAKey.c
OSX/sec/Security/SecRecoveryKey.m
OSX/sec/Security/SecServerEncryptionSupport.c
OSX/sec/Security/SecSharedCredential.c
OSX/sec/Security/SecSharedCredential.m [new file with mode: 0644]
OSX/sec/Security/SecTrust.c
OSX/sec/Security/SecTrustInternal.h
OSX/sec/Security/SecTrustStore.c
OSX/sec/Security/SecuritydXPC.c
OSX/sec/Security/SecuritydXPC.h
OSX/sec/Security/ios_tapi_hacks.h
OSX/sec/Security/p12pbegen.c
OSX/sec/SharedWebCredential/swcagent.m
OSX/sec/ipc/client.c
OSX/sec/ipc/client_endpoint.m
OSX/sec/ipc/com.apple.secd.plist
OSX/sec/ipc/com.apple.securityd.plist
OSX/sec/ipc/securityd_client.h
OSX/sec/ipc/server.c
OSX/sec/ipc/server_endpoint.m
OSX/sec/ipc/server_entitlement_helpers.c
OSX/sec/ipc/server_security_helpers.h
OSX/sec/ipc/server_security_helpers.m
OSX/sec/ipc/server_xpc.m
OSX/sec/os_log/com.apple.security.ckks.plist [new file with mode: 0644]
OSX/sec/os_log/com.apple.securityd.plist
OSX/sectests/SecurityTests-Entitlements.plist
OSX/sectests/testlist.h
OSX/shared_regressions/shared_regressions.h
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_SAN_seq_length.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_general_name_type.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/san_zero_length_sequence.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_aia.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_certificate_policies.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_crldps.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_explicit_paramaters.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/rdn_short_length.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/zero_length_rdn.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_critical_policy_mappings.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_ekus.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_extensions.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_general_subtrees.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_constructed_uri_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_directory_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_dns_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_edi_party_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_ip_address.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_other_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_registered_id.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_rfc822_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_uri_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_x400_name.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/AAACertificateServices.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ApplePublicServerRSA12-G1.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomainsParsingTest.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_ca.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf_and_ca.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_empty_spki.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_invalid_spki.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_without_spki.plist [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/OCSP_TestCA.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/PinningPolicyTrustTest.plist
OSX/shared_regressions/si-20-sectrust-policies-data/TestAppleWWDR-G3.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ids_init_public.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ids_test.cer
OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_eku.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_ku.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_responder.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_subca.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/test_iPh0ne_distribution.cer [new file with mode: 0644]
OSX/shared_regressions/si-20-sectrust-policies-data/test_iphone_distribution.cer [new file with mode: 0644]
OSX/shared_regressions/si-44-seckey-aks.m
OSX/shared_regressions/si-44-seckey-proxy.m
OSX/shared_regressions/si-88-sectrust-valid.m [deleted file]
OSX/utilities/Regressions/su-10-cfstring-der.c
OSX/utilities/Regressions/su-11-cfdata-der.c
OSX/utilities/Regressions/su-12-cfboolean-der.c
OSX/utilities/Regressions/su-13-cfnumber-der.c
OSX/utilities/Regressions/su-14-cfarray-der.c
OSX/utilities/Regressions/su-15-cfdictionary-der.c
OSX/utilities/Regressions/su-16-cfdate-der.c
OSX/utilities/Regressions/su-17-cfset-der.c
OSX/utilities/Regressions/su-40-secdb.c
OSX/utilities/Regressions/su-41-secdb-stress.c
OSX/utilities/SecADWrapper.c [deleted file]
OSX/utilities/SecADWrapper.h [deleted file]
OSX/utilities/SecCFCCWrappers.c
OSX/utilities/SecCFError.c
OSX/utilities/SecCFError.h
OSX/utilities/SecCFWrappers.h
OSX/utilities/SecCoreAnalytics.h
OSX/utilities/SecCoreAnalytics.m
OSX/utilities/SecDb.c
OSX/utilities/SecDb.h
OSX/utilities/SecDbInternal.h [new file with mode: 0644]
OSX/utilities/SecFileLocations.c
OSX/utilities/SecFileLocations.h
OSX/utilities/SecXPCError.c
OSX/utilities/SecXPCHelper.h
OSX/utilities/SecXPCHelper.m
OSX/utilities/debugging.c
OSX/utilities/debugging.h
OSX/utilities/der_array.c
OSX/utilities/der_boolean.c
OSX/utilities/der_data.c
OSX/utilities/der_date.c
OSX/utilities/der_date.h
OSX/utilities/der_dictionary.c
OSX/utilities/der_null.c
OSX/utilities/der_number.c
OSX/utilities/der_plist.c
OSX/utilities/der_plist.h
OSX/utilities/der_plist_internal.c
OSX/utilities/der_plist_internal.h
OSX/utilities/der_set.c
OSX/utilities/der_set.h
OSX/utilities/der_string.c
OSX/utilities/entitlements.c [new file with mode: 0644]
OSX/utilities/entitlements.h [new file with mode: 0644]
OSX/utilities/simulate_crash.m
OSX/utilities/simulatecrash_assert.h [new file with mode: 0644]
RegressionTests/Security.plist
RegressionTests/bats_utd_plist.h
RegressionTests/secitemnotifications/secitemnotifications.m
RegressionTests/secitemstresstest/secitemstresstest.m
RegressionTests/secseccodeapitest.c [new file with mode: 0644]
Security.exp-in
Security.xcodeproj/project.pbxproj
Security.xcodeproj/xcshareddata/xcschemes/CKKSTests.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/OctagonTests.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_ios.xcscheme [new file with mode: 0644]
Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_macos.xcscheme [new file with mode: 0644]
Security.xcodeproj/xcshareddata/xcschemes/TrustTests_ios.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/TrustTests_macos.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/TrustedPeers.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/ios - Debug.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/ios - Release.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/ios - secdtests.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/osx - World.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/osx - secdtests.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/osx - sectests.xcscheme
Security.xcodeproj/xcshareddata/xcschemes/secdmockaks.xcscheme
SecurityTests/SecurityTests-Entitlements.plist
SecurityTests/ssl-policy-certs/subCA_EKU_Root.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_ca.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_leaf.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_ca.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_leaf.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_smime_ca.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_smime_leaf.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_ssl_ca.cer [new file with mode: 0644]
SecurityTests/ssl-policy-certs/subCA_EKU_ssl_leaf.cer [new file with mode: 0644]
SecurityTool/macOS/authz.c
SecurityTool/macOS/createFVMaster.c
SecurityTool/macOS/db_commands.cpp
SecurityTool/macOS/identity_find.m
SecurityTool/macOS/key_create.c
SecurityTool/macOS/keychain_add.c
SecurityTool/macOS/keychain_import.c
SecurityTool/macOS/keychain_lock.c
SecurityTool/macOS/keychain_utilities.c
SecurityTool/macOS/readline.c
SecurityTool/macOS/requirement.c
SecurityTool/macOS/trusted_cert_ssl.m
SecurityTool/sharedTool/KeychainCheck.m
SecurityTool/sharedTool/SecurityCommands.h
SecurityTool/sharedTool/add_internet_password.c
SecurityTool/sharedTool/builtin_commands.h
SecurityTool/sharedTool/ca_revocation_additions.m [new file with mode: 0644]
SecurityTool/sharedTool/iOS/entitlements.plist
SecurityTool/sharedTool/macOS/entitlements.plist
SecurityTool/sharedTool/policy_dryrun.m
SecurityTool/sharedTool/scep.c
SecurityTool/sharedTool/sos.m
SecurityTool/sharedTool/sub_commands.h
SecurityTool/sharedTool/trust_update.m
SharedMocks/NSXPCConnectionMock.m
SharedWebCredentialViewService/SWCViewController.h
SharedWebCredentialViewService/SWCViewController.m
SharedWebCredentialViewService/entitlements.plist
TestPlan.xctestplan [deleted file]
base/SecBase.h
base/SecBasePriv.h
base/SecInternal.h
codesign_wrapper/check_entitlements.c
cssm/cssmapple.h
experiment/SecExperiment.m
experiment/SecExperimentInternal.h
experiment/tool/experimentTool.m
featureflags/Security.plist
header_symlinks/OctagonTrust/OTCDPRecoveryInformation.h [new symlink]
header_symlinks/OctagonTrust/OTEscrowAuthenticationInformation.h [new symlink]
header_symlinks/OctagonTrust/OTEscrowRecord.h [new symlink]
header_symlinks/OctagonTrust/OTEscrowRecordMetadata.h [new symlink]
header_symlinks/OctagonTrust/OTEscrowRecordMetadataClientMetadata.h [new symlink]
header_symlinks/OctagonTrust/OTEscrowTranslation.h [new symlink]
header_symlinks/OctagonTrust/OTICDPRecordContext.h [new symlink]
header_symlinks/OctagonTrust/OTICDPRecordSilentContext.h [new symlink]
header_symlinks/OctagonTrust/OctagonTrust.h [new symlink]
header_symlinks/Security/SFSignInAnalytics.h [deleted symlink]
header_symlinks/Security/SecExperimentPriv.h
header_symlinks/Security/certExtensionTemplates.h
header_symlinks/macOS/Security/SecBreadcrumb.h [deleted symlink]
header_symlinks/macOS/Security/SecCertificateBundle.h [deleted symlink]
keychain/CoreDataKeychain/SecCDKeychain.m
keychain/KeychainDataclassOwner/KeychainDataclassOwner.m
keychain/KeychainStasher/KeychainStasher-Info.plist [new file with mode: 0644]
keychain/KeychainStasher/KeychainStasher.entitlements [new file with mode: 0644]
keychain/KeychainStasher/KeychainStasher.h [new file with mode: 0644]
keychain/KeychainStasher/KeychainStasher.m [new file with mode: 0644]
keychain/KeychainStasher/KeychainStasherProtocol.h [new file with mode: 0644]
keychain/KeychainStasher/com.apple.security.KeychainStasher.plist [new file with mode: 0644]
keychain/KeychainStasher/com.apple.security.KeychainStasher.sb [new file with mode: 0644]
keychain/KeychainStasher/main.m [new file with mode: 0644]
keychain/OctagonTrust/Info.plist [new file with mode: 0644]
keychain/OctagonTrust/OTEscrowTranslation.h [new file with mode: 0644]
keychain/OctagonTrust/OTEscrowTranslation.m [new file with mode: 0644]
keychain/OctagonTrust/OctagonTrust.h [new file with mode: 0644]
keychain/OctagonTrust/OctagonTrust.m [new file with mode: 0644]
keychain/OctagonTrust/categories/OctagonTrustEscrowRecoverer.h [new file with mode: 0644]
keychain/OctagonTrust/ot-tests/OctagonTrustTests+Errors.m [new file with mode: 0644]
keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowRecords.m [new file with mode: 0644]
keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowTestVectors.h [new file with mode: 0644]
keychain/OctagonTrust/ot-tests/OctagonTrustTests-Info.plist [new file with mode: 0644]
keychain/OctagonTrust/ot-tests/OctagonTrustTests.h [new file with mode: 0644]
keychain/ResetCloudKeychainAccount/reset_ick_account [changed mode: 0644->0755]
keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.c
keychain/SecureObjectSync/CKDSimulatedStore.h
keychain/SecureObjectSync/CKDSimulatedStore.m
keychain/SecureObjectSync/Regressions/CKDSimulatedAccount.m
keychain/SecureObjectSync/Regressions/SOSRegressionUtilities.h
keychain/SecureObjectSync/Regressions/SOSRegressionUtilities.m
keychain/SecureObjectSync/Regressions/SOSTestDataSource.c
keychain/SecureObjectSync/Regressions/sc-130-resignationticket.c
keychain/SecureObjectSync/Regressions/sc-150-backupkeyderivation.c
keychain/SecureObjectSync/Regressions/sc-153-backupslicekeybag.c
keychain/SecureObjectSync/Regressions/sc-20-keynames.m
keychain/SecureObjectSync/Regressions/sc-25-soskeygen.c
keychain/SecureObjectSync/Regressions/sc-30-peerinfo.c
keychain/SecureObjectSync/Regressions/sc-31-peerinfo-simplefuzz.c
keychain/SecureObjectSync/Regressions/sc-40-circle.c
keychain/SecureObjectSync/Regressions/sc-42-circlegencount.c
keychain/SecureObjectSync/Regressions/sc-45-digestvector.c
keychain/SecureObjectSync/SOSAccount.h
keychain/SecureObjectSync/SOSAccount.m
keychain/SecureObjectSync/SOSAccountBackup.m
keychain/SecureObjectSync/SOSAccountCloudParameters.m
keychain/SecureObjectSync/SOSAccountConfiguration.proto
keychain/SecureObjectSync/SOSAccountCredentials.m
keychain/SecureObjectSync/SOSAccountFullPeerInfo.m
keychain/SecureObjectSync/SOSAccountGhost.m
keychain/SecureObjectSync/SOSAccountLog.m
keychain/SecureObjectSync/SOSAccountPersistence.m
keychain/SecureObjectSync/SOSAccountPriv.h
keychain/SecureObjectSync/SOSAccountRecovery.m
keychain/SecureObjectSync/SOSAccountRings.m
keychain/SecureObjectSync/SOSAccountTransaction.m
keychain/SecureObjectSync/SOSAccountTrust.m
keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h
keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.m
keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h
keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.m
keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h
keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.m
keychain/SecureObjectSync/SOSAccountTrustClassic.h
keychain/SecureObjectSync/SOSAccountTrustClassic.m
keychain/SecureObjectSync/SOSAccountUpdate.m
keychain/SecureObjectSync/SOSAccountViewSync.m
keychain/SecureObjectSync/SOSAuthKitHelpers.m
keychain/SecureObjectSync/SOSBackupSliceKeyBag.m
keychain/SecureObjectSync/SOSChangeTracker.h
keychain/SecureObjectSync/SOSCircle.c
keychain/SecureObjectSync/SOSCircleDer.c
keychain/SecureObjectSync/SOSCirclePriv.h
keychain/SecureObjectSync/SOSCloudCircle.h
keychain/SecureObjectSync/SOSCloudCircle.m
keychain/SecureObjectSync/SOSCloudCircleInternal.h
keychain/SecureObjectSync/SOSCoder.c
keychain/SecureObjectSync/SOSControlHelper.m
keychain/SecureObjectSync/SOSControlServer.m
keychain/SecureObjectSync/SOSECWrapUnwrap.c
keychain/SecureObjectSync/SOSEngine.c
keychain/SecureObjectSync/SOSEngine.h
keychain/SecureObjectSync/SOSExports.exp-in
keychain/SecureObjectSync/SOSFullPeerInfo.h
keychain/SecureObjectSync/SOSFullPeerInfo.m
keychain/SecureObjectSync/SOSGenCount.c
keychain/SecureObjectSync/SOSInternal.h
keychain/SecureObjectSync/SOSInternal.m
keychain/SecureObjectSync/SOSIntervalEvent.m
keychain/SecureObjectSync/SOSKVSKeys.h
keychain/SecureObjectSync/SOSMessage.c
keychain/SecureObjectSync/SOSPeerInfo.h
keychain/SecureObjectSync/SOSPeerInfo.m
keychain/SecureObjectSync/SOSPeerInfoDER.m
keychain/SecureObjectSync/SOSPeerInfoPriv.h
keychain/SecureObjectSync/SOSPeerInfoV2.h
keychain/SecureObjectSync/SOSPeerInfoV2.m
keychain/SecureObjectSync/SOSPeerOTRTimer.m
keychain/SecureObjectSync/SOSPeerRateLimiter.m
keychain/SecureObjectSync/SOSPiggyback.m
keychain/SecureObjectSync/SOSRecoveryKeyBag.m
keychain/SecureObjectSync/SOSRingBackup.m
keychain/SecureObjectSync/SOSRingBasic.m
keychain/SecureObjectSync/SOSRingConcordanceTrust.c
keychain/SecureObjectSync/SOSRingDER.c
keychain/SecureObjectSync/SOSRingPeerInfoUtils.c
keychain/SecureObjectSync/SOSRingRecovery.m
keychain/SecureObjectSync/SOSRingUtils.c
keychain/SecureObjectSync/SOSRingV0.m
keychain/SecureObjectSync/SOSTransport.m
keychain/SecureObjectSync/SOSTransportCircle.m
keychain/SecureObjectSync/SOSTransportCircleCK.m
keychain/SecureObjectSync/SOSTransportCircleKVS.m
keychain/SecureObjectSync/SOSTransportKeyParameter.m
keychain/SecureObjectSync/SOSTransportMessage.m
keychain/SecureObjectSync/SOSTransportMessageKVS.m
keychain/SecureObjectSync/SOSTypes.h
keychain/SecureObjectSync/SOSUserKeygen.m
keychain/SecureObjectSync/SOSViews.m
keychain/SecureObjectSync/Tool/accountCirclesViewsPrint.m
keychain/SecureObjectSync/Tool/keychain_sync.m
keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.h
keychain/SecureObjectSync/generated_source/SOSAccountConfiguration.m
keychain/SecurityUnitTests/SecItemTests.m
keychain/SecurityUnitTests/SecKeyTests.m
keychain/SigninMetrics/OctagonSignPosts.h
keychain/SigninMetrics/SFSignInAnalytics+Internal.h [deleted file]
keychain/SigninMetrics/SFSignInAnalytics.h [deleted file]
keychain/SigninMetrics/SFSignInAnalytics.m [deleted file]
keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m [deleted file]
keychain/Trieste/OctagonTestHarnessXPCService/SecRemoteDevice.m
keychain/Trieste/OctagonTriesteTests/Tests/OctagonTriesteTests/OctagonTests.swift
keychain/TrustedPeersHelper/BottledPeer/BottledPeer.swift
keychain/TrustedPeersHelper/BottledPeer/EscrowKeys.swift
keychain/TrustedPeersHelper/Client.swift
keychain/TrustedPeersHelper/Container.swift
keychain/TrustedPeersHelper/ContainerMap.swift
keychain/TrustedPeersHelper/Container_BottledPeers.swift
keychain/TrustedPeersHelper/Container_EscrowRecords.swift [new file with mode: 0644]
keychain/TrustedPeersHelper/Container_MachineIDs.swift
keychain/TrustedPeersHelper/Container_Peers.swift [new file with mode: 0644]
keychain/TrustedPeersHelper/Container_RecoveryKey.swift
keychain/TrustedPeersHelper/Container_UserSync.swift [new file with mode: 0644]
keychain/TrustedPeersHelper/OctagonPeerKeys.swift
keychain/TrustedPeersHelper/Policy.swift
keychain/TrustedPeersHelper/RecoveryKey/RecoverKeySet.swift
keychain/TrustedPeersHelper/RecoveryKey/RecoveryKey.swift
keychain/TrustedPeersHelper/TPHObjcTranslation.m
keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h
keychain/TrustedPeersHelper/TrustedPeersHelper-entitlements.plist
keychain/TrustedPeersHelper/TrustedPeersHelper.xcdatamodeld/TrustedPeersHelper_2.xcdatamodel/contents
keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h
keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.m
keychain/TrustedPeersHelper/com.apple.TrustedPeersHelper.sb [new file with mode: 0644]
keychain/TrustedPeersHelper/main.swift
keychain/TrustedPeersHelper/proto/generated_source/OTBottleContents.h
keychain/TrustedPeersHelperUnitTests/.swiftlint.yml
keychain/TrustedPeersHelperUnitTests/ContainerSync.swift
keychain/TrustedPeersHelperUnitTests/FakeCuttlefish.swift
keychain/TrustedPeersHelperUnitTests/MockCuttlefish.swift
keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests-BridgingHeader.h
keychain/TrustedPeersHelperUnitTests/TrustedPeersHelperUnitTests.swift
keychain/analytics/SecEventMetric.m
keychain/analytics/SecMetrics.m
keychain/behavior/SFBehavior.h [deleted file]
keychain/behavior/SFBehavior.m [deleted file]
keychain/ckks/CKKS.h
keychain/ckks/CKKS.m
keychain/ckks/CKKSAccountStateTracker.h
keychain/ckks/CKKSAccountStateTracker.m
keychain/ckks/CKKSAnalytics.h
keychain/ckks/CKKSAnalytics.m
keychain/ckks/CKKSCheckKeyHierarchyOperation.h [new file with mode: 0644]
keychain/ckks/CKKSCheckKeyHierarchyOperation.m [new file with mode: 0644]
keychain/ckks/CKKSConstants.m
keychain/ckks/CKKSControl.h
keychain/ckks/CKKSControl.m
keychain/ckks/CKKSControlProtocol.h
keychain/ckks/CKKSControlProtocol.m
keychain/ckks/CKKSControlServer.m
keychain/ckks/CKKSCreateCKZoneOperation.h [new file with mode: 0644]
keychain/ckks/CKKSCreateCKZoneOperation.m [new file with mode: 0644]
keychain/ckks/CKKSCurrentKeyPointer.m
keychain/ckks/CKKSDeleteCKZoneOperation.h [new file with mode: 0644]
keychain/ckks/CKKSDeleteCKZoneOperation.m [new file with mode: 0644]
keychain/ckks/CKKSDeviceStateEntry.m
keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.m
keychain/ckks/CKKSFixups.h
keychain/ckks/CKKSFixups.m
keychain/ckks/CKKSGroupOperation.m
keychain/ckks/CKKSHealKeyHierarchyOperation.h
keychain/ckks/CKKSHealKeyHierarchyOperation.m
keychain/ckks/CKKSHealTLKSharesOperation.h
keychain/ckks/CKKSHealTLKSharesOperation.m
keychain/ckks/CKKSIncomingQueueEntry.h
keychain/ckks/CKKSIncomingQueueEntry.m
keychain/ckks/CKKSIncomingQueueOperation.h
keychain/ckks/CKKSIncomingQueueOperation.m
keychain/ckks/CKKSItem.m
keychain/ckks/CKKSItemEncrypter.m
keychain/ckks/CKKSKey.h
keychain/ckks/CKKSKey.m
keychain/ckks/CKKSKeychainBackedKey.m
keychain/ckks/CKKSKeychainView.h
keychain/ckks/CKKSKeychainView.m
keychain/ckks/CKKSLocalResetOperation.h [new file with mode: 0644]
keychain/ckks/CKKSLocalResetOperation.m [new file with mode: 0644]
keychain/ckks/CKKSLocalSynchronizeOperation.m
keychain/ckks/CKKSLockStateTracker.m
keychain/ckks/CKKSLogging.m [new file with mode: 0644]
keychain/ckks/CKKSManifest.m
keychain/ckks/CKKSManifestLeafRecord.m
keychain/ckks/CKKSMirrorEntry.m
keychain/ckks/CKKSNewTLKOperation.h
keychain/ckks/CKKSNewTLKOperation.m
keychain/ckks/CKKSNotifier.m
keychain/ckks/CKKSOperationDependencies.h [new file with mode: 0644]
keychain/ckks/CKKSOperationDependencies.m [new file with mode: 0644]
keychain/ckks/CKKSOutgoingQueueEntry.h
keychain/ckks/CKKSOutgoingQueueEntry.m
keychain/ckks/CKKSOutgoingQueueOperation.h
keychain/ckks/CKKSOutgoingQueueOperation.m
keychain/ckks/CKKSPeer.m
keychain/ckks/CKKSPeerProvider.h
keychain/ckks/CKKSPeerProvider.m
keychain/ckks/CKKSProcessReceivedKeysOperation.h
keychain/ckks/CKKSProcessReceivedKeysOperation.m
keychain/ckks/CKKSProvideKeySetOperation.h
keychain/ckks/CKKSProvideKeySetOperation.m
keychain/ckks/CKKSRateLimiter.m
keychain/ckks/CKKSReachabilityTracker.m
keychain/ckks/CKKSRecordHolder.m
keychain/ckks/CKKSReencryptOutgoingItemsOperation.h
keychain/ckks/CKKSReencryptOutgoingItemsOperation.m
keychain/ckks/CKKSResultOperation.h
keychain/ckks/CKKSResultOperation.m
keychain/ckks/CKKSSIV.h
keychain/ckks/CKKSSIV.m
keychain/ckks/CKKSSQLDatabaseObject.h
keychain/ckks/CKKSSQLDatabaseObject.m
keychain/ckks/CKKSScanLocalItemsOperation.h
keychain/ckks/CKKSScanLocalItemsOperation.m
keychain/ckks/CKKSStates.h [new file with mode: 0644]
keychain/ckks/CKKSStates.m [new file with mode: 0644]
keychain/ckks/CKKSSynchronizeOperation.m
keychain/ckks/CKKSTLKShare.h
keychain/ckks/CKKSTLKShare.m
keychain/ckks/CKKSTLKShareRecord.m
keychain/ckks/CKKSUpdateCurrentItemPointerOperation.m
keychain/ckks/CKKSUpdateDeviceStateOperation.m
keychain/ckks/CKKSViewManager.h
keychain/ckks/CKKSViewManager.m
keychain/ckks/CKKSZone.h [deleted file]
keychain/ckks/CKKSZone.m [deleted file]
keychain/ckks/CKKSZoneChangeFetcher.h
keychain/ckks/CKKSZoneChangeFetcher.m
keychain/ckks/CKKSZoneModifier.m
keychain/ckks/CKKSZoneStateEntry.h
keychain/ckks/CKKSZoneStateEntry.m
keychain/ckks/CloudKitCategories.m
keychain/ckks/CloudKitDependencies.h
keychain/ckks/NSOperationCategories.m
keychain/ckks/OctagonAPSReceiver.h
keychain/ckks/OctagonAPSReceiver.m
keychain/ckks/RateLimiter.m
keychain/ckks/tests/AutoreleaseTest.c
keychain/ckks/tests/CKKSAESSIVEncryptionTests.m
keychain/ckks/tests/CKKSAPSHandlingTests.m
keychain/ckks/tests/CKKSCloudKitTests.m [deleted file]
keychain/ckks/tests/CKKSCloudKitTestsInfo.plist [deleted file]
keychain/ckks/tests/CKKSConditionTests.m
keychain/ckks/tests/CKKSDeviceStateUploadTests.m
keychain/ckks/tests/CKKSFetchTests.m
keychain/ckks/tests/CKKSLoggerTests.m
keychain/ckks/tests/CKKSManifestTests.m
keychain/ckks/tests/CKKSMockSOSPresentAdapter.h
keychain/ckks/tests/CKKSMockSOSPresentAdapter.m
keychain/ckks/tests/CKKSOperationTests.m
keychain/ckks/tests/CKKSSOSTests.m
keychain/ckks/tests/CKKSSQLTests.m
keychain/ckks/tests/CKKSServerValidationRecoveryTests.m
keychain/ckks/tests/CKKSTLKSharingEncryptionTests.m
keychain/ckks/tests/CKKSTLKSharingTests.m
keychain/ckks/tests/CKKSTests+API.m
keychain/ckks/tests/CKKSTests+Coalesce.m
keychain/ckks/tests/CKKSTests+CurrentPointerAPI.m
keychain/ckks/tests/CKKSTests+ForwardCompatibility.m [new file with mode: 0644]
keychain/ckks/tests/CKKSTests+ItemSyncChoice.m [new file with mode: 0644]
keychain/ckks/tests/CKKSTests+MultiZone.m
keychain/ckks/tests/CKKSTests.m
keychain/ckks/tests/CloudKitKeychainSyncingFixupTests.m
keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h
keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.m
keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h
keychain/ckks/tests/CloudKitMockXCTest.h
keychain/ckks/tests/CloudKitMockXCTest.m
keychain/ckks/tests/MockCloudKit.h
keychain/ckks/tests/MockCloudKit.m
keychain/ckks/tests/OctagonAPSReceiverTests.m
keychain/ckks/tests/RateLimiterTests.m
keychain/ckks/tests/gen_test_plist.py
keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist [deleted file]
keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m [deleted file]
keychain/ckksctl/ckksctl.m
keychain/escrowrequest/EscrowRequestController.m
keychain/escrowrequest/EscrowRequestXPCProtocol.m
keychain/headers/SecAccessControl.h
keychain/headers/SecIdentityPriv.h
keychain/headers/SecImportExport.h
keychain/headers/SecImportExportPriv.h
keychain/headers/SecItem.h
keychain/headers/SecItemPriv.h
keychain/headers/SecKey.h
keychain/headers/SecKeyPriv.h
keychain/headers/SecSharedCredential.h
keychain/ot/CuttlefishXPCWrapper.m
keychain/ot/OTClientStateMachine.m
keychain/ot/OTClientVoucherOperation.m
keychain/ot/OTClique+Private.h [new file with mode: 0644]
keychain/ot/OTClique.h
keychain/ot/OTClique.m
keychain/ot/OTConstants.h
keychain/ot/OTConstants.m
keychain/ot/OTControl.h
keychain/ot/OTControl.m
keychain/ot/OTControlProtocol.h
keychain/ot/OTControlProtocol.m
keychain/ot/OTCuttlefishAccountStateHolder.h
keychain/ot/OTCuttlefishAccountStateHolder.m
keychain/ot/OTCuttlefishContext.h
keychain/ot/OTCuttlefishContext.m
keychain/ot/OTDefines.h
keychain/ot/OTDefines.m
keychain/ot/OTDetermineCDPBitStatusOperation.m
keychain/ot/OTDeviceInformationAdapter.h
keychain/ot/OTDeviceInformationAdapter.m
keychain/ot/OTEnsureOctagonKeyConsistency.m
keychain/ot/OTEstablishOperation.m
keychain/ot/OTFetchCKKSKeysOperation.h
keychain/ot/OTFetchCKKSKeysOperation.m
keychain/ot/OTFetchViewsOperation.m
keychain/ot/OTFollowup.h
keychain/ot/OTFollowup.m
keychain/ot/OTJoinWithVoucherOperation.h
keychain/ot/OTJoinWithVoucherOperation.m
keychain/ot/OTJoiningConfiguration.m
keychain/ot/OTLocalCuttlefishReset.h
keychain/ot/OTLocalCuttlefishReset.m
keychain/ot/OTManager.h
keychain/ot/OTManager.m
keychain/ot/OTModifyUserControllableViewStatusOperation.h [new file with mode: 0644]
keychain/ot/OTModifyUserControllableViewStatusOperation.m [new file with mode: 0644]
keychain/ot/OTPreloadOctagonKeysOperation.h [new file with mode: 0644]
keychain/ot/OTPreloadOctagonKeysOperation.m [new file with mode: 0644]
keychain/ot/OTPrepareOperation.m
keychain/ot/OTRamping.m
keychain/ot/OTResetCKKSZonesLackingTLKsOperation.m
keychain/ot/OTSOSAdapter.h
keychain/ot/OTSOSAdapter.m
keychain/ot/OTSOSUpgradeOperation.m
keychain/ot/OTSetRecoveryKeyOperation.m
keychain/ot/OTStates.h
keychain/ot/OTStates.m
keychain/ot/OTUpdateTPHOperation.m
keychain/ot/OTUpdateTrustedDeviceListOperation.m
keychain/ot/OTUploadNewCKKSTLKsOperation.h
keychain/ot/OTUploadNewCKKSTLKsOperation.m
keychain/ot/OTVouchWithBottleOperation.h
keychain/ot/OTVouchWithBottleOperation.m
keychain/ot/OTVouchWithRecoveryKeyOperation.h
keychain/ot/OTVouchWithRecoveryKeyOperation.m
keychain/ot/OctagonCKKSPeerAdapter.h
keychain/ot/OctagonCKKSPeerAdapter.m
keychain/ot/OctagonCheckTrustStateOperation.m
keychain/ot/OctagonControlServer.m
keychain/ot/OctagonFlags.m
keychain/ot/OctagonPendingFlag.h
keychain/ot/OctagonPendingFlag.m
keychain/ot/OctagonStateMachine.h
keychain/ot/OctagonStateMachine.m
keychain/ot/OctagonStateMachineHelpers.h
keychain/ot/OctagonStateMachineHelpers.m
keychain/ot/OctagonStateMachineObservers.h
keychain/ot/OctagonStateMachineObservers.m
keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h
keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.m
keychain/ot/categories/OctagonEscrowRecoverer.h
keychain/ot/proto/OTAccountMetadataClassC.proto
keychain/ot/proto/OTCDPRecoveryInformation.proto [new file with mode: 0644]
keychain/ot/proto/OTEscrowRecord.proto [new file with mode: 0644]
keychain/ot/proto/OTPairingMessage.proto
keychain/ot/proto/generated_source/OTAccountMetadataClassC.h
keychain/ot/proto/generated_source/OTAccountMetadataClassC.m
keychain/ot/proto/generated_source/OTCDPRecoveryInformation.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTCDPRecoveryInformation.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecord.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecord.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecordMetadata.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTGlobalEnums.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTICDPRecordContext.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTICDPRecordContext.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTICDPRecordSilentContext.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTICDPRecordSilentContext.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTPairingMessage.h
keychain/ot/proto/generated_source/OTPairingMessage.m
keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.m
keychain/ot/proto/generated_source/OTSupportOctagonMessage.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTSupportOctagonMessage.m [new file with mode: 0644]
keychain/ot/proto/generated_source/OTSupportSOSMessage.h [new file with mode: 0644]
keychain/ot/proto/generated_source/OTSupportSOSMessage.m [new file with mode: 0644]
keychain/ot/proto/source/OTSOSMessage.h [deleted file]
keychain/ot/tests/gen_test_plist.py
keychain/ot/tests/octagon/.swiftlint.yml
keychain/ot/tests/octagon/OctagonDataPersistenceTests.swift
keychain/ot/tests/octagon/OctagonPolicyTests.swift [new file with mode: 0644]
keychain/ot/tests/octagon/OctagonTestMocks.swift
keychain/ot/tests/octagon/OctagonTests+Account.swift
keychain/ot/tests/octagon/OctagonTests+CKKS.swift
keychain/ot/tests/octagon/OctagonTests+CKKSConfiguration.swift
keychain/ot/tests/octagon/OctagonTests+CloudKitAccount.swift
keychain/ot/tests/octagon/OctagonTests+CoreFollowUp.swift
keychain/ot/tests/octagon/OctagonTests+DeviceList.swift
keychain/ot/tests/octagon/OctagonTests+ErrorHandling.swift
keychain/ot/tests/octagon/OctagonTests+EscrowRecords.swift [new file with mode: 0644]
keychain/ot/tests/octagon/OctagonTests+EscrowRecovery.swift
keychain/ot/tests/octagon/OctagonTests+EscrowTestVectors.swift [new file with mode: 0644]
keychain/ot/tests/octagon/OctagonTests+ForwardCompatibility.swift
keychain/ot/tests/octagon/OctagonTests+HealthCheck.swift
keychain/ot/tests/octagon/OctagonTests+Helpers.swift
keychain/ot/tests/octagon/OctagonTests+RecoveryKey.swift
keychain/ot/tests/octagon/OctagonTests+Reset.swift
keychain/ot/tests/octagon/OctagonTests+SOS.swift
keychain/ot/tests/octagon/OctagonTests+SOSUpgrade.swift
keychain/ot/tests/octagon/OctagonTests-BridgingHeader.h
keychain/ot/tests/octagon/OctagonTests.swift
keychain/ot/tests/octagon/OctagonTestsXPCConnections.swift
keychain/ot/tests/octagon/Pairing/OctagonPairingTests+Piggybacking.swift
keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProxMultiClients.swift
keychain/ot/tests/octagon/Pairing/OctagonPairingTests+ProximitySetup.swift
keychain/ot/tests/octagon/Pairing/OctagonPairingTests.swift
keychain/ot/tests/octagon/TestsObjcTranslation.h
keychain/ot/tests/octagon/TestsObjcTranslation.m
keychain/otctl/OTControlCLI.h
keychain/otctl/OTControlCLI.m
keychain/otctl/otctl.m
keychain/otpaird/OTPairingConstants.h
keychain/otpaird/OTPairingPacketContext.m
keychain/otpaird/OTPairingService.m
keychain/otpaird/OTPairingSession.m
keychain/otpaird/otpaird.iphoneos.entitlements
keychain/otpaird/otpaird.watchos.entitlements
keychain/securityd/PolicyReporter.m
keychain/securityd/Regressions/SOSAccountTesting.h
keychain/securityd/Regressions/SOSTransportTestTransports.m
keychain/securityd/Regressions/SecdTestKeychainUtilities.c
keychain/securityd/Regressions/secd-100-initialsync.m
keychain/securityd/Regressions/secd-130-other-peer-views.m
keychain/securityd/Regressions/secd-154-engine-backoff.m
keychain/securityd/Regressions/secd-155-otr-negotiation-monitor.m
keychain/securityd/Regressions/secd-200-logstate.m
keychain/securityd/Regressions/secd-201-coders.m
keychain/securityd/Regressions/secd-202-recoverykey.m
keychain/securityd/Regressions/secd-210-keyinterest.m
keychain/securityd/Regressions/secd-33-keychain-ctk.m
keychain/securityd/Regressions/secd-36-ks-encrypt.m
keychain/securityd/Regressions/secd-50-account.m
keychain/securityd/Regressions/secd-50-message.m
keychain/securityd/Regressions/secd-51-account-inflate.m
keychain/securityd/Regressions/secd-52-account-changed.m
keychain/securityd/Regressions/secd-52-offering-gencount-reset.m
keychain/securityd/Regressions/secd-55-account-circle.m
keychain/securityd/Regressions/secd-55-account-incompatibility.m
keychain/securityd/Regressions/secd-56-account-apply.m
keychain/securityd/Regressions/secd-57-1-account-last-standing.m
keychain/securityd/Regressions/secd-57-account-leave.m
keychain/securityd/Regressions/secd-58-password-change.m
keychain/securityd/Regressions/secd-59-account-cleanup.m
keychain/securityd/Regressions/secd-60-account-cloud-identity.m
keychain/securityd/Regressions/secd-61-account-leave-not-in-kansas-anymore.m
keychain/securityd/Regressions/secd-62-account-backup.m
keychain/securityd/Regressions/secd-63-account-resurrection.m
keychain/securityd/Regressions/secd-64-circlereset.m
keychain/securityd/Regressions/secd-65-account-retirement-reset.m
keychain/securityd/Regressions/secd-66-account-recovery.m
keychain/securityd/Regressions/secd-668-ghosts.m [deleted file]
keychain/securityd/Regressions/secd-67-prefixedKeyIDs.m
keychain/securityd/Regressions/secd-68-fullPeerInfoIntegrity.m [new file with mode: 0644]
keychain/securityd/Regressions/secd-70-engine-corrupt.m
keychain/securityd/Regressions/secd-70-engine-smash.m
keychain/securityd/Regressions/secd-70-engine.m
keychain/securityd/Regressions/secd-70-otr-remote.m
keychain/securityd/Regressions/secd-71-engine-save.m
keychain/securityd/Regressions/secd-74-engine-beer-servers.m
keychain/securityd/Regressions/secd-75-engine-views.m
keychain/securityd/Regressions/secd-80-views-alwayson.m
keychain/securityd/Regressions/secd-80-views-basic.m
keychain/securityd/Regressions/secd-81-item-acl.m
keychain/securityd/Regressions/secd60-account-cloud-exposure.m
keychain/securityd/Regressions/secd_regressions.h
keychain/securityd/SFKeychainControlManager.m
keychain/securityd/SFKeychainServer.m
keychain/securityd/SOSCloudCircleServer.h
keychain/securityd/SOSCloudCircleServer.m
keychain/securityd/SecDbBackupManager.h
keychain/securityd/SecDbBackupManager.m
keychain/securityd/SecDbBackupManager_Internal.h
keychain/securityd/SecDbItem.c
keychain/securityd/SecDbItem.h
keychain/securityd/SecDbKeychainItem.h
keychain/securityd/SecDbKeychainItem.m
keychain/securityd/SecDbKeychainItemV7.m
keychain/securityd/SecDbKeychainMetadataKeyStore.h
keychain/securityd/SecDbKeychainMetadataKeyStore.m
keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadataKey.proto [new file with mode: 0644]
keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.h [new file with mode: 0644]
keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.m [new file with mode: 0644]
keychain/securityd/SecDbQuery.c
keychain/securityd/SecDbQuery.h
keychain/securityd/SecItemBackupServer.c
keychain/securityd/SecItemBackupServer.h
keychain/securityd/SecItemDataSource.c
keychain/securityd/SecItemDb.c
keychain/securityd/SecItemDb.h
keychain/securityd/SecItemSchema.c
keychain/securityd/SecItemServer+SWC.h [new file with mode: 0644]
keychain/securityd/SecItemServer+SWC.m [new file with mode: 0644]
keychain/securityd/SecItemServer.c
keychain/securityd/SecItemServer.h
keychain/securityd/SecKeybagSupport.c
keychain/securityd/SecOTRRemote.m
keychain/securityd/com.apple.secd.sb
keychain/securityd/entitlements.plist
keychain/securityd/spi.c
keychain/tpctl/main.swift
libsecurity_smime/Security [deleted symlink]
libsecurity_smime/lib/CMSDecoder.c
libsecurity_smime/lib/CMSEncoder.c
libsecurity_smime/lib/CMSUtils.h
libsecurity_smime/lib/cmsdigest.c
libsecurity_smime/lib/cmssiginfo.c
libsecurity_smime/lib/crypto-embedded.c
libsecurity_smime/security_smime [deleted symlink]
ntlm/NtlmGenerator.c
ntlm/ntlmBlobPriv.c
protocol/SecProtocol.c
protocol/SecProtocolConfiguration.h
protocol/SecProtocolConfiguration.m
protocol/SecProtocolConfigurationTest.m
protocol/SecProtocolHelper.m
protocol/SecProtocolInternal.h
protocol/SecProtocolMetadata.h
protocol/SecProtocolOptions.h
protocol/SecProtocolPriv.h
protocol/SecProtocolTest.m
protocol/SecProtocolTypes.m
protocol/test_data/example1.json
secacltests/secacltests-entitlements.plist
secdtests/secdtests-entitlements.plist
secdxctests/CDKeychainTests.m
secdxctests/KeychainAPITests.m
secdxctests/KeychainAppClipTests.m [new file with mode: 0644]
secdxctests/KeychainBackupTests.m [new file with mode: 0644]
secdxctests/KeychainCryptoTests.m
secdxctests/KeychainEntitlementsTest.m
secdxctests/KeychainXCTest.h
secdxctests/KeychainXCTest.m
secdxctests/SFCredentialStoreTests.m
secdxctests/secdxctests-entitlements.plist [new file with mode: 0644]
sectask/SecEntitlements.h
sectask/SecTask.c
sectask/SecTask.h
sectask/SystemEntitlements.h [new file with mode: 0644]
securityd/etc/com.apple.securityd.sb
securityd/securityd_service/securityd_service.xcodeproj/project.pbxproj
securityd/securityd_service/securityd_service/main.c
securityd/securityd_service/securityd_service/securityd_service_client.c
securityd/securityd_service/securityd_service/securityd_service_client.h
securityd/src/ccaudit_extensions.cpp
securityd/src/credential.cpp
securityd/src/kcdatabase.cpp
securityd/src/keychainstasherinterface.h [new file with mode: 0644]
securityd/src/keychainstasherinterface.m [new file with mode: 0644]
securityd/src/main.cpp
securityd/src/notifications.cpp
securityd/src/notifications.h
securityd/src/process.cpp
securityd/src/securityd.entitlements
securityd/src/server.cpp
securityd/src/token.cpp
securityd/src/transition.cpp
sslViewer/SSLViewer.c
supd/Tests/SupdTests.m
supd/com.apple.securityuploadd.sb [new file with mode: 0644]
supd/main.m
supd/securityuploadd-Entitlements.plist
supd/supd.h
supd/supd.m
supdctl/main.m
tests/SecDbBackupTests/Entitlements.plist [deleted file]
tests/SecDbBackupTests/SecDbBackupTests-Entitlements.plist [new file with mode: 0644]
tests/SecDbBackupTests/SecDbBackupTests.m
tests/SecDbBackupTests/SecDbBackupTests.plist [deleted file]
tests/SecDbBackupTests/SecDbBackupTestsBase.h [new file with mode: 0644]
tests/SecDbBackupTests/SecDbBackupTestsBase.m [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.h [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.m [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/Info.plist [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.h [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.m [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestApp/main.m [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements [new file with mode: 0644]
tests/TestHostBinaries/KeychainEntitledTestRunner/KeychainEntitledTestRunner.m [new file with mode: 0644]
tests/TrustTests/DaemonTests/PersonalizationTests.m [new file with mode: 0644]
tests/TrustTests/DaemonTests/TrustDaemonTestCase.h
tests/TrustTests/EvaluationTests/AllowlistBlocklistTests.m [new file with mode: 0644]
tests/TrustTests/EvaluationTests/AllowlistBlocklistTests_data.h [new file with mode: 0644]
tests/TrustTests/EvaluationTests/CAIssuerTests.m [new file with mode: 0644]
tests/TrustTests/EvaluationTests/CAIssuerTests_data.h [new file with mode: 0644]
tests/TrustTests/EvaluationTests/CTTests.m
tests/TrustTests/EvaluationTests/KeySizeTests.m
tests/TrustTests/EvaluationTests/NameConstraintsTests.m
tests/TrustTests/EvaluationTests/PathParseTests.m
tests/TrustTests/EvaluationTests/PathParseTests_data.h
tests/TrustTests/EvaluationTests/PolicyTests.m
tests/TrustTests/EvaluationTests/SMIMEPolicyTests.m [new file with mode: 0644]
tests/TrustTests/EvaluationTests/SSLPolicyTests.m
tests/TrustTests/EvaluationTests/SSLPolicyTests_data.h
tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.h
tests/TrustTests/EvaluationTests/TrustEvaluationTestCase.m
tests/TrustTests/EvaluationTests/TrustSettingsTests.m [new file with mode: 0644]
tests/TrustTests/EvaluationTests/TrustSettingsTests_data.h [new file with mode: 0644]
tests/TrustTests/EvaluationTests/ValidTests.m [new file with mode: 0644]
tests/TrustTests/EvaluationTests/VerifyDateTests.m
tests/TrustTests/EvaluationTests/VerifyDateTests_data.h
tests/TrustTests/FrameworkTests/CertificateInterfaceTests.m
tests/TrustTests/FrameworkTests/CertificateInterfaceTests_data.h
tests/TrustTests/FrameworkTests/CertificateParseTests.m
tests/TrustTests/FrameworkTests/TrustInterfaceTests.m
tests/TrustTests/TestData/SMIMEPolicyTests-data/any_eku.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/common_name.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/data_encipher.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/digital_signature.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/email_field.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/email_protection.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_decipher_only.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_decipher.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_only.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/key_encipher.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/no_name.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/non_repudiation.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/root.cer [new file with mode: 0644]
tests/TrustTests/TestData/SMIMEPolicyTests-data/san_name.cer [new file with mode: 0644]
tests/TrustTests/TestData/TestCopyProperties_ios-data/TestCopyProperties_ios.plist
tests/TrustTests/TestRunners/Base.lproj/LaunchScreen.storyboard [deleted file]
tests/TrustTests/TestRunners/Base.lproj/Main.storyboard [deleted file]
tests/TrustTests/TestRunners/main.m
tests/TrustTests/TestRunners/trusttests_entitlements.plist
tests/TrustTests/TrustEvaluationTestHelpers.m
tests/TrustTests/gen_test_plist.py
tests/secdmockaks/mockaks.h
tests/secdmockaks/mockaks.m
tests/secdmockaks/mockaksKeychain.m
tests/stashtester/main.m [new file with mode: 0644]
tests/stashtester/stashtester.entitlements [new file with mode: 0644]
trust/headers/SecCertificate.h
trust/headers/SecCertificatePriv.h
trust/headers/SecPolicy.h
trust/headers/SecPolicyPriv.h
trust/headers/SecTrust.h
trust/headers/SecTrustPriv.h
trust/headers/SecTrustSettingsPriv.h
trust/headers/oids.h
trust/trustd/OTATrustUtilities.m
trust/trustd/SecCertificateServer.c
trust/trustd/SecCertificateServer.h
trust/trustd/SecCertificateSource.c
trust/trustd/SecCertificateSource.h
trust/trustd/SecOCSPResponse.c
trust/trustd/SecOCSPResponse.h
trust/trustd/SecPinningDb.m
trust/trustd/SecPolicyServer.c
trust/trustd/SecRevocationDb.c
trust/trustd/SecRevocationDb.h
trust/trustd/SecRevocationNetworking.h
trust/trustd/SecRevocationNetworking.m
trust/trustd/SecRevocationServer.c
trust/trustd/SecTrustExceptionResetCount.m
trust/trustd/SecTrustServer.c
trust/trustd/SecTrustServer.h
trust/trustd/SecTrustStoreServer.c
trust/trustd/SecTrustStoreServer.h
trust/trustd/SecTrustStoreServer.m
trust/trustd/iOS/entitlements.plist
trust/trustd/macOS/com.apple.trustd.sb
trust/trustd/macOS/entitlements.plist
trust/trustd/trustd.c
trust/trustd/trustd_spi.c
xcconfig/PlatformFeatures.xcconfig
xcconfig/PlatformLibraries.xcconfig
xcconfig/Security.xcconfig
xcconfig/all_arches.xcconfig [deleted file]
xcconfig/framework_requiring_modern_objc_runtime.xcconfig [deleted file]
xcconfig/lib_ios.xcconfig
xcconfig/swift_binary.xcconfig
xcscripts/install-test-framework.sh

index 43c689e8c3e7bb0d637f054494548766b3f24da6..ee93ab062910e5d5af631de46009d31d9cf7e639 100644 (file)
@@ -1,12 +1,16 @@
 indentation: 4
 disabled_rules:
+    - cyclomatic_complexity
     - file_length
     - function_body_length
     - function_parameter_count
     - identifier_name
+    - implicit_return
+    - large_tuple
     - line_length
     - todo
     - type_body_length
+    - type_name
 opt_in_rules:
     - anyobject_protocol
     - array_init
@@ -14,18 +18,30 @@ opt_in_rules:
       #- closure_end_indentation ## commented as --format removes option
     - closure_spacing
     - conditional_returns_on_newline
+    - contains_over_range_nil_comparison
     - empty_count
+    - empty_string
     - explicit_init
-    - implicit_return
+    - fatal_error_message
+    - first_where
+    - implicitly_unwrapped_optional
     - joined_default_parameter
       #- literal_expression_end_indentation  ## commented as --format removes option
+    - legacy_random
+    - let_var_whitespace
+    - lower_acl_than_parent
+    - multiline_function_chains
     - operator_usage_whitespace
+    - pattern_matching_keywords
     - redundant_nil_coalescing
     - redundant_type_annotation
     - sorted_imports
     - trailing_closure
     - unneeded_parentheses_in_closure_argument
     - untyped_error_in_catch
+    - vertical_whitespace_closing_braces
+    - xct_specific_matcher
+    - yoda_condition
 trailing_comma:
     mandatory_comma: true
 excluded:
index f33440930f98db67080ecfea02b1a94ae89db662..7d39c0afea2dbbff8764bf75219c03b3ed102022 100644 (file)
@@ -44,6 +44,8 @@ typedef NSString* LKAnalyticsFailableEvent NS_STRING_ENUM;
 typedef NSString* LKAnalyticsMetric NS_STRING_ENUM;
 
 extern LKAnalyticsFailableEvent const LKAEventUpgrade;
+extern LKAnalyticsFailableEvent const LKAEventStash;
+extern LKAnalyticsFailableEvent const LKAEventStashLoad;
 
 @interface LocalKeychainAnalytics : SFAnalytics
 
index 8d97a540bdea76213d5af0ac094b751406530002..9eabc0acd70f203dbe8eef627fc6b674e2c1c093 100644 (file)
@@ -32,6 +32,10 @@ LKAnalyticsFailableEvent const LKAEventUpgrade = (LKAnalyticsFailableEvent)@"LKA
 LKAnalyticsFailableEvent const LKAEventBackup = (LKAnalyticsFailableEvent)@"LKAEventBackup";
 LKAnalyticsMetric const LKAMetricBackupDuration = (LKAnalyticsMetric)@"LKAMetricBackupDuration";
 
+// <rdar://problem/60767235> SFAnalytics: Collect keychain masterkey stash success/failure rates and failure codes on macOS SUs
+LKAnalyticsFailableEvent const LKAEventStash = (LKAnalyticsFailableEvent)@"LKAEventStash";
+LKAnalyticsFailableEvent const LKAEventStashLoad = (LKAnalyticsFailableEvent)@"LKAEventStashLoad";
+
 // Internal consts
 NSString* const LKAOldSchemaKey = @"oldschema";
 NSString* const LKANewSchemaKey = @"newschema";
index 53e813129b23741921fe0d12d397d83e2157a967..872874185fb9ddcb04e908b85fabc7305feb3bfd 100644 (file)
@@ -26,7 +26,7 @@
 #define SOSAnalytics_h
 
 #import <Foundation/Foundation.h>
-#import "Analytics/SFAnalytics.h"
+#import <Security/SFAnalytics.h>
 
 extern NSString* const CKDKVSPerformanceCountersSampler;
 
index 55d35ba62c75084ea819c49b8cb6137b15f52ea5..2010156d81bb510d8afd8189db7f640944f7e15b 100644 (file)
@@ -26,9 +26,9 @@
 #define SFAnalytics_h
 
 #import <Foundation/Foundation.h>
-#import "SFAnalyticsSampler.h"
-#import "SFAnalyticsMultiSampler.h"
-#import "SFAnalyticsActivityTracker.h"
+#import <Security/SFAnalyticsSampler.h>
+#import <Security/SFAnalyticsMultiSampler.h>
+#import <Security/SFAnalyticsActivityTracker.h>
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -70,6 +70,9 @@ typedef NS_ENUM(uint32_t, SFAnalyticsTimestampBucket) {
 // Help for the subclass to pick a prefered location
 + (NSString *)defaultAnalyticsDatabasePath:(NSString *)basename;
 
++ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename uuid:(NSUUID * __nullable)userUuid;
++ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename; // uses current user UUID for path
+
 - (void)dailyCoreAnalyticsMetrics:(NSString *)eventName;
 
 // Log event-based metrics: create an event corresponding to some event in your feature
index a51eb5f90dafa0aa4d96589847e3d83ec1443d55..f3014caa66a6a6b5c4b30fc137032778b90227ff 100644 (file)
@@ -42,6 +42,7 @@
 
 #if TARGET_OS_OSX
 #include <sys/sysctl.h>
+#include <membership.h>
 #else
 #import <sys/utsname.h>
 #endif
@@ -80,6 +81,7 @@ NSString* const SFAnalyticsTopicCloudServices = @"CloudServicesTopic";
 NSString* const SFAnalyticsTopicKeySync = @"KeySyncTopic";
 NSString* const SFAnalyticsTopicTrust = @"TrustTopic";
 NSString* const SFAnalyticsTopicTransparency = @"TransparencyTopic";
+NSString* const SFAnalyticsTopicNetworking = @"NetworkingTopic";
 
 NSString* const SFAnalyticsTableSchema =    @"CREATE TABLE IF NOT EXISTS hard_failures (\n"
                                                 @"id INTEGER PRIMARY KEY AUTOINCREMENT,\n"
@@ -197,6 +199,61 @@ const NSTimeInterval SFAnalyticsSamplerIntervalOncePerReport = -1.0;
     return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)path) path];
 }
 
++ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename uuid:(NSUUID * __nullable)userUuid
+{
+    // Create the top-level directory with full access
+    NSMutableString *directory = [NSMutableString stringWithString:@"sfanalytics"];
+    WithPathInProtectedDirectory((__bridge  CFStringRef)directory, ^(const char *path) {
+        mode_t permissions = 0777;
+        int ret = mkpath_np(path, permissions);
+        if (!(ret == 0 || ret ==  EEXIST)) {
+            secerror("could not create path: %s (%s)", path, strerror(ret));
+        }
+        chmod(path, permissions);
+    });
+
+    // create per-user directory
+    if (userUuid) {
+        [directory appendString:@"/"];
+        [directory appendString:[userUuid UUIDString]];
+        WithPathInProtectedDirectory((__bridge  CFStringRef)directory, ^(const char *path) {
+#if TARGET_OS_IPHONE
+            mode_t permissions = 0775;
+#else
+            mode_t permissions = 0700;
+            if (geteuid() == 0) {
+                // Root user directory needs to be read/write for group so that user supd can upload root data
+                permissions = 0775;
+            }
+#endif // TARGET_OS_IPHONE
+            int ret = mkpath_np(path, permissions);
+            if (!(ret == 0 || ret ==  EEXIST)) {
+                secerror("could not create path: %s (%s)", path, strerror(ret));
+            }
+            chmod(path, permissions);
+        });
+    }
+    NSString *path = [NSString stringWithFormat:@"%@/%@.db", directory, basename];
+    return [(__bridge_transfer NSURL*)SecCopyURLForFileInProtectedDirectory((__bridge CFStringRef)path) path];
+}
+
++ (NSString *)defaultProtectedAnalyticsDatabasePath:(NSString *)basename
+{
+#if TARGET_OS_OSX
+    uid_t euid = geteuid();
+    uuid_t currentUserUuid;
+    int ret = mbr_uid_to_uuid(euid, currentUserUuid);
+    if (ret != 0) {
+        secerror("failed to get UUID for user(%d) - %d", euid, ret);
+        return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:nil];
+    }
+    NSUUID *userUuid = [[NSUUID alloc] initWithUUIDBytes:currentUserUuid];
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:userUuid];
+#else
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:basename uuid:nil];
+#endif // TARGET_OS_IPHONE
+}
+
 + (NSInteger)fuzzyDaysSinceDate:(NSDate*)date
 {
     // Sentinel: it didn't happen at all
index ec44cc55ab946e30c508e8cb58c4739e0e8d6534..0b7cab8d8392b4dbd8c39006a24b59ffe5605258 100644 (file)
                <key>splunk_bagURL</key>
                <string>https://metrics-config.icloud.com/config/TransparencyAnalytics</string>
        </dict>
+       <key>NetworkingTopic</key>
+       <dict>
+               <key>uploadSizeLimit</key>
+               <real>1000000</real>
+               <key>splunk_allowInsecureCertificate</key>
+               <false/>
+               <key>splunk_topic</key>
+               <string>xp_sear_trust</string>
+               <key>splunk_bagURL</key>
+               <string>https://xp.apple.com/config/1/report/xp_sear_trust</string>
+               <key>disableClientId</key>
+               <true/>
+       </dict>
 </dict>
 </plist>
index abf89eec69046ddf08351bbdfbb10cd7069672e0..06bff295a19501fda5121eb3ed446f2c1661a923 100644 (file)
@@ -61,6 +61,7 @@ extern NSString* const SFAnalyticsTopicCloudServices;
 extern NSString* const SFAnalyticsTopicKeySync;
 extern NSString* const SFAnalyticsTopicTrust;
 extern NSString* const SFAnalyticsTopicTransparency;
+extern NSString* const SFAnalyticsTopicNetworking;
 
 typedef NS_ENUM(NSInteger, SFAnalyticsEventClass) {
     SFAnalyticsEventClassSuccess,
index 16531fa5a5ac3a532c9939cb664b68ad66177124..c7bbade4765dd2110976b5846140519db9623e6e 100644 (file)
@@ -23,8 +23,8 @@
 
 #if __OBJC2__
 
-#import "Analytics/SQLite/SFSQLite.h"
-#import "SFAnalytics.h"
+#import <Security/SFSQLite.h>
+#import <Security/SFAnalytics.h>
 
 @interface SFAnalyticsSQLiteStore : SFSQLite
 
index fcde86f7f061d736ab77b340092b19af5baf56dc..e0f1a8ddee6f9121ad596d68c041c55e2d3efc31 100644 (file)
@@ -28,6 +28,7 @@
 #include <sqlite3.h>
 #include <CommonCrypto/CommonDigest.h>
 #import "utilities/debugging.h"
+#import "utilities/simulatecrash_assert.h"
 #include <os/transaction_private.h>
 
 #define kSFSQLiteBusyTimeout       (5*60*1000)
@@ -911,7 +912,7 @@ done:
 - (NSString *)_tableNameForClass:(Class)objectClass {
     NSString *className = [objectClass SFSQLiteClassName];
     if (![className hasPrefix:_objectClassPrefix]) {
-        secerror("sfsqlite: %@", [NSString stringWithFormat:@"Object class \"%@\" does not have prefix \"%@\"", className, _objectClassPrefix]);
+        secerror("sfsqlite: Object class \"%@\" does not have prefix \"%@\"", className, _objectClassPrefix);
         return nil;
     }
     return [className substringFromIndex:_objectClassPrefix.length];
index 031ad4a4cd42a3a1cab966bde57bf8820d8c6b31..30e4f01c2100f0a34c04344341b67cf8c4c5d10f 100644 (file)
@@ -68,7 +68,7 @@ typedef CF_ENUM(uint32_t, CMSSignerStatus) {
  * Create a CMSDecoder. Result must eventually be freed via CFRelease().
  */
 OSStatus CMSDecoderCreate(CMSDecoderRef * __nonnull CF_RETURNS_RETAINED cmsDecoderOut) /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Feed raw bytes of the message to be decoded into the decoder. Can be called
@@ -80,7 +80,7 @@ OSStatus CMSDecoderUpdateMessage(
     CMSDecoderRef              cmsDecoder,
     const void                 *msgBytes,
     size_t                             msgBytesLen)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Indicate that no more CMSDecoderUpdateMessage() calls are forthcoming;
@@ -89,7 +89,7 @@ OSStatus CMSDecoderUpdateMessage(
  * message.
  */
 OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * A signed CMS message optionally includes the data which was signed. If the
@@ -105,7 +105,7 @@ OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder)
 OSStatus CMSDecoderSetDetachedContent(
     CMSDecoderRef              cmsDecoder,
     CFDataRef                  detachedContent)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the detached content specified in CMSDecoderSetDetachedContent().
@@ -115,7 +115,7 @@ OSStatus CMSDecoderSetDetachedContent(
 OSStatus CMSDecoderCopyDetachedContent(
     CMSDecoderRef              cmsDecoder,
     CFDataRef * __nonnull CF_RETURNS_RETAINED detachedContentOut)      /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 #if SEC_OS_OSX
 /*
@@ -125,7 +125,7 @@ OSStatus CMSDecoderCopyDetachedContent(
 OSStatus CMSDecoderSetSearchKeychain(
     CMSDecoderRef        cmsDecoder,
     CFTypeRef            keychainOrArray)
-    API_DEPRECATED_WITH_REPLACEMENT("SecKeychainSetSearchList",macos(10.5, 10.13)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED_WITH_REPLACEMENT("SecKeychainSetSearchList",macos(10.5, 10.13)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #endif // SEC_OS_OSX
 
 /*
@@ -136,7 +136,7 @@ OSStatus CMSDecoderSetSearchKeychain(
 OSStatus CMSDecoderGetNumSigners(
     CMSDecoderRef              cmsDecoder,
     size_t                             *numSignersOut) /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the status of a CMS message's signature. A CMS message can
@@ -220,7 +220,7 @@ OSStatus CMSDecoderCopySignerStatus(
     CMSSignerStatus * __nullable signerStatusOut,               /* optional; RETURNED */
     SecTrustRef * __nullable CF_RETURNS_RETAINED secTrustOut,   /* optional; RETURNED */
     OSStatus * __nullable certVerifyResultCodeOut)              /* optional; RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the email address of signer 'signerIndex' of a CMS message, if
@@ -235,7 +235,7 @@ OSStatus CMSDecoderCopySignerEmailAddress(
     CMSDecoderRef              cmsDecoder,
     size_t                             signerIndex,
     CFStringRef        * __nonnull CF_RETURNS_RETAINED signerEmailAddressOut)  /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the certificate of signer 'signerIndex' of a CMS message, if
@@ -250,7 +250,7 @@ OSStatus CMSDecoderCopySignerCert(
     CMSDecoderRef              cmsDecoder,
     size_t                             signerIndex,
     SecCertificateRef * __nonnull CF_RETURNS_RETAINED signerCertOut)    /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Determine whether a CMS message was encrypted. Returns TRUE if so, FALSE if not.
@@ -262,7 +262,7 @@ OSStatus CMSDecoderCopySignerCert(
 OSStatus CMSDecoderIsContentEncrypted(
     CMSDecoderRef              cmsDecoder,
     Boolean                            *isEncryptedOut)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the eContentType OID for a SignedData's EncapsulatedContentType, if
@@ -274,7 +274,7 @@ OSStatus CMSDecoderIsContentEncrypted(
 OSStatus CMSDecoderCopyEncapsulatedContentType(
    CMSDecoderRef               cmsDecoder,
    CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut)  /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain an array of all of the certificates in a message. Elements of the
@@ -287,7 +287,7 @@ OSStatus CMSDecoderCopyEncapsulatedContentType(
 OSStatus CMSDecoderCopyAllCerts(
     CMSDecoderRef              cmsDecoder,
     CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut)    /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the actual message content (payload), if any. If the message was
@@ -298,7 +298,7 @@ OSStatus CMSDecoderCopyAllCerts(
 OSStatus CMSDecoderCopyContent(
     CMSDecoderRef              cmsDecoder,
     CFDataRef * __nonnull CF_RETURNS_RETAINED contentOut)      /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the signing time of signer 'signerIndex' of a CMS message, if
@@ -314,7 +314,7 @@ OSStatus CMSDecoderCopySignerSigningTime(
     CMSDecoderRef              cmsDecoder,
     size_t                             signerIndex,
     CFAbsoluteTime      *signingTime)                  /* RETURNED */
-    __API_AVAILABLE(macos(10.8)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.8)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
@@ -330,7 +330,7 @@ OSStatus CMSDecoderCopySignerTimestamp(
     CMSDecoderRef              cmsDecoder,
     size_t                             signerIndex,
     CFAbsoluteTime      *timestamp)                    /* RETURNED */
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * Obtain the timestamp of signer 'signerIndex' of a CMS message, if
@@ -347,7 +347,7 @@ OSStatus CMSDecoderCopySignerTimestampWithPolicy(
     CFTypeRef __nullable timeStampPolicy,
     size_t                             signerIndex,        /* usually 0 */
     CFAbsoluteTime      *timestamp)                    /* RETURNED */
-    API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * Obtain an array of the certificates in a timestamp response. Elements of the
@@ -365,7 +365,7 @@ OSStatus CMSDecoderCopySignerTimestampCertificates(
     CMSDecoderRef              cmsDecoder,
     size_t                             signerIndex,                            /* usually 0 */
     CFArrayRef * __nonnull CF_RETURNS_RETAINED certificateRefs) /* RETURNED */
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 CF_ASSUME_NONNULL_END
 
index 276b72ef2468cd22e91d914c5885a0fadbda32cb..02128b6cf05ace70b9d16b03762872d9eaf862f6 100644 (file)
@@ -62,13 +62,13 @@ CF_ASSUME_NONNULL_BEGIN
 typedef struct CF_BRIDGED_TYPE(id) _CMSEncoder *CMSEncoderRef;
 
 CFTypeID CMSEncoderGetTypeID(void)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Create a CMSEncoder. Result must eventually be freed via CFRelease().
  */
 OSStatus CMSEncoderCreate(CMSEncoderRef * __nonnull CF_RETURNS_RETAINED cmsEncoderOut) /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 extern const CFStringRef kCMSEncoderDigestAlgorithmSHA1;
 extern const CFStringRef kCMSEncoderDigestAlgorithmSHA256;
@@ -76,7 +76,7 @@ extern const CFStringRef kCMSEncoderDigestAlgorithmSHA256;
 OSStatus CMSEncoderSetSignerAlgorithm(
     CMSEncoderRef              cmsEncoder,
     CFStringRef                digestAlgorithm)
-    __API_AVAILABLE(macos(10.11)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.11)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Specify signers of the CMS message; implies that the message will be signed.
@@ -91,7 +91,7 @@ OSStatus CMSEncoderSetSignerAlgorithm(
 OSStatus CMSEncoderAddSigners(
     CMSEncoderRef              cmsEncoder,
     CFTypeRef                  signerOrArray)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain an array of signers as specified in CMSEncoderSetSigners().
@@ -101,7 +101,7 @@ OSStatus CMSEncoderAddSigners(
 OSStatus CMSEncoderCopySigners(
     CMSEncoderRef              cmsEncoder,
     CFArrayRef * __nonnull CF_RETURNS_RETAINED signersOut)             /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Specify recipients of the message. Implies that the message will
@@ -117,7 +117,7 @@ OSStatus CMSEncoderCopySigners(
 OSStatus CMSEncoderAddRecipients(
     CMSEncoderRef              cmsEncoder,
     CFTypeRef                  recipientOrArray)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain an array of recipients as specified in CMSEncoderSetRecipients().
@@ -128,7 +128,7 @@ OSStatus CMSEncoderAddRecipients(
 OSStatus CMSEncoderCopyRecipients(
     CMSEncoderRef              cmsEncoder,
     CFArrayRef * __nonnull CF_RETURNS_RETAINED recipientsOut)  /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * A signed message optionally includes the data to be signed. If the message
@@ -144,7 +144,7 @@ OSStatus CMSEncoderCopyRecipients(
 OSStatus CMSEncoderSetHasDetachedContent(
     CMSEncoderRef              cmsEncoder,
     Boolean                    detachedContent)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain a Boolean indicating whether the current message will have detached
@@ -155,7 +155,7 @@ OSStatus CMSEncoderSetHasDetachedContent(
 OSStatus CMSEncoderGetHasDetachedContent(
     CMSEncoderRef              cmsEncoder,
     Boolean                    *detachedContentOut)    /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 #if SEC_OS_OSX
 /*
@@ -173,7 +173,7 @@ OSStatus CMSEncoderGetHasDetachedContent(
 OSStatus CMSEncoderSetEncapsulatedContentType(
     CMSEncoderRef        cmsEncoder,
     const CSSM_OID    *eContentType)
-    API_DEPRECATED_WITH_REPLACEMENT("CMSEncoderSetEncapsulatedContentTypeOID", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED_WITH_REPLACEMENT("CMSEncoderSetEncapsulatedContentTypeOID", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #endif // SEC_OS_OSX
 
 /*
@@ -191,7 +191,7 @@ OSStatus CMSEncoderSetEncapsulatedContentType(
 OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
     CMSEncoderRef              cmsEncoder,
     CFTypeRef                  eContentTypeOID)
-    __API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the eContentType OID specified in CMSEncoderSetEncapsulatedContentType().
@@ -204,7 +204,7 @@ OSStatus CMSEncoderSetEncapsulatedContentTypeOID(
 OSStatus CMSEncoderCopyEncapsulatedContentType(
     CMSEncoderRef              cmsEncoder,
     CFDataRef * __nonnull CF_RETURNS_RETAINED eContentTypeOut)         /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Signed CMS messages can contain arbitrary sets of certificates beyond those
@@ -229,7 +229,7 @@ OSStatus CMSEncoderCopyEncapsulatedContentType(
 OSStatus CMSEncoderAddSupportingCerts(
     CMSEncoderRef              cmsEncoder,
     CFTypeRef                  certOrArray)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain the SecCertificates provided in CMSEncoderAddSupportingCerts().
@@ -240,7 +240,7 @@ OSStatus CMSEncoderAddSupportingCerts(
 OSStatus CMSEncoderCopySupportingCerts(
     CMSEncoderRef              cmsEncoder,
     CFArrayRef * __nonnull CF_RETURNS_RETAINED certsOut)                       /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Standard signed attributes, optionally specified in
@@ -285,7 +285,7 @@ typedef CF_OPTIONS(uint32_t, CMSSignedAttributes) {
 OSStatus CMSEncoderAddSignedAttributes(
     CMSEncoderRef              cmsEncoder,
     CMSSignedAttributes        signedAttributes)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Specification of what certificates to include in a signed message.
@@ -313,7 +313,7 @@ typedef CF_ENUM(uint32_t, CMSCertificateChainMode) {
 OSStatus CMSEncoderSetCertificateChainMode(
     CMSEncoderRef                      cmsEncoder,
     CMSCertificateChainMode    chainMode)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Obtain indication of which signer certs are to be included
@@ -322,7 +322,7 @@ OSStatus CMSEncoderSetCertificateChainMode(
 OSStatus CMSEncoderGetCertificateChainMode(
     CMSEncoderRef                      cmsEncoder,
     CMSCertificateChainMode    *chainModeOut)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Feed content bytes into the encoder.
@@ -333,7 +333,7 @@ OSStatus CMSEncoderUpdateContent(
     CMSEncoderRef              cmsEncoder,
     const void                 *content,
     size_t                             contentLen)
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 /*
  * Finish encoding the message and obtain the encoded result.
@@ -342,7 +342,7 @@ OSStatus CMSEncoderUpdateContent(
 OSStatus CMSEncoderCopyEncodedContent(
     CMSEncoderRef              cmsEncoder,
     CFDataRef * __nonnull CF_RETURNS_RETAINED encodedContentOut)       /* RETURNED */
-    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.5)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 #if TARGET_OS_OSX
 /*
@@ -377,7 +377,7 @@ OSStatus CMSEncode(
     const void *                content,
     size_t                      contentLen,
     CFDataRef * __nonnull CF_RETURNS_RETAINED encodedContentOut)    /* RETURNED */
-    API_DEPRECATED_WITH_REPLACEMENT("CMSEncodeContent", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED_WITH_REPLACEMENT("CMSEncodeContent", macos(10.5, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #endif // TARGET_OS_OSX
 
 /*
@@ -410,20 +410,20 @@ OSStatus CMSEncodeContent(
     const void              *content,
     size_t                  contentLen,
     CFDataRef * __nullable CF_RETURNS_RETAINED encodedContentOut)      /* RETURNED */
-    __API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), iosmac(11.0));
+    __API_AVAILABLE(macos(10.7)) SPI_AVAILABLE(ios(11.0), tvos(11.0), watchos(4.0), macCatalyst(11.0));
 
 OSStatus CMSEncoderCopySignerTimestamp(
     CMSEncoderRef              cmsEncoder,
     size_t                             signerIndex,        /* usually 0 */
     CFAbsoluteTime      *timestamp)                    /* RETURNED */
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 OSStatus CMSEncoderCopySignerTimestampWithPolicy(
     CMSEncoderRef           cmsEncoder,
     CFTypeRef __nullable    timeStampPolicy,
     size_t                  signerIndex,        /* usually 0 */
     CFAbsoluteTime          *timestamp)                        /* RETURNED */
-    API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.10)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 CF_ASSUME_NONNULL_END
 
index 548a279260fefeb5eb086693290747e8d8b1a633..b8a5c137631d908bd13fe3cd9143e53ae499220f 100644 (file)
@@ -115,7 +115,7 @@ OSStatus CMSEncoderSetAppleExpirationTime(
 
 void
 CmsMessageSetTSAContext(CMSEncoderRef cmsEncoder, CFTypeRef tsaContext)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
 
 /***
  *** Private CMSDecoder routines
index 44f7eadea5d35e5e36947ba14b2a123abfd7cfa1..77ec4ac5e80f3192d87898a94e989090bc8559f8 100644 (file)
@@ -69,9 +69,9 @@ typedef SecAsn1AlgId SECAlgorithmID;
     @discussion XXX This should probably move to SecKey.h
  */
 #if TARGET_OS_OSX
-typedef SecKeyRef SecSymmetricKeyRef API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+typedef SecKeyRef SecSymmetricKeyRef API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else
-typedef void * SecSymmetricKeyRef API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+typedef void * SecSymmetricKeyRef API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif
 
 /*!
@@ -173,7 +173,7 @@ typedef void (*SecCmsContentCallback)(void *arg, const char *buf, size_t len);
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 typedef SecSymmetricKeyRef(*SecCmsGetDecryptKeyCallback)(void *arg, SECAlgorithmID *algid)
-    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 
 /*!
index c799eb43bb3b9f3fc44c853d258ba43ffdafebb5..2a4eafeb79374aa9e9c7b8145def6c603f207c4c 100644 (file)
@@ -71,7 +71,7 @@ SecCmsContentInfoGetContent(SecCmsContentInfoRef cinfo);
  */
 extern CSSM_DATA_PTR
 SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -80,7 +80,7 @@ SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
  */
 extern const SecAsn1Item *
 SecCmsContentInfoGetInnerContent(SecCmsContentInfoRef cinfo)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 /*!
@@ -99,7 +99,7 @@ SecCmsContentInfoGetContentTypeTag(SecCmsContentInfoRef cinfo);
  */
 extern CSSM_OID *
 SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -108,7 +108,7 @@ SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
  */
 extern SecAsn1Oid *
 SecCmsContentInfoGetContentTypeOID(SecCmsContentInfoRef cinfo)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 /*!
@@ -143,7 +143,7 @@ SecCmsContentInfoGetContentEncAlg(SecCmsContentInfoRef cinfo)
  */
 extern OSStatus
 SecCmsContentInfoSetContentData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -157,7 +157,7 @@ SecCmsContentInfoSetContentData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinf
  */
 extern OSStatus
 SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef data, Boolean detached)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -173,7 +173,7 @@ SecCmsContentInfoSetContentData(SecCmsContentInfoRef cinfo, CFDataRef data, Bool
  */
 extern OSStatus
 SecCmsContentInfoSetContentSignedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -186,7 +186,7 @@ SecCmsContentInfoSetContentSignedData(SecCmsMessageRef cmsg, SecCmsContentInfoRe
  */
 extern OSStatus
 SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDataRef sigd)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -202,7 +202,7 @@ SecCmsContentInfoSetContentSignedData(SecCmsContentInfoRef cinfo, SecCmsSignedDa
  */
 extern OSStatus
 SecCmsContentInfoSetContentEnvelopedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -215,7 +215,7 @@ SecCmsContentInfoSetContentEnvelopedData(SecCmsMessageRef cmsg, SecCmsContentInf
  */
 extern OSStatus
 SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvelopedDataRef envd)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -231,7 +231,7 @@ SecCmsContentInfoSetContentEnvelopedData(SecCmsContentInfoRef cinfo, SecCmsEnvel
  */
 extern OSStatus
 SecCmsContentInfoSetContentDigestedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -244,7 +244,7 @@ SecCmsContentInfoSetContentDigestedData(SecCmsMessageRef cmsg, SecCmsContentInfo
  */
 extern OSStatus
 SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigestedDataRef digd)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -260,7 +260,7 @@ SecCmsContentInfoSetContentDigestedData(SecCmsContentInfoRef cinfo, SecCmsDigest
  */
 extern OSStatus
 SecCmsContentInfoSetContentEncryptedData(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -273,41 +273,41 @@ SecCmsContentInfoSetContentEncryptedData(SecCmsMessageRef cmsg, SecCmsContentInf
  */
 extern OSStatus
 SecCmsContentInfoSetContentEncryptedData(SecCmsContentInfoRef cinfo, SecCmsEncryptedDataRef encd)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
 OSStatus
 SecCmsContentInfoSetContentOther(SecCmsMessageRef cmsg, SecCmsContentInfoRef cinfo, CSSM_DATA_PTR data, Boolean detached, const CSSM_OID *eContentType)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 OSStatus
 SecCmsContentInfoSetContentOther(SecCmsContentInfoRef cinfo, SecAsn1Item *data, Boolean detached, const SecAsn1Oid *eContentType)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
 extern OSStatus
 SecCmsContentInfoSetContentEncAlg(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo,
                                   SECOidTag bulkalgtag, CSSM_DATA_PTR parameters, int keysize)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 extern OSStatus
 SecCmsContentInfoSetContentEncAlg(SecCmsContentInfoRef cinfo,
                                    SECOidTag bulkalgtag, const SecAsn1Item *parameters, int keysize)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
 extern OSStatus
 SecCmsContentInfoSetContentEncAlgID(SecArenaPoolRef pool, SecCmsContentInfoRef cinfo,
                                     SECAlgorithmID *algid, int keysize)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 extern OSStatus
 SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
                                    SECAlgorithmID *algid, int keysize)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !!TARGET_OS_OSX
 
 /*!
@@ -315,14 +315,14 @@ SecCmsContentInfoSetContentEncAlgID(SecCmsContentInfoRef cinfo,
  */
 extern void
 SecCmsContentInfoSetBulkKey(SecCmsContentInfoRef cinfo, SecSymmetricKeyRef bulkkey)
-    API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 
 /*!
     @function
  */
 extern SecSymmetricKeyRef
 SecCmsContentInfoGetBulkKey(SecCmsContentInfoRef cinfo)
-    API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4),ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 
 /*!
     @function
index b1eb50eca96694e51dfb0f735a2a8b2598e4e0a9..1098f80d60afd678af807d89ecac952c6bd62d0f 100644 (file)
@@ -68,7 +68,7 @@ SecCmsDecoderCreate(SecArenaPoolRef arena,
                     SecCmsGetDecryptKeyCallback decrypt_key_cb, void
                     *decrypt_key_cb_arg,
                     SecCmsDecoderRef *outDecoder)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 /*!
     @function
@@ -94,7 +94,7 @@ SecCmsDecoderCreate(SecCmsContentCallback cb, void *cb_arg,
                    SecCmsGetDecryptKeyCallback decrypt_key_cb, void
                    *decrypt_key_cb_arg,
                    SecCmsDecoderRef *outDecoder)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 /*!
@@ -161,7 +161,7 @@ SecCmsMessageDecode(const CSSM_DATA *encodedMessage,
                     PK11PasswordFunc pwfn, void *pwfn_arg,
                     SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
                     SecCmsMessageRef *outMessage)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 /*!
@@ -190,7 +190,7 @@ SecCmsMessageDecode(const SecAsn1Item *encodedMessage,
                     PK11PasswordFunc pwfn, void *pwfn_arg,
                     SecCmsGetDecryptKeyCallback decrypt_key_cb, void *decrypt_key_cb_arg,
                     SecCmsMessageRef *outMessage)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 
index 159a28271c711ea435d6c18e8c473e021a53843e..0a6e01943e1b0f444672328085e0f8b15fd32ae5 100644 (file)
@@ -44,7 +44,7 @@ __BEGIN_DECLS
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern SecCmsDigestContextRef
 SecCmsDigestContextStartMultiple(SECAlgorithmID **digestalgs)
-    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 
 /*!
@@ -70,7 +70,7 @@ SecCmsDigestContextCancel(SecCmsDigestContextRef cmsdigcx);
  */
 extern void
 SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // TARGET_OS_IPHONE
 
 #if TARGET_OS_OSX
@@ -83,7 +83,7 @@ SecCmsDigestContextDestroy(SecCmsDigestContextRef cmsdigcx)
 extern OSStatus
 SecCmsDigestContextFinishMultiple(SecCmsDigestContextRef cmsdigcx, SecArenaPoolRef arena,
                                   CSSM_DATA_PTR **digestsp)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #endif // TARGET_OS_OSX
 
index 6fc48c998e3dec056680dacdc2311a17244795e4..466b31392906a469ffe6a0c02c80a4e24a229c08 100644 (file)
@@ -51,7 +51,7 @@ __BEGIN_DECLS
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern SecCmsDigestedDataRef
 SecCmsDigestedDataCreate(SecCmsMessageRef cmsg, SECAlgorithmID *digestalg)
-    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4), ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 
 /*!
index 102c39af853ae1de9559648fc2b39d51d9cf9944..f43037acd0b1d914b2e4abcda6cde18d6e856be0 100644 (file)
@@ -77,7 +77,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg,
                     SecCmsGetDecryptKeyCallback encrypt_key_cb, void *encrypt_key_cb_arg,
                     SECAlgorithmID **detached_digestalgs, CSSM_DATA_PTR *detached_digests,
                     SecCmsEncoderRef *outEncoder)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 /*!
@@ -107,7 +107,7 @@ SecCmsEncoderCreate(SecCmsMessageRef cmsg,
                     PK11PasswordFunc pwfn, void *pwfn_arg,
                     SecCmsGetDecryptKeyCallback encrypt_key_cb, void *encrypt_key_cb_arg,
                     SecCmsEncoderRef *outEncoder)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
     
 /*!
@@ -157,7 +157,7 @@ SecCmsEncoderFinish(SecCmsEncoderRef encoder);
 extern OSStatus
 SecCmsMessageEncode(SecCmsMessageRef cmsg, const CSSM_DATA *input, SecArenaPoolRef arena,
                     CSSM_DATA_PTR outBer)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 /*!
@@ -172,7 +172,7 @@ SecCmsMessageEncode(SecCmsMessageRef cmsg, const CSSM_DATA *input, SecArenaPoolR
 extern OSStatus
 SecCmsMessageEncode(SecCmsMessageRef cmsg, const SecAsn1Item *input,
                     CFMutableDataRef outBer)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 __END_DECLS
index 497c4677baa9464d7708818e35181d66c012f3f6..7cbb8277e5c978605840deb33299b84d195bb872 100644 (file)
@@ -55,7 +55,7 @@ __BEGIN_DECLS
  */
 extern SecCmsMessageRef
 SecCmsMessageCreate(SecArenaPoolRef poolp)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 
 #else // !TARGET_OS_OSX
 
@@ -69,7 +69,7 @@ SecCmsMessageCreate(SecArenaPoolRef poolp)
  */
 extern SecCmsMessageRef
 SecCmsMessageCreate(void)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 
 #endif // !TARGET_OS_OSX
 
@@ -119,7 +119,7 @@ SecCmsMessageGetContentInfo(SecCmsMessageRef cmsg);
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern CSSM_DATA_PTR
 SecCmsMessageGetContent(SecCmsMessageRef cmsg)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 /*!
@@ -130,7 +130,7 @@ SecCmsMessageGetContent(SecCmsMessageRef cmsg)
  */
 extern const SecAsn1Item *
 SecCmsMessageGetContent(SecCmsMessageRef cmsg)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 /*!
index f57481fd736c82c9b659e9cfa3b3f0d7cac5f0b5..66db12dee5f31b6babeba5969f8a3c284a1cf1f3 100644 (file)
@@ -47,7 +47,7 @@ __BEGIN_DECLS
  */
 extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg, SecCertificateRef cert)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 
 #else // !TARGET_OS_OSX
 
@@ -59,7 +59,7 @@ SecCmsRecipientInfoCreate(SecCmsMessageRef cmsg, SecCertificateRef cert)
  */
 extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreate(SecCmsEnvelopedDataRef envd, SecCertificateRef cert)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 
@@ -70,14 +70,14 @@ extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg,
                                        CSSM_DATA_PTR subjKeyID,
                                        SecPublicKeyRef pubKey)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
                                        const SecAsn1Item *subjKeyID,
                                        SecPublicKeyRef pubKey)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 
@@ -85,12 +85,12 @@ SecCmsRecipientInfoCreateWithSubjKeyID(SecCmsEnvelopedDataRef envd,
 extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsMessageRef cmsg,
                                                SecCertificateRef cert)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #else // !TARGET_OS_OSX
 extern SecCmsRecipientInfoRef
 SecCmsRecipientInfoCreateWithSubjKeyIDFromCert(SecCmsEnvelopedDataRef envd, 
                                                SecCertificateRef cert)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 
index f74f89b2311f12c1fa832d069d4e9850db5493cf..a6e3c2a229737567c97770a8ce139e403bf74f94 100644 (file)
@@ -165,7 +165,7 @@ SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd);
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern CSSM_DATA_PTR *
 SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 /*!
@@ -174,7 +174,7 @@ SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
  */
 extern SecAsn1Item * *
 SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 /*!
@@ -200,7 +200,7 @@ SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg, SecCertificateRef cert, B
  */
 extern OSStatus SecCmsSignedDataSetDigestContext(SecCmsSignedDataRef sigd,
                                                                                                 SecCmsDigestContextRef digestContext)
-     API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macos, iosmac);
+     API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macos, macCatalyst);
 #endif
 
 #if TARGET_OS_OSX
@@ -214,7 +214,7 @@ extern OSStatus
 SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd,
                            SECAlgorithmID **digestalgs,
                            CSSM_DATA_PTR *digests)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #endif
 
index f3f80d6ed6e48ecca2f1a67b4ab08c206641a74a..095950c4120a4557e96e88be9f51f3d3a6d1af9d 100644 (file)
@@ -44,13 +44,13 @@ __BEGIN_DECLS
 #if TARGET_OS_OSX
 extern SecCmsSignerInfoRef
 SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag digestalgtag)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 
 #else // !TARGET_OSX
 
 extern SecCmsSignerInfoRef
 SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOidTag digestalgtag)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -58,12 +58,12 @@ SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOid
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern SecCmsSignerInfoRef
 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(macCatalyst);
 #pragma clang diagnostic pop
 #else // !TARGET_OS_OSX
 extern SecCmsSignerInfoRef
 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd, const SecAsn1Item *subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
-    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(iosmac);
+    API_AVAILABLE(ios(2.0), tvos(2.0), watchos(1.0)) API_UNAVAILABLE(macCatalyst);
 #endif // !TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -73,7 +73,7 @@ SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd, const SecAsn1Item
  */
 extern void
 SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
-    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.4)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #endif
 
 /*!
@@ -291,26 +291,26 @@ SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSign
 
 extern OSStatus
 SecCmsSignerInfoVerifyUnAuthAttrs(SecCmsSignerInfoRef signerinfo)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 extern OSStatus
 SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 extern CSSM_DATA *
 SecCmsSignerInfoGetEncDigest(SecCmsSignerInfoRef signerinfo)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #pragma clang diagnostic pop
 
 extern CFArrayRef
 SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 extern SecCertificateRef
 SecCmsSignerInfoGetTimestampSigningCert(SecCmsSignerInfoRef signerinfo)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
      @function
@@ -321,7 +321,7 @@ SecCmsSignerInfoGetTimestampSigningCert(SecCmsSignerInfoRef signerinfo)
  */
 OSStatus
 SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
      @function
@@ -332,7 +332,7 @@ SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stim
  */
 OSStatus
 SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef timeStampPolicy, CFAbsoluteTime *stime)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
      @function
@@ -342,7 +342,7 @@ SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 OSStatus
 SecCmsSignerInfoAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA *tstoken)
-    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.8)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #pragma clang diagnostic pop
 #endif // TARGET_OS_OSX
 
index 5cce51774d8200a795a1acaed6e339d04669c6a0..58692652301a8c31dc5634ecd9dd8815ed6ca0f2 100644 (file)
 
 -(id)initWithPeerInfo:(SOSPeerInfoRef)peerInfo
 {
-    self = [super init];
-    if (!self) {
-        return self;
-    }
-    
-    self.rawPeerInfo = CFRetainSafe(peerInfo);
-    self.applicantUIState = ApplicantWaiting;
-    
+    if ((self = [super init])) {
+        self.rawPeerInfo = CFRetainSafe(peerInfo);
+        self.applicantUIState = ApplicantWaiting;
+    }    
     return self;
 }
 
index 2d9caabd1430b7f15908dfa2628d477638998407..88d42276e10b24eea749ea5f4707b1e5e7d6abaa 100644 (file)
@@ -31,8 +31,7 @@
 #import <CloudServices/SecureBackup.h>
 #import <CoreFoundation/CFUserNotification.h>
 #import <Foundation/Foundation.h>
-#import <ManagedConfiguration/MCProfileConnection.h>
-#import <ManagedConfiguration/MCFeatures.h>
+#import <ManagedConfiguration/ManagedConfiguration.h>
 #import <MobileCoreServices/MobileCoreServices.h>
 #import <MobileCoreServices/LSApplicationWorkspace.h>
 #import <MobileGestalt.h>
index 8686852b3f809f71cf27aa4666ad2085a08d4b96..f971c7949d7b2baf41c8663571cd40dfdfdfee77 100644 (file)
@@ -31,9 +31,7 @@
 }
 
 - (instancetype)init {
-    self = [super init];
-
-    if (self) {
+    if ((self = [super init])) {
         XPCNotificationDispatcher* dispatcher = [XPCNotificationDispatcher dispatcher];
 
         _queue = dispatch_queue_create("CKDAKSLockMonitor", NULL);
@@ -86,6 +84,7 @@
 }
 
 - (void) _onqueueRecheck {
+    dispatch_assert_queue(_queue);
     CFErrorRef aksError = NULL;
     bool locked = true; // Assume locked if we get an error
 
index d586951c85f9a0f5821de2e3eceed24c3fab7b48..84b7982896240d0ce48d2d94be12c62022b4ed31 100644 (file)
 #include "keychain/SecureObjectSync/SOSARCDefines.h"
 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
 #include <utilities/SecCFWrappers.h>
-#include <utilities/SecPLWrappers.h>
 
 #include "SOSCloudKeychainConstants.h"
 
 #include <utilities/SecAKSWrappers.h>
-#include <utilities/SecADWrapper.h>
 #include <utilities/SecNSAdditions.h>
 #import "XPCNotificationDispatcher.h"
 
@@ -202,7 +200,7 @@ static NSString *kMonitorWroteInTimeSlice = @"TimeSlice";
 }
 
 - (void)synchronizeStore {
-    [self.store pushWrites];
+    [self.store pushWrites:[NSArray array] requiresForceSync:YES];
 }
 
 - (id) objectForKey: (NSString*) key {
@@ -336,9 +334,9 @@ static NSString *kMonitorWroteInTimeSlice = @"TimeSlice";
              [[self store] addOneToOutGoing];
              [self.store setObject:obj forKey:key];
          }
-     }];
-    
-    [self.store pushWrites];
+    }];
+
+    [self.store pushWrites:[mutableValues allKeys] requiresForceSync:NO];
 }
 
 - (void)setObjectsFromDictionary:(NSDictionary<NSString*, NSObject*> *)values
index 4e4b87dd0a9a67e55dd18175a0ff51668df488ea..f20f0bf0eb5009bd0a9114b0f537dcbc29ec92bb 100644 (file)
@@ -25,7 +25,7 @@
 
 - (NSDictionary<NSString *, id>*) copyAsDictionary;
 
-- (void)pushWrites;
+- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync;
 - (BOOL)pullUpdates:(NSError**) failure;
 
 - (void)kvsStoreChanged: (NSNotification*) notification;
index 03386203a791677b5e23b44f3e1157e4b8b52508..c46a6a418b83cb1b009bed08a21ba705e33bdc8e 100644 (file)
@@ -19,6 +19,9 @@
 
 #import "Analytics/Clients/SOSAnalytics.h"
 
+#include "keychain/SecureObjectSync/SOSKVSKeys.h"
+#include <Security/OTConstants.h>
+
 struct CKDKVSCounters {
     uint64_t synchronize;
     uint64_t synchronizeWithCompletionHandler;
@@ -29,8 +32,6 @@ struct CKDKVSCounters {
     uint64_t synchronizeFailures;
 };
 
-
-
 @interface CKDKVSStore ()
 @property (readwrite, weak) UbiqitousKVSProxy* proxy;
 @property (readwrite) NSUbiquitousKeyValueStore* cloudStore;
@@ -45,20 +46,20 @@ struct CKDKVSCounters {
 }
 
 - (instancetype)init {
-    self = [super init];
+    if ((self = [super init])) {
 
-    self->_cloudStore = [NSUbiquitousKeyValueStore defaultStore];
-    self->_proxy = nil;
+        self->_cloudStore = [NSUbiquitousKeyValueStore defaultStore];
+        self->_proxy = nil;
 
-    if (!self.cloudStore) {
-        secerror("NO NSUbiquitousKeyValueStore defaultStore!!!");
-        return nil;
-    }
-    self.perfQueue = dispatch_queue_create("CKDKVSStorePerfQueue", NULL);
-    self.perfCounters = calloc(1, sizeof(struct CKDKVSCounters));
+        if (!self.cloudStore) {
+            secerror("NO NSUbiquitousKeyValueStore defaultStore!!!");
+            return nil;
+        }
+        self.perfQueue = dispatch_queue_create("CKDKVSStorePerfQueue", NULL);
+        self.perfCounters = calloc(1, sizeof(struct CKDKVSCounters));
     
-    [self setupSamplers];
-
+        [self setupSamplers];
+    }
     return self;
 }
 
@@ -106,13 +107,70 @@ struct CKDKVSCounters {
     }];
 }
 
-- (void)pushWrites {
-    [[self cloudStore] synchronize];
+
+- (void)forceSynchronizeWithKVS
+{
+    secnoticeq("pushWrites", "requesting force synchronization with KVS on CloudKit");
+
+    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+        NSError *error = nil;
+        bool success = [self pullUpdates:&error];
+        if(!success || error != nil) {
+            secerror("pushWrites: failed to synchronize with KVS: %@", error);
+        } else {
+            secnoticeq("pushWrites", "successfully synced with KVS!");
+        }
+    });
     dispatch_async(self.perfQueue, ^{
         self.perfCounters->synchronize++;
     });
 }
 
+- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync
+{
+    secnoticeq("pushWrites", "Push writes");
+
+    if (SecKVSOnCloudKitIsEnabled() == NO) {
+        secnoticeq("pushWrites", "KVS on CloudKit not enabled");
+
+        [[self cloudStore] synchronize];
+        dispatch_async(self.perfQueue, ^{
+            self.perfCounters->synchronize++;
+        });
+        return;
+    }
+
+    if(requiresForceSync == YES) {
+        secnoticeq("pushWrites", "requested to force synchronize");
+        [self forceSynchronizeWithKVS];
+        return;
+    }
+    
+    //if KVS on CK is enabled we should only force sync rings, circles, and key parameters
+    secnoticeq("pushWrites", "KVS on CloudKit enabled. Evaluating changed keys");
+
+    if (keys == nil || [keys count] == 0){
+        secnoticeq("pushWrites", "key set is empty, returning");
+        return;
+    }
+
+    __block BOOL proceedWithSync = NO;
+    [keys enumerateObjectsUsingBlock:^(NSString *kvsKey, NSUInteger idx, BOOL *stop) {
+        if ([kvsKey containsString:(__bridge_transfer NSString*)sRingPrefix] ||
+            [kvsKey containsString:(__bridge_transfer NSString*)sCirclePrefix] ||
+            [kvsKey containsString:(__bridge_transfer NSString*)kSOSKVSKeyParametersKey]) {
+            proceedWithSync = YES;
+        }
+    }];
+
+    if (proceedWithSync == NO) {
+        secnoticeq("pushWrites", "no keys to force push, returning");
+        return;
+    }
+
+    [self forceSynchronizeWithKVS];
+}
+
 // Runs on the same thread that posted the notification, and that thread _may_ be the
 // kdkvsproxy_queue (see 30470419). Avoid deadlock by bouncing through global queue.
 - (void)kvsStoreChangedAsync:(NSNotification *)notification
@@ -217,8 +275,10 @@ struct CKDKVSCounters {
                 self.perfCounters->synchronize++;
             });
             secnotice("fresh", "%s RETURNING FROM syncdefaultsd SWCH: %@", kWAIT2MINID, self);
-            [[self cloudStore] synchronize]; // Per olivier in <rdar://problem/13412631>, sync before getting values
-            secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self);
+            if(SecKVSOnCloudKitIsEnabled() == NO) {
+                [[self cloudStore] synchronize]; // Per olivier in <rdar://problem/13412631>, sync before getting values
+                secnotice("fresh", "%s RETURNING FROM syncdefaultsd SYNC: %@", kWAIT2MINID, self);
+            }
         }
         dispatch_semaphore_signal(freshSemaphore);
     }];
index ec68f709ca9714f8c1d5021e8aabaafdfff50ae9..3fec1119139b9cad43d2a05c2a92ad80d0e27f98 100644 (file)
@@ -22,7 +22,7 @@
 
 - (NSDictionary<NSString *, id>*) copyAsDictionary;
 
-- (void)pushWrites;
+- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync;
 - (BOOL)pullUpdates:(NSError**) failure;
 
 - (void)perfCounters:(void(^)(NSDictionary *counters))callback;
index 3b6d7dca6aeb2b4ef41f62e219c908a846339b36..0c010d1302382e4219ff50eae4082e4710e5529d 100644 (file)
@@ -61,9 +61,7 @@ static const char *kXPCNotificationNameKey = "Notification";
 }
 
 - (instancetype) init {
-    self = [super init];
-
-    if (self) {
+    if ((self = [super init])) {
         self.queue = dispatch_queue_create("XPC Notification Dispatch", DISPATCH_QUEUE_SERIAL);
         self.listeners = [NSPointerArray weakObjectsPointerArray];
         __weak typeof(self) weakSelf = self;
index b0f39a4cb459a5be4f65753105ebe5be503f9719..b3a56ba89d4549b3b804a2ecf3d21af1ebd5591c 100644 (file)
 #import "CKDSecuritydAccount.h"
 #import "CKDKVSStore.h"
 #import "CKDAKSLockMonitor.h"
+#import "SOSCloudKeychainConstants.h"
 
+#include <utilities/simulatecrash_assert.h>
 
-void finalize_connection(void *not_used);
-void handle_connection_event(const xpc_connection_t peer);
-static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event);
 
-static bool operation_put_dictionary(xpc_object_t event);
-static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event);
+#define PROXYXPCSCOPE "xpcproxy"
 
-int ckdproxymain(int argc, const char *argv[]);
+@interface CloudKeychainProxy : NSObject
+-(id _Nullable) init;
 
-#define PROXYXPCSCOPE "xpcproxy"
+@property (nonatomic, retain) UbiqitousKVSProxy *proxyID;
+@property (nonatomic, retain) xpc_connection_t listener;
+@property (nonatomic, retain) dispatch_source_t sigterm_source;
+@property (nonatomic, retain) NSURL *registrationFileName;
+
++ (CloudKeychainProxy *) sharedObject;
+- (void) cloudkeychainproxy_peer_dictionary_handler: (const xpc_connection_t) peer forEvent: (xpc_object_t) event;
 
-static void describeXPCObject(char *prefix, xpc_object_t object)
+@end
+
+static void cloudkeychainproxy_event_handler(xpc_connection_t peer)
 {
-//#ifndef NDEBUG
-    // This is useful for debugging.
-    if (object)
+    if (xpc_get_type(peer) != XPC_TYPE_CONNECTION) {
+        secinfo(PROXYXPCSCOPE, "expected XPC_TYPE_CONNECTION");
+        return;
+    }
+
+    xpc_object_t ent = xpc_connection_copy_entitlement_value(peer, "com.apple.CloudKeychainProxy.client");
+    if (ent == NULL || xpc_get_type(ent) != XPC_TYPE_BOOL || xpc_bool_get_value(ent) != true) {
+        secnotice(PROXYXPCSCOPE, "cloudkeychainproxy_event_handler: rejected client %d", xpc_connection_get_pid(peer));
+        xpc_connection_cancel(peer);
+        return;
+    }
+
+    xpc_connection_set_target_queue(peer, [[CloudKeychainProxy sharedObject].proxyID ckdkvsproxy_queue]);
+    xpc_connection_set_event_handler(peer, ^(xpc_object_t event)
     {
+        // We could handle other peer events (e.g.) disconnects,
+        // but we don't keep per-client state so there is no need.
+        if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
+            [[CloudKeychainProxy sharedObject]   cloudkeychainproxy_peer_dictionary_handler: peer forEvent: event];
+        }
+    });
+    
+    // This will tell the connection to begin listening for events. If you
+    // have some other initialization that must be done asynchronously, then
+    // you can defer this call until after that initialization is done.
+    xpc_connection_resume(peer);
+}
+
+static void finalize_connection(void *not_used) {
+    secinfo(PROXYXPCSCOPE, "finalize_connection");
+    [[CloudKeychainProxy sharedObject].proxyID synchronizeStore];
+    xpc_transaction_end();
+}
+
+@implementation CloudKeychainProxy
+
+static CFStringRef kRegistrationFileName = CFSTR("com.apple.security.cloudkeychainproxy3.keysToRegister.plist");
+
++ (CloudKeychainProxy *) sharedObject {
+    static CloudKeychainProxy *sharedCKP = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sharedCKP = [CloudKeychainProxy new];
+    });
+    
+    return sharedCKP;
+}
+
+-(id _Nullable) init {
+    if ((self = [super init])) {
+        _registrationFileName = (NSURL *)CFBridgingRelease(SecCopyURLForFileInPreferencesDirectory(kRegistrationFileName));
+        _proxyID = [UbiqitousKVSProxy withAccount: [CKDSecuritydAccount securitydAccount]
+                                          store: [CKDKVSStore kvsInterface]
+                                    lockMonitor: [CKDAKSLockMonitor monitor]
+                                    persistence: _registrationFileName];
+        
+        _listener = xpc_connection_create_mach_service(kCKPServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+        xpc_connection_set_finalizer_f(_listener, finalize_connection);
+        xpc_connection_set_event_handler(_listener, ^(xpc_object_t object){ cloudkeychainproxy_event_handler(object); });
+
+        // It looks to me like there is insufficient locking to allow a request to come in on the XPC connection while doing the initial all items.
+        // Therefore I'm leaving the XPC connection suspended until that has time to process.
+        xpc_connection_resume(_listener);
+
+        (void)signal(SIGTERM, SIG_IGN);
+        _sigterm_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, _proxyID.ckdkvsproxy_queue);
+        dispatch_source_set_event_handler(_sigterm_source, ^{
+            secnotice(PROXYXPCSCOPE, "exiting due to SIGTERM");
+            xpc_transaction_exit_clean();
+        });
+        dispatch_activate(_sigterm_source);
+    }
+    return self;
+}
+
+
+- (void) describeXPCObject: (char *) prefix withObject: (xpc_object_t) object {
+    if(object) {
         char *desc = xpc_copy_description(object);
-        secdebug(PROXYXPCSCOPE, "%s%s\n", prefix, desc);
+        secinfo(PROXYXPCSCOPE, "%s%s", prefix, desc);
         free(desc);
+    } else {
+        secinfo(PROXYXPCSCOPE, "%s<NULL>", prefix);
     }
-    else
-        secdebug(PROXYXPCSCOPE, "%s<NULL>\n", prefix);
-
-//#endif
 }
 
-static NSObject *CreateNSObjectForCFXPCObjectFromKey(xpc_object_t xdict, const char * _Nonnull key)
-{
+- (NSObject *) CreateNSObjectForCFXPCObjectFromKey: (xpc_object_t) xdict withKey: (const char * _Nonnull) key {
     xpc_object_t xObj = xpc_dictionary_get_value(xdict, key);
-
     if (!xObj) {
         return nil;
     }
-
     return (__bridge_transfer NSObject *)(_CFXPCCreateCFObjectFromXPCObject(xObj));
 }
 
-static NSArray<NSString*> *CreateArrayOfStringsForCFXPCObjectFromKey(xpc_object_t xdict, const char * _Nonnull key) {
-    NSObject * possibleArray = CreateNSObjectForCFXPCObjectFromKey(xdict, key);
+- (NSArray<NSString*> *) CreateArrayOfStringsForCFXPCObjectFromKey: (xpc_object_t) xdict withKey: (const char * _Nonnull) key {
+    NSObject * possibleArray = [self CreateNSObjectForCFXPCObjectFromKey: xdict withKey: key];
 
-    if (![possibleArray isNSArray__])
+    if (![possibleArray isNSArray__]) {
         return nil;
-
+    }
+    
     __block bool onlyStrings = true;
     [(NSArray*) possibleArray enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
         if (![obj isNSString__]) {
@@ -127,208 +204,187 @@ static NSArray<NSString*> *CreateArrayOfStringsForCFXPCObjectFromKey(xpc_object_
     return onlyStrings ? (NSArray<NSString*>*) possibleArray : nil;
 }
 
-static CFStringRef kRegistrationFileName = CFSTR("com.apple.security.cloudkeychainproxy3.keysToRegister.plist");
-
-static UbiqitousKVSProxy *SharedProxy(void) {
-    static UbiqitousKVSProxy *sProxy = NULL;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        sProxy = [UbiqitousKVSProxy withAccount: [CKDSecuritydAccount securitydAccount]
-                                          store: [CKDKVSStore kvsInterface]
-                                    lockMonitor: [CKDAKSLockMonitor monitor]
-                                    persistence: (NSURL *)CFBridgingRelease(SecCopyURLForFileInPreferencesDirectory(kRegistrationFileName))];
-    });
-
-    return sProxy;
-}
-
-static void sendAckResponse(const xpc_connection_t peer, xpc_object_t event) {
+- (void)  sendAckResponse: (const xpc_connection_t) peer forEvent: (xpc_object_t) event {
     xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
-    if (replyMessage)   // Caller wanted an ACK, so give one
-    {
+    if (replyMessage) {  // Caller wanted an ACK, so give one
         xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
         xpc_connection_send_message(peer, replyMessage);
     }
 }
 
-static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event)
-{
+- (void) cloudkeychainproxy_peer_dictionary_handler: (const xpc_connection_t) peer forEvent: (xpc_object_t) event {
     bool result = false;
     int err = 0;
 
-    require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY");
+    @autoreleasepool {
 
-    const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation);
-    require_action(operation, xit, result = false);
+        require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY");
 
-    // Check protocol version
-    uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion);
-    secdebug(PROXYXPCSCOPE, "Reply version: %lld\n", version);
-    require_action(version == kCKDXPCVersion, xit, result = false);
+        const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation);
+        require_action(operation, xit, result = false);
 
-    // Operations
-    secdebug(PROXYXPCSCOPE, "Handling %s operation", operation);
+        // Check protocol version
+        uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion);
+        secinfo(PROXYXPCSCOPE, "Reply version: %lld", version);
+        require_action(version == kCKDXPCVersion, xit, result = false);
 
+        // Operations
+        secinfo(PROXYXPCSCOPE, "Handling %s operation", operation);
 
-    if (!strcmp(operation, kOperationPUTDictionary))
-    {
-        operation_put_dictionary(event);
-        sendAckResponse(peer, event);
-    }
-    else if (!strcmp(operation, kOperationGETv2))
-    {
-        operation_get_v2(peer, event);
-        // operationg_get_v2 sends the response
-    }
-    else if (!strcmp(operation, kOperationClearStore))
-    {
-        [SharedProxy() clearStore];
-        sendAckResponse(peer, event);
-    }
-    else if (!strcmp(operation, kOperationSynchronize))
-    {
-        [SharedProxy() synchronizeStore];
-        sendAckResponse(peer, event);
-    }
-    else if (!strcmp(operation, kOperationSynchronizeAndWait))
-    {
-        xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
-        secnotice(XPROXYSCOPE, "%s XPC request: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
-        
-        [SharedProxy() waitForSynchronization:^(__unused NSDictionary *values, NSError *error)
-         {
-             secnotice(PROXYXPCSCOPE, "%s Result from [Proxy waitForSynchronization:]: %@", kWAIT2MINID, error);
 
-             if (replyMessage)   // Caller wanted an ACK, so give one
+        if (!strcmp(operation, kOperationPUTDictionary))
+        {
+            [self operation_put_dictionary: event];
+            [self sendAckResponse: peer forEvent: event];
+        }
+        else if (!strcmp(operation, kOperationGETv2))
+        {
+            [self operation_get_v2: peer forEvent: event];
+            // operationg_get_v2 sends the response
+        }
+        else if (!strcmp(operation, kOperationClearStore))
+        {
+            [_proxyID clearStore];
+            [self sendAckResponse: peer forEvent: event];
+        }
+        else if (!strcmp(operation, kOperationSynchronize))
+        {
+            [_proxyID synchronizeStore];
+            [self sendAckResponse: peer forEvent: event];
+        }
+        else if (!strcmp(operation, kOperationSynchronizeAndWait))
+        {
+            xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
+            secnotice(XPROXYSCOPE, "%s XPC request: %s", kWAIT2MINID, kOperationSynchronizeAndWait);
+            
+            [_proxyID waitForSynchronization:^(__unused NSDictionary *values, NSError *error)
              {
-                 if (error)
+                 secnotice(PROXYXPCSCOPE, "%s Result from [Proxy waitForSynchronization:]: %@", kWAIT2MINID, error);
+
+                 if (replyMessage)   // Caller wanted an ACK, so give one
                  {
-                     xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
-                     xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
-                 } else {
-                     xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
+                     if (error)
+                     {
+                         xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
+                         xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
+                     } else {
+                         xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK");
+                     }
+                     xpc_connection_send_message(peer, replyMessage);
                  }
-                 xpc_connection_send_message(peer, replyMessage);
-             }
-         }];
-    }
-    else if (!strcmp(operation, kOperationRegisterKeys))
-    {
-        xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue);
+             }];
+        }
+        else if (!strcmp(operation, kOperationRegisterKeys))
+        {
+            xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue);
 
-        xpc_object_t xKTRallkeys = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageAllKeys);
+            xpc_object_t xKTRallkeys = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageAllKeys);
 
-        NSString* accountUUID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyAccountUUID);
+            NSString* accountUUID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey:event withKey: kMessageKeyAccountUUID];
 
-        if (![accountUUID isKindOfClass:[NSString class]]) {
-            accountUUID = nil;
-        }
+            if (![accountUUID isKindOfClass:[NSString class]]) {
+                accountUUID = nil;
+            }
 
-        NSDictionary *KTRallkeys = (__bridge_transfer NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xKTRallkeys));
+            NSDictionary *KTRallkeys = (__bridge_transfer NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xKTRallkeys));
 
-        [SharedProxy() registerKeys: KTRallkeys forAccount: accountUUID];
-        sendAckResponse(peer, event);
+            [_proxyID registerKeys: KTRallkeys forAccount: accountUUID];
+            [self sendAckResponse: peer forEvent: event];
 
-        secdebug(PROXYXPCSCOPE, "RegisterKeys message sent");
-    }
-    else if (!strcmp(operation, kOperationRemoveKeys))
-    {
-        xpc_object_t xkeysToRemoveDict = xpc_dictionary_get_value(event, kMessageKeyValue);
-        
-        NSString* accountUUID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyAccountUUID);
-        
-        if (![accountUUID isKindOfClass:[NSString class]]) {
-            accountUUID = nil;
+            secinfo(PROXYXPCSCOPE, "RegisterKeys message sent");
         }
-        
-        NSArray *KTRallkeys = (__bridge_transfer NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xkeysToRemoveDict));
-        
-        [SharedProxy() removeKeys:KTRallkeys forAccount:accountUUID];
-        sendAckResponse(peer, event);
-        
-        secdebug(PROXYXPCSCOPE, "RemoveKeys message sent");
-    }
-    else if (!strcmp(operation, kOperationRequestSyncWithPeers))
-    {
+        else if (!strcmp(operation, kOperationRemoveKeys))
+        {
+            xpc_object_t xkeysToRemoveDict = xpc_dictionary_get_value(event, kMessageKeyValue);
+            
+            NSString* accountUUID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyAccountUUID];
+            
+            if (![accountUUID isKindOfClass:[NSString class]]) {
+                accountUUID = nil;
+            }
+            
+            NSArray *KTRallkeys = (__bridge_transfer NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xkeysToRemoveDict));
+            
+            [_proxyID removeKeys:KTRallkeys forAccount:accountUUID];
+            [self sendAckResponse: peer forEvent: event];
+
+            secinfo(PROXYXPCSCOPE, "RemoveKeys message sent");
+        }
+        else if (!strcmp(operation, kOperationRequestSyncWithPeers))
+        {
 
-        NSArray<NSString*> * peerIDs = CreateArrayOfStringsForCFXPCObjectFromKey(event, kMessageKeyPeerIDList);
-        NSArray<NSString*> * backupPeerIDs = CreateArrayOfStringsForCFXPCObjectFromKey(event, kMesssgeKeyBackupPeerIDList);
+            NSArray<NSString*> * peerIDs = [self CreateArrayOfStringsForCFXPCObjectFromKey: event withKey: kMessageKeyPeerIDList];
+            NSArray<NSString*> * backupPeerIDs = [self CreateArrayOfStringsForCFXPCObjectFromKey: event withKey: kMesssgeKeyBackupPeerIDList];
 
-        require_action(peerIDs && backupPeerIDs, xit, (secnotice(XPROXYSCOPE, "Bad call to sync with peers"), result = false));
+            require_action(peerIDs && backupPeerIDs, xit, (secnotice(XPROXYSCOPE, "Bad call to sync with peers"), result = false));
 
-        [SharedProxy() requestSyncWithPeerIDs: peerIDs backupPeerIDs: backupPeerIDs];
-        sendAckResponse(peer, event);
+            [_proxyID requestSyncWithPeerIDs: peerIDs backupPeerIDs: backupPeerIDs];
+            [self sendAckResponse: peer forEvent: event];
 
-        secdebug(PROXYXPCSCOPE, "RequestSyncWithAllPeers reply sent");
-    }
-    else if (!strcmp(operation, kOperationHasPendingSyncWithPeer)) {
-        NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID);
+            secinfo(PROXYXPCSCOPE, "RequestSyncWithAllPeers reply sent");
+        }
+        else if (!strcmp(operation, kOperationHasPendingSyncWithPeer)) {
+            NSString *peerID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyPeerID];
 
-        BOOL hasPending = [SharedProxy() hasSyncPendingFor: peerID];
+            BOOL hasPending = [_proxyID hasSyncPendingFor: peerID];
 
-        xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
-        if (replyMessage)
-        {
-            xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
-            xpc_connection_send_message(peer, replyMessage);
-            secdebug(PROXYXPCSCOPE, "HasPendingSyncWithPeer reply sent");
+            xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
+            if (replyMessage)
+            {
+                xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
+                xpc_connection_send_message(peer, replyMessage);
+                secinfo(PROXYXPCSCOPE, "HasPendingSyncWithPeer reply sent");
+            }
         }
-    }
-    else if (!strcmp(operation, kOperationHasPendingKey)) {
-        NSString *peerID = (NSString*) CreateNSObjectForCFXPCObjectFromKey(event, kMessageKeyPeerID);
+        else if (!strcmp(operation, kOperationHasPendingKey)) {
+            NSString *peerID = (NSString*) [self CreateNSObjectForCFXPCObjectFromKey: event withKey: kMessageKeyPeerID];
 
-        BOOL hasPending = [SharedProxy() hasPendingKey: peerID];
+            BOOL hasPending = [_proxyID hasPendingKey: peerID];
 
-        xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
-        if (replyMessage)
+            xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
+            if (replyMessage)
+            {
+                xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
+                xpc_connection_send_message(peer, replyMessage);
+                secinfo(PROXYXPCSCOPE, "HasIncomingMessageFromPeer reply sent");
+            }
+        }
+        else if (!strcmp(operation, kOperationRequestEnsurePeerRegistration))
         {
-            xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, hasPending);
-            xpc_connection_send_message(peer, replyMessage);
-            secdebug(PROXYXPCSCOPE, "HasIncomingMessageFromPeer reply sent");
+            [_proxyID requestEnsurePeerRegistration];
+            [self sendAckResponse: peer forEvent: event];
+            secinfo(PROXYXPCSCOPE, "RequestEnsurePeerRegistration reply sent");
         }
-    }
-    else if (!strcmp(operation, kOperationRequestEnsurePeerRegistration))
-    {
-        [SharedProxy() requestEnsurePeerRegistration];
-        sendAckResponse(peer, event);
-        secdebug(PROXYXPCSCOPE, "RequestEnsurePeerRegistration reply sent");
-    }
-    else if (!strcmp(operation, kOperationFlush))
-    {
-        [SharedProxy() doAfterFlush:^{
-            sendAckResponse(peer, event);
-            secdebug(PROXYXPCSCOPE, "flush reply sent");
-        }];
-    }
-    else if (!strcmp(operation, kOperationPerfCounters)) {
-        [SharedProxy() perfCounters:^(NSDictionary *counters){
-            xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
-            xpc_object_t object = _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)counters);
-            xpc_dictionary_set_value(replyMessage, kMessageKeyValue, object);
-            xpc_connection_send_message(peer, replyMessage);
-        }];
-    }
-    else
-    {
-        char *description = xpc_copy_description(event);
-        secdebug(PROXYXPCSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description);
-        free(description);
-    }
-    result = true;
+        else if (!strcmp(operation, kOperationFlush))
+        {
+            [_proxyID doAfterFlush:^{
+                [self sendAckResponse: peer forEvent: event];
+                secinfo(PROXYXPCSCOPE, "flush reply sent");
+            }];
+        }
+        else if (!strcmp(operation, kOperationPerfCounters)) {
+            [_proxyID perfCounters:^(NSDictionary *counters){
+                xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
+                xpc_object_t object = _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)counters);
+                xpc_dictionary_set_value(replyMessage, kMessageKeyValue, object);
+                xpc_connection_send_message(peer, replyMessage);
+            }];
+        }
+        else
+        {
+            char *description = xpc_copy_description(event);
+            secinfo(PROXYXPCSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description);
+            free(description);
+        }
+        result = true;
 xit:
-    if (!result)
-        describeXPCObject("handle_operation fail: ", event);
-}
-
-void finalize_connection(void *not_used)
-{
-    secdebug(PROXYXPCSCOPE, "finalize_connection");
-    [SharedProxy() synchronizeStore];
-       xpc_transaction_end();
+        if (!result) {
+            [self describeXPCObject: "handle_operation fail: " withObject: event];
+        }
+    }
 }
 
-static bool operation_put_dictionary(xpc_object_t event)
-{
+- (bool) operation_put_dictionary: (xpc_object_t) event {
     // PUT a set of objects into the KVS store. Return false if error
     xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue);
     if (!xvalue) {
@@ -337,29 +393,28 @@ static bool operation_put_dictionary(xpc_object_t event)
 
     NSObject* object = (__bridge_transfer NSObject*) _CFXPCCreateCFObjectFromXPCObject(xvalue);
     if (![object isKindOfClass:[NSDictionary<NSString*, NSObject*> class]]) {
-        describeXPCObject("operation_put_dictionary unable to convert to CF: ", xvalue);
+        [self describeXPCObject: "operation_put_dictionary unable to convert to CF: " withObject: xvalue];
         return false;
     }
 
-    [SharedProxy() setObjectsFromDictionary: (NSDictionary<NSString*, NSObject*> *)object];
+    [_proxyID setObjectsFromDictionary: (NSDictionary<NSString*, NSObject*> *)object];
 
     return true;
 }
 
-static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
-{
+- (bool) operation_get_v2: (xpc_connection_t) peer forEvent: (xpc_object_t) event {
     // GET a set of objects from the KVS store. Return false if error
     xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
     if (!replyMessage)
     {
-        secdebug(PROXYXPCSCOPE, "can't create replyMessage");
+        secinfo(PROXYXPCSCOPE, "can't create replyMessage");
         assert(false);   //must have a reply handler
         return false;
     }
     xpc_object_t returnedValues = xpc_dictionary_create(NULL, NULL, 0);
     if (!returnedValues)
     {
-        secdebug(PROXYXPCSCOPE, "can't create returnedValues");
+        secinfo(PROXYXPCSCOPE, "can't create returnedValues");
         assert(false);   // must have a spot for the returned values
         return false;
     }
@@ -367,18 +422,18 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
     xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue);
     if (!xvalue)
     {
-        secdebug(PROXYXPCSCOPE, "missing \"value\" key");
+        secinfo(PROXYXPCSCOPE, "missing \"value\" key");
         return false;
     }
     
     xpc_object_t xkeystoget = xpc_dictionary_get_value(xvalue, kMessageKeyKeysToGet);
     if (xkeystoget)
     {
-        secdebug(PROXYXPCSCOPE, "got xkeystoget");
+        secinfo(PROXYXPCSCOPE, "got xkeystoget");
         CFTypeRef keystoget = _CFXPCCreateCFObjectFromXPCObject(xkeystoget);
         if (!keystoget || (CFGetTypeID(keystoget)!=CFArrayGetTypeID()))     // not "getAll", this is an error of some kind
         {
-            secdebug(PROXYXPCSCOPE, "can't convert keystoget or is not an array");
+            secinfo(PROXYXPCSCOPE, "can't convert keystoget or is not an array");
             CFReleaseSafe(keystoget);
             return false;
         }
@@ -386,16 +441,16 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
         [(__bridge NSArray *)keystoget enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL *stop)
         {
             NSString *key = (NSString *)obj;
-            id object = [SharedProxy() objectForKey:key];
-            secdebug(PROXYXPCSCOPE, "get: key: %@, object: %@", key, object);
+            id object = [_proxyID objectForKey:key];
+            secinfo(PROXYXPCSCOPE, "get: key: %@, object: %@", key, object);
             xpc_object_t xobject = object ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)object) : xpc_null_create();
             xpc_dictionary_set_value(returnedValues, [key UTF8String], xobject);
         }];
     }
     else    // get all values from kvs
     {
-        secdebug(PROXYXPCSCOPE, "get all values from kvs");
-        NSDictionary *all = [SharedProxy() copyAsDictionary];
+        secinfo(PROXYXPCSCOPE, "get all values from kvs");
+        NSDictionary *all = [_proxyID copyAsDictionary];
         [all enumerateKeysAndObjectsUsingBlock: ^ (id key, id obj, BOOL *stop)
         {
             xpc_object_t xobject = obj ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)obj) : xpc_null_create();
@@ -410,53 +465,23 @@ static bool operation_get_v2(xpc_connection_t peer, xpc_object_t event)
     return true;
 }
 
-static void cloudkeychainproxy_event_handler(xpc_connection_t peer)
-{
-    if (xpc_get_type(peer) != XPC_TYPE_CONNECTION)
-    {
-        secdebug(PROXYXPCSCOPE, "expected XPC_TYPE_CONNECTION");
-        return;
-    }
-
-    xpc_object_t ent = xpc_connection_copy_entitlement_value(peer, "com.apple.CloudKeychainProxy.client");
-    if (ent == NULL || xpc_get_type(ent) != XPC_TYPE_BOOL || xpc_bool_get_value(ent) != true) {
-        secnotice(PROXYXPCSCOPE, "cloudkeychainproxy_event_handler: rejected client %d", xpc_connection_get_pid(peer));
-        xpc_connection_cancel(peer);
-        return;
-    }
 
-    xpc_connection_set_target_queue(peer, [SharedProxy() ckdkvsproxy_queue]);
-    xpc_connection_set_event_handler(peer, ^(xpc_object_t event)
-    {
-        // We could handle other peer events (e.g.) disconnects,
-        // but we don't keep per-client state so there is no need.
-        if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
-            cloudkeychainproxy_peer_dictionary_handler(peer, event);
-        }
-       });
-       
-       // This will tell the connection to begin listening for events. If you
-       // have some other initialization that must be done asynchronously, then
-       // you can defer this call until after that initialization is done.
-       xpc_connection_resume(peer);
-}
+@end
 
-static void diagnostics(int argc, const char *argv[])
-{
-    @autoreleasepool
-    {
-        NSDictionary *all = [SharedProxy() copyAsDictionary];
+static void diagnostics(int argc, const char *argv[]) {
+    @autoreleasepool {
+        NSDictionary *all = [[CloudKeychainProxy sharedObject].proxyID copyAsDictionary];
         NSLog(@"All: %@",all);
     }
 }
 
-int ckdproxymain(int argc, const char *argv[])
-{
-    secdebug(PROXYXPCSCOPE, "Starting CloudKeychainProxy");
+
+
+int main(int argc, const char *argv[]) {
+    secinfo(PROXYXPCSCOPE, "Starting CloudKeychainProxy");
     char *wait4debugger = getenv("WAIT4DEBUGGER");
 
-    if (wait4debugger && !strcasecmp("YES", wait4debugger))
-    {
+    if (wait4debugger && !strcasecmp("YES", wait4debugger)) {
         syslog(LOG_ERR, "Waiting for debugger");
         kill(getpid(), SIGTSTP);
     }
@@ -465,31 +490,18 @@ int ckdproxymain(int argc, const char *argv[])
         diagnostics(argc, argv);
         return 0;
     }
-
-    UbiqitousKVSProxy* proxyID = SharedProxy();
-
-    if (proxyID) {  // nothing bad happened when initializing
-        xpc_connection_t listener = xpc_connection_create_mach_service(kCKPServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
-        xpc_connection_set_event_handler(listener, ^(xpc_object_t object){ cloudkeychainproxy_event_handler(object); });
-
-        // It looks to me like there is insufficient locking to allow a request to come in on the XPC connection while doing the initial all items.
-        // Therefore I'm leaving the XPC connection suspended until that has time to process.
-        xpc_connection_resume(listener);
-
-        @autoreleasepool
-        {
-            secdebug(PROXYXPCSCOPE, "Starting mainRunLoop");
-            NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
-            [runLoop run];
-        }
+    
+    CloudKeychainProxy *ckp = nil;
+    @autoreleasepool {
+        ckp = [CloudKeychainProxy sharedObject];
     }
-
-    secdebug(PROXYXPCSCOPE, "Exiting CloudKeychainProxy");
+    
+    if (ckp) {  // nothing bad happened when initializing
+        secinfo(PROXYXPCSCOPE, "Starting mainRunLoop");
+        NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
+        [runLoop run];
+    }
+    secinfo(PROXYXPCSCOPE, "Exiting CloudKeychainProxy");
 
     return EXIT_FAILURE;
 }
-
-int main(int argc, const char *argv[])
-{
-    return ckdproxymain(argc, argv);
-}
index 3bc684cd9998ba206df1270c2e13d6317554d464..bd17f5a6f521dcad90af069e1189638b574615cb 100644 (file)
@@ -162,29 +162,28 @@ static NSString* KCDSEpoch= @"epoch";
                                               freeWhenDone: false];
     });
 
-    self = [super init];
-
-    self.asSender = sender;
-    self.secret = sharedSecret;
-    self.send = malloc(ccgcm_context_size(ccaes_gcm_encrypt_mode()));
-    self.receive = malloc(ccgcm_context_size(ccaes_gcm_decrypt_mode()));
-    self.context = context;
-
-    _pairingUUID = pairingUUID;
-    _piggybackingVersion = piggybackingVersion;
-    _epoch = epoch;
-
-    if (self.send == nil || self.receive == nil) {
-        return nil;
+    if ((self = [super init])) {
+        self.asSender = sender;
+        self.secret = sharedSecret;
+        self.send = malloc(ccgcm_context_size(ccaes_gcm_encrypt_mode()));
+        self.receive = malloc(ccgcm_context_size(ccaes_gcm_decrypt_mode()));
+        self.context = context;
+
+        _pairingUUID = pairingUUID;
+        _piggybackingVersion = piggybackingVersion;
+        _epoch = epoch;
+
+        if (self.send == nil || self.receive == nil) {
+            return nil;
+        }
+
+        derive_and_init(ccaes_gcm_encrypt_mode(),
+                        self.send, self.secret,
+                        sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
+        derive_and_init(ccaes_gcm_decrypt_mode(),
+                        self.receive, self.secret,
+                        !sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
     }
-
-    derive_and_init(ccaes_gcm_encrypt_mode(),
-                    self.send, self.secret,
-                    sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
-    derive_and_init(ccaes_gcm_decrypt_mode(),
-                    self.receive, self.secret,
-                    !sender ? kdfInfoSendToReceive : kdfInfoReceiveToSend);
-
     return self;
 }
 
index 1f9d18746ed3a6418fd621bca6363ee1e092a6ef..9b140fe593d3469937634e7ffb1c3cd441e61ff2 100644 (file)
@@ -18,6 +18,8 @@ typedef enum {
     kUnexpectedMessage,
     kInternalError,
     kDERUnknownVersion,
+    kProcessApplicationFailure,
+    kUnsupportedTrustPlatform,
 } KCJoiningError;
 
 @interface NSError(KCJoiningError)
index 931144a8e065ca5d519dc1b7364305146cfba666..8e865fdfbe0572c36b949ff99fff912d9673367a 100644 (file)
@@ -20,7 +20,6 @@
 #include <corecrypto/ccsha2.h>
 #include <corecrypto/ccdh_gp.h>
 #include <utilities/debugging.h>
-#include <CommonCrypto/CommonRandomSPI.h>
 #include <notify.h>
 
 #if OCTAGON
@@ -30,6 +29,9 @@
 #import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
+#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
+#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
+#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
 #import "keychain/ot/proto/generated_source/OTPairingMessage.h"
 #endif
 
@@ -103,39 +105,39 @@ typedef enum {
                                             dsid: (uint64_t) dsid
                                              rng: (struct ccrng_state *)rng
                                            error: (NSError**) error {
-    self = [super init];
+    if ((self = [super init])) {
 
-    secnotice("accepting", "initWithSecretDelegate");
+        secnotice("accepting", "initWithSecretDelegate");
 
-    NSString* name = [NSString stringWithFormat: @"%llu", dsid];
+        NSString* name = [NSString stringWithFormat: @"%llu", dsid];
 
-    self->_context = [[KCSRPServerContext alloc] initWithUser: name
-                                                     password: [secretDelegate secret]
-                                                   digestInfo: ccsha256_di()
-                                                        group: ccsrp_gp_rfc5054_3072()
-                                                 randomSource: rng];
-    self.secretDelegate = secretDelegate;
-    self.circleDelegate = circleDelegate;
-    self->_state = kExpectingA;
-    self->_dsid = dsid;
-    self->_piggy_uuid = nil;
-    self->_defaults = [NSMutableDictionary dictionary];
+        self->_context = [[KCSRPServerContext alloc] initWithUser: name
+                                                         password: [secretDelegate secret]
+                                                       digestInfo: ccsha256_di()
+                                                            group: ccsrp_gp_rfc5054_3072()
+                                                     randomSource: rng];
+        self.secretDelegate = secretDelegate;
+        self.circleDelegate = circleDelegate;
+        self->_state = kExpectingA;
+        self->_dsid = dsid;
+        self->_piggy_uuid = nil;
+        self->_defaults = [NSMutableDictionary dictionary];
 
 #if OCTAGON
-    self->_otControl = [OTControl controlObject:true error:error];
-    self->_piggy_version = KCJoiningOctagonPiggybackingEnabled()? kPiggyV2 : kPiggyV1;
-    self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
-                                                                       uniqueDeviceID:@"acceptor-deviceid"
-                                                                       uniqueClientID:@"requester-deviceid"
-                                                                          pairingUUID:[[NSUUID UUID] UUIDString]
-                                                                        containerName:nil
-                                                                            contextID:OTDefaultContext
-                                                                                epoch:0
-                                                                          isInitiator:false];
+        self->_otControl = [OTControl controlObject:true error:error];
+        self->_piggy_version = KCJoiningOctagonPiggybackingEnabled()? kPiggyV2 : kPiggyV1;
+        self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
+                                                                           uniqueDeviceID:@"acceptor-deviceid"
+                                                                           uniqueClientID:@"requester-deviceid"
+                                                                              pairingUUID:[[NSUUID UUID] UUIDString]
+                                                                            containerName:nil
+                                                                                contextID:OTDefaultContext
+                                                                                    epoch:0
+                                                                              isInitiator:false];
 #else
-    self->_piggy_version = kPiggyV1;
+        self->_piggy_version = kPiggyV1;
 #endif
-    
+    }    
     return self;
 }
 
@@ -243,8 +245,14 @@ typedef enum {
                 captureError = epochError;
             }else{
                 OTPairingMessage* responseMessage = [[OTPairingMessage alloc] init];
+                responseMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
+                responseMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
+
                 responseMessage.epoch = [[OTSponsorToApplicantRound1M2 alloc] init];
                 responseMessage.epoch.epoch = epoch;
+                
+                responseMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+                responseMessage.supportsOctagon.supported = OTSupportType_supported;
                 next = responseMessage.data;
             }
             dispatch_semaphore_signal(sema);
@@ -405,7 +413,7 @@ typedef enum {
 
 - (NSData*) createTLKRequestResponse: (NSError**) error {
     NSError* localError = NULL;
-    NSData* initialSync = [self.circleDelegate circleGetInitialSyncViews:kSOSInitialSyncFlagTLKs error:&localError];
+    NSData* initialSync = [self.circleDelegate circleGetInitialSyncViews:kSOSInitialSyncFlagTLKsRequestOnly error:&localError];
     if (!initialSync) {
         secnotice("joining", "Failed to get initial sync view: %@", localError);
         if ( error!=NULL && localError != NULL )
@@ -429,6 +437,26 @@ typedef enum {
                                         error:error] der];
 }
 
+
+- (BOOL)shouldProcessSOSApplication:(KCJoiningMessage*)message pairingMessage:(OTPairingMessage*)pairingMessage
+{
+    BOOL shouldProcess = YES;
+
+    if (OctagonPlatformSupportsSOS() == NO) {
+        secnotice("joining", "platform does not support SOS");
+        shouldProcess = NO;
+    } else if (message.secondData == nil) {
+        secnotice("joining", "message does not contain SOS data");
+        shouldProcess = NO;
+    } else if (pairingMessage.hasSupportsSOS && pairingMessage.supportsSOS.supported == OTSupportType_not_supported) {
+        secnotice("joining", "requester explicitly does not support SOS");
+        shouldProcess = NO;
+    }
+
+    return shouldProcess;
+}
+
+
 - (NSData*) processApplication: (KCJoiningMessage*) message error:(NSError**) error {
     
     if ([message type] == kTLKRequest) {
@@ -473,9 +501,14 @@ typedef enum {
                 localError = err;
             }else{
                 OTPairingMessage *pairingResponse = [[OTPairingMessage alloc] init];
+                pairingResponse.supportsSOS = [[OTSupportSOSMessage alloc] init];
+                pairingResponse.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
                 pairingResponse.voucher = [[OTSponsorToApplicantRound2M2 alloc] init];
                 pairingResponse.voucher.voucher = voucher;
                 pairingResponse.voucher.voucherSignature = voucherSig;
+
+                pairingMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+                pairingMessage.supportsOctagon.supported = OTSupportType_supported;
                 next = pairingResponse.data;
             }
             dispatch_semaphore_signal(sema);
@@ -493,17 +526,19 @@ typedef enum {
         }
 
         NSData* encryptedOutgoing = nil;
-        if (OctagonPlatformSupportsSOS() && message.secondData) {
+        if ([self shouldProcessSOSApplication:message pairingMessage:pairingMessage]) {
             secnotice("joining", "doing SOS processSOSApplication");
-            //note we are stuffing SOS into the payload "secondData"
             encryptedOutgoing = [self processSOSApplication: message.secondData error:error];
-        } else {
-            secnotice("joining", "no platform support processSOSApplication, peer sent data: %s",
-                      message.secondData ? "yes" : "no");
+            if (encryptedOutgoing == nil) {
+                secerror("joining: failed to process SOS application: %@", error && *error ? *error : nil);
+                KCJoiningErrorCreate(kProcessApplicationFailure, error, @"message failed to process application");
+                return nil;
+            }
         }
 
         self->_state = kAcceptDone;
 
+        //note we are stuffing SOS into the payload
         return [[KCJoiningMessage messageWithType:kCircleBlob
                                              data:next
                                           payload:encryptedOutgoing
index 5dc66c706f896b06ae2dd20e064f1329e66e35be..97f57d80ecb247c61b35f1cf615923a4f0a6f217 100644 (file)
@@ -111,7 +111,7 @@ typedef enum {
 
 + (nullable instancetype) messageWithType: (KCJoiningMessageType) type
                                      data: (NSData*) firstData
-                                  payload: (NSData*) secondData
+                                  payload: (nullable NSData*) secondData
                                     error: (NSError**) error;
 
 
index 2eb0c94beb23b391339606bfd60380d3ac49fdc3..2fff03ee8331984a61770dfde8d7f24f4e37b633 100644 (file)
 
 + (nullable instancetype) messageWithType: (KCJoiningMessageType) type
                                      data: (NSData*) firstData
-                               secondData: (NSData*) secondData
+                               secondData: (nullable NSData*) secondData
                                     error: (NSError**) error {
     return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error];
 }
 
 + (nullable instancetype) messageWithType: (KCJoiningMessageType) type
                                      data: (NSData*) firstData
-                                  payload: (NSData*) secondData
+                                  payload: (nullable NSData*) secondData
                                     error: (NSError**) error {
     return [[KCJoiningMessage alloc] initWithType:type data:firstData payload:secondData error:error];
     
 
 - (nullable instancetype) initWithDER: (NSData*) message
                        error: (NSError**) error {
-    self = [super init];
-
-    self->_der = [NSData dataWithData: message];
-
+    if ((self = [super init])) {
+        self->_der = [NSData dataWithData: message];
+    }
     return [self inflatePartsOfEncoding: error] ? self : nil;
 }
 
                          data: (NSData*) firstData
                       payload: (nullable NSData*) secondData
                         error: (NSError**) error {
-    self = [super init];
-
-    self->_der = [KCJoiningMessage encodeToDERType:type
-                                              data:firstData
-                                           payload:secondData
-                                             error:error];
-    if (self->_der == nil) return nil;
-
+    if ((self = [super init])) {
+        self->_der = [KCJoiningMessage encodeToDERType:type
+                                                  data:firstData
+                                               payload:secondData
+                                                 error:error];
+        if (self->_der == nil) return nil;
+    }
     return [self inflatePartsOfEncoding: error] ? self : nil;
 }
 
index a8778b2935352ffb87655caebd6954eb1e2e7e70..e0fffb47cf15420569bca45ef3495e80cb0dc27f 100644 (file)
@@ -26,6 +26,9 @@
 #import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
+#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
+#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
+#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
 #import "keychain/ot/proto/generated_source/OTPairingMessage.h"
 #endif
 #import <KeychainCircle/NSError+KCCreationHelpers.h>
@@ -102,6 +105,7 @@ typedef enum {
     return [self->_session encrypt:initialMessage.data error:error];
 }
 
+
 - (nullable NSData*) initialMessage: (NSError**) error {
     secnotice("joining", "joining: KCJoiningRequestCircleSession initialMessage called");
 
@@ -129,6 +133,8 @@ typedef enum {
                 localError = err;
             } else{
                 OTPairingMessage *pairingMessage = [[OTPairingMessage alloc]init];
+                pairingMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
+                pairingMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
                 OTApplicantToSponsorRound2M1 *prepareMessage = [[OTApplicantToSponsorRound2M1 alloc]init];
                 prepareMessage.peerID = peerID;
                 prepareMessage.permanentInfo = permanentInfo;
@@ -137,6 +143,10 @@ typedef enum {
                 prepareMessage.stableInfoSig = stableInfoSig;
 
                 pairingMessage.prepare = prepareMessage;
+
+                pairingMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+                pairingMessage.supportsOctagon.supported = OTSupportType_supported;
+
                 next = pairingMessage.data;
             }
             dispatch_semaphore_signal(sema);
@@ -162,7 +172,7 @@ typedef enum {
         self->_state = kExpectingCircleBlob;
         NSData *encryptedInitialMessage = [self encryptedInitialMessage:next error:error];
 
-        return [[KCJoiningMessage messageWithType: kPeerInfo
+        return [[KCJoiningMessage messageWithType:kPeerInfo
                                              data:encryptedInitialMessage
                                           payload:encryptedPi
                                             error:error] der];
@@ -180,13 +190,34 @@ typedef enum {
 
 }
 
-- (void) attemptSosUpgrade
+- (void) waitForOctagonUpgrade
 {
-    [self.otControl attemptSosUpgrade:self.joiningConfiguration.containerName context:self.joiningConfiguration.contextID reply:^(NSError *error) {
+#if OCTAGON
+    [self.otControl waitForOctagonUpgrade:self.joiningConfiguration.containerName context:self.joiningConfiguration.contextID reply:^(NSError *error) {
         if(error){
             secerror("pairing: failed to upgrade initiator into Octagon: %@", error);
         }
     }];
+#endif
+}
+
+- (BOOL)shouldJoinSOS:(KCJoiningMessage*)message pairingMessage:(OTPairingMessage*)pairingMessage
+{
+
+    BOOL shouldJoin = YES;
+
+    if (OctagonPlatformSupportsSOS() == NO) {
+        secnotice("joining", "platform does not support SOS");
+        shouldJoin = NO;
+    } else if (message.secondData == nil) {
+        secnotice("joining", "message does not contain SOS data");
+        shouldJoin = NO;
+    } else if (pairingMessage.hasSupportsSOS && pairingMessage.supportsSOS.supported == OTSupportType_not_supported) {
+        secnotice("joining", "acceptor explicitly does not support SOS");
+        shouldJoin = NO;
+    }
+
+    return shouldJoin;
 }
 
 - (NSData*) handleCircleBlob: (KCJoiningMessage*) message error: (NSError**) error {
@@ -206,6 +237,7 @@ typedef enum {
             secerror("octagon: expected voucher! returning from piggybacking.");
             return nil;
         }
+
         OTSponsorToApplicantRound2M2 *voucher = pairingMessage.voucher;
 
         //handle voucher message then join octagon
@@ -228,16 +260,18 @@ typedef enum {
             return nil;
         }
 
-        if (OctagonPlatformSupportsSOS()) {
+        if ([self shouldJoinSOS:message pairingMessage:pairingMessage]) {
             secnotice("joining", "doing SOS processCircleJoinData");
             //note we are stuffing SOS into the payload "secondData"
             NSData* circleBlob = [self.session decryptAndVerify:message.secondData error:error];
-            if (circleBlob == nil) return nil;
-
-            if (![self.circleDelegate processCircleJoinData: circleBlob version:kPiggyV1 error:error])
+            if (circleBlob == nil) {
+                secnotice("joining", "decryptAndVerify failed: %@", error && *error ? *error : nil);
                 return nil;
-        } else {
-            secnotice("joining", "platform doesn't support SOS");
+            }
+            if (![self.circleDelegate processCircleJoinData: circleBlob version:kPiggyV1 error:error]){
+                secerror("joining: processCircleJoinData failed %@", error && *error ? *error : nil);
+                return nil;
+            }
         }
 
         self->_state = kRequestCircleDone;
@@ -257,10 +291,12 @@ typedef enum {
         return nil;
     } else {
         secnotice("joining", "joined the SOS circle!");
+#if OCTAGON
         if(OctagonIsEnabled()) {
             secnotice("joining", "kicking off SOS Upgrade into Octagon!");
-            [self attemptSosUpgrade];
+            [self waitForOctagonUpgrade];
         }
+#endif
     }
     self->_state = kRequestCircleDone;
 
@@ -311,27 +347,26 @@ typedef enum {
                                  error:(NSError**) error
 {
     secnotice("joining", "joining: KCJoiningRequestCircleSession initWithCircleDelegate called, uuid=%@", session.pairingUUID);
-    self = [super init];
-
-    self->_circleDelegate = circleDelegate;
-    self->_session = session;
-    self.state = kExpectingCircleBlob;
+    if ((self = [super init])) {
+        self->_circleDelegate = circleDelegate;
+        self->_session = session;
+        self.state = kExpectingCircleBlob;
 #if OCTAGON
-    self->_otControl = otcontrol;
-    self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
-                                                                       uniqueDeviceID:@"requester-id"
-                                                                       uniqueClientID:@"requester-id"
-                                                                          pairingUUID:session.pairingUUID
-                                                                        containerName:nil
-                                                                            contextID:OTDefaultContext
-                                                                                epoch:session.epoch
-                                                                          isInitiator:true];
-
-    self->_piggy_version = session.piggybackingVersion;
+        self->_otControl = otcontrol;
+        self->_joiningConfiguration = [[OTJoiningConfiguration alloc]initWithProtocolType:@"OctagonPiggybacking"
+                                                                           uniqueDeviceID:@"requester-id"
+                                                                           uniqueClientID:@"requester-id"
+                                                                              pairingUUID:session.pairingUUID
+                                                                            containerName:nil
+                                                                                contextID:OTDefaultContext
+                                                                                    epoch:session.epoch
+                                                                              isInitiator:true];
+
+        self->_piggy_version = session.piggybackingVersion;
 #else
-    self->_piggy_version = kPiggyV1;
+        self->_piggy_version = kPiggyV1;
 #endif
-
+    }
     return self;
 }
 
index 81b9aac8acf62b64b4ea8157e9b8133d9d2238d1..db52d630398e825aed1a819ae5dd77c3794278d4 100644 (file)
@@ -18,7 +18,6 @@
 #include <corecrypto/ccsha2.h>
 #include <corecrypto/ccdh_gp.h>
 #include <corecrypto/ccder.h>
-#include <CommonCrypto/CommonRandomSPI.h>
 #import <Security/SecureObjectSync/SOSTypes.h>
 #include <utilities/debugging.h>
 
@@ -33,6 +32,9 @@
 #import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
+#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
+#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
+#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
 #import "keychain/ot/proto/generated_source/OTPairingMessage.h"
 #endif
 #import <KeychainCircle/NSError+KCCreationHelpers.h>
@@ -70,9 +72,9 @@ bool KCJoiningOctagonPiggybackingEnabled() {
 @property (readwrite) uint64_t epoch;
 @property (readwrite) NSData* challenge;
 @property (readwrite) NSData* salt;
-#if OCTAGON
 @property (readwrite) NSString* sessionUUID;
 
+#if OCTAGON
 @property (nonatomic, strong) OTControl *otControl;
 #endif
 @property (nonatomic, strong) NSMutableDictionary *defaults;
@@ -212,15 +214,15 @@ bool KCJoiningOctagonPiggybackingEnabled() {
     }
 #if OCTAGON
     //handle octagon data if it exists
-    if(KCJoiningOctagonPiggybackingEnabled()){
+    if (KCJoiningOctagonPiggybackingEnabled()){
         self.piggy_version = [message secondData] ? kPiggyV2 : kPiggyV1;
 
         // The session may or may not exist at this point. If it doesn't, the version will be set at object creation time.
         self.session.piggybackingVersion = self.piggy_version;
 
-        if(self.piggy_version == kPiggyV2){
+        if (self.piggy_version == kPiggyV2){
             OTPairingMessage* pairingMessage = [[OTPairingMessage alloc]initWithData: [message secondData]];
-            if(pairingMessage.hasEpoch) {
+            if (pairingMessage.hasEpoch) {
                 secnotice("octagon", "received epoch message: %@", [pairingMessage.epoch dictionaryRepresentation]);
                 self.epoch = pairingMessage.epoch.epoch;
             }
@@ -340,31 +342,30 @@ bool KCJoiningOctagonPiggybackingEnabled() {
                                             rng: (struct ccrng_state *)rng
                                           error: (NSError**)error {
     secnotice("joining", "joining: initWithSecretDelegate called");
-    self = [super init];
-
-    self->_secretDelegate = secretDelegate;
-    self->_state = kExpectingB;
-    self->_dsid = dsid;
-    self->_defaults = [NSMutableDictionary dictionary];
+    if ((self = [super init])) {
+        self->_secretDelegate = secretDelegate;
+        self->_state = kExpectingB;
+        self->_dsid = dsid;
+        self->_defaults = [NSMutableDictionary dictionary];
 
 #if OCTAGON
-    self->_piggy_version = KCJoiningOctagonPiggybackingEnabled() ? kPiggyV2 : kPiggyV1;
-    self->_otControl = [OTControl controlObject:true error:error];
+        self->_piggy_version = KCJoiningOctagonPiggybackingEnabled() ? kPiggyV2 : kPiggyV1;
+        self->_otControl = [OTControl controlObject:true error:error];
 
-    _sessionUUID = [[NSUUID UUID] UUIDString];
+        _sessionUUID = [[NSUUID UUID] UUIDString];
 #else
-    self->_piggy_version = kPiggyV1;
+        self->_piggy_version = kPiggyV1;
 #endif
 
-    secnotice("joining", "joining: initWithSecretDelegate called, uuid=%@", self.sessionUUID);
+        secnotice("joining", "joining: initWithSecretDelegate called, uuid=%@", self.sessionUUID);
 
-    NSString* name = [NSString stringWithFormat: @"%llu", dsid];
+        NSString* name = [NSString stringWithFormat: @"%llu", dsid];
     
-    self->_context = [[KCSRPClientContext alloc] initWithUser: name
-                                                   digestInfo: ccsha256_di()
-                                                        group: ccsrp_gp_rfc5054_3072()
-                                                 randomSource: rng];
-
+        self->_context = [[KCSRPClientContext alloc] initWithUser: name
+                                                       digestInfo: ccsha256_di()
+                                                            group: ccsrp_gp_rfc5054_3072()
+                                                     randomSource: rng];
+    }
     return self;
 }
 
index 3d9d8a8ec4ed1222d47c05c166003cab165cca52..15bdf412bdb32fbffd36c464f61c60fa88623723 100644 (file)
@@ -50,14 +50,13 @@ static const NSStringEncoding srpStringEncoding = NSUTF8StringEncoding;
                         group: (ccsrp_const_gp_t) gp
                  randomSource: (struct ccrng_state *) rng
 {
-    self = [super init];
-    
-    self.context = malloc(ccsrp_sizeof_srp(di, gp));
-    ccsrp_ctx_init(self.context, di, gp);
-
-    self.user = user;
-    self.rng = rng;
+    if ((self = [super init])) {
+        self.context = malloc(ccsrp_sizeof_srp(di, gp));
+        ccsrp_ctx_init(self.context, di, gp);
 
+        self.user = user;
+        self.rng = rng;
+    }
     return self;
 }
 
@@ -179,15 +178,14 @@ static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NS
                    digestInfo: (const struct ccdigest_info *) di
                         group: (ccsrp_const_gp_t) gp
                  randomSource: (struct ccrng_state *) rng {
-    self = [super initWithUser: user
-                    digestInfo: di
-                         group: gp
-                  randomSource: rng];
-
-    if (![self resetWithPassword:password error:nil]) {
-        return nil;
+    if ((self = [super initWithUser: user
+                         digestInfo: di
+                              group: gp
+                       randomSource: rng])) {
+        if (![self resetWithPassword:password error:nil]) {
+            return nil;
+        }
     }
-
     return self;
 }
 
@@ -197,14 +195,13 @@ static bool ExactDataSizeRequirement(NSData* data, NSUInteger expectedLength, NS
                    digestInfo: (const struct ccdigest_info *) di
                         group: (ccsrp_const_gp_t) gp
                  randomSource: (struct ccrng_state *) rng {
-    self = [super initWithUser: user
-                    digestInfo: di
-                         group: gp
-                  randomSource: rng];
-
-    self.verifier = verifier;
-    self->_salt = salt;
-
+    if ((self = [super initWithUser: user
+                         digestInfo: di
+                              group: gp
+                       randomSource: rng])) {
+        self.verifier = verifier;
+        self->_salt = salt;
+    }
     return self;
 }
 
index 3627feae34c86598c4102e17db5c33de3c2f8766..60b5cf5e21e68a7c0cc09abb1ccb1b471e2976ea 100644 (file)
 #import <Security/SecureObjectSync/SOSTypes.h>
 #import <utilities/debugging.h>
 #import <utilities/SecCFWrappers.h>
+#import "utilities/SecCoreAnalytics.h"
 #import <ipc/securityd_client.h>
 #import "keychain/ot/OTManager.h"
 #import "keychain/ot/OctagonControlServer.h"
 #import "keychain/ot/OTControl.h"
 #import "keychain/ot/OctagonControlServer.h"
 #import "keychain/ot/OTJoiningConfiguration.h"
-#import "keychain/ot/proto/generated_source/OTPairingMessage.h"
 #import "keychain/ot/proto/generated_source/OTApplicantToSponsorRound2M1.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound2M2.h"
 #import "keychain/ot/proto/generated_source/OTSponsorToApplicantRound1M2.h"
+#import "keychain/ot/proto/generated_source/OTGlobalEnums.h"
+#import "keychain/ot/proto/generated_source/OTSupportSOSMessage.h"
+#import "keychain/ot/proto/generated_source/OTSupportOctagonMessage.h"
 #import "keychain/ot/proto/generated_source/OTPairingMessage.h"
 #include <notify.h>
 
@@ -29,7 +32,6 @@
 #import <MobileGestalt.h>
 #endif
 
-#import "utilities/SecADWrapper.h"
 
 KCPairingIntent_Type KCPairingIntent_Type_None = @"none";
 KCPairingIntent_Type KCPairingIntent_Type_SilentRepair = @"repair";
@@ -78,8 +80,7 @@ typedef void(^OTNextState)(NSData *inData, OTPairingInternalCompletion complete)
 
 - (nullable instancetype)initWithCoder:(NSCoder *)decoder
 {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _model = [decoder decodeObjectOfClass:[NSString class] forKey:@"model"];
         _modelVersion = [decoder decodeObjectOfClass:[NSString class] forKey:@"modelVersion"];
         _modelClass = [decoder decodeObjectOfClass:[NSString class] forKey:@"modelClass"];
@@ -256,9 +257,9 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
 
 //MARK: - Initiator
 
-- (void) attemptSosUpgrade
+- (void) waitForOctagonUpgrade
 {
-    [self.otControl attemptSosUpgrade:nil context:self.contextID reply:^(NSError *error) {
+    [self.otControl waitForOctagonUpgrade:nil context:self.contextID reply:^(NSError *error) {
         if(error){
             secerror("pairing: failed to upgrade initiator into Octagon: %@", error);
         }
@@ -407,12 +408,17 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
             return;
         } else {
             OTPairingMessage *octagonMessage = [[OTPairingMessage alloc]init];
+            octagonMessage.supportsSOS = [[OTSupportSOSMessage alloc] init];
+            octagonMessage.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
             OTApplicantToSponsorRound2M1 *prepare = [[OTApplicantToSponsorRound2M1 alloc] init];
             prepare.peerID = peerID;
             prepare.permanentInfo = permanentInfo;
             prepare.permanentInfoSig = permanentInfoSig;
             prepare.stableInfo = stableInfo;
             prepare.stableInfoSig = stableInfoSig;
+
+            octagonMessage.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+            octagonMessage.supportsOctagon.supported = OTSupportType_supported;
             octagonMessage.prepare = prepare;
             if(application){
                 secnotice(pairingScope, "initiatorCompleteSecondPacketOctagon returning octagon and sos data");
@@ -465,7 +471,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
                 } else {
                     //kick off SOS ugprade
                     if(OctagonIsEnabled() && !self.sessionSupportsOctagon) {
-                        [self attemptSosUpgrade];
+                        [self waitForOctagonUpgrade];
                     }
                     typeof(self) strongSelf = weakSelf;
                     secnotice("pairing", "initiator circle join complete, more data: %s: %@",
@@ -656,10 +662,13 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
                 [weakSelf acceptorSecondPacket:nsdata complete:kscomplete];
             };
             OTPairingMessage *response = [[OTPairingMessage alloc] init];
+            response.supportsSOS = [[OTSupportSOSMessage alloc] init];
+            response.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
             response.epoch = [[OTSponsorToApplicantRound1M2 alloc] init];
             response.epoch.epoch = epoch;
+            response.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+            response.supportsOctagon.supported = OTSupportType_supported;
             reply[@"o"] = response.data;
-
             secnotice("pairing", "acceptor reply to packet 1");
             complete(false, reply, error);
         }
@@ -755,9 +764,13 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
                 finished = false;
             }
             OTPairingMessage *response = [[OTPairingMessage alloc] init];
+            response.supportsSOS = [[OTSupportSOSMessage alloc] init];
+            response.supportsOctagon = [[OTSupportOctagonMessage alloc] init];
             response.voucher = [[OTSponsorToApplicantRound2M2 alloc] init];
             response.voucher.voucher = voucher;
             response.voucher.voucherSignature = voucherSig;
+            response.supportsSOS.supported = OctagonPlatformSupportsSOS() ? OTSupportType_supported : OTSupportType_not_supported;
+            response.supportsOctagon.supported = OTSupportType_supported;
 
             if (self.acceptorWillSendInitialSyncCredentials) {
                 // no need to share TLKs over the pairing channel, that's provided by octagon
@@ -866,7 +879,7 @@ const compression_algorithm pairingCompression = COMPRESSION_LZFSE;
             if (compressedData) {
                 NSString *key = [NSString stringWithFormat:@"com.apple.ckks.pairing.packet-size.%s.%u",
                                  self->_initiator ? "initiator" : "acceptor", self->_counter];
-                SecADClientPushValueForDistributionKey((__bridge CFStringRef)key, [compressedData length]);
+                [SecCoreAnalytics sendEvent:key event:@{SecCoreAnalyticsValue: [NSNumber numberWithUnsignedInteger:[compressedData length]]}];
                 secnotice("pairing", "pairing packet size %lu", (unsigned long)[compressedData length]);
             }
         }
index eafb80c6fa1802c1c631fa5e2e3e7a0f3f65ddf3..9feadd4d24950356fad5789e04113c0a0bbbfaa1 100644 (file)
@@ -4,8 +4,7 @@
 @implementation FakeNSXPCConnection
 - (instancetype) initWithControl:(id<SOSControlProtocol>)control
 {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _control = control;
     }
     return self;
     complete(true, nil);
 }
 
-- (void)triggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray<NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
 {
     complete(true, NULL);
 }
     complete(nil, nil);
 }
 
-- (void)triggerBackup:(NSArray<NSString *> *)backupPeers complete:(void (^)(NSError *))complete {
+- (void)iCloudIdentityStatus_internal: (void(^)(NSDictionary *tableSpid, NSError *error))complete {
+    complete(nil, nil);
+}
+
+- (void) iCloudIdentityStatus: (void(^)(NSData *json, NSError *error))complete {
+    complete(nil, nil);
+}
+
+- (void)rpcTriggerBackup:(NSArray<NSString *> *)backupPeers complete:(void (^)(NSError *))complete {
+    complete(nil);
+}
+
+- (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete {
     complete(nil);
 }
 
index 2cd57264e3fdca48d33e23e072faf64a4f00029e..f34ee6496070a0191d89cf3c7e44d02d489f87be 100644 (file)
@@ -17,8 +17,6 @@
 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
 #include "keychain/SecureObjectSync/SOSPeerInfoInternal.h"
 
-#include <CommonCrypto/CommonRandomSPI.h>
-
 
 static SecKeyRef GenerateFullECKey_internal(int keySize,  NSError** error)
 {
@@ -88,25 +86,26 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
 - (id) initWithSecret: (NSString*) secret
       incorrectSecret: (NSString*) incorrectSecret
        incorrectTries: (int) retries {
-    self = [super init];
+    if ((self = [super init])) {
 
-    SecKeyRef signingKey = GenerateFullECKey(256, NULL);
-    SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL);
-    SecKeyRef octagonEncryptionKey = GenerateFullECKey(384, NULL);
+        SecKeyRef signingKey = GenerateFullECKey(256, NULL);
+        SecKeyRef octagonSigningKey = GenerateFullECKey(384, NULL);
+        SecKeyRef octagonEncryptionKey = GenerateFullECKey(384, NULL);
 
-    SOSPeerInfoRef newPeerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, octagonEncryptionKey, NULL);
+        SOSPeerInfoRef newPeerInfo = SOSPeerInfoCreate(NULL, (__bridge CFDictionaryRef) @{(__bridge NSString*)kPIUserDefinedDeviceNameKey:@"Fakey"}, NULL, signingKey, octagonSigningKey, octagonEncryptionKey, NULL);
 
-    if (newPeerInfo == NULL) {
-        return nil;
-    }
-    self.peerInfo = newPeerInfo;
-    CFRelease(newPeerInfo);
-    newPeerInfo = NULL;
+        if (newPeerInfo == NULL) {
+            return nil;
+        }
+        self.peerInfo = newPeerInfo;
+        CFRelease(newPeerInfo);
+        newPeerInfo = NULL;
 
-    self.sharedSecret = secret;
-    self.incorrectSecret = incorrectSecret;
-    self.incorrectTries = retries;
+        self.sharedSecret = secret;
+        self.incorrectSecret = incorrectSecret;
+        self.incorrectTries = retries;
 
+    }
     return self;
 }
 
@@ -188,18 +187,17 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
 }
 
 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
-    self = [super init];
+    if ((self = [super init])) {
+        self->_secrets = secrets;
+        self.currentSecret = 0;
+        self->_retriesPerSecret = retries;
+        self->_retriesLeft = self.retriesPerSecret;
 
-    self->_secrets = secrets;
-    self.currentSecret = 0;
-    self->_retriesPerSecret = retries;
-    self->_retriesLeft = self.retriesPerSecret;
-
-    self->_codeToUse = code;
-
-    uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
-    self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
+        self->_codeToUse = code;
 
+        uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
+        self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
+    }
     return self;
 }
 
@@ -270,7 +268,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
     KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
                                                                                                              dsid:dsid
-                                                                                                              rng:ccDRBGGetRngState()
+                                                                                                              rng:ccrng(NULL)
                                                                                                             error:&error];
 
     NSData* initialMessage = [requestSession initialMessage: &error];
@@ -282,7 +280,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
                                                                                     circleDelegate:acceptDelegate
                                                                                               dsid:dsid
-                                                                                               rng:ccDRBGGetRngState()
+                                                                                               rng:ccrng(NULL)
                                                                                              error:&error];
     
     error = nil;
@@ -365,7 +363,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret incorrectSecret:@"777888" incorrectTries:3];
     KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
                                                                                                              dsid:dsid
-                                                                                                              rng:ccDRBGGetRngState()
+                                                                                                              rng:ccrng(NULL)
                                                                                                             error:&error];
 
     NSData* initialMessage = [requestSession initialMessage: &error];
@@ -377,7 +375,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
                                                                                     circleDelegate:acceptDelegate
                                                                                               dsid:dsid
-                                                                                               rng:ccDRBGGetRngState()
+                                                                                               rng:ccrng(NULL)
                                                                                              error:&error];
 
     error = nil;
@@ -471,7 +469,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningRequestTestDelegate* requestDelegate = [KCJoiningRequestTestDelegate requestDelegateWithSecret: secret];
     KCJoiningRequestSecretSession *requestSession = [[KCJoiningRequestSecretSession alloc] initWithSecretDelegate:requestDelegate
                                                                                                              dsid:dsid
-                                                                                                              rng:ccDRBGGetRngState()
+                                                                                                              rng:ccrng(NULL)
                                                                                                             error:&error];
 
     NSData* initialMessage = [requestSession initialMessage: &error];
@@ -483,7 +481,7 @@ static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
     KCJoiningAcceptSession* acceptSession = [[KCJoiningAcceptSession alloc] initWithSecretDelegate:acceptDelegate
                                                                                     circleDelegate:acceptDelegate
                                                                                               dsid:dsid
-                                                                                               rng:ccDRBGGetRngState()
+                                                                                               rng:ccrng(NULL)
                                                                                              error:&error];
 
     error = nil;
index 137bf0776948255de8882eb414ae4c688e66aac9..112ebe33af9f9e2cba26013720e6ad7f8f349c56 100644 (file)
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testSecPairBasicTest KCPairing.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>testSecPairBasicTest</string>
+                               <string>KCPairing.xctest</string>
                        </array>
                </dict>
        </array>
index e518a2614520d183c2cdfc29af49bd9e11737405..6a516cd4da7e674b378da6daac87b5fd42a33142 100644 (file)
@@ -10,7 +10,6 @@
 #include <corecrypto/ccrng.h>
 #include <corecrypto/ccsha2.h>
 #include <corecrypto/ccdh_gp.h>
-#include <CommonCrypto/CommonRandomSPI.h>
 
 @interface KCSRPTests : XCTestCase
 
     [self negotiateWithUser: @"TestUser"
                  digestInfo: ccsha256_di()
                       group: ccsrp_gp_rfc5054_3072()
-               randomSource: ccDRBGGetRngState()];
+               randomSource: ccrng(NULL)];
 }
 
 @end
index 325f198c42912cea5ef3141378f70a702b5e8458..8ab9c0154be36c45337cf67c5afe21420cc54c10 100644 (file)
 
 #include <CommonCrypto/CommonRandomSPI.h>
 
-
-static SecKeyRef GenerateFullECKey_internal(int keySize,  NSError** error)
-{
-    SecKeyRef full_key = NULL;
-
-    NSDictionary* keygen_parameters = @{ (__bridge NSString*)kSecAttrKeyType:(__bridge NSString*) kSecAttrKeyTypeEC,
-                                         (__bridge NSString*)kSecAttrKeySizeInBits: [NSNumber numberWithInt: keySize] };
-
-
-    (void) OSStatusError(SecKeyGeneratePair((__bridge CFDictionaryRef)keygen_parameters, NULL, &full_key), error, @"Generate Key failed");
-
-    return full_key;
-}
-
-static SecKeyRef GenerateFullECKey(int keySize, NSError** error) {
-    return GenerateFullECKey_internal(keySize, error);
-}
-
 static NSData* createTlkRequestMessage (KCAESGCMDuplexSession* aesSession) {
     char someData[] = {1,2,3,4,5,6};
     NSError* error = NULL;
@@ -165,18 +147,17 @@ static NSData* createTlkRequestMessage (KCAESGCMDuplexSession* aesSession) {
 }
 
 - (id) initWithSecrets: (NSArray<NSString*>*) secrets retries: (int) retries code: (NSString*) code {
-    self = [super init];
-
-    self->_secrets = secrets;
-    self.currentSecret = 0;
-    self->_retriesPerSecret = retries;
-    self->_retriesLeft = self.retriesPerSecret;
+    if ((self = [super init])) {
+        self->_secrets = secrets;
+        self.currentSecret = 0;
+        self->_retriesPerSecret = retries;
+        self->_retriesLeft = self.retriesPerSecret;
 
-    self->_codeToUse = code;
-
-    uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
-    self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
+        self->_codeToUse = code;
 
+        uint8_t joinDataBuffer[] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
+        self->_circleJoinData = [NSData dataWithBytes: joinDataBuffer length: sizeof(joinDataBuffer) ];
+    }
     return self;
 }
 
index daf13f84928568d6cc9f5da8edcae2c3605e12e0..d34989d67a5c27f014d6085fed62269794388e3f 100644 (file)
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest KCDerTest KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>KCDerTest</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
                <dict>
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testAESGCMDuplex KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>testAESGCMDuplex</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
                <dict>
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testAESGCMDuplexCoding KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>testAESGCMDuplexCoding</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
                <dict>
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSession KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>testJoiningSession</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
                <dict>
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSessionRetry KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>testJoiningSessionRetry</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
                <dict>
                        <false/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest testJoiningSessionCodeChange KeychainCircleTests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string> NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES </string>
+                               <string>-XCTest</string>
+                               <string>testJoiningSessionCodeChange</string>
+                               <string>KeychainCircleTests.xctest</string>
                        </array>
                </dict>
        </array>
diff --git a/KeychainEntitledTestApp_ios/AppDelegate.h b/KeychainEntitledTestApp_ios/AppDelegate.h
deleted file mode 100644 (file)
index 998155c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-//  AppDelegate.h
-//  KeychainEntitledTestApp_ios
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved. 
-//
-//
-
-#import <UIKit/UIKit.h>
-
-@interface AppDelegate : UIResponder <UIApplicationDelegate>
-
-@property (strong, nonatomic) UIWindow *window;
-
-
-@end
-
diff --git a/KeychainEntitledTestApp_ios/AppDelegate.m b/KeychainEntitledTestApp_ios/AppDelegate.m
deleted file mode 100644 (file)
index 7905dda..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-//  AppDelegate.m
-//  KeychainEntitledTestApp_ios
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import "AppDelegate.h"
-
-@interface AppDelegate ()
-
-@end
-
-@implementation AppDelegate
-
-
-- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
-    // Override point for customization after application launch.
-    return YES;
-}
-
-
-- (void)applicationWillResignActive:(UIApplication *)application {
-    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
-    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
-}
-
-
-- (void)applicationDidEnterBackground:(UIApplication *)application {
-    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
-    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
-}
-
-
-- (void)applicationWillEnterForeground:(UIApplication *)application {
-    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
-}
-
-
-- (void)applicationDidBecomeActive:(UIApplication *)application {
-    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
-}
-
-
-- (void)applicationWillTerminate:(UIApplication *)application {
-    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
-}
-
-
-@end
diff --git a/KeychainEntitledTestApp_ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/KeychainEntitledTestApp_ios/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644 (file)
index d8db8d6..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "iphone",
-      "size" : "20x20",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "20x20",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "29x29",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "40x40",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "iphone",
-      "size" : "60x60",
-      "scale" : "3x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "20x20",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "20x20",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "29x29",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "29x29",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "40x40",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "40x40",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "76x76",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "76x76",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "ipad",
-      "size" : "83.5x83.5",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "ios-marketing",
-      "size" : "1024x1024",
-      "scale" : "1x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/KeychainEntitledTestApp_ios/Info.plist b/KeychainEntitledTestApp_ios/Info.plist
deleted file mode 100644 (file)
index d052473..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIdentifier</key>
-       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-       <key>LSRequiresIPhoneOS</key>
-       <true/>
-       <key>UILaunchStoryboardName</key>
-       <string>LaunchScreen</string>
-       <key>UIMainStoryboardFile</key>
-       <string>Main</string>
-       <key>UIRequiredDeviceCapabilities</key>
-       <array>
-               <string>armv7</string>
-       </array>
-       <key>UISupportedInterfaceOrientations</key>
-       <array>
-               <string>UIInterfaceOrientationPortrait</string>
-               <string>UIInterfaceOrientationLandscapeLeft</string>
-               <string>UIInterfaceOrientationLandscapeRight</string>
-       </array>
-       <key>UISupportedInterfaceOrientations~ipad</key>
-       <array>
-               <string>UIInterfaceOrientationPortrait</string>
-               <string>UIInterfaceOrientationPortraitUpsideDown</string>
-               <string>UIInterfaceOrientationLandscapeLeft</string>
-               <string>UIInterfaceOrientationLandscapeRight</string>
-       </array>
-</dict>
-</plist>
diff --git a/KeychainEntitledTestApp_ios/ViewController.h b/KeychainEntitledTestApp_ios/ViewController.h
deleted file mode 100644 (file)
index 2300ca2..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-//  ViewController.h
-//  KeychainEntitledTestApp_ios
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import <UIKit/UIKit.h>
-
-@interface ViewController : UIViewController
-
-
-@end
-
diff --git a/KeychainEntitledTestApp_ios/ViewController.m b/KeychainEntitledTestApp_ios/ViewController.m
deleted file mode 100644 (file)
index 30c0bb6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-//  ViewController.m
-//  KeychainEntitledTestApp_ios
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import "ViewController.h"
-
-@interface ViewController ()
-
-@end
-
-@implementation ViewController
-
-- (void)viewDidLoad {
-    [super viewDidLoad];
-    // Do any additional setup after loading the view, typically from a nib.
-}
-
-
-- (void)didReceiveMemoryWarning {
-    [super didReceiveMemoryWarning];
-    // Dispose of any resources that can be recreated.
-}
-
-
-@end
diff --git a/KeychainEntitledTestApp_ios/main.m b/KeychainEntitledTestApp_ios/main.m
deleted file mode 100644 (file)
index d553ece..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-//  main.m
-//  KeychainEntitledTestApp_ios
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import <UIKit/UIKit.h>
-#import "AppDelegate.h"
-
-int main(int argc, char * argv[]) {
-    @autoreleasepool {
-        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
-    }
-}
diff --git a/KeychainEntitledTestApp_mac/AppDelegate.h b/KeychainEntitledTestApp_mac/AppDelegate.h
deleted file mode 100644 (file)
index 5452eb9..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-//  AppDelegate.h
-//  KeychainEntitledTestApp_mac
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import <Cocoa/Cocoa.h>
-
-@interface AppDelegate : NSObject <NSApplicationDelegate>
-
-
-@end
-
diff --git a/KeychainEntitledTestApp_mac/AppDelegate.m b/KeychainEntitledTestApp_mac/AppDelegate.m
deleted file mode 100644 (file)
index e1e6dc3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  AppDelegate.m
-//  KeychainEntitledTestApp_mac
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import "AppDelegate.h"
-
-@interface AppDelegate ()
-
-@end
-
-@implementation AppDelegate
-
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
-    // Insert code here to initialize your application
-}
-
-
-- (void)applicationWillTerminate:(NSNotification *)aNotification {
-    // Insert code here to tear down your application
-}
-
-
-@end
diff --git a/KeychainEntitledTestApp_mac/Assets.xcassets/AppIcon.appiconset/Contents.json b/KeychainEntitledTestApp_mac/Assets.xcassets/AppIcon.appiconset/Contents.json
deleted file mode 100644 (file)
index 2db2b1c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "mac",
-      "size" : "16x16",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "16x16",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "32x32",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "32x32",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "128x128",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "128x128",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "256x256",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "256x256",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "512x512",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "mac",
-      "size" : "512x512",
-      "scale" : "2x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}
\ No newline at end of file
diff --git a/KeychainEntitledTestApp_mac/Info.plist b/KeychainEntitledTestApp_mac/Info.plist
deleted file mode 100644 (file)
index 8a4ebbf..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIconFile</key>
-       <string></string>
-       <key>CFBundleIdentifier</key>
-       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>APPL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-       <key>LSMinimumSystemVersion</key>
-       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
-       <key>NSPrincipalClass</key>
-       <string>NSApplication</string>
-</dict>
-</plist>
diff --git a/KeychainEntitledTestApp_mac/ViewController.h b/KeychainEntitledTestApp_mac/ViewController.h
deleted file mode 100644 (file)
index 3a40d4b..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-//  ViewController.h
-//  KeychainEntitledTestApp_mac
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import <Cocoa/Cocoa.h>
-
-@interface ViewController : NSViewController
-
-
-@end
-
diff --git a/KeychainEntitledTestApp_mac/ViewController.m b/KeychainEntitledTestApp_mac/ViewController.m
deleted file mode 100644 (file)
index 452e757..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-//  ViewController.m
-//  KeychainEntitledTestApp_mac
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import "ViewController.h"
-
-@implementation ViewController
-
-- (void)viewDidLoad {
-    [super viewDidLoad];
-
-    // Do any additional setup after loading the view.
-}
-
-
-- (void)setRepresentedObject:(id)representedObject {
-    [super setRepresentedObject:representedObject];
-
-    // Update the view, if already loaded.
-}
-
-
-@end
diff --git a/KeychainEntitledTestApp_mac/main.m b/KeychainEntitledTestApp_mac/main.m
deleted file mode 100644 (file)
index bc0cd59..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-//  main.m
-//  KeychainEntitledTestApp_mac
-//
-//  Copyright (c) 2017 Apple Inc. All rights reserved.
-//
-//
-
-#import <Cocoa/Cocoa.h>
-
-int main(int argc, const char * argv[]) {
-    return NSApplicationMain(argc, argv);
-}
index 030606c437f8abf2a5315530faf21b270098c207..cc31d6762e85bfea1e17c0f4ed0de34e6e823faa 100644 (file)
 // was asked to file this radar for accounts: <rdar://problem/40176124> Invoke DataclassOwner when enabling or signing into an account
 - (void)account:(ACAccount *)account didChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount {
 
-    if((changeType == kACAccountChangeTypeAdded || changeType == kACAccountChangeTypeModified) &&
+    if((changeType == kACAccountChangeTypeAdded || changeType == kACAccountChangeTypeModified || changeType == kACAccountChangeTypeWarmingUp) &&
        [account.accountType.identifier isEqualToString: ACAccountTypeIdentifierAppleAccount] &&
        [self accountIsPrimary:account]) {
 
+        SOSCCLoggedIntoAccount(NULL);
+
 #if OCTAGON
         if(OctagonIsEnabled()){
             NSString* altDSID =  [account aa_altDSID];
diff --git a/Modules/OctagonTrust.modulemap b/Modules/OctagonTrust.modulemap
new file mode 100644 (file)
index 0000000..be8cef6
--- /dev/null
@@ -0,0 +1,6 @@
+framework module OctagonTrust [system] {
+  umbrella header "OctagonTrust.h"
+
+  export *
+  module * { export * }
+}
index 19cd51d0f44196faa22921ada3a8b03fdf36278a..7672ee88a10bacef328b741222a29cacb065af36 100644 (file)
@@ -1,4 +1,4 @@
-framework module Security [extern_c] {
+framework module Security [extern_c][system] {
   umbrella header "Security.h"
 
   export *
index e183b64676669dadbc210f5855ac0c513117a41b..935d8655c9042507cfaba3a85225487d9019ccd6 100644 (file)
@@ -1,4 +1,4 @@
-framework module Security [extern_c] {
+framework module Security [extern_c][system] {
   umbrella header "Security.h"
 
   export *
index 9645c117f1f40d9ca33c0e0114670721f4d45d50..83865039472ffe29efd8348e11f33919e3a64315 100644 (file)
@@ -1,4 +1,4 @@
-module Security.SecTask [extern_c] {
+module Security.SecTask [extern_c][system] {
     header "SecTask.h"
     export *
 }
diff --git a/OSX/Breadcrumb/README b/OSX/Breadcrumb/README
deleted file mode 100644 (file)
index 894c607..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-Breadcrumbs
-===========
-
-simple defintions:
-
-       old password 
-       new password
-       K = random 16 byte key
-       EK = Encrypted K
-       EKold =  ECB(PBKDF2(password_old), K)
-       EKnew =  ECB(PBKDF2(password_new), K)
-       Breadcrumb = AES-GCM(K, old password)
-
-
-Breadcrumbs are to make life easier when using AppleID password as
-local password by allowing upgrade of keychains from old password to new
-password.
-
-When changing the password on one machine, the keychains for the user are
-still encrypted (AES-GCM, key derived using PBKDF2) with the old password on
-all machines.
-
-This happens for one machine when changing password on the AppleID.apple.com webpage.
-
-An EK is stored on the apple server. Each machine have its own EK stored on the web server.
-
-When user change the password on the AppleID.apple.com website, the
-web server will unwrap the key K with the old password and then rewrap
-it with the new password.
-
-       unwrap(EKold, old password) -> K
-       wrap(K, new password) -> EKnew
-
-This means that if the user changes password more then ones, the computer can still upgrade the keychain to the current password since K will be the same until a new EK is uploaded the the computer.
-
-PKDF2 is used to avoid prebuilt lists of string2key tables attacks on
-the breadcrumb + encryptedKey if the attacker possesses both.
-
-Breadcrumb contain current password that encrypts the keychain. The breadcrumb itself is encrypted with a machine-specific key K.
-
-The breadcrumb is stored on the local machine and never leaves the
-local machine.
-
-When the computer have upgrade keychain to the current password and new K, EK, and breadcrumb is generated.
-
-Format
-======
-
-K = Random 16 byte
-EK = ECB(PBKDF2(pw), key K) (16byte) | pbkdf-salt (20byte) | 4byte int network order of pbdf-iter
-Breadcrumb = version (1) 1byte | AES-GCM-ENC(key K, password length (4byte, network order) | password | pad  ) | tag
-
-The encrypted key (EK) is a PKDF2 salt + iteration count + random AES-128 key (K) 
-encrypted with ECB of the PKDF2(salt, iteration, password).
-
-There is no integrity on this encryption on purpose since that would make the
-EK an verifier.
-
-The format of the EncryptedKey is
-
-    ECB(PBKDF2(pw), key K) (16byte) | pbkdf-salt (20byte) | 4byte int network order of pbdf-iter
-    
-The random key (K) is used to encrypt a breadcrumb that is stored
-locally on the machine. The breadcrumb allows you to recover the old
-password if you know the new password and have the encrypted key.
-
-The client machine encrypts the password with AES-GCM using key K. The data
-is padded to 256 bytes to no tell password length.
-
-The format of the breadcrumb
-
-    version (1) 1byte | AES-GCM-ENC(key K, password length (4byte, network order) | password | pad  ) | tag
-    
-tag is the 16 byte GCM tag
-key is the key (K) from the EncryptedKey (EK)
-assoc data i AES-GCM covers version byte
-
-Password length including up to pad is encrypted with AES-GCM
-
-Password is padded to paddingSize (256) to avoid exposing length of password.
-
-The PBKDF2 function is PBKDF2-HMAC-SHA256.
-
-
-Updating the Encrypted Key (EK) on server
-=========================================
-
-When a user update the password on the apple id server the server
-updates the breadcrumb for each machine that the user have associsated
-with the account.
-
-1. The server takes the old password generates a the key using PBKDF2
-   using the salt and interation count.
-
-2. The server takes the new password generates a the key using PBKDF2
-   using the same salt and interation count.
-
-3. Decrypts the first block with the key of old password and
-   re-encrypt with the key of new password.
diff --git a/OSX/Breadcrumb/SecBreadcrumb.c b/OSX/Breadcrumb/SecBreadcrumb.c
deleted file mode 100644 (file)
index 067c93c..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- * Copyright (c) 2014 - 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 <Security/Security.h>
-#include <Security/SecBreadcrumb.h>
-#include <Security/SecRandom.h>
-
-#include <corecrypto/ccaes.h>
-#include <corecrypto/ccpbkdf2.h>
-#include <corecrypto/ccmode.h>
-#include <corecrypto/ccmode_factory.h>
-#include <corecrypto/ccsha2.h>
-
-#include <CommonCrypto/CommonRandomSPI.h>
-
-#import "SecCFAllocator.h"
-
-#define CFReleaseNull(CF) ({ __typeof__(CF) *const _pcf = &(CF), _cf = *_pcf; (_cf ? (*_pcf) = ((__typeof__(CF))0), (CFRelease(_cf), ((__typeof__(CF))0)) : _cf); })
-
-#define kBCKeySize CCAES_KEY_SIZE_128
-#define kBCSaltSize 20
-#define kBCIterations 5000
-#define BCTagLen 16
-#define BCIVLen 16
-#define BCversion1 1
-#define BCversion2 2
-#define BCPaddingSize 256
-#define BCMaxSize 1024
-
-Boolean
-SecBreadcrumbCreateFromPassword(CFStringRef inPassword,
-                                CFDataRef *outBreadcrumb,
-                                CFDataRef *outEncryptedKey,
-                                CFErrorRef *outError)
-{
-    const struct ccmode_ecb *ecb = ccaes_ecb_encrypt_mode();
-    const struct ccmode_gcm *gcm = ccaes_gcm_encrypt_mode();
-    uint8_t iv[BCIVLen];
-    CFMutableDataRef key, npw;
-    CFDataRef pw;
-    
-    *outBreadcrumb = NULL;
-    *outEncryptedKey = NULL;
-    if (outError)
-        *outError = NULL;
-    
-    key = CFDataCreateMutable(SecCFAllocatorZeroize(), 0);
-    if (key == NULL)
-        return false;
-    
-    CFDataSetLength(key, kBCKeySize + kBCSaltSize + 4);
-    if (SecRandomCopyBytes(kSecRandomDefault, CFDataGetLength(key) - 4, CFDataGetMutableBytePtr(key)) != 0) {
-        CFReleaseNull(key);
-        return false;
-    }
-    if (SecRandomCopyBytes(kSecRandomDefault, BCIVLen, iv) != 0) {
-        CFReleaseNull(key);
-        return false;
-    }
-
-    uint32_t size = htonl(kBCIterations);
-    memcpy(CFDataGetMutableBytePtr(key) + kBCKeySize + kBCSaltSize, &size, sizeof(size));
-    
-    /*
-     * Create data for password
-     */
-    
-    pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
-    if (pw == NULL) {
-        CFReleaseNull(key);
-        return false;
-    }
-
-    const CFIndex passwordLength = CFDataGetLength(pw);
-    
-    if (passwordLength > BCMaxSize) {
-        CFReleaseNull(pw);
-        CFReleaseNull(key);
-        return false;
-    }
-
-    CFIndex paddedSize = passwordLength + BCPaddingSize - (passwordLength % BCPaddingSize);
-    const CFIndex outLength = 1 + BCIVLen + 4 + paddedSize + BCTagLen;
-    
-    npw = CFDataCreateMutable(NULL, outLength);
-    if (npw == NULL) {
-        CFReleaseNull(pw);
-        CFReleaseNull(key);
-        return false;
-    }
-    CFDataSetLength(npw, outLength);
-
-    cc_clear(outLength, CFDataGetMutableBytePtr(npw));
-    CFDataGetMutableBytePtr(npw)[0] = BCversion2;
-    memcpy(CFDataGetMutableBytePtr(npw) + 1, iv, BCIVLen);
-    size = htonl(passwordLength);
-    memcpy(CFDataGetMutableBytePtr(npw) + 1 + BCIVLen, &size, sizeof(size));
-    memcpy(CFDataGetMutableBytePtr(npw) + 1 + BCIVLen + 4, CFDataGetBytePtr(pw), passwordLength);
-    
-    /*
-     * Now create a GCM encrypted password using the random key
-     */
-    
-    ccgcm_ctx_decl(gcm->size, ctx);
-    ccgcm_init(gcm, ctx, kBCKeySize, CFDataGetMutableBytePtr(key));
-    ccgcm_set_iv(gcm, ctx, BCIVLen, iv);
-    ccgcm_gmac(gcm, ctx, 1, CFDataGetMutableBytePtr(npw));
-    ccgcm_update(gcm, ctx, outLength - BCTagLen - BCIVLen - 1, CFDataGetMutableBytePtr(npw) + 1 + BCIVLen, CFDataGetMutableBytePtr(npw) + 1 + BCIVLen);
-    ccgcm_finalize(gcm, ctx, BCTagLen, CFDataGetMutableBytePtr(npw) + outLength - BCTagLen);
-    ccgcm_ctx_clear(gcm->size, ctx);
-    
-    /*
-     * Wrapping key is PBKDF2(sha256) over password
-     */
-    
-    const struct ccdigest_info *di = ccsha256_di();
-    uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
-    _Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
-    if (sizeof(rawkey) != di->output_size) abort();
-
-    if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
-                      kBCSaltSize, CFDataGetMutableBytePtr(key) + kBCKeySize,
-                      kBCIterations,
-                      sizeof(rawkey), rawkey) != 0)
-        abort();
-    
-    /*
-     * Wrap the random key with one round of ECB cryto
-     */
-
-    ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
-    ccecb_init(ecb, ecbkey, kBCKeySize, rawkey);
-    ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(key), CFDataGetMutableBytePtr(key));
-    ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
-
-    /*
-     *
-     */
-    
-    cc_clear(sizeof(rawkey), rawkey);
-    CFReleaseNull(pw);
-    
-    *outBreadcrumb = npw;
-    *outEncryptedKey = key;
-    
-    return true;
-}
-
-
-Boolean
-SecBreadcrumbCopyPassword(CFStringRef inPassword,
-                          CFDataRef inBreadcrumb,
-                          CFDataRef inEncryptedKey,
-                          CFStringRef *outPassword,
-                          CFErrorRef *outError)
-{
-    const struct ccmode_ecb *ecb = ccaes_ecb_decrypt_mode();
-    CFMutableDataRef gcmkey, oldpw;
-    CFIndex outLength;
-    CFDataRef pw;
-    uint32_t size;
-    
-    *outPassword = NULL;
-    if (outError)
-        *outError = NULL;
-    
-    if (CFDataGetLength(inEncryptedKey) < kBCKeySize + kBCSaltSize + 4) {
-        return false;
-    }
-    
-    if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
-        if (CFDataGetLength(inBreadcrumb) < 1 + 4 + BCPaddingSize + BCTagLen)
-            return false;
-
-        outLength = CFDataGetLength(inBreadcrumb) - 1 - BCTagLen;
-    } else if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion2) {
-        if (CFDataGetLength(inBreadcrumb) < 1 + BCIVLen + 4 + BCPaddingSize + BCTagLen)
-            return false;
-        outLength = CFDataGetLength(inBreadcrumb) - 1 - BCIVLen - BCTagLen;
-    } else {
-        return false;
-    }
-    
-    gcmkey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, inEncryptedKey);
-    if (gcmkey == NULL) {
-        return false;
-    }
-    
-    if ((outLength % 16) != 0 && outLength < 4) {
-        CFReleaseNull(gcmkey);
-        return false;
-    }
-
-    oldpw = CFDataCreateMutable(SecCFAllocatorZeroize(), outLength);
-    if (oldpw == NULL) {
-        CFReleaseNull(gcmkey);
-        return false;
-    }
-    CFDataSetLength(oldpw, outLength);
-
-    /*
-     * Create data for password
-     */
-    
-    pw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), inPassword, kCFStringEncodingUTF8, 0);
-    if (pw == NULL) {
-        CFReleaseNull(oldpw);
-        CFReleaseNull(gcmkey);
-        return false;
-    }
-    
-    /*
-     * Wrapping key is HMAC(sha256) over password
-     */
-
-    const struct ccdigest_info *di = ccsha256_di();
-    uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
-    _Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
-    if (sizeof(rawkey) != di->output_size) abort();
-
-    memcpy(&size, CFDataGetMutableBytePtr(gcmkey) + kBCKeySize + kBCSaltSize, sizeof(size));
-    size = ntohl(size);
-    
-    if (ccpbkdf2_hmac(di, CFDataGetLength(pw), CFDataGetBytePtr(pw),
-                      kBCSaltSize, CFDataGetMutableBytePtr(gcmkey) + kBCKeySize,
-                      size,
-                      sizeof(rawkey), rawkey) != 0)
-        abort();
-
-    CFReleaseNull(pw);
-    
-    /*
-     * Unwrap the random key with one round of ECB cryto
-     */
-
-    ccecb_ctx_decl(ccecb_context_size(ecb), ecbkey);
-    ccecb_init(ecb, ecbkey, kBCKeySize, rawkey);
-    ccecb_update(ecb, ecbkey, 1, CFDataGetMutableBytePtr(gcmkey), CFDataGetMutableBytePtr(gcmkey));
-    ccecb_ctx_clear(ccecb_context_size(ecb), ecbkey);
-    /*
-     * GCM unwrap
-     */
-
-    uint8_t tag[BCTagLen];
-
-    if (CFDataGetBytePtr(inBreadcrumb)[0] == BCversion1) {
-        memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, BCTagLen);
-
-        ccgcm_one_shot_legacy(ccaes_gcm_decrypt_mode(), kBCKeySize,  CFDataGetMutableBytePtr(gcmkey), 0, NULL, 1, CFDataGetBytePtr(inBreadcrumb),
-                              outLength, CFDataGetBytePtr(inBreadcrumb) + 1, CFDataGetMutableBytePtr(oldpw), BCTagLen, tag);
-        if (memcmp(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + outLength, BCTagLen) != 0) {
-            CFReleaseNull(oldpw);
-            CFReleaseNull(gcmkey);
-            return false;
-        }
-
-    } else {
-        const uint8_t *iv = CFDataGetBytePtr(inBreadcrumb) + 1;
-        int res;
-        memcpy(tag, CFDataGetBytePtr(inBreadcrumb) + 1 + BCIVLen + outLength, BCTagLen);
-
-        res = ccgcm_one_shot(ccaes_gcm_decrypt_mode(), kBCKeySize, CFDataGetMutableBytePtr(gcmkey),
-                             BCIVLen, iv,
-                             1, CFDataGetBytePtr(inBreadcrumb),
-                             outLength, CFDataGetBytePtr(inBreadcrumb) + 1 + BCIVLen, CFDataGetMutableBytePtr(oldpw),
-                             BCTagLen, tag);
-        if (res) {
-            CFReleaseNull(gcmkey);
-            CFReleaseNull(oldpw);
-            CFReleaseNull(gcmkey);
-            return false;
-        }
-    }
-
-    CFReleaseNull(gcmkey);
-    
-
-    memcpy(&size, CFDataGetMutableBytePtr(oldpw), sizeof(size));
-    size = ntohl(size);
-    if ((ssize_t) size > outLength - 4) {
-        CFReleaseNull(oldpw);
-        return false;
-    }
-    memmove(CFDataGetMutableBytePtr(oldpw), CFDataGetMutableBytePtr(oldpw) + 4, size);
-    CFDataSetLength(oldpw, size);
-    
-    *outPassword = CFStringCreateFromExternalRepresentation(SecCFAllocatorZeroize(), oldpw, kCFStringEncodingUTF8);
-    CFReleaseNull(oldpw);
-
-    return true;
-}
-
-CFDataRef
-SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword,
-                                   CFStringRef newPassword,
-                                   CFDataRef encryptedKey,
-                                   CFErrorRef *outError)
-{
-    const struct ccmode_ecb *enc = ccaes_ecb_encrypt_mode();
-    const struct ccmode_ecb *dec = ccaes_ecb_decrypt_mode();
-    const struct ccdigest_info *di = ccsha256_di();
-    uint8_t rawkey[CCSHA256_OUTPUT_SIZE];
-    CFDataRef newpw = NULL, oldpw = NULL;
-    CFMutableDataRef newEncryptedKey;
-
-    _Static_assert(sizeof(rawkey) >= kBCKeySize, "keysize changed w/o updating digest");
-    if (sizeof(rawkey) != di->output_size) abort();
-
-    if (CFDataGetLength(encryptedKey) < kBCKeySize + kBCSaltSize + 4) {
-        return NULL;
-    }
-
-    newEncryptedKey = CFDataCreateMutableCopy(SecCFAllocatorZeroize(), 0, encryptedKey);
-    if (newEncryptedKey == NULL) {
-        return NULL;
-    }
-    
-    oldpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), oldPassword, kCFStringEncodingUTF8, 0);
-    if (oldpw == NULL) {
-        CFReleaseNull(newEncryptedKey);
-        return false;
-    }
-
-    newpw = CFStringCreateExternalRepresentation(SecCFAllocatorZeroize(), newPassword, kCFStringEncodingUTF8, 0);
-    if (newpw == NULL) {
-        CFReleaseNull(newEncryptedKey);
-        CFReleaseNull(oldpw);
-        return false;
-    }
-
-    /*
-     * Unwrap with new key
-     */
-
-    uint32_t iter;
-    
-    memcpy(&iter, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize + kBCSaltSize, sizeof(iter));
-    iter = ntohl(iter);
-    
-    if (ccpbkdf2_hmac(di, CFDataGetLength(oldpw), CFDataGetBytePtr(oldpw),
-                      kBCSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize,
-                      iter,
-                      sizeof(rawkey), rawkey) != 0)
-        abort();
-    
-    CFReleaseNull(oldpw);
-
-    
-    ccecb_ctx_decl(dec->size, deckey);
-    ccecb_init(dec, deckey, kBCKeySize, rawkey);
-    ccecb_update(dec, deckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
-    ccecb_ctx_clear(ccecb_context_size(dec), deckey);
-
-    cc_clear(sizeof(rawkey), rawkey);
-
-    /*
-     * Re-wrap with new key
-     */
-   
-    if (ccpbkdf2_hmac(di, CFDataGetLength(newpw), CFDataGetBytePtr(newpw),
-                      kBCSaltSize, CFDataGetMutableBytePtr(newEncryptedKey) + kBCKeySize,
-                      iter,
-                      sizeof(rawkey), rawkey) != 0)
-        abort();
-    
-    CFReleaseNull(newpw);
-
-    
-    ccecb_ctx_decl(enc->size, enckey);
-    ccecb_init(enc, enckey, kBCKeySize, rawkey);
-    ccecb_update(enc, enckey, 1, CFDataGetMutableBytePtr(newEncryptedKey), CFDataGetMutableBytePtr(newEncryptedKey));
-    ccecb_ctx_clear(ccecb_context_size(enc), enckey);
-
-    cc_clear(sizeof(rawkey), rawkey);
-
-    return newEncryptedKey;
-}
diff --git a/OSX/Breadcrumb/SecBreadcrumb.h b/OSX/Breadcrumb/SecBreadcrumb.h
deleted file mode 100644 (file)
index e7cc408..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2014 - 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@
- */
-
-/*!
- @function     SecBreadcrumbCreateFromPassword
- @abstract     Encryptes the password using a random key and then returns
- the encrypted password (breadcrumb) and the password encrypted random key.
-
- @param inPassword is the password to encrypt and use to encrypt the random key.
- @param outBreadcrumb is the password encrypted using a random key.
- @param outEncryptedKey is the random key encrypted using inPassword.
- @param outError An optional pointer to a CFErrorRef. This value is set
- if an error occurred. If not NULL, the caller is responsible for
- releasing the CFErrorRef.
- @result On return a Boolean indicating success or failure.
-
- @discussion This function generates the breadcrumb that will be used to
- update the user's keychain password when their Apple ID Login password
- is changed on appleid.apple.com.
-*/
-
-Boolean
-SecBreadcrumbCreateFromPassword(CFStringRef inPassword,
-       CFDataRef *outBreadcrumb,
-       CFDataRef *outEncryptedKey,
-       CFErrorRef *outError);
-
-
-/*!
- @function     SecBreadcrumbCopyPassword
- @abstract     Decryptes the encrypted key using the password and uses the key to
- decrypt the breadcrumb and returns the password stored in the breadcrumb.
-
- @param inPassword is the password to decrypt the encrypted random key.
- @param inBreadcrumb is the breadcrumb encrypted by the key. It contains
- and encrypted version of the users old password.
- @param inEncryptedKey is an encrypted version of the key used to encrypt the
- breadcrumb.
- @param outPassword is the cleartext password that was stored in the breadcrumb.
- @param outError An optional pointer to a CFErrorRef. This value is set
- if an error occurred. If not NULL, the caller is responsible for
- releasing the CFErrorRef.
- @result On return a Boolean indicating success or failure.
-
- @discussion This function uses the password to decrypt the encrypted key and then
- uses that key to decrypt the breadcrumb.
-*/
-
-Boolean
-SecBreadcrumbCopyPassword(CFStringRef inPassword,
-       CFDataRef inBreadcrumb,
-       CFDataRef inEncryptedKey,
-       CFStringRef *outPassword,
-       CFErrorRef *outError);
-
-/*
- * Change password used to encrypt the key from old password to new password
- */
-
-CFDataRef
-SecBreadcrumbCreateNewEncryptedKey(CFStringRef oldPassword,
-                                   CFStringRef newPassword,
-                                   CFDataRef encryptedKey,
-                                   CFErrorRef *outError);
diff --git a/OSX/Breadcrumb/bc-10-knife-on-bread.m b/OSX/Breadcrumb/bc-10-knife-on-bread.m
deleted file mode 100644 (file)
index a3f80db..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2014 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 <Foundation/Foundation.h>
-#include <Security/Security.h>
-#include <Security/SecBreadcrumb.h>
-#include <utilities/SecCFRelease.h>
-
-#include "breadcrumb_regressions.h"
-
-static NSString *after1 = @"XAKyA0TbLKpDOBl+Ur1CQpjGDtn3wp8bYiM07iJSGVIhaaG4AAATiA==";
-static NSString *bc1 = @"AdSXILtQrtsD+eT/UjMxxu4QTjlIJjvFDhpMXfk2eZ1CCJVhCuAhNcoL4DsU85DgSBCAswzVcSEU+bLMt+DT1jJfjJKVBus1Hd5lCA+N4wVtC66w3GK/WDQdGvLZ+BL86GkeRM2/+wH4/t5qOtxIJPS5SYZhnM5EP8xFYg30MLqXZqpwZhqYBJmVPMqEbLuihYAcAJreiZm4NN09CxvD36mvU3NyQOdHzAiQ+ADMiVI84qjU0qFH1KaZEoMHn3AqjAdviHUTOaNQXNepidedBZhSl4QBeuT2CaCYHjCXny9BYT+hCEU1yXn3RYeWyjcmFKmIz8gRvWf3ckF3XaSVL7MwqfsWw1tdI9OPi7zhauqphRGELw==";
-
-static NSString *after2 = @"l/y+EOCUEeQHudNLQd5SoCJ2s/+rfH/kdbxbwZ7YGGb/U2FMAAATiA==";
-static NSString *bc2 = @"AuuaJCuKmffY3XAqTYNygSFQ4QnlkSqTHGYUMaxDRA1lQhbxJh58zAOvcsahYH9lSb4+YoMR6G7hDmqlKae8h3jrn0vhT4FlIySFS3MUPvmGOuhUecb+Gi2AYwc9x1uz7f0FSRxxL+v04r2AkmH1Cv6cL7pvued7vxUjzX4VrexFj+uF7i/HSGStg2+D3L+CRs2+dKZZ9BqiKjavsX9XPkvJAD0r8rKHncOBrRxL7A3+ysBTZi2VCi/8QTDSGp6DmpXEJ4NTo/IrZ+trOXe0MuocLMg+Jf6V8jy5ZfaQoGTuM3fJiD6EFGT68QtLrjqU9KdtHhQdCmFVi60zbWqEBRNN7IyRNyPJX48NqFPZuAUW7BL0YbuhdUX2Oj7+hFz99vch1T0=";
-
-#define kTestCount 10
-int bc_10_password(int argc, char *const *argv)
-{
-    CFDataRef breadcrumb = NULL, encryptedKey = NULL;
-    CFStringRef oldPassword = NULL;
-    CFStringRef password = CFSTR("password");
-    CFStringRef newpassword = CFSTR("newpassword");
-    CFErrorRef error = NULL;
-
-    plan_tests(kTestCount);
-
-    ok(SecBreadcrumbCreateFromPassword(password, &breadcrumb, &encryptedKey, &error), "wrap failed");
-
-    ok(SecBreadcrumbCopyPassword(password, breadcrumb, encryptedKey, &oldPassword, NULL), "unwrap failed");
-
-    ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
-    CFReleaseSafe(oldPassword);
-
-    CFDataRef newEncryptedKey;
-
-    printf("changing password from \"password\" to \"newpassword\"\n");
-
-    newEncryptedKey = SecBreadcrumbCreateNewEncryptedKey(password,
-                                                         newpassword,
-                                                         encryptedKey,
-                                                         &error);
-    ok(newEncryptedKey, "no new encrypted key");
-    
-    ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
-    
-    ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
-
-    CFReleaseSafe(breadcrumb);
-    CFReleaseSafe(oldPassword);
-    CFReleaseSafe(newEncryptedKey);
-
-    /*
-     * Check KAT for IV less operation (version1)
-     */
-
-    breadcrumb = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:bc1 options:0]);
-    newEncryptedKey = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:after1 options:0]);
-
-    ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
-
-    ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
-
-    CFReleaseSafe(breadcrumb);
-    CFReleaseSafe(oldPassword);
-    CFReleaseSafe(newEncryptedKey);
-
-    /*
-     * Check KAT for IV less operation (version2)
-     */
-
-    breadcrumb = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:bc2 options:0]);
-    newEncryptedKey = CFBridgingRetain([[NSData alloc] initWithBase64EncodedString:after2 options:0]);
-
-    ok(SecBreadcrumbCopyPassword(newpassword, breadcrumb, newEncryptedKey, &oldPassword, NULL), "unwrap failed");
-
-    ok(oldPassword && CFStringCompare(password, oldPassword, 0) == kCFCompareEqualTo, "not same password");
-
-    CFReleaseSafe(breadcrumb);
-    CFReleaseSafe(oldPassword);
-    CFReleaseSafe(newEncryptedKey);
-
-    return 0;
-}
diff --git a/OSX/Breadcrumb/breadcrumb_regressions.h b/OSX/Breadcrumb/breadcrumb_regressions.h
deleted file mode 100644 (file)
index 29894bf..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/* To add a test:
- 1) add it here
- 2) Add it as command line argument for SecurityTest.app in the Release and Debug schemes
- */
-#include <regressions/test/testmore.h>
-
-ONE_TEST(bc_10_password)
index d4bdc363fadb272e4498e0d6644605bd077acf39..686d16543ea0db881c009238efbcf65f02774df0 100644 (file)
@@ -1,9 +1,9 @@
 .Dd November 02, 2016
-.Dt Keychain Circle Notification 8
+.Dt Keychain\ Circle\ Notification 8
 .Os
 .Sh NAME
 .Nm Keychain Circle Notification
-.Nd part of iCloud Keychain syncing.
+.Nd Part of iCloud Keychain syncing.
 .Sh DESCRIPTION
 .Nm
-part of iCloud Keychain syncing.
+Part of iCloud Keychain syncing.
index 91f8864ec7e127d582ccaf68ab0cc0905c786acb..563467dc140fb005d04f3dc2ddb6413ce73f2ddf 100644 (file)
 
 -(id)initWithPeerObject:(id)peerObject
 {
-       self = [super init];
-       if (!self) {
-               return self;
-       }
-       
-       self.peerObject = peerObject;
-       self.name = (__bridge NSString *)(SOSPeerInfoGetPeerName((__bridge SOSPeerInfoRef)peerObject));
-       self.idString = (__bridge NSString *)(SOSPeerInfoGetPeerID((__bridge SOSPeerInfoRef)peerObject));
-       
-       return self;
+    if ((self = [super init])) {
+        self.peerObject = peerObject;
+        self.name = (__bridge NSString *)(SOSPeerInfoGetPeerName((__bridge SOSPeerInfoRef)peerObject));
+        self.idString = (__bridge NSString *)(SOSPeerInfoGetPeerID((__bridge SOSPeerInfoRef)peerObject));
+    }
+    return self;
 }
 
 -(NSString*)description
index 66e36e7c1d4aee94a96cfa78859aef3069d6ccc0..114784bfce0f807bfb5742ce3798dc1589ac5e08 100644 (file)
@@ -160,14 +160,15 @@ typedef void (^applicantBlock)(id applicant);
 
 -(id)init
 {
-       self = [super init];
-       int token;
+    if ((self = [super init])) {
+        int token;
     
-    self->_queue_ = dispatch_queue_create([[NSString stringWithFormat:@"KDSecCircle@%p", self] UTF8String], NULL);
-    self->_callbacks = [NSMutableArray new];
-       notify_register_dispatch(kSOSCCCircleChangedNotification, &token, self.queue_, ^(int token1){
-               [self updateCheck];
-       });
+        self->_queue_ = dispatch_queue_create([[NSString stringWithFormat:@"KDSecCircle@%p", self] UTF8String], NULL);
+        self->_callbacks = [NSMutableArray new];
+        notify_register_dispatch(kSOSCCCircleChangedNotification, &token, self.queue_, ^(int token1) {
+                [self updateCheck];
+            });
+    }
     return self;
 }
 
diff --git a/OSX/Modules b/OSX/Modules
deleted file mode 120000 (symlink)
index 287aeb4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./Modules
\ No newline at end of file
index c1dd8e6c44eda793f9f34c8e31ee3a1fad459340..899819c1d0f37edf34ae9512f2754bfc6a0c2556 100644 (file)
                <string>123456.test.group2</string>
                <string>com.apple.bluetooth</string>
        </array>
+       <key>com.apple.private.AuthorizationServices</key>
+       <array>
+               <string>com.apple.trust-settings.admin</string>
+       </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
index 5c3ef633c7e46001cfa0aa01f5c5866730c1c95b..6bee84a9dd43bb4463fc0f4511a91d1943f61b6b 100644 (file)
@@ -1,7 +1,6 @@
 /* Don't prevent multiple inclusion of this file. */
 #include <libsecurity_ssl/regressions/ssl_regressions.h>
 #include <libsecurity_keychain/regressions/keychain_regressions.h>
-#include <Breadcrumb/breadcrumb_regressions.h>
 #include <libsecurity_cms/regressions/cms_regressions.h>
 #include <libsecurity_transform/regressions/transform_regressions.h>
 #include <shared_regressions/shared_regressions.h>
diff --git a/OSX/authd/PreloginUserDb.h b/OSX/authd/PreloginUserDb.h
new file mode 100644 (file)
index 0000000..f2a707f
--- /dev/null
@@ -0,0 +1,6 @@
+//
+//  PreloginUserDb.h
+//  authd
+//
+
+OSStatus preloginudb_copy_userdb(const char * _Nullable uuid, UInt32 flags, CFArrayRef _Nonnull * _Nonnull output);
diff --git a/OSX/authd/PreloginUserDb.m b/OSX/authd/PreloginUserDb.m
new file mode 100644 (file)
index 0000000..dff4982
--- /dev/null
@@ -0,0 +1,548 @@
+//
+//  PreloginUserDb.m
+//  authd
+//
+//  Copyright © 2019 Apple. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <libgen.h>
+#import <APFS/APFS.h>
+#import <DiskManagement/DiskManagement.h>
+#import "PreloginUserDb.h"
+#import <LocalAuthentication/LAContext+Private.h>
+#import <SoftLinking/SoftLinking.h>
+#import "debugging.h"
+#import <Security/Authorization.h>
+#import <Security/AuthorizationTagsPriv.h>
+#import <libaks_filevault.h>
+
+AUTHD_DEFINE_LOG
+
+SOFT_LINK_FRAMEWORK(Frameworks, LocalAuthentication)
+SOFT_LINK_FRAMEWORK(PrivateFrameworks, DiskManagement)
+SOFT_LINK_FRAMEWORK(Frameworks, DiskArbitration)
+SOFT_LINK_FRAMEWORK(PrivateFrameworks, APFS)
+
+SOFT_LINK_CLASS(LocalAuthentication, LAContext)
+SOFT_LINK_CLASS(DiskManagement, DMManager)
+SOFT_LINK_CLASS(DiskManagement, DMAPFS)
+SOFT_LINK_FUNCTION(APFS, APFSVolumeGetUnlockRecord, soft_APFSVolumeGetUnlockRecord, errno_t, (const char *disk, uuid_t wrecUUID, CFDataRef *data), (disk, wrecUUID, data))
+SOFT_LINK_FUNCTION(DiskArbitration, DADiskMount, soft_DADiskMount, void, ( DADiskRef disk, CFURLRef __nullable path, DADiskMountOptions options, DADiskMountCallback __nullable callback, void * __nullable context), (disk, path, options, callback, context ))
+SOFT_LINK_FUNCTION(DiskArbitration, DADiskUnmount, soft_DADiskUnmount, void, ( DADiskRef disk, DADiskUnmountOptions options, DADiskUnmountCallback __nullable callback, void * __nullable context), (disk, options, callback, context ))
+SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatusString, soft_DADissenterGetStatusString, CFStringRef __nullable, ( DADissenterRef dissenter ), ( dissenter ))
+SOFT_LINK_FUNCTION(DiskManagement, DMUnlocalizedTechnicalErrorString, soft_DMUnlocalizedTechnicalErrorString, NSString *, ( DMDiskErrorType inError ), ( inError ))
+SOFT_LINK_FUNCTION(DiskArbitration, DASessionCreate, soft_DASessionCreate, DASessionRef __nullable, ( CFAllocatorRef __nullable allocator ), ( allocator ))
+SOFT_LINK_FUNCTION(DiskArbitration, DADissenterGetStatus, soft_DADissenterGetStatus, DAReturn, ( DADissenterRef dissenter ), ( dissenter ))
+SOFT_LINK_FUNCTION(DiskArbitration, DASessionSetDispatchQueue, soft_DASessionSetDispatchQueue, void, ( DASessionRef session, dispatch_queue_t __nullable queue ), ( session, queue ))
+
+static NSString *kVekItemName = @"SecureAccessToken";
+static NSString *kGUIDItemName = @"GeneratedUID";
+static NSString *kAuthenticationAuthority = @"AuthenticationAuthority";
+static NSString *kIsAdmintemName = @"Admin";
+static NSString *kSCUnlockDataItemName = @"FVTokenSecret";
+static NSString *kSCEnforcementItemName  = @"SmartCardEnforcement";
+static NSString *kSCUacItemName  = @"userAccountControl";
+
+static NSString *kLongNameItemName = @"RealName";
+static NSString *kUidItemName = @"UID";
+static NSString *kVekFile = @"%@/%@/var/db/secureaccesstoken.plist";
+static NSString *kUsersFile = @"%@/%@/var/db/AllUsersInfo.plist";
+
+static NSString *kUsersGUID = @"UserIdent";
+static NSString *kUsersNameSection = @"UserNamesData";
+static NSString *kUsersSection = @"CryptoUsers";
+
+
+@interface PreloginUserDb : NSObject
+
+- (instancetype)init;
+
+- (BOOL) loadWithError:(NSError **)error;
+
+- (NSArray<NSDictionary *> *) users;
+- (NSArray<NSDictionary *> *) users:(NSString *)volumeUuid;
+
+@end
+
+typedef void (^AIRDBDACommonCompletionHandler)(DADissenterRef dissenter);
+static void _commonDACompletionCallback(DADiskRef disk, DADissenterRef dissenter, void *context)
+{
+       AIRDBDACommonCompletionHandler handler = (__bridge AIRDBDACommonCompletionHandler)context;
+       handler(dissenter);
+}
+
+@implementation PreloginUserDb {
+       DMManager *_diskMgr;
+       id _daSession;
+       NSMutableDictionary<NSString*, NSMutableArray*> *_dbDataDict; // NSDictionary indexed by volume UUID (NSString*)
+    NSMutableDictionary<NSString*, NSString*> *_dbVolumeGroupMap;
+       dispatch_queue_t _queue;
+}
+
+- (instancetype)init
+{
+       if ((self = [super init])) {
+               _queue = dispatch_queue_create("com.apple.PLUDB", DISPATCH_QUEUE_SERIAL);
+               if (!_queue) {
+                       os_log_error(AUTHD_LOG, "Failed to create queue");
+                       return nil;
+               }
+
+        _diskMgr = [[getDMManagerClass() alloc] init];
+               if (!_diskMgr) {
+                       os_log_error(AUTHD_LOG, "Failed to get DM");
+                       return nil;
+               }
+
+               _daSession = (__bridge_transfer id)soft_DASessionCreate(kCFAllocatorDefault);
+               if (!_daSession) {
+                       os_log_error(AUTHD_LOG, "Failed to get DA");
+                       return nil;
+               }
+
+        soft_DASessionSetDispatchQueue((__bridge DASessionRef _Nullable)_daSession, _queue);
+        [_diskMgr setDefaultDASession:(__bridge DASessionRef _Nullable)(_daSession)];
+       }
+       return self;
+}
+
+- (BOOL)loadWithError:(NSError **)err
+{
+    // get all preboot volumes
+    NSArray* prebootVolumes = [self allPrebootVolumes];
+    if (prebootVolumes.count == 0) {
+        os_log_error(AUTHD_LOG, "Failed to get preboot volumes for Prelogin userDB");
+        if (err) {
+            *err = [NSError errorWithDomain:@"com.apple.authorization" code:-1000 userInfo:@{ NSLocalizedDescriptionKey : @"Failed to get preboot volumes for Prelogin userDB"}];
+        }
+        return NO;
+    }
+
+    NSUUID *uuid = [self currentRecoveryVolumeUUID];
+    os_log_info(AUTHD_LOG, "Current Recovery Volume UUID: %{public}@", uuid);
+
+    _dbDataDict = [NSMutableDictionary new];
+    _dbVolumeGroupMap = [NSMutableDictionary new];
+    [self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:uuid];
+
+    if (_dbDataDict.count == 0 && uuid != nil) {
+        os_log(AUTHD_LOG, "No admins found. Try to load all preboot partitions");
+        _dbDataDict = [NSMutableDictionary new];
+        [self processPrebootVolumes:prebootVolumes currentRecoveryVolumeUUID:nil]; // load admins from ALL preboot partitions
+    }
+
+    if (err) {
+        *err = nil;
+    }
+    return YES;
+}
+
+- (NSArray<NSDictionary *> *)users
+{
+    return [self users:nil];
+}
+
+- (NSArray<NSDictionary *> *) users:(NSString *)requestedUuid
+{
+    if (!_dbDataDict.allValues) {
+        return nil;
+    }
+    if (requestedUuid && !_dbDataDict[requestedUuid]) {
+        NSString *realUuid = _dbVolumeGroupMap[requestedUuid];
+        if (!realUuid) {
+            os_log_info(AUTHD_LOG, "Requested volume %{public}@ was not found and is not volumeGroup", requestedUuid);
+            NSArray *keys = [_dbVolumeGroupMap allKeysForObject:requestedUuid];
+            for(NSString *uuid in keys) {
+                if (_dbDataDict[uuid]) {
+                    realUuid = uuid;
+                    break;
+                }
+            }
+            if (!realUuid) {
+                os_log_info(AUTHD_LOG, "Requested volumeGroup %{public}@ was not found", requestedUuid);
+                return nil; // no users for requested partition and no mapping for VolumeGroup or vice versa
+            }
+        }
+        os_log_info(AUTHD_LOG, "Requested volume %{public}@ has no users, trying volume %{public}@", requestedUuid, realUuid);
+        requestedUuid = realUuid;
+    }
+    
+    NSMutableArray *allUsers = [NSMutableArray new];
+    for (NSString *uuid in _dbDataDict) {
+        if (requestedUuid && ![requestedUuid isEqualToString:uuid]) {
+            os_log_info(AUTHD_LOG, "Requested volume %{public}@ so ignoring volume %{public}@", requestedUuid, uuid);
+            continue;
+        }
+        [allUsers addObjectsFromArray:_dbDataDict[uuid]];
+    }
+    return allUsers;
+}
+#pragma mark - Private Methods
+
+- (void)processPrebootVolumes:(NSArray*)prebootVolumes currentRecoveryVolumeUUID:(NSUUID *)currentRecoveryVolumeUUID
+{
+    // process each preboot volume
+    for (id prebootVolume in prebootVolumes) {
+
+        // mount the preboot volume. If it fails it could be already mounted. Try to get mountPoint anyway.
+        Boolean mounted = [self mountPrebootVolume:prebootVolume];
+
+        // get a mount point of the preboot volume
+        NSString* mountPoint = [self mountPointForPrebootVolume:prebootVolume];
+        if (!mountPoint) {
+            continue;
+        }
+
+        // process the preboot volume
+        NSDirectoryEnumerator *dirEnumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:mountPoint isDirectory:YES] includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants errorHandler:nil];
+        for (NSURL *url in dirEnumerator) {
+            BOOL isDir = NO;
+            [[NSFileManager defaultManager] fileExistsAtPath:url.path isDirectory:&isDir];
+            if (!isDir) {
+                os_log_info(AUTHD_LOG, "Skipping file %{public}@ (not a directory)", url.path);
+                continue;
+            }
+
+            NSUUID* volumeUUID =  [[NSUUID alloc] initWithUUIDString:url.lastPathComponent]; // the dir has the name as UUID
+            if (!volumeUUID) {
+                os_log_info(AUTHD_LOG, "Ignoring folder %{public}@ (not UUID)", url);
+                continue;
+            }
+
+            if (currentRecoveryVolumeUUID && ![currentRecoveryVolumeUUID isEqualTo:volumeUUID]) {
+                os_log_info(AUTHD_LOG, "The preboot volume skipped: %{public}@ (not the currentRecoveryVolumeUUID %{public}@)", url, currentRecoveryVolumeUUID);
+                continue;
+            }
+
+            [self processVolumeData:volumeUUID mountPoint:mountPoint];
+        }
+
+        // unmount the preboot volume
+        if (mounted) {
+            [self unmountPrebootVolume:prebootVolume];
+        }
+    }
+}
+
+#define kEFISystemVolumeUUIDVariableName "SystemVolumeUUID"
+- (NSUUID *)currentRecoveryVolumeUUID
+{
+    NSData *data;
+    NSString * const LANVRAMNamespaceStartupManager = @"5EEB160F-45FB-4CE9-B4E3-610359ABF6F8";
+    
+    NSString *key = [NSString stringWithFormat:@"%@:%@", LANVRAMNamespaceStartupManager, @kEFISystemVolumeUUIDVariableName];
+    
+    io_registry_entry_t match = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
+    if (match)  {
+        CFTypeRef entry = IORegistryEntryCreateCFProperty(match, (__bridge CFStringRef)key, kCFAllocatorDefault, 0);
+        IOObjectRelease(match);
+        
+        if (entry)
+        {
+            if (CFGetTypeID(entry) == CFDataGetTypeID())
+                data = CFBridgingRelease(entry);
+            else
+                CFRelease(entry);
+        }
+    }
+    os_log_info(AUTHD_LOG, "Current boot volume: %{public}@", data);
+    
+    if (data) {
+        return [[NSUUID alloc] initWithUUIDBytes:data.bytes];
+    } else {
+        return nil;
+    }
+}
+
+- (NSArray *)allPrebootVolumes
+{
+    NSMutableArray* result = [NSMutableArray new];
+
+    DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
+
+    for (id tmp in _diskMgr.disks) {
+        DADiskRef diskRef = (__bridge DADiskRef)(tmp);
+        os_log_info(AUTHD_LOG, "Found disk %{public}@", diskRef);
+        
+        BOOL preboot;
+        DMDiskErrorType diskErr = [dmAPFS isPrebootVolume:diskRef prebootRole:&preboot];
+        if (diskErr) {
+            os_log(AUTHD_LOG, "Failed to determine preboot state for %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
+            continue;
+        }
+        if (!preboot) {
+            os_log_info(AUTHD_LOG, "Not a preboot volume: %{public}@", diskRef);
+            continue;
+        }
+
+        id prebootVolume = CFBridgingRelease([_diskMgr copyBooterDiskForDisk:diskRef error:&diskErr]);
+        if (prebootVolume) {
+            os_log_info(AUTHD_LOG, "Found APFS preboot %{public}@", prebootVolume);
+            [result addObject:prebootVolume];
+        } else {
+            os_log_error(AUTHD_LOG, "Failed to copy preboot for disk %{public}@, err: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
+        }
+    }
+
+    return result;
+}
+
+- (BOOL)mountPrebootVolume:(id)preboot
+{
+    __block BOOL success = NO;
+    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
+    AIRDBDACommonCompletionHandler completionHandler = ^(DADissenterRef dissenter) {
+        success = (dissenter == NULL);
+        if (dissenter != NULL) {
+            os_log(AUTHD_LOG, "Failed to mount preboot volume %{public}@ (status: 0x%x, reason: \"%{public}@\").", preboot, soft_DADissenterGetStatus(dissenter), soft_DADissenterGetStatusString(dissenter));
+        }
+        dispatch_semaphore_signal(sem);
+    };
+    soft_DADiskMount((__bridge DADiskRef _Nonnull)(preboot), NULL, kDADiskMountOptionDefault, _commonDACompletionCallback, (__bridge void * _Nullable)(completionHandler));
+    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+    return success;
+}
+
+- (NSString *)mountPointForPrebootVolume:(id)preboot
+{
+    DMDiskErrorType diskErr;
+    NSString* result = [_diskMgr mountPointForDisk:(__bridge DADiskRef _Nonnull)(preboot) error:&diskErr];
+    if (result) {
+        os_log_info(AUTHD_LOG, "Mounted preboot partition %{public}@ at %{public}@", preboot, result);
+    } else {
+        os_log_error(AUTHD_LOG, "Failed to get preboot mount point: %{public}@", soft_DMUnlocalizedTechnicalErrorString(diskErr));
+    }
+    return result;
+}
+
+- (void)unmountPrebootVolume:(id)preboot
+{
+    soft_DADiskUnmount((__bridge DADiskRef _Nonnull)(preboot), kDADiskUnmountOptionDefault, nil, nil);
+    os_log_info(AUTHD_LOG, "Preboot partition unmounted: %{public}@", preboot);
+}
+
+- (NSString *)deviceNodeForVolumeWithUUID:(NSUUID *)volumeUuid diskRef:(DADiskRef *)diskRef
+{
+    DMDiskErrorType diskErr;
+    DADiskRef localDiskRef = [_diskMgr copyDiskForVolumeUUID:volumeUuid.UUIDString error:&diskErr];
+    if (!localDiskRef) {
+        os_log_error(AUTHD_LOG, "Failed to find disk with volume %{public}@: %{public}@", volumeUuid, soft_DMUnlocalizedTechnicalErrorString(diskErr));
+        return nil;
+    }
+    if (diskRef) {
+        *diskRef = localDiskRef;
+        CFRetain(*diskRef);
+    }
+    os_log_info(AUTHD_LOG, "Found disk %{public}@ with volume UUID %{public}@", localDiskRef, volumeUuid);
+    NSString* deviceNode = [self deviceNodeForDisk:localDiskRef];
+    CFRelease(localDiskRef);
+    return deviceNode;
+}
+
+- (NSString *)deviceNodeForDisk:(DADiskRef)diskRef
+{
+    DMDiskErrorType diskErr;
+    NSString *deviceNode = [_diskMgr deviceNodeForDisk:diskRef error:&diskErr];
+    if (!deviceNode) {
+        os_log_error(AUTHD_LOG, "Failed to find device node for disk %{public}@: %{public}@", diskRef, soft_DMUnlocalizedTechnicalErrorString(diskErr));
+        return nil;
+    }
+    os_log_info(AUTHD_LOG, "Device node found: %{public}@", deviceNode);
+    return deviceNode;
+}
+
+- (NSData *)loadVEKforVolumeWithUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
+{
+    NSString *vekPath = [NSString stringWithFormat:kVekFile, mountPoint, volumeUuid.UUIDString];
+    NSDictionary *vekDict = [NSDictionary dictionaryWithContentsOfFile:vekPath];
+    NSData *vek = vekDict[kVekItemName];
+    if (!vek) {
+        os_log_error(AUTHD_LOG, "Failed to load DiskToken from %{public}@", vekPath);
+        return nil;
+    }
+    os_log_info(AUTHD_LOG, "Loaded DiskToken from %{public}@", vekPath);
+    
+    return vek;
+}
+
+- (NSData *)loadKEKforUuid:(NSString *)userUuid deviceNode:(NSString *)deviceNode
+{
+    NSUUID *nsUuid = [[NSUUID alloc] initWithUUIDString:userUuid];
+    uuid_t uuid;
+    [nsUuid getUUIDBytes:uuid];
+    CFDataRef dataCF;
+    errno_t err = soft_APFSVolumeGetUnlockRecord(deviceNode.UTF8String, uuid, &dataCF);
+    if(err != 0) {
+        os_log_error(AUTHD_LOG, "Failed to find SecureToken on device node %{public}@ and UUID %{public}@ (%d)", deviceNode, userUuid, err);
+        return nil;
+    }
+    os_log_info(AUTHD_LOG, "Loaded SecureToken from device node %{public}@", deviceNode);
+    
+    NSData *kek = CFBridgingRelease(dataCF);
+    return kek;
+}
+
+- (NSDictionary *)loadUserDatabaseForVolumeUUID:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
+{
+    NSString *usersPath = [NSString stringWithFormat:kUsersFile, mountPoint, volumeUuid.UUIDString];
+    NSDictionary *users = [NSDictionary dictionaryWithContentsOfFile:usersPath];
+    if (users.count == 0) {
+        os_log_error(AUTHD_LOG, "Failed to find user records in file %{public}@", usersPath);
+        return nil;
+    }
+    os_log_debug(AUTHD_LOG, "Loaded %lu user records from file %{public}@", (unsigned long)users.count, usersPath);
+    return users;
+}
+
+- (void)processVolumeData:(NSUUID *)volumeUuid mountPoint:(NSString *)mountPoint
+{
+    os_log_info(AUTHD_LOG, "Processing volume data: %{public}@", volumeUuid);
+    NSData *vek = [self loadVEKforVolumeWithUUID:volumeUuid mountPoint:mountPoint];
+    if (!vek) {
+        return;
+    }
+
+    DADiskRef cfDiskRef = NULL;
+    NSString* deviceNode = [self deviceNodeForVolumeWithUUID:volumeUuid diskRef:&cfDiskRef];
+    id diskRef = CFBridgingRelease(cfDiskRef);
+    if (!deviceNode) {
+        return;
+    }
+    NSString *volumeGroupUuid;
+    DMAPFS* dmAPFS = [[getDMAPFSClass() alloc] initWithManager:_diskMgr];
+    DMDiskErrorType diskErr = [dmAPFS volumeGroupForVolume:(__bridge DADiskRef _Nonnull)(diskRef) id:&volumeGroupUuid];
+    if (diskErr != kDiskErrorNoError || volumeGroupUuid == nil) {
+        os_log_error(AUTHD_LOG, "Error %d while trying to get volume group for %{public}@", diskErr, volumeUuid);
+    } else {
+           if ([volumeUuid.UUIDString isEqualTo:volumeGroupUuid]) {
+                   NSArray *systemVolumeDisks = nil;
+                   diskErr = [dmAPFS disksForVolumeGroup:volumeGroupUuid volumeDisks:nil systemVolumeDisks:&systemVolumeDisks dataVolumeDisks:nil userVolumeDisks:nil container:nil];
+                   if (diskErr != kDiskErrorNoError || systemVolumeDisks == nil) {
+                           os_log_error(AUTHD_LOG, "Error %d while trying to get volume group disks for %{public}@", diskErr, volumeGroupUuid);
+                   } else {
+                           // There should be only one systemVolume, but the API returns an array so we'll process as many as it wants to give us
+                           for (id tmp in systemVolumeDisks) {
+                                   DADiskRef systemVolumeDiskRef = (__bridge DADiskRef)(tmp);
+                                   NSString *systemVolumeUuid = nil;
+                                   diskErr = [dmAPFS volumeUUIDForVolume:systemVolumeDiskRef UUID:&systemVolumeUuid];
+                                   if (diskErr != kDiskErrorNoError || systemVolumeUuid == nil) {
+                                           os_log_error(AUTHD_LOG, "Error %d while trying to get volume uuid disks for some system volumes of group %{public}@", diskErr, volumeGroupUuid);
+                                   } else {
+                                           os_log(AUTHD_LOG, "Volume %{public}@ belongs to the group %{public}@", systemVolumeUuid, volumeGroupUuid);
+                                           _dbVolumeGroupMap[systemVolumeUuid] = volumeGroupUuid;
+                                   }
+                           }
+                   }
+           }
+    }
+
+    NSDictionary *users = [self loadUserDatabaseForVolumeUUID:volumeUuid mountPoint:mountPoint];
+    for (NSString *userName in users) {
+        NSDictionary *userData = users[userName];
+        os_log_debug(AUTHD_LOG, "Processing user: %{public}@", userData);
+        NSString *userGuid = userData[kGUIDItemName];
+        if (userGuid == nil) {
+            os_log_error(AUTHD_LOG, "Failed to find GUID for user %{public}@", userName);
+            continue;
+        }
+        NSData* kek = [self loadKEKforUuid:userGuid deviceNode:deviceNode];
+        if (!kek) {
+            os_log_error(AUTHD_LOG, "Failed to find SecureToken for user %{public}@", userName);
+            continue;
+        }
+        
+        NSArray *aauthority = userData[kAuthenticationAuthority];
+        NSMutableDictionary *dict = @{}.mutableCopy;
+        if (aauthority) {
+            dict[@PLUDB_SCPAIR] = aauthority;
+            os_log_debug(AUTHD_LOG, "Using authority: %{public}@", aauthority);
+        }
+        
+        Boolean owner;
+        struct aks_fv_param_s params = {};
+        aks_fv_blob_state_s verifier_state = {};
+        struct aks_fv_data_s kekData = { .data = (void *)kek.bytes, .len = kek.length };
+
+        int res = aks_fv_get_blob_state(&params, &kekData, &verifier_state);
+        if (res) {
+            os_log_error(AUTHD_LOG, "Blob state failed: %x", res);
+            owner = NO;
+        } else {
+            owner = ((verifier_state.flags & aks_fv_state_is_owner) == aks_fv_state_is_owner);
+        }
+        
+        dict[@PLUDB_USERNAME] = userName;
+        dict[@PLUDB_GUID] = userGuid;
+        dict[@PLUDB_ADMIN] = userData[kIsAdmintemName];
+        dict[@PLUDB_KEK] = kek;
+        dict[@PLUDB_VEK] = vek;
+        dict[@PLUDB_DNODE] = deviceNode;
+        dict[@PLUDB_OWNER] = @(owner);
+
+        if ([userData.allKeys containsObject:kSCUnlockDataItemName]) {
+            dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCUnlockDataItemName];
+        }
+        if ([userData.allKeys containsObject:kSCEnforcementItemName]) {
+            dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCEnforcementItemName];
+        }
+        if ([userData.allKeys containsObject:kSCUnlockDataItemName]) {
+            dict[@PLUDB_SCUNLOCK_DATA] = userData[kSCUnlockDataItemName];
+        }
+        if ([userData.allKeys containsObject:kSCUacItemName]) {
+            dict[@PLUDB_SCUAC] = userData[kSCUacItemName];
+        }
+        if ([userData.allKeys containsObject:kLongNameItemName]) {
+            dict[@PLUDB_LUSERNAME] = userData[kLongNameItemName];
+        }
+        
+        NSMutableArray *array = _dbDataDict[volumeUuid.UUIDString];
+        if (array == nil) {
+            array = [NSMutableArray new];
+            if (!array) {
+                os_log_error(AUTHD_LOG, "Failed to create users array");
+                return;
+            }
+            _dbDataDict[volumeUuid.UUIDString] = array;
+        }
+        
+        os_log_info(AUTHD_LOG, "Prelogin UserDB added entry: %{public}@", dict);
+        [array addObject:dict];
+    }
+}
+
+@end
+
+OSStatus preloginudb_copy_userdb(const char *uuid, UInt32 flags, CFArrayRef *output)
+{
+    if (!output) {
+        return errAuthorizationBadAddress;
+    }
+    static PreloginUserDb *database;
+    static OSStatus loadError = errAuthorizationSuccess;
+    static dispatch_once_t onceToken;
+    
+    dispatch_once(&onceToken, ^{
+        
+        os_log_info(AUTHD_LOG, "Going to load User DB");
+
+        database = [[PreloginUserDb alloc] init];
+        if (!database) {
+            loadError = errAuthorizationInvalidSet;
+        } else {
+            NSError *error;
+            if ([database loadWithError:&error]) {
+                loadError = (int)error.code;
+            }
+        }
+    });
+    
+    if (loadError) {
+        return loadError;
+    }
+    
+    os_log_debug(AUTHD_LOG, "Processing user db for volume %{public}s with flags %d", uuid, flags);
+
+    *output = CFBridgingRetain([database users:uuid ? [NSString stringWithUTF8String:uuid]  : nil]);
+    return errAuthorizationSuccess;
+}
index 7ef4f57c7622eb871b025d425d6ff731e3f5e22d..e73d99365c23a5cb40fbfe8092f35aece2f57adc 100644 (file)
@@ -2,9 +2,13 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+       <key>com.apple.keystore.console</key>
+       <true/>
        <key>com.apple.private.LocalAuthentication.ExtractCredential</key>
        <true/>
-       <key>com.apple.keystore.console</key>
+       <key>com.apple.private.security.clear-library-validation</key>
+       <true/>
+       <key>com.apple.keystore.filevault</key>
        <true/>
 </dict>
 </plist>
index 4fc95b64c7c4e514b38c9b9f75699563ac50923d..6d72a97c5c353b97ec893b54441d5b1ac62c3dc9 100644 (file)
@@ -106,7 +106,9 @@ enum {
     AUTHORIZATION_DISMISS,
     AUTHORIZATION_SETUP,
     AUTHORIZATION_ENABLE_SMARTCARD,
-       AUTHORIZATION_PREAUTHORIZE_CREDENTIALS
+       AUTHORIZATION_PREAUTHORIZE_CREDENTIALS,
+    AUTHORIZATION_COPY_PRELOGIN_USERDB,
+    AUTHORIZATION_COPY_RIGHT_PROPERTIES
 };
     
 #if defined(__cplusplus)
index c10ce840bd8c56cc43fca6d9920cb07423673d51..959fc8177834f993f6dd547ba2f0104b3dc729ce 100644 (file)
@@ -943,13 +943,18 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_
         if (version_check) {
             if (rule_get_id(rule) != 0) { // rule already exists see if we need to update
                 rule_t current = rule_create_with_string(rule_get_name(rule), dbconn);
-                if (rule_get_version(rule) > rule_get_version(current)) {
+                int64_t currVer = rule_get_version(current);
+                int64_t newVer = rule_get_version(rule);
+
+                if (newVer > currVer) {
                     update = true;
                 }
                 CFReleaseSafe(current);
                 
                 if (!update) {
                     continue;
+                } else {
+                    os_log(AUTHD_LOG, "authdb: right %{public}s new version %lld vs existing version %lld, will update", rule_get_name(rule), newVer, currVer);
                 }
             }
         }
@@ -977,7 +982,7 @@ _import_rules(authdb_connection_t dbconn, CFMutableArrayRef rules, bool version_
         
         if (!delayCommit) {
             bool success = rule_sql_commit(rule, dbconn, now, NULL);
-            os_log_debug(AUTHD_LOG, "authdb: %{public}s %{public}s %{public}s %{public}s",
+            os_log(AUTHD_LOG, "authdb: %{public}s %{public}s %{public}s %{public}s",
                  update ? "updating" : "importing",
                  rule_get_type(rule) == RT_RULE ? "rule" : "right",
                  rule_get_name(rule), success ? "success" : "FAIL");
index ea49287ad8ca864d148488dca7f5763fe5554833..4e5945f022c5313360153dddcdb0f0f600c07bb5 100644 (file)
@@ -6,9 +6,12 @@
 
 #include "authutilities.h"
 #include <Security/AuthorizationTags.h>
+#include <Security/AuthorizationTagsPriv.h>
 #include <dispatch/private.h>
 #include <CommonCrypto/CommonCrypto.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 AUTHD_DEFINE_LOG
 
 typedef struct _auth_item_s * auth_item_t;
@@ -48,7 +51,7 @@ auth_item_copy_auth_item_xpc(auth_item_t item)
     xpc_dictionary_set_string(xpc_data, AUTH_XPC_ITEM_NAME, item->data.name);
     if (item->data.value) {
         // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
-        bool sensitive = strcmp(item->data.name, "password") == 0;
+        bool sensitive = strcmp(item->data.name, AGENT_PASSWORD) == 0;
         if (sensitive) {
             vm_address_t vmBytes = 0;
             size_t xpcOutOfBandBlockSize = (item->data.valueLength > 32768 ? item->data.valueLength : 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
index 4377483756bd3fc865206fa8273cf52c142ea889..4236dff67813d359bddee7ce1b9f75f04b34d1b3 100644 (file)
@@ -578,14 +578,17 @@ See remaining rules for examples.
                </dict>
                <key>com.apple.trust-settings.admin</key>
                <dict>
-                       <key>allow-root</key>
-                       <true/>
-                       <key>class</key>
-                       <string>user</string>
                        <key>comment</key>
-                       <string>For modifying Trust Settings in the Local Admin domain.</string>
-                       <key>group</key>
-                       <string>admin</string>
+                       <string>For modifying Trust Settings in the Admin domain. Requires entitlement or admin authentication.</string>
+                       <key>class</key>
+                       <string>rule</string>
+                       <key>k-of-n</key>
+                       <integer>1</integer>
+                       <key>rule</key>
+                       <array>
+                               <string>entitled</string>
+                               <string>authenticate-admin</string>
+                       </array>
                </dict>
                <key>com.apple.trust-settings.user</key>
                <dict>
@@ -596,10 +599,14 @@ See remaining rules for examples.
                </dict>
                <key>com.apple.uninstalld.uninstall</key>
                <dict>
+                       <key>authenticate-user</key>
+                       <false/>
                        <key>class</key>
-                       <string>rule</string>
-                       <key>rule</key>
-                       <string>entitled-admin-or-authenticate-admin</string>
+                       <string>user</string>
+                       <key>entitled</key>
+                       <true/>
+                       <key>version</key>
+                       <integer>1</integer>
                </dict>
                <key>config.add.</key>
                <dict>
@@ -675,6 +682,23 @@ See remaining rules for examples.
                        <key>comment</key>
                        <string>For burning media.</string>
                </dict>
+               <key>com.apple.installassistant.requestpassword</key>
+               <dict>
+                       <key>authenticate-user</key>
+                       <true/>
+                       <key>class</key>
+                       <string>user</string>
+                       <key>comment</key>
+                       <string>Authenticate as an administrator, password only.</string>
+                       <key>group</key>
+                       <string>admin</string>
+                       <key>password-only</key>
+                       <true/>
+                       <key>shared</key>
+                       <false/>
+                       <key>timeout</key>
+                       <integer>0</integer>
+               </dict>
                <key>system.csfde.requestpassword.weak</key>
                <dict>
                        <key>class</key>
@@ -825,7 +849,7 @@ See remaining rules for examples.
                        <key>class</key>
                        <string>rule</string>
                        <key>comment</key>
-                       <string>Checked when user is installing Apple-provided software.</string>
+                       <string>Checked when user is installing Apple software.</string>
                        <key>rule</key>
                        <string>root-or-entitled-admin-or-authenticate-admin</string>
                </dict>
@@ -914,6 +938,7 @@ See remaining rules for examples.
                        <key>mechanisms</key>
                        <array>
                                <string>builtin:policy-banner</string>
+                               <string>builtin:prelogin</string>
                                <string>loginwindow:login</string>
                                <string>builtin:login-begin</string>
                                <string>builtin:reset-password,privileged</string>
@@ -931,7 +956,24 @@ See remaining rules for examples.
                                <string>loginwindow:done</string>
                        </array>
                        <key>version</key>
-                       <integer>7</integer>
+                       <integer>8</integer>
+               </dict>
+               <key>system.login.filevault</key>
+               <dict>
+                       <key>class</key>
+                       <string>evaluate-mechanisms</string>
+                       <key>comment</key>
+                       <string>Login mechanism based rule for Filevault.</string>
+                       <key>mechanisms</key>
+                       <array>
+                               <string>builtin:policy-banner</string>
+                               <string>loginwindow:login</string>
+                               <string>builtin:login-begin</string>
+                               <string>builtin:authenticate,privileged</string>
+                               <string>builtin:login-success</string>
+                               <string>loginwindow:success</string>
+                               <string>loginwindow:done</string>
+                       </array>
                </dict>
                <key>system.login.fus</key>
                <dict>
@@ -1601,6 +1643,36 @@ See remaining rules for examples.
                        <key>version</key>
                        <integer>1</integer>
                </dict>
+               <key>com.apple.configurationprofiles.deviceenrollment.install</key>
+               <dict>
+                       <key>class</key>
+                       <string>user</string>
+                       <key>comment</key>
+                       <string>This right is used by UserManagement to ask for an admin password.</string>
+                       <key>group</key>
+                       <string>admin</string>
+                       <key>password-only</key>
+                       <true/>
+                       <key>shared</key>
+                       <false/>
+                       <key>version</key>
+                       <integer>1</integer>
+               </dict>
+               <key>com.apple.configurationprofiles.deviceenrollment.uninstall</key>
+               <dict>
+                       <key>class</key>
+                       <string>user</string>
+                       <key>comment</key>
+                       <string>This right is used by UserManagement to ask for an admin password.</string>
+                       <key>group</key>
+                       <string>admin</string>
+                       <key>password-only</key>
+                       <true/>
+                       <key>shared</key>
+                       <false/>
+                       <key>version</key>
+                       <integer>1</integer>
+               </dict>
                <key>com.apple.safaridriver.allow</key>
                <dict>
                        <key>comment</key>
@@ -1692,7 +1764,29 @@ See remaining rules for examples.
                        <key>shared</key>
                        <false/>
                </dict>
-       </dict>
+        <key>com.apple.system-migration.launch</key>
+        <dict>
+            <key>comment</key>
+            <string>Used by Migration Assistant.</string>
+            <key>class</key>
+            <string>rule</string>
+            <key>rule</key>
+            <string>authenticate-admin-nonshared</string>
+            <key>shared</key>
+            <false/>
+        </dict>
+        <key>com.apple.system-migration.cleanup</key>
+        <dict>
+            <key>comment</key>
+            <string>Used by System Migration.</string>
+            <key>class</key>
+            <string>rule</string>
+            <key>rule</key>
+            <string>authenticate-admin-nonshared</string>
+            <key>shared</key>
+            <false/>
+        </dict>
+    </dict>
        <key>rules</key>
        <dict>
                <key>admin</key>
@@ -1741,8 +1835,9 @@ See remaining rules for examples.
                                <string>builtin:authenticate</string>
                                <string>builtin:reset-password,privileged</string>
                                <string>builtin:authenticate,privileged</string>
-                               <string>PKINITMechanism:auth,privileged</string>
                        </array>
+                       <key>version</key>
+                       <integer>1</integer>                    
                </dict>
                <key>kcunlock</key>
                <dict>
index 611d44150277d906c8d25ac268e14199c5405428..b39d393c33ffa6bece4723c84a060d0a6dcfd4ce 100644 (file)
@@ -13,6 +13,8 @@
 #include <Security/SecBase.h>
 #include <sandbox.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 AUTHD_DEFINE_LOG
 
 static Boolean AuthTokenEqualCallBack(const void *value1, const void *value2)
index 60b6b2fdfb54f8cfe390d8175eec93ef51b78be4..3bcd2c0ca3cf83603da478fca5ebff12aef68b7b 100644 (file)
@@ -5,7 +5,6 @@
 #include "debugging.h"
 
 #include <AssertMacros.h>
-#include <assert.h>
 
 AUTHD_DEFINE_LOG
 
@@ -23,6 +22,11 @@ SerializeItemSet(const AuthorizationItemSet * itemSet)
         xpc_object_t item = xpc_dictionary_create(NULL, NULL, 0);
         require(item != NULL, done);
         
+        if (itemSet->items[i].name == NULL) {
+            os_log_error(AUTHD_LOG, "ItemSet - item #%d name is NULL", i);
+            xpc_release(item);
+            continue;
+        }
         xpc_dictionary_set_string(item, AUTH_XPC_ITEM_NAME, itemSet->items[i].name);
         xpc_dictionary_set_uint64(item, AUTH_XPC_ITEM_FLAGS, itemSet->items[i].flags);
         xpc_dictionary_set_data(item, AUTH_XPC_ITEM_VALUE, itemSet->items[i].value, itemSet->items[i].valueLength);
@@ -305,3 +309,9 @@ done:
     free_safe(values);
     return result;
 }
+
+bool isInLWOS()
+{
+    // temporary solution until we find a better way
+    return getenv("__OSINSTALL_ENVIRONMENT") != NULL;
+}
index ebe1e5a4e94abe064b516e5c1eef9a4ca82cc2f4..981b9beff2477bf638ad2f31aa481f51ae76fbc8 100644 (file)
@@ -26,7 +26,9 @@ void * _copy_data(const void * data, size_t dataLen);
 bool _cf_set_iterate(CFSetRef, bool(^iterator)(CFTypeRef value));
 bool _cf_bag_iterate(CFBagRef, bool(^iterator)(CFTypeRef value));
 bool _cf_dictionary_iterate(CFDictionaryRef, bool(^iterator)(CFTypeRef key,CFTypeRef value));
-    
+
+bool isInLWOS(void);
+
 #if defined(__cplusplus)
 }
 #endif
index 5b94ca8a289ba8c8e3caed313c64559d1eb97d46..0c17b4d6ba5eb13690ce7d1bd2c978fede6a85df 100644 (file)
@@ -27,7 +27,9 @@
        (global-name "com.apple.security.authhost")
        (global-name "com.apple.SecurityServer")
        (global-name "com.apple.system.opendirectoryd.api")
-       (global-name "com.apple.ocspd"))
+       (global-name "com.apple.ocspd")
+       (global-name "com.apple.DiskArbitration.diskarbitrationd")
+       (global-name "com.apple.diskmanagementd"))
 
 (allow ipc-posix-shm
        (ipc-posix-name "apple.shm.notification_center")
@@ -40,3 +42,7 @@
        (preference-domain "com.apple.authd"))
 
 (allow system-audit system-sched)
+
+(allow iokit-open 
+       (iokit-user-client-class "AppleAPFSUserClient")
+       (iokit-user-client-class "AppleKeyStoreUserClient"))
index 85184384066f70647f3d4b9fed12698d50826585..fab34a2c4402eecbeadbacfb00944ae64df42ec1 100644 (file)
@@ -19,7 +19,7 @@ crc64_init()
 AUTH_INLINE uint64_t
 crc64_final(uint64_t crc)
 {
-      return crc ^= xorout;
+      return crc ^ xorout;
 }
     
 AUTH_INLINE AUTH_NONNULL_ALL uint64_t
index 6fd46fc04b932ff919b26f14aabfe093fcc6b753..24c0f67358d7b6b83c832d71c5275d7704d55549 100644 (file)
@@ -2,6 +2,8 @@
 
 #include "credential.h"
 #include "authutilities.h"
+#include "authitems.h"
+#include <Security/AuthorizationTagsPriv.h>
 #include "debugging.h"
 #include "crc.h"
 
@@ -101,7 +103,7 @@ static credential_t
 _credential_create()
 {
     credential_t cred = NULL;
-    
+
     cred = (credential_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, credential_get_type_id(), AUTH_CLASS_SIZE(credential), NULL);
     require(cred != NULL, done);
     
@@ -141,6 +143,23 @@ done:
     return cred;
 }
 
+credential_t
+credential_create_lwos(auth_items_t context, bool session)
+{
+    credential_t cred = NULL;
+    
+    cred = _credential_create();
+    require(cred != NULL, done);
+
+    const char *username = session ? "system session" : auth_items_get_string(context, AGENT_USERNAME);
+    cred->uid = session ? 0 : -500;
+    cred->name = _copy_string(username);
+    cred->realName = _copy_string(username);
+    cred->valid = false;
+done:
+    return cred;
+}
+
 credential_t
 credential_create_with_credential(credential_t srcCred, bool shared)
 {
@@ -220,9 +239,14 @@ credential_is_right(credential_t cred)
 }
 
 bool
-credential_check_membership(credential_t cred,const char* group)
+credential_check_membership(credential_t cred, const char* group)
 {
     bool result = false;
+    
+    if (isInLWOS()) {
+       return false; // cannot succeed in LWOS as we do not have group data
+    }
+    
     CFStringRef cachedGroup = NULL;
     require(group != NULL, done);
     require(cred->uid != 0 || cred->uid != (uid_t)-2, done);
index 1f7576e786967b8fed29ffee63eeb72d7b34e625..fd283e449e5e489e67d659c77eafde2578767c79 100644 (file)
@@ -20,6 +20,9 @@ credential_t credential_create_with_credential(credential_t,bool);
 AUTH_WARN_RESULT AUTH_MALLOC AUTH_NONNULL_ALL AUTH_RETURNS_RETAINED    
 credential_t credential_create_with_right(const char *);
 
+AUTH_WARN_RESULT AUTH_MALLOC AUTH_RETURNS_RETAINED
+credential_t credential_create_lwos(auth_items_t context, bool session);
+
 AUTH_NONNULL_ALL
 uid_t credential_get_uid(credential_t);
 
index 7df8370caa2f7b3eaca73797b0b78d9fa6be1d2c..08a4f80e07c6d45af0961db3de1e32d4ef50b63a 100644 (file)
@@ -37,8 +37,8 @@ static void _set_auth_token_hints(auth_items_t, auth_items_t, auth_token_t);
 static OSStatus _evaluate_user_credential_for_rule(engine_t, credential_t, rule_t, bool, bool, enum Reason *);
 static void _engine_set_credential(engine_t, credential_t, bool);
 static OSStatus _evaluate_rule(engine_t, rule_t, bool *);
-static bool _preevaluate_class_rule(engine_t engine, rule_t rule);
-static bool _preevaluate_rule(engine_t engine, rule_t rule);
+static bool _preevaluate_class_rule(engine_t engine, rule_t rule, const char **group);
+static bool _preevaluate_rule(engine_t engine, rule_t rule, const char **group);
 
 static uint64_t global_engine_count;
 
@@ -65,7 +65,6 @@ struct _engine_s {
     auth_rights_t grantedRights;
     
        CFTypeRef la_context;
-       bool preauthorizing;
 
     enum Reason reason;
     int32_t tries;
@@ -156,14 +155,16 @@ engine_create(connection_t conn, auth_token_t auth)
     
     engine->reason = noReason;
 
-       engine->preauthorizing = false;
-
        engine->la_context = NULL;
     
     engine->now = CFAbsoluteTimeGetCurrent();
     
     session_update(auth_token_get_session(engine->auth));
-    engine->sessionCredential = credential_create(session_get_uid(auth_token_get_session(engine->auth)));
+    if (isInLWOS()) {
+        engine->sessionCredential = credential_create_lwos(NULL, true);
+    } else {
+        engine->sessionCredential = credential_create(session_get_uid(auth_token_get_session(engine->auth)));
+    }
     engine->credentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
     engine->effectiveCredentials = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
     
@@ -313,6 +314,27 @@ _evaluate_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, b
     }
 }
 
+static bool _is_lwos_user_in_group(engine_t engine, rule_t rule)
+{
+    if (!isInLWOS()) {
+        return false;
+    }
+    
+    const char *group = rule_get_group(rule);
+    if (!(group && strcmp(group, "admin") == 0)) {
+        os_log_error(AUTHD_LOG, "Group %{public}s not supported in FV mode (engine %lld)", group, engine->engine_index);
+        return false;
+    }
+
+    const char *data = auth_items_get_string(engine->context, kAuthorizationFVAdmin);
+    if (!data) {
+        os_log_error(AUTHD_LOG, "User is not member of the group %{public}s (engine %lld)", group, engine->engine_index);
+        return false;
+    }
+    
+    return (strcmp(data, "1") == 0);
+}
+
 static OSStatus
 _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t rule, bool ignoreShared, bool sessionOwner, enum Reason * reason)
 {
@@ -329,7 +351,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru
         return errAuthorizationDenied;
     }
 
-    if (credential_get_valid(cred) != true) {
+    if (credential_get_valid(cred) != true && !isInLWOS()) {
         os_log(AUTHD_LOG, "%{public}s %i invalid (does NOT satisfy rule) (engine %lld)", cred_label, credential_get_uid(cred), engine->engine_index);
         if (reason) {  *reason = invalidPassphrase; }
         return errAuthorizationDenied;
@@ -376,7 +398,7 @@ _evaluate_user_credential_for_rule(engine_t engine, credential_t cred, rule_t ru
                 }
             }
             
-            if (credential_check_membership(cred, rule_get_group(rule))) {
+            if (credential_check_membership(cred, rule_get_group(rule)) || _is_lwos_user_in_group(engine, rule)) {
                 os_log(AUTHD_LOG, "%{public}s %i is member of group %{public}s (does satisfy rule) (engine %lld)", cred_label, credential_get_uid(cred), rule_get_group(rule), engine->engine_index);
                 return errAuthorizationSuccess;
             } else {
@@ -651,11 +673,16 @@ done:
 static OSStatus
 _evaluate_authentication(engine_t engine, rule_t rule)
 {
+    os_log_debug(AUTHD_LOG, "engine %lld: FV mode %d", engine->engine_index, isInLWOS());
+
     OSStatus status = errAuthorizationDenied;
     ccaudit_t ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthint);
     os_log_debug(AUTHD_LOG, "engine %lld: evaluate authentication", engine->engine_index);
     _set_rule_hints(engine->hints, rule);
-    _set_session_hints(engine, rule);
+    if (!isInLWOS()) {
+        // we do not need to set hints in LWOS as we do not know which user will be authenticated
+        _set_session_hints(engine, rule);
+    }
 
     CFArrayRef mechanisms = rule_get_mechanisms(rule);
     if (!(CFArrayGetCount(mechanisms) > 0)) {
@@ -684,10 +711,14 @@ _evaluate_authentication(engine_t engine, rule_t rule)
             status = errAuthorizationDenied;
             
             credential_t newCred = NULL;
-            if (auth_items_exist(engine->context, "uid")) {
-                newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
+
+            if (isInLWOS() && auth_items_exist(engine->context, kAuthorizationFVAdmin)) {
+                os_log_debug(AUTHD_LOG, "Credentials for FV unlock (engine %lld)", engine->engine_index);
+                newCred = credential_create_lwos(engine->context, false);
+            } else if (auth_items_exist(engine->context, AGENT_CONTEXT_UID)) {
+                newCred = credential_create(auth_items_get_uint(engine->context, AGENT_CONTEXT_UID));
             } else {
-                os_log_info(AUTHD_LOG, "Mechanism failed to return a valid uid (engine %lld)", engine->engine_index);
+                os_log_error(AUTHD_LOG, "Mechanism failed to return a valid UID (engine %lld)", engine->engine_index);
                                if (engine->la_context) {
                                        // sheet failed so remove sheet reference and next time, standard dialog will be displayed
                                        CFReleaseNull(engine->la_context);
@@ -695,12 +726,12 @@ _evaluate_authentication(engine_t engine, rule_t rule)
             }
             
             if (newCred) {
-                if (credential_get_valid(newCred)) {
-                    os_log(AUTHD_LOG, "UID %u authenticated as user %{public}s (UID %u) for right '%{public}s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName);
+                if (credential_get_valid(newCred) || isInLWOS()) {
+                    os_log(AUTHD_LOG, "UID %u authenticated as user %{public}s (UID %i) for right '%{public}s'", auth_token_get_uid(engine->auth), credential_get_name(newCred), credential_get_uid(newCred), engine->currentRightName);
                     ccaudit_log_success(ccaudit, newCred, engine->currentRightName);
                 } else {
-                    os_log(AUTHD_LOG, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine->auth), auth_items_get_string(engine->context, "username"), engine->currentRightName);
-                    ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, "username"), engine->currentRightName);
+                    os_log(AUTHD_LOG, "UID %u failed to authenticate as user '%{public}s' for right '%{public}s'", auth_token_get_uid(engine->auth), auth_items_get_string(engine->context, AGENT_USERNAME), engine->currentRightName);
+                    ccaudit_log_failure(ccaudit, auth_items_get_string(engine->context, AGENT_USERNAME), engine->currentRightName);
                 }
                 
                 status = _evaluate_user_credential_for_rule(engine, newCred, rule, true, false, &engine->reason);
@@ -799,10 +830,12 @@ _evaluate_class_user(engine_t engine, rule_t rule)
     }
     
     if (!rule_get_authenticate_user(rule)) {
-        status = _evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL);
-        
-        if (status == errAuthorizationSuccess) {
-            return errAuthorizationSuccess;
+        if (!isInLWOS()) {
+            status = _evaluate_user_credential_for_rule(engine, engine->sessionCredential, rule, true, true, NULL);
+            
+            if (status == errAuthorizationSuccess) {
+                return errAuthorizationSuccess;
+            }
         }
         
         return errAuthorizationDenied;
@@ -860,22 +893,22 @@ _evaluate_class_user(engine_t engine, rule_t rule)
         return errAuthorizationSuccess;
        }
 
-       if (!engine->preauthorizing) {
-               if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) {
+    if (!(engine->flags & kAuthorizationFlagSheet)) {
+        if (!(engine->flags & kAuthorizationFlagInteractionAllowed)) {
             os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (kAuthorizationFlagInteractionAllowed not set) (engine %lld)", engine->engine_index);
-                       return errAuthorizationInteractionNotAllowed;
-               }
-
-               if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
-                       os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine->engine_index);
-                       return errAuthorizationInteractionNotAllowed;
-               }
-
-               if (server_in_dark_wake() && !(engine->flags & kAuthorizationFlagIgnoreDarkWake)) {
-                       os_log_error(AUTHD_LOG, "Fatal: authorization denied (DW) (engine %lld)", engine->engine_index);
-                       return errAuthorizationDenied;
-               }
-       }
+            return errAuthorizationInteractionNotAllowed;
+        }
+        
+        if (!(session_get_attributes(auth_token_get_session(engine->auth)) & AU_SESSION_FLAG_HAS_GRAPHIC_ACCESS)) {
+            os_log_error(AUTHD_LOG, "Fatal: interaction not allowed (session has no ui access) (engine %lld)", engine->engine_index);
+            return errAuthorizationInteractionNotAllowed;
+        }
+        
+        if (server_in_dark_wake() && !(engine->flags & kAuthorizationFlagIgnoreDarkWake)) {
+            os_log_error(AUTHD_LOG, "Fatal: authorization denied (DW) (engine %lld)", engine->engine_index);
+            return errAuthorizationDenied;
+        }
+    }
 
        return _evaluate_authentication(engine, rule);
 }
@@ -925,15 +958,14 @@ _evaluate_class_rule(engine_t engine, rule_t rule, bool *save_pwd)
 }
 
 static bool
-_preevaluate_class_rule(engine_t engine, rule_t rule)
+_preevaluate_class_rule(engine_t engine, rule_t rule, const char **group)
 {
        os_log_debug(AUTHD_LOG, "engine %lld: _preevaluate_class_rule %{public}s", engine->engine_index, rule_get_name(rule));
 
        __block bool password_only = false;
        rule_delegates_iterator(rule, ^bool(rule_t delegate) {
-               if (_preevaluate_rule(engine, delegate)) {
+               if (_preevaluate_rule(engine, delegate, group)) {
                                password_only = true;
-                               return false;
                }
                return true;
        });
@@ -972,8 +1004,8 @@ _evaluate_class_mechanism(engine_t engine, rule_t rule)
         
                if (status == errAuthorizationSuccess) {
                        credential_t newCred = NULL;
-                       if (auth_items_exist(engine->context, "uid")) {
-                               newCred = credential_create(auth_items_get_uint(engine->context, "uid"));
+                       if (auth_items_exist(engine->context, AGENT_CONTEXT_UID)) {
+                               newCred = credential_create(auth_items_get_uint(engine->context, AGENT_CONTEXT_UID));
                        } else {
                                os_log_info(AUTHD_LOG, "Mechanism did not return a uid (engine %lld)", engine->engine_index);
                        }
@@ -1049,7 +1081,7 @@ _evaluate_rule(engine_t engine, rule_t rule, bool *save_pwd)
 
 // returns true if this rule or its children contain RC_USER rule with password_only==true
 static bool
-_preevaluate_rule(engine_t engine, rule_t rule)
+_preevaluate_rule(engine_t engine, rule_t rule, const char **group)
 {
        os_log_debug(AUTHD_LOG, "engine %lld: _preevaluate_rule %{public}s", engine->engine_index, rule_get_name(rule));
 
@@ -1058,9 +1090,12 @@ _preevaluate_rule(engine_t engine, rule_t rule)
                case RC_DENY:
                        return false;
                case RC_USER:
+            if (group && !*group) {
+                *group = rule_get_group(rule);
+            }
                        return rule_get_password_only(rule);
                case RC_RULE:
-                       return _preevaluate_class_rule(engine, rule);
+                       return _preevaluate_class_rule(engine, rule, group);
                case RC_MECHANISM:
                        return false;
                default:
@@ -1183,129 +1218,49 @@ static bool _verify_sandbox(engine_t engine, const char * right)
 #pragma mark -
 #pragma mark engine methods
 
-OSStatus engine_preauthorize(engine_t engine, auth_items_t credentials)
+OSStatus engine_get_right_properties(engine_t engine, const char *rightName, CFDictionaryRef *output)
 {
-       os_log(AUTHD_LOG, "engine %lld: preauthorizing", engine->engine_index);
-
-       OSStatus status = errAuthorizationDenied;
-       bool save_password = false;
-
-       engine->flags = kAuthorizationFlagExtendRights;
-       engine->preauthorizing = true;
-    CFAssignRetained(engine->la_context, engine_copy_context(engine, credentials));
-       _extract_password_from_la(engine);
-
-       const char *user = auth_items_get_string(credentials, kAuthorizationEnvironmentUsername);
-       require(user, done);
-
-       auth_items_set_string(engine->context, kAuthorizationEnvironmentUsername, user);
-       struct passwd *pwd = getpwnam(user);
-       require(pwd, done);
-
-       auth_items_set_int(engine->context, AGENT_CONTEXT_UID, pwd->pw_uid);
-
-       const char *service = auth_items_get_string(credentials, AGENT_CONTEXT_AP_PAM_SERVICE_NAME);
-
-       if (service) {
-               auth_items_set_string(engine->context, AGENT_CONTEXT_AP_USER_NAME, user);
-               auth_items_set_string(engine->context, AGENT_CONTEXT_AP_PAM_SERVICE_NAME, service);
-       }
-
-       if (auth_items_exist(credentials, AGENT_CONTEXT_AP_TOKEN)) {
-               size_t datalen = 0;
-               const void *data = auth_items_get_data(credentials, AGENT_CONTEXT_AP_TOKEN, &datalen);
-               if (data) {
-                       auth_items_set_data(engine->context, AGENT_CONTEXT_AP_TOKEN, data, datalen);
-               }
-       }
-
-       auth_items_t decrypted_items = auth_items_create();
-       require_action(decrypted_items != NULL, done, os_log_error(AUTHD_LOG, "Unable to create items (engine %lld)", engine->engine_index));
-       auth_items_content_copy(decrypted_items, auth_token_get_context(engine->auth));
-       auth_items_decrypt(decrypted_items, auth_token_get_encryption_key(engine->auth));
-       auth_items_copy(engine->context, decrypted_items);
-       CFReleaseSafe(decrypted_items);
-
-       engine->dismissed = false;
-       auth_rights_clear(engine->grantedRights);
-
-       rule_t rule = rule_create_preauthorization();
-       engine->currentRightName = rule_get_name(rule);
-       engine->currentRule = rule;
-       status = _evaluate_rule(engine, rule, &save_password);
-       switch (status) {
-                       case errAuthorizationSuccess:
-                               os_log(AUTHD_LOG, "Succeeded preauthorizing client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (engine %lld)",
-                                       process_get_code_url(engine->proc), process_get_pid(engine->proc),
-                                       auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), engine->engine_index);
-                               status = errAuthorizationSuccess;
-                               break;
-                       case errAuthorizationDenied:
-                       case errAuthorizationInteractionNotAllowed:
-                       case errAuthorizationCanceled:
-                               os_log(AUTHD_LOG, "Failed to preauthorize client '%{public}s' [%d] for authorization created by '%{public}s' [%d] (%X,%d) (%i) (engine %lld)",
-                                       process_get_code_url(engine->proc), process_get_pid(engine->proc),
-                                       auth_token_get_code_url(engine->auth), auth_token_get_pid(engine->auth), (unsigned int)engine->flags, auth_token_least_privileged(engine->auth), (int)status, engine->engine_index);
-                               break;
-                       default:
-                               os_log_error(AUTHD_LOG, "Preauthorize returned %d => returning errAuthorizationInternal (engine %lld)", (int)status, engine->engine_index);
-                               status = errAuthorizationInternal;
-                               break;
-               }
-
-               CFReleaseSafe(rule);
-
-       if (engine->dismissed) {
-               os_log_error(AUTHD_LOG, "Engine dismissed (engine %lld)", engine->engine_index);
-               status = errAuthorizationDenied;
-       }
-
-       os_log_debug(AUTHD_LOG, "engine %lld: preauthorize result: %d", engine->engine_index, (int)status);
-
-               _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
-                       credential_t cred = (credential_t)value;
-                       // skip all uid credentials when running in least privileged
-                       if (auth_token_least_privileged(engine->auth) && !credential_is_right(cred))
-                               return true;
-
-                       session_t session = auth_token_get_session(engine->auth);
-                       auth_token_set_credential(engine->auth, cred);
-                       if (credential_get_shared(cred)) {
-                               session_set_credential(session, cred);
-                       }
-                       if (credential_is_right(cred)) {
-                               os_log(AUTHD_LOG, "engine %lld: adding least privileged %{public}scredential %{public}s to authorization", engine->engine_index, credential_get_shared(cred) ? "shared " : "", credential_get_name(cred));
-                       } else {
-                               os_log(AUTHD_LOG, "engine %lld: adding %{public}scredential %{public}s (%i) to authorization", engine->engine_index, credential_get_shared(cred) ? "shared " : "", credential_get_name(cred), credential_get_uid(cred));
-                       }
-                       return true;
-               });
-
-
-       if (status == errAuthorizationSuccess && save_password) {
-               auth_items_set_flags(engine->context, kAuthorizationEnvironmentPassword, kAuthorizationContextFlagExtractable);
-       }
+    OSStatus status = errAuthorizationInternal;
+    
+    CFMutableDictionaryRef properties = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+    require(properties != NULL, done);
+    require(rightName != NULL, done);
 
-       if ((status == errAuthorizationSuccess) || (status == errAuthorizationCanceled)) {
-               auth_items_t encrypted_items = auth_items_create();
-               require_action(encrypted_items != NULL, done, os_log_error(AUTHD_LOG, "Unable to create items (engine %lld)", engine->engine_index));
-               auth_items_content_copy_with_flags(encrypted_items, engine->context, kAuthorizationContextFlagExtractable);
-#if DEBUG
-               os_log_debug(AUTHD_LOG, "engine %lld: ********** Dumping preauthorized context for encryption **********", engine->engine_index);
-               os_log_debug(AUTHD_LOG, "%@", encrypted_items);
-#endif
-               auth_items_encrypt(encrypted_items, auth_token_get_encryption_key(engine->auth));
-               auth_items_copy_with_flags(auth_token_get_context(engine->auth), encrypted_items, kAuthorizationContextFlagExtractable);
-               os_log_debug(AUTHD_LOG, "engine %lld: encrypted preauthorization context data", engine->engine_index);
-               CFReleaseSafe(encrypted_items);
-       }
+    // first check if any of rights uses rule with password-only set to true
+    // if so, set appropriate hint so SecurityAgent won't use alternate authentication methods like smartcard etc.
+    authdb_connection_t dbconn = authdb_connection_acquire(server_get_database()); // get db handle
+    
+    os_log_debug(AUTHD_LOG, "engine %lld: get right properties %{public}s", engine->engine_index, rightName);
+    rule_t rule = _find_rule(engine, dbconn, rightName);
+    
+    if (rule) {
+        const char *group = NULL;
+        bool passwordOnly = _preevaluate_rule(engine, rule, &group);
+        CFDictionarySetValue(properties, CFSTR(kAuthorizationRuleParameterPasswordOnly), passwordOnly ? kCFBooleanTrue : kCFBooleanFalse);
+        if (group) {
+            CFStringRef groupCf = CFStringCreateWithCString(kCFAllocatorDefault, group, kCFStringEncodingUTF8);
+            if (groupCf) {
+                CFDictionarySetValue(properties, CFSTR(kAuthorizationRuleParameterGroup), groupCf);
+                CFRelease(groupCf);
+            }
+        }
+        CFRelease(rule);
+        status = errAuthorizationSuccess;
+    } else {
+        os_log_debug(AUTHD_LOG, "engine %lld: cannot get right properties %{public}s", engine->engine_index, rightName);
+        status = errAuthorizationInvalidRef;
+    }
+    
+    authdb_connection_release(&dbconn); // release db handle
+    os_log_debug(AUTHD_LOG, "engine %lld: right properties %@", engine->engine_index, properties);
 
+    if (output && status == errAuthorizationSuccess) {
+        *output = properties;
+        CFRetain(*output);
+    }
 done:
-       engine->preauthorizing = false;
-       auth_items_clear(engine->context);
-       auth_items_clear(engine->sticky_context);
-       CFDictionaryRemoveAllValues(engine->mechanism_agents);
-       return status;
+    CFReleaseSafe(properties);
+    return status;
 }
 
 OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t environment, AuthorizationFlags flags)
@@ -1313,11 +1268,12 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
     __block OSStatus status = errAuthorizationSuccess;
     __block bool save_password = false;
        __block bool password_only = false;
-    CFIndex rights_count = auth_rights_get_count(rights);
+    CFIndex rights_count = 0;
     ccaudit_t ccaudit = NULL;
-    
     require(rights != NULL, done);
     
+    rights_count = auth_rights_get_count(rights);
+    
     ccaudit = ccaudit_create(engine->proc, engine->auth, AUE_ssauthorize);
     if (auth_rights_get_count(rights) > 0) {
         ccaudit_log(ccaudit, "begin evaluation", NULL, 0);
@@ -1405,7 +1361,6 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
 
                engine_acquire_sheet_data(engine);
                _extract_password_from_la(engine);
-               engine->preauthorizing = true;
        }
     
     engine->dismissed = false;
@@ -1422,8 +1377,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
                        os_log_debug(AUTHD_LOG, "engine %lld: checking if rule %{public}s contains password-only item", engine->engine_index, key);
 
                        rule_t rule = _find_rule(engine, dbconn, key);
-
-                       if (rule && _preevaluate_rule(engine, rule)) {
+                       if (rule && _preevaluate_rule(engine, rule, NULL)) {
                                password_only = true;
                 CFReleaseSafe(rule);
                                return false;
@@ -1462,6 +1416,7 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
 
         // only need the hints & mechanisms if we are going to show ui
         if (engine->flags & kAuthorizationFlagInteractionAllowed || engine->flags & kAuthorizationFlagSheet) {
+            os_log_debug(AUTHD_LOG, "setting hints for UI authorization");
             _set_right_hints(engine->hints, key);
             _set_localization_hints(dbconn, engine->hints, rule);
             if (!engine->authenticateRule) {
@@ -1545,10 +1500,6 @@ OSStatus engine_authorize(engine_t engine, auth_rights_t rights, auth_items_t en
     
     os_log_debug(AUTHD_LOG, "engine %lld: authorize result: %d", engine->engine_index, (int)status);
 
-       if (engine->flags & kAuthorizationFlagSheet) {
-               engine->preauthorizing = false;
-       }
-
     if ((engine->flags & kAuthorizationFlagExtendRights) && !(engine->flags & kAuthorizationFlagDestroyRights)) {
         _cf_set_iterate(engine->credentials, ^bool(CFTypeRef value) {
             credential_t cred = (credential_t)value;
index aec7c29675048c7f0a85adbd87173617ffa73111..5ef5ce4179cef94b4a41fad08461a93ff9d4d77e 100644 (file)
@@ -17,7 +17,7 @@ AUTH_NONNULL1 AUTH_NONNULL2
 OSStatus engine_authorize(engine_t, auth_rights_t rights, auth_items_t environment, AuthorizationFlags);
 
 AUTH_NONNULL1 AUTH_NONNULL2
-OSStatus engine_preauthorize(engine_t engine, auth_items_t credentials);
+OSStatus engine_get_right_properties(engine_t engine, const char *rightName, CFDictionaryRef *output);
 
 AUTH_NONNULL_ALL
 OSStatus engine_verify_modification(engine_t, rule_t, bool remove, bool force_modify);
index dbdcf4360d877c833562f0ea68dad8ad7fe1b2ab..8f220f3d42cb3643c914511fbfd9403b078f6855 100644 (file)
@@ -14,7 +14,7 @@
 #include <xpc/xpc.h>
 #include <xpc/private.h>
 #include <dispatch/dispatch.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <sandbox.h>
 
 #if DEBUG
@@ -109,9 +109,12 @@ security_auth_peer_event_handler(xpc_connection_t connection, xpc_object_t event
                 }
                 status = errAuthorizationSuccess;
                 break;
-                       case AUTHORIZATION_PREAUTHORIZE_CREDENTIALS:
-                               status = authorization_preauthorize_credentials(conn,event,reply);
+                       case AUTHORIZATION_COPY_RIGHT_PROPERTIES:
+                               status = authorization_copy_right_properties(conn,event,reply);
                                break;
+            case AUTHORIZATION_COPY_PRELOGIN_USERDB:
+                status = authorization_copy_prelogin_userdb(conn,event,reply);
+                break;
 #if DEBUG
             case AUTHORIZATION_DEV:
                 server_dev();
index 4e5b5c16c75d72c97c69bafac5e910526443407b..9affe4245979c1f5b34fbbeebcd990722ed3cfe1 100644 (file)
@@ -13,6 +13,8 @@
 #include <Security/SecCode.h>
 #include <Security/SecRequirement.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 AUTHD_DEFINE_LOG
 
 struct _process_s {
index a706b4d3abd5a669211a89ced27019460b2dc929..b854c1b76dc83d1a1e438bd5ba53190511ecc81f 100644 (file)
@@ -175,36 +175,11 @@ rule_create_default()
     mech = mechanism_create_with_string("builtin:authenticate,privileged", NULL);
     CFArrayAppendValue(rule->mechanisms, mech);
     CFReleaseNull(mech);
-
-    mech = mechanism_create_with_string("PKINITMechanism:auth,privileged", NULL);
-    CFArrayAppendValue(rule->mechanisms, mech);
-    CFReleaseNull(mech);
     
 done:
     return rule;
 }
 
-rule_t
-rule_create_preauthorization()
-{
-       rule_t rule = _rule_create();
-       require(rule != NULL, done);
-
-       auth_items_set_int64(rule->data, RULE_TYPE, RT_RIGHT);
-       auth_items_set_string(rule->data, RULE_NAME, "(preauthorization)");
-       auth_items_set_int64(rule->data, RULE_CLASS, RC_USER);
-       auth_items_set_string(rule->data, RULE_GROUP, "admin");
-       auth_items_set_int64(rule->data, RULE_TRIES, 1);
-       auth_items_set_int64(rule->data, RULE_FLAGS, RuleFlagShared | RuleFlagAuthenticateUser | RuleFlagRequireAppleSigned);
-
-       mechanism_t mech = mechanism_create_with_string("builtin:authenticate,privileged", NULL);
-       CFArrayAppendValue(rule->mechanisms, mech);
-       CFReleaseNull(mech);
-
-done:
-       return rule;
-}
-
 rule_t
 rule_create_with_string(const char * str, authdb_connection_t dbconn)
 {
@@ -1168,6 +1143,9 @@ rule_check_flags(rule_t rule, RuleFlags flags)
 bool
 rule_get_shared(rule_t rule)
 {
+    if (isInLWOS()) {
+        return false;
+    }
     return rule_check_flags(rule, RuleFlagShared);
 }
 
index 098087d58bba75989cacb872a4a4426005957494..2d9b630e874b3fe8c6a740aa894cfb64a74cfa7c 100644 (file)
@@ -50,9 +50,6 @@ typedef enum  {
 AUTH_WARN_RESULT AUTH_MALLOC AUTH_NONNULL_ALL AUTH_RETURNS_RETAINED
 rule_t rule_create_default(void);
 
-AUTH_WARN_RESULT AUTH_MALLOC AUTH_NONNULL_ALL AUTH_RETURNS_RETAINED
-rule_t rule_create_preauthorization(void);
-
 AUTH_WARN_RESULT AUTH_MALLOC AUTH_NONNULL1 AUTH_RETURNS_RETAINED
 rule_t rule_create_with_string(const char *,authdb_connection_t);
         
index 728ae6e280787402452f54698f6d5a70b2e77185..493105f34c610fcc86958329db60f83b63af0ab9 100644 (file)
@@ -15,6 +15,7 @@
 #include "engine.h"
 #include "connection.h"
 #include "AuthorizationTags.h"
+#include "PreloginUserDb.h"
 
 #include <bsm/libbsm.h>
 #include <Security/Authorization.h>
@@ -29,6 +30,8 @@
 #include <IOKit/pwr_mgt/IOPMLib.h>
 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 AUTHD_DEFINE_LOG
 
 #define MAX_PROCESS_RIGHTS   100
@@ -384,27 +387,26 @@ done:
     return status;
 }
 
-static OSStatus _server_preauthorize(connection_t conn, auth_token_t auth, auth_items_t context, engine_t * engine_out)
+static OSStatus _server_get_right_properties(connection_t conn, const char *rightName, CFDictionaryRef *properties)
 {
-       __block OSStatus status = errAuthorizationDenied;
-       engine_t engine = NULL;
+    OSStatus status = errAuthorizationDenied;
+    auth_token_t auth = NULL;
+    engine_t engine = NULL;
 
-       require_action(conn, done, status = errAuthorizationInternal);
+    require_action(conn, done, status = errAuthorizationInternal);
+    
+    auth = auth_token_create(connection_get_process(conn), false);
+    require_action(auth, done, status = errAuthorizationInternal);
 
-       engine = engine_create(conn, auth);
-       require_action(engine, done, status = errAuthorizationInternal);
+    engine = engine_create(conn, auth);
+    require_action(engine, done, status = errAuthorizationInternal);
 
-       status = engine_preauthorize(engine, context);
+    status = engine_get_right_properties(engine, rightName, properties);
 
 done:
-       if (engine) {
-               if (engine_out) {
-                       *engine_out = engine;
-               } else {
-                       CFRelease(engine);
-               }
-       }
-       return status;
+    CFReleaseSafe(engine);
+    CFReleaseSafe(auth);
+    return status;
 }
 
 static OSStatus _server_authorize(connection_t conn, auth_token_t auth, AuthorizationFlags flags, auth_rights_t rights, auth_items_t environment, engine_t * engine_out)
@@ -546,28 +548,31 @@ done:
 // IN:  AUTH_XPC_BLOB, AUTH_XPC_DATA
 // OUT:
 OSStatus
-authorization_preauthorize_credentials(connection_t conn, xpc_object_t message, xpc_object_t reply)
+authorization_copy_right_properties(connection_t conn, xpc_object_t message, xpc_object_t reply)
 {
-       OSStatus status = errAuthorizationDenied;
-       engine_t engine = NULL;
-
-       process_t proc = connection_get_process(conn);
-
-       // Passed in args
-       auth_items_t context = auth_items_create_with_xpc(xpc_dictionary_get_value(message, AUTH_XPC_DATA));
-
-       auth_token_t auth = NULL;
-       status = _process_find_copy_auth_token_from_xpc(proc, message, &auth);
-       require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "preauthorize_credentials: no auth token"));
+    OSStatus status = errAuthorizationDenied;
+    CFDataRef serializedProperties = NULL;
+    CFDictionaryRef properties = NULL;
+    
+    // Passed in args
+    const char *right = xpc_dictionary_get_string(message, AUTH_XPC_RIGHT_NAME);
+    os_log_debug(AUTHD_LOG, "server: right %s", right);
 
-       status = _server_preauthorize(conn, auth, context, &engine);
-       require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "preauthorize_credentials: authorization failed"));
+    require_action(right != NULL, done, status = errAuthorizationInvalidPointer);
 
+    status = _server_get_right_properties(conn, right, &properties);
+    require_noerr(status, done);
+  
+    if (properties) {
+        serializedProperties = CFPropertyListCreateData(kCFAllocatorDefault, properties, kCFPropertyListBinaryFormat_v1_0, 0, NULL);
+        if (serializedProperties) {
+            xpc_dictionary_set_data(reply, AUTH_XPC_OUT_ITEMS, CFDataGetBytePtr(serializedProperties), CFDataGetLength(serializedProperties));
+        }
+    }
+    
 done:
-       CFReleaseSafe(context);
-       CFReleaseSafe(auth);
-       CFReleaseSafe(engine);
-
+    CFReleaseSafe(serializedProperties);
+       CFReleaseSafe(properties);
        return status;
 }
 
@@ -1175,3 +1180,29 @@ server_dev() {
 //    CFReleaseSafe(items);
 }
 
+// IN:  AUTH_XPC_TAG, AUTH_XPC_FLAGS
+// OUT: AUTH_XPC_DATA
+OSStatus
+authorization_copy_prelogin_userdb(connection_t conn, xpc_object_t message, xpc_object_t reply)
+{
+    OSStatus status = errAuthorizationDenied;
+    xpc_object_t xpcarr = NULL;
+    CFArrayRef cfarray = NULL;
+
+    const char *uuid = xpc_dictionary_get_string(message, AUTH_XPC_TAG);
+    UInt32 flags = (AuthorizationFlags)xpc_dictionary_get_uint64(message, AUTH_XPC_FLAGS);
+
+    status = preloginudb_copy_userdb(uuid, flags, &cfarray);
+    xpc_dictionary_set_int64(reply, AUTH_XPC_STATUS, status);
+    require_noerr_action_quiet(status, done, os_log_error(AUTHD_LOG, "authorization_copy_prelogin_userdb: database failed"));
+  
+    xpcarr = _CFXPCCreateXPCObjectFromCFObject(cfarray);
+    require(xpcarr != NULL, done);
+    xpc_dictionary_set_value(reply, AUTH_XPC_DATA, xpcarr);
+
+done:
+    CFReleaseSafe(cfarray);
+    xpc_release_safe(xpcarr);
+
+    return status;
+}
index 7889bb32e2b064854af79326ccf6ac42e2ac4bec..5fe99d9a2a335b3b7e92d1b343216c8831693b55 100644 (file)
@@ -47,7 +47,7 @@ AUTH_NONNULL_ALL
 OSStatus authorization_free(connection_t,xpc_object_t,xpc_object_t);
     
 AUTH_NONNULL_ALL
-OSStatus authorization_preauthorize_credentials(connection_t, xpc_object_t, xpc_object_t);
+OSStatus authorization_copy_right_properties(connection_t, xpc_object_t, xpc_object_t);
 
 AUTH_NONNULL_ALL
 OSStatus authorization_copy_rights(connection_t,xpc_object_t,xpc_object_t);
@@ -76,6 +76,9 @@ OSStatus authorization_right_remove(connection_t,xpc_object_t,xpc_object_t);
 AUTH_NONNULL_ALL
 OSStatus session_set_user_preferences(connection_t,xpc_object_t,xpc_object_t);
     
+AUTH_NONNULL_ALL
+OSStatus authorization_copy_prelogin_userdb(connection_t,xpc_object_t,xpc_object_t);
+
 #if defined(__cplusplus)
 }
 #endif
index 83d548e8eb321b3a9be1a30bda0e2f1a1117bc2c..0df2882ef884dd8b7eaef34b2ab3120e0b09cd6d 100644 (file)
@@ -6,6 +6,8 @@
 #include <dispatch/dispatch.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 AUTHD_DEFINE_LOG
 
 struct _session_s {
index 1987df61ebe3c93f1275a065df2451111852da4d..befca8f574671a3327490c7247b81ae29d943238 100644 (file)
@@ -4,3 +4,4 @@
 ONE_TEST(authd_01_authorizationdb)
 ONE_TEST(authd_02_basicauthorization)
 ONE_TEST(authd_04_executewithprivileges)
+ONE_TEST(authd_05_rightproperties)
index c6c4518049ec4f91d14aeeef930c4319e7815ae3..99bb8eac4842ef3b5e68a63c42cc7ee7951e8e76 100644 (file)
@@ -4,6 +4,7 @@
 //
 
 #import <Security/Authorization.h>
+#import <Security/AuthorizationPriv.h>
 #import <Security/AuthorizationDB.h>
 #import <Security/AuthorizationTagsPriv.h>
 #import <Foundation/Foundation.h>
@@ -282,3 +283,42 @@ int authd_04_executewithprivileges(int argc, char *const *argv)
     AuthorizationFree(authorizationRef, kAuthorizationFlagDestroyRights);
     return 0;
 }
+
+int authd_05_rightproperties(int argc, char *const *argv)
+{
+    plan_tests(5);
+
+    NSDictionary *properties;
+    CFDictionaryRef cfProperties;
+    NSString *group;
+    NSNumber *passwordOnly;
+    
+    OSStatus status = AuthorizationCopyRightProperties("system.csfde.requestpassword", &cfProperties);
+    properties = CFBridgingRelease(cfProperties);
+    if (status != errAuthorizationSuccess) {
+        fail("AuthorizationCopyRightProperties failed with %d", (int)status);
+        goto done;
+    }
+    
+    pass("AuthorizationCopyRightProperties call succeess");
+    passwordOnly = properties[@(kAuthorizationRuleParameterPasswordOnly)];
+    ok(passwordOnly.boolValue, "Returned system.csfde.requestpassword as password only right");
+    group = properties[@(kAuthorizationRuleParameterGroup)];
+    ok([group isEqualToString:@"admin"], "Returned admin as a required group for system.csfde.requestpassword");
+
+    status = AuthorizationCopyRightProperties("com.apple.Safari.allow-unsigned-app-extensions", &cfProperties);
+    properties = CFBridgingRelease(cfProperties);
+    if (status != errAuthorizationSuccess) {
+        fail("AuthorizationCopyRightProperties failed with %d", (int)status);
+        goto done;
+    }
+    group = properties[@(kAuthorizationRuleParameterGroup)];
+    passwordOnly = properties[@(kAuthorizationRuleParameterPasswordOnly)];
+    ok(group.length == 0 && passwordOnly.boolValue == NO, "Returned safari right as non-password only, no specific group");
+    
+    status = AuthorizationCopyRightProperties("non-existing-right", &cfProperties);
+    ok(status == errAuthorizationSuccess, "Returned success for default for unknown right: %d", (int)status);
+
+done:
+    return 0;
+}
index 7c298b95cbf87853794747ab0401294d54941c9d..81c1da200c8e8cced64870f57d206ead889b816f 100644 (file)
@@ -14,7 +14,7 @@ SKIP_INSTALL = YES
 
 ALWAYS_SEARCH_USER_PATHS = NO
 
-GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_C_LANGUAGE_STANDARD = gnu2x
 
 GCC_TREAT_WARNINGS_AS_ERRORS = YES;
 
index f341fbd7ed5a8b3b5122e38f7a5d049e2e9bcbbc..3ee4720d4ab25e4650bf1e2de20b2c9a69876457 100644 (file)
@@ -12,16 +12,23 @@ DYLIB_CURRENT_VERSION = $(CURRENT_PROJECT_VERSION)
 MODULEMAP_FILE = Modules/Security.macOS.modulemap
 DEFINES_MODULE = YES
 
-EXPORTED_SYMBOLS_FILE = $(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).exp
+EXPORTED_SYMBOLS_FILE = $(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).$(CURRENT_ARCH).exp
 ORDER_FILE = OSX/lib/Security.order
 INFOPLIST_FILE = OSX/lib/Info-Security.plist
 
 INSTALL_PATH = $(SYSTEM_LIBRARY_DIR)/Frameworks
 
 ASAN_EXTRA_LDFLAGS_YES = -Wl,-no_warn_inits
-ASAN_EXTRA_LDFLAGS_NO = -Wl,-no_inits
+ASAN_EXTRA_LDFLAGS_NO =
 ASAN_EXTRA_LDFLAGS_ = $(ASAN_EXTRA_LDFLAGS_NO)
-OTHER_LDFLAGS = -laks -lCrashReporterClient -Wl,-upward_framework,Foundation $(ASAN_EXTRA_LDFLAGS_$(ENABLE_ADDRESS_SANITIZER))
+TSAN_EXTRA_LDFLAGS_YES = -Wl,-no_warn_inits
+TSAN_EXTRA_LDFLAGS_NO =
+TSAN_EXTRA_LDFLAGS_ = $(TSAN_EXTRA_LDFLAGS_NO)
+
+// order here matters, so later more specific options override earlier.
+NOINIT_LDFLAGS = -Wl,-no_inits $(ASAN_EXTRA_LDFLAGS_$(ENABLE_ADDRESS_SANITIZER)) $(TSAN_EXTRA_LDFLAGS_$(ENABLE_THREAD_SANITIZER))
+
+OTHER_LDFLAGS = -laks -lCrashReporterClient -Wl,-upward_framework,Foundation $(NOINIT_LDFLAGS)
 
 SECTORDER_FLAGS = -order_file_statistics
 APPLY_RULES_IN_COPY_FILES = NO
index 58ed08ab3535af6fdb67cc6f69208e2d00f2e743..bdd02709cd7d6dc884d3a785d0ad07af43d50ac0 100644 (file)
@@ -11,7 +11,7 @@ LIBRARY_SEARCH_PATHS = $(inherited) /usr/lib/system
 STRIP_INSTALLED_PRODUCT = YES
 DEPLOYMENT_POSTPROCESSING = NO
 
-GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_C_LANGUAGE_STANDARD = gnu2x
 SUPPORTED_PLATFORMS = macosx
 
 GCC_TREAT_WARNINGS_AS_ERRORS = YES
diff --git a/OSX/include/security_asn1 b/OSX/include/security_asn1
deleted file mode 120000 (symlink)
index 09ef080..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_asn1/lib
\ No newline at end of file
diff --git a/OSX/include/security_cdsa_client b/OSX/include/security_cdsa_client
deleted file mode 120000 (symlink)
index 9737c61..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_cdsa_client/lib
\ No newline at end of file
diff --git a/OSX/include/security_cdsa_plugin b/OSX/include/security_cdsa_plugin
deleted file mode 120000 (symlink)
index 2be156f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_cdsa_plugin/lib
\ No newline at end of file
diff --git a/OSX/include/security_cdsa_utilities b/OSX/include/security_cdsa_utilities
deleted file mode 120000 (symlink)
index 2634481..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_cdsa_utilities/lib
\ No newline at end of file
diff --git a/OSX/include/security_cdsa_utils b/OSX/include/security_cdsa_utils
deleted file mode 120000 (symlink)
index f3e5247..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_cdsa_utils/lib
\ No newline at end of file
diff --git a/OSX/include/security_codesigning b/OSX/include/security_codesigning
deleted file mode 120000 (symlink)
index 7c67092..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_codesigning/lib
\ No newline at end of file
diff --git a/OSX/include/security_comcryption b/OSX/include/security_comcryption
deleted file mode 120000 (symlink)
index cbcdf21..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_comcryption/lib
\ No newline at end of file
diff --git a/OSX/include/security_cryptkit b/OSX/include/security_cryptkit
deleted file mode 120000 (symlink)
index 609dcc3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_cryptkit/lib
\ No newline at end of file
diff --git a/OSX/include/security_filedb b/OSX/include/security_filedb
deleted file mode 120000 (symlink)
index 99185cd..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_filedb/lib
\ No newline at end of file
diff --git a/OSX/include/security_keychain b/OSX/include/security_keychain
deleted file mode 120000 (symlink)
index aac53b6..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_keychain/lib
\ No newline at end of file
diff --git a/OSX/include/security_ocspd b/OSX/include/security_ocspd
deleted file mode 120000 (symlink)
index 449ea98..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_ocspd/common
\ No newline at end of file
diff --git a/OSX/include/security_pkcs12 b/OSX/include/security_pkcs12
deleted file mode 120000 (symlink)
index 8fdcb01..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_pkcs12/lib
\ No newline at end of file
diff --git a/OSX/include/security_smime b/OSX/include/security_smime
deleted file mode 120000 (symlink)
index e1a40ba..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_smime/lib
\ No newline at end of file
diff --git a/OSX/include/security_utilities b/OSX/include/security_utilities
deleted file mode 120000 (symlink)
index 4d363d1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurity_utilities/lib
\ No newline at end of file
diff --git a/OSX/include/securityd_client b/OSX/include/securityd_client
deleted file mode 120000 (symlink)
index 2edb676..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./libsecurityd/lib
\ No newline at end of file
index b99cba584dfa7ac4c4f7c3e61d7f51641925b2a3..79058ccc58581eb0f607fa6da8625595f9418c54 100644 (file)
Binary files a/OSX/lib/en.lproj/InfoPlist.strings and b/OSX/lib/en.lproj/InfoPlist.strings differ
index 1871c226a14edfb1cd27fd4a9c331b7adf50767d..b7c044ed52ab6b2d44aab8af4f4e5c8bdbc57e39 100644 (file)
 "com.apple.security.sudo" = "Allow";
 
 "com.apple.configurationprofiles.userenrollment.install" = "Enroll";
+
+"com.apple.configurationprofiles.deviceenrollment.install" = "Enroll";
+
+"com.apple.configurationprofiles.deviceenrollment.uninstall" = "Unenroll";
index e54e35f7ba6b68c0f64b16744f0145f9cf2b11f6..d434c80d40c347ecb877101115be49159783cf92 100644 (file)
@@ -1,6 +1,6 @@
 "system.preferences.accounts" = "Touch ID to Unlock Users & Groups Preferences.";
 
-"com.apple.SoftwareUpdate.scan" = "Touch ID to Check for New Apple-provided Software.";
+"com.apple.SoftwareUpdate.scan" = "Touch ID to Check for New Apple Software.";
 
 "system.preferences.datetime" = "Touch ID to Unlock the Date & Time Preferences.";
 
@@ -48,9 +48,9 @@
 
 "system.preferences.energysaver" = "Touch ID to Unlock the Energy Saver Preferences.";
 
-"system.install.apple-software" = "Touch ID to Install Apple-provided Software.";
+"system.install.apple-software" = "Touch ID to Install Apple Software.";
 
-"system.install.apple-software.standard-user" = "Touch ID to Install Apple-provided software.";
+"system.install.apple-software.standard-user" = "Touch ID to Install Apple software.";
 
 "com.apple.security.assessment.update" = "Touch ID to Install an App from an Unidentified Developer.";
 
index 43870767ceb289b2283145cf0f6871f8b3b24901..568c080abcb26488234a58de76db295a791ba0e4 100644 (file)
@@ -1,6 +1,6 @@
 "system.preferences.accounts" = "__APPNAME__ is trying to unlock Users & Groups preferences.";
 
-"com.apple.SoftwareUpdate.scan" = "__APPNAME__ is trying to check for new Apple-provided software.";
+"com.apple.SoftwareUpdate.scan" = "__APPNAME__ is trying to check for new Apple software.";
 
 "system.preferences.datetime" = "__APPNAME__ is trying to unlock the Date & Time preferences.";
 
@@ -48,9 +48,9 @@
 
 "system.preferences.energysaver" = "__APPNAME__ is trying to unlock the Energy Saver preferences.";
 
-"system.install.apple-software" = "__APPNAME__ is trying to install Apple-provided software.";
+"system.install.apple-software" = "__APPNAME__ is trying to install Apple software.";
 
-"system.install.apple-software.standard-user" = "__APPNAME__ is trying to install Apple-provided software.";
+"system.install.apple-software.standard-user" = "__APPNAME__ is trying to install Apple software.";
 
 "com.apple.security.assessment.update" = "You are overriding your security preferences to install an app from an unidentified developer.";
 
 "com.apple.system-extensions.admin" = "__APPNAME__ is trying to modify a System Extension.";
 
 "com.apple.tcc.util.admin" = "__APPNAME__ is trying to modify your Security & Privacy settings.";
+
+"com.apple.configurationprofiles.deviceenrollment.install" = "__APPNAME__ is trying to enroll you in a remote management (MDM) service.";
+
+"com.apple.configurationprofiles.deviceenrollment.uninstall" = "__APPNAME__ is trying to unenroll you from a remote management (MDM) service.";
diff --git a/OSX/lib/framework.sb b/OSX/lib/framework.sb
deleted file mode 100644 (file)
index e37bf7c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-;; allow clients to communicate with secd
-(allow mach-lookup (global-name "com.apple.secd"))
-;; allow clients to communicate with coreauthd
-(allow mach-lookup (global-name "com.apple.CoreAuthentication.daemon"))
-(allow mach-lookup (global-name "com.apple.CoreAuthentication.agent"))
-;; allow clients to communicate with ctkd
-(allow mach-lookup (global-name "com.apple.ctkd.token-client"))
-
-;; On internal builds, allow clients to read the AMFITrustedKeys NVRAM variable
-(with-filter (system-attribute apple-internal)
-    (allow nvram-get (nvram-variable "AMFITrustedKeys")))
index 6060dfe57f292ef3d35bfacf03c3d1cfc1c68d50..d5dc2e4e2b0eb582c3d4129e0d5c73353bd6eccc 100644 (file)
@@ -27,7 +27,7 @@
 #include <security_cdsa_utilities/cssmdata.h>
 #include <AppleCSPSession.h>
 #include <AppleCSPUtils.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_utilities/debugging.h>
 #include <Security/oidsalg.h>
 #include <YarrowConnection.h>
index aec4d18ddf1ee7166d84d56397ba6214b6c05a46..33232c7a965166c3b6400874367d231e3715964f 100644 (file)
@@ -121,7 +121,7 @@ DH *rawCssmKeyToDh(
                // someone else's key (should never happen)
                CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
        }
-       assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 
+       assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
        /* validate and figure out what we're dealing with */
        switch(hdr->KeyClass) {
                case CSSM_KEYCLASS_PUBLIC_KEY:
index 080d555d04766b070e4fe187e9bf459bcb4afc0f..d9c08703cff28a245cb4689eaf0ee119eb2811c1 100644 (file)
@@ -106,7 +106,7 @@ void CryptKit::FEEDContext::init(
                        mAllocdPrivKey);
        }
        else {
-               assert(opStarted());    
+               assert(opStarted());
        }
        if(mPubKey == NULL) {
                assert(!opStarted());
@@ -118,7 +118,7 @@ void CryptKit::FEEDContext::init(
                        mAllocdPubKey);
        }
        else {
-               assert(opStarted());    
+               assert(opStarted());
        }
        
        /* validate context - no other attributes allowed */
index 8c317b80ebdb1b97023ea989853e570cf5fb5501..4966db8d9a156b40be9d36a21400253c4b490bf7 100644 (file)
@@ -168,7 +168,7 @@ feePubKey CryptKit::rawCssmKeyToFee(
        const CssmKey   &cssmKey)
 {
        const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
-       assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 
+       assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
        
        switch(hdr->AlgorithmId) {
                case CSSM_ALGID_FEE:
index e906bdf821f0d1ee73020e7336c50cc20e29ea6e..1dc36ae76598f0deef05699a94015cf8c708e7ac 100644 (file)
@@ -31,7 +31,7 @@
 #include <security_cdsa_utilities/cssmdata.h>
 #include "AppleCSPSession.h"
 #include "AppleCSPUtils.h"
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_utilities/debugging.h>
 
 #define feeKeyDebug(args...)   secinfo("feeKey", ## args)
index 413b6cf13c9e16b94480fb2187a477006ecfa36a..4175a0cbf72e52f62a8c83a610692f4bf3eb004a 100644 (file)
@@ -28,7 +28,7 @@
 #include <security_cryptkit/feeDigitalSignature.h>
 #include <security_cryptkit/falloc.h>
 #include <stdexcept>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_utilities/debugging.h>
 
 #define feeSigObjDebug(args...)                secinfo("feeSig", ##args)
index e73c092f0580015a2681fa1a908c45fb0ff7c3e8..5974f7888d7a3dc32540380cfa8abb3940cac461 100644 (file)
@@ -26,7 +26,7 @@
 #include <security_cdsa_utilities/cssmdata.h>
 #include <AppleCSPSession.h>
 #include <AppleCSPUtils.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_utilities/debugging.h>
 #include "RSA_DSA_utils.h"
 #include <YarrowConnection.h>
index ae818296acfb7628eec4c8ff74add6e4758da543..fdcbf96b68f70d4340ccecde33fbcc8cbce756b9 100644 (file)
@@ -23,7 +23,7 @@
 #include "RSA_DSA_signature.h"
 #include "RSA_DSA_utils.h"
 #include <stdexcept>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_utilities/debugging.h>
 #include <security_cdsa_utilities/cssmdata.h>
 #include <opensslUtils/opensslUtils.h>
index 8fb48fd16a94b9001610e95567eea561af4502f5..7b8f894e43a79a5c47258f0431932971d6150136 100644 (file)
@@ -114,7 +114,7 @@ RSAKeySizes::RSAKeySizes()
 
        if (d->dict())
        {
-               auto_ptr<Dictionary>apd(d);
+               unique_ptr<Dictionary>apd(d);
                rsaLookupVal(*apd, kRSAMaxKeySizePref, maxKeySize);
                rsaLookupVal(*apd, kRSAMaxPublicExponentPref, maxPubExponentSize);
        }
@@ -223,7 +223,7 @@ RSA *rawCssmKeyToRsa(
        bool isPub;
        bool isOaep = false;
        
-       assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 
+       assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
        
        switch(hdr->AlgorithmId) {
                case CSSM_ALGID_RSA:
@@ -504,7 +504,7 @@ DSA *rawCssmKeyToDsa(
        const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
        bool isPub;
        
-       assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 
+       assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
        
        if(hdr->AlgorithmId != CSSM_ALGID_DSA) {
                // someone else's key (should never happen)
index d0983f5b1ed0d9ccbe219a999bd3b33539d3a0b9..2d394aca26e92a8988108798a0f8b9bb811ff8ce 100644 (file)
@@ -85,7 +85,7 @@ void RSA_CryptContext::init(const Context &context, bool encoding /*= true*/)
                }
        }
        else {
-               assert(opStarted());    
+               assert(opStarted());
        }
 
        unsigned cipherBlockSize = RSA_size(mRsaKey);
index 6e0b42799f191d2ddc15efa7ee4511e20abe9fc8..dce62a69c81d36ff9128db5217d69ebbef5ec4ca 100644 (file)
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <security_asn1/SecNssCoder.h>
 
 #include <CoreFoundation/CoreFoundation.h>
index 6d1a16c733392935bac7f25d304d44f49928fcd6..d68c3170f4b068615e5973746b91f87213756448 100644 (file)
@@ -88,7 +88,7 @@ void AppleCSPSession::pkcs8InferKeyHeader(
         */
        CSSM_KEY_SIZE keySize;
        try {
-               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+               unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
                provider->QueryKeySizeInBits(keySize);
        }
        catch(const CssmError &cerror) {
@@ -103,7 +103,7 @@ void AppleCSPSession::pkcs8InferKeyHeader(
                   (hdr.AlgorithmId == CSSM_ALGID_DSA)) {
                        hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
                        try {
-                               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+                               unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
                                provider->QueryKeySizeInBits(keySize);
                        }
                        catch(...) {
@@ -198,7 +198,7 @@ void AppleCSPSession::opensslInferKeyHeader(
        /* now figure out the key size by finding a provider for this key */
        CSSM_KEY_SIZE keySize;
        try {
-               auto_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
+               unique_ptr<CSPKeyInfoProvider> provider(infoProvider(key));
                provider->QueryKeySizeInBits(keySize);
        }
        catch(...) {
index b956a092a08e9f16d1115e08e8598ddabb72fe11..eb23d6580f4240987d3452a9e889b6aaffd10dce 100644 (file)
@@ -80,7 +80,7 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include "cryptlib.h"
 #include "bn_lcl.h"
 
index c896a752ab20f231b95211ec1cd2d2f2020340ff..c769764d4123431025212e090cf379540b3bc81d 100644 (file)
@@ -78,7 +78,7 @@
 #endif
 
 #include <stdio.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include "cryptlib.h"
 #include <openssl/bn_legacy.h>
 
index 8117323766e8093a561ccd46c483a231ee571778..6c67c1b94fe8ba8ae0b8a494688f1f09c24c185b 100644 (file)
 #ifdef ATALLA
 # include <alloca.h>
 # include <atasi.h>
-# include <assert.h>
+# include <security_utilities/simulatecrash_assert.h>
 # include <dlfcn.h>
 #endif
 
index af312c7f6943277ed65e991caf51098e8aebf50d..801b6fe27b7a36787002f85cc2659b2e57942409 100644 (file)
@@ -225,13 +225,8 @@ extern "C" {
 #define Lw(t)    (((BN_ULONG)(t))&BN_MASK2)
 #define Hw(t)    (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2)
 
-/* This is used for internal error checking and is not normally used */
-#ifdef BN_DEBUG
-# include <assert.h>
-# define bn_check_top(a) assert ((a)->top >= 0 && (a)->top <= (a)->dmax);
-#else
-# define bn_check_top(a)
-#endif
+#include <security_utilities/simulatecrash_assert.h>
+#define bn_check_top(a) assert((a)->top >= 0 && (a)->top <= (a)->max);
 
 /* This macro is to add extra stuff for development checking */
 #ifdef BN_DEBUG
index cd652271eaa7f466fe6646ddc328fd7b1bc76c0e..cb01bce2b4b716e1e84b98f4e368dcf4ae4b9fab 100644 (file)
@@ -35,7 +35,7 @@
 #include <Security/oidsalg.h>
 #include <Security/SecAsn1Templates.h>
 
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #define sslAsn1Debug(args...)  secinfo("sslAsn1", ##args)
 
index 550299167776167fafbbaa4e405e814d9096e949..1264b623605a37c877c764ef5ce281ad351736e6 100644 (file)
@@ -155,8 +155,10 @@ int RSA_verify_ASN1_OCTET_STRING(int dtype, unsigned char *m,
                ret=1;
 err:
        if (sig != NULL) M_ASN1_OCTET_STRING_free(sig);
-       memset(s,0,(unsigned int)siglen);
-       Free(s);
+    if(s) {
+        memset(s,0,(unsigned int)siglen);
+        Free(s);
+    }
        return(ret);
-       }
+}
 
index fff3be5f0c8deba7263d8d93a6d675c466b4dd3d..323dc930286dfd18a2c4b9da6bbe444d748c4da5 100644 (file)
@@ -232,8 +232,10 @@ int RSA_verify(int dtype, unsigned char *m, unsigned int m_len,
        }
 err:
        if (sig != NULL) X509_SIG_free(sig);
-       memset(s,0,(unsigned int)siglen);
-       Free(s);
+    if(s) {
+        memset(s,0,(unsigned int)siglen);
+        Free(s);
+    }
        return(ret);
-       }
+}
 
index d079b3f09c0c94f94512667490c4f66a11afe99b..48c6012035e9e75c5d995415cf93b4d348833367 100644 (file)
@@ -357,9 +357,9 @@ SSCSPSession::FreeKey(const AccessCredentials *accessCred,
                // that!
 
                // Find the key in the map.  Tell tell the key to free itself
-               // (when the auto_ptr deletes the key it removes itself from the map). 
+               // (when the unique_ptr deletes the key it removes itself from the map). 
            secinfo("freeKey", "CSPDL FreeKey");
-               auto_ptr<SSKey> ssKey(&mSSCSPDLSession.find<SSKey>(ioKey));
+               unique_ptr<SSKey> ssKey(&mSSCSPDLSession.find<SSKey>(ioKey));
                ssKey->free(accessCred, ioKey, deleteKey);
        }
        else
index b052393204ae44b16e6f86726454a9c57c6ab019..4f23d98647833715e836e0b53e47bdcba207a7ed 100644 (file)
@@ -488,7 +488,7 @@ SSCryptContext::final(CssmData &out)
        if(!inSize) return;
 
        const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize);
-       IFDEBUG(size_t origOutSize = out.length());
+       size_t origOutSize = out.length();
        if (encoding()) {
                clientSession().encrypt(*mContext, mKeyHandle, in, out);
        }
index aa198e08d697da6e56bd87d31ef9d0e4d9acb0e6..de2e019b3fe2c6b5d82671eca7df96416d4f369b 100644 (file)
@@ -335,7 +335,7 @@ bool getFieldSubjectKeyId(
        
        /* if this fails, we're out of sync with nssExtenInfo[] in 
         * CLFieldsCommon.cpp */
-       assert(nssObj != NULL); 
+       assert(nssObj != NULL);
        clAllocCopyData(alloc, *nssObj, *cdsaObj);
        getFieldExtenCommon(cdsaObj, *decodedExt, fieldValue);
        return true;
index d94b373d265151446831ce60ceb3fc868bb438e0..3ebe668b92556c58559a0c5381251f07153b9119 100644 (file)
@@ -37,7 +37,7 @@
 /* 
  * Avoid inlining this for debuggability 
  */
-void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc)
+void *ArenaAllocator::malloc(size_t len)
 {
        try {
                return mCoder.malloc(len);
@@ -48,11 +48,11 @@ void *ArenaAllocator::malloc(size_t len) throw(std::bad_alloc)
 }
 
 /* intentionally not implemented, should never be called */
-void ArenaAllocator::free(void *p) throw()
+void ArenaAllocator::free(void *p) _NOEXCEPT
 {
 }
        
-void *ArenaAllocator::realloc(void *p, size_t len) throw(std::bad_alloc)
+void *ArenaAllocator::realloc(void *p, size_t len)
 {
        throw std::bad_alloc();
 }
index e62cffac9e9779e6fb52aa64a8b4abdb8da5d2f2..ebca2ebd99ab4a7a139e7e57277e4a3e39562575 100644 (file)
@@ -42,9 +42,9 @@ public:
        ArenaAllocator(SecNssCoder &coder)
                : mCoder(coder) { }
        ~ArenaAllocator() { }
-       void *malloc(size_t) throw(std::bad_alloc) ;
-       void free(void *) throw() ;
-       void *realloc(void *, size_t) throw(std::bad_alloc);
+       void *malloc(size_t);
+       void free(void *) _NOEXCEPT ;
+       void *realloc(void *, size_t);
 private:
        SecNssCoder             &mCoder;
 };
index 460af75a8dc0d83592578c1fd660eba436c8e971..e5554ff0ed9b50b12caa5ea5714838da1317f905 100644 (file)
@@ -31,7 +31,7 @@
 #include <security_ocspd/ocspResponse.h>
 #include <security_ocspd/ocspExtensions.h>
 #include <security_ocspd/ocspdUtils.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <string.h>
 #include <Security/oidsalg.h>
 #include <Security/oidscert.h>
index 0ad65a537522e64de4d4e33b972874ba7c9d15dd..3bf095dc8d7a8c33fcc163416786046b67f0fd2f 100644 (file)
 #include <Security/oidsalg.h>
 #include <Security/cssmapple.h>
 
-/*
- * This is a temporary hack to allow verification of PKINIT server certs
- * which are self-signed and not in the system anchors list. If the self-
- * signed cert is in a magic keychain (whose location is not published),
- * we'll allow it as if it were indeed a full-fledged anchor cert.
- */
-#define TP_PKINIT_SERVER_HACK  1
-#if            TP_PKINIT_SERVER_HACK
-
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainSearch.h>
-#include <Security/SecCertificate.h>
-#include <Security/oidscert.h>
-#include <sys/types.h>
-#include <pwd.h>
-
-#define CFRELEASE(cf)  if(cf) { CFRelease(cf); }
-
-/*
- * Returns true if we are to allow/trust the specified
- * cert as a PKINIT-only anchor.
- */
-static bool tpCheckPkinitServerCert(
-       TPCertGroup &certGroup)
-{
-       /*
-        * Basic requirement: exactly one cert, self-signed.
-        * The numCerts == 1 requirement might change...
-        */
-       unsigned numCerts = certGroup.numCerts();
-       if(numCerts != 1) {
-               tpDebug("tpCheckPkinitServerCert: too many certs");
-               return false;
-       }
-       /* end of chain... */
-       TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1);
-       if(!theCert->isSelfSigned()) {
-               tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed");
-               return false;
-       }
-       const CSSM_DATA *subjectName = theCert->subjectName();
-
-       /*
-        * Open the magic keychain.
-        * We're going up and over the Sec layer here, not generally
-        * kosher, but this is a hack.
-        */
-       OSStatus ortn;
-       SecKeychainRef kcRef = NULL;
-       string fullPathName;
-       const char *homeDir = getenv("HOME");
-       if (homeDir == NULL)
-       {
-               // If $HOME is unset get the current user's home directory
-               // from the passwd file.
-               uid_t uid = geteuid();
-               if (!uid) uid = getuid();
-               struct passwd *pw = getpwuid(uid);
-               if (!pw) {
-                       return false;
-               }
-               homeDir = pw->pw_dir;
-       }
-       fullPathName = homeDir;
-       fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain";
-       ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef);
-       if(ortn) {
-               tpDebug("tpCheckPkinitServerCert: keychain not found (1)");
-               return false;
-       }
-       /* subsequent errors to errOut: */
-
-       bool ourRtn = false;
-       SecKeychainStatus kcStatus;
-       CSSM_DATA_PTR subjSerial = NULL;
-       CSSM_RETURN crtn;
-       SecKeychainSearchRef            srchRef = NULL;
-       SecKeychainAttributeList        attrList;
-       SecKeychainAttribute            attrs[2];
-       SecKeychainItemRef                      foundItem = NULL;
-
-       ortn = SecKeychainGetStatus(kcRef, &kcStatus);
-       if(ortn) {
-               tpDebug("tpCheckPkinitServerCert: keychain not found (2)");
-               goto errOut;
-       }
-
-       /*
-        * We already have this cert's normalized name; get its
-        * serial number.
-        */
-       crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
-       if(crtn) {
-               /* should never happen */
-               tpDebug("tpCheckPkinitServerCert: error fetching serial number");
-               goto errOut;
-       }
-
-       attrs[0].tag    = kSecSubjectItemAttr;
-       attrs[0].length = (UInt32)subjectName->Length;
-       attrs[0].data   = subjectName->Data;
-       attrs[1].tag    = kSecSerialNumberItemAttr;
-       attrs[1].length = (UInt32)subjSerial->Length;
-       attrs[1].data   = subjSerial->Data;
-       attrList.count  = 2;
-       attrList.attr   = attrs;
-
-       ortn = SecKeychainSearchCreateFromAttributes(kcRef,
-               kSecCertificateItemClass,
-               &attrList,
-               &srchRef);
-       if(ortn) {
-               tpDebug("tpCheckPkinitServerCert: search failure");
-               goto errOut;
-       }
-       for(;;) {
-               ortn = SecKeychainSearchCopyNext(srchRef, &foundItem);
-               if(ortn) {
-                       tpDebug("tpCheckPkinitServerCert: end search");
-                       break;
-               }
-
-               /* found a matching cert; do byte-for-byte compare */
-               CSSM_DATA certData;
-               ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData);
-               if(ortn) {
-                       tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure");
-                       continue;
-               }
-               if(tpCompareCssmData(&certData, theCert->itemData())){
-                       tpDebug("tpCheckPkinitServerCert: FOUND CERT");
-                       ourRtn = true;
-                       break;
-               }
-               tpDebug("tpCheckPkinitServerCert: skipping matching cert");
-               CFRelease(foundItem);
-               foundItem = NULL;
-       }
-errOut:
-       CFRELEASE(kcRef);
-       CFRELEASE(srchRef);
-       CFRELEASE(foundItem);
-       if(subjSerial != NULL) {
-               theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial);
-       }
-       return ourRtn;
-}
-#endif /* TP_PKINIT_SERVER_HACK */
 
 /*-----------------------------------------------------------------------------
  * CertGroupConstruct
@@ -829,16 +681,6 @@ void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand,
                        if(policyAbort) {
                                break;
                        }
-                       #if             TP_PKINIT_SERVER_HACK
-                       if(tpPolicy == kTP_PKINIT_Server) {
-                               /* possible override of "root not in anchors" */
-                               if(constructReturn == CSSMERR_TP_INVALID_ANCHOR_CERT) {
-                                       if(tpCheckPkinitServerCert(outCertGroup)) {
-                                               constructReturn = CSSM_OK;
-                                       }
-                               }
-                       }
-                       #endif  /* TP_PKINIT_SERVER_HACK */
                }
 
                /*
index 28e9e1793859310cea5dfe3235ac791d473bc1ca..2eb31d0833809ae29465af5442d913fb203e9ed5 100644 (file)
@@ -32,7 +32,7 @@
 #include <Security/cssmapple.h>
 #include <security_utilities/debugging.h>
 #include <Security/cssmapple.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #define tpCredDebug(args...)   secinfo("tpCred", ## args)
 
index 5ac0ef4fd1c2b5f7bb8f72cf9c69d940ac489cb1..786e2f8a23731d776dde091502dd968623dacd21 100644 (file)
@@ -31,7 +31,7 @@
 #include <security_utilities/globalizer.h>
 #include <security_utilities/threading.h>
 #include <security_ocspd/ocspdUtils.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 /*
  * Set this flag nonzero to turn off this cache module. Generally used to debug
index 17c152f83cd3036028314ee7ea87762f5f0a2f81..24a24e2e88b2cd6b0e1c19bcb80e1515e26d9790 100644 (file)
@@ -36,7 +36,7 @@
 #include <Security/SecCertificatePriv.h>
 #include <string.h>
 #include <ctype.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <CoreFoundation/CFString.h>
 #include <CommonCrypto/CommonDigest.h>
 
index 058cab00fbf8639e1d8f2c5832b6abad4ca7cd94..b0983af09c13a444e9ed2b4f8ce10248a7bf4492 100644 (file)
@@ -28,6 +28,8 @@
 #include <ctype.h>
 #include <stdbool.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 /*
  * Given a string containing either a UTC-style or "generalized time"
  * time string, convert to a CFDateRef. Returns nonzero on
index 067fb8d89ea84c0a9f3cae54b69395c4a7a625ce..ef321524c5188e704fc9b5c7f45c283fad4e9232 100644 (file)
@@ -32,7 +32,7 @@
 #include <security_utilities/utilities.h>
 #include <security_asn1/secasn1.h>
 #include <string.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #ifdef NDEBUG
 #define THROW_ENABLE   1
index 93dda3e7ae9994421e5edc8699dae455ab4668f8..302445c55cde24f27c5387081876843d548fd8f7 100644 (file)
@@ -26,7 +26,6 @@
 #include "SecAsn1Templates.h"
 #include "X509Templates.h"
 #include "keyTemplates.h"
-#include <assert.h>
 #include <stddef.h>
 
 /* 
index 84ce8b34a4d24760bbb35327163dde41c2b1ce22..370512d97580a8c0a11c748c0e01aeb87b3e67f4 100644 (file)
@@ -28,7 +28,7 @@
 #include "X509Templates.h"
 #include "keyTemplates.h"
 #include <stddef.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 typedef struct {
     SecAsn1Oid typeId;
index 0dcbf947821877444d048b547770c3609d91e067..8721457f36541e458ede0c0df544bdcab4c84aa6 100644 (file)
@@ -27,7 +27,6 @@
 #include "keyTemplates.h"              /* for kSecAsn1AlgorithmIDTemplate */
 #include "SecAsn1Templates.h"
 #include <stddef.h>
-#include <assert.h>
 
 // MARK: ----- OCSP Request -----
 
index 48c69b3e3faf3fa4f2cda50f8ea3ab79ca815d6b..b072da1e55f78c17860269882e725337a538edc9 100644 (file)
@@ -300,8 +300,9 @@ static void FreeArenaList(PLArenaPool *pool, PLArena *head, PRBool reallyFree)
 
     ap = &head->next;
     a = *ap;
-    if (!a)
+    if (!a) {
         return;
+    }
 
        do {
                *ap = a->next;
index c0b3b8418b2f0685e7b2b71de5348c44e3a0445f..9256da957a853d411e3ca7dc5004620871d7af75 100644 (file)
@@ -236,7 +236,7 @@ NSPR_API(void) PR_LogFlush(void);
 
 #ifdef __APPLE__
 
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #define PR_ASSERT(_exp)                        assert(_exp)
 #define PR_NOT_REACHED(_reas)  assert(0)
@@ -250,10 +250,19 @@ NSPR_API(void) PR_Assert(const char *s, const char *file, PRIntn ln);
     PR_Assert(_reasonStr,__FILE__,__LINE__)
 #endif
 
-#else
+#else /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */
+
+#ifdef __APPLE__
 
+#include <security_utilities/simulatecrash_assert.h>
+
+#define PR_ASSERT(_exp)                        assert(_exp)
+#define PR_NOT_REACHED(_reas)  assert(0)
+
+#else
 #define PR_ASSERT(expr) ((void) 0)
 #define PR_NOT_REACHED(reasonStr)
+#endif
 
 #endif /* defined(DEBUG) || defined(FORCE_PR_ASSERT) */
 
index cd37fc4abc83adaf95c7cac36f235081ae3f547e..f33852704bbd54e6b2241cf5031ca108ca04f6a6 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "secasn1.h"
 #include "secerr.h"
-#include "assert.h"
+#include <security_utilities/simulatecrash_assert.h>
 
 #ifdef NDEBUG
 #define DEBUG_DECASN1  0
@@ -1879,8 +1879,9 @@ sec_asn1d_add_to_subitems (sec_asn1d_state *state,
        if (copy == NULL) {
                dprintf("decodeError: alloc\n");        
            state->top->status = decodeError;
-        if (!state->top->our_pool)
+        if (!state->top->our_pool) {
             PORT_Free(thing);
+        }
            return NULL;
        }
        PORT_Memcpy (copy, data, len);
diff --git a/OSX/libsecurity_asn1/security_asn1 b/OSX/libsecurity_asn1/security_asn1
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index 92e1faf0c965ba809e5ac8808a1149853bbb41c8..e88dae1fdaf4b0c99daf4ada03236864eeb7a3cc 100644 (file)
@@ -14,7 +14,6 @@
 #include <xpc/xpc.h>
 #include <xpc/private.h>
 #include <mach/mach.h>
-#include <syslog.h>
 #include <AssertMacros.h>
 #include <CoreFoundation/CFXPCBridge.h>
 #include <CoreGraphics/CGWindow.h>
@@ -53,20 +52,24 @@ get_authorization_connection()
             connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
 
             if (!connection) {
-                syslog(LOG_ERR, "Authorization, failed to create xpc connection to %s", SECURITY_AUTH_NAME);
+                os_log_error(AUTH_LOG, "Failed to create xpc connection to %s", SECURITY_AUTH_NAME);
                 connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
             }
             
+            if (connection == NULL) {
+                os_log_error(AUTH_LOG, "Still failed to create xpc connection to %s", SECURITY_AUTH_NAME);
+                return;
+            }
             xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
                 if (xpc_get_type(event) == XPC_TYPE_ERROR) {
                     if (event == XPC_ERROR_CONNECTION_INVALID) {
-                        syslog(LOG_ERR, "Authorization, server not available");
+                        os_log_error(AUTH_LOG, "Server not available");
                     }
                     // XPC_ERROR_CONNECTION_INTERRUPTED
                     // XPC_ERROR_TERMINATION_IMMINENT
                 } else {
                     char * desc = xpc_copy_description(event);
-                    syslog(LOG_ERR, "Authorization, we should never get messages on this connection: %s", desc);
+                    os_log_error(AUTH_LOG, "We should never get messages on this connection: %s", desc);
                     free(desc);
                 }
             });
@@ -119,7 +122,9 @@ OSStatus AuthorizationCreate(const AuthorizationRights *rights,
     xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags | (authorization ? 0 : kAuthorizationFlagNoData));
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action_quiet(reply != NULL, done, status = errAuthorizationInternal);
     require_action_quiet(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal;);
 
@@ -131,7 +136,7 @@ OSStatus AuthorizationCreate(const AuthorizationRights *rights,
         size_t len;
         const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
         require_action(data != NULL, done, status = errAuthorizationInternal);
-        assert(len == sizeof(AuthorizationBlob));
+        require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
         
         AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
         require_action(blob != NULL, done, status = errAuthorizationInternal);
@@ -167,7 +172,9 @@ OSStatus AuthorizationCreateWithAuditToken(audit_token_t token,
     xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -179,8 +186,8 @@ OSStatus AuthorizationCreateWithAuditToken(audit_token_t token,
         size_t len;
         const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
         require_action(data != NULL, done, status = errAuthorizationInternal);
-        assert(len == sizeof(AuthorizationBlob));
-        
+        require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
+
         AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
         require_action(blob != NULL, done, status = errAuthorizationInternal);
         *blob = *(AuthorizationBlob*)data;
@@ -213,7 +220,9 @@ OSStatus AuthorizationFree(AuthorizationRef authorization, AuthorizationFlags fl
     xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
 
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -229,62 +238,40 @@ done:
     return status;
 }
 
-static OSStatus
-_AuthorizationPreauthorizeCredentials_send_message(xpc_object_t message)
-{
-       OSStatus status = errAuthorizationInternal;
-       xpc_object_t reply = NULL;
-
-       // Send
-       require_action(message != NULL, done, status = errAuthorizationInternal);
-
-       // Reply
-       reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
-       require_action(reply != NULL, done, status = errAuthorizationInternal);
-       require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
-
-       // Status
-       status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
-
-done:
-       xpc_release_safe(reply);
-       return status;
-}
-
-static OSStatus
-_AuthorizationPreauthorizeCredentials_prepare_message(AuthorizationRef authorization, const AuthorizationItemSet *credentials, xpc_object_t *message_out)
+OSStatus AuthorizationCopyRightProperties(const char *rightName, CFDictionaryRef *output)
 {
-       OSStatus status = errAuthorizationInternal;
-       AuthorizationBlob *blob = NULL;
-       xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
-       require_action(message != NULL, done, status = errAuthorizationInternal);
-
-       require_action(authorization != NULL, done, status = errAuthorizationInvalidRef);
-       blob = (AuthorizationBlob *)authorization;
-
-       xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_PREAUTHORIZE_CREDENTIALS);
-       xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
-       setItemSet(message, AUTH_XPC_DATA, credentials);
-
-       *message_out = message;
-       message = NULL;
-       status = errAuthorizationSuccess;
-
-done:
-       xpc_release_safe(message);
-       return status;
-}
-
-OSStatus AuthorizationPreauthorizeCredentials(AuthorizationRef authorization, const AuthorizationItemSet *credentials)
-{
-       OSStatus status = errAuthorizationInternal;
-       xpc_object_t message = NULL;
-
-       require_noerr(status = _AuthorizationPreauthorizeCredentials_prepare_message(authorization, credentials, &message), done);
-       require_noerr(status = _AuthorizationPreauthorizeCredentials_send_message(message), done);
-
+    OSStatus status = errAuthorizationInternal;
+    xpc_object_t reply = NULL;
+    CFDataRef data = NULL;
+    xpc_object_t message = NULL;
+    require_action(rightName != NULL, done, status = errAuthorizationInvalidPointer);
+    
+    message = xpc_dictionary_create(NULL, NULL, 0);
+    require_action(message != NULL, done, status = errAuthorizationInternal);
+    
+    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHT_PROPERTIES);
+    xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
+    
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
+    require_action(reply != NULL, done, status = errAuthorizationInternal);
+    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
+    
+    // Status
+    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
+    if (output && status == errAuthorizationSuccess) {
+        size_t len;
+        const void *bytes = xpc_dictionary_get_data(reply, AUTH_XPC_OUT_ITEMS, &len);
+        data = CFDataCreate(kCFAllocatorDefault, bytes, len);
+        require_action(data != NULL, done, status = errAuthorizationInternal);
+        *output = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
+    }
 done:
        xpc_release_safe(message);
+    xpc_release_safe(reply);
+    CFReleaseSafe(data);
+    
        return status;
 }
 
@@ -298,7 +285,9 @@ _AuthorizationCopyRights_send_message(xpc_object_t message, AuthorizationRights
     require_action(message != NULL, done, status = errAuthorizationInternal);
 
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
 
@@ -440,7 +429,9 @@ OSStatus AuthorizationDismiss()
     xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_DISMISS);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -477,7 +468,9 @@ OSStatus AuthorizationCopyInfo(AuthorizationRef authorization,
     }
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -519,7 +512,9 @@ OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
     xpc_dictionary_set_data(message, AUTH_XPC_BLOB, blob, sizeof(AuthorizationBlob));
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -531,8 +526,8 @@ OSStatus AuthorizationMakeExternalForm(AuthorizationRef authorization,
         size_t len;
         const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_EXTERNAL, &len);
         require_action(data != NULL, done, status = errAuthorizationInternal);
-        assert(len == sizeof(AuthorizationExternalForm));
-        
+        require_action(len == sizeof(AuthorizationExternalForm), done, status = errAuthorizationInternal);
+
         *extForm = *(AuthorizationExternalForm*)data;
     }
     
@@ -560,7 +555,9 @@ OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *ex
     xpc_dictionary_set_data(message, AUTH_XPC_EXTERNAL, extForm, sizeof(AuthorizationExternalForm));
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -572,8 +569,8 @@ OSStatus AuthorizationCreateFromExternalForm(const AuthorizationExternalForm *ex
         size_t len;
         const void * data = xpc_dictionary_get_data(reply, AUTH_XPC_BLOB, &len);
         require_action(data != NULL, done, status = errAuthorizationInternal);
-        assert(len == sizeof(AuthorizationBlob));
-        
+        require_action(len == sizeof(AuthorizationBlob), done, status = errAuthorizationInternal);
+
         AuthorizationBlob * blob = (AuthorizationBlob*)calloc(1u, sizeof(AuthorizationBlob));
         require_action(blob != NULL, done, status = errAuthorizationInternal);
         *blob = *(AuthorizationBlob*)data;
@@ -610,7 +607,9 @@ OSStatus AuthorizationEnableSmartCard(AuthorizationRef authRef, Boolean enable)
     xpc_dictionary_set_bool(message, AUTH_XPC_DATA, enable);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -640,7 +639,9 @@ OSStatus AuthorizationRightGet(const char *rightName,
     xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -784,7 +785,9 @@ OSStatus AuthorizationRightSet(AuthorizationRef authRef,
     xpc_release_safe(value);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -820,7 +823,9 @@ OSStatus AuthorizationRightRemove(AuthorizationRef authorization,
     xpc_dictionary_set_string(message, AUTH_XPC_RIGHT_NAME, rightName);
     
     // Reply
-    reply = xpc_connection_send_message_with_reply_sync(get_authorization_connection(), message);
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
     require_action(reply != NULL, done, status = errAuthorizationInternal);
     require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
     
@@ -832,3 +837,40 @@ done:
     xpc_release_safe(reply);
     return status;
 }
+
+OSStatus AuthorizationCopyPreloginUserDatabase(const char * _Nullable const volumeUuid, const UInt32 flags, CFArrayRef _Nonnull * _Nonnull output)
+{
+    OSStatus status = errAuthorizationInternal;
+    xpc_object_t message = NULL;
+    xpc_object_t reply = NULL;
+
+    require_action(output != NULL, done, status = errAuthorizationInvalidRef);
+    
+    // Send
+    message = xpc_dictionary_create(NULL, NULL, 0);
+    require_action(message != NULL, done, status = errAuthorizationInternal);
+    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_PRELOGIN_USERDB);
+    if (volumeUuid) {
+        xpc_dictionary_set_string(message, AUTH_XPC_TAG, volumeUuid);
+    }
+    xpc_dictionary_set_uint64(message, AUTH_XPC_FLAGS, flags);
+
+    // Reply
+    xpc_connection_t conn = get_authorization_connection();
+    require_action(conn != NULL, done, status = errAuthorizationInternal);
+    reply = xpc_connection_send_message_with_reply_sync(conn, message);
+    require_action(reply != NULL, done, status = errAuthorizationInternal);
+    require_action(xpc_get_type(reply) != XPC_TYPE_ERROR, done, status = errAuthorizationInternal);
+    
+    status = (OSStatus)xpc_dictionary_get_int64(reply, AUTH_XPC_STATUS);
+    
+    // fill the output
+    if (status == errAuthorizationSuccess) {
+        *output = _CFXPCCreateCFObjectFromXPCObject(xpc_dictionary_get_value(reply, AUTH_XPC_DATA));
+    }
+
+done:
+    xpc_release_safe(message);
+    xpc_release_safe(reply);
+    return status;
+}
index 71db80cf8b20375a2e9bddd2f506e96f74890ccb..5cdbab487285e455bdc911bffa7d3fe09ae85cb8 100644 (file)
@@ -34,6 +34,7 @@
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/SecBase.h>
 #include <security_utilities/logging.h>
+#include "LegacyAPICounts.h"
 
 //
 // This no longer talks to securityd; it is a kernel function.
@@ -105,75 +106,7 @@ OSStatus SessionGetDistinguishedUser(SecuritySessionId session, uid_t *user)
     END_API(CSSM)
 }
 
-//OSStatus _SessionSetUserPreferences(SecuritySessionId session);
-//
-//static
-//void SessionUserPreferencesChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
-//{
-//#warning "The cast will loose some information"
-//     _SessionSetUserPreferences((SecuritySessionId)uintptr_t(observer));
-//}
-//
-//OSStatus _SessionSetUserPreferences(SecuritySessionId session)
-//{
-//    BEGIN_API
-//     CFStringRef appleLanguagesStr = CFSTR("AppleLanguages");
-//     CFStringRef controlTintStr = CFSTR("AppleAquaColorVariant");
-//     CFStringRef keyboardUIModeStr = CFSTR("AppleKeyboardUIMode");
-//     CFStringRef textDirectionStr = CFSTR("AppleTextDirection");
-//     CFStringRef hitoolboxAppIDStr = CFSTR("com.apple.HIToolbox");
-//     CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
-//
-//     CFRef<CFMutableDictionaryRef> userPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-//     CFRef<CFMutableDictionaryRef> globalPrefsDict(CFDictionaryCreateMutable(NULL, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
-//     
-//     if (!userPrefsDict || !globalPrefsDict)
-//             return errSessionValueNotSet;
-//     
-//     CFRef<CFArrayRef> appleLanguagesArray(static_cast<CFArrayRef>(CFPreferencesCopyAppValue(appleLanguagesStr, kCFPreferencesCurrentApplication)));
-//     if (appleLanguagesArray)
-//             CFDictionarySetValue(globalPrefsDict, appleLanguagesStr, appleLanguagesArray);
-//     
-//     CFRef<CFNumberRef> controlTintNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(controlTintStr, kCFPreferencesCurrentApplication)));
-//     if (controlTintNumber)
-//             CFDictionarySetValue(globalPrefsDict, controlTintStr, controlTintNumber);
-//
-//     CFRef<CFNumberRef> keyboardUIModeNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(keyboardUIModeStr, kCFPreferencesCurrentApplication)));
-//     if (keyboardUIModeNumber)
-//             CFDictionarySetValue(globalPrefsDict, keyboardUIModeStr, keyboardUIModeNumber);
-//
-//     CFRef<CFNumberRef> textDirectionNumber(static_cast<CFNumberRef>(CFPreferencesCopyAppValue(textDirectionStr, kCFPreferencesCurrentApplication)));
-//     if (textDirectionNumber)
-//             CFDictionarySetValue(globalPrefsDict, textDirectionStr, textDirectionNumber);
-//     
-//     if (CFDictionaryGetCount(globalPrefsDict) > 0)
-//             CFDictionarySetValue(userPrefsDict, kCFPreferencesAnyApplication, globalPrefsDict);
-//
-//     CFPreferencesSynchronize(hitoolboxAppIDStr, kCFPreferencesCurrentUser, 
-//                     kCFPreferencesCurrentHost);
-//     CFRef<CFDictionaryRef> hitoolboxPrefsDict(static_cast<CFDictionaryRef>(CFPreferencesCopyMultiple(NULL, hitoolboxAppIDStr, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)));
-//     if (hitoolboxPrefsDict) {
-//             CFDictionarySetValue(userPrefsDict, hitoolboxAppIDStr, hitoolboxPrefsDict);
-//             CFNotificationCenterPostNotification(center, CFSTR("com.apple.securityagent.InputPrefsChanged"), CFSTR("com.apple.loginwindow"), hitoolboxPrefsDict, true);
-//     }
-//     
-//     CFRef<CFDataRef> userPrefsData(CFPropertyListCreateXMLData(NULL, userPrefsDict));
-//     if (!userPrefsData)
-//             return errSessionValueNotSet;
-//     server().setSessionUserPrefs(session, (uint32_t)CFDataGetLength(userPrefsData), CFDataGetBytePtr(userPrefsData));
-//
-//    END_API(CSSM)
-//}
-
 OSStatus SessionSetUserPreferences(SecuritySessionId session)
 {
-//     OSStatus status = _SessionSetUserPreferences(session);
-//     if (errSecSuccess == status) {
-//             CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter();
-//             // We've succeeded in setting up a static set of prefs, now set up 
-//             CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifySelectedKeyboardInputSourceChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
-//             CFNotificationCenterAddObserver(center, (void*)session, SessionUserPreferencesChanged, CFSTR("com.apple.Carbon.TISNotifyEnabledKeyboardInputSourcesChanged"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
-//     }
-//     return status;
     return errSecSuccess;
 }
index 41f33df7df187118fedba9a2af717e264c416cde..534c8adf5b3f9aeb2c5e72593494c7c45ea7fcc3 100644 (file)
@@ -145,7 +145,7 @@ typedef const char *AuthorizationString;
 
 
 /*!
-       @struct AuthorizationItem
+       @typedef AuthorizationItem
        Each AuthorizationItem describes a single string-named item with optional
        parameter value. The value must be contiguous memory of valueLength bytes;
        internal structure is defined separately for each name.
@@ -165,7 +165,7 @@ typedef struct {
 
 
 /*!
-       @struct AuthorizationItemSet
+       @typedef AuthorizationItemSet
        An AuthorizationItemSet structure represents a set of zero or more AuthorizationItems.  Since it is a set it should not contain any identical AuthorizationItems.
 
        @field count Number of items identified by items.
@@ -179,7 +179,7 @@ typedef struct {
 
 static const size_t kAuthorizationExternalFormLength = 32;
 /*!
-       @struct AuthorizationExternalForm
+       @typedef AuthorizationExternalForm
        An AuthorizationExternalForm structure can hold the externalized form of
        an AuthorizationRef. As such, it can be transmitted across IPC channels
        to other processes, which can re-internalize it to recover a valid AuthorizationRef
index de083b3f0ef34f70ac322a87c2a1446cc659b166..4447c72ab366f78ccda587aabcdb7689152c9687 100644 (file)
@@ -181,7 +181,7 @@ enum {
 
 
 /*!
-    @struct
+    @typedef
     Callback API provided by the AuthorizationEngine. 
     
     @field version      Engine callback version.
@@ -289,7 +289,7 @@ typedef struct AuthorizationCallbacks {
 
 
 /*!
-    @struct
+    @typedef
     Interface that must be implemented by each plugin. 
     
     @field version  Must be set to kAuthorizationPluginInterfaceVersion
index bd9ec9365a973d6b10b915aa171f059d9f31773c..d66b9cca40ace273c645a98a03b081c85eb61e54 100644 (file)
@@ -35,6 +35,7 @@
 #include <Security/AuthSession.h>
 #include <sys/types.h> // uid_t
 #include <mach/message.h>
+#include <CoreFoundation/CFDictionary.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -133,12 +134,13 @@ OSStatus AuthorizationExecuteWithPrivileges(AuthorizationRef _Nonnull authorizat
                                                                                                FILE * __nullable * __nullable communicationsPipe) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_1,__MAC_10_7,__IPHONE_NA,__IPHONE_NA);
 
 /*!
- @function AuthorizationPreauthorizeCredentials
- Tries to preauthorize provided credentials by authorizationhost PAM. No user interface will be shown.
- Credentials is set of the context items which will be passed to the authorizationhost.
+ @function AuthorizationCopyRightProperties
+ Returns a dictionary with the properties associated with the given authorization right
+ @param rightName right name for which we need the propertiers
+ @param output CFDictionaryRef which will hold the properties
+
  */
-OSStatus AuthorizationPreauthorizeCredentials(AuthorizationRef _Nonnull authorization,
-                                                                                         const AuthorizationItemSet * __nonnull credentials) __OSX_AVAILABLE_STARTING(__MAC_10_3, __IPHONE_NA);
+OSStatus AuthorizationCopyRightProperties(const char * __nonnull rightName, CFDictionaryRef __nullable * __nullable output) __OSX_AVAILABLE_STARTING(__MAC_10_15, __IPHONE_NA);
 
 /*!
  @function AuthorizationCopyPrivilegedReference
@@ -230,7 +232,7 @@ OSStatus AuthorizationEnableSmartCard(AuthorizationRef _Nonnull authRef, Boolean
      @param stdIn File descriptor which will contain write-end of the stdin pipe of the privileged tool, use -1 if not needed.
      @param processFinished This block is called when privileged process finishes.
      */
-    OSStatus AuthorizationExecuteWithPrivilegesInternal(const AuthorizationRef _Nonnull authorization,
+OSStatus AuthorizationExecuteWithPrivilegesInternal(const AuthorizationRef _Nonnull authorization,
                                                         const char * _Nonnull pathToTool,
                                                         const char * _Nonnull const * _Nonnull arguments,
                                                         pid_t * _Nullable newProcessPid,
@@ -259,7 +261,7 @@ OSStatus AuthorizationEnableSmartCard(AuthorizationRef _Nonnull authRef, Boolean
      @param stdIn File descriptor which will contain write-end of the stdin pipe of the privileged tool, use -1 if not needed.
      @param processFinished This block is called when privileged process finishes.
      */
-    OSStatus AuthorizationExecuteWithPrivilegesExternalFormInternal(const AuthorizationExternalForm * _Nonnull extAuthorization,
+OSStatus AuthorizationExecuteWithPrivilegesExternalFormInternal(const AuthorizationExternalForm * _Nonnull extAuthorization,
                                                                     const char * _Nonnull pathToTool,
                                                                     const char * _Nullable const * _Nullable arguments,
                                                                     pid_t * _Nullable newProcessPid,
@@ -268,6 +270,17 @@ OSStatus AuthorizationEnableSmartCard(AuthorizationRef _Nonnull authRef, Boolean
                                                                     int stdErr,
                                                                     int stdIn,
                                                                     void(^__nullable processFinished)(const int exitStatus));
+
+/*!
+    @function AuthorizationCopyPreloginUserDatabase
+    Returns CFArrayRef with user database from Prelogin volume
+
+    @param volumeUuid Optional uuid of the volume for which user database will be returned. If not set, users from all volumes are returned.
+    @param flags Specifies subset of data required in the output
+    @param output Output array of dictionaries- each dictionary with details for each user
+*/
+OSStatus AuthorizationCopyPreloginUserDatabase(const char * _Nullable const volumeUuid, const UInt32 flags, CFArrayRef _Nonnull * _Nonnull output);
+
 #if defined(__cplusplus)
 }
 #endif
index 8800d326fc803e6416ac1da1db7038b01fac6282..b3654b188fba01ce08c3d495e5871626d4db50ce 100644 (file)
 #define AGENT_HINT_SHOW_RESET "show-reset"
 #define AGENT_HINT_PASSWORD_ONLY "password-only"
 #define AGENT_HINT_SHEET_CONTEXT "sheet-context"
+#define AGENT_HINT_LACONTEXT "lacontext"
+#define AGENT_HINT_REQUIRED_USER "required-user"
 
 // Public Key Hash from certificate used for login
 #define AGENT_HINT_TOKEN_HASH "token-hash"
 #define AGENT_HINT_IGNORE_SESSION "ignore-session-state"
 #define AGENT_HINT_NO_UI_EXPECTED "no-ui-expected"
 
+/* LocalAuthentication specific */
+#define AGENT_HINT_EXT_PASSWORD "la-ext-passwd"
+
 /* Keychain synchronization */
 // iDisk keychain blob metainfo dictionary; follows "defaults" naming
 #define AGENT_HINT_KCSYNC_DICT "com.apple.keychainsync.dictionary"
 /* Sheet window ID */
 #define kAuthorizationEnvironmentWindowId "cgwindowid"
 
+/* LWOS authenticate approval and admin status */
+#define kAuthorizationFVAdmin "fvadmin"
+
+/* Prelogin user database defines */
+#define PLUDB_USERNAME "username"
+#define PLUDB_LUSERNAME "lusername"
+#define PLUDB_KEK "kek"
+#define PLUDB_VEK "vek"
+#define PLUDB_GUID "guid"
+#define PLUDB_ADMIN "admin"
+#define PLUDB_SCPAIR "scpairing"
+#define PLUDB_IMAGE "image"
+#define PLUDB_PWDHINT "pwdhint"
+#define PLUDB_SCUNLOCK_DATA "scunl"
+#define PLUDB_SCENF "scen"
+#define PLUDB_SCUAC "scuac"
+#define PLUDB_DNODE "dnode"
+#define PLUDB_OWNER "owner"
+
+/* FVUnlock related defines */
+#define AGENT_FVUNLOCK_USER "fvusername"
+#define AGENT_FVUNLOCK_PASSWORD "fvpassword"
+
+/* PRL related defines */
+#define AGENT_CONTEXT_AKS_MAX_ATTEMPTS "aks-max-attempts"
+#define AGENT_CONTEXT_AKS_FAILURES "aks-fail-count"
+#define AGENT_CONTEXT_AKS_BACKOFF "aks-backoff"
+
 #endif /* !_SECURITY_AUTHORIZATIONTAGSPRIV_H_ */
index b7c5ee855b0ecbbd24c8ef9e88a90aaf081f60f8..943a8badb3261c5586cd320df767613866421053 100644 (file)
@@ -25,7 +25,6 @@
 //
 // trampolineClient - Authorization trampoline client-side implementation
 //
-#include <asl.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <errno.h>
@@ -106,13 +105,6 @@ FILE **communicationsPipe)
     if (extForm == NULL)
         return errAuthorizationInvalidPointer;
     
-    // report the caller to the authorities
-    aslmsg m = asl_new(ASL_TYPE_MSG);
-    asl_set(m, "com.apple.message.domain", "com.apple.libsecurity_authorization.AuthorizationExecuteWithPrivileges");
-    asl_set(m, "com.apple.message.signature", getprogname());
-    asl_log(NULL, m, ASL_LEVEL_NOTICE, "AuthorizationExecuteWithPrivileges!");
-    asl_free(m);
-    
     // flags are currently reserved
     if (flags != 0)
         return errAuthorizationInvalidFlags;
index 1fd0e6e82ef08b595bc91e0cf7b803c725ed7fd2..bf2fccfa8bf6035472b522616cd83ae2178c2f88 100644 (file)
@@ -38,7 +38,7 @@ using namespace CssmClient;
 // Exception model
 //
 const char *
-Error::what () const throw()
+Error::what () const _NOEXCEPT
 {
        return "CSSM client library error";
 }
index a7bc57ea6989021becd05a1a75d48bcf98afe0c1..34fa6643f34b2042356bbcd05bd71093908e64bb 100644 (file)
@@ -66,7 +66,7 @@ private:
 class Error : public CssmError {
 public:
        Error(CSSM_RETURN err) : CssmError(err, false) { }
-       virtual const char *what () const throw();
+       virtual const char *what () const _NOEXCEPT;
        
        enum {
                objectBusy = -1,
index 6caef051a3733ef6fe422647b175668e54788917..7a8bf719c402882c4f542dcb8fb6857ed3ada8d1 100644 (file)
@@ -6,7 +6,8 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/cssmaci.h>
-
+// The disclaimer up top used to be true but rdar://24426719 removed libsecurity_cdsa_plugin_generate
+#include "LegacyAPICounts.h"
 
 ACAbstractPluginSession::~ACAbstractPluginSession()
 { /* virtual */ }
index bfb5e7fe73efab115b2878a78d31f34b52bf1e0c..daeade84215a79d84b2d46ef7e1193ef6fd8596f 100644 (file)
@@ -6,7 +6,8 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/cssmcli.h>
-
+// The disclaimer up top used to be true but rdar://24426719 removed libsecurity_cdsa_plugin_generate
+#include "LegacyAPICounts.h"
 
 CLAbstractPluginSession::~CLAbstractPluginSession()
 { /* virtual */ }
index a138ed2e06399ef758ef1b5b65750c7da9eddf1c..980e4cd91cbfd85e6a44e546778b8315a7700177 100644 (file)
@@ -6,7 +6,8 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/cssmcspi.h>
-
+// The disclaimer up top used to be true but rdar://24426719 removed libsecurity_cdsa_plugin_generate
+#include "LegacyAPICounts.h"
 
 CSPAbstractPluginSession::~CSPAbstractPluginSession()
 { /* virtual */ }
index d29da3d4007cd7fe1b0245fc5b70881690542f8d..a6dc6dcce2334fd88cf669fbe42ec68c60f94f47 100644 (file)
@@ -6,6 +6,8 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/cssmdli.h>
+// The disclaimer up top used to be true but rdar://24426719 removed libsecurity_cdsa_plugin_generate
+#include "LegacyAPICounts.h"
 
 
 DLAbstractPluginSession::~DLAbstractPluginSession()
index 89a8869016080e21ceec073d1228d7a8e5b3b1ab..1b9ee4bf01e4bc9be4c720c69a81085aa021a14f 100644 (file)
@@ -47,11 +47,11 @@ DLPluginSession::DLPluginSession(CSSM_MODULE_HANDLE theHandle,
 //
 // Implement Allocator methods from the PluginSession side
 //
-void *DLPluginSession::malloc(size_t size) throw(std::bad_alloc)
+void *DLPluginSession::malloc(size_t size)
 { return PluginSession::malloc(size); }
 
-void DLPluginSession::free(void *addr) throw()
+void DLPluginSession::free(void *addr) _NOEXCEPT
 { return PluginSession::free(addr); }
 
-void *DLPluginSession::realloc(void *addr, size_t size) throw(std::bad_alloc)
+void *DLPluginSession::realloc(void *addr, size_t size)
 { return PluginSession::realloc(addr, size); }
index 67c35ecb8a8ade5fb211de2ff07729e77d741d64..cbd5613560cdf81dc1e536ae570f98d368ff0706 100644 (file)
@@ -44,9 +44,9 @@ public:
                     const CSSM_UPCALLS &upcalls,
                     DatabaseManager &databaseManager);
 
-       void *malloc(size_t size) throw(std::bad_alloc);
-       void free(void *addr) throw();
-       void *realloc(void *addr, size_t size) throw(std::bad_alloc);
+       void *malloc(size_t size);
+       void free(void *addr) _NOEXCEPT;
+       void *realloc(void *addr, size_t size);
 
 protected:
     CSSM_MODULE_FUNCS_PTR construct();
index ef7da4341d1438620cd66a52774b490f955969d5..f34f5ba4d947bb24808af480c9d405e05e6c2357 100644 (file)
@@ -39,7 +39,7 @@ DatabaseManager::get (const DbName &inDbName)
     DatabaseMap::iterator anIterator = mDatabaseMap.find (inDbName);
     if (anIterator == mDatabaseMap.end())
     {
-        auto_ptr<Database> aDatabase(make(inDbName));
+        unique_ptr<Database> aDatabase(make(inDbName));
         mDatabaseMap.insert(DatabaseMap::value_type(aDatabase->mDbName, aDatabase.get()));
         return aDatabase.release();
     }
@@ -164,7 +164,7 @@ Database::_dbOpen(DatabaseSession &inDatabaseSession,
                   const AccessCredentials *inAccessCred,
                   const void *inOpenParameters)
 {
-    auto_ptr<DbContext>aDbContext(makeDbContext(inDatabaseSession,
+    unique_ptr<DbContext>aDbContext(makeDbContext(inDatabaseSession,
                                                 inAccessRequest,
                                                 inAccessCred,
                                                 inOpenParameters));
@@ -195,7 +195,7 @@ Database::_dbCreate(DatabaseSession &inDatabaseSession,
                     const CSSM_RESOURCE_CONTROL_CONTEXT *inCredAndAclEntry,
                     const void *inOpenParameters)
 {
-    auto_ptr<DbContext>aDbContext(makeDbContext(inDatabaseSession,
+    unique_ptr<DbContext>aDbContext(makeDbContext(inDatabaseSession,
                                                 inAccessRequest,
                                                 (inCredAndAclEntry
                                                                                                 ? AccessCredentials::optional(inCredAndAclEntry->AccessCred)
index 15a6f6957e26445bfeca8a03c29e787b608d0f25..723b1e2f5ef6a006ae23be4927553f46eb9af9c8 100644 (file)
@@ -192,7 +192,7 @@ DatabaseSession::DbClose(CSSM_DB_HANDLE inDbHandle)
     DbContextMap::iterator it = mDbContextMap.find(inDbHandle);
     if (it == mDbContextMap.end())
         CssmError::throwMe(CSSM_ERRCODE_INVALID_DB_HANDLE);
-    auto_ptr<DbContext> aDbContext(it->second);
+    unique_ptr<DbContext> aDbContext(it->second);
     mDbContextMap.erase(it);
     mDatabaseManager.dbClose(*aDbContext);
 }
index acfb0493ef0fc69e54748d2f21f89f4af2baea7e..1396717f47db64d759d6f12846c9eac629e98c7c 100644 (file)
@@ -6,7 +6,8 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_utilities/cssmbridge.h>
 #include <Security/cssmtpi.h>
-
+// The disclaimer up top used to be true but rdar://24426719 removed libsecurity_cdsa_plugin_generate
+#include "LegacyAPICounts.h"
 
 TPAbstractPluginSession::~TPAbstractPluginSession()
 { /* virtual */ }
index e0d78ff14539b518c694b2864a6a177fd38be53b..55a43002f6fce7ed8d5dfe47d9107d5e8b3ef99c 100644 (file)
@@ -33,9 +33,10 @@ using LowLevelMemoryUtilities::increment;
 CSPFullPluginSession::Writer::Writer(CssmData *v, uint32 n, CssmData *rem)
 : vec(v), firstVec(v), lastVec(v + n - 1), remData(rem)
 {
-    if (vec == NULL || n == 0)
+    if (vec == NULL || n == 0) {
         CssmError::throwMe(CSSMERR_CSP_INVALID_OUTPUT_VECTOR); // CDSA p.253, amended
-       useData(vec);
+    }
+    useData(vec);
     written = 0;
 }
 
index c8680c4b0f9ca6cae508761755255f7229ffe482..c1c7e7c6ffaee543bcc25217d7fa4a41b21db93e 100644 (file)
@@ -27,6 +27,7 @@
 #include <security_cdsa_plugin/cssmplugin.h>
 #include <security_cdsa_plugin/pluginsession.h>
 #include <memory>
+#include "LegacyAPICounts.h"
 
 
 ModuleNexus<CssmPlugin::SessionMap> CssmPlugin::sessionMap;
@@ -54,10 +55,13 @@ void CssmPlugin::moduleLoad(const Guid &cssmGuid,
                 const Guid &moduleGuid,
                 const ModuleCallback &newCallback)
 {
-    if (mLoaded)
+    static dispatch_once_t onceToken;
+    countLegacyAPI(&onceToken, "CssmPlugin::moduleLoad");
+    if (mLoaded) {
         CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
-        
-       mMyGuid = moduleGuid;
+    }
+
+    mMyGuid = moduleGuid;
 
     // let the implementation know that we're loading
        this->load();
@@ -78,12 +82,16 @@ void CssmPlugin::moduleUnload(const Guid &cssmGuid,
                                const Guid &moduleGuid,
                 const ModuleCallback &oldCallback)
 {
+    // These are called from the public pluginspi.h
+    static dispatch_once_t onceToken;
+    countLegacyAPI(&onceToken, "CssmPlugin::moduleUnload");
     // check the callback vector
-    if (!mLoaded || oldCallback != mCallback)
+    if (!mLoaded || oldCallback != mCallback) {
         CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
+    }
 
     // tell our subclass that we're closing down
-       this->unload();
+    this->unload();
 
     // commit closure
     mLoaded = false;
@@ -108,12 +116,14 @@ void CssmPlugin::moduleAttach(CSSM_MODULE_HANDLE theHandle,
                               const CSSM_UPCALLS &upcalls,
                               CSSM_MODULE_FUNCS_PTR &funcTbl)
 {
+       static dispatch_once_t onceToken;
+       countLegacyAPI(&onceToken, "CssmPlugin::moduleAttach");
        // basic (in)sanity checks
        if (moduleGuid != mMyGuid)
                CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID);
     
     // make the new session object, hanging in thin air
-    auto_ptr<PluginSession> session(this->makeSession(theHandle,
+    unique_ptr<PluginSession> session(this->makeSession(theHandle,
                                          version,
                                          subserviceId, subserviceType,
                                          attachFlags,
@@ -140,6 +150,8 @@ void CssmPlugin::moduleAttach(CSSM_MODULE_HANDLE theHandle,
 //
 void CssmPlugin::moduleDetach(CSSM_MODULE_HANDLE handle)
 {
+       static dispatch_once_t onceToken;
+       countLegacyAPI(&onceToken, "CssmPlugin::moduleDetach");
        // locate the plugin and hold the sessionMapLock
        PluginSession *session;
        {
index c73328ceb500c89a44388100285f7d28eebb73cb..8de73c8d599ec03511b99f25adfc39b368c64201 100644 (file)
@@ -61,18 +61,20 @@ void PluginSession::detach()
 //
 // Allocation management
 //
-void *PluginSession::malloc(size_t size) throw(std::bad_alloc)
+void *PluginSession::malloc(size_t size)
 {
-    if (void *addr = upcalls.malloc_func(handle(), size))
+    if (void *addr = upcalls.malloc_func(handle(), size)) {
         return addr;
-       throw std::bad_alloc();
+    }
+    throw std::bad_alloc();
 }
 
-void *PluginSession::realloc(void *oldAddr, size_t size) throw(std::bad_alloc)
+void *PluginSession::realloc(void *oldAddr, size_t size)
 {
-    if (void *addr = upcalls.realloc_func(handle(), oldAddr, size))
+    if (void *addr = upcalls.realloc_func(handle(), oldAddr, size)) {
         return addr;
-       throw std::bad_alloc();
+    }
+    throw std::bad_alloc();
 }
 
 
index d58ba5ea8df2ee66ff3117c431ffb054f725c5ef..fe8c6461139c10bcc269f8fcd7008c239432aab0 100644 (file)
@@ -68,9 +68,9 @@ protected:
 
 public:
     // implement Allocator
-    void *malloc(size_t size) throw(std::bad_alloc);
-    void *realloc(void *addr, size_t size) throw(std::bad_alloc);
-    void free(void *addr) throw() { upcalls.free_func(handle(), addr); }
+    void *malloc(size_t size);
+    void *realloc(void *addr, size_t size);
+    void free(void *addr) _NOEXCEPT { upcalls.free_func(handle(), addr); }
 
        // about ourselves
        const CSSM_VERSION &version() const { return mVersion; }
index f5d8d49107c6a090524438a26dad61ef7c75c38e..3bc97d2942ca58888e5ea73a694f91d58237af09 100644 (file)
@@ -47,7 +47,7 @@ SPIPREFIX CSSM_RETURN SPINAME(CSSM_SPI_ModuleLoad) (const CSSM_GUID *CssmGuid,
     CSSM_SPI_ModuleEventHandler CssmNotifyCallback,
     void *CssmNotifyCallbackCtx)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     plugin().moduleLoad(Guid::required(CssmGuid),
         Guid::required(ModuleGuid),
         ModuleCallback(CssmNotifyCallback, CssmNotifyCallbackCtx));
@@ -64,7 +64,7 @@ SPIPREFIX CSSM_RETURN SPINAME(CSSM_SPI_ModuleUnload) (const CSSM_GUID *CssmGuid,
     CSSM_SPI_ModuleEventHandler CssmNotifyCallback,
     void *CssmNotifyCallbackCtx)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     plugin().moduleUnload(Guid::required(CssmGuid),
         Guid::required(ModuleGuid),
         ModuleCallback(CssmNotifyCallback, CssmNotifyCallbackCtx));
@@ -97,7 +97,7 @@ SPIPREFIX CSSM_RETURN SPINAME(CSSM_SPI_ModuleAttach) (const CSSM_GUID *ModuleGui
     const CSSM_UPCALLS *Upcalls,
     CSSM_MODULE_FUNCS_PTR *FuncTbl)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     plugin().moduleAttach(ModuleHandle,
         Guid::required(CssmGuid),
         Guid::required(ModuleGuid),
@@ -117,7 +117,7 @@ SPIPREFIX CSSM_RETURN SPINAME(CSSM_SPI_ModuleDetach) (CSSM_MODULE_HANDLE ModuleH
 
 SPIPREFIX CSSM_RETURN SPINAME(CSSM_SPI_ModuleDetach) (CSSM_MODULE_HANDLE ModuleHandle)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     plugin().moduleDetach(ModuleHandle);
     END_API(CSSM)
 }
index fdc29c9f5780bb9567c84b0bee7d9ebcaada968f..dccd5d931941096de23c13bdd1e281e071c48b2f 100644 (file)
@@ -104,9 +104,7 @@ CommentAclSubject *CommentAclSubject::Maker::make(Version, Reader &pub, Reader &
        // Phew. I'd rather be lucky than good...
        //
        // So let's get started:
-#ifndef NDEBUG
        static const size_t minCssmList = 12;   // min(sizeof(CSSM_LIST)) of all architectures
-#endif
        pub.get<void>(4);                       // skip first 4 bytes
        uint32_t lop; pub(lop);         // read L4n-or-(bottom of)P8h
        uint32_t tol; pub(tol);         // read T4h-or-L4n
index 7918ff4704dfdd41d7e4d262d31db3ef56e0c99d..d9773dae2543db36d51afe356fe9554cc8c1d64c 100644 (file)
@@ -89,11 +89,12 @@ ProcessAclSubject *ProcessAclSubject::Maker::make(const TypedList &list) const
     // validate input
     if (selector.version != CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION)
         CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
-    if (!selector.uses(CSSM_ACL_MATCH_BITS))
+    if (!selector.uses(CSSM_ACL_MATCH_BITS)) {
         CssmError::throwMe(CSSM_ERRCODE_INVALID_ACL_SUBJECT_VALUE);
+    }
         
     // okay
-       return new ProcessAclSubject(selector);
+    return new ProcessAclSubject(selector);
 }
 
 ProcessAclSubject *ProcessAclSubject::Maker::make(Version, Reader &pub, Reader &priv) const
index 7cccfa6d271a14cf3e0b3ce8341f960403509f64..9d45cd8e353083b2a160e8909724eb4d56169cac 100644 (file)
@@ -112,8 +112,9 @@ ThresholdAclSubject *ThresholdAclSubject::Maker::make(const TypedList &list) con
     // now compile the subSubjects
     AclSubjectVector elements(totalSubjects);
     const ListElement *subSubject = &list[3];
-    for (uint32 n = 0; n < totalSubjects; n++, subSubject = subSubject->next())
+    for (uint32 n = 0; n < totalSubjects; n++, subSubject = subSubject->next()) {
         elements[n] = ObjectAcl::make(subSubject->typedList());
+    }
        return new ThresholdAclSubject(totalSubjects, minimumNeeded, elements);
 }
 
index d5e9532dfbec3cb1be70506c2b17eb60bab9c00f..03db058fba242f72d80362d25704528a7220361f 100644 (file)
@@ -187,11 +187,11 @@ public:
        }
 
 public:
-    void *operator new (size_t size, Allocator &alloc) throw(std::bad_alloc)
+    void *operator new (size_t size, Allocator &alloc) 
     { return alloc.malloc(size); }
-    void operator delete (void *addr, size_t, Allocator &alloc) throw()
+    void operator delete (void *addr, size_t, Allocator &alloc) _NOEXCEPT
     { return alloc.free(addr); }
-    static void destroy(Context *context, Allocator &alloc) throw()
+    static void destroy(Context *context, Allocator &alloc) _NOEXCEPT
     { alloc.free(context->ContextAttributes); alloc.free(context); }
        
 public:
index 63d262b28d2170751c5137f0a19d0acf6263fbfd..a7bb291ca68f41cda3c9b6c1e3f9964b6078fbca 100644 (file)
@@ -40,13 +40,13 @@ namespace Security {
 //
 // CssmMemoryFunctionsAllocators
 //
-void *CssmMemoryFunctionsAllocator::malloc(size_t size) throw(std::bad_alloc)
+void *CssmMemoryFunctionsAllocator::malloc(size_t size)
 { return functions.malloc(size); }
 
-void CssmMemoryFunctionsAllocator::free(void *addr) throw()
+void CssmMemoryFunctionsAllocator::free(void *addr) _NOEXCEPT
 { return functions.free(addr); }
 
-void *CssmMemoryFunctionsAllocator::realloc(void *addr, size_t size) throw(std::bad_alloc)
+void *CssmMemoryFunctionsAllocator::realloc(void *addr, size_t size)
 { return functions.realloc(addr, size); }
 
 
@@ -62,16 +62,16 @@ CssmAllocatorMemoryFunctions::CssmAllocatorMemoryFunctions(Allocator &alloc)
        calloc_func = relayCalloc;
 }
 
-void *CssmAllocatorMemoryFunctions::relayMalloc(size_t size, void *ref) throw(std::bad_alloc)
+void *CssmAllocatorMemoryFunctions::relayMalloc(size_t size, void *ref)
 { return allocator(ref).malloc(size); }
 
-void CssmAllocatorMemoryFunctions::relayFree(void *mem, void *ref) throw()
+void CssmAllocatorMemoryFunctions::relayFree(void *mem, void *ref) _NOEXCEPT
 { allocator(ref).free(mem); }
 
-void *CssmAllocatorMemoryFunctions::relayRealloc(void *mem, size_t size, void *ref) throw(std::bad_alloc)
+void *CssmAllocatorMemoryFunctions::relayRealloc(void *mem, size_t size, void *ref)
 { return allocator(ref).realloc(mem, size); }
 
-void *CssmAllocatorMemoryFunctions::relayCalloc(uint32 count, size_t size, void *ref) throw(std::bad_alloc)
+void *CssmAllocatorMemoryFunctions::relayCalloc(uint32 count, size_t size, void *ref)
 {
        // Allocator doesn't have a calloc() method
        size_t alloc_size = 0;
index 01a14e37545fcfe4f27478439f764ab59ed7a05f..6c4365ea096c2687a2deea3b697ed94f5e2cffca 100644 (file)
@@ -46,30 +46,30 @@ public:
        { *(CSSM_MEMORY_FUNCS *)this = funcs; }
        CssmMemoryFunctions() { }
 
-       void *malloc(size_t size) const throw(std::bad_alloc);
-       void free(void *mem) const throw() { free_func(mem, AllocRef); }
-       void *realloc(void *mem, size_t size) const throw(std::bad_alloc);
-       void *calloc(uint32 count, size_t size) const throw(std::bad_alloc);
+       void *malloc(size_t size) const;
+       void free(void *mem) const _NOEXCEPT { free_func(mem, AllocRef); }
+       void *realloc(void *mem, size_t size) const;
+       void *calloc(uint32 count, size_t size) const;
        
-       bool operator == (const CSSM_MEMORY_FUNCS &other) const throw()
+       bool operator == (const CSSM_MEMORY_FUNCS &other) const _NOEXCEPT
        { return !memcmp(this, &other, sizeof(*this)); }
 };
 
-inline void *CssmMemoryFunctions::malloc(size_t size) const throw(std::bad_alloc)
+inline void *CssmMemoryFunctions::malloc(size_t size) const
 {
        if (void *addr = malloc_func(size, AllocRef))
                return addr;
        throw std::bad_alloc();
 }
 
-inline void *CssmMemoryFunctions::calloc(uint32 count, size_t size) const throw(std::bad_alloc)
+inline void *CssmMemoryFunctions::calloc(uint32 count, size_t size) const
 {
        if (void *addr = calloc_func(count, size, AllocRef))
                return addr;
        throw std::bad_alloc();
 }
 
-inline void *CssmMemoryFunctions::realloc(void *mem, size_t size) const throw(std::bad_alloc)
+inline void *CssmMemoryFunctions::realloc(void *mem, size_t size) const
 {
        if (void *addr = realloc_func(mem, size, AllocRef))
                return addr;
@@ -84,11 +84,11 @@ class CssmMemoryFunctionsAllocator : public Allocator {
 public:
        CssmMemoryFunctionsAllocator(const CssmMemoryFunctions &memFuncs) : functions(memFuncs) { }
        
-       void *malloc(size_t size) throw(std::bad_alloc);
-       void free(void *addr) throw();
-       void *realloc(void *addr, size_t size) throw(std::bad_alloc);
+       void *malloc(size_t size);
+       void free(void *addr) _NOEXCEPT;
+       void *realloc(void *addr, size_t size);
        
-       operator const CssmMemoryFunctions & () const throw() { return functions; }
+       operator const CssmMemoryFunctions & () const _NOEXCEPT { return functions; }
 
 private:
        const CssmMemoryFunctions functions;
@@ -106,12 +106,12 @@ public:
        CssmAllocatorMemoryFunctions() { /*IFDEBUG(*/ AllocRef = NULL /*)*/ ; } // later assignment req'd
        
 private:
-       static void *relayMalloc(size_t size, void *ref) throw(std::bad_alloc);
-       static void relayFree(void *mem, void *ref) throw();
-       static void *relayRealloc(void *mem, size_t size, void *ref) throw(std::bad_alloc);
-       static void *relayCalloc(uint32 count, size_t size, void *ref) throw(std::bad_alloc);
+       static void *relayMalloc(size_t size, void *ref);
+       static void relayFree(void *mem, void *ref) _NOEXCEPT;
+       static void *relayRealloc(void *mem, size_t size, void *ref);
+       static void *relayCalloc(uint32 count, size_t size, void *ref);
 
-       static Allocator &allocator(void *ref) throw()
+       static Allocator &allocator(void *ref) _NOEXCEPT
        { return *reinterpret_cast<Allocator *>(ref); }
 };
 
index f2f92dbd066dc20108410d6b1cf04ec936a3d979..73e0d4b2bbbad29dae8e2cfd70cca57aa5e88001 100644 (file)
 #include <security_cdsa_utilities/cssmerrors.h>
 #include <Security/cssm.h>
 
-
 namespace Security {
 
-
 //
 // API boilerplate macros. These provide a frame for C++ code that is impermeable to exceptions.
 // Usage:
@@ -46,7 +44,12 @@ namespace Security {
 //     END_API0                // completely ignores exceptions; falls through in all cases
 //     END_API1(bad)   // return (bad) on exception; fall through on success
 //
-#define BEGIN_API      try {
+#define BEGIN_API      try { \
+       static dispatch_once_t countToken; \
+       countLegacyAPI(&countToken, __FUNCTION__);
+
+#define BEGIN_API_NO_METRICS   try {
+
 #define END_API(base)  } \
 catch (const CommonError &err) { return CssmError::cssmError(err, CSSM_ ## base ## _BASE_ERROR); } \
 catch (const std::bad_alloc &) { return CssmError::cssmError(CSSM_ERRCODE_MEMORY_ERROR, CSSM_ ## base ## _BASE_ERROR); } \
index 5dec094e98bacaf3718d5a9cf7b3e8d51961df0a..2816590904396f6147972ee204d4fc3e6d3b98b7 100644 (file)
@@ -240,7 +240,7 @@ CssmDateData::CssmDateData(const CSSM_DATE &date)
 }
 
 
-CssmData& CssmOwnedData::get() const throw()
+CssmData& CssmOwnedData::get() const _NOEXCEPT
 {
        return referent;
 }
index eee84a0ac673ff049a55b952f0daefdcc8e43094..c69172d74f1ebf8cb9f8755e51675cf826d83ae5 100644 (file)
@@ -243,7 +243,7 @@ public:
        void *data() const                                      { return get().data(); }
        size_t length() const                           { return get().length(); }
        
-       virtual CssmData &get() const throw() = 0; // get shared copy, no ownership change
+       virtual CssmData &get() const _NOEXCEPT = 0; // get shared copy, no ownership change
        virtual CssmData release() = 0;         // give up copy, ownership is transferred
        virtual void reset() = 0;                       // give up copy, data is discarded
 };
@@ -372,7 +372,7 @@ public:
        void operator = (CssmOwnedData &source) { set(source); }
        void operator = (const CSSM_DATA &source) { copy(source); }
        
-       CssmData &get() const throw();
+       CssmData &get() const _NOEXCEPT;
        
 public:
        void fromOid(const char *oid);          // fill from text OID form (1.2.3...)
index 66c9bcb285e7d5d26fa3cfc585b1f8b58202cff3..be227a3b8a56dd8b7e385d10d1b03f70d347a3d9 100644 (file)
@@ -220,9 +220,7 @@ class CssmDLPolyData
 public:
        CssmDLPolyData(const CSSM_DATA &data, CSSM_DB_ATTRIBUTE_FORMAT format)
        : mData(CssmData::overlay(data))
-#ifndef NDEBUG
     , mFormat(format)
-#endif 
     {}
 
        // @@@ Don't use assert, but throw an exception.
@@ -269,9 +267,7 @@ public:
 
 private:
        const CssmData &mData;
-#ifndef NDEBUG
        CSSM_DB_ATTRIBUTE_FORMAT mFormat;
-#endif
 };
 
 
@@ -686,6 +682,8 @@ public:
                const CSSM_NET_ADDRESS *location = NULL)
                : mImpl(new Impl(CssmSubserviceUid(guid, NULL, ssid, sstype), name, location)) { }
 
+    DLDbIdentifier(const DLDbIdentifier& i) : mImpl(i.mImpl) {}
+
        // Conversion Operators
        bool operator !() const { return !mImpl; }
        operator bool() const { return mImpl; }
@@ -749,7 +747,10 @@ struct DLDbFlatIdentifier {
                address(const_cast<CssmNetAddress *>(ident.dbLocation()))
                { }
 
-    operator DLDbIdentifier () { return DLDbIdentifier(*uid, name, address); }
+    operator DLDbIdentifier () {
+        DLDbIdentifier db(*uid, name, address);
+        return db;
+    }
 };
 
 template<class Action>
index 98ec8dd8646b7a7690c9f0bcc72b647c7917608c..12e3bc74f4913314de127cb29c6ec18ad22f4a6b 100644 (file)
@@ -53,7 +53,7 @@ CssmError::CssmError(CSSM_RETURN err, bool suppresslogging) : error(err)
 }
 
 
-const char *CssmError::what() const throw ()
+const char *CssmError::what() const _NOEXCEPT
 {
     return whatBuffer;
 }
index 7da29adbef8be76c3ad213e17d0a5e0331a5fa51..6da470fa6921483dac2f2c33870de59191fb374a 100644 (file)
@@ -46,7 +46,7 @@ public:
     const CSSM_RETURN error;
     virtual OSStatus osStatus() const;
        virtual int unixError() const;
-    virtual const char *what () const throw ();
+    virtual const char *what () const _NOEXCEPT;
 
     static CSSM_RETURN merge(CSSM_RETURN error, CSSM_RETURN base);
     
index 911cf2c6a0105b9b4a1d7d184f321730a133d166..055bf7da44c6d3f439ba0852be005122582fe651 100644 (file)
@@ -152,6 +152,14 @@ ListElement &CssmList::operator [] (unsigned ix) const
        throw 999;      //@@@
 }
 
+CssmList &CssmList::operator =(const CssmList& other)
+{
+    ListType = other.ListType;
+    Head = other.Head;
+    Tail = other.Tail;
+    return *this;
+}
+
 unsigned int CssmList::length() const
 {
        unsigned int len = 0;
index 40f77b76a09979abc3797434894b0d9f3bcec28f..1e65adbdcfffb9f255085bfc1d387ca8e4abc25d 100644 (file)
@@ -141,6 +141,8 @@ public:
     
     // logically remove the first element (skip it)
     void snip();
+
+    CssmList &operator =(const CssmList& other);
        
 public:
        void clear(Allocator &alloc);           // free my contents
index 8915894df6890a0bfc04c67d809ebee0f40e22dc..2a067c44cfa2713f9bfb2155b37aec39cda1ccf5 100644 (file)
@@ -38,9 +38,10 @@ char *Guid::toString(char buffer[stringRepLength+1]) const
 {
     sprintf(buffer, "{%8.8x-%4.4hx-%4.4hx-",
             int(n2h(Data1)), n2h(Data2), n2h(Data3));
-    for (int n = 0; n < 2; n++)
+    for (int n = 0; n < 2; n++) {
         sprintf(buffer + 20 + 2*n, "%2.2hhx", Data4[n]);
-       buffer[24] = '-';
+    }
+    buffer[24] = '-';
     for (int n = 2; n < 8; n++)
         sprintf(buffer + 21 + 2*n, "%2.2hhx", Data4[n]);
     buffer[37] = '}';
@@ -86,8 +87,9 @@ void Guid::parseGuid(const char *string)
        
     int d1;
     uint16 d2, d3;
-    if (sscanf(string, "{%8x-%4hx-%4hx-", &d1, &d2, &d3) != 3)
+    if (sscanf(string, "{%8x-%4hx-%4hx-", &d1, &d2, &d3) != 3) {
         CssmError::throwMe(CSSM_ERRCODE_INVALID_GUID);
+    }
        Data1 = h2n(uint32(d1));
        Data2 = h2n(d2);
        Data3 = h2n(d3);
@@ -131,7 +133,7 @@ CssmSubserviceUid::CssmSubserviceUid(const CSSM_GUID &guid,
 }
 
 
-bool CssmSubserviceUid::operator == (const CSSM_SUBSERVICE_UID &otherUid) const
+bool CssmSubserviceUid::operator == (const CssmSubserviceUid &otherUid) const
 {
     // make sure we don't crash if we get bad data
 #pragma clang diagnostic push
@@ -145,7 +147,7 @@ bool CssmSubserviceUid::operator == (const CSSM_SUBSERVICE_UID &otherUid) const
                && guid() == other.guid();
 }
 
-bool CssmSubserviceUid::operator < (const CSSM_SUBSERVICE_UID &otherUid) const
+bool CssmSubserviceUid::operator < (const CssmSubserviceUid &otherUid) const
 {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wtautological-undefined-compare"
@@ -173,7 +175,7 @@ CryptoDataClass::~CryptoDataClass()
 
 CSSM_RETURN CryptoDataClass::callbackShim(CSSM_DATA *output, void *ctx)
 {
-       BEGIN_API
+       BEGIN_API_NO_METRICS
        *output = reinterpret_cast<CryptoDataClass *>(ctx)->yield();
        END_API(CSSM)
 }
index c1b1c542ccf932256233d4828eb0bcb2fc670107..55d7e2ed3f364bc96bf33ecd02e08f1a538c9d83 100644 (file)
@@ -43,17 +43,18 @@ class Guid : public PodWrapper<Guid, CSSM_GUID> {
 public:
     Guid() { /*IFDEBUG(*/ memset(this, 0, sizeof(*this)) /*)*/ ; }
     Guid(const CSSM_GUID &rGuid) { memcpy(this, &rGuid, sizeof(*this)); }
+    Guid(const Guid &rGuid) { memcpy(this, &rGuid, sizeof(*this)); }
     Guid(const char *string);
        Guid(const std::string &s);
 
-    Guid &operator = (const CSSM_GUID &rGuid)
+    Guid &operator = (const Guid &rGuid)
     { memcpy(this, &rGuid, sizeof(CSSM_GUID)); return *this; }
    
-    bool operator == (const CSSM_GUID &other) const
+    bool operator == (const Guid &other) const
     { return (this == &other) || !memcmp(this, &other, sizeof(CSSM_GUID)); }
-    bool operator != (const CSSM_GUID &other) const
+    bool operator != (const Guid &other) const
     { return (this != &other) && memcmp(this, &other, sizeof(CSSM_GUID)); }
-    bool operator < (const CSSM_GUID &other) const
+    bool operator < (const Guid &other) const
     { return memcmp(this, &other, sizeof(CSSM_GUID)) < 0; }
     size_t hash() const {      //@@@ revisit this hash
         return Data1 + (Data2 << 3) + (Data3 << 11) + (Data4[3]) + (Data4[6] << 22);
@@ -84,12 +85,12 @@ public:
     CssmSubserviceUid() { clearPod(); }
     CssmSubserviceUid(const CSSM_SUBSERVICE_UID &rSSuid) { memcpy(this, &rSSuid, sizeof(*this)); }
 
-    CssmSubserviceUid &operator = (const CSSM_SUBSERVICE_UID &rSSuid)
+    CssmSubserviceUid &operator = (const CssmSubserviceUid &rSSuid)
     { memcpy(this, &rSSuid, sizeof(CSSM_SUBSERVICE_UID)); return *this; }
    
-    bool operator == (const CSSM_SUBSERVICE_UID &other) const;
-    bool operator != (const CSSM_SUBSERVICE_UID &other) const { return !(*this == other); }
-    bool operator < (const CSSM_SUBSERVICE_UID &other) const;
+    bool operator == (const CssmSubserviceUid &other) const;
+    bool operator != (const CssmSubserviceUid &other) const { return !(*this == other); }
+    bool operator < (const CssmSubserviceUid &other) const;
 
     CssmSubserviceUid(const CSSM_GUID &guid, const CSSM_VERSION *version = NULL,
                uint32 subserviceId = 0,
index 6211a11df9ce76c121d3ae8b5209c3f7c3d6d903..d715d72ceb0eab6bcca7ad2cf752a94acc7cce4b 100644 (file)
@@ -31,7 +31,6 @@
 #include <Security/cssmtype.h>
 #include <Security/cssmapple.h>                /* cssmPerror() */
 #include <CoreFoundation/CoreFoundation.h>
-#include <assert.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -65,13 +64,14 @@ OSStatus cmsRtnToOSStatus(
 
 #define CFRELEASE(cfr) if(cfr != NULL) { CFRelease(cfr); }
 
+#include <security_utilities/simulatecrash_assert.h>
+#define ASSERT(s) assert(s)
+
 #define CMS_DEBUG 0
 #if    CMS_DEBUG
-#define ASSERT(s)                      assert(s)
 #define CSSM_PERROR(s, r)      cssmPerror(s, r)
 #define dprintf(args...)       printf(args)
 #else
-#define ASSERT(s)
 #define CSSM_PERROR(s, r)
 #define dprintf(args...)
 #endif
index f81de057e5d20716058b058acc309eadfbdfb8b1..7a493755f76c4abfac1d26acf50b6f6c7a2f709a 100644 (file)
@@ -32,7 +32,7 @@
 #include <sys/param.h>
 #include <xpc/xpc.h>
 #include <syslog.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <libproc.h>
 #include <sandbox.h>
 #include <syslog.h>
index a7e46bcd4b384e6308cef5dc9d839909ea125cf1..10465dff236a8a31942f99a1b01dabee8366ab4f 100644 (file)
@@ -34,8 +34,6 @@
 static void
 request(xpc_connection_t peer, xpc_object_t event)
 {
-       OSStatus rc;
-       
        pid_t pid = (pid_t)xpc_dictionary_get_int64(event, "pid");
        if (pid <= 0)
                return;
@@ -61,11 +59,11 @@ request(xpc_connection_t peer, xpc_object_t event)
                                                         auditData);
        }
        CFRef<SecCodeRef> code;
-       if ((rc = SecCodeCopyGuestWithAttributes(NULL, attributes, kSecCSDefaultFlags, &code.aref())) == noErr) {
+       if (SecCodeCopyGuestWithAttributes(NULL, attributes, kSecCSDefaultFlags, &code.aref()) == noErr) {
                
                // path to base of client code
                CFRef<CFURLRef> codePath;
-               if ((rc = SecCodeCopyPath(code, kSecCSDefaultFlags, &codePath.aref())) == noErr) {
+               if (SecCodeCopyPath(code, kSecCSDefaultFlags, &codePath.aref()) == noErr) {
                        CFRef<CFDataRef> data = CFURLCreateData(NULL, codePath, kCFStringEncodingUTF8, true);
                        xpc_dictionary_set_data(reply, "bundleURL", CFDataGetBytePtr(data), CFDataGetLength(data));
                }
index c91e927db5ce73ad735660a804e22d0307856cbd..47c974a88fc8b9228687627700cee534086724a0 100644 (file)
@@ -27,7 +27,7 @@ public:
        : text(s)
        {
        }
-       virtual ~ANTLRException() throw()
+       virtual ~ANTLRException() _NOEXCEPT
        {
        }
 
index ee7ad43729ef553ef8fa435d0640de0ddf1897c7..96e3b416fd15521446df0858bcfba226bc44dd4e 100644 (file)
@@ -19,7 +19,7 @@ class ANTLR_API CharStreamException : public ANTLRException {
 public:
        CharStreamException(const ANTLR_USE_NAMESPACE(std)string& s)
                : ANTLRException(s) {}
-       ~CharStreamException() throw() {}
+       ~CharStreamException() _NOEXCEPT {}
 };
 
 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
index ebbb0fd674582dc053fee031d884fa2e884bd17c..f4bdcd2200cd0f2a9cfbc7ecbee446238e3e5f27 100644 (file)
@@ -21,7 +21,7 @@ public:
 
        CharStreamIOException(ANTLR_USE_NAMESPACE(std)exception& e)
                : CharStreamException(e.what()), io(e) {}
-       ~CharStreamIOException() throw() {}
+       ~CharStreamIOException() _NOEXCEPT {}
 };
 
 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
index ed87f8acfad06e148a51496286d008d619f4352a..41840d475b0ffefdb9b9cfe746765f13bc054f6b 100644 (file)
@@ -33,7 +33,7 @@ public:
                : ANTLRException(mesg)
        {
        }
-       virtual ~IOException() throw()
+       virtual ~IOException() _NOEXCEPT
        {
        }
 };
index 450541297497f1ed38a77ed350b213eade8741d3..ce10e42d27e4d323717a297657544574662f5406 100644 (file)
@@ -87,7 +87,7 @@ public:
                CharScanner* scanner_
        );
 
-       ~MismatchedCharException() throw() {}
+       ~MismatchedCharException() _NOEXCEPT {}
 
        /**
         * Returns a clean error message (no line number/column information)
index 4631f50b2764b7d53d6120845b7d39c7b8aac50b..6099efc7d712b02b90600e481b9a1e0f5cee9b93 100644 (file)
@@ -81,7 +81,7 @@ public:
                bool matchNot,
                const ANTLR_USE_NAMESPACE(std)string& fileName_
        );
-       ~MismatchedTokenException() throw() {}
+       ~MismatchedTokenException() _NOEXCEPT {}
 
        /**
         * Returns a clean error message (no line number/column information)
index e3677ded47c24695e0fda1820e7ca3a0233eb9da..51f3061010f072d81422983e2ba15dabc3aeee3e 100644 (file)
@@ -25,7 +25,7 @@ public:
        NoViableAltException(RefAST t);
        NoViableAltException(RefToken t,const ANTLR_USE_NAMESPACE(std)string& fileName_);
 
-       ~NoViableAltException() throw() {}
+       ~NoViableAltException() _NOEXCEPT {}
 
        /**
         * Returns a clean error message (no line number/column information)
index d61c18b09b927436a0871638139338f6ee8931fb..54c1344c1e8f1ba90ca5b981b64b6836327f50d5 100644 (file)
@@ -24,7 +24,7 @@ public:
        NoViableAltForCharException(int c, const ANTLR_USE_NAMESPACE(std)string& fileName_,
                                                                                 int line_, int column_);
 
-       virtual ~NoViableAltForCharException() throw()
+       virtual ~NoViableAltForCharException() _NOEXCEPT
        {
        }
 
index c131831b61a543a4e31fc1936a237ca9ff78cec2..410adb3d75ef19a4cc29f81b53e5481f1482b64d 100644 (file)
@@ -24,26 +24,26 @@ namespace antlr
                                                                        const ANTLR_USE_NAMESPACE(std)string& fileName,
                                                                        int line, int column );
 
-               virtual ~RecognitionException() throw()
+               virtual ~RecognitionException() _NOEXCEPT
                {
                }
 
                /// Return file where mishap occurred.
-               virtual ANTLR_USE_NAMESPACE(std)string getFilename() const throw()
+               virtual ANTLR_USE_NAMESPACE(std)string getFilename() const _NOEXCEPT
                {
                        return fileName;
                }
                /**
                 * @return the line number that this exception happened on.
                 */
-               virtual int getLine() const throw()
+               virtual int getLine() const _NOEXCEPT
                {
                        return line;
                }
                /**
                 * @return the column number that this exception happened on.
                 */
-               virtual int getColumn() const throw()
+               virtual int getColumn() const _NOEXCEPT
                {
                        return column;
                }
index c8e9ea395a1d34ba873b760cb5412a5468ed2390..71aab7bb440c80a5fb92392ff40f631cf887fed4 100644 (file)
@@ -28,7 +28,7 @@ public:
        {
        }
 
-       ~SemanticException() throw()
+       ~SemanticException() _NOEXCEPT
        {
        }
 };
index a3f4d5488c483dedceaa2e438eb71bb75b1fd035..7763c072480f35d8cc67e2f5ab7e44c8cf27bfa2 100644 (file)
@@ -29,7 +29,7 @@ public:
        : ANTLRException(s)
        {
        }
-       virtual ~TokenStreamException() throw()
+       virtual ~TokenStreamException() _NOEXCEPT
        {
        }
 };
index 29f508bf83a9238d874671dca3dd444633e2d00a..9ad1855636387814f392a937e7911042bb9c3b4e 100644 (file)
@@ -26,7 +26,7 @@ public:
        , io(e)
        {
        }
-       ~TokenStreamIOException() throw()
+       ~TokenStreamIOException() _NOEXCEPT
        {
        }
 private:
index 3968578913d80af075cfe6a22cb6034ad3e23b84..9c8ec589303734906b8bd08c3c3490e8e9f5e5a2 100644 (file)
@@ -26,7 +26,7 @@ public:
        , recog(re)
        {
        }
-       virtual ~TokenStreamRecognitionException() throw()
+       virtual ~TokenStreamRecognitionException() _NOEXCEPT
        {
        }
        virtual ANTLR_USE_NAMESPACE(std)string toString() const
@@ -34,15 +34,15 @@ public:
                return recog.getFileLineColumnString()+getMessage();
        }
 
-       virtual ANTLR_USE_NAMESPACE(std)string getFilename() const throw()
+       virtual ANTLR_USE_NAMESPACE(std)string getFilename() const _NOEXCEPT
        {
                return recog.getFilename();
        }
-       virtual int getLine() const throw()
+       virtual int getLine() const _NOEXCEPT
        {
                return recog.getLine();
        }
-       virtual int getColumn() const throw()
+       virtual int getColumn() const _NOEXCEPT
        {
                return recog.getColumn();
        }
index 7d17b3cda5e9f12da3f6cc4751d1c95e674c8a67..a50cfb07bd1ac59b76bac9956e6a484220f51ddd 100644 (file)
@@ -18,7 +18,7 @@ namespace antlr {
 class TokenStreamRetryException : public TokenStreamException {
 public:
        TokenStreamRetryException() {}
-       ~TokenStreamRetryException() throw() {}
+       ~TokenStreamRetryException() _NOEXCEPT {}
 };
 
 #ifdef ANTLR_CXX_SUPPORTS_NAMESPACE
index 4279355eb028b9b630716a8f4d4a74023e0513dc..a44f3ef02e49a0680a9d2e018c91ae2c379493e8 100644 (file)
@@ -129,29 +129,30 @@ void TokenStreamRewriteEngine::toStream( std::ostream& out,
 
        size_t tokenCursor = firstToken;
        // make sure we don't run out of the tokens we have...
-       if( lastToken > (tokens.size() - 1) )
-               lastToken = tokens.size() - 1;
+    if( lastToken > (tokens.size() - 1) ) {
+        lastToken = tokens.size() - 1;
+    }
 
-               while ( tokenCursor <= lastToken )
-               {
+    while ( tokenCursor <= lastToken )
+    {
 //                     std::cout << "tokenCursor = " << tokenCursor << " first prog index = " << (*rewriteOpIndex)->getIndex() << std::endl;
 
-                       if( rewriteOpIndex != rewriteOpEnd )
-                       {
-                               size_t up_to_here = std::min(lastToken,(*rewriteOpIndex)->getIndex());
-                               while( tokenCursor < up_to_here )
-                                       out << tokens[tokenCursor++]->getText();
-                       }
-                       while ( rewriteOpIndex != rewriteOpEnd &&
-                                         tokenCursor == (*rewriteOpIndex)->getIndex() &&
-                                         tokenCursor <= lastToken )
-                       {
-                               tokenCursor = (*rewriteOpIndex)->execute(out);
-                               ++rewriteOpIndex;
-                       }
-                       if( tokenCursor <= lastToken )
-                               out << tokens[tokenCursor++]->getText();
-               }
+        if( rewriteOpIndex != rewriteOpEnd )
+        {
+            size_t up_to_here = std::min(lastToken,(*rewriteOpIndex)->getIndex());
+            while( tokenCursor < up_to_here )
+                out << tokens[tokenCursor++]->getText();
+        }
+        while ( rewriteOpIndex != rewriteOpEnd &&
+                  tokenCursor == (*rewriteOpIndex)->getIndex() &&
+                  tokenCursor <= lastToken )
+        {
+            tokenCursor = (*rewriteOpIndex)->execute(out);
+            ++rewriteOpIndex;
+        }
+        if( tokenCursor <= lastToken )
+            out << tokens[tokenCursor++]->getText();
+    }
        // std::cout << "Handling tail operations # left = " << std::distance(rewriteOpIndex,rewriteOpEnd) << std::endl;
        // now see if there are operations (append) beyond last token index
        std::for_each( rewriteOpIndex, rewriteOpEnd, executeOperation(out) );
index d3a6bb182f8a5ebab60aab06859dd7a402af0e54..b39fbe6fa487908474220041a825783ca80d5033 100644 (file)
@@ -215,6 +215,7 @@ typedef CF_OPTIONS(uint32_t, SecCSFlags) {
        kSecCSReportProgress = 1 << 28,                 /* make progress report call-backs when configured */
     kSecCSCheckTrustedAnchors = 1 << 27, /* build certificate chain to system trust anchors, not to any self-signed certificate */
        kSecCSQuickCheck = 1 << 26,             /* (internal) */
+    kSecCSApplyEmbeddedPolicy = 1 << 25, /* Apply Embedded (iPhone) policy regardless of the platform we're running on */
 };
 
 
@@ -251,6 +252,9 @@ typedef CF_OPTIONS(uint32_t, SecCSFlags) {
        @constant kSecCodeSignatureRuntime
        Instructs the kernel to apply runtime hardening policies as required by the
        hardened runtime version
+       @constant kSecCodeSignatureLinkerSigned
+       The code was automatically signed by the linker. This signature should be
+       ignored in any new signing operation.
  */
 typedef CF_OPTIONS(uint32_t, SecCodeSignatureFlags) {
        kSecCodeSignatureHost = 0x0001,                 /* may host guest code */
@@ -262,6 +266,7 @@ typedef CF_OPTIONS(uint32_t, SecCodeSignatureFlags) {
        kSecCodeSignatureEnforcement = 0x1000, /* enforce code signing */
        kSecCodeSignatureLibraryValidation = 0x2000, /* library validation required */
        kSecCodeSignatureRuntime = 0x10000, /* apply runtime hardening policies */
+       kSecCodeSignatureLinkerSigned = 0x20000, /* identify that the signature was auto-generated by the linker*/
 };
 
 /*!
index 712b2ff4cf0f4bfa67f56ac2c826376ce5ec3968..a3f11c4f04d8f7a0df3943e9ba5f80fa77fbd6dc 100644 (file)
@@ -48,7 +48,7 @@ SecCode::SecCode(SecCode *host)
 //
 // Clean up a SecCode object
 //
-SecCode::~SecCode() throw()
+SecCode::~SecCode() _NOEXCEPT
 try {
 } catch (...) {
        return;
index aa5942c90c785ed544dee4097b7d33cbcec1834e..bb189a6c8c868020ea2eafe0cc8d72b478c910e0 100644 (file)
@@ -49,7 +49,7 @@ public:
        SECCFFUNCTIONS(SecCode, SecCodeRef, errSecCSInvalidObjectRef, gCFObjects().Code)
 
        SecCode(SecCode *host);
-    virtual ~SecCode() throw();
+    virtual ~SecCode() _NOEXCEPT;
        
     bool equal(SecCFObject &other);
     CFHashCode hash();
index bc11737f28fc70528b10f54b4db77f34cc580abf..8cbc67f88d8a16cbcf728a12f566d8fa5bf0e23e 100644 (file)
@@ -121,7 +121,7 @@ SecCodeSigner::SecCodeSigner(SecCSFlags flags)
 //
 // Clean up a SecCodeSigner
 //
-SecCodeSigner::~SecCodeSigner() throw()
+SecCodeSigner::~SecCodeSigner() _NOEXCEPT
 try {
        delete mLimitedAsync;
 } catch (...) {
@@ -182,9 +182,13 @@ bool SecCodeSigner::valid() const
 //
 void SecCodeSigner::sign(SecStaticCode *code, SecCSFlags flags)
 {
-       code->setValidationFlags(flags);
-       if (code->isSigned() && (flags & kSecCSSignPreserveSignature))
+       //Never preserve a linker signature.
+       if (code->isSigned() &&
+               (flags & kSecCSSignPreserveSignature) &&
+               !code->flag(kSecCodeSignatureLinkerSigned)) {
                return;
+       }
+       code->setValidationFlags(flags);
        Signer operation(*this, code);
        if ((flags | mOpFlags) & kSecCSRemoveSignature) {
                secinfo("signer", "%p will remove signature from %p", this, code);
index 099d18c7e33edf1d0edd30ca982c97d8ad4b4091..7e897850764e7396a8954cbf6aac567d81500434 100644 (file)
@@ -51,7 +51,7 @@ public:
        SECCFFUNCTIONS(SecCodeSigner, SecCodeSignerRef, errSecCSInvalidObjectRef, gCFObjects().CodeSigner)
 
        SecCodeSigner(SecCSFlags flags);
-    virtual ~SecCodeSigner() throw();
+    virtual ~SecCodeSigner() _NOEXCEPT;
        
        void parameters(CFDictionaryRef args);  // parse and set parameters
        bool valid() const;
index d2fb04feb589d71d3406805dd054f2befb8d525e..36a2786faf192c02c6a71679903eedfe4d63f8d4 100644 (file)
@@ -62,7 +62,7 @@ SecRequirement::SecRequirement(const Requirement *req, bool transferOwnership)
 //
 // Clean up a SecRequirement object
 //
-SecRequirement::~SecRequirement() throw()
+SecRequirement::~SecRequirement() _NOEXCEPT
 try {
        ::free((void *)mReq);
 } catch (...) {
index 8a266f1c46018d805d8338bb6a92a1b2b2b63a1c..f42126858dc3e8718185ab8d2825265b0f884966 100644 (file)
@@ -46,7 +46,7 @@ public:
 
        SecRequirement(const void *data, size_t length);
        SecRequirement(const Requirement *req, bool transferOwnership = false);
-    virtual ~SecRequirement() throw();
+    virtual ~SecRequirement() _NOEXCEPT;
        
     bool equal(SecCFObject &other);
     CFHashCode hash();
index 1db113117d57501dbd4c5d0906d34901a4b0c83d..84f5c10e6d1201e2a3eada135163a1498f14e4d3 100644 (file)
@@ -425,10 +425,10 @@ CFDictionaryRef SecAssessmentCopyUpdate(CFTypeRef target,
 
        if (flags & kSecAssessmentFlagDirect) {
                // ask the engine right here to do its thing
-               result = gEngine().update(target, flags, ctx);
+               result.take(gEngine().update(target, flags, ctx));
        } else {
                // relay the question to our daemon for consideration
-               result = xpcEngineUpdate(target, flags, ctx);
+               result.take(xpcEngineUpdate(target, flags, ctx));
        }
 
        traceUpdate(target, context, result);
index 2a494dc7e0b8fb11668339aaf64c786f91126f75..40cc82035941d232f4d377f01c831c05d00057bf 100644 (file)
@@ -33,6 +33,7 @@
 #include "cskernel.h"
 #include <security_utilities/cfmunge.h>
 #include <security_utilities/logging.h>
+#include <xpc/private.h>
 
 using namespace CodeSigning;
 
@@ -213,6 +214,31 @@ OSStatus SecCodeCreateWithAuditToken(const audit_token_t *audit,
        
        END_CSAPI
 }
+
+OSStatus SecCodeCreateWithXPCMessage(xpc_object_t message, SecCSFlags flags,
+                                                                        SecCodeRef * __nonnull CF_RETURNS_RETAINED target)
+{
+       BEGIN_CSAPI
+
+       checkFlags(flags);
+
+       if (xpc_get_type(message) != XPC_TYPE_DICTIONARY) {
+               return errSecCSInvalidObjectRef;
+       }
+       
+       xpc_connection_t connection = xpc_dictionary_get_remote_connection(message);
+       if (connection == NULL) {
+               return errSecCSInvalidObjectRef;
+       }
+
+       audit_token_t t = {0};
+       xpc_connection_get_audit_token(connection, &t);
+
+       return SecCodeCreateWithAuditToken(&t, flags, target);
+
+       END_CSAPI
+}
+
 #endif // TARGET_OS_OSX
 
 
@@ -289,6 +315,7 @@ const CFStringRef kSecCodeInfoResourceDirectory = CFSTR("ResourceDirectory");
 const CFStringRef kSecCodeInfoNotarizationDate = CFSTR("NotarizationDate");
 const CFStringRef kSecCodeInfoCMSDigestHashType = CFSTR("CMSDigestHashType");
 const CFStringRef kSecCodeInfoCMSDigest =        CFSTR("CMSDigest");
+const CFStringRef kSecCodeInfoSignatureVersion = CFSTR("SignatureVersion");
 
 /* DiskInfoRepInfo types */
 const CFStringRef kSecCodeInfoDiskRepVersionPlatform =         CFSTR("VersionPlatform");
index aa53b5acc9ee85d804ecc57ca8bbea80d85cf9ed..14009a51874963de7cc7ea1fd815fa9d8baa4280 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <Security/CSCommon.h>
 #include <CoreFoundation/CFBase.h>
+#include <xpc/xpc.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -187,6 +188,28 @@ extern const CFStringRef kSecGuestAttributeSubarchitecture;
 
 OSStatus SecCodeCopyGuestWithAttributes(SecCodeRef __nullable host,
        CFDictionaryRef __nullable attributes,  SecCSFlags flags, SecCodeRef * __nonnull CF_RETURNS_RETAINED guest);
+
+/*!
+       @function SecCodeCreateWithXPCMessage
+       Creates a SecCode reference to the process that sent the provided XPC message, using the
+    associated audit token.
+
+       @param message The xpc_object_t of a message recieved via xpc to look up the audit token
+       of the process that sent the message.
+       @param flags Optional flags. Pass kSecCSDefaultFlags for standard behavior.
+       @param processRef On successful return, a SecCode object reference identifying
+       the particular guest of the process from the audit token. This argument will not be
+       changed if the call fails (does not return errSecSuccess).
+       @result Upon success, errSecSuccess. Upon error, an OSStatus value documented in
+       CSCommon.h or certain other Security framework headers. In particular:
+    @error errSecCSInvalidObjectRef The xpc_object_t was not of type XPC_TYPE_DICTIONARY.
+       @error errSecCSInvalidObjectRef The xpc_object_t was not an xpc message with an associated
+       connection.
+    For a complete list of errors, please see {@link SecCodeCopyGuestWithAttributes}.
+*/
+OSStatus SecCodeCreateWithXPCMessage(xpc_object_t message, SecCSFlags flags,
+       SecCodeRef * __nonnull CF_RETURNS_RETAINED target);
+
 #endif // TARGET_OS_OSX
 
 
@@ -215,7 +238,7 @@ OSStatus SecCodeCheckValidity(SecCodeRef code, SecCSFlags flags,
        SecRequirementRef __nullable requirement);
 
 /*!
-       @function SecCodeCheckValidityWifErrors
+       @function SecCodeCheckValidityWithErrors
        Performs dynamic validation of the given SecCode object. The call obtains and
        verifies the signature on the code object. It checks the validity of only those
        sealed components required to establish identity. It checks the SecCode's
@@ -290,7 +313,10 @@ OSStatus SecCodeCopyDesignatedRequirement(SecStaticCodeRef code, SecCSFlags flag
        @function SecCodeCopySigningInformation
        For a given Code or StaticCode object, extract various pieces of information
        from its code signature and return them in the form of a CFDictionary. The amount
-       and detail level of the data is controlled by the flags passed to the call.
+       and detail level of the data is controlled by the flags passed to the call. For
+       Code objects, some of the signing information returned will be from disk. You can
+       call one of the CheckValidity functions to check that the content on disk matches
+       the signing information attached to the running Code.
        
        If the code exists but is not signed at all, this call will succeed and return
        a dictionary that does NOT contain the kSecCodeInfoIdentifier key. This is the
index d88239c8c832be674a9443a6b4e1c54ec14e1b39..e2cac5dd1c3d169b1eb8bb73da90edcd296a7375 100644 (file)
@@ -47,6 +47,7 @@ extern const CFStringRef kSecCodeInfoResourceDirectory;               /* Internal */
 extern const CFStringRef kSecCodeInfoNotarizationDate;      /* Internal */
 extern const CFStringRef kSecCodeInfoCMSDigestHashType;     /* Internal */
 extern const CFStringRef kSecCodeInfoCMSDigest;             /* Internal */
+extern const CFStringRef kSecCodeInfoSignatureVersion;      /* Internal */
 
 extern const CFStringRef kSecCodeInfoDiskRepVersionPlatform;     /* Number */
 extern const CFStringRef kSecCodeInfoDiskRepVersionMin;          /* Number */
@@ -229,7 +230,10 @@ OSStatus SecCodeValidateFileResource(SecStaticCodeRef code, CFStringRef relative
  entirely eventually, we makes this a private flag.
  */
 CF_ENUM(uint32_t) {
+       // NOTE: These values needs to align with the public definitions for static code validity too.
        kSecCSStrictValidateStructure = 1 << 13,
+       kSecCSSkipRootVolumeExceptions = 1 << 14,
+
 };
 
 #if TARGET_OS_OSX
index eba1183066b0226d3e772f4de680ccd918d79891..c1a83ba4625537594c16a5cc6147cf2a22ede75f 100644 (file)
@@ -38,7 +38,11 @@ extern "C" {
        @typedef SecCodeSignerRef
        This is the type of a reference to a code requirement.
 */
+#ifdef BRIDGED_SECCODESIGNER
+typedef struct CF_BRIDGED_TYPE(id) __SecCodeSigner *SecCodeSignerRef;  /* code signing object */
+#else
 typedef struct __SecCodeSigner *SecCodeSignerRef;      /* code signing object */
+#endif
 
 
 /*!
@@ -215,10 +219,13 @@ enum {
     kSecCSEditSignature = 1 << 10,      // edit existing signature
 };
 
-
+#ifdef BRIDGED_SECCODESIGNER
+OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
+       SecCodeSignerRef * __nonnull CF_RETURNS_RETAINED signer);
+#else
 OSStatus SecCodeSignerCreate(CFDictionaryRef parameters, SecCSFlags flags,
        SecCodeSignerRef *signer);
-
+#endif
 
 /*!
        @function SecCodeSignerAddSignature
index b240b4b899ee1c26dd02847bed4ac0330f9a4e50..0fa873e1a24ca54fd75661ea55b2d64e45c6bb17 100644 (file)
@@ -122,21 +122,26 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
                | kSecCSCheckGatekeeperArchitectures
                | kSecCSRestrictSymlinks
                | kSecCSRestrictToAppLike
-        | kSecCSUseSoftwareSigningCert
-           | kSecCSValidatePEH
+               | kSecCSUseSoftwareSigningCert
+               | kSecCSValidatePEH
                | kSecCSSingleThreaded
+               | kSecCSApplyEmbeddedPolicy
+               | kSecCSSkipRootVolumeExceptions
        );
 
        if (errors)
                flags |= kSecCSFullReport;      // internal-use flag
 
+#if !TARGET_OS_OSX
+       flags |= kSecCSApplyEmbeddedPolicy;
+#endif
+
        SecPointer<SecStaticCode> code = SecStaticCode::requiredStatic(staticCodeRef);
        code->setValidationFlags(flags);
        const SecRequirement *req = SecRequirement::optional(requirementRef);
        DTRACK(CODESIGN_EVAL_STATIC, code, (char*)code->mainExecutablePath().c_str());
        code->staticValidate(flags, req);
 
-#if TARGET_OS_IPHONE
     // Everything checked out correctly but we need to make sure that when
     // we validated the code directory, we trusted the signer.  We defer this
     // until now because the caller may still trust the signer via a
@@ -144,10 +149,9 @@ OSStatus SecStaticCodeCheckValidityWithErrors(SecStaticCodeRef staticCodeRef, Se
     // the directory, we potentially skip resource validation even though the
     // caller will go on to trust the signature
     // <rdar://problem/6075501> Applications that are validated against a provisioning profile do not have their resources checked
-    if (code->trustedSigningCertChain() == false) {
+    if ((flags & kSecCSApplyEmbeddedPolicy) && code->trustedSigningCertChain() == false) {
         return CSError::cfError(errors, errSecCSSignatureUntrusted);
     }
-#endif
 
 
        END_CSAPI_ERRORS
@@ -251,7 +255,7 @@ OSStatus SecCodeMapMemory(SecStaticCodeRef codeRef, SecCSFlags flags)
                                MacOSError::throwMe(errSecCSNoMainExecutable);
                        }
 
-                       auto_ptr<MachO> arch(execImage->architecture());
+                       unique_ptr<MachO> arch(execImage->architecture());
                        if (arch.get() == NULL) {
                                MacOSError::throwMe(errSecCSNoMainExecutable);
                        }
index b053623ebe1a7fb66b7029cf08ab17123bb51c49..53712cbf90d5d0332b79738ae5685474da69cbd3 100644 (file)
@@ -178,9 +178,10 @@ CF_ENUM(uint32_t) {
        kSecCSRestrictSymlinks = 1 << 7,
        kSecCSRestrictToAppLike = 1 << 8,
        kSecCSRestrictSidebandData = 1 << 9,
-    kSecCSUseSoftwareSigningCert = 1 << 10,
+       kSecCSUseSoftwareSigningCert = 1 << 10,
        kSecCSValidatePEH = 1 << 11,
        kSecCSSingleThreaded = 1 << 12,
+       // NOTE: These values have gaps for internal usage.
 };
 
 OSStatus SecStaticCodeCheckValidity(SecStaticCodeRef staticCode, SecCSFlags flags,
index 2d5a3e90bcd2a5edccc5189fdd1c569150a3f325..033ef507f861d64fb1bbd79a1f44004b122f84a9 100644 (file)
@@ -67,6 +67,7 @@
 #include <dispatch/private.h>
 #include <os/assumes.h>
 #include <regex.h>
+#import <utilities/entitlements.h>
 
 
 namespace Security {
@@ -109,11 +110,7 @@ SecStaticCode::SecStaticCode(DiskRep *rep, uint32_t flags)
          mOuterScope(NULL), mResourceScope(NULL),
          mDesignatedReq(NULL), mGotResourceBase(false), mMonitor(NULL), mLimitedAsync(NULL),
          mFlags(flags), mNotarizationChecked(false), mStaplingChecked(false), mNotarizationDate(NAN)
-#if TARGET_OS_OSX
-    , mEvalDetails(NULL)
-#else
     , mTrustedSigningCertChain(false)
-#endif
 
 {
        CODESIGN_STATIC_CREATE(this, rep);
@@ -126,7 +123,7 @@ SecStaticCode::SecStaticCode(DiskRep *rep, uint32_t flags)
 //
 // Clean up a SecStaticCode object
 //
-SecStaticCode::~SecStaticCode() throw()
+SecStaticCode::~SecStaticCode() _NOEXCEPT
 try {
        ::free(const_cast<Requirement *>(mDesignatedReq));
        delete mResourcesValidContext;
@@ -361,9 +358,6 @@ void SecStaticCode::resetValidity()
        mNotarizationChecked = false;
        mStaplingChecked = false;
        mNotarizationDate = NAN;
-#if TARGET_OS_OSX
-       mEvalDetails = NULL;
-#endif
        mRep->flush();
 
 #if TARGET_OS_OSX
@@ -771,297 +765,292 @@ bool SecStaticCode::verifySignature()
 
        DTRACK(CODESIGN_EVAL_STATIC_SIGNATURE, this, (char*)this->mainExecutablePath().c_str());
 #if TARGET_OS_OSX
-       // decode CMS and extract SecTrust for verification
-       CFRef<CMSDecoderRef> cms;
-       MacOSError::check(CMSDecoderCreate(&cms.aref())); // create decoder
-       CFDataRef sig = this->signature();
-       MacOSError::check(CMSDecoderUpdateMessage(cms, CFDataGetBytePtr(sig), CFDataGetLength(sig)));
-       this->codeDirectory();  // load CodeDirectory (sets mDir)
-       MacOSError::check(CMSDecoderSetDetachedContent(cms, mBaseDir));
-       MacOSError::check(CMSDecoderFinalizeMessage(cms));
-       MacOSError::check(CMSDecoderSetSearchKeychain(cms, cfEmptyArray()));
-       CFRef<CFArrayRef> vf_policies(createVerificationPolicies());
-       CFRef<CFArrayRef> ts_policies(createTimeStampingAndRevocationPolicies());
-
-       CMSSignerStatus status;
-       MacOSError::check(CMSDecoderCopySignerStatus(cms, 0, vf_policies,
-                               false, &status, &mTrust.aref(), NULL));
-
-       if (status != kCMSSignerValid) {
-               const char *reason;
-               switch (status) {
-                       case kCMSSignerUnsigned: reason="kCMSSignerUnsigned"; break;
-                       case kCMSSignerNeedsDetachedContent: reason="kCMSSignerNeedsDetachedContent"; break;
-                       case kCMSSignerInvalidSignature: reason="kCMSSignerInvalidSignature"; break;
-                       case kCMSSignerInvalidCert: reason="kCMSSignerInvalidCert"; break;
-                       case kCMSSignerInvalidIndex: reason="kCMSSignerInvalidIndex"; break;
-                       default: reason="unknown"; break;
-               }
-               Security::Syslog::error("CMSDecoderCopySignerStatus failed with %s error (%d)",
-                                                               reason, (int)status);
-               MacOSError::throwMe(errSecCSSignatureFailed);
-       }
-
-       // retrieve auxiliary v1 data bag and verify against current state
-       CFRef<CFDataRef> hashAgilityV1;
-       switch (OSStatus rc = CMSDecoderCopySignerAppleCodesigningHashAgility(cms, 0, &hashAgilityV1.aref())) {
-       case noErr:
-               if (hashAgilityV1) {
-                       CFRef<CFDictionaryRef> hashDict = makeCFDictionaryFrom(hashAgilityV1);
-                       CFArrayRef cdList = CFArrayRef(CFDictionaryGetValue(hashDict, CFSTR("cdhashes")));
-                       CFArrayRef myCdList = this->cdHashes();
-
-                       /* Note that this is not very "agile": There's no way to calculate the exact
-                        * list for comparison if it contains hash algorithms we don't know yet... */
-                       if (cdList == NULL || !CFEqual(cdList, myCdList))
-                               MacOSError::throwMe(errSecCSSignatureFailed);
+       if (!(mValidationFlags & kSecCSApplyEmbeddedPolicy)) {
+               // decode CMS and extract SecTrust for verification
+               CFRef<CMSDecoderRef> cms;
+               MacOSError::check(CMSDecoderCreate(&cms.aref())); // create decoder
+               CFDataRef sig = this->signature();
+               MacOSError::check(CMSDecoderUpdateMessage(cms, CFDataGetBytePtr(sig), CFDataGetLength(sig)));
+               this->codeDirectory();  // load CodeDirectory (sets mDir)
+               MacOSError::check(CMSDecoderSetDetachedContent(cms, mBaseDir));
+               MacOSError::check(CMSDecoderFinalizeMessage(cms));
+               MacOSError::check(CMSDecoderSetSearchKeychain(cms, cfEmptyArray()));
+               CFRef<CFArrayRef> vf_policies(createVerificationPolicies());
+               CFRef<CFArrayRef> ts_policies(createTimeStampingAndRevocationPolicies());
+
+               CMSSignerStatus status;
+               MacOSError::check(CMSDecoderCopySignerStatus(cms, 0, vf_policies,
+                                       false, &status, &mTrust.aref(), NULL));
+
+               if (status != kCMSSignerValid) {
+                       const char *reason;
+                       switch (status) {
+                               case kCMSSignerUnsigned: reason="kCMSSignerUnsigned"; break;
+                               case kCMSSignerNeedsDetachedContent: reason="kCMSSignerNeedsDetachedContent"; break;
+                               case kCMSSignerInvalidSignature: reason="kCMSSignerInvalidSignature"; break;
+                               case kCMSSignerInvalidCert: reason="kCMSSignerInvalidCert"; break;
+                               case kCMSSignerInvalidIndex: reason="kCMSSignerInvalidIndex"; break;
+                               default: reason="unknown"; break;
+                       }
+                       Security::Syslog::error("CMSDecoderCopySignerStatus failed with %s error (%d)",
+                                                                       reason, (int)status);
+                       MacOSError::throwMe(errSecCSSignatureFailed);
                }
-               break;
-       case -1:        /* CMS used to return this for "no attribute found", so tolerate it. Now returning noErr/NULL */
-               break;
-       default:
-               MacOSError::throwMe(rc);
-       }
 
-       // retrieve auxiliary v2 data bag and verify against current state
-       CFRef<CFDictionaryRef> hashAgilityV2;
-       switch (OSStatus rc = CMSDecoderCopySignerAppleCodesigningHashAgilityV2(cms, 0, &hashAgilityV2.aref())) {
+               // retrieve auxiliary v1 data bag and verify against current state
+               CFRef<CFDataRef> hashAgilityV1;
+               switch (OSStatus rc = CMSDecoderCopySignerAppleCodesigningHashAgility(cms, 0, &hashAgilityV1.aref())) {
                case noErr:
-                       if (hashAgilityV2) {
-                               /* Require number of code directoris and entries in the hash agility
-                                * dict to be the same size (no stripping out code directories).
-                                */
-                               if (CFDictionaryGetCount(hashAgilityV2) != mCodeDirectories.size()) {
+                       if (hashAgilityV1) {
+                               CFRef<CFDictionaryRef> hashDict = makeCFDictionaryFrom(hashAgilityV1);
+                               CFArrayRef cdList = CFArrayRef(CFDictionaryGetValue(hashDict, CFSTR("cdhashes")));
+                               CFArrayRef myCdList = this->cdHashes();
+
+                               /* Note that this is not very "agile": There's no way to calculate the exact
+                                * list for comparison if it contains hash algorithms we don't know yet... */
+                               if (cdList == NULL || !CFEqual(cdList, myCdList))
                                        MacOSError::throwMe(errSecCSSignatureFailed);
-                               }
+                       }
+                       break;
+               case -1:        /* CMS used to return this for "no attribute found", so tolerate it. Now returning noErr/NULL */
+                       break;
+               default:
+                       MacOSError::throwMe(rc);
+               }
 
-                               /* Require every cdhash of every code directory whose hash
-                                * algorithm we know to be in the agility dictionary.
-                                *
-                                * We check untruncated cdhashes here because we can.
-                                */
-                               bool foundOurs = false;
-                               for (auto& entry : mCodeDirectories) {
-                                       SECOidTag tag = CodeDirectorySet::SECOidTagForAlgorithm(entry.first);
-
-                                       if (tag == SEC_OID_UNKNOWN) {
-                                               // Unknown hash algorithm, ignore.
-                                               continue;
+               // retrieve auxiliary v2 data bag and verify against current state
+               CFRef<CFDictionaryRef> hashAgilityV2;
+               switch (OSStatus rc = CMSDecoderCopySignerAppleCodesigningHashAgilityV2(cms, 0, &hashAgilityV2.aref())) {
+                       case noErr:
+                               if (hashAgilityV2) {
+                                       /* Require number of code directoris and entries in the hash agility
+                                        * dict to be the same size (no stripping out code directories).
+                                        */
+                                       if (CFDictionaryGetCount(hashAgilityV2) != mCodeDirectories.size()) {
+                                               MacOSError::throwMe(errSecCSSignatureFailed);
                                        }
 
-                                       CFRef<CFNumberRef> key = makeCFNumber(int(tag));
-                                       CFRef<CFDataRef> entryCdhash;
-                                       entryCdhash = (CFDataRef)CFDictionaryGetValue(hashAgilityV2, (void*)key.get());
-
-                                       CodeDirectory const *cd = (CodeDirectory const*)CFDataGetBytePtr(entry.second);
-                                       CFRef<CFDataRef> ourCdhash = cd->cdhash(false); // Untruncated cdhash!
-                                       if (!CFEqual(entryCdhash, ourCdhash)) {
-                                               MacOSError::throwMe(errSecCSSignatureFailed);
+                                       /* Require every cdhash of every code directory whose hash
+                                        * algorithm we know to be in the agility dictionary.
+                                        *
+                                        * We check untruncated cdhashes here because we can.
+                                        */
+                                       bool foundOurs = false;
+                                       for (auto& entry : mCodeDirectories) {
+                                               SECOidTag tag = CodeDirectorySet::SECOidTagForAlgorithm(entry.first);
+
+                                               if (tag == SEC_OID_UNKNOWN) {
+                                                       // Unknown hash algorithm, ignore.
+                                                       continue;
+                                               }
+
+                                               CFRef<CFNumberRef> key = makeCFNumber(int(tag));
+                                               CFRef<CFDataRef> entryCdhash;
+                                               entryCdhash = (CFDataRef)CFDictionaryGetValue(hashAgilityV2, (void*)key.get());
+
+                                               CodeDirectory const *cd = (CodeDirectory const*)CFDataGetBytePtr(entry.second);
+                                               CFRef<CFDataRef> ourCdhash = cd->cdhash(false); // Untruncated cdhash!
+                                               if (!CFEqual(entryCdhash, ourCdhash)) {
+                                                       MacOSError::throwMe(errSecCSSignatureFailed);
+                                               }
+
+                                               if (entry.first == this->hashAlgorithm()) {
+                                                       foundOurs = true;
+                                               }
                                        }
 
-                                       if (entry.first == this->hashAlgorithm()) {
-                                               foundOurs = true;
+                                       /* Require the cdhash of our chosen code directory to be in the dictionary.
+                                        * In theory, the dictionary could be full of unsupported cdhashes, but we
+                                        * really want ours, which is bound to be supported, to be covered.
+                                        */
+                                       if (!foundOurs) {
+                                               MacOSError::throwMe(errSecCSSignatureFailed);
                                        }
                                }
+                               break;
+                       case -1:        /* CMS used to return this for "no attribute found", so tolerate it. Now returning noErr/NULL */
+                               break;
+                       default:
+                               MacOSError::throwMe(rc);
+               }
 
-                               /* Require the cdhash of our chosen code directory to be in the dictionary.
-                                * In theory, the dictionary could be full of unsupported cdhashes, but we
-                                * really want ours, which is bound to be supported, to be covered.
-                                */
-                               if (!foundOurs) {
-                                       MacOSError::throwMe(errSecCSSignatureFailed);
-                               }
-                       }
-                       break;
-               case -1:        /* CMS used to return this for "no attribute found", so tolerate it. Now returning noErr/NULL */
+               // internal signing time (as specified by the signer; optional)
+               mSigningTime = 0;       // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
+               switch (OSStatus rc = CMSDecoderCopySignerSigningTime(cms, 0, &mSigningTime)) {
+               case errSecSuccess:
+               case errSecSigningTimeMissing:
                        break;
                default:
+                       Security::Syslog::error("Could not get signing time (error %d)", (int)rc);
                        MacOSError::throwMe(rc);
-       }
-
-       // internal signing time (as specified by the signer; optional)
-       mSigningTime = 0;       // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
-       switch (OSStatus rc = CMSDecoderCopySignerSigningTime(cms, 0, &mSigningTime)) {
-       case errSecSuccess:
-       case errSecSigningTimeMissing:
-               break;
-       default:
-               Security::Syslog::error("Could not get signing time (error %d)", (int)rc);
-               MacOSError::throwMe(rc);
-       }
-
-       // certified signing time (as specified by a TSA; optional)
-       mSigningTimestamp = 0;
-       switch (OSStatus rc = CMSDecoderCopySignerTimestampWithPolicy(cms, ts_policies, 0, &mSigningTimestamp)) {
-       case errSecSuccess:
-       case errSecTimestampMissing:
-               break;
-       default:
-               Security::Syslog::error("Could not get timestamp (error %d)", (int)rc);
-               MacOSError::throwMe(rc);
-       }
+               }
 
-       // set up the environment for SecTrust
-    if (mValidationFlags & kSecCSNoNetworkAccess) {
-        MacOSError::check(SecTrustSetNetworkFetchAllowed(mTrust,false)); // no network?
-    }
-    MacOSError::check(SecTrustSetKeychainsAllowed(mTrust, false));
+               // certified signing time (as specified by a TSA; optional)
+               mSigningTimestamp = 0;
+               switch (OSStatus rc = CMSDecoderCopySignerTimestampWithPolicy(cms, ts_policies, 0, &mSigningTimestamp)) {
+               case errSecSuccess:
+               case errSecTimestampMissing:
+                       break;
+               default:
+                       Security::Syslog::error("Could not get timestamp (error %d)", (int)rc);
+                       MacOSError::throwMe(rc);
+               }
 
-       CSSM_APPLE_TP_ACTION_DATA actionData = {
-               CSSM_APPLE_TP_ACTION_VERSION,   // version of data structure
-               0       // action flags
-       };
+               // set up the environment for SecTrust
+               if (mValidationFlags & kSecCSNoNetworkAccess) {
+                       MacOSError::check(SecTrustSetNetworkFetchAllowed(mTrust,false)); // no network?
+               }
+               MacOSError::check(SecTrustSetKeychainsAllowed(mTrust, false));
 
-       if (!(mValidationFlags & kSecCSCheckTrustedAnchors)) {
-               /* no need to evaluate anchor trust when building cert chain */
-               MacOSError::check(SecTrustSetAnchorCertificates(mTrust, cfEmptyArray())); // no anchors
-               actionData.ActionFlags |= CSSM_TP_ACTION_IMPLICIT_ANCHORS;      // action flags
-       }
+               CSSM_APPLE_TP_ACTION_DATA actionData = {
+                       CSSM_APPLE_TP_ACTION_VERSION,   // version of data structure
+                       0       // action flags
+               };
 
-       for (;;) {      // at most twice
-               MacOSError::check(SecTrustSetParameters(mTrust,
-                       CSSM_TP_ACTION_DEFAULT, CFTempData(&actionData, sizeof(actionData))));
+               if (!(mValidationFlags & kSecCSCheckTrustedAnchors)) {
+                       /* no need to evaluate anchor trust when building cert chain */
+                       MacOSError::check(SecTrustSetAnchorCertificates(mTrust, cfEmptyArray())); // no anchors
+                       actionData.ActionFlags |= CSSM_TP_ACTION_IMPLICIT_ANCHORS;      // action flags
+               }
 
-               // evaluate trust and extract results
-               SecTrustResultType trustResult;
-               MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
-               MacOSError::check(SecTrustGetResult(mTrust, &trustResult, &mCertChain.aref(), &mEvalDetails));
-
-               // if this is an Apple developer cert....
-               if (teamID() && SecStaticCode::isAppleDeveloperCert(mCertChain)) {
-                       CFRef<CFStringRef> teamIDFromCert;
-                       if (CFArrayGetCount(mCertChain) > 0) {
-                               /* Note that SecCertificateCopySubjectComponent sets the out parameter to NULL if there is no field present */
-                               MacOSError::check(SecCertificateCopySubjectComponent((SecCertificateRef)CFArrayGetValueAtIndex(mCertChain, Requirement::leafCert),
-                                                                                                                                        &CSSMOID_OrganizationalUnitName,
-                                                                                                                                        &teamIDFromCert.aref()));
-
-                               if (teamIDFromCert) {
-                                       CFRef<CFStringRef> teamIDFromCD = CFStringCreateWithCString(NULL, teamID(), kCFStringEncodingUTF8);
-                                       if (!teamIDFromCD) {
-                                               Security::Syslog::error("Could not get team identifier (%s)", teamID());
-                                               MacOSError::throwMe(errSecCSInvalidTeamIdentifier);
+               for (;;) {      // at most twice
+                       MacOSError::check(SecTrustSetParameters(mTrust,
+                               CSSM_TP_ACTION_DEFAULT, CFTempData(&actionData, sizeof(actionData))));
+
+                       // evaluate trust and extract results
+                       SecTrustResultType trustResult;
+                       MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
+                       mCertChain.take(copyCertChain(mTrust));
+
+                       // if this is an Apple developer cert....
+                       if (teamID() && SecStaticCode::isAppleDeveloperCert(mCertChain)) {
+                               CFRef<CFStringRef> teamIDFromCert;
+                               if (CFArrayGetCount(mCertChain) > 0) {
+                                       SecCertificateRef leaf = (SecCertificateRef)CFArrayGetValueAtIndex(mCertChain, Requirement::leafCert);
+                                       CFArrayRef organizationalUnits = SecCertificateCopyOrganizationalUnit(leaf);
+                                       if (organizationalUnits) {
+                                               teamIDFromCert.take((CFStringRef)CFRetain(CFArrayGetValueAtIndex(organizationalUnits, 0)));
+                                               CFRelease(organizationalUnits);
+                                       } else {
+                                               teamIDFromCert = NULL;
                                        }
 
-                                       if (CFStringCompare(teamIDFromCert, teamIDFromCD, 0) != kCFCompareEqualTo) {
-                                               Security::Syslog::error("Team identifier in the signing certificate (%s) does not match the team identifier (%s) in the code directory",
-                                                                                               cfString(teamIDFromCert).c_str(), teamID());
-                                               MacOSError::throwMe(errSecCSBadTeamIdentifier);
+                                       if (teamIDFromCert) {
+                                               CFRef<CFStringRef> teamIDFromCD = CFStringCreateWithCString(NULL, teamID(), kCFStringEncodingUTF8);
+                                               if (!teamIDFromCD) {
+                                                       Security::Syslog::error("Could not get team identifier (%s)", teamID());
+                                                       MacOSError::throwMe(errSecCSInvalidTeamIdentifier);
+                                               }
+
+                                               if (CFStringCompare(teamIDFromCert, teamIDFromCD, 0) != kCFCompareEqualTo) {
+                                                       Security::Syslog::error("Team identifier in the signing certificate (%s) does not match the team identifier (%s) in the code directory",
+                                                                                                       cfString(teamIDFromCert).c_str(), teamID());
+                                                       MacOSError::throwMe(errSecCSBadTeamIdentifier);
+                                               }
                                        }
                                }
                        }
-               }
 
-               CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? (int)CFArrayGetCount(mCertChain) : 0);
-               switch (trustResult) {
-               case kSecTrustResultProceed:
-               case kSecTrustResultUnspecified:
-                       break;                          // success
-               case kSecTrustResultDeny:
-                       MacOSError::throwMe(CSSMERR_APPLETP_TRUST_SETTING_DENY);        // user reject
-               case kSecTrustResultInvalid:
-                       assert(false);          // should never happen
-                       MacOSError::throwMe(CSSMERR_TP_NOT_TRUSTED);
-               default:
-                       {
-                               OSStatus result;
-                               MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result));
-                               // if we have a valid timestamp, CMS validates against (that) signing time and all is well.
-                               // If we don't have one, may validate against *now*, and must be able to tolerate expiration.
-                               if (mSigningTimestamp == 0) { // no timestamp available
-                                       if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET))
-                                                       && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
-                                               CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this);
-                                               actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs)
-                                               continue;               // retry validation while tolerating expiration
+                       CODESIGN_EVAL_STATIC_SIGNATURE_RESULT(this, trustResult, mCertChain ? (int)CFArrayGetCount(mCertChain) : 0);
+                       switch (trustResult) {
+                       case kSecTrustResultProceed:
+                       case kSecTrustResultUnspecified:
+                               break;                          // success
+                       case kSecTrustResultDeny:
+                               MacOSError::throwMe(CSSMERR_APPLETP_TRUST_SETTING_DENY);        // user reject
+                       case kSecTrustResultInvalid:
+                               assert(false);          // should never happen
+                               MacOSError::throwMe(CSSMERR_TP_NOT_TRUSTED);
+                       default:
+                               {
+                                       OSStatus result;
+                                       MacOSError::check(SecTrustGetCssmResultCode(mTrust, &result));
+                                       // if we have a valid timestamp, CMS validates against (that) signing time and all is well.
+                                       // If we don't have one, may validate against *now*, and must be able to tolerate expiration.
+                                       if (mSigningTimestamp == 0) { // no timestamp available
+                                               if (((result == CSSMERR_TP_CERT_EXPIRED) || (result == CSSMERR_TP_CERT_NOT_VALID_YET))
+                                                               && !(actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED)) {
+                                                       CODESIGN_EVAL_STATIC_SIGNATURE_EXPIRED(this);
+                                                       actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED; // (this also allows postdated certs)
+                                                       continue;               // retry validation while tolerating expiration
+                                               }
                                        }
+                                       if (checkfix41082220(result)) {
+                                               break; // success
+                                       }
+                                       Security::Syslog::error("SecStaticCode: verification failed (trust result %d, error %d)", trustResult, (int)result);
+                                       MacOSError::throwMe(result);
                                }
-                               if (checkfix41082220(result)) {
-                                       break; // success
-                               }
-                               Security::Syslog::error("SecStaticCode: verification failed (trust result %d, error %d)", trustResult, (int)result);
-                               MacOSError::throwMe(result);
                        }
-               }
 
-               if (mSigningTimestamp) {
-                       CFIndex rootix = CFArrayGetCount(mCertChain);
-                       if (SecCertificateRef mainRoot = SecCertificateRef(CFArrayGetValueAtIndex(mCertChain, rootix-1)))
-                               if (isAppleCA(mainRoot)) {
-                                       // impose policy: if the signature itself draws to Apple, then so must the timestamp signature
-                                       CFRef<CFArrayRef> tsCerts;
-                                       OSStatus result = CMSDecoderCopySignerTimestampCertificates(cms, 0, &tsCerts.aref());
-                                       if (result) {
-                                               Security::Syslog::error("SecStaticCode: could not get timestamp certificates (error %d)", (int)result);
-                                               MacOSError::check(result);
+                       if (mSigningTimestamp) {
+                               CFIndex rootix = CFArrayGetCount(mCertChain);
+                               if (SecCertificateRef mainRoot = SecCertificateRef(CFArrayGetValueAtIndex(mCertChain, rootix-1)))
+                                       if (isAppleCA(mainRoot)) {
+                                               // impose policy: if the signature itself draws to Apple, then so must the timestamp signature
+                                               CFRef<CFArrayRef> tsCerts;
+                                               OSStatus result = CMSDecoderCopySignerTimestampCertificates(cms, 0, &tsCerts.aref());
+                                               if (result) {
+                                                       Security::Syslog::error("SecStaticCode: could not get timestamp certificates (error %d)", (int)result);
+                                                       MacOSError::check(result);
+                                               }
+                                               CFIndex tsn = CFArrayGetCount(tsCerts);
+                                               bool good = tsn > 0 && isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(tsCerts, tsn-1)));
+                                               if (!good) {
+                                                       result = CSSMERR_TP_NOT_TRUSTED;
+                                                       Security::Syslog::error("SecStaticCode: timestamp policy verification failed (error %d)", (int)result);
+                                                       MacOSError::throwMe(result);
+                                               }
                                        }
-                                       CFIndex tsn = CFArrayGetCount(tsCerts);
-                                       bool good = tsn > 0 && isAppleCA(SecCertificateRef(CFArrayGetValueAtIndex(tsCerts, tsn-1)));
-                                       if (!good) {
-                                               result = CSSMERR_TP_NOT_TRUSTED;
-                                               Security::Syslog::error("SecStaticCode: timestamp policy verification failed (error %d)", (int)result);
-                                               MacOSError::throwMe(result);
-                                       }
-                               }
+                       }
+
+                       return actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED;
                }
 
-               return actionData.ActionFlags & CSSM_TP_ACTION_ALLOW_EXPIRED;
-       }
-#else
-    // Do some pre-verification initialization
-    CFDataRef sig = this->signature();
-    this->codeDirectory();     // load CodeDirectory (sets mDir)
-    mSigningTime = 0;  // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
-
-    CFRef<CFDictionaryRef> attrs;
-       CFRef<CFArrayRef> vf_policies(createVerificationPolicies());
-
-    // Verify the CMS signature against mBaseDir (SHA1)
-    MacOSError::check(SecCMSVerifyCopyDataAndAttributes(sig, mBaseDir, vf_policies, &mTrust.aref(), NULL, &attrs.aref()));
-
-    // Copy the signing time
-    mSigningTime = SecTrustGetVerifyTime(mTrust);
-
-    // Validate the cert chain
-    SecTrustResultType trustResult;
-    MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
-
-    // retrieve auxiliary data bag and verify against current state
-    CFRef<CFDataRef> hashBag;
-    hashBag = CFDataRef(CFDictionaryGetValue(attrs, kSecCMSHashAgility));
-    if (hashBag) {
-        CFRef<CFDictionaryRef> hashDict = makeCFDictionaryFrom(hashBag);
-        CFArrayRef cdList = CFArrayRef(CFDictionaryGetValue(hashDict, CFSTR("cdhashes")));
-        CFArrayRef myCdList = this->cdHashes();
-        if (cdList == NULL || !CFEqual(cdList, myCdList))
-            MacOSError::throwMe(errSecCSSignatureFailed);
-    }
+       } else
+#endif
+       {
+               // Do some pre-verification initialization
+               CFDataRef sig = this->signature();
+               this->codeDirectory();  // load CodeDirectory (sets mDir)
+               mSigningTime = 0;       // "not present" marker (nobody could code sign on Jan 1, 2001 :-)
 
-    /*
-     * Populate mCertChain with the certs.  If we failed validation, the
-     * signer's cert will be checked installed provisioning profiles as an
-     * alternative to verification against the policy for store-signed binaries
-     */
-    SecCertificateRef leafCert = SecTrustGetCertificateAtIndex(mTrust, 0);
-    if (leafCert != NULL) {
-        CFIndex count = SecTrustGetCertificateCount(mTrust);
-
-        CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, count,
-                                                       &kCFTypeArrayCallBacks);
-
-        CFArrayAppendValue(certs, leafCert);
-        for (CFIndex i = 1; i < count; ++i) {
-            CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(mTrust, i));
-        }
-        
-        mCertChain.take((CFArrayRef)certs);
-    }
-    
-    // Did we implicitly trust the signer?
-    mTrustedSigningCertChain = (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed);
+               CFRef<CFDictionaryRef> attrs;
+               CFRef<CFArrayRef> vf_policies(createVerificationPolicies());
 
-    return false; // XXX: Not checking for expired certs
-#endif
+               // Verify the CMS signature against mBaseDir (SHA1)
+               MacOSError::check(SecCMSVerifyCopyDataAndAttributes(sig, mBaseDir, vf_policies, &mTrust.aref(), NULL, &attrs.aref()));
+
+               // Copy the signing time
+               mSigningTime = SecTrustGetVerifyTime(mTrust);
+
+               // Validate the cert chain
+               SecTrustResultType trustResult;
+               MacOSError::check(SecTrustEvaluate(mTrust, &trustResult));
+
+               // retrieve auxiliary data bag and verify against current state
+               CFRef<CFDataRef> hashBag;
+               hashBag = CFDataRef(CFDictionaryGetValue(attrs, kSecCMSHashAgility));
+               if (hashBag) {
+                       CFRef<CFDictionaryRef> hashDict = makeCFDictionaryFrom(hashBag);
+                       CFArrayRef cdList = CFArrayRef(CFDictionaryGetValue(hashDict, CFSTR("cdhashes")));
+                       CFArrayRef myCdList = this->cdHashes();
+                       if (cdList == NULL || !CFEqual(cdList, myCdList))
+                               MacOSError::throwMe(errSecCSSignatureFailed);
+               }
+
+               /*
+                * Populate mCertChain with the certs.  If we failed validation, the
+                * signer's cert will be checked installed provisioning profiles as an
+                * alternative to verification against the policy for store-signed binaries
+                */
+               mCertChain.take(copyCertChain(mTrust));
+
+               // Did we implicitly trust the signer?
+               mTrustedSigningCertChain = (trustResult == kSecTrustResultUnspecified || trustResult == kSecTrustResultProceed);
+
+               return false; // XXX: Not checking for expired certs
+       }
 }
 
 #if TARGET_OS_OSX
@@ -1084,6 +1073,11 @@ CFArrayRef SecStaticCode::createVerificationPolicies()
                return makeCFArray(1, ssRef.get());
        }
 #if TARGET_OS_OSX
+       if (mValidationFlags & kSecCSApplyEmbeddedPolicy) {
+               CFRef<SecPolicyRef> iOSRef = SecPolicyCreateiPhoneApplicationSigning();
+               return makeCFArray(1, iOSRef.get());
+       }
+
        CFRef<SecPolicyRef> core;
        MacOSError::check(SecPolicyCopy(CSSM_CERT_X_509v3,
                                                                        &CSSMOID_APPLE_TP_CODE_SIGNING, &core.aref()));
@@ -1134,6 +1128,25 @@ CFArrayRef SecStaticCode::createTimeStampingAndRevocationPolicies()
 
 }
 
+CFArrayRef SecStaticCode::copyCertChain(SecTrustRef trust)
+{
+       SecCertificateRef leafCert = SecTrustGetCertificateAtIndex(trust, 0);
+       if (leafCert != NULL) {
+               CFIndex count = SecTrustGetCertificateCount(trust);
+
+               CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, count,
+                                                                                                          &kCFTypeArrayCallBacks);
+
+               CFArrayAppendValue(certs, leafCert);
+               for (CFIndex i = 1; i < count; ++i) {
+                       CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, i));
+               }
+
+               return certs;
+       }
+       return NULL;
+}
+
 
 //
 // Validate a particular sealed, cached resource against its (special) CodeDirectory slot.
@@ -1242,6 +1255,14 @@ void SecStaticCode::validateResources(SecCSFlags flags)
        }
 
        if (doit) {
+               string root = cfStringRelease(copyCanonicalPath());
+               bool itemIsOnRootFS = isOnRootFilesystem(root.c_str());
+               bool requestForcedValidation = (mValidationFlags & kSecCSSkipRootVolumeExceptions);
+               bool useRootFSPolicy = itemIsOnRootFS && !requestForcedValidation;
+
+               secinfo("staticCode", "performing resource validation for %s (%d, %d, %d)", root.c_str(),
+                               itemIsOnRootFS, requestForcedValidation, useRootFSPolicy);
+
                if (mLimitedAsync == NULL) {
                        bool runMultiThreaded = ((flags & kSecCSSingleThreaded) == kSecCSSingleThreaded) ? false :
                                        (diskRep()->fd().mediumType() == kIOPropertyMediumTypeSolidStateKey);
@@ -1264,13 +1285,15 @@ void SecStaticCode::validateResources(SecCSFlags flags)
 
                        // check for weak resource rules
                        bool strict = flags & kSecCSStrictValidate;
-                       if (strict) {
-                               if (hasWeakResourceRules(rules, version, mAllowOmissions))
-                                       if (mTolerateErrors.find(errSecCSWeakResourceRules) == mTolerateErrors.end())
-                                               MacOSError::throwMe(errSecCSWeakResourceRules);
-                               if (version == 1)
-                                       if (mTolerateErrors.find(errSecCSWeakResourceEnvelope) == mTolerateErrors.end())
-                                               MacOSError::throwMe(errSecCSWeakResourceEnvelope);
+                       if (!useRootFSPolicy) {
+                               if (strict) {
+                                       if (hasWeakResourceRules(rules, version, mAllowOmissions))
+                                               if (mTolerateErrors.find(errSecCSWeakResourceRules) == mTolerateErrors.end())
+                                                       MacOSError::throwMe(errSecCSWeakResourceRules);
+                                       if (version == 1)
+                                               if (mTolerateErrors.find(errSecCSWeakResourceEnvelope) == mTolerateErrors.end())
+                                                       MacOSError::throwMe(errSecCSWeakResourceEnvelope);
+                               }
                        }
 
                        Dispatch::Group group;
@@ -1288,7 +1311,21 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                                bool isSymlink = (ent->fts_info == FTS_SL);
 
                                void (^validate)() = ^{
-                                       validateResource(files, relpath, isSymlink, *mResourcesValidContext, flags, version);
+                                       bool needsValidation = true;
+
+                                       if (useRootFSPolicy) {
+                                               CFRef<CFURLRef> itemURL = makeCFURL(relpath, false, resourceBase());
+                                               string itemPath = cfString(itemURL);
+                                               if (isOnRootFilesystem(itemPath.c_str())) {
+                                                       secinfo("staticCode", "resource validation on root volume skipped: %s", itemPath.c_str());
+                                                       needsValidation = false;
+                                               }
+                                       }
+
+                                       if (needsValidation) {
+                                               secinfo("staticCode", "performing resource validation on item: %s", relpath.c_str());
+                                               validateResource(files, relpath, isSymlink, *mResourcesValidContext, flags, version);
+                                       }
                                        reportProgress();
                                };
 
@@ -1296,10 +1333,15 @@ void SecStaticCode::validateResources(SecCSFlags flags)
                        });
                        group.wait();   // wait until all async resources have been validated as well
 
-                       unsigned leftovers = unsigned(CFDictionaryGetCount(resourceMap));
-                       if (leftovers > 0) {
-                               secinfo("staticCode", "%d sealed resource(s) not found in code", int(leftovers));
-                               CFDictionaryApplyFunction(resourceMap, SecStaticCode::checkOptionalResource, mResourcesValidContext);
+                       if (useRootFSPolicy) {
+                               // It's ok to allow leftovers on the root filesystem for now.
+                       } else {
+                               // Look through the leftovers and make sure they're all properly optional resources.
+                               unsigned leftovers = unsigned(CFDictionaryGetCount(resourceMap));
+                               if (leftovers > 0) {
+                                       secinfo("staticCode", "%d sealed resource(s) not found in code", int(leftovers));
+                                       CFDictionaryApplyFunction(resourceMap, SecStaticCode::checkOptionalResource, mResourcesValidContext);
+                               }
                        }
 
                        // now check for any errors found in the reporting context
@@ -2070,7 +2112,7 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
 
 //DR not currently supported on iOS
 #if TARGET_OS_OSX
-        try {
+               try {
                        if (const Requirements *reqs = this->internalRequirements()) {
                                CFDictionaryAddValue(dict, kSecCodeInfoRequirements,
                                        CFTempString(Dumper::dump(reqs)));
@@ -2090,10 +2132,26 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
 #endif
 
        try {
-          if (CFDataRef ent = this->component(cdEntitlementSlot)) {
-                  CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
-                  if (CFDictionaryRef entdict = this->entitlements())
-                               CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict);
+               if (CFDataRef ent = this->component(cdEntitlementSlot)) {
+                       CFDictionaryAddValue(dict, kSecCodeInfoEntitlements, ent);
+                       if (CFDictionaryRef entdict = this->entitlements()) {
+                               if (needsCatalystEntitlementFixup(entdict)) {
+                                       // If this entitlement dictionary needs catalyst entitlements, make a copy and stick that into the
+                                       // output dictionary instead.
+                                       secinfo("staticCode", "%p fixed catalyst entitlements", this);
+                                       CFRef<CFMutableDictionaryRef> tempEntitlements = makeCFMutableDictionary(entdict);
+                                       updateCatalystEntitlements(tempEntitlements);
+                                       CFRef<CFDictionaryRef> newEntitlements = CFDictionaryCreateCopy(NULL, tempEntitlements);
+                                       if (newEntitlements) {
+                                               CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, newEntitlements.get());
+                                       } else {
+                                               secerror("%p unable to fixup entitlement dictionary", this);
+                                               CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict);
+                                       }
+                               } else {
+                                       CFDictionaryAddValue(dict, kSecCodeInfoEntitlementsDict, entdict);
+                               }
+                       }
                }
        } catch (...) { }
 
@@ -2123,6 +2181,10 @@ CFDictionaryRef SecStaticCode::signingInformation(SecCSFlags flags)
                                secerror("Error creating date from timestamp: %f", mNotarizationDate);
                        }
                }
+               if (this->codeDirectory()) {
+                       uint32_t version = this->codeDirectory()->version;
+                       CFDictionaryAddValue(dict, kSecCodeInfoSignatureVersion, CFTempNumber(version));
+               }
        }
 
        if (flags & kSecCSCalculateCMSDigest) {
@@ -2248,8 +2310,9 @@ void SecStaticCode::staticValidate(SecCSFlags flags, const SecRequirement *req)
        reportEvent(CFSTR("prepared"), NULL);
 
        // resources: once for all architectures
-       if (!(flags & kSecCSDoNotValidateResources))
+       if (!(flags & kSecCSDoNotValidateResources)) {
                this->validateResources(flags);
+       }
 
        // perform strict validation if desired
        if (flags & kSecCSStrictValidate) {
index 567268243d6d3ac10e16c8c0cc492bb4a67f4286..ae4cc60237300d36324855bb80f4bd9a5533fe50 100644 (file)
@@ -107,7 +107,7 @@ public:
        static SecCode *optionalDynamic(SecStaticCodeRef ref); // extract SecCodeRef or NULL if static
 
        SecStaticCode(DiskRep *rep, uint32_t flags = 0);
-    virtual ~SecStaticCode() throw();
+    virtual ~SecStaticCode() _NOEXCEPT;
 
     void initializeFromParent(const SecStaticCode& parent);
 
@@ -200,9 +200,7 @@ public:
        CFDictionaryRef signingInformation(SecCSFlags flags); // omnibus information-gathering API (creates new dictionary)
 
        static bool isAppleDeveloperCert(CFArrayRef certs); // determines if this is an apple developer certificate for library validation
-#if !TARGET_OS_OSX
     bool trustedSigningCertChain() { return mTrustedSigningCertChain; }
-#endif
 
        void handleOtherArchitectures(void (^handle)(SecStaticCode* other));
 
@@ -231,6 +229,7 @@ private:
        void validateOtherVersions(CFURLRef path, SecCSFlags flags, SecRequirementRef req, SecStaticCode *code);
        bool checkfix30814861(string path, bool addition);
        bool checkfix41082220(OSStatus result);
+       CFArrayRef copyCertChain(SecTrustRef trust);
 
        ResourceBuilder *mCheckfix30814861builder1;
        dispatch_once_t mCheckfix30814861builder1_once;
@@ -306,11 +305,7 @@ private:
        // signature verification outcome (mTrust == NULL => not done yet)
        CFRef<SecTrustRef> mTrust;                      // outcome of crypto validation (valid or not)
        CFRef<CFArrayRef> mCertChain;
-#if TARGET_OS_OSX
-    CSSM_TP_APPLE_EVIDENCE_INFO *mEvalDetails;
-#else
     bool mTrustedSigningCertChain;
-#endif
 
 };
 
index 7c4909702644b1685db09b6dac96f61e0f53336b..efc14c1cc34681fbe6000a0671828166a5c3f331 100644 (file)
@@ -198,7 +198,7 @@ void BundleDiskRep::setup(const Context *ctx)
        // we're getting desperate here. Perhaps an oldish-style installer package? Look for a *.dist file
        std::string distFile = findDistFile(this->resourcesRootPath());
        if (!distFile.empty()) {
-               mMainExecutableURL = makeCFURL(distFile);
+               mMainExecutableURL.take(makeCFURL(distFile));
                mExecRep = new FileDiskRep(this->mainExecutablePath().c_str());
                checkPlainFile(mExecRep->fd(), this->mainExecutablePath());
                mInstallerPackage = true;
index 4d3c1c80015884dcc02a2837b9ade80189e8310b..9c559dcdbb9d325d9b8215687db33235adab5c9d 100644 (file)
@@ -419,5 +419,6 @@ const SecCodeDirectoryFlagTable kSecCodeDirectoryFlagTable[] = {
        { "enforcement",        kSecCodeSignatureEnforcement,           true },
        { "library-validation", kSecCodeSignatureLibraryValidation,             true },
        { "runtime",    kSecCodeSignatureRuntime,               true },
+       { "linker-signed",      kSecCodeSignatureLinkerSigned,  true },
        { NULL }
 };
index 1e6d98e708444c0eb71a1a81c2a7e8f1f85e1851..907e1ee3c09313efc9587230faef71cfc796534d 100644 (file)
@@ -34,7 +34,7 @@ namespace CodeSigning {
 //
 // We need a nothrow destructor
 //
-CSError::~CSError() throw ()
+CSError::~CSError() _NOEXCEPT
 { }
 
 
index f46528f10f0b12a482339cf135b7c959e34fd576..41b97ac3f8289dc80b2867623b14e51abd80dc02 100644 (file)
@@ -42,7 +42,7 @@ class CSError : public MacOSError {
 public:
        CSError(OSStatus rc) : MacOSError(rc) { }
        CSError(OSStatus rc, CFDictionaryRef dict) : MacOSError(rc), mInfoDict(dict) { } // takes dict
-       ~CSError() throw ();
+       ~CSError() _NOEXCEPT;
        
     static void throwMe(OSStatus rc) __attribute__((noreturn));
        static void throwMe(OSStatus rc, CFDictionaryRef info) __attribute__ ((noreturn)); // takes dict
index 0d1c485227beecaa86e2cccb9361ca4d63a95b69..0eca965383132d2c11e4b03818b37dd714c093b7 100644 (file)
@@ -175,7 +175,7 @@ SecCodeStatus KernelCode::getGuestStatus(SecCode *iguest)
 {
        if (ProcessCode *guest = dynamic_cast<ProcessCode *>(iguest)) {
                uint32_t pFlags;
-               csops(guest, CS_OPS_STATUS, &pFlags);
+               csops(guest, CS_OPS_STATUS, &pFlags, sizeof(pFlags));
                secinfo("kcode", "guest %p(%d) kernel status 0x%x", guest, guest->pid(), pFlags);
                return pFlags;
        } else
index b0a370e42f43b6c412ca3d0097f5e0e82fb6bf50..0d717e556a49c62fef135280c4354b43e4b2d258 100644 (file)
@@ -43,7 +43,7 @@ namespace CodeSigning {
 class ProcessCode : public SecCode {
 public:
        ProcessCode(pid_t pid, const audit_token_t* token, PidDiskRep *pidDiskRep = NULL);
-       ~ProcessCode() throw () { delete mAudit; }
+       ~ProcessCode() _NOEXCEPT { delete mAudit; }
        
        pid_t pid() const { return mPid; }
        const audit_token_t* audit() const { return mAudit; }
index 774b6ee2c50d96f9f3992b284665380b5106239c..2d9c65bfd3aa97e2cfeae3313aa0e1d29e3e6805 100644 (file)
 #include <security_asn1/SecAsn1Templates.h>
 #include <Security/SecCertificatePriv.h>
 #include <Security/SecCertificate.h>
+#include <Security/SecPolicyPriv.h>
 #include <utilities/SecAppleAnchorPriv.h>
 #include <utilities/SecInternalReleasePriv.h>
 #include "requirement.h"
 #include <security_utilities/hashing.h>
 #include <security_utilities/debugging.h>
 #include <security_utilities/errors.h>
+#include <sys/mount.h>
 #include <sys/utsname.h>
+#include "debugging.h"
 
 extern "C" {
 
@@ -85,13 +88,7 @@ void hashOfCertificate(const void *certData, size_t certLength, SHA1::Digest dig
 void hashOfCertificate(SecCertificateRef cert, SHA1::Digest digest)
 {
        assert(cert);
-#if TARGET_OS_OSX
-       CSSM_DATA certData;
-       MacOSError::check(SecCertificateGetData(cert, &certData));
-       hashOfCertificate(certData.Data, certData.Length, digest);
-#else
     hashOfCertificate(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert), digest);
-#endif
 }
 
 
@@ -112,36 +109,32 @@ bool verifyHash(SecCertificateRef cert, const Hashing::Byte *digest)
 //
 bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid)
 {
-       assert(cert);
-       CSSM_DATA *value;
-       switch (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &oid, &value)) {
-       case errSecSuccess:
-               MacOSError::check(SecCertificateReleaseFirstFieldValue(cert, &oid, value));
-               return true;                                    // extension found by oid
-       case errSecUnknownTag:
-               break;                                                  // oid not recognized by CL - continue below
-       default:
-               MacOSError::throwMe(rc);                // error: fail
+       CFDataRef oidData = NULL;
+       CFDataRef data = NULL;
+       bool isCritical = false;
+       bool matched = false;
+
+       oidData = CFDataCreateWithBytesNoCopy(NULL, oid.Data, oid.Length,
+                                             kCFAllocatorNull);
+       if (!(cert && oidData)) {
+               goto out;
        }
-       
-       // check the CL's bag of unrecognized extensions
-       CSSM_DATA **values;
-       bool found = false;
-       if (SecCertificateCopyFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, &values))
-               return false;   // no unrecognized extensions - no match
-       if (values)
-               for (CSSM_DATA **p = values; *p; p++) {
-                       const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)(*p)->Data;
-                       if (oid == ext->extnId) {
-                               found = true;
-                               break;
-                       }
-               }
-       MacOSError::check(SecCertificateReleaseFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, values));
-       return found;
+       data = SecCertificateCopyExtensionValue(cert, oidData, &isCritical);
+       if (data == NULL) {
+               goto out;
+       }
+       matched = true;
+out:
+       if (data) {
+               CFRelease(data);
+       }
+       if (oidData) {
+               CFRelease(oidData);
+       }
+       return matched;
 }
-    
-    
+
+
 //
 // Retrieve X.509 policy extension OIDs, if any.
 // This currently ignores policy qualifiers.
@@ -149,24 +142,16 @@ bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid)
 bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid)
 {
        bool matched = false;
-       assert(cert);
-       CSSM_DATA *data;
-       if (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_CertificatePolicies, &data))
-               MacOSError::throwMe(rc);
-       if (data && data->Data && data->Length == sizeof(CSSM_X509_EXTENSION)) {
-               const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)data->Data;
-               assert(ext->format == CSSM_X509_DATAFORMAT_PARSED);
-               const CE_CertPolicies *policies = (const CE_CertPolicies *)ext->value.parsedValue;
-               if (policies)
-                       for (unsigned int n = 0; n < policies->numPolicies; n++) {
-                               const CE_PolicyInformation &cp = policies->policies[n];
-                               if (cp.certPolicyId == policyOid) {
-                                       matched = true;
-                                       break;
-                               }
-                       }
+       CFDataRef oidData = CFDataCreateWithBytesNoCopy(NULL, policyOid.Data, policyOid.Length,
+                                             kCFAllocatorNull);
+       if (!(cert && oidData)) {
+               goto out;
+       }
+       matched = SecPolicyCheckCertCertificatePolicy(cert, oidData);
+out:
+       if (oidData) {
+               CFRelease(oidData);
        }
-       SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_PolicyConstraints, data);
        return matched;
 }
 
@@ -337,5 +322,18 @@ bool LimitedAsync::perform(Dispatch::Group &groupRef, void (^block)()) {
        }
 }
 
+bool isOnRootFilesystem(const char *path)
+{
+       int rc = 0;
+       struct statfs sfb;
+
+       rc = statfs(path, &sfb);
+       if (rc != 0) {
+               secerror("Unable to check if path is on rootfs: %d, %s", errno, path);
+               return false;
+       }
+       return ((sfb.f_flags & MNT_ROOTFS) == MNT_ROOTFS);
+}
+
 } // end namespace CodeSigning
 } // end namespace Security
index bd4408cdb5dfb676adc4209db3458287766ccd6c..2c9017f348f1b58b08c823fb0ce8cca339632ed4 100644 (file)
@@ -225,6 +225,8 @@ private:
        Dispatch::Semaphore *mResourceSemaphore;
 };
 
+// Check if the path is on the root filesystem, protected by the OS.
+bool isOnRootFilesystem(const char *path);
 
 
 } // end namespace CodeSigning
index 15140faccacf296f0ffaa49cd71eeca7d047b340..83d961906baa541965cd999d32b4b0e009096ad7 100644 (file)
@@ -28,6 +28,8 @@
 #include <security_utilities/logging.h>
 #include "dirscanner.h"
 
+#include <sstream>
+
 namespace Security {
 namespace CodeSigning {
 
@@ -157,7 +159,9 @@ void DirValidator::validate(const string &root, OSStatus error)
                        reqMatched.insert(rule);
        }
        if (reqMatched.size() != (unsigned long) mRequireCount) {
-               secinfo("dirval", "matched %lu of %d required rules", reqMatched.size(), mRequireCount);
+               ostringstream os;
+               os << "matched " << reqMatched.size() << " of " << mRequireCount << " required rules";
+               secinfo("dirval", "%s", os.str().c_str());
                MacOSError::throwMe(error);              // not all required rules were matched
        }
 }
index 02e7faa8bae1baf03095e2fbe53a462a135aab93..157e6e7aabe08bab7660acb00a46fbf032e014f6 100644 (file)
@@ -25,6 +25,7 @@
 // machorep - DiskRep mix-in for handling Mach-O main executables
 //
 #include "machorep.h"
+#include "notarization.h"
 #include "StaticCode.h"
 #include "reqmaker.h"
 #include <security_utilities/logging.h>
@@ -53,7 +54,7 @@ MachORep::MachORep(const char *path, const Context *ctx)
                if (ctx->offset)
                        mExecutable = new Universal(fd(), (size_t)ctx->offset, ctx->size);
                else if (ctx->arch) {
-                       auto_ptr<Universal> full(new Universal(fd()));
+                       unique_ptr<Universal> full(new Universal(fd()));
                        mExecutable = new Universal(fd(), full->archOffset(ctx->arch), full->archLength(ctx->arch));
                } else
                        mExecutable = new Universal(fd());
@@ -109,7 +110,7 @@ Universal *MachORep::mainExecutableImage()
 void MachORep::prepareForSigning(SigningContext &context)
 {
        if (context.digestAlgorithms().empty()) {
-        auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+        unique_ptr<MachO> macho(mainExecutableImage()->architecture());
                
                uint32_t limit = 0;
                switch (macho->platform()) {
@@ -150,19 +151,22 @@ size_t MachORep::signingBase()
        
 size_t MachORep::signingLimit()
 {
-       auto_ptr<MachO> macho(mExecutable->architecture());
+       unique_ptr<MachO> macho(mExecutable->architecture());
        return macho->signingExtent();
 }
 
 bool MachORep::needsExecSeg(const MachO& macho) {
        uint32_t platform = macho.platform();
-       // Everything embedded gets an exec segment.
-       return platform != 0 && platform != PLATFORM_MACOS;
+       
+       // Everything gets an exec segment. This is ignored
+       // on non-PPL devices, and explicitly wastes some
+       // space on those devices, but is simpler logic.
+       return platform != 0;
 }
 
 size_t MachORep::execSegBase(const Architecture *arch)
 {
-       auto_ptr<MachO> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
+       unique_ptr<MachO> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
 
        if (!needsExecSeg(*macho)) {
                return 0;
@@ -187,7 +191,7 @@ size_t MachORep::execSegBase(const Architecture *arch)
 
 size_t MachORep::execSegLimit(const Architecture *arch)
 {
-       auto_ptr<MachO> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
+       unique_ptr<MachO> macho(arch ? mExecutable->architecture(*arch) : mExecutable->architecture());
 
        if (!needsExecSeg(*macho)) {
                return 0;
@@ -218,7 +222,7 @@ size_t MachORep::execSegLimit(const Architecture *arch)
 //
 CFDataRef MachORep::identification()
 {
-       std::auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+       std::unique_ptr<MachO> macho(mainExecutableImage()->architecture());
        return identificationFor(macho.get());
 }
 
@@ -271,6 +275,12 @@ CFDataRef MachORep::component(CodeDirectory::SpecialSlot slot)
 EditableDiskRep::RawComponentMap MachORep::createRawComponents()
 {
        EditableDiskRep::RawComponentMap  blobMap;
+
+       // First call to signingData() caches the result, so this
+       // _should_ not cause performance issues.
+       if (NULL == signingData()) {
+               MacOSError::throwMe(errSecCSUnsigned);
+       }
        const EmbeddedSignatureBlob &blobs = *signingData();
        
        for (unsigned int i = 0; i < blobs.count(); ++i) {
@@ -304,7 +314,7 @@ CFDataRef MachORep::embeddedComponent(CodeDirectory::SpecialSlot slot)
 EmbeddedSignatureBlob *MachORep::signingData()
 {
        if (!mSigningData) {            // fetch and cache
-               auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+               unique_ptr<MachO> macho(mainExecutableImage()->architecture());
                if (macho.get())
                        if (const linkedit_data_command *cs = macho->findCodeSignature()) {
                                size_t offset = macho->flip(cs->dataoff);
@@ -332,7 +342,7 @@ CFDataRef MachORep::infoPlist()
 {
        CFRef<CFDataRef> info;
        try {
-               auto_ptr<MachO> macho(mainExecutableImage()->architecture());
+               unique_ptr<MachO> macho(mainExecutableImage()->architecture());
                if (const section *sect = macho->findSection("__TEXT", "__info_plist")) {
                        if (macho->is64()) {
                                const section_64 *sect64 = reinterpret_cast<const section_64 *>(sect);
@@ -391,7 +401,7 @@ void MachORep::flush()
 
 CFDictionaryRef MachORep::diskRepInformation()
 {
-    auto_ptr<MachO> macho (mainExecutableImage()->architecture());
+    unique_ptr<MachO> macho (mainExecutableImage()->architecture());
     CFRef<CFDictionaryRef> info;
 
        uint32_t platform = 0;
@@ -469,7 +479,7 @@ const Requirements *MachORep::defaultRequirements(const Architecture *arch, cons
 
 Requirement *MachORep::libraryRequirements(const Architecture *arch, const SigningContext &ctx)
 {
-       auto_ptr<MachO> macho(mainExecutableImage()->architecture(*arch));
+       unique_ptr<MachO> macho(mainExecutableImage()->architecture(*arch));
        Requirement::Maker maker;
        Requirement::Maker::Chain chain(maker, opOr);
 
@@ -564,6 +574,14 @@ void MachORep::Writer::component(CodeDirectory::SpecialSlot slot, CFDataRef data
        MacOSError::throwMe(errSecCSInternalError);
 }
 
+void MachORep::registerStapledTicket()
+{
+       CFRef<CFDataRef> data = NULL;
+       if (mSigningData) {
+               data.take(mSigningData->component(cdTicketSlot));
+               registerStapledTicketInMachO(data);
+       }
+}
 
 } // end namespace CodeSigning
 } // end namespace Security
index ef2181bb6dddb9011387019f1d7f927ed5d300c7..0a9044679ff63e5262492e69c8156b05fce68649 100644 (file)
@@ -71,6 +71,7 @@ public:
        void flush();           // flush cache
 
        static bool candidate(UnixPlusPlus::FileDesc &fd);
+       void registerStapledTicket();
        
 public:
        static CFDataRef identificationFor(MachO *macho);
index f645fd2eec9130864442b899b1d11ffdf9986e9e..6587dccdc4ed1552a8d595042b06dbbc8f5fcbf7 100644 (file)
@@ -299,5 +299,15 @@ registerStapledTicketInDMG(CFDataRef ticketData)
        registerStapledTicketWithSystem(ticketData);
 }
 
+void
+registerStapledTicketInMachO(CFDataRef ticketData)
+{
+       if (ticketData == NULL) {
+               return;
+       }
+       secinfo("notarization", "successfully found stapled ticket in MachO");
+       registerStapledTicketWithSystem(ticketData);
+}
+
 }
 }
index 21ae3c16c191a61d550672318f8cc597cb1a9219..1e2a22b41163fec484de654be6a62b3be5205080 100644 (file)
@@ -44,6 +44,7 @@ bool isNotarized(const Requirement::Context *context);
 void registerStapledTicketInPackage(const std::string& path);
 void registerStapledTicketInBundle(const std::string& path);
 void registerStapledTicketInDMG(CFDataRef ticketData);
+void registerStapledTicketInMachO(CFDataRef ticketData);
 
 } // end namespace CodeSigning
 } // end namespace Security
index 0aeeb81e1123f650a21396d802f17f5ededf3874..7f74d24b05e820cac8199c7dec0ee7268ee5e1dc 100644 (file)
@@ -86,10 +86,11 @@ PidDiskRep::fetchData(void)
        xpc_release(request);
        xpc_release(conn);
     
-    if (!mBundleURL)
+    if (!mBundleURL) {
         MacOSError::throwMe(errSecCSNoSuchCode);
-       
-       mDataFetched = true;
+    }
+
+    mDataFetched = true;
 }
 
 
index 4ff172124ddaeb273f4f0bf0baed7290d9ec2b5c..f39706502ea2b258c8a465510fb041046541bbb8 100644 (file)
 #include <sys/csr.h>
 #include <IOKit/IOKitLib.h>
 #include <IOKit/IOCFUnserialize.h>
+#include <libDER/oids.h>
 #include "csutilities.h"
 #include "notarization.h"
 #include "legacydevid.h"
 
+#define WAITING_FOR_LIB_AMFI_INTERFACE 1
+
+#if WAITING_FOR_LIB_AMFI_INTERFACE
+#define __mac_syscall __sandbox_ms
+#include <security/mac.h>
+
+#define AMFI_INTF_CD_HASH_LEN 20
+#endif
+
 namespace Security {
 namespace CodeSigning {
 
@@ -242,7 +252,6 @@ bool Requirement::Interpreter::entitlementValue(const string &key, const Match &
 
 bool Requirement::Interpreter::certFieldValue(const string &key, const Match &match, SecCertificateRef cert)
 {
-// XXX: Not supported on embedded yet due to lack of supporting API
 #if TARGET_OS_OSX
        // no cert, no chance
        if (cert == NULL)
@@ -251,32 +260,31 @@ bool Requirement::Interpreter::certFieldValue(const string &key, const Match &ma
        // a table of recognized keys for the "certificate[foo]" syntax
        static const struct CertField {
                const char *name;
-               const CSSM_OID *oid;
+               const DERItem *oid;
        } certFields[] = {
-               { "subject.C", &CSSMOID_CountryName },
-               { "subject.CN", &CSSMOID_CommonName },
-               { "subject.D", &CSSMOID_Description },
-               { "subject.L", &CSSMOID_LocalityName },
+               { "subject.C", &oidCountryName},
+               { "subject.CN", &oidCommonName },
+               { "subject.D", &oidDescription },
+               { "subject.L", &oidLocalityName },
 //             { "subject.C-L", &CSSMOID_CollectiveLocalityName },     // missing from Security.framework headers
-               { "subject.O", &CSSMOID_OrganizationName },
-               { "subject.C-O", &CSSMOID_CollectiveOrganizationName },
-               { "subject.OU", &CSSMOID_OrganizationalUnitName },
-               { "subject.C-OU", &CSSMOID_CollectiveOrganizationalUnitName },
-               { "subject.ST", &CSSMOID_StateProvinceName },
-               { "subject.C-ST", &CSSMOID_CollectiveStateProvinceName },
-               { "subject.STREET", &CSSMOID_StreetAddress },
-               { "subject.C-STREET", &CSSMOID_CollectiveStreetAddress },
-               { "subject.UID", &CSSMOID_UserID },
+               { "subject.O", &oidOrganizationName },
+               { "subject.C-O", &oidCollectiveOrganizationName },
+               { "subject.OU", &oidOrganizationalUnitName},
+               { "subject.C-OU", &oidCollectiveOrganizationalUnitName},
+               { "subject.ST", &oidStateOrProvinceName},
+               { "subject.C-ST", &oidCollectiveStateOrProvinceName },
+               { "subject.STREET", &oidStreetAddress },
+               { "subject.C-STREET", &oidCollectiveStreetAddress },
+               { "subject.UID", &oidUserId },
                { NULL, NULL }
        };
 
        // DN-component single-value match
        for (const CertField *cf = certFields; cf->name; cf++)
                if (cf->name == key) {
-                       CFRef<CFStringRef> value;
-            OSStatus rc = SecCertificateCopySubjectComponent(cert, cf->oid, &value.aref());
-                       if (rc) {
-                               secinfo("csinterp", "cert %p lookup for DN.%s failed rc=%d", cert, key.c_str(), (int)rc);
+                       CFRef<CFStringRef> value(SecCertificateCopySubjectAttributeValue(cert, (DERItem *)cf->oid));
+                       if (!value.get()) {
+                               secinfo("csinterp", "cert %p lookup for DN.%s failed", cert, key.c_str());
                                return false;
                        }
                        return match(value);
@@ -403,14 +411,15 @@ CFArrayRef Requirement::Interpreter::getAdditionalTrustedAnchors()
 
 bool Requirement::Interpreter::appleLocalAnchored()
 {
-    static CFArrayRef additionalTrustedCertificates = NULL;
+       static CFArrayRef additionalTrustedCertificates = NULL;
 
-    if (csr_check(CSR_ALLOW_APPLE_INTERNAL))
+    if (csr_check(CSR_ALLOW_APPLE_INTERNAL)) {
         return false;
+    }
 
-       if (mContext->forcePlatform) {
-               return true;
-       }
+    if (mContext->forcePlatform) {
+        return true;
+    }
 
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
@@ -430,18 +439,76 @@ bool Requirement::Interpreter::appleLocalAnchored()
     return false;
 }
 
+#if WAITING_FOR_LIB_AMFI_INTERFACE
+// These bits are here until we get get a new build alias for libamfi-interface.
+
+#define MAC_AMFI_POLICY_NAME "AMFI"
+
+#define AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE  95
+
+typedef struct amfi_cdhash_in_trustcache_ {
+    uint8_t cdhash[20];
+    uint64_t result;
+} amfi_cdhash_in_trustcache_t;
+
+static int
+__amfi_interface_cdhash_in_trustcache(const uint8_t cdhash[], uint64_t* trustcache_result)
+{
+    amfi_cdhash_in_trustcache_t args;
+    static_assert(AMFI_INTF_CD_HASH_LEN == sizeof(args.cdhash), "Error: cdhash length mismatch");
+    int err;
+    memcpy(args.cdhash, cdhash, sizeof(args.cdhash));
+    args.result = 0;
+    err = __mac_syscall(MAC_AMFI_POLICY_NAME, AMFI_SYSCALL_CDHASH_IN_TRUSTCACHE, &args);
+    if (err) {
+        err = errno;
+    }
+    *trustcache_result = args.result;
+    return err;
+}
+
+static int
+amfi_interface_cdhash_in_trustcache(const uint8_t cdhash[], size_t cdhash_len, uint64_t* trustcache_result)
+{
+    int err = EINVAL;
+
+    if (cdhash == nullptr || cdhash_len != AMFI_INTF_CD_HASH_LEN || trustcache_result == nullptr) {
+        goto lb_end;
+    }
+    *trustcache_result = 0;
+
+    err = __amfi_interface_cdhash_in_trustcache(cdhash, trustcache_result);
+
+lb_end:
+    return err;
+}
+#endif
+
+bool Requirement::Interpreter::inTrustCache()
+{
+    uint64_t result = 0;
+    CFRef<CFDataRef> cdhashRef = mContext->directory->cdhash(true);
+    const uint8_t *cdhash = CFDataGetBytePtr(cdhashRef);
+    size_t cdhash_len = CFDataGetLength(cdhashRef);
+    int err = amfi_interface_cdhash_in_trustcache(cdhash, cdhash_len, &result);
+    return (err == 0) && (result != 0);
+}
+
 bool Requirement::Interpreter::appleSigned()
 {
-    if (appleAnchored()) {
-               if (SecCertificateRef intermed = mContext->cert(-2))    // first intermediate
-                       // first intermediate common name match (exact)
-                       if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
-                                       && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
-                               return true;
+    if (inTrustCache()) {
+        return true;
+    }
+    else if (appleAnchored()) {
+        if (SecCertificateRef intermed = mContext->cert(-2))   // first intermediate
+            // first intermediate common name match (exact)
+            if (certFieldValue("subject.CN", Match(appleIntermediateCN, matchEqual), intermed)
+                && certFieldValue("subject.O", Match(appleIntermediateO, matchEqual), intermed))
+                return true;
     } else if (appleLocalAnchored()) {
         return true;
-       }
-       return false;
+    }
+    return false;
 }
 
 
@@ -453,15 +520,7 @@ bool Requirement::Interpreter::verifyAnchor(SecCertificateRef cert, const unsign
        // get certificate bytes
        if (cert) {
         SHA1 hasher;
-#if TARGET_OS_OSX
-               CSSM_DATA certData;
-               MacOSError::check(SecCertificateGetData(cert, &certData));
-               
-               // verify hash
-               hasher(certData.Data, certData.Length);
-#else
         hasher(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert));
-#endif
                return hasher.verify(digest);
        }
        return false;
index 83b2fb02b40b431d0e438af7a0798f1377849c06..7e828f5ecb2a9665d5d73c8cac118c13e9a0bd21 100644 (file)
@@ -88,6 +88,7 @@ protected:
        bool verifyAnchor(SecCertificateRef cert, const unsigned char *digest);
        bool appleSigned();
        bool appleAnchored();
+       bool inTrustCache();
 
        bool trustedCerts();
        bool trustedCert(int slot);
index eff950abc01b261491e1989ea64330a5aa04b904..576459c8e4c41e005ac0b707584ab8ea72f2b8f5 100644 (file)
@@ -143,12 +143,17 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
        if (CFRef<CFDataRef> infoData = rep->component(cdInfoSlot))
                infoDict.take(makeCFDictionaryFrom(infoData));
        
-       uint32_t inherit = code->isSigned() ? state.mPreserveMetadata : 0;
+       uint32_t inherit = 0;
+
+       if (code->isSigned() && (code->codeDirectory(false)->flags & kSecCodeSignatureLinkerSigned) == 0) {
+               inherit = state.mPreserveMetadata;
+       }
 
        // work out the canonical identifier
        identifier = state.mIdentifier;
-       if (identifier.empty() && (inherit & kSecCodeSignerPreserveIdentifier))
+       if (identifier.empty() && (inherit & kSecCodeSignerPreserveIdentifier)) {
                identifier = code->identifier();
+       }
        if (identifier.empty()) {
                identifier = rep->recommendedIdentifier(*this);
                if (identifier.find('.') == string::npos)
@@ -174,8 +179,6 @@ void SecCodeSigner::Signer::prepare(SecCSFlags flags)
        entitlements = state.mEntitlementData;
        if (!entitlements && (inherit & kSecCodeSignerPreserveEntitlements))
                entitlements = code->component(cdEntitlementSlot);
-
-       generateEntitlementDER = signingFlags() & kSecCSSignGenerateEntitlementDER;
        
        // work out the CodeDirectory flags word
        bool haveCdFlags = false;
@@ -409,12 +412,12 @@ void SecCodeSigner::Signer::buildResources(std::string root, std::string relBase
        if (!(signingFlags() & kSecCSSignV1)) {
                CFCopyRef<CFDictionaryRef> rules2 = cfget<CFDictionaryRef>(rulesDict, "rules2");
                if (!rules2) {
-            // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules,
-            // because the default weight, according to ResourceBuilder::addRule(), is 1).
+                       // Clone V1 rules and add default nesting rules at weight 0 (overridden by anything in rules,
+                       // because the default weight, according to ResourceBuilder::addRule(), is 1).
                        // V1 rules typically do not cover these places so we'll prevail, but if they do, we defer to them.
-                       rules2 = cfmake<CFDictionaryRef>("{+%O"
+                       rules2.take(cfmake<CFDictionaryRef>("{+%O"
                                "'^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/' = {nested=#T, weight=0}" // exclude dynamic repositories
-                       "}", rules);
+                       "}", rules));
                }
 
                Dispatch::Group group;
@@ -540,7 +543,7 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context
        if (state.mPreserveAFSC)
                writer->setPreserveAFSC(state.mPreserveAFSC);
 
-       auto_ptr<ArchEditor> editor(state.mDetached
+       unique_ptr<ArchEditor> editor(state.mDetached
                ? static_cast<ArchEditor *>(new BlobEditor(*fat, *this))
                : new MachOEditor(writer, *fat, this->digestAlgorithms(), rep->mainExecutablePath()));
        assert(editor->count() > 0);
@@ -558,6 +561,22 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context
                                MacOSError::throwMe(errSecCSBadLVArch);
                        }
                }
+               
+               bool generateEntitlementDER = false;
+               if (signingFlags() & kSecCSSignGenerateEntitlementDER) {
+                       generateEntitlementDER = true;
+               } else {
+                       uint32_t platform = arch.source->platform();
+                       switch (platform) {
+                               case PLATFORM_WATCHOS:
+                               case PLATFORM_BRIDGEOS:
+                                       generateEntitlementDER = false;
+                                       break;
+                               default:
+                                       generateEntitlementDER = true;
+                                       break;
+                       }
+               }
 
                bool mainBinary = arch.source.get()->type() == MH_EXECUTE;
 
@@ -581,7 +600,7 @@ void SecCodeSigner::Signer::signMachO(Universal *fat, const Requirement::Context
                                                 arch.source->offset(), arch.source->signingExtent(),
                                                 mainBinary, rep->execSegBase(&(arch.architecture)), rep->execSegLimit(&(arch.architecture)),
                                                 unsigned(digestAlgorithms().size()-1),
-                                                preEncryptHashMaps[arch.architecture], runtimeVersionToUse);
+                                                preEncryptHashMaps[arch.architecture], runtimeVersionToUse, generateEntitlementDER);
                        });
                }
        
@@ -660,7 +679,8 @@ void SecCodeSigner::Signer::signArchitectureAgnostic(const Requirement::Context
                                 rep->execSegBase(NULL), rep->execSegLimit(NULL),
                                 unsigned(digestAlgorithms().size()-1),
                                 preEncryptHashMaps[preEncryptMainArch], // Only one map, the default.
-                                (cdFlags & kSecCodeSignatureRuntime) ? state.mRuntimeVersionOverride : 0);
+                                (cdFlags & kSecCodeSignatureRuntime) ? state.mRuntimeVersionOverride : 0,
+                                signingFlags() & kSecCSSignGenerateEntitlementDER);
                
                CodeDirectory *cd = builder.build();
                if (!state.mDryRun)
@@ -708,7 +728,7 @@ void SecCodeSigner::Signer::populate(CodeDirectory::Builder &builder, DiskRep::W
                                                                         bool mainBinary, size_t execSegBase, size_t execSegLimit,
                                                                         unsigned alternateDigestCount,
                                                                         PreEncryptHashMap const &preEncryptHashMap,
-                                                                        uint32_t runtimeVersion)
+                                                                        uint32_t runtimeVersion, bool generateEntitlementDER)
 {
        // fill the CodeDirectory
        builder.executable(rep->mainExecutablePath(), pagesize, offset, length);
index 960cf7960785c7b6f92aac8bcde3d3e83801d1bb..346f51efbf75574537fc9828e69fbc54dab8e3a6 100644 (file)
@@ -96,7 +96,7 @@ protected:
                                  bool mainBinary, size_t execSegBase, size_t execSegLimit,
                                  unsigned alternateDigestCount,
                                  const PreEncryptHashMap& preEncryptHashMap,
-                                 uint32_t runtimeVersion);     // per-architecture
+                                 uint32_t runtimeVersion, bool generateEntitlementDER);        // per-architecture
        CFDataRef signCodeDirectory(const CodeDirectory *cd,
                                                                CFDictionaryRef hashDict, CFArrayRef hashList);
 
@@ -146,7 +146,6 @@ private:
        CFAbsoluteTime signingTime;             // signing time for CMS signature (0 => now)
        bool emitSigningTime;                   // emit signing time as a signed CMS attribute
        bool strict;                                    // strict validation
-       bool generateEntitlementDER;    // generate entitlement DER
        
        // Signature Editing
        Architecture editMainArch;              // main architecture for editing
index 1bd01d8ce9d92a53e5f6b5c29a60f12cb30550e2..e40752a2f88a8d64cafdc097d76e393997698ba1 100644 (file)
@@ -103,7 +103,7 @@ public:
        //
        struct Arch : public BlobWriter {
                Architecture architecture;              // our architecture
-               auto_ptr<MachO> source;                 // Mach-O object to be signed
+               unique_ptr<MachO> source;                       // Mach-O object to be signed
                std::map<CodeDirectory::HashAlgorithm, RefPointer<CodeDirectory::Builder> > cdBuilders;
                InternalRequirements ireqs;             // consolidated internal requirements
                size_t blobSize;                                // calculated SuperBlob size
index d6e37ed9d3d99a96181e84648dfff055d05509c9..8189f0c08ca755c5ef0f42a39f82f75c9ce5a1ad 100644 (file)
@@ -269,11 +269,13 @@ CFDictionaryRef xpcEngineUpdate(CFTypeRef target, SecAssessmentFlags flags, CFDi
        
        msg.send();
 
-       if (localAuthorization)
+       if (localAuthorization) {
                AuthorizationFree(localAuthorization, kAuthorizationFlagDefaults);
+       }
        
-    if (int64_t error = xpc_dictionary_get_int64(msg, "error"))
-        MacOSError::throwMe((int)error);
+       if (int64_t error = xpc_dictionary_get_int64(msg, "error")) {
+               MacOSError::throwMe((int)error);
+       }
        
        size_t resultLength;
        const void *resultData = xpc_dictionary_get_data(msg, "result", &resultLength);
index bb9db9966d6a3b54bbf3d79f9bc92a68f7a82e81..de3b8979e8a51443ee50d79bb0c01db2917217eb 100644 (file)
@@ -55,8 +55,8 @@ class feeException
 protected:
        feeException(feeReturn frtn, const char *op);   
 public:
-       ~feeException() throw() {}
-       feeReturn frtn() const throw() { return mFrtn; }
+       ~feeException() _NOEXCEPT {}
+       feeReturn frtn() const _NOEXCEPT { return mFrtn; }
     static void throwMe(feeReturn frtn, const char *op = NULL) __attribute__((noreturn));
 private:
        feeReturn mFrtn;
index 8c950d38cc2565a0dc243c3bf77951c8865f9a78..a26d61bc76226dd231c861c993397b35b5a54612 100644 (file)
@@ -37,7 +37,6 @@
  *************************************************************/
 
 #include <stdio.h>
-#include<assert.h>
 #include <math.h>
 #include <stdlib.h>
 #include "giants.h"
index bf70b3ab7fdb75d94391d66fb5a5406a77fc3b36..cf8ac1545c36669ea1b65ffd16a09535d0f1d9cb 100644 (file)
@@ -31,7 +31,6 @@
  *************************************************************/
 
 #include <stdio.h>
-#include<assert.h>
 #include <math.h>
 #include"giants.h"
 #include "tools.h"
index 9c6ae1d3321617ef2bdb25ccfbbb1043f93c8a5c..ed0ac83c7fe4a703514d165404dac16cda8f16ac 100644 (file)
@@ -924,14 +924,6 @@ feeReturn feeFEEDDecryptBlock(feeFEED feed,
                    return FR_BadCipherText;
                }
 
-               /*
-                * we already know how long this should be...
-                */
-               if(finst->initialRSSize != finst->initialRSSize) {
-                   dbgLog(("feeFEEDDecryptBlock: initialRS sync error\n"));
-                   return FR_BadCipherText;
-               }
-
                /*
                 * Set up clues
                 */
index 59ab540ccc4388ac64f55096c490aec8456d8ce1..f697dbb13c5e864d15679441635447461885689b 100644 (file)
@@ -145,28 +145,28 @@ Attachment::~Attachment()
 //
 void *Attachment::upcallMalloc(CSSM_HANDLE handle, size_t size)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     return HandleObject::find<Attachment>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE).malloc(size);
     END_API1(NULL)
 }
 
 void Attachment::upcallFree(CSSM_HANDLE handle, void *mem)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     return HandleObject::find<Attachment>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE).free(mem);
     END_API0
 }
 
 void *Attachment::upcallRealloc(CSSM_HANDLE handle, void *mem, size_t size)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     return HandleObject::find<Attachment>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE).realloc(mem, size);
     END_API1(NULL)
 }
 
 void *Attachment::upcallCalloc(CSSM_HANDLE handle, size_t num, size_t size)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     return HandleObject::find<Attachment>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE).calloc(size, num);
     END_API1(NULL)
 }
@@ -174,7 +174,7 @@ void *Attachment::upcallCalloc(CSSM_HANDLE handle, size_t num, size_t size)
 CSSM_RETURN Attachment::upcallCcToHandle(CSSM_CC_HANDLE handle,
                                          CSSM_MODULE_HANDLE *modHandle)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     Required(modHandle) = HandleObject::find<HandleContext>((CSSM_HANDLE)handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE).attachment.handle();
     END_API(CSP)
 }
@@ -190,7 +190,7 @@ CSSM_RETURN Attachment::upcallGetModuleInfo(CSSM_MODULE_HANDLE handle,
                                             CSSM_FUNC_NAME_ADDR_PTR FunctionTable,
                                             uint32 NumFunctions)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     Attachment &attachment = HandleObject::find<Attachment>(handle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE);
     Required(guid) = attachment.myGuid();
     Required(version) = attachment.mVersion;
index 496d039c959dd50c15a3eb9ce942630d6fd8b8c7..c41afa3899704612301753424dbabedf695feea9 100644 (file)
@@ -31,7 +31,7 @@
 #include "module.h"
 #include <security_utilities/globalizer.h>
 #include <security_cdsa_utilities/cssmbridge.h>
-
+#include "LegacyAPICounts.h"
 
 //
 // We currently use exactly one instance of CssmManager.
index 6f82501963c1ae9a37befe045767a1d4ce4f9ed4..4a5ae461c90c76c0e328a5f1fdfd9628518d771a 100644 (file)
@@ -68,18 +68,18 @@ public:
     void mergeAttributes(const CSSM_CONTEXT_ATTRIBUTE *attributes, uint32 count);
     CSSM_RETURN validateChange(CSSM_CONTEXT_EVENT event);
 
-    void *operator new (size_t size, Allocator &alloc) throw(std::bad_alloc)
+    void *operator new (size_t size, Allocator &alloc)
     { return alloc.malloc(size); }
-    void operator delete (void *addr, size_t, Allocator &alloc) throw()
+    void operator delete (void *addr, size_t, Allocator &alloc) _NOEXCEPT
     { return alloc.free(addr); }
-    static void destroy(HandleContext *context, Allocator &alloc) throw()
+    static void destroy(HandleContext *context, Allocator &alloc) _NOEXCEPT
     { context->~HandleContext(); alloc.free(context); }
 
     class Maker;       // deluxe builder
 
 #if __GNUC__ > 2
 private:
-    void operator delete (void *addr) throw() { assert(0); }
+    void operator delete (void *addr) _NOEXCEPT { assert(0); }
 #endif
 
 protected:
index 4465dbc07857c294220b9603b8d8997031998cce..3d8bd1c04c405b98bdb39de34601cf9939e35743 100644 (file)
@@ -38,18 +38,6 @@ extern "C" {
  * (i.e. those with names like kSec...).
  */
 
-
-/* Common error codes. */
-enum {
-       CSSM_BASE_ERROR =                               -0x7FFF0000 /* 0x80010000 */
-};
-
-enum {
-       CSSM_ERRORCODE_MODULE_EXTENT =  0x00000800,
-       CSSM_ERRORCODE_CUSTOM_OFFSET =  0x00000400,
-       CSSM_ERRORCODE_COMMON_EXTENT =  0x100
-};
-
 /* Macros for convertible error code manipulation. */
 #define CSSM_ERRCODE(CODE) \
        (((CODE) - CSSM_BASE_ERROR) & (CSSM_ERRORCODE_MODULE_EXTENT - 1)) 
@@ -65,6 +53,12 @@ enum {
 
 /* Error Bases for different module types. */
 enum {
+    CSSM_BASE_ERROR =                                  -0x7FFF0000,    /* 0x80010000 */
+
+       CSSM_ERRORCODE_MODULE_EXTENT =          0x00000800,
+       CSSM_ERRORCODE_CUSTOM_OFFSET =          0x00000400,
+       CSSM_ERRORCODE_COMMON_EXTENT =          0x100,
+
        CSSM_CSSM_BASE_ERROR =                          CSSM_BASE_ERROR,
        CSSM_CSSM_PRIVATE_ERROR =                       CSSM_BASE_ERROR + CSSM_ERRORCODE_CUSTOM_OFFSET,
        CSSM_CSP_BASE_ERROR =                           CSSM_CSSM_BASE_ERROR + CSSM_ERRORCODE_MODULE_EXTENT,
index 7dce28fe171244dc0a701b41f452cefc8eba8ac7..713a31dc5af26de61887eeef5023d199d6a8d818 100644 (file)
@@ -155,7 +155,7 @@ CSSM_RETURN Module::spiEventRelay(const CSSM_GUID *ModuleGuid,
                                    CSSM_SERVICE_TYPE ServiceType,
                                    CSSM_MODULE_EVENT EventType)
 {
-    BEGIN_API
+    BEGIN_API_NO_METRICS
     static_cast<Module *>(Context)->spiEvent(EventType,
                                              Guid::required(ModuleGuid),
                                              SubserviceId,
index 8f78be84d8f4942c22ec8b1b7402430ba9816cc6..5e844f3fb14c365faea64575587f535c9a7fb663 100644 (file)
@@ -46,6 +46,7 @@
 #include <Security/cssmkrapi.h>
 #include <Security/cssmkrspi.h>
 #include <security_cdsa_utilities/cssmbridge.h>
+#include "LegacyAPICounts.h"
 
 
 //
index 60b47123f3d34337ec2f08cee985ce5b48a30d76..7f37d472b3c5e732cf3350642716c08265cb898f 100644 (file)
@@ -110,7 +110,7 @@ Table::readIndexSection()
                uint32 indexOffset = mTableSection.at(indexSectionOffset + (i + 2) * AtomSize);
                ReadSection indexSection(mTableSection.subsection(indexOffset));
 
-               auto_ptr<DbConstIndex> index(new DbConstIndex(*this, indexSection));
+               unique_ptr<DbConstIndex> index(new DbConstIndex(*this, indexSection));
                mIndexMap.insert(ConstIndexMap::value_type(index->indexId(), index.get()));
                index.release();
        }
@@ -289,7 +289,7 @@ ModifiedTable::insertRecord(uint32 inVersionId,
 {
        modifyTable();
 
-       auto_ptr<WriteSection> aWriteSection(new WriteSection());
+       unique_ptr<WriteSection> aWriteSection(new WriteSection());
        getMetaRecord().packRecord(*aWriteSection, inAttributes, inData);
     uint32 aRecordNumber = nextRecordNumber();
 
@@ -341,7 +341,7 @@ ModifiedTable::updateRecord(const RecordId &inRecordId,
 #endif
 
        // Update the actual packed record.
-    auto_ptr<WriteSection> aDbRecord(new WriteSection());
+    unique_ptr<WriteSection> aDbRecord(new WriteSection());
        getMetaRecord().updateRecord(anOldDbRecord, *aDbRecord,
                CssmDbRecordAttributeData::overlay(inAttributes), inData, inModifyMode);
 
@@ -507,7 +507,7 @@ ModifiedTable::createMutableIndexes()
 
        Table::ConstIndexMap::const_iterator it;
        for (it = mTable->mIndexMap.begin(); it != mTable->mIndexMap.end(); it++) {
-               auto_ptr<DbMutableIndex> mutableIndex(new DbMutableIndex(*it->second));
+               unique_ptr<DbMutableIndex> mutableIndex(new DbMutableIndex(*it->second));
                mIndexMap.insert(MutableIndexMap::value_type(it->first, mutableIndex.get()));
                mutableIndex.release();
        }
@@ -522,7 +522,7 @@ ModifiedTable::findIndex(uint32 indexId, const MetaRecord &metaRecord, bool isUn
 
        if (it == mIndexMap.end()) {
                // create the new index
-               auto_ptr<DbMutableIndex> index(new DbMutableIndex(metaRecord, indexId, isUniqueIndex));
+               unique_ptr<DbMutableIndex> index(new DbMutableIndex(metaRecord, indexId, isUniqueIndex));
                it = mIndexMap.insert(MutableIndexMap::value_type(indexId, index.get())).first;
                index.release();
        }
@@ -932,7 +932,7 @@ DbVersion::open()
                        // XXX Set the size boundary on aTableSection.
                        const ReadSection aTableSection =
                                aSchemaSection.subsection(aTableOffset);
-                       auto_ptr<Table> aTable(new Table(aTableSection));
+                       unique_ptr<Table> aTable(new Table(aTableSection));
                        Table::Id aTableId = aTable->getMetaRecord().dataRecordType();
                        mTableMap.insert(TableMap::value_type(aTableId, aTable.get()));
                        aTable.release();
@@ -1048,7 +1048,7 @@ DbVersion::open()
                        uint32 anAttributeId = aRecordData[1];
                        uint32 anAttributeNameFormat = aRecordData[2];
                        uint32 anAttributeFormat = aRecordData[5];
-                       auto_ptr<string> aName;
+                       unique_ptr<string> aName;
                        const CssmData *aNameID = NULL;
 
                        if (aRecordData[3].size() == 1)
@@ -1056,8 +1056,8 @@ DbVersion::open()
                                if (aRecordData[3].format() != CSSM_DB_ATTRIBUTE_FORMAT_STRING)
                                        CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
 
-                               auto_ptr<string> aName2(new string(static_cast<string>(aRecordData[3])));
-                               aName = aName2;
+                               unique_ptr<string> aName2(new string(static_cast<string>(aRecordData[3])));
+                               aName = std::move(aName2);
                        }
 
                        if (aRecordData[4].size() == 1)
@@ -1300,7 +1300,7 @@ IndexCursor::IndexCursor(DbQueryKey *queryKey, const DbVersion &inDbVersion,
 
 IndexCursor::~IndexCursor()
 {
-       // the query key will be deleted automatically, since it's an auto_ptr
+       // the query key will be deleted automatically, since it's an unique_ptr
 }
 
 bool
@@ -1554,7 +1554,7 @@ DbModifier::modifyDatabase()
                        mDbVersion->mTableMap.end();
                for (; anIt != anEnd; ++anIt)
                {
-                       auto_ptr<ModifiedTable> aTable(new ModifiedTable(anIt->second));
+                       unique_ptr<ModifiedTable> aTable(new ModifiedTable(anIt->second));
                        mModifiedTableMap.insert(ModifiedTableMap::value_type(anIt->first,
                                                                                                                                  aTable.get()));
                        aTable.release();
@@ -1601,8 +1601,8 @@ DbModifier::updateRecord(Table::Id inTableId, const RecordId &inRecordId,
 ModifiedTable *
 DbModifier::createTable(MetaRecord *inMetaRecord)
 {
-       auto_ptr<MetaRecord> aMetaRecord(inMetaRecord);
-       auto_ptr<ModifiedTable> aModifiedTable(new ModifiedTable(inMetaRecord));
+       unique_ptr<MetaRecord> aMetaRecord(inMetaRecord);
+       unique_ptr<ModifiedTable> aModifiedTable(new ModifiedTable(inMetaRecord));
        // Now that aModifiedTable is fully constructed it owns inMetaRecord
        aMetaRecord.release();
 
@@ -1744,7 +1744,7 @@ DbModifier::commit()
 }
 
 void
-DbModifier::rollback() throw()
+DbModifier::rollback() _NOEXCEPT
 {
        // This will destroy the AtomicTempFile if we have one causing it to rollback.
        mAtomicTempFile = NULL;
@@ -2367,7 +2367,7 @@ AppleDatabase::dataGetFirst(DbContext &inDbContext,
 {
        // XXX: register Cursor with DbContext and have DbContext call
        // dataAbortQuery for all outstanding Query objects on close.
-       auto_ptr<Cursor> aCursor(mDbModifier.createCursor(inQuery));
+       unique_ptr<Cursor> aCursor(mDbModifier.createCursor(inQuery));
        Table::Id aTableId;
        RecordId aRecordId;
 
@@ -2387,7 +2387,7 @@ AppleDatabase::dataGetNext(DbContext &inDbContext,
                            CssmData *inoutData,
                            CSSM_DB_UNIQUE_RECORD_PTR &outUniqueRecord)
 {
-       auto_ptr<Cursor> aCursor(&HandleObject::find<Cursor>(inResultsHandle, CSSMERR_DL_INVALID_RESULTS_HANDLE));
+       unique_ptr<Cursor> aCursor(&HandleObject::find<Cursor>(inResultsHandle, CSSMERR_DL_INVALID_RESULTS_HANDLE));
        Table::Id aTableId;
        RecordId aRecordId;
 
index 1ad330fda56b019fd3516598492d915db7611758..bd3413979d4947947a8ec3c6f737854bc95e37be 100644 (file)
@@ -361,7 +361,7 @@ public:
                                        RecordId &recordId);
 
 private:
-       auto_ptr<DbQueryKey> mQueryKey;
+       unique_ptr<DbQueryKey> mQueryKey;
        const Table &mTable;
        const DbConstIndex *mIndex;
        
@@ -383,10 +383,10 @@ public:
                                        Allocator &inAllocator,
                                        RecordId &recordId);
 private:
-       auto_ptr<CssmAutoQuery> mQuery;
+       unique_ptr<CssmAutoQuery> mQuery;
 
        DbVersion::const_iterator mTableIterator;
-       auto_ptr<Cursor> mCursor;
+       unique_ptr<Cursor> mCursor;
 };
 
 //
@@ -413,7 +413,7 @@ public:
        void deleteDatabase();
 
     void commit();
-    void rollback() throw();
+    void rollback() _NOEXCEPT;
 
        // Record changing members
        void deleteRecord(Table::Id inTableId, const RecordId &inRecordId);
index 6c21d12d2ab272967dd019f3802627475467881f..24ca9907493b1fa4713737b8501f6978db44dc49 100644 (file)
@@ -36,7 +36,7 @@
 #include <copyfile.h>
 #include <sandbox.h>
 #include <set>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #define kAtomicFileMaxBlockSize INT_MAX
 
@@ -391,8 +391,8 @@ AtomicBufferedFile::~AtomicBufferedFile()
 {
        if (mFileRef >= 0)
        {
-               // In release mode, the assert() is compiled out so rv may be unused.
-               __unused int rv = AtomicFile::rclose(mFileRef);
+               // In release mode, the assert() is compiled out so rv may be unused.
+               __unused int rv = AtomicFile::rclose(mFileRef);
                assert(rv == 0);
                secinfo("atomicfile", "%p closed %s", this, mPath.c_str());
        }
@@ -830,7 +830,7 @@ AtomicTempFile::commit()
 
 // Rollback the current create or write (happens automatically if commit() isn't called before the destructor is.
 void
-AtomicTempFile::rollback() throw()
+AtomicTempFile::rollback() _NOEXCEPT
 {
        if (mFileRef >= 0)
        {
@@ -1240,7 +1240,7 @@ AtomicLockedFile::lock(mode_t mode)
 
 
 
-void AtomicLockedFile::unlock() throw()
+void AtomicLockedFile::unlock() _NOEXCEPT
 {
        mFileLocker->unlock();
 }
index 86be8bea9ef8371519e4090ea95384751aa5ac25..0662eedb56412efc505259076c5d6ad3e54161a3 100644 (file)
@@ -160,7 +160,7 @@ private:
        void close();
 
     // Rollback the current create or write (happens automatically if commit() isn't called before the destructor is).
-    void rollback() throw();
+    void rollback() _NOEXCEPT;
 
 private:
        // Our AtomicFile object.
@@ -241,7 +241,7 @@ public:
 
 private:
        void lock(mode_t mode = (S_IRUSR|S_IRGRP|S_IROTH) /* === 0444 */);
-       void unlock() throw();
+       void unlock() _NOEXCEPT;
 
 private:
        FileLocker* mFileLocker;
index e95603b59e58953ebb9273cc50b6c2da18412937..007b2f69f14330c57e415f07ade2a09142f82a93 100644 (file)
@@ -64,8 +64,8 @@ DbKeyComparator::operator () (uint32 offset1, uint32 offset2) const
        
        for (uint32 i = 0; i < mKey.mNumKeyValues; i++) {
                const MetaAttribute &metaAttribute = *mKey.mIndex.mAttributes[i];
-               auto_ptr<DbValue> value1(metaAttribute.createValue(*key1, valueOffset1));
-               auto_ptr<DbValue> value2(metaAttribute.createValue(*key2, valueOffset2));
+               unique_ptr<DbValue> value1(metaAttribute.createValue(*key1, valueOffset1));
+               unique_ptr<DbValue> value2(metaAttribute.createValue(*key2, valueOffset2));
                
                if (metaAttribute.evaluate(value1.get(), value2.get(), CSSM_DB_LESS_THAN))
                        return true;
@@ -92,9 +92,9 @@ DbIndexKey::operator < (const DbIndexKey &other) const
        
        for (uint32 i = 0; i < numAttributes; i++) {
                const MetaAttribute &metaAttribute = *mIndex.mAttributes[i];
-               auto_ptr<DbValue> value1(metaAttribute.createValue(mKeySection.subsection(mKeyRange),
+               unique_ptr<DbValue> value1(metaAttribute.createValue(mKeySection.subsection(mKeyRange),
                        valueOffset1));
-               auto_ptr<DbValue> value2(metaAttribute.createValue(other.mKeySection.subsection(other.mKeyRange),
+               unique_ptr<DbValue> value2(metaAttribute.createValue(other.mKeySection.subsection(other.mKeyRange),
                        valueOffset2));
                
                if (metaAttribute.evaluate(value1.get(), value2.get(), CSSM_DB_LESS_THAN))
index 9fe1b4890b427ca947de1c0fcdc76a04b47ea811..c97dfdbf5dd8ff1303121d9d5dbaf2b2391e37a9 100644 (file)
@@ -49,9 +49,10 @@ void WriteSection::grow(size_t inNewCapacity)
        size_t aNewCapacity = max(n, inNewCapacity);
        mAddress = reinterpret_cast<uint8 *>(mAllocator.realloc(mAddress, aNewCapacity));
 
-    if (mAddress == NULL)
+    if (mAddress == NULL) {
         CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
+    }
 
-       memset(mAddress + mCapacity, 0, aNewCapacity - mCapacity);
-       mCapacity = aNewCapacity;
+    memset(mAddress + mCapacity, 0, aNewCapacity - mCapacity);
+    mCapacity = aNewCapacity;
 }
index f77e8c4cf9049599b945c41c93878327e8fb7101..7b2b514756f09b627d190e5d4f82cdb0728a2edb 100644 (file)
@@ -76,7 +76,7 @@ public:
 
     uint32 at(uint32 inOffset) const
     {
-               if (inOffset > mLength)
+               if (CheckUInt32Add(inOffset, AtomSize) > mLength)
                {
             CssmError::throwMe(CSSMERR_DL_DATABASE_CORRUPT);
                }
diff --git a/OSX/libsecurity_keychain/Security b/OSX/libsecurity_keychain/Security
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index a2f1ec1b8bb70d152fd7941f821fdcac3c05a34d..e20ee2cf685f61d15daf5c0747d265c3f0c5bf3d 100644 (file)
@@ -78,7 +78,7 @@ CertificateValues::CertificateValues(SecCertificateRef certificateRef) : mCertif
                CFRetain(mCertificateRef);
 }
 
-CertificateValues::~CertificateValues() throw()
+CertificateValues::~CertificateValues() _NOEXCEPT
 {
        if (mCertificateProperties)
                CFRelease(mCertificateProperties);
index 41d17c3fe53972368de6c72dc065fff96e9aaabb..64150acb5c32dd8cb03567a1ac9ae03681cf3edf 100644 (file)
@@ -43,7 +43,7 @@ class CertificateValues
 public:
 
        CertificateValues(SecCertificateRef certificateRef);
-       virtual ~CertificateValues() throw();
+       virtual ~CertificateValues() _NOEXCEPT;
 
        static CFStringRef remapLabelToKey(CFStringRef label);
        CFArrayRef copyPropertyValues(CFErrorRef *error);
index aa168bd8b3d257f6b514296606b21580078e1dda..1477478833a3f3c19802df76eb39190ecd8c17ca 100644 (file)
@@ -415,13 +415,14 @@ DLDbListCFPref::resetCachedValues()
 
 void DLDbListCFPref::save()
 {
-    if (!hasChanged())
+    if (!hasChanged()) {
         return;
+    }
 
-       // Resync from disc to make sure we don't clobber anyone elses changes.
-       // @@@ This is probably already done by the next layer up so we don't
-       // really need to do it here again.
-       loadPropertyList(true);
+    // Resync from disc to make sure we don't clobber anyone elses changes.
+    // @@@ This is probably already done by the next layer up so we don't
+    // really need to do it here again.
+    loadPropertyList(true);
 
     // Do the searchList first since it might end up invoking defaultDLDbIdentifier() which can set
     // mLoginDLDbIdentifierSet and mDefaultDLDbIdentifierSet to true.
index 791c0cc2be17d1dd1304317ea5def6fc55424e60..d81650d319ad097a76a214b076fc5f737acaaa67 100644 (file)
@@ -116,7 +116,7 @@ ExtendedAttribute::ExtendedAttribute(
        setupAttrs();
 }
 
-ExtendedAttribute::~ExtendedAttribute() throw()
+ExtendedAttribute::~ExtendedAttribute() _NOEXCEPT
 {
 
 }
index ed2b1f75026cd6369ede154eda56f93f9f0f6978..2469fce62e3f564cfbf2fd7fed68e3047358e43d 100644 (file)
@@ -69,7 +69,7 @@ public:
        
        ExtendedAttribute(ExtendedAttribute &extendedAttribute);
 
-    virtual ~ExtendedAttribute() throw();
+    virtual ~ExtendedAttribute() _NOEXCEPT;
 
        virtual PrimaryKey add(Keychain &keychain);
        bool operator == (const ExtendedAttribute &other) const;
index 85b0636decf8b943ec2477680040cce7f8c6474a..6447eb9b110ed02c176b05daf7bbd57af7cc63ca 100644 (file)
@@ -113,7 +113,7 @@ Identity::Identity(const StorageManager::KeychainList &keychains, const SecPoint
     }
 }
 
-Identity::~Identity() throw()
+Identity::~Identity() _NOEXCEPT
 {
     if (mPrivateKey)
         CFRelease(mPrivateKey);
index 29170a27fb6af24b4288fc30a962948caed52c84..e942f6a342d99ca89fc05c9e27cb2e01a6d7eca0 100644 (file)
@@ -47,7 +47,7 @@ public:
     Identity(const SecKeyRef privateKey,
              const SecPointer<Certificate> &certificate);
     Identity(const StorageManager::KeychainList &keychains, const SecPointer<Certificate> &certificate);
-    virtual ~Identity() throw();
+    virtual ~Identity() _NOEXCEPT;
 
        SecPointer<KeyItem> privateKey() const;
        SecPointer<Certificate> certificate() const;
index 519b47c2543c6ae49759fb57a6f8ae3f7089af58..773800c888d1f9da8fa548d17a86964e57da658f 100644 (file)
@@ -55,7 +55,7 @@ IdentityCursorPolicyAndID::IdentityCursorPolicyAndID(const StorageManager::Keych
        }
 }
 
-IdentityCursorPolicyAndID::~IdentityCursorPolicyAndID() throw()
+IdentityCursorPolicyAndID::~IdentityCursorPolicyAndID() _NOEXCEPT
 {
        if (mPolicy) {
                CFRelease(mPolicy);
@@ -271,7 +271,7 @@ IdentityCursor::IdentityCursor(const StorageManager::KeychainList &searchList, C
                mKeyCursor->add(CSSM_DB_EQUAL, KeySchema::Unwrap, true);
 }
 
-IdentityCursor::~IdentityCursor() throw()
+IdentityCursor::~IdentityCursor() _NOEXCEPT
 {
 }
 
@@ -281,7 +281,7 @@ IdentityCursor::pubKeyHashForSystemIdentity(CFStringRef domain)
        StLock<Mutex>_(mMutex);
 
     CFDataRef entryValue = nil;
-       auto_ptr<Dictionary> identDict;
+       unique_ptr<Dictionary> identDict;
        Dictionary* d = Dictionary::CreateDictionary("com.apple.security.systemidentities", Dictionary::US_System);
        if (d)
        {
index aa9d7f58c1ab475c5094379ee203b26205f3f815..1e0e275cb2098971454427f681ce0ee5da4f39b6 100644 (file)
@@ -50,7 +50,7 @@ public:
        SECCFFUNCTIONS(IdentityCursor, SecIdentitySearchRef, errSecInvalidSearchRef, gTypes().IdentityCursor)
 
     IdentityCursor(const StorageManager::KeychainList &searchList, CSSM_KEYUSE keyUsage);
-       virtual ~IdentityCursor() throw();
+       virtual ~IdentityCursor() _NOEXCEPT;
        virtual bool next(SecPointer<Identity> &identity);
 
        CFDataRef pubKeyHashForSystemIdentity(CFStringRef domain);
@@ -69,7 +69,7 @@ class IdentityCursorPolicyAndID : public IdentityCursor
 {
 public:
     IdentityCursorPolicyAndID(const StorageManager::KeychainList &searchList, CSSM_KEYUSE keyUsage, CFStringRef idString, SecPolicyRef policy, bool returnOnlyValidIdentities);
-       virtual ~IdentityCursorPolicyAndID() throw();
+       virtual ~IdentityCursorPolicyAndID() _NOEXCEPT;
        virtual bool next(SecPointer<Identity> &identity);
        virtual void findPreferredIdentity();
 
index 4d4dc772e14dbc548e949c50289fe3d6b205013b..f6720512bf26996e55579a6ea3a944b6f235b29c 100644 (file)
@@ -331,7 +331,7 @@ DbAttributes* ItemImpl::getCurrentAttributes() {
 
 void ItemImpl::encodeAttributes(CssmOwnedData &attributeBlob) {
     // Sometimes we don't have our attributes. Find them.
-    auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
+    unique_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
     encodeAttributesFromDictionary(attributeBlob, dbAttributes.get());
 
 }
@@ -456,7 +456,7 @@ void ItemImpl::encodeAttributesFromDictionary(CssmOwnedData &attributeBlob, DbAt
 }
 
 void ItemImpl::computeDigest(CssmOwnedData &sha2) {
-    auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
+    unique_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
     ItemImpl::computeDigestFromDictionary(sha2, dbAttributes.get());
 }
 
@@ -593,7 +593,7 @@ bool ItemImpl::checkIntegrity(AclBearer& aclBearer) {
         return true;
     }
 
-    auto_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
+    unique_ptr<DbAttributes> dbAttributes(getCurrentAttributes());
     return checkIntegrityFromDictionary(aclBearer, dbAttributes.get());
 }
 
@@ -607,7 +607,7 @@ bool ItemImpl::checkIntegrityFromDictionary(AclBearer& aclBearer, DbAttributes*
         // them.
 
         AclEntryInfo &info = aclInfos.at(0);
-        auto_ptr<ACL> acl(new ACL(info, Allocator::standard()));
+        unique_ptr<ACL> acl(new ACL(info, Allocator::standard()));
 
         for(int i = 1; i < aclInfos.count(); i++) {
             secnotice("integrity", "*** DUPLICATE INTEGRITY ACL, something has gone wrong");
@@ -1073,7 +1073,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC
     } catch (CssmError cssme) {
         // If there's a "duplicate" of this item, it might be an item with corrupt/invalid attributes
         // Try to extract the item and check its attributes, then try again if necessary
-        auto_ptr<CssmClient::DbAttributes> primaryKeyAttrs;
+        unique_ptr<CssmClient::DbAttributes> primaryKeyAttrs;
         if(cssme.error == CSSMERR_DL_INVALID_UNIQUE_INDEX_DATA) {
             secnotice("integrity", "possible duplicate, trying to delete invalid items");
 
@@ -1113,7 +1113,7 @@ ItemImpl::doChange(Keychain keychain, CSSM_DB_RECORDTYPE recordType, void (^tryC
 
                     // The item on-disk might have more or different attributes than we do, since we're
                     // only searching via primary key. Fetch all of its attributes.
-                    auto_ptr<DbAttributes>dbDupAttributes (new DbAttributes(kc->database(), 1));
+                    unique_ptr<DbAttributes>dbDupAttributes (new DbAttributes(kc->database(), 1));
                     fillDbAttributesFromSchema(*dbDupAttributes, recordType, kc);
 
                     // Occasionally this cursor won't return the item attributes (for an unknown reason).
index 8e9460dd62ed23ad7371857c64840f9f65f0e5f1..bbcacb51473000caafc8e16f330b958c597a9478 100644 (file)
@@ -179,8 +179,8 @@ public:
        void postItemEvent (SecKeychainEvent theEvent);
 
        // Only call these functions while holding globals().apiLock.
-       bool inCache() const throw() { return mInCache; }
-       void inCache(bool inCache) throw() { mInCache = inCache; }
+       bool inCache() const _NOEXCEPT { return mInCache; }
+       void inCache(bool inCache) _NOEXCEPT { mInCache = inCache; }
 
        /* For binding to extended attributes. */
        virtual const CssmData &itemID();
@@ -222,7 +222,7 @@ protected:
 
        // new item members
        RefPointer<CssmDataContainer> mData;
-       auto_ptr<CssmClient::DbAttributes> mDbAttributes;
+       unique_ptr<CssmClient::DbAttributes> mDbAttributes;
        SecPointer<Access> mAccess;
 
        // db item members
index ad7039cf3844cd30cd3a7058ebc68d2ef604b074..4122197763eed3822b9ea3454b89337ac071181e 100644 (file)
@@ -172,7 +172,7 @@ KCCursorImpl::KCCursorImpl(const StorageManager::KeychainList &searchList, const
        }
 }
 
-KCCursorImpl::~KCCursorImpl() throw()
+KCCursorImpl::~KCCursorImpl() _NOEXCEPT
 {
 }
 
index 91027f162a6a442ca7957b4a65d001b286254dc8..4ce190a160a0f75fc9694bc9151667a7bf5ac265 100644 (file)
@@ -47,7 +47,7 @@ protected:
        KCCursorImpl(const StorageManager::KeychainList &searchList, const SecKeychainAttributeList *attrList);
 
 public:
-       virtual ~KCCursorImpl() throw();
+       virtual ~KCCursorImpl() _NOEXCEPT;
        bool next(Item &item);
     bool mayDelete();
 
index 6bec5672a6a0ef6bed4b9e19a4b54966630bb02b..1f079ff570819d6736db162f9b2bf50bb1a9c519 100644 (file)
@@ -75,7 +75,7 @@ KeyItem *KeyItem::optional(SecKeyRef ptr)
     }
 }
 
-KeyItem::operator CFTypeRef() const throw()
+KeyItem::operator CFTypeRef() const _NOEXCEPT
 {
     StMaybeLock<Mutex> _(this->getMutexForObject());
 
@@ -758,8 +758,8 @@ KeyItem::createPair(
             pubKeyHash.set(*pubKeyHashData);
             passThrough.allocator().free(pubKeyHashData);
 
-            auto_ptr<string> privDescription;
-            auto_ptr<string> pubDescription;
+            unique_ptr<string> privDescription;
+            unique_ptr<string> pubDescription;
             try {
                 privDescription.reset(new string(initialAccess->promptDescription()));
                 pubDescription.reset(new string(initialAccess->promptDescription()));
@@ -997,8 +997,8 @@ KeyItem::importPair(
                csp.allocator().free(cssmData->Data);
                csp.allocator().free(cssmData);
 
-               auto_ptr<string>privDescription;
-               auto_ptr<string>pubDescription;
+               unique_ptr<string>privDescription;
+               unique_ptr<string>pubDescription;
                try {
                        privDescription.reset(new string(initialAccess->promptDescription()));
                        pubDescription.reset(new string(initialAccess->promptDescription()));
index 8f048f5cee755fa5245ef45beb3c19752438ad89..326279d95fe951dd7bc425ba150e613f9f073aaf 100644 (file)
@@ -46,7 +46,7 @@ public:
     // SECCFUNCTIONS macro to retarget SecKeyRef to foreign object instead of normal way through SecCFObject.
     static KeyItem *required(SecKeyRef ptr);
     static KeyItem *optional(SecKeyRef ptr);
-    operator CFTypeRef() const throw();
+    operator CFTypeRef() const _NOEXCEPT;
     static SecCFObject *fromSecKeyRef(CFTypeRef ref);
     void attachSecKeyRef() const;
     void initializeWithSecKeyRef(SecKeyRef ref);
index 507b270ca3a4d74618562ef5c0c8103962996793..b33ae6a4b28ad07ac6a65e5d2f11bf980a15a4f3 100644 (file)
@@ -218,8 +218,8 @@ public:
        const AccessCredentials *defaultCredentials();
 
        // Only call these functions while holding globals().apiLock.
-       bool inCache() const throw() { return mInCache; }
-       void inCache(bool inCache) throw() { mInCache = inCache; }
+       bool inCache() const _NOEXCEPT { return mInCache; }
+       void inCache(bool inCache) _NOEXCEPT { mInCache = inCache; }
        
        void postEvent(SecKeychainEvent kcEvent, ItemImpl* item);
     void postEvent(SecKeychainEvent kcEvent, ItemImpl* item, PrimaryKey pk);
diff --git a/OSX/libsecurity_keychain/lib/LegacyAPICounts.h b/OSX/libsecurity_keychain/lib/LegacyAPICounts.h
new file mode 100644 (file)
index 0000000..578e59a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020 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 LegacyAPICounts_h
+#define LegacyAPICounts_h
+
+#include <stdbool.h>
+#include <dispatch/dispatch.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+void countLegacyAPI(dispatch_once_t* token, const char* api);
+void setCountLegacyAPIEnabledForThread(bool value);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* LegacyAPICounts_h */
diff --git a/OSX/libsecurity_keychain/lib/LegacyAPICounts.m b/OSX/libsecurity_keychain/lib/LegacyAPICounts.m
new file mode 100644 (file)
index 0000000..04cde0f
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020 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 <os/feature_private.h>
+#import <sys/codesign.h>
+
+#import "LegacyAPICounts.h"
+#import "utilities/SecCoreAnalytics.h"
+#import "SecEntitlements.h"
+#import "debugging.h"
+#import "SecInternalReleasePriv.h"
+
+#pragma mark - File-Private
+
+static NSString* applicationIdentifierForSelf() {
+    NSString* identifier = nil;
+    SecTaskRef task = SecTaskCreateFromSelf(kCFAllocatorDefault);
+
+    if (task) {
+        CFStringRef val = (CFStringRef)SecTaskCopyValueForEntitlement(task, kSecEntitlementApplicationIdentifier, NULL);
+        if (val && CFGetTypeID(val) != CFStringGetTypeID()) {
+            CFRelease(val);
+        } else {
+            identifier = CFBridgingRelease(val);
+        }
+
+        // security tool doesn't have entitlements, I wonder if there are more.
+        if (!identifier) {
+            identifier = CFBridgingRelease(SecTaskCopySigningIdentifier(task, NULL));
+        }
+
+        CFRelease(task);
+    }
+
+    return identifier;
+}
+
+static BOOL countLegacyAPIEnabledForThread() {
+    NSNumber* value = [[NSThread currentThread] threadDictionary][@"countLegacyAPIEnabled"];
+
+    // No value means not set at all, so not disabled by SecItem*
+    if (!value || (value && [value isKindOfClass:[NSNumber class]] && [value boolValue])) {
+        return YES;
+    }
+    return NO;
+}
+
+#pragma mark - SPI
+
+void setCountLegacyAPIEnabledForThread(bool value) {
+    [[NSThread currentThread] threadDictionary][@"countLegacyAPIEnabled"] = value ? @YES : @NO;
+}
+
+void countLegacyAPI(dispatch_once_t* token, const char* api) {
+    static NSString* identifier;
+    static BOOL shouldCount;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        identifier = applicationIdentifierForSelf() ?: @"unknown";
+        shouldCount = os_feature_enabled(Security, LegacyAPICounts);
+    });
+
+    if (api == nil) {
+        secerror("LegacyAPICounts: Attempt to count API without name");
+        return;
+    }
+
+    if (!shouldCount || !countLegacyAPIEnabledForThread()) {
+        return;
+    }
+
+    dispatch_once(token, ^{
+        NSString* apiStringObject = [NSString stringWithCString:api encoding:NSUTF8StringEncoding];
+        if (!apiStringObject) {
+            secerror("LegacyAPICounts: Surprisingly, char* for api name \"%s\" did not turn into NSString", api);
+            return;
+        }
+
+        [SecCoreAnalytics sendEventLazy:@"com.apple.security.LegacyAPICounts" builder:^NSDictionary<NSString *,NSObject *> * _Nonnull{
+            return @{
+                @"app" : identifier,
+                @"api" : apiStringObject,
+            };
+        }];
+    });
+}
index 68cdcce2189fea4a1c5c1a42d4f9ca1e18c74043..783e0152bb2712d38f15439aebad85e1854393e5 100644 (file)
@@ -64,7 +64,7 @@ PasswordImpl::PasswordImpl(PasswordImpl& existing)
 
 
 
-PasswordImpl::~PasswordImpl() throw()
+PasswordImpl::~PasswordImpl() _NOEXCEPT
 {
 }
 
index f142a9a47ad6aa7d60467e8f9d68612a4c72ba20..a633fa0a5b41f570fbef7778476590d096fb2a61 100644 (file)
@@ -44,7 +44,7 @@ public:
     PasswordImpl(SecItemClass itemClass, SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList);
        PasswordImpl(PasswordImpl& existing);
 
-    virtual ~PasswordImpl() throw();
+    virtual ~PasswordImpl() _NOEXCEPT;
 
     bool getData(UInt32 *length, const void **data);
     void setData(UInt32 length,const void *data);
index 4f0cd43348e7b8257f3aacc71524593ffc762fb7..c78e53567fc77e2985beb7a57867ac961988e67c 100644 (file)
@@ -85,7 +85,7 @@ Policy::Policy(TP supportingTp, const CssmOid &policyOid)
        secinfo("policy", "Policy() this %p", this);
 }
 
-Policy::~Policy() throw()
+Policy::~Policy() _NOEXCEPT
 {
        secinfo("policy", "~Policy() this %p", this);
 }
index f4331b4dd85db570d6d28a6f4b7365779c42e875..b2c934a020125bed2bae75337dc5b203f9e52bef 100644 (file)
@@ -55,7 +55,7 @@ public:
     Policy(TP supportingTp, const CssmOid &policyOid);
 
 public:
-    virtual ~Policy() throw();
+    virtual ~Policy() _NOEXCEPT;
 
     TP &tp()                                                   { return mTp; }
     const TP &tp() const                               { return mTp; }
index d8db218b81625c0f6644bf9fbc216a4be6a6765d..6c11e1073bcc790522656a6d0fd73ba5db124a15 100644 (file)
@@ -85,7 +85,7 @@ PolicyCursor::PolicyCursor(const CSSM_OID* oid, const CSSM_DATA* value)
 //
 // Destroy
 //
-PolicyCursor::~PolicyCursor() throw()
+PolicyCursor::~PolicyCursor() _NOEXCEPT
 {
 }
 
index c7503b685ece0460b55cd5c8a74be941e49dc682..351b641aedce4df6bc9208b7d76991b2aa09ae91 100644 (file)
@@ -49,7 +49,7 @@ public:
        SECCFFUNCTIONS(PolicyCursor, SecPolicySearchRef, errSecInvalidSearchRef, gTypes().PolicyCursor)
 
        PolicyCursor(const CSSM_OID* oid, const CSSM_DATA* value);
-       virtual ~PolicyCursor() throw();
+       virtual ~PolicyCursor() _NOEXCEPT;
        bool next(SecPointer<Policy> &policy);
        bool oidProvided() { return mOidGiven; }
 
index 5e5dbb7b3a5701b5ef2e05de304b73884930c10b..23cb241351302292056a7bfd142d395e5532ce49 100644 (file)
@@ -30,6 +30,8 @@
 
 #include "SecBridge.h"
 
+#include "LegacyAPICounts.h"
+
 // Forward reference
 /*!
        @function GetACLAuthorizationTagFromString
@@ -89,6 +91,7 @@ OSStatus SecACLCreateWithSimpleContents(SecAccessRef access,
                                                                                SecKeychainPromptSelector promptSelector,
                                                                                SecACLRef *newAcl)
 {
+       COUNTLEGACYAPI
        CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
        cdsaPromptSelector.version = CSSM_ACL_KEYCHAIN_PROMPT_CURRENT_VERSION;
        cdsaPromptSelector.flags = promptSelector;
@@ -156,6 +159,7 @@ OSStatus SecACLCopyContents(SecACLRef acl,
                                                        CFStringRef *description, 
                                                        SecKeychainPromptSelector *promptSelector)
 {
+       COUNTLEGACYAPI
        CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
        memset(&cdsaPromptSelector, 0, sizeof(cdsaPromptSelector));
        OSStatus err = errSecSuccess;
@@ -208,6 +212,7 @@ OSStatus SecACLSetContents(SecACLRef acl,
                                                   CFStringRef description, 
                                                   SecKeychainPromptSelector promptSelector)
 {
+       COUNTLEGACYAPI
        CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR cdsaPromptSelector;
        cdsaPromptSelector.version = CSSM_ACL_PROCESS_SELECTOR_CURRENT_VERSION;
        cdsaPromptSelector.flags = promptSelector;
@@ -248,6 +253,7 @@ OSStatus SecACLGetAuthorizations(SecACLRef acl,
 
 CFArrayRef SecACLCopyAuthorizations(SecACLRef acl)
 {
+       COUNTLEGACYAPI
        CFArrayRef result = NULL;
        if (NULL == acl)
        {
@@ -310,6 +316,7 @@ OSStatus SecACLSetAuthorizations(SecACLRef aclRef,
 
 OSStatus SecACLUpdateAuthorizations(SecACLRef acl, CFArrayRef authorizations)
 {
+       COUNTLEGACYAPI
        if (NULL == acl || NULL == authorizations)
        {
                return errSecParam;
index 91680d824ab8abf9b281f61f67ddf57bd90c9a3d..443689921f18b274d965dc6740894043f1a44d84 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <utilities/SecCFWrappers.h>
 
+#include "LegacyAPICounts.h"
 
 /* No restrictions. Permission to perform all operations on
    the resource or available to an ACL owner.  */
@@ -289,6 +290,7 @@ OSStatus SecAccessCreateFromOwnerAndACL(const CSSM_ACL_OWNER_PROTOTYPE *owner,
 
 SecAccessRef SecAccessCreateWithOwnerAndACL(uid_t userId, gid_t groupId, SecAccessOwnerType ownerType, CFArrayRef acls, CFErrorRef *error)
 {
+       COUNTLEGACYAPI
        SecAccessRef result = NULL;
 
        CSSM_ACL_PROCESS_SUBJECT_SELECTOR selector =
@@ -416,6 +418,7 @@ OSStatus SecAccessGetOwnerAndACL(SecAccessRef accessRef,
 
 OSStatus SecAccessCopyOwnerAndACL(SecAccessRef accessRef, uid_t* userId, gid_t* groupId, SecAccessOwnerType* ownerType, CFArrayRef* aclList)
 {
+       COUNTLEGACYAPI
        CSSM_ACL_OWNER_PROTOTYPE_PTR owner = NULL;
        CSSM_ACL_ENTRY_INFO_PTR acls = NULL;
        uint32 aclCount = 0;
@@ -532,6 +535,7 @@ OSStatus SecAccessCopySelectedACLList(SecAccessRef accessRef,
 
 CFArrayRef SecAccessCopyMatchingACLList(SecAccessRef accessRef, CFTypeRef authorizationTag)
 {
+       COUNTLEGACYAPI
        CFArrayRef result = NULL;
        CSSM_ACL_AUTHORIZATION_TAG tag = GetACLAuthorizationTagFromString((CFStringRef)authorizationTag);
        OSStatus err = SecAccessCopySelectedACLList(accessRef, tag, &result);
@@ -564,8 +568,9 @@ CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trus
 
     // Make a bundle instance using the URLRef.
     secBundle = CFBundleCreate(kCFAllocatorDefault,bundleURL);
-    if (!secBundle)
+    if (!secBundle) {
         goto xit;
+    }
 
        trustedAppListFileNameWithoutExtension =
                CFStringCreateMutableCopy(NULL,CFStringGetLength(trustedAppListFileName),trustedAppListFileName);
@@ -575,11 +580,13 @@ CFArrayRef copyTrustedAppListFromBundle(CFStringRef bundlePath, CFStringRef trus
 
     // Look for a resource in the bundle by name and type
     trustedAppsURL = CFBundleCopyResourceURL(secBundle,trustedAppListFileNameWithoutExtension,CFSTR("plist"),NULL);
-    if (!trustedAppsURL)
+    if (!trustedAppsURL) {
         goto xit;
+    }
 
-       if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,trustedAppsURL,&xmlDataRef,NULL,NULL,&errorCode))
+    if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault,trustedAppsURL,&xmlDataRef,NULL,NULL,&errorCode)) {
         goto xit;
+    }
 
        trustedAppsPlist = CFPropertyListCreateFromXMLData(kCFAllocatorDefault,xmlDataRef,kCFPropertyListImmutable,&errorString);
     trustedAppList = (CFArrayRef)trustedAppsPlist;
@@ -602,6 +609,7 @@ xit:
 
 OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess)
 {
+       COUNTLEGACYAPI
        OSStatus err = errSecSuccess;
        SecAccessRef accessToReturn=nil;
        CFMutableArrayRef trustedApplications=nil;
index d9e151ce6b16e61c549bec8d4be4ecd39dde5bf5..01946113c170b50b0d7584ac5d8d410023a16986 100644 (file)
@@ -127,7 +127,7 @@ CFTypeID SecAccessGetTypeID(void);
        @param accessRef On return, a pointer to the new access reference.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecAccessCreate(CFStringRef descriptor, CFArrayRef __nullable trustedlist, SecAccessRef * __nonnull CF_RETURNS_RETAINED accessRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecAccessCreate(CFStringRef descriptor, CFArrayRef __nullable trustedlist, SecAccessRef * __nonnull CF_RETURNS_RETAINED accessRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecAccessCreateFromOwnerAndACL
@@ -189,7 +189,7 @@ OSStatus SecAccessCopyOwnerAndACL(SecAccessRef accessRef, uid_t * __nullable use
        @param aclList On return, a pointer to a new created CFArray of SecACL instances.  The caller is responsible for calling CFRelease on this array.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecAccessCopyACLList(SecAccessRef accessRef, CFArrayRef * __nonnull CF_RETURNS_RETAINED aclList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecAccessCopyACLList(SecAccessRef accessRef, CFArrayRef * __nonnull CF_RETURNS_RETAINED aclList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecAccessCopySelectedACLList
index 9596f4fc8052e4ddcc292f39a632fbed91d7a97d..c9982afeb4451e9ddcfe5855aa159ac97401f7f9 100644 (file)
@@ -39,9 +39,6 @@
 extern "C" {
 #endif
 
-OSStatus SecKeychainAddIToolsPassword(SecKeychainRef keychain, UInt32 accountNameLength, const char *accountName,
-    UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef) __deprecated_msg("iTools is no longer supported") API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
-
 /*!
        @function SecAccessCreateWithTrustedApplications
        @abstract Creates a SecAccess object with the specified trusted applications.
@@ -53,7 +50,7 @@ OSStatus SecKeychainAddIToolsPassword(SecKeychainRef keychain, UInt32 accountNam
        @discussion The SecAccessCreateWithPList creates a SecAccess with the provided list of trusted applications.
 */
 
-OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecAccessCreateWithTrustedApplications(CFStringRef trustedApplicationsPListPath, CFStringRef accessLabel, Boolean allowAny, SecAccessRef* returnedAccess) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 #if defined(__cplusplus)
index 2d82dd36097a336da1627b390fedb88e52eb1d73..cf69d48a2ae0323d3ba8d0333738ac2e56f8512f 100644 (file)
@@ -141,10 +141,11 @@ copyErrorMessageFromBundle(OSStatus status,CFStringRef tableName)
        
     // Convert status to Int32 string representation, e.g. "-25924"
     keyString = CFStringCreateWithFormat (kCFAllocatorDefault,NULL,CFSTR("%d"),(int)status);
-    if (!keyString)
+    if (!keyString) {
         goto xit;
+    }
 
-       errorString = CFCopyLocalizedStringFromTableInBundle(keyString,tableName,secBundle,NULL);
+    errorString = CFCopyLocalizedStringFromTableInBundle(keyString,tableName,secBundle,NULL);
     if (CFStringCompare(errorString, keyString, 0)==kCFCompareEqualTo) // no real error message
        {
                if (errorString)
index c52a5b29696eb9143d30778a4cfefefa8755f589..c9e39bf9c5cf56d39c38150161628ce33d1523b4 100644 (file)
 #include <Security/SecKeychainPriv.h>
 #include <security_keychain/KCUtilities.h>
 #include <security_cdsa_utilities/cssmbridge.h>
+#include "LegacyAPICounts.h"
 
 using namespace KeychainCore;
 
+#define COUNTLEGACYAPI static dispatch_once_t countToken; \
+       countLegacyAPI(&countToken, __FUNCTION__);
+
 //
 // API boilerplate macros. These provide a frame for C++ code that is impermeable to exceptions.
 // Usage:
@@ -46,6 +50,8 @@ using namespace KeychainCore;
 //
 #define BEGIN_SECAPI \
        OSStatus __secapiresult = errSecSuccess; \
+       static dispatch_once_t countToken; \
+       countLegacyAPI(&countToken, __FUNCTION__); \
        try {
 #define END_SECAPI }\
        catch (const MacOSError &err) { __secapiresult=err.osStatus(); } \
@@ -73,6 +79,8 @@ using namespace KeychainCore;
 //
 #define BEGIN_SECKCITEMAPI \
        OSStatus __secapiresult=errSecSuccess; \
+       static dispatch_once_t countToken; \
+       countLegacyAPI(&countToken, __FUNCTION__); \
        SecKeychainItemRef __itemImplRef=NULL; \
        bool __is_certificate=(itemRef && (CFGetTypeID(itemRef) == SecCertificateGetTypeID())); \
        if (__is_certificate) { \
@@ -108,6 +116,8 @@ using namespace KeychainCore;
 //
 #define BEGIN_SECCERTAPI \
        OSStatus __secapiresult=errSecSuccess; \
+       static dispatch_once_t countToken; \
+       countLegacyAPI(&countToken, __FUNCTION__); \
        SecCertificateRef __itemImplRef=NULL; \
        if (SecCertificateIsItemImplInstance(certificate)) { __itemImplRef=(SecCertificateRef)CFRetain(certificate); } \
        if (!__itemImplRef && certificate) { __itemImplRef=(SecCertificateRef)SecCertificateCopyKeychainItem(certificate); } \
index ca154314f95f560b729adeab1b4a1ee4eb431486..720861128194d23ce75b84c51c5b0bfb0da51779 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/param.h>
 #include <syslog.h>
 #include "CertificateValues.h"
+#include "LegacyAPICounts.h"
 
 OSStatus SecCertificateGetCLHandle_legacy(SecCertificateRef certificate, CSSM_CL_HANDLE *clHandle);
 extern CSSM_KEYUSE ConvertArrayToKeyUsage(CFArrayRef usage);
@@ -72,13 +73,6 @@ SecCertificateIsItemImplInstance(SecCertificateRef certificate)
 
     CFTypeID typeID = CFGetTypeID(certificate);
 
-#if 0 /* debug code to verify type IDs */
-       syslog(LOG_ERR, "SecCertificate typeID=%d [STU=%d, OSX=%d, SKI=%d]",
-                       (int)typeID,
-                       (int)SecCertificateGetTypeID(),
-                       (int)SecCertificateGetTypeID_osx(),
-                       (int)SecKeychainItemGetTypeID());
-#endif
        if (typeID == _kCFRuntimeNotATypeID) {
                return false;
        }
@@ -622,12 +616,14 @@ SecCertificateCopyPreference(
     FourCharCode itemType = 'cprf';
     cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    if (keyUsage)
+    if (keyUsage) {
         cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
+    }
 
-       Item prefItem;
-       if (!cursor->next(prefItem))
-               MacOSError::throwMe(errSecItemNotFound);
+    Item prefItem;
+    if (!cursor->next(prefItem)) {
+        MacOSError::throwMe(errSecItemNotFound);
+    }
 
        // get persistent certificate reference
        SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
@@ -707,8 +703,9 @@ SecCertificateFindPreferenceItemWithNameAndKeyUsage(
     CssmData service(const_cast<char *>(idUTF8), idUTF8Len);
     cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'cprf');
-    if (keyUsage)
+    if (keyUsage) {
         cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
+    }
 
        Item item;
        if (!cursor->next(item))
@@ -814,12 +811,11 @@ OSStatus SecCertificateSetPreference(
     FourCharCode itemType = 'cprf';
     cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    if (keyUsage)
+    if (keyUsage) {
         cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
-    if (date)
-        ; // %%%TBI
+    }
 
-       Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
+    Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
     bool add = (!cursor->next(item));
        // at this point, we either have a new item to add or an existing item to update
 
@@ -830,10 +826,6 @@ OSStatus SecCertificateSetPreference(
     item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
     item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
 
-    // date
-    if (date)
-        ; // %%%TBI
-
        // generic attribute (store persistent certificate reference)
        CFDataRef pItemRef = nil;
        Certificate::required(__itemImplRef)->copyPersistentReference(pItemRef);
@@ -876,6 +868,7 @@ OSStatus SecCertificateSetPreferred(
        CFStringRef name,
        CFArrayRef keyUsage)
 {
+       COUNTLEGACYAPI
        CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage);
        return SecCertificateSetPreference(certificate, name, keyUse, NULL);
 }
diff --git a/OSX/libsecurity_keychain/lib/SecCertificateBundle.cpp b/OSX/libsecurity_keychain/lib/SecCertificateBundle.cpp
deleted file mode 100644 (file)
index 5e60033..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2002-2004,2011,2013-2014 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 <Security/SecCertificateBundle.h>
-
-#include "SecBridge.h"
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-// misspelled function name is declared here so symbol won't be stripped
-OSStatus SecCertifcateBundleExport(
-        CFArrayRef itemList,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CSSM_DATA* data);
-#if defined(__cplusplus)
-}
-#endif
-
-
-OSStatus
-SecCertificateBundleImport(
-        SecKeychainRef keychain,
-        const CSSM_CERT_BUNDLE* bundle,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CFArrayRef keychainListToSkipDuplicates)
-{
-    BEGIN_SECAPI
-
-       MacOSError::throwMe(errSecUnimplemented);//%%%for now
-
-    END_SECAPI
-}
-
-
-OSStatus
-SecCertificateBundleExport(
-        CFArrayRef certificates,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CSSM_DATA* data)
-{
-    BEGIN_SECAPI
-
-       MacOSError::throwMe(errSecUnimplemented);//%%%for now
-
-    END_SECAPI
-}
-
-// note: misspelled function name is still exported as a precaution;
-// can remove this after deprecation
-OSStatus
-SecCertifcateBundleExport(
-        CFArrayRef itemList,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CSSM_DATA* data)
-{
-       return SecCertificateBundleExport(itemList, type, encodingType, data);
-}
diff --git a/OSX/libsecurity_keychain/lib/SecCertificateBundle.h b/OSX/libsecurity_keychain/lib/SecCertificateBundle.h
deleted file mode 100644 (file)
index a20f1bc..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2002-2004,2011,2014 Apple Inc. All Rights Reserved.
- * 
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*!
-       @header SecCertificateBundle
-       The functions provided in SecCertificateBundle implement a way to issue a certificate request to a
-       certificate authority.
-*/
-
-#ifndef _SECURITY_SECCERTIFICATEBUNDLE_H_
-#define _SECURITY_SECCERTIFICATEBUNDLE_H_
-
-#include <Security/SecBase.h>
-#include <Security/cssmtype.h>
-#include <CoreFoundation/CFArray.h>
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-/*!
-       @function SecCertificateBundleImport
-       @abstract Imports one or more certificates into a keychain with the specified encoding and bundle type.
-    @param keychain The destination keychain for the import. Specify NULL for the default keychain.
-    @param bundle A pointer to the bundle data.
-    @param type The bundle type as defined in cssmtype.h.
-    @param encodingType The bundle encoding type as defined in cssmtype.h.
-    @param keychainListToSkipDuplicates A reference to an array of keychains.  These keychains contain certificates that shouldn't be duplicated during the import.    
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-*/
-OSStatus SecCertificateBundleImport(
-        SecKeychainRef keychain,
-        const CSSM_CERT_BUNDLE* bundle,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CFArrayRef keychainListToSkipDuplicates) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
-        
-/*!
-       @function SecCertificateBundleExport
-       @abstract Exports one or more certificates into a bundle with the specified encoding and bundle type.
-    @param certificates An array of certificate and keychain items used to help build the bundle.
-    @param type The bundle type as defined in cssmtype.h. If the bundle type is unknown, an attempt will be made to determine the type for you.
-    @param encodingType The encoding type as defined in cssmtype.h.
-    @param data A pointer to data.  On return, this points to the bundle data.
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-*/
-OSStatus SecCertificateBundleExport(
-        CFArrayRef certificates,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CSSM_DATA* data) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
-
-/* misspelled version of above */
-OSStatus SecCertifcateBundleExport(
-        CFArrayRef itemList,
-        CSSM_CERT_BUNDLE_TYPE type,
-        CSSM_CERT_BUNDLE_ENCODING encodingType,
-        CSSM_DATA* data) DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif /* !_SECURITY_SECCERTIFICATEBUNDLE_H_ */
index 6473cf159a5623e58eabab232913c0112d6e541b..da93a08a73e6e4d0747320741d76f21c17ce7436 100644 (file)
@@ -33,6 +33,7 @@
 #include <Security/SecIdentityPriv.h>
 #include <Security/SecItem.h>
 #include <Security/SecBase.h>
+#include <security_utilities/simulatecrash_assert.h>
 using namespace Security;
 using namespace KeychainCore;
 
index 5d21959bc243ca61b3488e330d91e9f1fb0974f6..533ecabf81a02351a1ab771248a690e856e70822 100644 (file)
@@ -39,6 +39,7 @@
 #include <sys/param.h>
 #include <syslog.h>
 #include <os/activity.h>
+#include "LegacyAPICounts.h"
 
 /* private function declarations */
 OSStatus
@@ -216,6 +217,7 @@ SecIdentityCreate(
        SecCertificateRef certificate,
        SecKeyRef privateKey)
 {
+       COUNTLEGACYAPI
        SecIdentityRef identityRef = NULL;
        OSStatus __secapiresult;
        SecCertificateRef __itemImplRef = NULL;
@@ -244,38 +246,6 @@ SecIdentityCreate(
        return identityRef;
 }
 
-CFComparisonResult
-SecIdentityCompare(
-       SecIdentityRef identity1,
-       SecIdentityRef identity2,
-       CFOptionFlags compareOptions)
-{
-       if (!identity1 || !identity2)
-       {
-               if (identity1 == identity2)
-                       return kCFCompareEqualTo;
-               else if (identity1 < identity2)
-                       return kCFCompareLessThan;
-               else
-                       return kCFCompareGreaterThan;
-       }
-
-    try {
-        SecPointer<Identity> id1(Identity::required(identity1));
-        SecPointer<Identity> id2(Identity::required(identity2));
-
-        if (id1 == id2)
-            return kCFCompareEqualTo;
-        else if (id1 < id2)
-            return kCFCompareLessThan;
-        else
-            return kCFCompareGreaterThan;
-    } catch(...)
-    {}
-
-    return kCFCompareGreaterThan;
-}
-
 static
 CFArrayRef _SecIdentityCopyPossiblePaths(
     CFStringRef name)
@@ -401,8 +371,9 @@ OSStatus _SecIdentityCopyPreferenceMatchingName(
        FourCharCode itemType = 'iprf';
     cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), itemType);
-    if (keyUsage)
+    if (keyUsage) {
         cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
+    }
 
        Item prefItem;
        if (!cursor->next(prefItem))
@@ -681,50 +652,11 @@ OSStatus SecIdentitySetPreference(
 OSStatus
 SecIdentitySetPreferred(SecIdentityRef identity, CFStringRef name, CFArrayRef keyUsage)
 {
+       COUNTLEGACYAPI
        CSSM_KEYUSE keyUse = ConvertArrayToKeyUsage(keyUsage);
        return SecIdentitySetPreference(identity, name, keyUse);
 }
 
-OSStatus
-SecIdentityFindPreferenceItem(
-       CFTypeRef keychainOrArray,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecIdentityFindPreferenceItem", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList(keychainOrArray, keychains);
-       KCCursor cursor(keychains, kSecGenericPasswordItemClass, NULL);
-
-       char idUTF8[MAXPATHLEN];
-    idUTF8[0] = (char)'\0';
-       if (idString)
-       {
-               if (!CFStringGetCString(idString, idUTF8, sizeof(idUTF8)-1, kCFStringEncodingUTF8))
-                       idUTF8[0] = (char)'\0';
-       }
-    size_t idUTF8Len = strlen(idUTF8);
-    if (!idUTF8Len)
-        MacOSError::throwMe(errSecParam);
-
-    CssmData service(const_cast<char *>(idUTF8), idUTF8Len);
-    cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
-       cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-
-       Item item;
-       if (!cursor->next(item))
-               MacOSError::throwMe(errSecItemNotFound);
-
-       if (itemRef)
-               *itemRef=item->handle();
-
-    END_SECAPI
-}
-
 OSStatus
 SecIdentityFindPreferenceItemWithNameAndKeyUsage(
        CFTypeRef keychainOrArray,
@@ -755,8 +687,9 @@ SecIdentityFindPreferenceItemWithNameAndKeyUsage(
     CssmData service(const_cast<char *>(idUTF8), idUTF8Len);
     cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecServiceItemAttr), service);
        cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-    if (keyUsage)
+    if (keyUsage) {
         cursor->add(CSSM_DB_EQUAL, Schema::attributeInfo(kSecScriptCodeItemAttr), (sint32)keyUsage);
+    }
 
        Item item;
        if (!cursor->next(item))
@@ -773,6 +706,7 @@ OSStatus SecIdentityDeletePreferenceItemWithNameAndKeyUsage(
        CFStringRef name,
        int32_t keyUsage)
 {
+       COUNTLEGACYAPI
        // when a specific key usage is passed, we'll only match & delete that pref;
        // when a key usage of 0 is passed, all matching prefs should be deleted.
        // maxUsages represents the most matches there could theoretically be, so
@@ -793,295 +727,6 @@ OSStatus SecIdentityDeletePreferenceItemWithNameAndKeyUsage(
        return (status == errSecItemNotFound) ? errSecSuccess : status;
 }
 
-
-static
-OSStatus _SecIdentityAddPreferenceItemWithName(
-       SecKeychainRef keychainRef,
-       SecIdentityRef identityRef,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    // this is NOT exported, and called only from SecIdentityAddPreferenceItem (below), so no BEGIN/END macros here;
-    // caller must handle exceptions
-
-       if (!identityRef || !idString)
-               return errSecParam;
-       SecPointer<Certificate> cert(Identity::required(identityRef)->certificate());
-       Item item(kSecGenericPasswordItemClass, 'aapl', 0, NULL, false);
-       sint32 keyUsage = 0;
-
-       // determine the account attribute
-       //
-       // This attribute must be synthesized from certificate label + pref item type + key usage,
-       // as only the account and service attributes can make a generic keychain item unique.
-       // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
-       // we can save a certificate preference if an identity preference already exists for the
-       // given service name, and vice-versa.
-       // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
-       //
-    CFStringRef labelStr = nil;
-       cert->inferLabel(false, &labelStr);
-       if (!labelStr) {
-        return errSecDataTooLarge; // data is "in a format which cannot be displayed"
-       }
-       CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1;
-       const char *templateStr = "%s [key usage 0x%X]";
-       const int keyUsageMaxStrLen = 8;
-       accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen;
-       char *accountUTF8 = (char *)malloc(accountUTF8Len);
-       if (!accountUTF8) {
-               MacOSError::throwMe(errSecMemoryError);
-       }
-    if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8))
-               accountUTF8[0] = (char)'\0';
-       if (keyUsage)
-               snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage);
-       snprintf(accountUTF8, accountUTF8Len-1, "%s ", accountUTF8);
-    CssmDataContainer account(const_cast<char *>(accountUTF8), strlen(accountUTF8));
-    free(accountUTF8);
-    CFRelease(labelStr);
-
-       // service attribute (name provided by the caller)
-       CFIndex serviceUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(idString), kCFStringEncodingUTF8) + 1;;
-       char *serviceUTF8 = (char *)malloc(serviceUTF8Len);
-       if (!serviceUTF8) {
-               MacOSError::throwMe(errSecMemoryError);
-       }
-    if (!CFStringGetCString(idString, serviceUTF8, serviceUTF8Len-1, kCFStringEncodingUTF8))
-        serviceUTF8[0] = (char)'\0';
-    CssmDataContainer service(const_cast<char *>(serviceUTF8), strlen(serviceUTF8));
-    free(serviceUTF8);
-
-       // set item attribute values
-       item->setAttribute(Schema::attributeInfo(kSecServiceItemAttr), service);
-       item->setAttribute(Schema::attributeInfo(kSecLabelItemAttr), service);
-       item->setAttribute(Schema::attributeInfo(kSecTypeItemAttr), (FourCharCode)'iprf');
-       item->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
-       item->setAttribute(Schema::attributeInfo(kSecScriptCodeItemAttr), keyUsage);
-
-       // generic attribute (store persistent certificate reference)
-       CFDataRef pItemRef = nil;
-       OSStatus status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)cert->handle(), &pItemRef);
-       if (!pItemRef)
-               status = errSecInvalidItemRef;
-       if (status)
-                return status;
-       const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef);
-       CFIndex dataLen = CFDataGetLength(pItemRef);
-       CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen);
-       item->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref);
-       CFRelease(pItemRef);
-
-       Keychain keychain = nil;
-       try {
-        keychain = Keychain::optional(keychainRef);
-        if (!keychain->exists())
-            MacOSError::throwMe(errSecNoSuchKeychain); // Might be deleted or not available at this time.
-    }
-    catch(...) {
-        keychain = globals().storageManager.defaultKeychainUI(item);
-    }
-
-       try {
-               keychain->add(item);
-       }
-       catch (const MacOSError &err) {
-               if (err.osStatus() != errSecDuplicateItem)
-                       throw; // if item already exists, fall through to update
-       }
-
-       item->update();
-
-    if (itemRef)
-               *itemRef = item->handle();
-
-    return status;
-}
-
-OSStatus SecIdentityAddPreferenceItem(
-       SecKeychainRef keychainRef,
-       SecIdentityRef identityRef,
-       CFStringRef idString,
-       SecKeychainItemRef *itemRef)
-{
-    // The original implementation of SecIdentityAddPreferenceItem adds the exact string only.
-    // That implementation has been moved to _SecIdentityAddPreferenceItemWithName (above),
-    // and this function is a wrapper which calls it, so that existing clients will get the
-    // extended behavior of server domain matching for items that specify URLs.
-    // (Note that behavior is unchanged if the specified idString is not a URL.)
-
-    BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecIdentityAddPreferenceItem", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-    OSStatus status = errSecInternalComponent;
-    CFArrayRef names = _SecIdentityCopyPossiblePaths(idString);
-    if (!names) {
-        return status;
-    }
-
-    CFIndex total = CFArrayGetCount(names);
-    if (total > 0) {
-        // add item for name (first element in array)
-        CFStringRef aName = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
-        try {
-            status = _SecIdentityAddPreferenceItemWithName(keychainRef, identityRef, aName, itemRef);
-        }
-        catch (const MacOSError &err)   { status=err.osStatus(); }
-        catch (const CommonError &err)  { status=SecKeychainErrFromOSStatus(err.osStatus()); }
-        catch (const std::bad_alloc &)  { status=errSecAllocate; }
-        catch (...)                     { status=errSecInternalComponent; }
-    }
-    if (total > 2) {
-               Boolean setDomainDefaultIdentity = FALSE;
-               CFTypeRef val = (CFTypeRef)CFPreferencesCopyValue(CFSTR("SetDomainDefaultIdentity"),
-                                                                                                                 CFSTR("com.apple.security.identities"),
-                                                                                                                 kCFPreferencesCurrentUser,
-                                                                                                                 kCFPreferencesAnyHost);
-               if (val) {
-                       if (CFGetTypeID(val) == CFBooleanGetTypeID())
-                               setDomainDefaultIdentity = CFBooleanGetValue((CFBooleanRef)val) ? TRUE : FALSE;
-                       CFRelease(val);
-               }
-               if (setDomainDefaultIdentity) {
-                       // add item for domain (second-to-last element in array, e.g. "*.apple.com")
-                       OSStatus tmpStatus = errSecSuccess;
-                       CFStringRef aName = (CFStringRef)CFArrayGetValueAtIndex(names, total-2);
-                       try {
-                               tmpStatus = _SecIdentityAddPreferenceItemWithName(keychainRef, identityRef, aName, itemRef);
-                       }
-                       catch (const MacOSError &err)   { tmpStatus=err.osStatus(); }
-                       catch (const CommonError &err)  { tmpStatus=SecKeychainErrFromOSStatus(err.osStatus()); }
-                       catch (const std::bad_alloc &)  { tmpStatus=errSecAllocate; }
-                       catch (...)                     { tmpStatus=errSecInternalComponent; }
-               }
-    }
-
-    CFRelease(names);
-    return status;
-
-    END_SECAPI
-}
-
-/* deprecated in 10.5 */
-OSStatus SecIdentityUpdatePreferenceItem(
-                       SecKeychainItemRef itemRef,
-                       SecIdentityRef identityRef)
-{
-    BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecIdentityUpdatePreferenceItem", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-       if (!itemRef || !identityRef)
-               MacOSError::throwMe(errSecParam);
-       SecPointer<Certificate> certificate(Identity::required(identityRef)->certificate());
-       Item prefItem = ItemImpl::required(itemRef);
-
-       // get the current key usage value for this item
-       sint32 keyUsage = 0;
-       UInt32 actLen = 0;
-       SecKeychainAttribute attr = { kSecScriptCodeItemAttr, sizeof(sint32), &keyUsage };
-       try {
-               prefItem->getAttribute(attr, &actLen);
-       }
-       catch(...) {
-               keyUsage = 0;
-       };
-
-       // set the account attribute
-       //
-       // This attribute must be synthesized from certificate label + pref item type + key usage,
-       // as only the account and service attributes can make a generic keychain item unique.
-       // For 'iprf' type items (but not 'cprf'), we append a trailing space. This insures that
-       // we can save a certificate preference if an identity preference already exists for the
-       // given service name, and vice-versa.
-       // If the key usage is 0 (i.e. the normal case), we omit the appended key usage string.
-       //
-    CFStringRef labelStr = nil;
-       certificate->inferLabel(false, &labelStr);
-       if (!labelStr) {
-        MacOSError::throwMe(errSecDataTooLarge); // data is "in a format which cannot be displayed"
-       }
-       CFIndex accountUTF8Len = CFStringGetMaximumSizeForEncoding(CFStringGetLength(labelStr), kCFStringEncodingUTF8) + 1;
-       const char *templateStr = "%s [key usage 0x%X]";
-       const int keyUsageMaxStrLen = 8;
-       accountUTF8Len += strlen(templateStr) + keyUsageMaxStrLen;
-       char *accountUTF8 = (char *)malloc(accountUTF8Len);
-       if (!accountUTF8) {
-               MacOSError::throwMe(errSecMemoryError);
-       }
-       if (!CFStringGetCString(labelStr, accountUTF8, accountUTF8Len-1, kCFStringEncodingUTF8))
-               accountUTF8[0] = (char)'\0';
-       if (keyUsage)
-               snprintf(accountUTF8, accountUTF8Len-1, templateStr, accountUTF8, keyUsage);
-       snprintf(accountUTF8, accountUTF8Len-1, "%s ", accountUTF8);
-       CssmDataContainer account(const_cast<char *>(accountUTF8), strlen(accountUTF8));
-       prefItem->setAttribute(Schema::attributeInfo(kSecAccountItemAttr), account);
-       free(accountUTF8);
-       CFRelease(labelStr);
-
-       // generic attribute (store persistent certificate reference)
-       CFDataRef pItemRef = nil;
-       OSStatus status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)certificate->handle(), &pItemRef);
-       if (!pItemRef)
-               status = errSecInvalidItemRef;
-       if (status)
-               MacOSError::throwMe(status);
-       const UInt8 *dataPtr = CFDataGetBytePtr(pItemRef);
-       CFIndex dataLen = CFDataGetLength(pItemRef);
-       CssmData pref(const_cast<void *>(reinterpret_cast<const void *>(dataPtr)), dataLen);
-       prefItem->setAttribute(Schema::attributeInfo(kSecGenericItemAttr), pref);
-       CFRelease(pItemRef);
-
-       prefItem->update();
-
-    END_SECAPI
-}
-
-OSStatus SecIdentityCopyFromPreferenceItem(
-                       SecKeychainItemRef itemRef,
-                       SecIdentityRef *identityRef)
-{
-    BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecIdentityCopyFromPreferenceItem", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-       if (!itemRef || !identityRef)
-               MacOSError::throwMe(errSecParam);
-       Item prefItem = ItemImpl::required(itemRef);
-
-       // get persistent certificate reference
-       SecKeychainAttribute itemAttrs[] = { { kSecGenericItemAttr, 0, NULL } };
-       SecKeychainAttributeList itemAttrList = { sizeof(itemAttrs) / sizeof(itemAttrs[0]), itemAttrs };
-       prefItem->getContent(NULL, &itemAttrList, NULL, NULL);
-
-       // find certificate, given persistent reference data
-       CFDataRef pItemRef = CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)itemAttrs[0].data, itemAttrs[0].length, kCFAllocatorNull);
-       SecKeychainItemRef certItemRef = nil;
-       OSStatus status = SecKeychainItemCopyFromPersistentReference(pItemRef, &certItemRef); //%%% need to make this a method of ItemImpl
-       prefItem->freeContent(&itemAttrList, NULL);
-       if (pItemRef)
-               CFRelease(pItemRef);
-       if (status)
-               return status;
-
-       // create identity reference, given certificate
-       StorageManager::KeychainList keychains;
-       globals().storageManager.optionalSearchList((CFTypeRef)NULL, keychains);
-       Item certItem = ItemImpl::required(SecKeychainItemRef(certItemRef));
-       SecPointer<Certificate> certificate(static_cast<Certificate *>(certItem.get()));
-       SecPointer<Identity> identity(new Identity(keychains, certificate));
-       if (certItemRef)
-               CFRelease(certItemRef);
-
-       Required(identityRef) = identity->handle();
-
-    END_SECAPI
-}
-
 /*
  * System Identity Support.
  */
@@ -1114,7 +759,7 @@ OSStatus SecIdentityCopySystemIdentity(
     os_release(activity);
 
        StLock<Mutex> _(systemIdentityLock());
-       auto_ptr<Dictionary> identDict;
+       unique_ptr<Dictionary> identDict;
 
        /* get top-level dictionary - if not present, we're done */
        Dictionary* d = Dictionary::CreateDictionary(IDENTITY_DOMAIN, Dictionary::US_System);
@@ -1189,7 +834,7 @@ OSStatus SecIdentitySetSystemIdentity(
                MacOSError::throwMe(errSecAuthFailed);
        }
 
-       auto_ptr<MutableDictionary> identDict;
+       unique_ptr<MutableDictionary> identDict;
        MutableDictionary *d = MutableDictionary::CreateMutableDictionary(IDENTITY_DOMAIN, Dictionary::US_System);
        if (d)
        {
index b3f58d608823b194924f1cfb1ec77e2fc8176706..d91069cc1a6a11cbd2ef0ded96e5653e922d6bd0 100644 (file)
@@ -29,7 +29,7 @@
 #include <os/activity.h>
 
 #include "SecBridge.h"
-
+#include "LegacyAPICounts.h"
 
 CFTypeID
 SecIdentitySearchGetTypeID(void)
index df6755649cf383f691b050c62b20a4527f64f76c..3a4fb9a05f0d580103a8f4e2b70777f754afc0a4 100644 (file)
@@ -32,6 +32,8 @@
 #include <string.h>
 #include <ctype.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 /* 
  * Text parsing routines. 
  *
index 165d567c3bacb6eff8d713afc72b93f0ae854efe..f0b988f4c1c6358214ec2427eecad738eb1d347b 100644 (file)
@@ -53,7 +53,7 @@
 #include <Security/SecKeyPriv.h>
 #include <security_cdsa_utils/cuCdsaUtils.h>
 #include <openssl/pem.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <Security/SecBase.h>
 
 #define SecPkcs8Dbg(args...)   secinfo("SecPkcs8", ## args)
index 2cdb17f942f5d256d6dc24c426f987c6dfa1d390..e5b078ad01aa9b189fd1ccc28b3dba9e469d732f 100644 (file)
@@ -42,6 +42,7 @@
 #include <Security/SecTrustPriv.h>
 #include "utilities/array_size.h"
 #include "utilities/SecCFWrappers.h"
+#include "LegacyAPICounts.h"
 
 #include <AssertMacros.h>
 #include <syslog.h>
@@ -71,8 +72,6 @@ OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result);
 OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result);
 OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
 OSStatus SecItemDelete_ios(CFDictionaryRef query);
-OSStatus SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes);
-
 
 OSStatus SecItemValidateAppleApplicationGroupAccess(CFStringRef group);
 CFDictionaryRef SecItemCopyTranslatedAttributes(CFDictionaryRef inOSXDict, CFTypeRef itemClass,
@@ -3827,6 +3826,8 @@ AddItemResults(SecKeychainItemRef item,
        //
        // Note that we allocate *items if needed.
 
+       CFTypeRef localResult = NULL;
+
        if (!item || !itemParams || !result)
                return errSecParam;
 
@@ -3855,7 +3856,8 @@ AddItemResults(SecKeychainItemRef item,
                        CFArrayAppendValue(itemArray, itemRef);
                }
                else {
-                       *result = CFRetain((CFTypeRef)itemRef);
+                       CFReleaseNull(localResult);
+                       localResult = CFRetain((CFTypeRef)itemRef);
                }
        }
 
@@ -3874,7 +3876,8 @@ AddItemResults(SecKeychainItemRef item,
                                CFArrayAppendValue(itemArray, persistentRef);
                        }
                        else {
-                               *result = CFRetain(persistentRef);
+                               CFReleaseNull(localResult);
+                               localResult = CFRetain(persistentRef);
                        }
                        CFRelease(persistentRef);
                }
@@ -3898,7 +3901,8 @@ AddItemResults(SecKeychainItemRef item,
                                        CFArrayAppendValue(itemArray, dataRef);
                                }
                                else {
-                                       *result = CFRetain(dataRef);
+                                       CFReleaseNull(localResult);
+                                       localResult = CFRetain(dataRef);
                                }
                                CFRelease(dataRef);
                                status = errSecSuccess;
@@ -3920,7 +3924,8 @@ AddItemResults(SecKeychainItemRef item,
                                        CFArrayAppendValue(itemArray, dataRef);
                                }
                                else {
-                                       *result = CFRetain(dataRef);
+                                       CFReleaseNull(localResult);
+                                       localResult = CFRetain(dataRef);
                                }
                                CFRelease(dataRef);
                                (void) SecKeychainItemFreeContent(NULL, data);
@@ -3949,7 +3954,8 @@ AddItemResults(SecKeychainItemRef item,
                                CFArrayAppendValue(itemArray, attrsDict);
                        }
                        else {
-                               *result = CFRetain(attrsDict);
+                               CFReleaseNull(localResult);
+                               localResult = CFRetain(attrsDict);
                        }
                        CFRelease(attrsDict);
                }
@@ -3962,14 +3968,22 @@ AddItemResults(SecKeychainItemRef item,
                if (itemArray) {
                        CFArrayAppendValue(itemArray, itemDict);
                        CFRelease(itemDict);
-                       *result = itemArray;
+                       CFReleaseNull(localResult);
+                       localResult = itemArray;
                }
                else {
-                       *result = itemDict;
+                       CFReleaseNull(localResult);
+                       localResult = itemDict;
                }
        }
        else if (itemArray) {
-               *result = itemArray;
+               CFReleaseNull(localResult);
+               localResult = itemArray;
+       }
+
+       if (localResult) {
+               *result = localResult;
+               localResult = NULL;
        }
 
        return status;
@@ -5082,14 +5096,6 @@ SecItemDelete(CFDictionaryRef query)
        return status;
 }
 
-OSStatus
-SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
-{
-       OSStatus status = SecItemUpdateTokenItems_ios(tokenID, tokenItemsAttributes);
-       secitemlog(LOG_NOTICE, "SecItemUpdateTokenItems_ios result: %d", status);
-       return status;
-}
-
 OSStatus
 SecItemCopyMatching_osx(
        CFDictionaryRef query,
@@ -5100,6 +5106,8 @@ SecItemCopyMatching_osx(
        else
                *result = NULL;
 
+    setCountLegacyAPIEnabledForThread(false);
+
        CFAllocatorRef allocator = CFGetAllocator(query);
        CFIndex matchCount = 0;
        CFMutableArrayRef itemArray = NULL;
@@ -5144,20 +5152,9 @@ error_exit:
        }
        _FreeSecItemParams(itemParams);
 
-       return status;
-}
+    setCountLegacyAPIEnabledForThread(true);
 
-OSStatus
-SecItemCopyDisplayNames(
-       CFArrayRef items,
-       CFArrayRef *displayNames)
-{
-    BEGIN_SECAPI
-       Required(items);
-       Required(displayNames);
-    //%%%TBI
-    return errSecUnimplemented;
-    END_SECAPI
+       return status;
 }
 
 OSStatus
@@ -5170,6 +5167,8 @@ SecItemAdd_osx(
        else if (result)
                *result = NULL;
 
+    setCountLegacyAPIEnabledForThread(false);
+
        CFAllocatorRef allocator = CFGetAllocator(attributes);
        CFMutableArrayRef itemArray = NULL;
        SecKeychainItemRef item = NULL;
@@ -5303,6 +5302,7 @@ error_exit:
                *result = NULL;
        }
        _FreeSecItemParams(itemParams);
+    setCountLegacyAPIEnabledForThread(true);
 
        return status;
 }
@@ -5330,6 +5330,8 @@ SecItemUpdate_osx(
                CFRelease(results);
        }
 
+    setCountLegacyAPIEnabledForThread(false);
+
        OSStatus result = errSecSuccess;
        CFIndex ix, count = CFArrayGetCount(items);
        for (ix=0; ix < count; ix++) {
@@ -5340,6 +5342,8 @@ SecItemUpdate_osx(
                }
        }
 
+    setCountLegacyAPIEnabledForThread(true);
+
        if (items) {
                CFRelease(items);
        }
@@ -5368,6 +5372,8 @@ SecItemDelete_osx(
                CFRelease(results);
        }
 
+    setCountLegacyAPIEnabledForThread(false);
+
        OSStatus result = errSecSuccess;
        CFIndex ix, count = CFArrayGetCount(items);
        for (ix=0; ix < count; ix++) {
@@ -5383,6 +5389,8 @@ SecItemDelete_osx(
                }
        }
 
+    setCountLegacyAPIEnabledForThread(true);
+
        if (items)
                CFRelease(items);
 
index 4f56a5c745d9ecf666b2554e34b0cc46b59ac125..40552090ffc9ab744d8a42f6d5f28cb8d72c22f6 100644 (file)
@@ -126,6 +126,13 @@ SEC_CONST_DECL (kSecAttrRounds, "rounds");
 //SEC_CONST_DECL (kSecAttrPCSPlaintextPublicKey, "pcsk");
 //SEC_CONST_DECL (kSecAttrPCSPlaintextPublicIdentity, "pcsi");
 
+//SEC_CONST_DECL (kSecDataInetExtraNotes, "binn");
+//SEC_CONST_DECL (kSecDataInetExtraHistory, "bini");
+//SEC_CONST_DECL (kSecDataInetExtraClientDefined0, "bin0");
+//SEC_CONST_DECL (kSecDataInetExtraClientDefined1, "bin1");
+//SEC_CONST_DECL (kSecDataInetExtraClientDefined2, "bin2");
+//SEC_CONST_DECL (kSecDataInetExtraClientDefined3, "bin3");
+
 /* Predefined access groups constants */
 //SEC_CONST_DECL (kSecAttrAccessGroupToken, "com.apple.token");
 
index 7ef6027bf481f69692e8523c84ffde40384840ba..940caae2b85a5b5477e2b3edb50bf79a18ee52cc 100644 (file)
@@ -804,20 +804,19 @@ static Boolean SecCDSAKeySetParameter(SecKeyRef key, CFStringRef name, CFPropert
 const SecKeyDescriptor kSecCDSAKeyDescriptor = {
     .version = kSecKeyDescriptorVersion,
     .name = "CDSAKey",
+    .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
 
     .init = SecCDSAKeyInit,
     .destroy = SecCDSAKeyDestroy,
     .blockSize = SecCDSAKeyGetBlockSize,
-    .getAlgorithmID = SecCDSAKeyGetAlgorithmId,
     .copyDictionary = SecCDSAKeyCopyAttributeDictionary,
+    .getAlgorithmID = SecCDSAKeyGetAlgorithmId,
     .copyPublic = SecCDSAKeyCopyPublicBytes,
     .copyExternalRepresentation = SecCDSAKeyCopyExternalRepresentation,
     .copyPublicKey = SecCDSAKeyCopyPublicKey,
     .copyOperationResult = SecCDSAKeyCopyOperationResult,
     .isEqual = SecCDSAKeyIsEqual,
     .setParameter = SecCDSAKeySetParameter,
-
-    .extraBytes = (sizeof(class CDSASecKey) > sizeof(struct __SecKey) ? (sizeof(class CDSASecKey) - sizeof(struct __SecKey)) : 0),
 };
 
 namespace Security {
index 53265b9533aed869a39786f59d64c987f0cb81ac..ca80c80b0a322530139cbda1a3f5b8a3217718f2 100644 (file)
 #include <Security/AuthorizationTagsPriv.h>
 #include <Security/Authorization.h>
 #include "TokenLogin.h"
+#include "LegacyAPICounts.h"
+
+extern "C" {
+#include "ctkloginhelper.h"
+}
 
 OSStatus
 SecKeychainMDSInstall()
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainMDSInstall", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -68,6 +74,7 @@ SecKeychainGetTypeID(void)
 OSStatus
 SecKeychainGetVersion(UInt32 *returnVers)
 {
+    COUNTLEGACYAPI
     if (!returnVers)
                return errSecSuccess;
 
@@ -80,47 +87,23 @@ OSStatus
 SecKeychainOpen(const char *pathName, SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-       RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle();
-
-       END_SECAPI
-}
-
 
-OSStatus
-SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName,
-                                               const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain)
-{
-    BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainOpenWithGuid", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+          os_activity_t activity = os_activity_create("SecKeychainOpen", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
-       // range check parameters
-       RequiredParam (guid);
-       RequiredParam (dbName);
-       
-       // create a DLDbIdentifier that describes what should be opened
-    const CSSM_VERSION *version = NULL;
-    const CssmSubserviceUid ssuid(*guid, version, subserviceId, subserviceType);
-       DLDbIdentifier dLDbIdentifier(ssuid, dbName, dbLocation);
-       
-       // make a keychain from the supplied info
-       RequiredParam(keychain) = globals().storageManager.makeKeychain(dLDbIdentifier, false, false)->handle ();
+       RequiredParam(keychainRef)=globals().storageManager.make(pathName, false)->handle();
 
        END_SECAPI
 }
 
-
 OSStatus
 SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void *password,
        Boolean promptUser, SecAccessRef initialAccess, SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCreate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
     
@@ -147,7 +130,8 @@ OSStatus
 SecKeychainDelete(SecKeychainRef keychainOrArray)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -165,7 +149,8 @@ OSStatus
 SecKeychainSetSettings(SecKeychainRef keychainRef, const SecKeychainSettings *newSettings)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetSettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -185,7 +170,8 @@ OSStatus
 SecKeychainCopySettings(SecKeychainRef keychainRef, SecKeychainSettings *outSettings)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopySettings", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -208,7 +194,8 @@ OSStatus
 SecKeychainUnlock(SecKeychainRef keychainRef, UInt32 passwordLength, const void *password, Boolean usePassword)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainUnlock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -227,7 +214,8 @@ OSStatus
 SecKeychainLock(SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainLock", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -242,7 +230,8 @@ OSStatus
 SecKeychainLockAll(void)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainLockAll", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -255,7 +244,8 @@ SecKeychainLockAll(void)
 OSStatus SecKeychainResetLogin(UInt32 passwordLength, const void* password, Boolean resetSearchList)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainResetLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
         //
@@ -322,7 +312,8 @@ OSStatus
 SecKeychainSetDefault(SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -334,7 +325,8 @@ SecKeychainSetDefault(SecKeychainRef keychainRef)
 OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopySearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -350,7 +342,8 @@ OSStatus SecKeychainCopySearchList(CFArrayRef *searchList)
 OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -366,7 +359,8 @@ OSStatus SecKeychainSetSearchList(CFArrayRef searchList)
 OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRef *keychainRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopyDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -378,7 +372,8 @@ OSStatus SecKeychainCopyDomainDefault(SecPreferencesDomain domain, SecKeychainRe
 OSStatus SecKeychainSetDomainDefault(SecPreferencesDomain domain, SecKeychainRef keychainRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetDomainDefault", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -403,7 +398,8 @@ OSStatus SecKeychainCopyDomainSearchList(SecPreferencesDomain domain, CFArrayRef
 OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef searchList)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetDomainSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -419,7 +415,8 @@ OSStatus SecKeychainSetDomainSearchList(SecPreferencesDomain domain, CFArrayRef
 OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -431,7 +428,8 @@ OSStatus SecKeychainSetPreferenceDomain(SecPreferencesDomain domain)
 OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainGetPreferenceDomain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
        
@@ -478,7 +476,7 @@ SecKeychainGetKeychainVersion(SecKeychainRef keychainRef, UInt32* version)
 {
     BEGIN_SECAPI
 
-    RequiredParam(version);
+          RequiredParam(version);
 
     *version = Keychain::optional(keychainRef)->database()->dbBlobVersion();
 
@@ -489,7 +487,8 @@ OSStatus
 SecKeychainAttemptMigrationWithMasterKey(SecKeychainRef keychain, UInt32 version, const char* masterKeyFilename)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainAttemptMigrationWithMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -587,7 +586,8 @@ pascal OSStatus
 SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void* userContext)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainAddCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -602,7 +602,8 @@ OSStatus
 SecKeychainRemoveCallback(SecKeychainCallback callbackFunction)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainRemoveCallback", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -616,7 +617,8 @@ OSStatus
 SecKeychainAddInternetPassword(SecKeychainRef keychainRef, UInt32 serverNameLength, const char *serverName, UInt32 securityDomainLength, const char *securityDomain, UInt32 accountNameLength, const char *accountName, UInt32 pathLength, const char *path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainAddInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -678,7 +680,8 @@ SecKeychainFindInternetPassword(CFTypeRef keychainOrArray, UInt32 serverNameLeng
                                                                                                
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainFindInternetPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -757,7 +760,8 @@ OSStatus
 SecKeychainAddGenericPassword(SecKeychainRef keychainRef, UInt32 serviceNameLength, const char *serviceName, UInt32 accountNameLength, const char *accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef *itemRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainAddGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -806,7 +810,8 @@ SecKeychainFindGenericPassword(CFTypeRef keychainOrArray, UInt32 serviceNameLeng
                                                                                                                                                           
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainFindGenericPassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -878,7 +883,8 @@ OSStatus
 SecKeychainGetDLDBHandle(SecKeychainRef keychainRef, CSSM_DL_DB_HANDLE *dldbHandle)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainGetDLDBHandle", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -944,7 +950,8 @@ OSStatus
 SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword,  UInt32 newPasswordLength, const void *newPassword)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainChangePassword", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -959,7 +966,8 @@ OSStatus
 SecKeychainCopyLogin(SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopyLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -973,7 +981,8 @@ OSStatus
 SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, const void* password)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainLogin", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1009,7 +1018,8 @@ SecKeychainLogin(UInt32 nameLength, const void* name, UInt32 passwordLength, con
 OSStatus SecKeychainStash()
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainStash", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
     
@@ -1036,7 +1046,8 @@ OSStatus
 SecKeychainLogout()
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainLogout", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1059,7 +1070,8 @@ static Keychain make(const char *name)
 OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *keychainRef)
 {
     BEGIN_SECAPI
-        RequiredParam(fullPathName);
+
+       RequiredParam(fullPathName);
         RequiredParam(keychainRef)=make(fullPathName)->handle();
        END_SECAPI
 }
@@ -1070,7 +1082,8 @@ OSStatus SecKeychainMakeFromFullPath(const char *fullPathName, SecKeychainRef *k
 OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
 {
     BEGIN_SECAPI
-        *isValid = false;
+
+       *isValid = false;
         if (KeychainImpl::optional(keychainRef)->dlDbIdentifier().ssuid().guid() == gGuidAppleCSPDL)
             *isValid = true;
        END_SECAPI
@@ -1081,7 +1094,8 @@ OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
 OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainRemoveFromSearchList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
         StorageManager::KeychainList singleton;
@@ -1095,7 +1109,8 @@ OSStatus SecKeychainRemoveFromSearchList(SecKeychainRef keychainRef)
 OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength, const char* inPassword)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCreateNew", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
         RequiredParam(inPassword);
@@ -1108,7 +1123,8 @@ OSStatus SecKeychainCreateNew(SecKeychainRef keychainRef, UInt32 passwordLength,
 OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlobArray, CFDataRef extraData)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainRecodeKeychain", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1186,7 +1202,8 @@ OSStatus SecKeychainRecodeKeychain(SecKeychainRef keychainRef, CFArrayRef dbBlob
 OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychainSignature) 
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopySignature", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1213,7 +1230,8 @@ OSStatus SecKeychainCopySignature(SecKeychainRef keychainRef, CFDataRef *keychai
 OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCopyBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1235,7 +1253,8 @@ OSStatus SecKeychainCopyBlob(SecKeychainRef keychainRef, CFDataRef *dbBlob)
 OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, SecKeychainRef *kcRef)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainCreateWithBlob", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
        
@@ -1262,7 +1281,8 @@ OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char
                                                                                 const CSSM_GUID *guid, uint32 subServiceType)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainAddDBToKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1278,7 +1298,8 @@ OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char*
                                                                                const CSSM_GUID *guid, uint32 subServiceType)
 {
        BEGIN_SECAPI
-       RequiredParam(dbName);
+
+          RequiredParam(dbName);
        StorageManager &smr = globals().storageManager;
        smr.isInDomainList(domain, dbName, *guid, subServiceType);
        END_SECAPI
@@ -1289,7 +1310,8 @@ OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const
                                                                                          const CSSM_GUID *guid, uint32 subServiceType)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainRemoveDBFromKeychainList", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
        RequiredParam(dbName);
@@ -1310,7 +1332,8 @@ void SecKeychainSetServerMode()
 OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
 {
        BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainSetBatchMode", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
        RequiredParam(kcRef);
@@ -1324,13 +1347,15 @@ OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean ro
 OSStatus SecKeychainCleanupHandles()
 {
        BEGIN_SECAPI
-       END_SECAPI // which causes the handle cache cleanup routine to run
+
+          END_SECAPI // which causes the handle cache cleanup routine to run
 }
 
 OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainVerifyKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
     SecurityServer::ClientSession().verifyKeyStorePassphrase(retries);
@@ -1340,7 +1365,8 @@ OSStatus SecKeychainVerifyKeyStorePassphrase(uint32_t retries)
 OSStatus SecKeychainChangeKeyStorePassphrase()
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainChangeKeyStorePassphrase", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
     SecurityServer::ClientSession().changeKeyStorePassphrase();
@@ -1350,7 +1376,8 @@ OSStatus SecKeychainChangeKeyStorePassphrase()
 static OSStatus SecKeychainGetMasterKey(SecKeychainRef userKeychainRef, CFDataRef *masterKey, CFStringRef password)
 {
     BEGIN_SECAPI
-    os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
+
+          os_activity_t activity = os_activity_create("SecKeychainGetMasterKey", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
 
@@ -1468,6 +1495,7 @@ static bool _SASetAutologinPW(CFStringRef inAutologinPW)
 }
 
 OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRef systemKeychainRef, CFStringRef username, CFStringRef password) {
+       COUNTLEGACYAPI
     SecTrustedApplicationRef itemPath;
     SecAccessRef ourAccessRef = NULL;
     
@@ -1568,6 +1596,7 @@ OSStatus SecKeychainStoreUnlockKey(SecKeychainRef userKeychainRef, SecKeychainRe
 OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
 {
     BEGIN_SECAPI
+
     os_activity_t activity = os_activity_create("SecKeychainGetUserPromptAttempts", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
@@ -1582,6 +1611,7 @@ OSStatus SecKeychainGetUserPromptAttempts(uint32_t * attempts)
 OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringRef tokenID, CFDataRef wrapPubKeyHash,
                                                  SecKeychainRef userKeychain, CFStringRef password)
 {
+       COUNTLEGACYAPI
        CFRef<CFStringRef> pwd;
        OSStatus result;
 
@@ -1667,15 +1697,32 @@ OSStatus SecKeychainStoreUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash, CFStringR
        }
 
        secnotice("SecKeychain", "SecKeychainStoreUnlockKeyWithPubKeyHash result %d", (int) result);
+    
+    // create SC KEK
+    // this might fail if KC password is different from user's password
+    uid_t uid = geteuid();
+    if (!uid) {
+        uid = getuid();
+    }
+    struct passwd *passwd = getpwuid(uid);
+    if (passwd) {
+        CFRef<CFStringRef> username = CFStringCreateWithCString(kCFAllocatorDefault, passwd->pw_name, kCFStringEncodingUTF8);
+        OSStatus kekRes = TKAddSecureToken(username, pwd, tokenID, wrapPubKeyHash);
+        if (kekRes != noErr) {
+            secnotice("SecKeychain", "Failed to register SC token: %d", (int) kekRes); // do not fail because KC functionality be still OK
+        }
+    } else {
+        secnotice("SecKeychain", "Unable to get name for uid %d", uid);
+    }
        return result;
 }
 
 OSStatus SecKeychainEraseUnlockKeyWithPubKeyHash(CFDataRef pubKeyHash)
 {
+       COUNTLEGACYAPI
     OSStatus result = TokenLoginDeleteUnlockData(pubKeyHash);
     if (result != errSecSuccess) {
         secnotice("SecKeychain", "Failed to erase stored wrapped unlock key: %d", (int) result);
     }
     return result;
 }
-
index b832915420ea4c11ec250a1f6e38a2caf143f0cf..b95f2ec543487b356f9e4f73481360711dca8205 100644 (file)
@@ -250,14 +250,14 @@ typedef CF_OPTIONS(UInt32, SecKeychainEventMask)
        @field pid The id of the process that generated this event.
        @discussion The SecKeychainCallbackInfo type represents a structure that contains information about the keychain event for which your application is being notified. For information on how to write a keychain event callback function, see SecKeychainCallback.
 */
-struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) SecKeychainCallbackInfo
+struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst) SecKeychainCallbackInfo
 {
     UInt32                          version;
     SecKeychainItemRef __nonnull       item;
     SecKeychainRef __nonnull           keychain;
        pid_t                           pid;
 };
-typedef struct SecKeychainCallbackInfo SecKeychainCallbackInfo API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct SecKeychainCallbackInfo SecKeychainCallbackInfo API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainGetTypeID
@@ -297,7 +297,7 @@ OSStatus SecKeychainOpen(const char *pathName, SecKeychainRef * __nonnull CF_RET
     @param keychain On return, a pointer to a keychain reference. The memory that keychain occupies must be released by calling CFRelease when finished with it.
        @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if the keychain parameter is invalid (NULL).
 */
-OSStatus SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void * __nullable password, Boolean promptUser, SecAccessRef __nullable initialAccess, SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainCreate(const char *pathName, UInt32 passwordLength, const void * __nullable password, Boolean promptUser, SecAccessRef __nullable initialAccess, SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainDelete
@@ -305,7 +305,7 @@ OSStatus SecKeychainCreate(const char *pathName, UInt32 passwordLength, const vo
     @param keychainOrArray A single keychain reference or a reference to an array of keychains to delete. IMPORTANT: SecKeychainDelete does not dispose the memory occupied by keychain references; use the CFRelease function when you are completely finished with a keychain.
        @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecInvalidKeychain (-25295) may be returned if the keychain parameter is invalid (NULL).
 */
-OSStatus SecKeychainDelete(SecKeychainRef __nullable keychainOrArray) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainDelete(SecKeychainRef __nullable keychainOrArray) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainSetSettings
@@ -314,7 +314,7 @@ OSStatus SecKeychainDelete(SecKeychainRef __nullable keychainOrArray) API_UNAVAI
        @param newSettings A pointer to the new keychain settings.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainSetSettings(SecKeychainRef __nullable keychain, const SecKeychainSettings *newSettings) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainSetSettings(SecKeychainRef __nullable keychain, const SecKeychainSettings *newSettings) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainCopySettings
@@ -323,7 +323,7 @@ OSStatus SecKeychainSetSettings(SecKeychainRef __nullable keychain, const SecKey
     @param outSettings  A pointer to a keychain settings structure. Since this structure is versioned, you must preallocate it and fill in the version of the structure.
  @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainCopySettings(SecKeychainRef __nullable keychain, SecKeychainSettings *outSettings) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainCopySettings(SecKeychainRef __nullable keychain, SecKeychainSettings *outSettings) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainUnlock
@@ -335,7 +335,7 @@ OSStatus SecKeychainCopySettings(SecKeychainRef __nullable keychain, SecKeychain
        @result A result code.  See "Security Error Codes" (SecBase.h).
        @discussion In most cases, your application does not need to call the SecKeychainUnlock function directly, since most Keychain Manager functions that require an unlocked keychain call SecKeychainUnlock automatically. If your application needs to verify that a keychain is unlocked, call the function SecKeychainGetStatus.
 */
-OSStatus SecKeychainUnlock(SecKeychainRef __nullable keychain, UInt32 passwordLength, const void * __nullable password, Boolean usePassword) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainUnlock(SecKeychainRef __nullable keychain, UInt32 passwordLength, const void * __nullable password, Boolean usePassword) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainLock
@@ -343,14 +343,14 @@ OSStatus SecKeychainUnlock(SecKeychainRef __nullable keychain, UInt32 passwordLe
     @param keychain A reference to the keychain to lock.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainLock(SecKeychainRef        __nullable keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainLock(SecKeychainRef        __nullable keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainLockAll
        @abstract Locks all keychains belonging to the current user.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainLockAll(void) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainLockAll(void) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainCopyDefault
@@ -358,7 +358,7 @@ OSStatus SecKeychainLockAll(void) API_UNAVAILABLE(ios, watchos, tvos, bridgeos,
        @param keychain On return, a pointer to the default keychain reference.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainCopyDefault(SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainCopyDefault(SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainSetDefault
@@ -366,7 +366,7 @@ OSStatus SecKeychainCopyDefault(SecKeychainRef * __nonnull CF_RETURNS_RETAINED k
        @param keychain A reference to the keychain to set as default.
        @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if the keychain parameter is invalid (NULL).
 */
-OSStatus SecKeychainSetDefault(SecKeychainRef __nullable keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainSetDefault(SecKeychainRef __nullable keychain) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainCopySearchList
@@ -374,7 +374,7 @@ OSStatus SecKeychainSetDefault(SecKeychainRef __nullable keychain) API_UNAVAILAB
        @param searchList The returned list of keychains to search. When finished with the array, you must call CFRelease() to release the memory.
        @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if the keychain list is not specified (NULL).
 */
-OSStatus SecKeychainCopySearchList(CFArrayRef * __nonnull CF_RETURNS_RETAINED searchList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainCopySearchList(CFArrayRef * __nonnull CF_RETURNS_RETAINED searchList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainSetSearchList
@@ -382,7 +382,7 @@ OSStatus SecKeychainCopySearchList(CFArrayRef * __nonnull CF_RETURNS_RETAINED se
        @param searchList The list of keychains to use in a search list when the SecKeychainCopySearchList function is called. An empty array clears the search list.
        @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if the keychain list is not specified (NULL).
 */
-OSStatus SecKeychainSetSearchList(CFArrayRef searchList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainSetSearchList(CFArrayRef searchList) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*
@@ -411,7 +411,7 @@ OSStatus SecKeychainGetPreferenceDomain(SecPreferencesDomain *domain);
        @param keychainStatus On return, a pointer to the status of the specified keychain.  See KeychainStatus for valid status constants.
     @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainGetStatus(SecKeychainRef __nullable keychain, SecKeychainStatus *keychainStatus) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainGetStatus(SecKeychainRef __nullable keychain, SecKeychainStatus *keychainStatus) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainGetPath
@@ -421,7 +421,7 @@ OSStatus SecKeychainGetStatus(SecKeychainRef __nullable keychain, SecKeychainSta
        @param pathName On return, the POSIX path to the keychain.
     @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainGetPath(SecKeychainRef __nullable keychain, UInt32 *ioPathLength, char *pathName) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainGetPath(SecKeychainRef __nullable keychain, UInt32 *ioPathLength, char *pathName) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma mark ---- Keychain Item Attribute Information ----
 /*!
@@ -433,7 +433,7 @@ OSStatus SecKeychainGetPath(SecKeychainRef __nullable keychain, UInt32 *ioPathLe
     @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if not enough valid parameters were supplied (NULL).
        @discussion Warning, this call returns more attributes than are support by the old style Keychain API and passing them into older calls will yield an invalid attribute error. The recommended call to retrieve the attribute values is the SecKeychainItemCopyAttributesAndData function.
 */
-OSStatus SecKeychainAttributeInfoForItemID(SecKeychainRef __nullable keychain,  UInt32 itemID, SecKeychainAttributeInfo * __nullable * __nonnull info) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainAttributeInfoForItemID(SecKeychainRef __nullable keychain,  UInt32 itemID, SecKeychainAttributeInfo * __nullable * __nonnull info) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainFreeAttributeInfo
@@ -441,7 +441,7 @@ OSStatus SecKeychainAttributeInfoForItemID(SecKeychainRef __nullable keychain,
        @param info A pointer to the keychain attribute information to release.
     @result A result code.  See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if not enough valid parameters were supplied (NULL).
 */
-OSStatus SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma mark ---- Keychain Manager Callbacks ----
 
@@ -460,7 +460,7 @@ OSStatus SecKeychainFreeAttributeInfo(SecKeychainAttributeInfo *info) API_UNAVAI
 
        To add your callback function, use the SecKeychainAddCallback function.  To remove your callback function, use the SecKeychainRemoveCallback function.
 */
-typedef OSStatus (*SecKeychainCallback)(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void * __nullable context) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef OSStatus (*SecKeychainCallback)(SecKeychainEvent keychainEvent, SecKeychainCallbackInfo *info, void * __nullable context) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainAddCallback
@@ -470,7 +470,7 @@ typedef OSStatus (*SecKeychainCallback)(SecKeychainEvent keychainEvent, SecKeych
        @param userContext A pointer to application-defined storage that will be passed to your callback function. Your application can use this to associate any particular call of SecKeychainAddCallback with any particular call of your keychain event callback function.
     @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void * __nullable userContext) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychainEventMask eventMask, void * __nullable userContext) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainRemoveCallback
@@ -478,7 +478,7 @@ OSStatus SecKeychainAddCallback(SecKeychainCallback callbackFunction, SecKeychai
        @param callbackFunction The callback function pointer to remove
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma mark ---- High Level Keychain Manager Calls ----
 /*!
@@ -502,7 +502,7 @@ OSStatus SecKeychainRemoveCallback(SecKeychainCallback callbackFunction) API_UNA
        @result A result code.  See "Security Error Codes" (SecBase.h).
        @discussion The SecKeychainAddInternetPassword function adds a new Internet server password to the specified keychain. Required parameters to identify the password are serverName and accountName (you cannot pass NULL for both parameters). In addition, some protocols may require an optional securityDomain when authentication is requested. SecKeychainAddInternetPassword optionally returns a reference to the newly added item.
 */
-OSStatus SecKeychainAddInternetPassword(SecKeychainRef __nullable keychain, UInt32 serverNameLength, const char * __nullable serverName, UInt32 securityDomainLength, const char * __nullable securityDomain, UInt32 accountNameLength, const char * __nullable accountName, UInt32 pathLength, const char * __nullable path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainAddInternetPassword(SecKeychainRef __nullable keychain, UInt32 serverNameLength, const char * __nullable serverName, UInt32 securityDomainLength, const char * __nullable securityDomain, UInt32 accountNameLength, const char * __nullable accountName, UInt32 pathLength, const char * __nullable path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainFindInternetPassword
@@ -525,7 +525,7 @@ OSStatus SecKeychainAddInternetPassword(SecKeychainRef __nullable keychain, UInt
        @result A result code.  See "Security Error Codes" (SecBase.h).
        @discussion The SecKeychainFindInternetPassword function finds the first Internet password item which matches the attributes you provide. Most attributes are optional; you should pass only as many as you need to narrow the search sufficiently for your application's intended use. SecKeychainFindInternetPassword optionally returns a reference to the found item.
 */
-OSStatus SecKeychainFindInternetPassword(CFTypeRef __nullable keychainOrArray, UInt32 serverNameLength, const char * __nullable serverName, UInt32 securityDomainLength, const char * __nullable securityDomain, UInt32 accountNameLength, const char * __nullable accountName, UInt32 pathLength, const char * __nullable path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 * __nullable passwordLength, void * __nullable * __nullable passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainFindInternetPassword(CFTypeRef __nullable keychainOrArray, UInt32 serverNameLength, const char * __nullable serverName, UInt32 securityDomainLength, const char * __nullable securityDomain, UInt32 accountNameLength, const char * __nullable accountName, UInt32 pathLength, const char * __nullable path, UInt16 port, SecProtocolType protocol, SecAuthenticationType authenticationType, UInt32 * __nullable passwordLength, void * __nullable * __nullable passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainAddGenericPassword
@@ -541,7 +541,7 @@ OSStatus SecKeychainFindInternetPassword(CFTypeRef __nullable keychainOrArray, U
        @result A result code. See "Security Error Codes" (SecBase.h).
        @discussion The SecKeychainAddGenericPassword function adds a new generic password to the default keychain. Required parameters to identify the password are serviceName and accountName, which are application-defined strings. SecKeychainAddGenericPassword optionally returns a reference to the newly added item.
 */
-OSStatus SecKeychainAddGenericPassword(SecKeychainRef __nullable keychain, UInt32 serviceNameLength, const char * __nullable serviceName, UInt32 accountNameLength, const char * __nullable accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainAddGenericPassword(SecKeychainRef __nullable keychain, UInt32 serviceNameLength, const char * __nullable serviceName, UInt32 accountNameLength, const char * __nullable accountName, UInt32 passwordLength, const void *passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainFindGenericPassword
@@ -557,7 +557,7 @@ OSStatus SecKeychainAddGenericPassword(SecKeychainRef __nullable keychain, UInt3
        @result A result code.  See "Security Error Codes" (SecBase.h).
        @discussion The SecKeychainFindGenericPassword function finds the first generic password item which matches the attributes you provide. Most attributes are optional; you should pass only as many as you need to narrow the search sufficiently for your application's intended use. SecKeychainFindGenericPassword optionally returns a reference to the found item.
 */
-OSStatus SecKeychainFindGenericPassword(CFTypeRef __nullable keychainOrArray,  UInt32 serviceNameLength, const char * __nullable serviceName, UInt32 accountNameLength, const char * __nullable accountName, UInt32 * __nullable passwordLength, void * __nullable * __nullable passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainFindGenericPassword(CFTypeRef __nullable keychainOrArray,  UInt32 serviceNameLength, const char * __nullable serviceName, UInt32 accountNameLength, const char * __nullable accountName, UInt32 * __nullable passwordLength, void * __nullable * __nullable passwordData, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma mark ---- Managing User Interaction ----
 /*!
@@ -566,7 +566,7 @@ OSStatus SecKeychainFindGenericPassword(CFTypeRef __nullable keychainOrArray,  U
        @param state A boolean representing the state of user interaction.  You should pass TRUE to allow user interaction, and FALSE to disallow user interaction
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainSetUserInteractionAllowed(Boolean state) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainSetUserInteractionAllowed(Boolean state) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainGetUserInteractionAllowed
@@ -574,7 +574,7 @@ OSStatus SecKeychainSetUserInteractionAllowed(Boolean state) API_UNAVAILABLE(ios
        @param state On return, a pointer to the current state of user interaction.  If this is TRUE then user interaction is allowed, if it is FALSE, then user interaction is not allowed.
        @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainGetUserInteractionAllowed(Boolean *state) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainGetUserInteractionAllowed(Boolean *state) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #pragma mark ---- CSSM Bridge Functions ----
 /*!
diff --git a/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp b/OSX/libsecurity_keychain/lib/SecKeychainAddIToolsPassword.cpp
deleted file mode 100644 (file)
index db82b83..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  Copyright (c) 2003-2013 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@
- *
- *  SecKeychainAddIToolsPassword.c
- *  
- *     Based on Keychain item access control example
- *       -- added "always allow" ACL support
- */
-
-#include <Security/SecKeychain.h>
-#include <Security/SecKeychainItem.h>
-#include <Security/SecAccess.h>
-#include <Security/SecAccessPriv.h>
-#include <Security/SecTrustedApplicationPriv.h>
-#include <Security/SecACL.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-
-OSStatus SecKeychainAddIToolsPassword(SecKeychainRef __unused keychain,
-                                      UInt32 __unused accountNameLength,
-                                      const char * __unused accountName,
-                                      UInt32 __unused passwordLength,
-                                      const void * __unused passwordData,
-                                      SecKeychainItemRef * __unused itemRef)
-{
-    return errSecParam;
-}
index 6b31ddea90d7b12780e80429ce3a9c7a53f5a16c..b5bd97483166592d1600e2697611d69b773ccf9f 100644 (file)
@@ -44,6 +44,7 @@
 #include "KCExceptions.h"
 #include "Access.h"
 #include "SecKeychainItemExtendedAttributes.h"
+#include "LegacyAPICounts.h"
 
 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
 
@@ -79,7 +80,6 @@ CFTypeID
 SecKeychainItemGetTypeID(void)
 {
        BEGIN_SECAPI
-
        return gTypes().ItemImpl.typeID;
 
        END_SECAPI1(_kCFRuntimeNotATypeID)
@@ -127,7 +127,7 @@ SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeLis
 OSStatus
 SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
     os_activity_t activity = os_activity_create("SecKeychainItemModifyContent", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
@@ -171,7 +171,7 @@ SecKeychainItemFreeContent(SecKeychainAttributeList *attrList, void *data)
 OSStatus
 SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList *attrList, UInt32 length, const void *data)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
     os_activity_t activity = os_activity_create("SecKeychainItemModifyAttributesAndData", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
@@ -186,7 +186,7 @@ SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeyc
 OSStatus
 SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info, SecItemClass *itemClass, SecKeychainAttributeList **attrList, UInt32 *length, void **outData)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
 
        Item item = ItemImpl::required(__itemImplRef);
        item->getAttributesAndData(info, itemClass, attrList, length, outData);
@@ -199,7 +199,6 @@ OSStatus
 SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *data)
 {
        BEGIN_SECAPI
-
        ItemImpl::freeAttributesAndData(attrList, data);
 
        END_SECAPI
@@ -209,7 +208,7 @@ SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList *attrList, void *d
 OSStatus
 SecKeychainItemDelete(SecKeychainItemRef itemRef)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
     os_activity_t activity = os_activity_create("SecKeychainItemDelete", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
@@ -244,7 +243,7 @@ SecKeychainItemDelete(SecKeychainItemRef itemRef)
 OSStatus
 SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef* keychainRef)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
 
        // make sure this item has a keychain
        Keychain kc = ItemImpl::required(__itemImplRef)->keychain();
@@ -263,7 +262,7 @@ OSStatus
 SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef destKeychainRef,
        SecAccessRef initialAccess, SecKeychainItemRef *itemCopy)
 {
-       BEGIN_SECKCITEMAPI
+    BEGIN_SECKCITEMAPI
     os_activity_t activity = os_activity_create("SecKeychainItemCreateCopy", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_IF_NONE_PRESENT);
     os_activity_scope(activity);
     os_release(activity);
@@ -304,34 +303,6 @@ SecKeychainItemGetDLDBHandle(SecKeychainItemRef itemRef, CSSM_DL_DB_HANDLE* dldb
        END_SECKCITEMAPI
 }
 
-#if 0
-static
-OSStatus SecAccessCreateFromObject(CFTypeRef sourceRef,
-       SecAccessRef *accessRef)
-{
-       BEGIN_SECAPI
-
-       Required(accessRef);    // preflight
-       SecPointer<Access> access = new Access(*aclBearer(sourceRef));
-       *accessRef = access->handle();
-
-       END_SECAPI
-}
-
-
-/*!
- */
-static
-OSStatus SecAccessModifyObject(SecAccessRef accessRef, CFTypeRef sourceRef)
-{
-       BEGIN_SECAPI
-
-       Access::required(accessRef)->setAccess(*aclBearer(sourceRef), true);
-
-       END_SECAPI
-}
-#endif
-
 OSStatus
 SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef* accessRef)
 {
@@ -567,6 +538,7 @@ OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainA
 static OSStatus SecKeychainItemCreatePersistentReferenceFromCertificate(SecCertificateRef certRef,
     CFDataRef *persistentItemRef, Boolean isIdentity)
 {
+       COUNTLEGACYAPI
        OSStatus __secapiresult;
        if (!certRef || !persistentItemRef) {
                return errSecParam;
index 764cea36571b2213e67e00e84d0fc496c05d5131..ec6f00579097842a7df65b9a9aef8e77f011a6d1 100644 (file)
@@ -160,7 +160,7 @@ CFTypeID SecKeychainItemGetTypeID(void);
     @result A result code. See "Security Error Codes" (SecBase.h).
        @discussion The keychain item is written to the keychain's permanent data store. If the keychain item has not previously been added to a keychain, a call to the SecKeychainItemModifyContent function does nothing and returns errSecSuccess.
 */
-OSStatus SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList * __nullable attrList, UInt32 length, const void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, const SecKeychainAttributeList * __nullable attrList, UInt32 length, const void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCreateFromContent
@@ -176,7 +176,7 @@ OSStatus SecKeychainItemModifyAttributesAndData(SecKeychainItemRef itemRef, cons
 */
 OSStatus SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAttributeList *attrList,
                UInt32 length, const void * __nullable data, SecKeychainRef __nullable keychainRef,
-               SecAccessRef __nullable initialAccess, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+               SecAccessRef __nullable initialAccess, SecKeychainItemRef * __nullable CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemModifyContent
@@ -187,7 +187,7 @@ OSStatus SecKeychainItemCreateFromContent(SecItemClass itemClass, SecKeychainAtt
        @param data A pointer to a buffer containing the data to store. Pass NULL if you don't need to modify the data.
     @result A result code.  See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList * __nullable attrList, UInt32 length, const void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeychainAttributeList * __nullable attrList, UInt32 length, const void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyContent
@@ -199,7 +199,7 @@ OSStatus SecKeychainItemModifyContent(SecKeychainItemRef itemRef, const SecKeych
        @param outData On return, a pointer to a buffer containing the data in this item. Pass NULL if you don't need to retrieve the data. You must call SecKeychainItemFreeContent when you no longer need the data.
     @result A result code. See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if not enough valid parameters are supplied.
 */
-OSStatus SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass * __nullable itemClass, SecKeychainAttributeList * __nullable attrList, UInt32 * __nullable length, void * __nullable * __nullable outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass * __nullable itemClass, SecKeychainAttributeList * __nullable attrList, UInt32 * __nullable length, void * __nullable * __nullable outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemFreeContent
@@ -207,7 +207,7 @@ OSStatus SecKeychainItemCopyContent(SecKeychainItemRef itemRef, SecItemClass * _
        @param attrList A pointer to the attribute list to release. Pass NULL to ignore this parameter.
     @param data A pointer to the data buffer to release. Pass NULL to ignore this parameter.
 */
-OSStatus SecKeychainItemFreeContent(SecKeychainAttributeList * __nullable attrList, void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemFreeContent(SecKeychainAttributeList * __nullable attrList, void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyAttributesAndData
@@ -220,7 +220,7 @@ OSStatus SecKeychainItemFreeContent(SecKeychainAttributeList * __nullable attrLi
        @param outData On return, a pointer to a buffer containing the data in this item. Pass NULL if you don't need to retrieve the data. You must call SecKeychainItemFreeAttributesAndData when you no longer need the data.
     @result A result code. See "Security Error Codes" (SecBase.h). In addition, errSecParam (-50) may be returned if not enough valid parameters are supplied.
 */
-OSStatus SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo * __nullable info, SecItemClass * __nullable itemClass, SecKeychainAttributeList * __nullable * __nullable attrList, UInt32 * __nullable length, void * __nullable * __nullable outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo * __nullable info, SecItemClass * __nullable itemClass, SecKeychainAttributeList * __nullable * __nullable attrList, UInt32 * __nullable length, void * __nullable * __nullable outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemFreeAttributesAndData
@@ -229,7 +229,7 @@ OSStatus SecKeychainItemCopyAttributesAndData(SecKeychainItemRef itemRef, SecKey
     @param data A pointer to the data buffer to release. Pass NULL to ignore this parameter.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList * __nullable attrList, void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList * __nullable attrList, void * __nullable data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemDelete
@@ -238,7 +238,7 @@ OSStatus SecKeychainItemFreeAttributesAndData(SecKeychainAttributeList * __nulla
     @result A result code. See "Security Error Codes" (SecBase.h).
        @discussion If itemRef has not previously been added to the keychain, SecKeychainItemDelete does nothing and returns errSecSuccess. IMPORTANT: SecKeychainItemDelete does not dispose the memory occupied by the item reference itself; use the CFRelease function when you are completely finished with an item.
 */
-OSStatus SecKeychainItemDelete(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemDelete(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyKeychain
@@ -247,7 +247,7 @@ OSStatus SecKeychainItemDelete(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios,
        @param keychainRef On return, the keychain reference for the specified item. Release this reference by calling the CFRelease function.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychainRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef * __nonnull CF_RETURNS_RETAINED keychainRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCreateCopy
@@ -259,7 +259,7 @@ OSStatus SecKeychainItemCopyKeychain(SecKeychainItemRef itemRef, SecKeychainRef
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
 OSStatus SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef __nullable destKeychainRef,
-       SecAccessRef __nullable initialAccess, SecKeychainItemRef * __nonnull CF_RETURNS_RETAINED itemCopy) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecAccessRef __nullable initialAccess, SecKeychainItemRef * __nonnull CF_RETURNS_RETAINED itemCopy) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @function SecKeychainItemCreatePersistentReference
@@ -268,7 +268,7 @@ OSStatus SecKeychainItemCreateCopy(SecKeychainItemRef itemRef, SecKeychainRef __
     @param persistentItemRef On return, a CFDataRef containing a persistent reference. You must release this data reference by calling the CFRelease function.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef * __nonnull CF_RETURNS_RETAINED persistentItemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CFDataRef * __nonnull CF_RETURNS_RETAINED persistentItemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*!
@@ -278,7 +278,7 @@ OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CF
     @param itemRef On return, a SecKeychainItemRef for the keychain item described by the persistent reference. You must release this item reference by calling the CFRelease function.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef * __nonnull CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef * __nonnull CF_RETURNS_RETAINED itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 #pragma mark ---- CSSM Bridge Functions ----
@@ -312,7 +312,7 @@ OSStatus SecKeychainItemGetUniqueRecordID(SecKeychainItemRef itemRef, const CSSM
     @param access On return, a reference to the keychain item's access.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef * __nonnull CF_RETURNS_RETAINED access) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef * __nonnull CF_RETURNS_RETAINED access) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemSetAccess
@@ -321,7 +321,7 @@ OSStatus SecKeychainItemCopyAccess(SecKeychainItemRef itemRef, SecAccessRef * __
     @param access A reference to an access to replace the keychain item's current access.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
-OSStatus SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef access) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemSetAccess(SecKeychainItemRef itemRef, SecAccessRef access) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 CF_ASSUME_NONNULL_END
 
index 60c98f3133deb3e814a5599b62195a40c757a860..3ae8d1bfcea741b720dcb464ec35e4e5381df407 100644 (file)
 #include "KCCursor.h"
 #include <os/activity.h>
 
-/* I'm not sure we need this */
-#if 0
-CFTypeID SecKeychainItemExtendedAttributesGetTypeID(void);
-
-static CFTypeID SecKeychainItemExtendedAttributesGetTypeID(void)
-{
-       BEGIN_SECAPI
-
-       return gTypes().ExtendedAttribute.typeID;
-
-       END_SECAPI1(_kCFRuntimeNotATypeID)
-}
-#endif
+#include "LegacyAPICounts.h"
 
 extern "C" Boolean SecKeyIsCDSAKey(SecKeyRef ref);
 
index 1bd1caeaa73e60fcc8a5fd5f80610c469dfc3903..9e925f2d7ea6ac65227055971dfc8f953c4c8519 100644 (file)
@@ -77,7 +77,7 @@ OSStatus SecKeychainItemSetExtendedAttribute(
        CFStringRef                                     attrName,               /* identifies the attribute */
        CFDataRef                                       attrValue)              /* value to set; NULL means delete the
                                                                                                 *    attribute */
-    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * SecKeychainItemCopyExtendedAttribute() -  Obtain the value of an an extended attribute.
@@ -91,7 +91,7 @@ OSStatus SecKeychainItemSetExtendedAttribute(
 OSStatus SecKeychainItemCopyExtendedAttribute(
        SecKeychainItemRef                      itemRef,
        CFStringRef                                     attrName,
-       CFDataRef                                       *attrValue) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);              /* RETURNED */
+       CFDataRef                                       *attrValue) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);         /* RETURNED */
 
 /*
  * SecKeychainItemCopyAllExtendedAttributes() - obtain all of an item's extended attributes.
@@ -119,7 +119,7 @@ OSStatus SecKeychainItemCopyAllExtendedAttributes(
        CFArrayRef                                      *attrNames,                     /* RETURNED, each element is a CFStringRef */
        CFArrayRef                                      *attrValues)            /* optional, RETURNED, each element is a
                                                                                                         *   CFDataRef */
-    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #if defined(__cplusplus)
 }
 #endif
index 96e89d0eb51f2f5daf62a4cd2f044966b510ccb3..d9b13b26b7f83e3d97e974e7d15a15c8a2fddfe4 100644 (file)
@@ -72,23 +72,23 @@ enum {
        /* also kSecModDateItemAttr from SecKeychainItem.h */
 };
 
-OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCreateNew(SecItemClass itemClass, OSType itemCreator, UInt32 length, const void* data, SecKeychainItemRef* itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemGetData(SecKeychainItemRef itemRef, UInt32 maxLength, void* data, UInt32* actualLength) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemGetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute, UInt32* actualLength) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemSetAttribute(SecKeychainItemRef itemRef, SecKeychainAttribute* attribute) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemAdd(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemAddNoUI(SecKeychainRef keychainRef, SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemUpdate(SecKeychainItemRef itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemSetData(SecKeychainItemRef itemRef, UInt32 length, const void* data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
-OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainAttributeList *attrList, SecKeychainSearchRef *searchRef, SecKeychainItemRef *itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyRecordIdentifier
@@ -98,7 +98,7 @@ OSStatus SecKeychainItemFindFirst(SecKeychainRef keychainRef, const SecKeychainA
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
 
-OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataRef *recordIdentifier) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyFromRecordIdentifier
@@ -111,7 +111,7 @@ OSStatus SecKeychainItemCopyRecordIdentifier(SecKeychainItemRef itemRef, CFDataR
 
 OSStatus SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychain,
                                                                                                 SecKeychainItemRef *itemRef,
-                                                                                                CFDataRef recordIdentifier) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+                                                                                                CFDataRef recordIdentifier) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCopyAttributesAndEncryptedData
@@ -128,7 +128,7 @@ OSStatus SecKeychainItemCopyFromRecordIdentifier(SecKeychainRef keychain,
 */
 OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRef, SecKeychainAttributeInfo *info,
                                                                                                           SecItemClass *itemClass, SecKeychainAttributeList **attrList,
-                                                                                                          UInt32 *length, void **outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+                                                                                                          UInt32 *length, void **outData) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemModifyEncryptedData
@@ -140,7 +140,7 @@ OSStatus SecKeychainItemCopyAttributesAndEncryptedData(SecKeychainItemRef itemRe
     @result A result code.  See "Security Error Codes" (SecBase.h).
        @discussion The keychain item is written to the keychain's permanent data store. If the keychain item has not previously been added to a keychain, a call to the SecKeychainItemModifyContent function does nothing and returns errSecSuccess.
 */
-OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 length, const void *data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainItemCreateFromEncryptedContent
@@ -156,7 +156,7 @@ OSStatus SecKeychainItemModifyEncryptedData(SecKeychainItemRef itemRef, UInt32 l
 */
 OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, UInt32 length, const void *data,
                                                                                                   SecKeychainRef keychainRef, SecAccessRef initialAccess,
-                                                                                                  SecKeychainItemRef *itemRef, CFDataRef *itemLocalID) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+                                                                                                  SecKeychainItemRef *itemRef, CFDataRef *itemLocalID) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
  /*!
     @function SecKeychainItemSetAccessWithPassword
@@ -167,7 +167,7 @@ OSStatus SecKeychainItemCreateFromEncryptedContent(SecItemClass itemClass, UInt3
     @param password A buffer containing the password for the keychain. if this password is incorrect, this call might fail---it will not prompt the user.
     @result A result code. See "Security Error Codes" (SecBase.h).
 */
- OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+ OSStatus SecKeychainItemSetAccessWithPassword(SecKeychainItemRef itemRef, SecAccessRef accessRef, UInt32 passwordLength, const void * password) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 #if defined(__cplusplus)
 }
 #endif
index 2b035d948da2c61634d57a81387ff956bbfe6aab..7caaad33b6ebc4d9c913de7361ea38e79fe418e3 100644 (file)
@@ -48,8 +48,6 @@ OSStatus SecKeychainIsValid(SecKeychainRef keychainRef, Boolean* isValid)
     __OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_NA);
 OSStatus SecKeychainChangePassword(SecKeychainRef keychainRef, UInt32 oldPasswordLength, const void *oldPassword,  UInt32 newPasswordLength, const void *newPassword)
     __OSX_AVAILABLE_STARTING(__MAC_10_2, __IPHONE_NA);
-OSStatus SecKeychainOpenWithGuid(const CSSM_GUID *guid, uint32 subserviceId, uint32 subserviceType, const char* dbName, const CSSM_NET_ADDRESS *dbLocation, SecKeychainRef *keychain)
-    API_DEPRECATED("CSSM_GUID/CSSM_NET_ADDRESS is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
 OSStatus SecKeychainSetBatchMode (SecKeychainRef kcRef, Boolean mode, Boolean rollback)
     __OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_NA);
 
@@ -98,11 +96,11 @@ OSStatus SecKeychainCreateWithBlob(const char* fullPathName, CFDataRef dbBlob, S
 
 /* Keychain list manipulation */
 OSStatus SecKeychainAddDBToKeychainList (SecPreferencesDomain domain, const char* dbName, const CSSM_GUID *guid, uint32 subServiceType)
-    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 OSStatus SecKeychainDBIsInKeychainList (SecPreferencesDomain domain, const char* dbName, const CSSM_GUID *guid, uint32 subServiceType)
-    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 OSStatus SecKeychainRemoveDBFromKeychainList (SecPreferencesDomain domain, const char* dbName, const CSSM_GUID *guid, uint32 subServiceType)
-    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_DEPRECATED("CSSM_GUID is deprecated", macos(10.4,10.14)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /* server operation (keychain inhibit) */
 void SecKeychainSetServerMode(void)
index 5e94b58c025fe34c690845f3869e06ee382619e7..a84f0e3ee5a419fbb1786f67beb1e1f1fcbb1c4d 100644 (file)
 #include <os/activity.h>
 
 #include "SecBridge.h"
+#include "LegacyAPICounts.h"
 
 CFTypeID
 SecKeychainSearchGetTypeID(void)
 {
        BEGIN_SECAPI
-
        return gTypes().KCCursorImpl.typeID;
 
        END_SECAPI1(_kCFRuntimeNotATypeID)
index fed709fab8ae035993eccd5730146d68b9361b52..3a85f4854f50d402b13eb3e186809e18f65745ee 100644 (file)
@@ -45,7 +45,7 @@ CF_ASSUME_NONNULL_BEGIN
        @discussion This API is deprecated in 10.7. The SecKeychainSearchRef type is no longer used.
 */
 CFTypeID SecKeychainSearchGetTypeID(void)
-               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainSearchCreateFromAttributes
@@ -58,7 +58,7 @@ CFTypeID SecKeychainSearchGetTypeID(void)
        @discussion This function is deprecated in Mac OS X 10.7 and later; to find keychain items which match specified attributes, please use the SecItemCopyMatching API (see SecItem.h).
 */
 OSStatus SecKeychainSearchCreateFromAttributes(CFTypeRef __nullable keychainOrArray, SecItemClass itemClass, const SecKeychainAttributeList * __nullable attrList, SecKeychainSearchRef * __nonnull CF_RETURNS_RETAINED searchRef)
-               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecKeychainSearchCopyNext
@@ -69,7 +69,7 @@ OSStatus SecKeychainSearchCreateFromAttributes(CFTypeRef __nullable keychainOrAr
        @discussion This function is deprecated in Mac OS X 10.7 and later; to find keychain items which match specified attributes, please use the SecItemCopyMatching API (see SecItem.h).
 */
 OSStatus SecKeychainSearchCopyNext(SecKeychainSearchRef searchRef, SecKeychainItemRef * __nonnull CF_RETURNS_RETAINED itemRef)
-               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+               API_DEPRECATED("SecKeychainSearch is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 CF_ASSUME_NONNULL_END
 
index 6ac71ed4a4cd47b4857119da4dcad84a2156914a..f56197ae3bbfbb3b61cf2657d5d91707416a0ec5 100644 (file)
 
 #include <os/activity.h>
 
-#if 0
-static CFTypeID
-SecPasswordGetTypeID(void)
-{
-       BEGIN_SECAPI
-    
-       return gTypes().PasswordImpl.typeID;
-    
-       END_SECAPI1(_kCFRuntimeNotATypeID)
-}
-#endif
+#include "LegacyAPICounts.h"
 
 OSStatus
 SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef)
@@ -254,7 +244,7 @@ SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt3
         
     }
 
-    // If we're still here the use gave us his password, store it if keychain is in use
+    // If we're still here the user gave us their password, store it if keychain is in use
     if (passwordRef->useKeychain())
     {
         if (passwordRef->rememberInKeychain()) {
index 9be0a79d4511a4d51b0eb2463ff20f81c6702ac5..7ffaaa69d14aad72c902c3e38c4f1ab2d9e59eb3 100644 (file)
@@ -65,7 +65,7 @@ enum {
        @param itemAttrList (in/opt) A list of attributes which will be used for item creation.
     @param itemRef (out) On return, a pointer to a password reference.  Release this by calling the CFRelease function.
  */
-OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecKeychainAttributeList *itemAttrList, SecPasswordRef *itemRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @function SecPasswordAction
@@ -80,13 +80,13 @@ OSStatus SecGenericPasswordCreate(SecKeychainAttributeList *searchAttrList, SecK
        @param data A pointer to a buffer containing the data to store.
 
  */
-OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecPasswordAction(SecPasswordRef itemRef, CFTypeRef message, UInt32 flags, UInt32 *length, const void **data) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @function SecPasswordSetInitialAccess
     @abstract Set the initial access ref.  Only used when a password is first added to the keychain.
  */
-OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+OSStatus SecPasswordSetInitialAccess(SecPasswordRef itemRef, SecAccessRef accessRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #if defined(__cplusplus)
 }
index 56aeaefdaefad9de403a4741e6df860767c356e5..7f20d6260a3d9bdd4796ba8ada4bd25597abf164 100644 (file)
@@ -435,54 +435,6 @@ SecPolicyGetTPHandle(SecPolicyRef policyRef, CSSM_TP_HANDLE* tpHandle)
        return errSecServiceNotAvailable;
 }
 
-/* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
-OSStatus
-SecPolicyCopyAll(CSSM_CERT_TYPE certificateType, CFArrayRef* policies)
-{
-       /* bridge to support old functionality */
-#if SECTRUST_DEPRECATION_WARNINGS
-    syslog(LOG_ERR, "WARNING: SecPolicyCopyAll was deprecated in 10.7. Please use SecPolicy creation functions instead.");
-#endif
-    if (!policies) {
-               return errSecParam;
-       }
-       CFMutableArrayRef curPolicies = CFArrayCreateMutable(NULL, 0, NULL);
-       if (!curPolicies) {
-               return errSecAllocate;
-       }
-       /* build the subset of policies which were supported on OS X,
-          and which are also implemented on iOS */
-       CFStringRef supportedPolicies[] = {
-               kSecPolicyAppleX509Basic, /* CSSMOID_APPLE_X509_BASIC */
-               kSecPolicyAppleSSL, /* CSSMOID_APPLE_TP_SSL */
-               kSecPolicyAppleSMIME, /* CSSMOID_APPLE_TP_SMIME */
-               kSecPolicyAppleEAP, /*CSSMOID_APPLE_TP_EAP */
-               kSecPolicyAppleSWUpdateSigning, /* CSSMOID_APPLE_TP_SW_UPDATE_SIGNING */
-               kSecPolicyAppleIPsec, /* CSSMOID_APPLE_TP_IP_SEC */
-               kSecPolicyAppleCodeSigning, /* CSSMOID_APPLE_TP_CODE_SIGNING */
-               kSecPolicyMacAppStoreReceipt, /* CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT */
-               kSecPolicyAppleIDValidation, /* CSSMOID_APPLE_TP_APPLEID_SHARING */
-               kSecPolicyAppleTimeStamping, /* CSSMOID_APPLE_TP_TIMESTAMPING */
-               kSecPolicyAppleRevocation, /* CSSMOID_APPLE_TP_REVOCATION_{CRL,OCSP} */
-               NULL
-       };
-       CFIndex ix = 0;
-       while (true) {
-               CFStringRef policyID = supportedPolicies[ix++];
-               if (!policyID) {
-                       break;
-               }
-               SecPolicyRef curPolicy = SecPolicyCreateWithProperties(policyID, NULL);
-               if (curPolicy) {
-                       CFArrayAppendValue(curPolicies, curPolicy);
-                       CFRelease(curPolicy);
-               }
-       }
-       *policies = CFArrayCreateCopy(NULL, curPolicies);
-       CFRelease(curPolicies);
-       return errSecSuccess;
-}
-
 /* OS X only: __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA) */
 OSStatus
 SecPolicyCopy(CSSM_CERT_TYPE certificateType, const CSSM_OID *policyOID, SecPolicyRef* policy)
index 6bde108610b50404578267980f4515277d9c032d..9bb6dfd196c546b869556be8067ae8274368f607 100644 (file)
@@ -33,7 +33,6 @@ CFTypeID
 SecPolicySearchGetTypeID(void)
 {
        BEGIN_SECAPI
-
        return gTypes().PolicyCursor.typeID;
 
        END_SECAPI1(_kCFRuntimeNotATypeID)
@@ -67,7 +66,6 @@ SecPolicySearchCopyNext(
             SecPolicyRef* policyRef)
 {
        BEGIN_SECAPI
-
        RequiredParam(policyRef);
        SecPointer<Policy> policy;
 
index 3d64c65dd654df61d0a139f1839c1ede78af4d40..9e17b2553339c28d65096ea9ebaa64580aa360d3 100644 (file)
@@ -43,10 +43,11 @@ void SecTrustLegacySourcesListenForKeychainEvents(void) {
     notify_register_dispatch(kSecServerCertificateTrustNotification, &out_token,
                              dispatch_get_main_queue(),
                              ^(int token __unused) {
-                                 // Purge keychain parent cache
-                                 SecItemParentCachePurge();
-                                 // Purge unrestricted roots cache
-                                 SecTrustSettingsPurgeUserAdminCertsCache();
-
-                             });
+        // Purge keychain parent cache
+        SecItemParentCachePurge();
+        // Purge tust settings cert cache
+        SecTrustSettingsPurgeUserAdminCertsCache();
+        // Purge the trust settings cache
+        SecTrustSettingsPurgeCache();
+    });
 }
index f4ecc54e40461ee874851ce77c295c6ac233d2b0..c2a7e1334b2189377a107672ffa71cd3432faad8 100644 (file)
@@ -48,7 +48,7 @@
 #include <security_utilities/simpleprefs.h>
 #include <securityd_client/dictionary.h>
 #include <securityd_client/ssclient.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <dlfcn.h>
 #include <libproc.h>
 #include <syslog.h>
@@ -108,7 +108,7 @@ static bool tsUserTrustSettingsDisabled()
        Dictionary* dictionary = Dictionary::CreateDictionary(kSecTrustSettingsPrefsDomain, Dictionary::US_System);
        if (dictionary)
        {
-               auto_ptr<Dictionary> prefsDict(dictionary);
+               unique_ptr<Dictionary> prefsDict(dictionary);
                /* this returns false if the pref isn't there, just like we want */
                tsUserTrustDisable = prefsDict->getBoolValue(kSecTrustSettingsDisableUserTrustSettings);
        }
@@ -348,7 +348,7 @@ static OSStatus tsCopyTrustSettings(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath
+       unique_ptr<TrustSettings>_(ts); // make sure this gets deleted just in case something throws underneath
 
        if(trustSettings) {
                *trustSettings = ts->copyTrustSettings(cert);
@@ -360,6 +360,59 @@ static OSStatus tsCopyTrustSettings(
        END_RCSAPI
 }
 
+/*
+ * Common code for SecTrustSettingsCopyTrustSettings(),
+ * SecTrustSettingsCopyModificationDate().
+ */
+static OSStatus tsCopyTrustSettings_cached(
+    SecCertificateRef cert,
+    SecTrustSettingsDomain domain,
+    CFArrayRef CF_RETURNS_RETAINED *trustSettings)
+{
+    BEGIN_RCSAPI
+
+    TS_REQUIRED(cert)
+
+    StLock<Mutex>    _(sutCacheLock());
+    TrustSettings* ts = tsGetGlobalTrustSettings(domain);
+
+    // rather than throw these results, just return them because we are at the top level
+    if (ts == NULL) {
+        return errSecItemNotFound;
+    }
+
+    if(trustSettings) {
+        *trustSettings = ts->copyTrustSettings(cert);
+    }
+
+    END_RCSAPI
+}
+
+static OSStatus tsContains(
+    SecCertificateRef cert,
+    SecTrustSettingsDomain domain)
+{
+    BEGIN_RCSAPI
+
+    TS_REQUIRED(cert)
+
+    StLock<Mutex>    _(sutCacheLock());
+    TrustSettings* ts = tsGetGlobalTrustSettings(domain);
+
+    // rather than throw these results, just return them because we are at the top level
+    if (ts == NULL) {
+        return errSecItemNotFound;
+    }
+
+    if (ts->contains(cert)) {
+        return errSecSuccess;
+    } else {
+        return errSecItemNotFound;
+    }
+
+    END_RCSAPI
+}
+
 static void tsAddConditionalCerts(CFMutableArrayRef certArray);
 
 /*
@@ -727,7 +780,7 @@ OSStatus SecTrustSettingsSetTrustSettingsExternal(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        if(certRef != NULL) {
                ts->setTrustSettings(certRef, trustSettingsDictOrArray);
@@ -738,6 +791,25 @@ OSStatus SecTrustSettingsSetTrustSettingsExternal(
        END_RCSAPI
 }
 
+void SecTrustSettingsPurgeCache(void) {
+    tsPurgeCache();
+}
+
+OSStatus SecTrustSettingsCopyTrustSettings_Cached(
+    SecCertificateRef certRef,
+    SecTrustSettingsDomain domain,
+    CFArrayRef CF_RETURNS_RETAINED *trustSettings)                /* RETURNED */
+{
+    TS_REQUIRED(certRef)
+    TS_REQUIRED(trustSettings)
+
+    OSStatus result = tsCopyTrustSettings_cached(certRef, domain, trustSettings);
+    if (result == errSecSuccess && *trustSettings == NULL) {
+        result = errSecItemNotFound; /* documented result if no trust settings exist */
+    }
+    return result;
+}
+
 #pragma mark --- API functions ---
 
 OSStatus SecTrustSettingsCopyTrustSettings(
@@ -792,7 +864,7 @@ OSStatus SecTrustSettingsSetTrustSettings(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        ts->setTrustSettings(certRef, trustSettingsDictOrArray);
        ts->flushToDisk();
@@ -822,7 +894,7 @@ OSStatus SecTrustSettingsRemoveTrustSettings(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        /* deleteTrustSettings throws if record not found */
        trustSettingsDbg("SecTrustSettingsRemoveTrustSettings: deleting from domain %d",
@@ -854,7 +926,7 @@ OSStatus SecTrustSettingsCopyCertificates(
                return status;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     
@@ -1003,6 +1075,16 @@ OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains(
     return result;
 }
 
+bool SecTrustSettingsUserAdminDomainsContain(SecCertificateRef certRef)
+{
+    TS_REQUIRED(certRef)
+    if (tsContains(certRef, kSecTrustSettingsDomainAdmin) == errSecSuccess ||
+        tsContains(certRef, kSecTrustSettingsDomainUser) == errSecSuccess) {
+        return true;
+    }
+    return false;
+}
+
 /*
  * Obtain an external, portable representation of the specified
  * domain's TrustSettings. Caller must CFRelease the returned data.
@@ -1023,7 +1105,7 @@ OSStatus SecTrustSettingsCreateExternalRepresentation(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        *trustSettings = ts->createExternal();
        return errSecSuccess;
@@ -1053,7 +1135,7 @@ OSStatus SecTrustSettingsImportExternalRepresentation(
                return result;
        }
 
-       auto_ptr<TrustSettings>_(ts);
+       unique_ptr<TrustSettings>_(ts);
 
        ts->flushToDisk();
        tsTrustSettingsChanged();
index 5f9e0c7883f470bf2ab1512e87a4124bbd18def5..6a240424cf94a5b8d677c41f829bbc0d1cda51c1 100644 (file)
@@ -44,7 +44,6 @@ CFTypeID
 SecTrustedApplicationGetTypeID(void)
 {
        BEGIN_SECAPI
-
        return gTypes().TrustedApplication.typeID;
 
        END_SECAPI1(_kCFRuntimeNotATypeID)
@@ -195,7 +194,6 @@ OSStatus SecTrustedApplicationCreateApplicationGroup(const char *groupName,
        SecCertificateRef anchor, SecTrustedApplicationRef *appRef)
 {
        BEGIN_SECAPI
-
        CFRef<SecRequirementRef> req;
        MacOSError::check(SecRequirementCreateGroup(CFTempString(groupName), anchor,
                kSecCSDefaultFlags, &req.aref()));
index b1f37a6e829afbf391fceb4df384aff9110291e7..286ce28765abf823c11d480899af90e92c7a5b7a 100644 (file)
@@ -58,7 +58,7 @@ CFTypeID SecTrustedApplicationGetTypeID(void);
 */
 OSStatus SecTrustedApplicationCreateFromPath(const char * __nullable path, SecTrustedApplicationRef * __nonnull CF_RETURNS_RETAINED app)
     API_DEPRECATED("No longer supported", macos(10.0, 10.15))
-    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecTrustedApplicationCopyData
@@ -69,7 +69,7 @@ OSStatus SecTrustedApplicationCreateFromPath(const char * __nullable path, SecTr
 */
 OSStatus SecTrustedApplicationCopyData(SecTrustedApplicationRef appRef, CFDataRef * __nonnull CF_RETURNS_RETAINED data)
     API_DEPRECATED("No longer supported", macos(10.0, 10.15))
-    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecTrustedApplicationSetData
@@ -80,7 +80,7 @@ OSStatus SecTrustedApplicationCopyData(SecTrustedApplicationRef appRef, CFDataRe
 */
 OSStatus SecTrustedApplicationSetData(SecTrustedApplicationRef appRef, CFDataRef data)
     API_DEPRECATED("No longer supported", macos(10.0, 10.15))
-    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 CF_ASSUME_NONNULL_END
 
index 1b9911adeed94f26c8cb8c7c6a83c11697845cfd..6c6badad135bc8fdbfa8287d0238f185268a273e 100644 (file)
@@ -42,7 +42,7 @@ extern "C" {
  * Determine whether the application at path satisfies the trust expressed in appRef.
  */
 OSStatus
-SecTrustedApplicationValidateWithPath(SecTrustedApplicationRef appRef, const char *path) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+SecTrustedApplicationValidateWithPath(SecTrustedApplicationRef appRef, const char *path) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecTrustedApplicationCreateFromRequirement
@@ -60,7 +60,7 @@ SecTrustedApplicationValidateWithPath(SecTrustedApplicationRef appRef, const cha
        @result A result code. See SecBase.h and CSCommon.h.
 */
 OSStatus SecTrustedApplicationCreateFromRequirement(const char *description,
-       SecRequirementRef requirement, SecTrustedApplicationRef *app) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecRequirementRef requirement, SecTrustedApplicationRef *app) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecTrustedApplicationCopyRequirement
@@ -78,7 +78,7 @@ OSStatus SecTrustedApplicationCreateFromRequirement(const char *description,
                no SecRequirementRef could be obtained.
  */
 OSStatus SecTrustedApplicationCopyRequirement(SecTrustedApplicationRef appRef,
-       SecRequirementRef *requirement) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecRequirementRef *requirement) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*!
@@ -101,7 +101,7 @@ OSStatus SecTrustedApplicationCopyRequirement(SecTrustedApplicationRef appRef,
        @result A result code. See SecBase.h and CSCommon.h.
  */
 OSStatus SecTrustedApplicationCreateApplicationGroup(const char *groupName,
-       SecCertificateRef anchor, SecTrustedApplicationRef *app) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecCertificateRef anchor, SecTrustedApplicationRef *app) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*!
@@ -118,7 +118,7 @@ OSStatus SecTrustedApplicationCreateApplicationGroup(const char *groupName,
  */
 OSStatus SecTrustedApplicationCopyExternalRepresentation(
        SecTrustedApplicationRef appRef,
-       CFDataRef *externalRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       CFDataRef *externalRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
        @function SecTrustedApplicationCreateWithExternalRepresentation
@@ -133,7 +133,7 @@ OSStatus SecTrustedApplicationCopyExternalRepresentation(
  */
 OSStatus SecTrustedApplicationCreateWithExternalRepresentation(
        CFDataRef externalRef,
-       SecTrustedApplicationRef *appRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecTrustedApplicationRef *appRef) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*
@@ -146,10 +146,10 @@ enum {
 
 OSStatus
 SecTrustedApplicationMakeEquivalent(SecTrustedApplicationRef oldRef,
-       SecTrustedApplicationRef newRef, UInt32 flags) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+       SecTrustedApplicationRef newRef, UInt32 flags) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 OSStatus
-SecTrustedApplicationRemoveEquivalence(SecTrustedApplicationRef appRef, UInt32 flags) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+SecTrustedApplicationRemoveEquivalence(SecTrustedApplicationRef appRef, UInt32 flags) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*
@@ -157,7 +157,7 @@ SecTrustedApplicationRemoveEquivalence(SecTrustedApplicationRef appRef, UInt32 f
  * pre-emptive code equivalency establishment
  */
 OSStatus
-SecTrustedApplicationIsUpdateCandidate(const char *installroot, const char *path) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+SecTrustedApplicationIsUpdateCandidate(const char *installroot, const char *path) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 /*
@@ -165,7 +165,7 @@ SecTrustedApplicationIsUpdateCandidate(const char *installroot, const char *path
  * This is for system update installers (only)!
  */
 OSStatus
-SecTrustedApplicationUseAlternateSystem(const char *systemRoot) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+SecTrustedApplicationUseAlternateSystem(const char *systemRoot) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
 #if defined(__cplusplus)
index 83b8db377a3a2aa6d0e9c57fa5dbe608690ab652..a438f948c2098926833d57f140cd9a248e66b439 100644 (file)
@@ -34,7 +34,7 @@
 #include <security_asn1/SecNssCoder.h>
 #include <security_cdsa_utils/cuCdsaUtils.h>
 
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 using namespace Security;
 using namespace KeychainCore;
index efab9b8b414d8e8a3a7e5f2e583498a729bdc087..e173e8512de9069b5e76bd6aa95cf7e723bf0001 100644 (file)
@@ -1356,10 +1356,11 @@ void StorageManager::login(ConstStringPtr name, ConstStringPtr password)
 {
        StLock<Mutex>_(mMutex);
 
-    if ( name == NULL || password == NULL )
+    if ( name == NULL || password == NULL ) {
         MacOSError::throwMe(errSecParam);
+    }
 
-       login(name[0], name + 1, password[0], password + 1, false);
+    login(name[0], name + 1, password[0], password + 1, false);
 }
 
 void StorageManager::login(UInt32 nameLength, const void *name,
index 3fa9aabbd7fcfe1cf688343537aa8efd8ab92d4d..0710cadb3a325ccb48fab9ead2715879558ab558 100644 (file)
@@ -377,10 +377,11 @@ CFArrayRef potentialEVChainWithCertificates(CFArrayRef certificates)
 //
 static SecCertificateRef _rootCertificateWithSubjectOfCertificate(SecCertificateRef certificate)
 {
-    if (!certificate)
+    if (!certificate) {
         return NULL;
+    }
 
-       StLock<Mutex> _(SecTrustKeychainsGetMutex());
+    StLock<Mutex> _(SecTrustKeychainsGetMutex());
 
     // get data+length for the provided certificate
     CSSM_CL_HANDLE clHandle = 0;
@@ -519,8 +520,9 @@ static SecCertificateRef _rootCertificateWithSubjectKeyIDOfCertificate(SecCertif
     SecCertificateRef resultCert = NULL;
        OSStatus status = errSecSuccess;
 
-    if (!certificate)
+    if (!certificate) {
         return NULL;
+    }
 
        StLock<Mutex> _(SecTrustKeychainsGetMutex());
 
@@ -557,8 +559,9 @@ CFArrayRef CF_RETURNS_RETAINED _possibleRootCertificatesForOidString(CFStringRef
 {
        StLock<Mutex> _(SecTrustKeychainsGetMutex());
 
-    if (!oidString)
+    if (!oidString) {
         return NULL;
+    }
        CFDictionaryRef evOidDict = _evCAOidDict();
        if (!evOidDict)
                return NULL;
index 6338d1c0d3f706f6cb16bdf52ffacc9c86a5d700..8cd49615c57de5e3f4fcfc66bd231eb4c9ea9ceb 100644 (file)
@@ -261,7 +261,7 @@ CFMutableArrayRef Trust::addPreferenceRevocationPolicies(
        pd = new Dictionary(tempDict);
        CFRelease(tempDict);
 
-       auto_ptr<Dictionary> prefsDict(pd);
+       unique_ptr<Dictionary> prefsDict(pd);
 
        bool doOcsp = false;
        bool doCrl = false;
index 7474aca6e1aca1f6d36ee67a0fd906291609c2cb..c834712cb1a1891c8c9c0adc92571ea60e5d06fd 100644 (file)
@@ -50,7 +50,7 @@
 #include <security_keychain/KCCursor.h>
 #include <security_ocspd/ocspdClient.h>
 #include <CoreFoundation/CoreFoundation.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <dispatch/dispatch.h>
 #include <sys/stat.h>
 #include <syslog.h>
@@ -1019,6 +1019,14 @@ CFDateRef TrustSettings::copyModDate(
        return modDate;
 }
 
+bool TrustSettings::contains(SecCertificateRef certRef)
+{
+    if(findDictionaryForCert(certRef) != NULL) {
+        return true;
+    }
+    return false;
+}
+
 /*
  * Modify cert's trust settings, or add a new cert to the record.
  */
index d1362d53007ac3591f1a571f5119d193588e14dd..c98d1a263751b3317aad4a85ba2f6f44a7a3a319 100644 (file)
@@ -177,6 +177,11 @@ public:
         */
        CFDataRef createExternal();
 
+    /*
+     * Indicates whether the trust settings contain any settings for this cert.
+     */
+    bool contains(SecCertificateRef certRef);
+
 private:
        /* common code to init mPropList from raw data */
        void initFromData(
index e001afd0bd7898c52efe5400e671028e348d512a..934449a61f195906249ae86f9f9a7bac59d818ed 100644 (file)
@@ -30,7 +30,6 @@
 #include <Security/cssmtype.h>
 #include <Security/cssmapple.h>
 #include <Security/oidscert.h>
-#include <assert.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/fcntl.h>
index a3508aa5facdcd4960cf1755f1fc254881cd11ca..8cc1201a2c581f8fc7da8b40e0c1ec2f0d6a6ac2 100644 (file)
@@ -227,16 +227,19 @@ static void checkKeyUse(SecKeyRef key, OSStatus expectedStatus) {
 
     CFErrorRef error = NULL;
     CFDataRef ciphertextData = SecTransformExecute(transform, &error);
+    CFDataRef roundtripData = NULL;
 
     if(error) {
-        is(CFErrorGetCode(error), expectedStatus, "%s: Encrypting data failed: %d %s (and expected %d)", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(CFErrorCopyDescription(error), kCFStringEncodingUTF8), (int) expectedStatus);
+        CFStringRef errorStr = CFErrorCopyDescription(error);
+        is(CFErrorGetCode(error), expectedStatus, "%s: Encrypting data failed: %d %s (and expected %d)", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(errorStr, kCFStringEncodingUTF8), (int) expectedStatus);
+        CFReleaseSafe(errorStr);
 
         if(expectedStatus != errSecSuccess) {
             // make test numbers match and quit
             for(int i = 1; i < checkKeyUseTests; i++) {
                 pass("test numbers match");
             }
-            return;
+            goto cleanup;
         }
 
     } else {
@@ -251,21 +254,21 @@ static void checkKeyUse(SecKeyRef key, OSStatus expectedStatus) {
     SecTransformSetAttribute(transform, kSecEncryptionMode, kSecModeCBCKey, NULL);
     SecTransformSetAttribute(transform, kSecTransformInputAttributeName, ciphertextData, NULL);
 
-    CFDataRef roundtripData = SecTransformExecute(transform, &error);
+    roundtripData = SecTransformExecute(transform, &error);
     is(error, NULL, "%s: checkKeyUse: SecTransformExecute (decrypt)", testName);
 
     if(error) {
         CFStringRef errorStr = CFErrorCopyDescription(error);
         fail("%s: Decrypting data failed: %d %s", testName, (int) CFErrorGetCode(error), CFStringGetCStringPtr(errorStr, kCFStringEncodingUTF8));
-        CFRelease(errorStr);
+        CFReleaseSafe(errorStr);
     } else {
         pass("%s: make test numbers match", testName);
     }
 
-    CFReleaseSafe(transform);
-
     eq_cf(plaintextData, roundtripData, "%s: checkKeyUse: roundtripped data is input data", testName);
 
+ cleanup:
+    CFReleaseSafe(transform);
     CFReleaseSafe(plaintext);
     CFReleaseSafe(plaintextData);
     CFReleaseSafe(ciphertextData);
index 148be634e3601dff033ce7a38806db873e96f1a3..180950acbd72eda1bcf2a028b59d8002f4ad90e7 100644 (file)
@@ -48,7 +48,8 @@ void sendTSARequest(CFDataRef tsaReq, const char *tsaURL, TSARequestCompletionBl
  
 - (id)init
 {
-    self = [super init];
+    if ((self = [super init])) {
+    }
     return self;
 }
 
index c7d3429f576639e753807a7ea2b0d0255b763d2c..d181e1efb7d8b404fa19af87891fff5744b91099 100644 (file)
@@ -584,12 +584,13 @@ void AppleManifest::ReconstructOther (uint32& finger, const uint8* data, Manifes
 
 void AppleManifest::ReconstructManifestItemList (uint32 &finger, const uint8* data, ManifestItemList &itemList)
 {
-       uint32 start = finger;
-       uint64_t length = ReconstructUInt64 (finger, data);
+    uint32 start = finger;
+    uint64_t length = ReconstructUInt64 (finger, data);
     uint32 end = (uint32)(start + length);
 
-    if (length > UINT32_MAX || (length + (uint64_t)start) > (uint64_t)UINT32_MAX)
+    if (length > UINT32_MAX || (length + (uint64_t)start) > (uint64_t)UINT32_MAX) {
         MacOSError::throwMe (errSecManifestDamaged);
+    }
 
        while (finger < end)
        {
index 42b75c6ad6555ad541d1d2db072572c236aa16bb..b8d9d835b2ea21d747f5625738280b1b4f967370 100644 (file)
@@ -35,7 +35,7 @@ Manifest::Manifest () : mManifestSigner (NULL)
 
 
 
-Manifest::~Manifest () throw ()
+Manifest::~Manifest () _NOEXCEPT
 {
        delete mManifestSigner;
 }
index 27ebff42b98ed28429712f6bc33a4c08d984029a..8e0e223f0e28d54afd3a0468d86f7e63b1425ee3 100644 (file)
@@ -49,7 +49,7 @@ public:
        
        Manifest ();
 
-       virtual ~Manifest () throw ();
+       virtual ~Manifest () _NOEXCEPT;
        
        ManifestInternal& GetManifestInternal () {return mManifestInternal;}
        ManifestSigner* GetSigner () {return mManifestSigner;}
index e035ca50efe09bfdb8576182281e9cbaa3244415..7e5a4921ab7b23bfa38087c6deda853133f6358e 100644 (file)
@@ -3,6 +3,8 @@
 #include "SecureDownloadInternal.h"
 #include "SecCFRelease.h"
 
+#include "simulatecrash_assert.h"
+
 //
 // SecureDownloadXML: SecureDownloadXML.c
 //        cc -g -framework CoreFoundation -o $@ $^
index f11949ef1a3ecb501b65efe22abb11136c257e55..42c421f070062396c8660e7b6fef6db4a0050c29 100644 (file)
@@ -37,7 +37,7 @@
 #include <sys/param.h>
 #include <dirent.h>
 #include <fcntl.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <time.h>
 #include <string>
 #include <unistd.h>
index 0c8718da0a19270369be7862ac2bfaf997fa512c..078652cc0748aaa3bbe6d2e124522160f16c91f9 100644 (file)
@@ -71,11 +71,11 @@ public:
        void removeSubservice(const char *guid, uint32 ssid);
 
     // implement CssmHeap::Allocator
-    void *malloc(size_t size) throw(std::bad_alloc)
+    void *malloc(size_t size)
        { return mCssmMemoryFunctions.malloc(size); }
-    void free(void *addr) throw()
+    void free(void *addr) _NOEXCEPT
        { mCssmMemoryFunctions.free(addr); }
-       void *realloc(void *addr, size_t size) throw(std::bad_alloc)
+       void *realloc(void *addr, size_t size)
        { return mCssmMemoryFunctions.realloc(addr, size); }
 
        MDSModule               &module()       { return mModule; }
index 2f18194ad1fe24beade62009272a73e0fa05b832..3ab20d1d62d49a35a2f9376cd718aad06a3496a9 100644 (file)
@@ -36,6 +36,7 @@
 #include <memory>
 #include <security_utilities/globalizer.h>
 #include <security_utilities/threading.h>
+#include "LegacyAPICounts.h"
 
 #define MSApiDebug(args...)    secinfo("MDS_API", ## args)
 
@@ -286,7 +287,7 @@ CSSM_RETURN CSSMAPI
 MDS_Terminate (MDS_HANDLE inMDSHandle)
 {
     BEGIN_API
-    auto_ptr<MDSSession> aMDSSession (&HandleObject::findAndKill<MDSSession> (inMDSHandle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE));
+    unique_ptr<MDSSession> aMDSSession (&HandleObject::findAndKill<MDSSession> (inMDSHandle, CSSMERR_CSSM_INVALID_ADDIN_HANDLE));
     aMDSSession->terminate (); // Even if terminate throws the MDSSession object will be deleted.
     END_API(MDS)
 }
index 01db7249d1516da53281e7d496d801f03d12cd62..be931ce6861f6f1da3afb2cda9de986b6c6cce6a 100644 (file)
@@ -313,10 +313,11 @@ CSSM_RETURN ocspdCRLStatus(
                issuers.Data, (mach_msg_type_number_t)issuers.Length,
                crlIssuer ? crlIssuer->Data : NULL, crlIssuer ? (mach_msg_type_number_t)crlIssuer->Length : 0,
                crlURL ? crlURL->Data : NULL, crlURL ? (mach_msg_type_number_t)crlURL->Length : 0);
-    if (krtn == MACH_SEND_INVALID_DEST)
+    if (krtn == MACH_SEND_INVALID_DEST) {
         OcspdGlobals().resetServerPort();
+    }
 
-       return krtn;
+    return krtn;
 }
 
 /*
index a1e93fd27b52eb092308edc1c6db275f05378de5..b1902a0591bc24afd8dd2f554d94d0a655496052 100644 (file)
@@ -31,7 +31,7 @@
 #include "pkcs12BagAttrs.h"
 #include "pkcs12Utils.h"
 #include <security_asn1/nssUtils.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <Security/SecBase.h>
 /* 
  * Copying constructor used by P12SafeBag during encoding
index f2e068bcaed0b58e149bf43831c4d0a64d45f030..4620c43808581da02f2cebcb19a484fc20cff28a 100644 (file)
@@ -29,7 +29,7 @@
 #include "pkcs12Debug.h"
 #include "pkcs12Utils.h"
 #include <string.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <Security/Security.h>
 #include <Security/SecKeyPriv.h>
 #include <Security/SecAsn1Templates.h>
index b72e2e528cede16e4a1601d66f1ceb45d6a64480..802f98e6a320743f431a46bc37f6b46b091b2dc9 100644 (file)
@@ -360,9 +360,9 @@ SDCSPSession::FreeKey(const AccessCredentials *accessCred,
                // that!
 
                // Find the key in the map.  Tell tell the key to free itself
-               // (when the auto_ptr deletes the key it removes itself from the map). 
+               // (when the unique_ptr deletes the key it removes itself from the map). 
            secinfo("freeKey", "CSPDL FreeKey");
-               auto_ptr<SDKey> ssKey(&mSDCSPDLSession.find<SDKey>(ioKey));
+               unique_ptr<SDKey> ssKey(&mSDCSPDLSession.find<SDKey>(ioKey));
                ssKey->free(accessCred, ioKey, deleteKey);
        }
        else
index 1717eaf5ce33f24c8ced05ccb8c4cc021814f167..788b0b3fda07cd2c937bbf7d43aaa8eb06bb370f 100644 (file)
@@ -486,7 +486,7 @@ SDCryptContext::final(CssmData &out)
        if(!inSize) return;
 
        const CssmData in(const_cast<void *>(mNullDigest.digestPtr()), inSize);
-       IFDEBUG(size_t origOutSize = out.length());
+       size_t origOutSize = out.length();
        if (encoding()) {
                clientSession().encrypt(*mContext, mKeyHandle, in, out);
        }
index 8c99fef3cc66aaeae9c22fa4f1d4afceeed3056e..dd737709cd4dd6d4d00c28b692d9414e15213b39 100644 (file)
@@ -39,6 +39,7 @@
 #include <Security/cssmapi.h>
 #include <Security/oidscert.h>
 #include <Security/oidscert.h>
+#include <utilities/SecCFWrappers.h>
 #include <syslog.h>
 
 /* for errKCDuplicateItem */
 #define dprintf(args...)
 #endif
 
-/* @@@ Remove this once it's back in the appropriate header. */
-static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
-static const CSSM_OID OID_X509V1IssuerNameStd = {INTEL_X509V3_CERT_R08_LENGTH+1,  (uint8 *)X509V1IssuerNameStd};
-
 /* 
  * Normalize a Printable String. Per RFC2459 (4.1.2.4), printable strings are case 
  * insensitive and we're supposed to ignore leading and trailing 
@@ -579,100 +576,59 @@ SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retIt
 // Extract the issuer and serial number from a certificate
 SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
 {
-    OSStatus status;
     SecCmsIssuerAndSN *certIssuerAndSN;
-    SecCertificateRef certRef;
-    SecCertificateRef itemImplRef = NULL;
-    CSSM_CL_HANDLE clHandle = 0;
-    CSSM_DATA_PTR serialNumber = 0;
-    CSSM_DATA_PTR issuer = 0;
-    CSSM_DATA certData = {};
-    CSSM_HANDLE resultsHandle = 0;
-    uint32 numberOfFields = 0;
-    CSSM_RETURN result;
-    void *mark;
 
+    void *mark;
     mark = PORT_ArenaMark(pl);
-
-    /* Retain input cert and get pointer to its data */
-    certRef = (SecCertificateRef)((cert) ? CFRetain(cert) : NULL);
-    if (!certRef || SecCertificateGetData(certRef, &certData)) {
+    CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
+    CFDataRef serial_data = SecCertificateCopySerialNumberData(cert, NULL);
+    if (!issuer_data || !serial_data) {
         goto loser;
     }
-#if 1
-    // Convert unified input certRef to itemImpl instance.
-    // note: must not release this instance while we're using its CL handle!
-    itemImplRef = SecCertificateCreateItemImplInstance(cert);
-    status = SecCertificateGetCLHandle_legacy(itemImplRef, &clHandle);
-#else
-    status = SecCertificateGetCLHandle(certRef, &clHandle);
-#endif
-    if (status)
-        goto loser;
-
-    /* Get the issuer from the cert. */
-    result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
-        &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
 
-    if (result || numberOfFields < 1)
-        goto loser;
-    result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
-    if (result)
-        goto loser;
-
-    /* Get the serialNumber from the cert. */
-    result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
-        &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
-    if (result || numberOfFields < 1)
-        goto loser;
-    result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
-    if (result)
-        goto loser;
+    SecAsn1Item serialNumber = {
+        .Length = CFDataGetLength(serial_data),
+        .Data = (uint8_t *)CFDataGetBytePtr(serial_data)
+    };
+    SecAsn1Item issuer = {
+        .Length = CFDataGetLength(issuer_data),
+        .Data = (uint8_t *)CFDataGetBytePtr(issuer_data)
+    };
 
     /* Allocate the SecCmsIssuerAndSN struct. */
     certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
-    if (certIssuerAndSN == NULL)
+    if (certIssuerAndSN == NULL) {
         goto loser;
+    }
 
     /* Copy the issuer. */
-    certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
-    if (!certIssuerAndSN->derIssuer.Data)
+    certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
+    if (!certIssuerAndSN->derIssuer.Data) {
         goto loser;
-    PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length);
-    certIssuerAndSN->derIssuer.Length = issuer->Length;
+    }
+    PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
+    certIssuerAndSN->derIssuer.Length = issuer.Length;
 
     /* Copy the serialNumber. */
-    certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length);
-    if (!certIssuerAndSN->serialNumber.Data)
+    certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
+    if (!certIssuerAndSN->serialNumber.Data) {
         goto loser;
-    PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length);
-    certIssuerAndSN->serialNumber.Length = serialNumber->Length;
-
-    PORT_ArenaUnmark(pl, mark);
-
-    CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
-    CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
+    }
+    PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
+    certIssuerAndSN->serialNumber.Length = serialNumber.Length;
 
-    if (itemImplRef)
-        CFRelease(itemImplRef);
-    if (certRef)
-        CFRelease(certRef);
+    CFRelease(serial_data);
+    CFRelease(issuer_data);
 
+    PORT_ArenaUnmark(pl, mark);
     return certIssuerAndSN;
 
 loser:
+    CFReleaseNull(serial_data);
+    CFReleaseNull(issuer_data);
     PORT_ArenaRelease(pl, mark);
-
-    if (serialNumber)
-        CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
-    if (issuer)
-        CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
-    if (itemImplRef)
-        CFRelease(itemImplRef);
-    if (certRef)
-        CFRelease(certRef);
-
     PORT_SetError(SEC_INTERNAL_ONLY);
+
     return NULL;
 }
 
index 102b8a4fb85aee7a9fa9a4370986f664bdb865de..42d5ae51524c1b418e44672447a5497f7e60cf5d 100644 (file)
@@ -34,7 +34,7 @@
 /*
  * CMS digesting.
  */
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #include "cmslocal.h"
 
index 3a83746d9462c2d1ff49c085f5e8da37c2d18e68..c3cd380bd281e884b0a813eed483774a288d4a56 100644 (file)
@@ -456,24 +456,22 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_
 
     SECITEM_FreeItem(&signature, PR_FALSE);
 
-    if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) {
-       /*
-        * RFC 3278 section section 2.1.1 states that the signatureAlgorithm 
-        * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey 
-        * as would appear in other forms of signed datas. However Microsoft doesn't 
-        * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, 
-        * MS can't verify - presumably because it takes the digest of the digest 
-        * before feeding it to ECDSA.
-        * We handle this with a preference; default if it's not there is 
-        * "Microsoft compatibility mode". 
-        */
-       if(!SecCmsMsEcdsaCompatMode()) {
-           pubkAlgTag = SEC_OID_ECDSA_WithSHA1;
-       }
-       /* else violating the spec for compatibility */
-    }
-
-    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
+    SECOidTag sigAlgTag = SecCmsUtilMakeSignatureAlgorithm(digestalgtag, pubkAlgTag);
+    if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY && SecCmsMsEcdsaCompatMode()) {
+        /*
+         * RFC 3278 section section 2.1.1 states that the signatureAlgorithm
+         * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey
+         * as would appear in other forms of signed datas. However Microsoft doesn't
+         * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there,
+         * MS can't verify - presumably because it takes the digest of the digest
+         * before feeding it to ECDSA.
+         * We handle this with a preference; default if it's not there is
+         * "Microsoft compatibility mode".
+         */
+        sigAlgTag = SEC_OID_EC_PUBLIC_KEY;
+    }
+
+    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), sigAlgTag,
                               NULL) != SECSuccess)
        goto loser;
 
@@ -599,16 +597,6 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
     digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
     digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
     
-    /*
-     * Gross hack necessitated by RFC 3278 section 2.1.1, which states 
-     * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1, 
-     * *not* (as in all other algorithms) the raw signature algorithm, e.g. 
-     * pkcs1RSAEncryption.
-     */
-    if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) {
-       digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY;
-    }
-    
     if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
        if (contentType) {
            /*
@@ -1182,12 +1170,19 @@ SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo)
     SecCertificateRef signercert;
     CFStringRef emailAddress = NULL;
 
-    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
-       return NULL;
-
-    SecCertificateGetEmailAddress(signercert, &emailAddress);
+    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL) {
+        return NULL;
+    }
 
-    return CFRetainSafe(emailAddress);
+    CFArrayRef names = SecCertificateCopyRFC822Names(signercert);
+    if (names) {
+        if (CFArrayGetCount(names) > 0) {
+            emailAddress = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
+        }
+        CFRetainSafe(emailAddress);
+        CFRelease(names);
+    }
+    return emailAddress;
 }
 
 
index 9718426cbacb0e66dc2cf8da1d97821326ca4224..85711fd175d0f248f79c82c48308415f1822a42b 100644 (file)
@@ -1158,9 +1158,10 @@ static OSStatus impExpImportCertUnCommon(
        }
 
 xit:
-    if (certRef)
+    if (certRef) {
         CFRelease(certRef);
-       return status;
+    }
+    return status;
 }
 
 static void saveTSACertificates(CSSM_DATA **signingCerts, CFMutableArrayRef    outArray)
index 342d03416acf774f2221ff0b0b7d41d27b1f40a2..6e627be2c9522f8edfe2f43ffb18c41819c4bc5e 100644 (file)
@@ -26,7 +26,6 @@
 #include <Security/keyTemplates.h>     /* for kSecAsn1AlgorithmIDTemplate */
 #include <Security/SecAsn1Templates.h>
 #include <stddef.h>
-#include <assert.h>
 
 #include "tsaTemplates.h"
 #include "cmslocal.h"
index 7af821b76b64ed0999e27fdcd268d13f7aedc26b..7981647390b157a4fa14aa24db5b9fd4344b6624 100644 (file)
@@ -102,12 +102,12 @@ out:
 }
 
 #define kNumberCleanupTests 1
-static void cleanup_keychain(SecKeychainRef keychain, SecIdentityRef identity, SecCertificateRef cert) {
+static void cleanup_keychain(SecKeychainRef* keychain, SecIdentityRef* identity, SecCertificateRef* cert) {
     /* Delete keychain - from the search list and from disk */
-    ok_status(SecKeychainDelete(keychain), "Delete temporary keychain");
-    CFReleaseNull(keychain);
-    CFReleaseNull(cert);
-    CFReleaseNull(identity);
+    ok_status(SecKeychainDelete(*keychain), "Delete temporary keychain");
+    CFReleaseNull(*keychain);
+    CFReleaseNull(*cert);
+    CFReleaseNull(*identity);
 }
 
 static OSStatus sign_please(SecIdentityRef identity, SECOidTag digestAlgTag, bool withAttrs, uint8_t *expected_output, size_t expected_len) {
@@ -370,7 +370,7 @@ static void sign_tests(SecIdentityRef identity, bool isRSA) {
     is(sign_please(identity, SEC_OID_SHA1, false, (isRSA) ? rsa_sha1 : NULL,
                    (isRSA) ? sizeof(rsa_sha1) : 0),
        errSecSuccess, "Signed with SHA-1");
-    is(sign_please(identity, SEC_OID_SHA256, false, (isRSA) ? rsa_sha256 : NULL,
+    is(sign_please(identity, SEC_OID_SHA256, false, (isRSA) ? new_sig_alg_rsa_sha256 : NULL,
                    (isRSA) ? sizeof(rsa_sha256) : 0),
        errSecSuccess, "Signed with SHA-256");
     is(sign_please(identity, SEC_OID_SHA384, false, NULL, 0), errSecSuccess, "Signed with SHA-384");
@@ -494,7 +494,7 @@ int cms_01_basic(int argc, char *const *argv)
     verify_tests(kc, true);
     encrypt_tests(certificate);
     decrypt_tests(true);
-    cleanup_keychain(kc, identity, certificate);
+    cleanup_keychain(&kc, &identity, &certificate);
 
     /* EC tests */
     kc = setup_keychain(_ec_identity, sizeof(_ec_identity), &identity, &certificate);
@@ -502,7 +502,7 @@ int cms_01_basic(int argc, char *const *argv)
     verify_tests(kc, false);
     encrypt_tests(certificate);
     decrypt_tests(false);
-    cleanup_keychain(kc, identity, certificate);
+    cleanup_keychain(&kc, &identity, &certificate);
 
     return 0;
 }
index 371b8f69bdf8d5fa2effe8371f7239003c0131b3..c7ad36b937ead3900c51b941ecc247ef98919e7c 100644 (file)
@@ -465,7 +465,7 @@ unsigned char rsa_sha1[] = {
     0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
     0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65,
     0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
-    0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00,
+    0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00,
     0x29, 0xbb, 0xc2, 0xc1, 0x17, 0xb9, 0x7d, 0x8b, 0x43, 0xc6, 0x25, 0xad, 0xf1, 0xae, 0xb6, 0x26, 0x78, 0x9c, 0x92, 0x47,
     0x77, 0xf8, 0xac, 0x53, 0xca, 0x17, 0x58, 0x4a, 0x8d, 0x66, 0x44, 0x99, 0x14, 0x3f, 0x63, 0x98, 0x3a, 0x7c, 0xe6, 0x65,
     0xf0, 0x2a, 0x5e, 0x49, 0xbe, 0xdd, 0x40, 0x6e, 0x21, 0x43, 0xe1, 0xb9, 0x13, 0xa8, 0x31, 0xbf, 0x12, 0xb2, 0x78, 0x97,
@@ -565,6 +565,89 @@ unsigned char rsa_sha256[] = {
     0x45, 0xc2, 0x99, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+unsigned char new_sig_alg_rsa_sha256[] = {
+    0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01,
+    0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x80, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x29, 0x54, 0x68, 0x69, 0x73,
+    0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x20,
+    0x41, 0x69, 0x6e, 0x27, 0x74, 0x20, 0x69, 0x74, 0x20, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x3f, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xa0, 0x82, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30, 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+    0x00, 0x30, 0x81, 0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53, 0x20, 0x52,
+    0x53, 0x41, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+    0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70, 0x70, 0x6c,
+    0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25, 0x53, 0x65,
+    0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61,
+    0x6e, 0x64, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06,
+    0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f,
+    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
+    0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31,
+    0x34, 0x30, 0x30, 0x31, 0x38, 0x32, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x34, 0x31, 0x33, 0x30, 0x30, 0x31, 0x38,
+    0x32, 0x39, 0x5a, 0x30, 0x81, 0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53,
+    0x20, 0x52, 0x53, 0x41, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70,
+    0x70, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25,
+    0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
+    0x20, 0x61, 0x6e, 0x64, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30,
+    0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21,
+    0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e,
+    0x61, 0x6d, 0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65, 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, 0xe2, 0x9b, 0xcb, 0x6c, 0x77, 0xb7, 0xd1, 0x05, 0xa0, 0xae, 0x86, 0x20, 0x45, 0xd3,
+    0xf4, 0x24, 0x8d, 0x25, 0x34, 0x31, 0xa9, 0xe2, 0x10, 0x36, 0xf5, 0x0a, 0x0b, 0x90, 0x4a, 0xa5, 0x6b, 0x5c, 0x16, 0xcd,
+    0xb0, 0x72, 0xe9, 0xa9, 0x80, 0x5f, 0x6d, 0xb2, 0x4d, 0xd9, 0x58, 0x16, 0x9f, 0x68, 0x81, 0x9a, 0x6b, 0xeb, 0xd5, 0x4b,
+    0xf7, 0x7d, 0x59, 0xe9, 0x46, 0x2b, 0x5b, 0x8f, 0xe4, 0xec, 0xab, 0x5c, 0x07, 0x74, 0xa2, 0x0e, 0x59, 0xbb, 0xfc, 0xd3,
+    0xcf, 0xf7, 0x21, 0x88, 0x6c, 0x88, 0xd9, 0x6b, 0xa3, 0xa3, 0x4e, 0x5b, 0xd1, 0x1c, 0xfb, 0x04, 0xf5, 0xb2, 0x12, 0x0e,
+    0x54, 0x59, 0x4d, 0xce, 0x0a, 0xe0, 0x26, 0x24, 0x06, 0xeb, 0xc8, 0xa2, 0xc6, 0x41, 0x28, 0xf9, 0x79, 0xe4, 0xb1, 0x4e,
+    0x00, 0x6f, 0x6e, 0xf8, 0x96, 0x9e, 0x45, 0x28, 0x70, 0xec, 0xc7, 0xdc, 0xa2, 0xdd, 0x92, 0xab, 0xdd, 0x6f, 0xd8, 0x57,
+    0xba, 0xcc, 0x29, 0xbe, 0xb7, 0x00, 0x1e, 0x8d, 0x13, 0x3f, 0x47, 0x34, 0x3c, 0xd0, 0xc6, 0xc8, 0x17, 0xdf, 0x74, 0x8a,
+    0xb1, 0xc3, 0x68, 0xd5, 0xba, 0x76, 0x60, 0x55, 0x5f, 0x8d, 0xfa, 0xbd, 0xe7, 0x11, 0x9e, 0x59, 0x96, 0xe5, 0x93, 0x70,
+    0xad, 0x41, 0xfb, 0x61, 0x46, 0x70, 0xc4, 0x05, 0x12, 0x23, 0x23, 0xc0, 0x9d, 0xc8, 0xc5, 0xf5, 0x96, 0xe5, 0x48, 0x10,
+    0x86, 0x8a, 0x1e, 0x3b, 0x83, 0xd1, 0x47, 0x3a, 0x27, 0x00, 0x71, 0x10, 0xa3, 0x52, 0xba, 0xae, 0x01, 0x43, 0x87, 0x9c,
+    0x6a, 0x1b, 0xea, 0x1a, 0x44, 0x4f, 0x4a, 0xac, 0xd4, 0x82, 0x55, 0xee, 0x1f, 0x25, 0x9c, 0x55, 0xca, 0xd2, 0xd0, 0x3a,
+    0x0b, 0x70, 0x90, 0x60, 0x49, 0x47, 0x02, 0xfd, 0x89, 0x2c, 0x9a, 0x26, 0x36, 0x34, 0x8f, 0x24, 0x39, 0x8c, 0xe9, 0xa2,
+    0x52, 0x8f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x13, 0x30, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+    0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+    0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4c, 0xed, 0x5b, 0xaf, 0x13, 0x16, 0x5d, 0xe2, 0xdd, 0x5c, 0x48, 0x1c,
+    0xd5, 0x6e, 0x8b, 0x04, 0x51, 0xd6, 0x38, 0x80, 0xfd, 0x52, 0x4a, 0x34, 0xdc, 0x13, 0x35, 0x6e, 0x64, 0x39, 0x39, 0x39,
+    0x09, 0xa7, 0x6c, 0x2d, 0x39, 0xf2, 0x04, 0x21, 0xe3, 0xea, 0x8f, 0xf8, 0xbe, 0x46, 0x0e, 0x20, 0x82, 0xd0, 0xc5, 0x60,
+    0xbf, 0x57, 0x6f, 0xd8, 0x29, 0xb4, 0x66, 0xdb, 0xbf, 0x92, 0xc9, 0xdc, 0x90, 0x97, 0x0f, 0x2f, 0x59, 0xa0, 0x13, 0xf3,
+    0xa4, 0xca, 0xde, 0x3f, 0x80, 0x2a, 0x99, 0xb4, 0xee, 0x71, 0xc3, 0x56, 0x71, 0x51, 0x37, 0x55, 0xa1, 0x60, 0x89, 0xab,
+    0x94, 0x0e, 0xb9, 0x70, 0xa5, 0x55, 0xf3, 0x1a, 0x87, 0xa4, 0x41, 0x4c, 0x45, 0xba, 0xb6, 0x56, 0xd6, 0x45, 0x56, 0x12,
+    0x60, 0xe5, 0x91, 0xec, 0xf7, 0xbe, 0x39, 0xa4, 0x80, 0x08, 0x9f, 0xea, 0x17, 0x12, 0x0e, 0xa6, 0xe6, 0xef, 0x09, 0xf7,
+    0x61, 0x51, 0x57, 0x73, 0xe3, 0x57, 0x88, 0xd7, 0xf8, 0x5f, 0xaf, 0x5d, 0xaf, 0x88, 0x32, 0xb4, 0x09, 0x3e, 0x7c, 0x25,
+    0x77, 0x35, 0xe9, 0x3e, 0x6e, 0x0a, 0xb9, 0xb4, 0xa3, 0x06, 0x07, 0x0f, 0x7e, 0x93, 0x26, 0x16, 0x38, 0x1e, 0x4e, 0x72,
+    0xaf, 0x06, 0x44, 0x1e, 0x8d, 0x96, 0xa6, 0x15, 0x9c, 0x82, 0x6d, 0x71, 0x99, 0x84, 0x8d, 0x12, 0x46, 0xf2, 0xbb, 0xa7,
+    0x63, 0x7a, 0x32, 0xda, 0xa9, 0xde, 0xb6, 0x34, 0x14, 0xfb, 0x07, 0x0c, 0xab, 0x3b, 0x0a, 0xa1, 0x8b, 0xda, 0x15, 0xb3,
+    0x63, 0xf3, 0x5c, 0x45, 0x2f, 0x0b, 0x6e, 0xc7, 0x27, 0x72, 0xc1, 0x37, 0x56, 0x30, 0xe3, 0x26, 0xbb, 0x19, 0x4f, 0x91,
+    0xa1, 0xd0, 0x30, 0x29, 0x5b, 0x79, 0x79, 0x5c, 0xe6, 0x4f, 0xed, 0xcf, 0x81, 0xb2, 0x50, 0x35, 0x96, 0x23, 0xb2, 0x9f,
+    0xca, 0x3f, 0xb5, 0x54, 0x31, 0x82, 0x01, 0xdc, 0x30, 0x82, 0x01, 0xd8, 0x02, 0x01, 0x01, 0x30, 0x81, 0xb0, 0x30, 0x81,
+    0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53, 0x20, 0x52, 0x53, 0x41, 0x20,
+    0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+    0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20,
+    0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+    0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+    0x01, 0x0b, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc9, 0x25, 0xbe, 0xb8, 0xf2, 0x2c, 0x7f, 0xc8, 0x3a, 0xc3, 0xc2, 0x4b,
+    0xac, 0x54, 0xcf, 0xa6, 0x75, 0xaa, 0xeb, 0x40, 0x68, 0xee, 0xe2, 0xb1, 0xa8, 0x70, 0x9e, 0xe9, 0x8b, 0xf1, 0x0a, 0x85,
+    0x88, 0x40, 0xef, 0xb8, 0xa5, 0x04, 0x87, 0x63, 0x03, 0xf5, 0x41, 0x81, 0x29, 0x42, 0x7f, 0x31, 0x8f, 0x5b, 0xde, 0xe8,
+    0x15, 0xc1, 0xa3, 0x45, 0xf1, 0xbc, 0xff, 0x81, 0x58, 0xbd, 0xac, 0x4c, 0xa5, 0xb3, 0x30, 0x9a, 0xb8, 0x9e, 0x69, 0x10,
+    0xad, 0x44, 0x7b, 0x93, 0x28, 0xba, 0xca, 0x6f, 0x2e, 0xf8, 0x1b, 0x03, 0xc2, 0x0a, 0x4a, 0x06, 0x32, 0x4d, 0x30, 0x50,
+    0xb7, 0x9c, 0x57, 0x4d, 0x4b, 0x6c, 0x34, 0x53, 0xd8, 0xf5, 0xca, 0x91, 0xa5, 0xdf, 0xa6, 0x67, 0x0a, 0x2e, 0x02, 0x47,
+    0x1c, 0x1c, 0xd6, 0x2b, 0xe2, 0x85, 0xc1, 0xda, 0x79, 0xa2, 0xe2, 0x1e, 0xf8, 0x5e, 0xf9, 0x76, 0x55, 0xaf, 0x61, 0xaf,
+    0xde, 0x0a, 0x7b, 0xeb, 0xa1, 0xa8, 0xc6, 0xef, 0x76, 0x2f, 0x50, 0xd1, 0x0a, 0xce, 0xdb, 0x14, 0xc3, 0x13, 0x72, 0xe5,
+    0x26, 0x67, 0x90, 0x19, 0x15, 0x7b, 0x79, 0x05, 0xeb, 0x20, 0xb3, 0x5a, 0x4e, 0x78, 0xae, 0x2d, 0x9c, 0xd1, 0x31, 0xfd,
+    0x2e, 0xcb, 0x84, 0xb9, 0x67, 0xea, 0xaf, 0xb3, 0xc2, 0x5f, 0xf5, 0xcd, 0x7b, 0x66, 0x3f, 0xdf, 0xf7, 0xe7, 0x76, 0x46,
+    0x57, 0xd9, 0xee, 0x4b, 0xb2, 0xc8, 0x7b, 0xf9, 0x88, 0xab, 0x8e, 0xca, 0xfc, 0x39, 0xd1, 0x8e, 0x1c, 0xba, 0x3e, 0x63,
+    0xb7, 0xe8, 0x0e, 0x2f, 0xde, 0x6b, 0x76, 0x81, 0xbf, 0x78, 0x26, 0x0c, 0xa0, 0x2c, 0x35, 0x21, 0xde, 0xb4, 0x45, 0x0a,
+    0x84, 0xea, 0x68, 0xa5, 0x37, 0xe8, 0x4a, 0xbc, 0xa6, 0xcf, 0x24, 0x85, 0x46, 0x33, 0x9e, 0xd9, 0xba, 0x58, 0x75, 0xd7,
+    0x45, 0xc2, 0x99, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
 /*
  * MARK: RSA-signed messages (with attributes)
  */
@@ -726,7 +809,7 @@ unsigned char rsa_sha1_attr[] = {
     0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31, 0x38, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5a, 0x30,
     0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0xef, 0x53, 0x0b, 0xfa,
     0xcf, 0x34, 0x18, 0xb3, 0x30, 0xff, 0xf8, 0x9e, 0x09, 0xb3, 0xb6, 0x21, 0xd6, 0x83, 0xb9, 0xe9, 0x30, 0x0d, 0x06, 0x09,
-    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x52, 0xbd, 0xa1, 0x0a, 0x41,
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x52, 0xbd, 0xa1, 0x0a, 0x41,
     0xce, 0xc1, 0xe8, 0xe8, 0x2f, 0x2e, 0x1f, 0x73, 0xd1, 0x2f, 0x2e, 0x53, 0x53, 0x21, 0xec, 0x88, 0x30, 0x6a, 0x9d, 0x58,
     0x64, 0x95, 0xef, 0xf2, 0x20, 0x55, 0xb0, 0x15, 0x64, 0x02, 0x1d, 0xf9, 0x44, 0xdd, 0xcb, 0x7a, 0x9c, 0x50, 0x10, 0xea,
     0xfa, 0x6f, 0x07, 0x64, 0xaf, 0x30, 0x6e, 0xe2, 0xc1, 0x34, 0x55, 0xd0, 0x6a, 0x6e, 0xe1, 0x09, 0x91, 0xb7, 0xe3, 0x7b,
@@ -814,7 +897,7 @@ unsigned char rsa_sha256_attr[] = {
     0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04,
     0x31, 0x22, 0x04, 0x20, 0x33, 0x1f, 0x3a, 0xc4, 0x95, 0x97, 0x64, 0x1c, 0x99, 0x9b, 0x37, 0xc8, 0xf2, 0xba, 0xd0, 0xb4,
     0x38, 0xa5, 0x9c, 0x3a, 0xa3, 0x78, 0xf9, 0xfb, 0x66, 0x28, 0x4e, 0x6a, 0x90, 0xcc, 0x0e, 0x4c, 0x30, 0x0d, 0x06, 0x09,
-    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xae, 0x6d, 0xa9, 0xa7, 0xee,
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xae, 0x6d, 0xa9, 0xa7, 0xee,
     0x0c, 0x94, 0x1b, 0xf3, 0x93, 0x40, 0x43, 0x11, 0x41, 0x20, 0x11, 0x60, 0xd9, 0x4e, 0xb6, 0x2d, 0x3e, 0x98, 0xfe, 0x06,
     0xd2, 0xc4, 0xe4, 0x0a, 0x66, 0xdc, 0xbb, 0xbd, 0x4d, 0x8e, 0xcb, 0xe1, 0x87, 0x39, 0x3f, 0xb3, 0x4b, 0xf8, 0xe7, 0x18,
     0x6f, 0x39, 0xad, 0x01, 0xd4, 0xe8, 0x85, 0x8c, 0x84, 0x96, 0x2c, 0x3a, 0xd4, 0xcf, 0x3c, 0xe5, 0x05, 0xdd, 0xc7, 0xc0,
diff --git a/OSX/libsecurity_ssl/Security b/OSX/libsecurity_ssl/Security
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index 0a4ac1153b22b291d9caa4e4dbbf6becdab6d84a..a4e737ffdd440d47c420c3f1c99abadadea35da4 100644 (file)
@@ -36,7 +36,7 @@
  * Defined as enum for debugging, but in the protocol
  * it is actually exactly two bytes
  */
-#if TARGET_OS_IPHONE && !TARGET_OS_IOSMAC
+#if ((TARGET_OS_IPHONE && !TARGET_OS_MACCATALYST) || (TARGET_OS_OSX && TARGET_CPU_ARM64))
 /* 16-bit value on iOS */
 typedef uint16_t SSLCipherSuite;
 #else
index 8da7af2a113306fda4626ca0df71e486f17947a4..28cf1a6b057cc8499d6a80e87125ae27055b27c3 100644 (file)
@@ -330,8 +330,8 @@ SSLRecordSetOption(SSLRecordContextRef ref, SSLRecordOption option, bool value)
 
 /***** Internal Record Layer APIs *****/
 
-#include <CommonCrypto/CommonRandomSPI.h>
-#define CCRNGSTATE ccDRBGGetRngState()
+#include <corecrypto/ccrng.h>
+#define CCRNGSTATE ccrng(NULL)
 
 SSLRecordContextRef
 SSLCreateInternalRecordLayer(SSLContextRef sslCtx)
index f7a6c5f9c4037b01883f7719e4bbd2877696ec49..34e7521a96acd3d025e40b21147cd2e8cfbbcfbf 100644 (file)
@@ -516,7 +516,7 @@ OSStatus SSLGetDHEEnabled(SSLContextRef ctx, bool *enabled);
 OSStatus
 _SSLSetProtocolVersionEnabled (SSLContextRef   context,
                               SSLProtocol              protocol,
-                               Boolean                 enable) API_UNAVAILABLE(iosmac);
+                               Boolean                 enable) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain a value specified in SSLSetProtocolVersionEnabled.
@@ -526,7 +526,7 @@ _SSLSetProtocolVersionEnabled (SSLContextRef        context,
 OSStatus
 _SSLGetProtocolVersionEnabled(SSLContextRef            context,
                              SSLProtocol               protocol,
-                              Boolean                  *enable) API_UNAVAILABLE(iosmac);               /* RETURNED */
+                              Boolean                  *enable) API_UNAVAILABLE(macCatalyst);          /* RETURNED */
 
 /*
  * Get/set SSL protocol version; optional. Default is kSSLProtocolUnknown,
@@ -541,7 +541,7 @@ _SSLGetProtocolVersionEnabled(SSLContextRef                 context,
  */
 OSStatus
 _SSLSetProtocolVersion         (SSLContextRef          context,
-                             SSLProtocol               version) API_UNAVAILABLE(iosmac);
+                             SSLProtocol               version) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain the protocol version specified in SSLSetProtocolVersion.
@@ -555,7 +555,7 @@ _SSLSetProtocolVersion              (SSLContextRef          context,
  */
 OSStatus
 _SSLGetProtocolVersion         (SSLContextRef          context,
-                             SSLProtocol               *protocol) API_UNAVAILABLE(iosmac);             /* RETURNED */
+                             SSLProtocol               *protocol) API_UNAVAILABLE(macCatalyst);                /* RETURNED */
 
 /* API REVIEW:
  The following 15 calls were used to change the behaviour of the trust
@@ -573,11 +573,11 @@ _SSLGetProtocolVersion            (SSLContextRef          context,
  */
 OSStatus
 _SSLSetEnableCertVerify                (SSLContextRef                  context,
-                             Boolean                           enableVerify) API_UNAVAILABLE(iosmac);
+                             Boolean                           enableVerify) API_UNAVAILABLE(macCatalyst);
 
 OSStatus
 _SSLGetEnableCertVerify                (SSLContextRef                  context,
-                             Boolean                           *enableVerify) API_UNAVAILABLE(iosmac); /* RETURNED */
+                             Boolean                           *enableVerify) API_UNAVAILABLE(macCatalyst);    /* RETURNED */
 
 /*
  * Specify the option of ignoring certificates' "expired" times.
@@ -587,14 +587,14 @@ _SSLGetEnableCertVerify           (SSLContextRef                  context,
  */
 OSStatus
 _SSLSetAllowsExpiredCerts      (SSLContextRef          context,
-                             Boolean                   allowsExpired) API_UNAVAILABLE(iosmac);
+                             Boolean                   allowsExpired) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain the current value of an SSLContext's "allowExpiredCerts" flag.
  */
 OSStatus
 _SSLGetAllowsExpiredCerts      (SSLContextRef          context,
-                             Boolean                   *allowsExpired) API_UNAVAILABLE(iosmac); /* RETURNED */
+                             Boolean                   *allowsExpired) API_UNAVAILABLE(macCatalyst); /* RETURNED */
 
 /*
  * Similar to SSLSetAllowsExpiredCerts(), this function allows the
@@ -604,11 +604,11 @@ _SSLGetAllowsExpiredCerts (SSLContextRef          context,
  */
 OSStatus
 _SSLSetAllowsExpiredRoots      (SSLContextRef          context,
-                             Boolean                   allowsExpired) API_UNAVAILABLE(iosmac);
+                             Boolean                   allowsExpired) API_UNAVAILABLE(macCatalyst);
 
 OSStatus
 _SSLGetAllowsExpiredRoots      (SSLContextRef          context,
-                             Boolean                   *allowsExpired) API_UNAVAILABLE(iosmac); /* RETURNED */
+                             Boolean                   *allowsExpired) API_UNAVAILABLE(macCatalyst); /* RETURNED */
 
 /*
  * Specify option of allowing for an unknown root cert, i.e., one which
@@ -627,14 +627,14 @@ _SSLGetAllowsExpiredRoots (SSLContextRef          context,
  */
 OSStatus
 _SSLSetAllowsAnyRoot                   (SSLContextRef          context,
-                                 Boolean                       anyRoot) API_UNAVAILABLE(iosmac);
+                                 Boolean                       anyRoot) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain the current value of an SSLContext's "allow any root" flag.
  */
 OSStatus
 _SSLGetAllowsAnyRoot                   (SSLContextRef          context,
-                                 Boolean                       *anyRoot) API_UNAVAILABLE(iosmac); /* RETURNED */
+                                 Boolean                       *anyRoot) API_UNAVAILABLE(macCatalyst); /* RETURNED */
 
 /*
  * Augment or replace the system's default trusted root certificate set
@@ -651,7 +651,7 @@ _SSLGetAllowsAnyRoot                        (SSLContextRef          context,
 OSStatus
 _SSLSetTrustedRoots                    (SSLContextRef          context,
                              CFArrayRef                trustedRoots,
-                             Boolean                   replaceExisting) API_UNAVAILABLE(iosmac);
+                             Boolean                   replaceExisting) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain an array of SecCertificateRefs representing the current
@@ -662,7 +662,7 @@ _SSLSetTrustedRoots                 (SSLContextRef          context,
  */
 OSStatus
 _SSLCopyTrustedRoots                   (SSLContextRef          context,
-                                 CFArrayRef            *trustedRoots) API_UNAVAILABLE(iosmac); /* RETURNED */
+                                 CFArrayRef            *trustedRoots) API_UNAVAILABLE(macCatalyst);    /* RETURNED */
 
 /*
  * Add a SecCertificateRef, or a CFArray of them, to a server's list
@@ -680,7 +680,7 @@ _SSLCopyTrustedRoots                        (SSLContextRef          context,
 OSStatus
 _SSLSetCertificateAuthorities(SSLContextRef            context,
                              CFTypeRef                 certificateOrArray,
-                              Boolean                  replaceExisting) API_UNAVAILABLE(iosmac);
+                              Boolean                  replaceExisting) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Obtain the certificates specified in SSLSetCertificateAuthorities(),
@@ -691,7 +691,7 @@ _SSLSetCertificateAuthorities(SSLContextRef         context,
 
 OSStatus
 _SSLCopyCertificateAuthorities(SSLContextRef           context,
-                              CFArrayRef               *certificates) API_UNAVAILABLE(iosmac); /* RETURNED */
+                              CFArrayRef               *certificates) API_UNAVAILABLE(macCatalyst);    /* RETURNED */
 
 /*
  * Request peer certificates. Valid anytime, subsequent to
@@ -716,7 +716,7 @@ _SSLCopyCertificateAuthorities(SSLContextRef                context,
  */
 OSStatus
 _SSLCopyPeerCertificates               (SSLContextRef          context,
-                             CFArrayRef                        *certs) API_UNAVAILABLE(iosmac);        /* RETURNED */
+                             CFArrayRef                        *certs) API_UNAVAILABLE(macCatalyst);   /* RETURNED */
 
 /*
  * Specify Diffie-Hellman parameters. Optional; if we are configured to allow
@@ -726,7 +726,7 @@ _SSLCopyPeerCertificates            (SSLContextRef          context,
  */
 OSStatus _SSLSetDiffieHellmanParams    (SSLContextRef                  context,
                                      const void                        *dhParams,
-                                     size_t                                    dhParamsLen) API_UNAVAILABLE(iosmac);
+                                     size_t                                    dhParamsLen) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Return parameter block specified in SSLSetDiffieHellmanParams.
@@ -734,7 +734,7 @@ OSStatus _SSLSetDiffieHellmanParams (SSLContextRef                  context,
  */
 OSStatus _SSLGetDiffieHellmanParams    (SSLContextRef                  context,
                                      const void                        **dhParams,
-                                     size_t                                    *dhParamsLen) API_UNAVAILABLE(iosmac);
+                                     size_t                                    *dhParamsLen) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Enable/Disable RSA blinding. This feature thwarts a known timing
@@ -743,10 +743,10 @@ OSStatus _SSLGetDiffieHellmanParams       (SSLContextRef                  context,
  * enabled.
  */
 OSStatus _SSLSetRsaBlinding                    (SSLContextRef                  context,
-                                     Boolean                           blinding) API_UNAVAILABLE(iosmac);
+                                     Boolean                           blinding) API_UNAVAILABLE(macCatalyst);
 
 OSStatus _SSLGetRsaBlinding                    (SSLContextRef                  context,
-                                     Boolean                           *blinding) API_UNAVAILABLE(iosmac);
+                                     Boolean                           *blinding) API_UNAVAILABLE(macCatalyst);
 
 /*
  * Create a new SSL/TLS session context.
@@ -754,14 +754,14 @@ OSStatus _SSLGetRsaBlinding                       (SSLContextRef                  context,
  */
 OSStatus
 _SSLNewContext                         (Boolean                        isServer,
-                             SSLContextRef             *tlsContextPtr) API_UNAVAILABLE(iosmac);     /* RETURNED */
+                             SSLContextRef             *tlsContextPtr) API_UNAVAILABLE(macCatalyst);     /* RETURNED */
 
 /*
  * Dispose of an SSLContextRef.  This is effectivly a CFRelease.
  * Deprecated.
  */
 OSStatus
-_SSLDisposeContext                     (SSLContextRef          context) API_UNAVAILABLE(iosmac);
+_SSLDisposeContext                     (SSLContextRef          context) API_UNAVAILABLE(macCatalyst);
 
 /* We redefine the names of all SPIs to avoid collision with unavailable APIs */
 #define SSLSetProtocolVersionEnabled _SSLSetProtocolVersionEnabled
@@ -807,7 +807,7 @@ _SSLProtocolVersionToWireFormatValue   (SSLProtocol protocol);
  */
 OSStatus
 SSLNewDatagramContext          (Boolean                        isServer,
-                             SSLContextRef             *dtlsContextPtr) API_UNAVAILABLE(iosmac);       /* RETURNED */
+                             SSLContextRef             *dtlsContextPtr) API_UNAVAILABLE(macCatalyst);  /* RETURNED */
 
 
 
index 47588641ed85d677a6a0cf1069e0e80f52e0f89e..8633fbef60d2bf9b7c9b7a059e311caf0fbe2afb 100644 (file)
@@ -36,7 +36,6 @@
 #include <tls_handshake.h>
 
 #include <string.h>
-#include <assert.h>
 #include <Security/SecBase.h>
 #include <Security/SecureTransportPriv.h>
 
index fc1826feb498ef885f4980884d2c4e133d3f3cb4..26e01a85e2aa9a1f934bcf46422061730a1231e9 100644 (file)
@@ -2246,21 +2246,23 @@ SSLCopyPeerTrust(
     SSLContextRef              ctx,
     SecTrustRef        *trust) /* RETURNED */
 {
-       OSStatus status = errSecSuccess;
-       if (ctx == NULL || trust == NULL)
-               return errSecParam;
+    OSStatus status = errSecSuccess;
+    if (ctx == NULL || trust == NULL) {
+        return errSecParam;
+    }
 
-       /* Create a SecTrustRef if this was a resumed session and we
-          didn't have one yet. */
-       if (!ctx->peerSecTrust) {
-               status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
+    /* Create a SecTrustRef if this was a resumed session and we
+     didn't have one yet. */
+    if (!ctx->peerSecTrust) {
+        status = sslCreateSecTrust(ctx, &ctx->peerSecTrust);
     }
 
-       *trust = ctx->peerSecTrust;
-    if (ctx->peerSecTrust)
+    *trust = ctx->peerSecTrust;
+    if (ctx->peerSecTrust) {
         CFRetain(ctx->peerSecTrust);
+    }
 
-       return status;
+    return status;
 }
 
 OSStatus SSLGetPeerSecTrust(
index e26fff2fd14a87a7307b4d892aa4a1fb01cc8547..bd4c071cec87281ebcb8a264d87f1894f173cb11 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
+#include "utilities/simulatecrash_assert.h"
 
 #include <Security/SecTrustPriv.h>
 #include <Security/SecPolicy.h>
index 387c34ab052c888c07722890d20ddead5704b1bc..9c4c997cb2f62982b1e43bef9420bbb97ca75860 100644 (file)
@@ -41,7 +41,7 @@
 #include "sslDebug.h"
 #include "sslKeychain.h"
 #include <string.h>
-#include <assert.h>
+#include "utilities/simulatecrash_assert.h"
 
 
 #include <Security/Security.h>
index d5ec8974e54aca25da9bfe9e637bfca0b4c72b51..564b36146fe1f469a8f425613e209a0bc8cc813a 100644 (file)
@@ -34,7 +34,6 @@
 #include "SSLRecordInternal.h"
 
 #include <string.h>
-#include <assert.h>
 
 #include <utilities/SecIOFormat.h>
 
index c22cf5002d3e7ff4897b4336c7738d78a7f444bd..a56d10d71d7eb826df9fb2df80fcf15dbce2f4f8 100644 (file)
 #include "sslDebug.h"
 #include "sslCipherSpecs.h"
 
-#include <assert.h>
+#include <utilities/simulatecrash_assert.h>
 #include <string.h>
 
 #include <utilities/SecIOFormat.h>
 #include <utilities/SecCFWrappers.h>
+#import <utilities/SecCoreAnalytics.h>
 
 #include <CommonCrypto/CommonDigest.h>
 #include <Security/SecCertificatePriv.h>
@@ -476,14 +477,12 @@ SSLHandshake(SSLContext *ctx)
 
 #if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
 
-#include "SecADWrapper.h"
-
 static void ad_log_SecureTransport_early_fail(long signature)
 {
     CFStringRef key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("com.apple.SecureTransport.early_fail.%ld"), signature);
 
     if (key) {
-        SecADAddValueForScalarKey(key, 1);
+        SecCoreAnalyticsSendValue(key, 1);
         CFRelease(key);
     }
 }
index d17e73d46f76fb0ee7d45bc1f35eaf55f3a910c2..13a2c8c7ce657f8bcca547710fc4a07995a5faae 100644 (file)
@@ -35,6 +35,8 @@
 #include <tls_helpers.h>
 #include <tls_cache.h>
 
+#include "utilities/simulatecrash_assert.h"
+
 static
 int tls_handshake_write_callback(tls_handshake_ctx_t ctx, const SSLBuffer data, uint8_t content_type)
 {
index 9eaa1ff75caf1f689f217822f5fe6b0fc17f8b0c..11cd14472eaac88892bba41b158f384f7111b208 100644 (file)
@@ -86,6 +86,7 @@ static int SocketConnect(const char *hostName, int port)
     int                                        sock;
     int                 err;
     struct hostent      *ent;
+    char **h_addr_list = NULL;
 
     if (hostName[0] >= '0' && hostName[0] <= '9') {
         host.s_addr = inet_addr(hostName);
@@ -95,11 +96,14 @@ static int SocketConnect(const char *hostName, int port)
             printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno));
             return -2;
         }
-        memcpy(&host, ent->h_addr, sizeof(struct in_addr));
+        h_addr_list = malloc(sizeof(char *));
+        memcpy(h_addr_list, ent->h_addr_list, sizeof(char *));
+        memcpy(&host, h_addr_list[0], sizeof(struct in_addr));
     }
 
     sock = socket(AF_INET, SOCK_STREAM, 0);
-    addr.sin_addr = host;
+    addr.sin_addr.s_addr = host.s_addr;
+    free(h_addr_list);
     addr.sin_port = htons((u_short)port);
 
     addr.sin_family = AF_INET;
@@ -113,7 +117,6 @@ static int SocketConnect(const char *hostName, int port)
 
     /* make non blocking */
     fcntl(sock, F_SETFL, O_NONBLOCK);
-
     return sock;
 }
 
index 441ae28320178e2649d6a1ca8fd02d0027456428..657402e86ae2376b2c5b4e85261d9e0e6f848a71 100644 (file)
@@ -46,9 +46,8 @@
 
 #define test_printf(x...)
 
-/* extern struct ccrng_state *ccDRBGGetRngState(); */
-#include <CommonCrypto/CommonRandomSPI.h>
-#define CCRNGSTATE ccDRBGGetRngState()
+#include <corecrypto/ccrng.h>
+#define CCRNGSTATE ccrng(NULL)
 
 struct RecQueueItem {
     STAILQ_ENTRY(RecQueueItem) next; /* link to next queued entry or NULL */
index adaa8a98e22e28a990bfcab8c86dfd505016f518..9c20b57cc44770acf874dec3b73648ab80c34552 100644 (file)
@@ -100,6 +100,7 @@ static int SocketConnect(const char *hostName, int port)
        int                                     sock;
     int                 err;
     struct hostent      *ent;
+    char **h_addr_list = NULL;
 
     if (hostName[0] >= '0' && hostName[0] <= '9') {
         host.s_addr = inet_addr(hostName);
@@ -109,11 +110,14 @@ static int SocketConnect(const char *hostName, int port)
                        printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno));
             return -2;
         }
-        memcpy(&host, ent->h_addr, sizeof(struct in_addr));
+        h_addr_list = malloc(sizeof(char *));
+        memcpy(h_addr_list, ent->h_addr_list, sizeof(char *));
+        memcpy(&host, h_addr_list[0], sizeof(struct in_addr));
     }
 
     sock = socket(AF_INET, SOCK_STREAM, 0);
-    addr.sin_addr = host;
+    addr.sin_addr.s_addr = host.s_addr;
+    free(h_addr_list);
     addr.sin_port = htons((u_short)port);
 
     addr.sin_family = AF_INET;
diff --git a/OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_ios.xctestplan b/OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_ios.xctestplan
new file mode 100644 (file)
index 0000000..9b1a6a2
--- /dev/null
@@ -0,0 +1,24 @@
+{
+  "configurations" : [
+    {
+      "id" : "5A402836-E1DD-4825-904B-BFAEC12C977B",
+      "name" : "Configuration 1",
+      "options" : {
+
+      }
+    }
+  ],
+  "defaultOptions" : {
+
+  },
+  "testTargets" : [
+    {
+      "target" : {
+        "containerPath" : "container:Security.xcodeproj",
+        "identifier" : "3DD1FFAC201FDB1D0086D049",
+        "name" : "SecureTransportTests_ios"
+      }
+    }
+  ],
+  "version" : 1
+}
diff --git a/OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_macos.xctestplan b/OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_macos.xctestplan
new file mode 100644 (file)
index 0000000..ec8f30d
--- /dev/null
@@ -0,0 +1,24 @@
+{
+  "configurations" : [
+    {
+      "id" : "C4B1D35D-6AAD-4F4E-A674-0453730B68EB",
+      "name" : "Configuration 1",
+      "options" : {
+
+      }
+    }
+  ],
+  "defaultOptions" : {
+
+  },
+  "testTargets" : [
+    {
+      "target" : {
+        "containerPath" : "container:Security.xcodeproj",
+        "identifier" : "3DD1FEF5201C07F30086D049",
+        "name" : "SecureTransportTests_macos"
+      }
+    }
+  ],
+  "version" : 1
+}
index ef1755a23b0347c641174c9f4811edb369a373ea..539e487630f23e40d5da4b082b206d7f265b27d3 100644 (file)
                        <string>/AppleInternal/XCTests/com.apple.security/</string>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest Self SecureTransport_ios_tests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string> -ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>Self</string>
+                               <string>SecureTransport_ios_tests.xctest</string>
                        </array>
                </dict>
        </array>
index 64a927ab6f83b68ea64b82e98c0c36e76db9b9b2..266c4f5644f706732485522aace2acfff837af11 100644 (file)
                        <string>/AppleInternal/XCTests/com.apple.security/</string>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD -NSTreatUnknownArgumentsAsOpen NO -ApplePersistenceIgnoreState YES -XCTest Self SecureTransport_macos_tests.xctest</string>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>Self</string>
+                               <string>SecureTransport_macos_tests.xctest</string>
                        </array>
                </dict>
        </array>
index b20a9b020c7929f97a44e3cd2f0a1550f029dc42..bc766e708d0ce31d58963f0ef0e4ac658e7c645a 100644 (file)
@@ -185,7 +185,7 @@ ssl_test_handle_create(int comm, CFArrayRef certs)
 static void *securetransport_ssl_thread(void *arg)
 {
     OSStatus ortn;
-    int sock = (int)arg;
+    int sock = *((int*)arg);
 
     int socket = accept(sock, NULL, NULL);
 
@@ -244,7 +244,7 @@ tests(void)
     }
     //fprintf(stderr, "session_id: %d\n", session_id);
 
-    pthread_create(&server_thread, NULL, securetransport_ssl_thread, (void*)socket);
+    pthread_create(&server_thread, NULL, securetransport_ssl_thread, (void*)&socket);
 
     system("/usr/bin/openssl s_client -msg -debug -connect localhost:4443");
 
index 91a48385dd5167928d53d9091f56ea5670a38627..f58405006f726f4c43fa22b90e183fc0de854e45 100644 (file)
@@ -46,9 +46,8 @@
 
 #define test_printf(x...)
 
-/* extern struct ccrng_state *ccDRBGGetRngState(); */
-#include <CommonCrypto/CommonRandomSPI.h>
-#define CCRNGSTATE ccDRBGGetRngState()
+#include <corecrypto/ccrng.h>
+#define CCRNGSTATE ccrng(NULL)
 
 struct RecQueueItem {
     STAILQ_ENTRY(RecQueueItem) next; /* link to next queued entry or NULL */
diff --git a/OSX/libsecurity_ssl/security_ssl b/OSX/libsecurity_ssl/security_ssl
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index 28e1048493b00bcb97adca294dfc7c9a96f3aab0..1327a2e85b0501a642fefe558270c61f1723c3bf 100644 (file)
@@ -24,7 +24,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include "SecEncodeTransform.h"
+#include <Security/SecEncodeTransform.h>
 
 #ifdef __cplusplus
 extern "C" {
index d61f6e2df8196e992e9ddb91b39acd91fc5a63df..00e0a9e18a2999c1bd5e3ddc43fd1d98dd4813e6 100644 (file)
@@ -25,7 +25,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include "SecTransform.h"
+#include <Security/SecTransform.h>
 
 #ifdef __cplusplus
 extern "C" {
index 499b242fff662d3fec75fbf80650e355aafe5b75..169bbf79d0f1007e43264539797f7f468959f3cf 100644 (file)
@@ -24,7 +24,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include "SecTransform.h"
+#include <Security/SecTransform.h>
 
 #ifdef __cplusplus
 extern "C" {
index 0a744fcfedf656333825d9d07e8e9f026fe77282..541d1ce1ddf385fdc26ed612b1222a16b4db5db7 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <Security/SecKey.h>
-#include "SecTransform.h"
+#include <Security/SecTransform.h>
 
 #ifdef __cplusplus
 extern "C" {
index a4665279f40b4f496a732620aea06854df0c1594..00f5cbedfa7e6139d0a76b8db2cccf6183ec6c51 100644 (file)
@@ -27,7 +27,9 @@
 #include "Utilities.h"
 #include <Security/Security.h>
 #include "misc.h"
-#include <mach-o/dyld_priv.h> // for dyld_get_program_sdk_version
+#include <mach-o/dyld_priv.h>
+
+#include "simulatecrash_assert.h"
 
 const static CFStringRef SignName = CFSTR("com.apple.security.Sign"), VerifyName = CFSTR("com.apple.security.Verify");
 const CFStringRef __nonnull kSecKeyAttributeName = CFSTR("KEY"), kSecSignatureAttributeName = CFSTR("Signature"), kSecInputIsAttributeName = CFSTR("InputIs");
@@ -410,8 +412,8 @@ static SecTransformInstanceBlock SignTransform(CFStringRef name,
                                OSStatus rc = SecKeyGetCSSMKey(key, &cssm_key);
                                SEC_FAIL(rc);
 
-                if (((!cssm_key->KeyHeader.KeyUsage) & CSSM_KEYUSE_SIGN)               // Keep the previous test to be compatible with existing apps
-                    || ((dyld_get_program_sdk_version() >= DYLD_MACOSX_VERSION_10_13)  // Better check for newly compiled apps
+                if (((!cssm_key->KeyHeader.KeyUsage) & CSSM_KEYUSE_SIGN)
+                    || (dyld_program_sdk_at_least(dyld_platform_version_macOS_10_13) // Keep the previous test to be compatible with existing apps
                         && !(cssm_key->KeyHeader.KeyUsage & (CSSM_KEYUSE_SIGN|CSSM_KEYUSE_ANY))))
                                {
                                        key = NULL; // This key cannot sign! 
@@ -539,8 +541,8 @@ static SecTransformInstanceBlock VerifyTransform(CFStringRef name,
                                rc = SecKeyGetCSSMKey((SecKeyRef)value, &cssm_key);
                                SEC_FAIL(rc);
 
-                if (((!cssm_key->KeyHeader.KeyUsage) & CSSM_KEYUSE_SIGN)               // Keep the previous test to be compatible with existing apps
-                    || ((dyld_get_program_sdk_version() >= DYLD_MACOSX_VERSION_10_13)  // Better check for newly compiled apps
+                if (((!cssm_key->KeyHeader.KeyUsage) & CSSM_KEYUSE_SIGN)
+                    || (dyld_program_sdk_at_least(dyld_platform_version_macOS_10_13) // Keep the previous test to be compatible with existing apps
                         && !(cssm_key->KeyHeader.KeyUsage & (CSSM_KEYUSE_VERIFY|CSSM_KEYUSE_ANY))))
                                {
                                        key = NULL; // This key cannot verify!
index 0753aad03a98b80ba1ea9b531814ceb03344dcf6..073ff69e3e8b9b5514075417964ddd47a755eb67 100644 (file)
@@ -25,7 +25,7 @@
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#include "SecTransform.h"
+#include <Security/SecTransform.h>
 #include <Security/SecBase.h>
 
 
index a9d1fc7c878c576aac690006b2fa74f15c1f4c2f..6a1e64064b5db6c1daef6be5232636c3acc1bd86 100644 (file)
@@ -156,9 +156,11 @@ SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attri
        SecTransformAttributeRef search_for = pthread_getspecific(ah_search_key_slot);
        if (!search_for)
        {
-               search_for = makeAH((transform_attribute*)malloc(sizeof(transform_attribute)));
+               transform_attribute* ta = (transform_attribute*)malloc(sizeof(transform_attribute));
+               search_for = makeAH(ta);
                if (!search_for)
                {
+                       free(ta);
                        return NULL;
                }
                
@@ -185,12 +187,14 @@ SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attri
                ah = makeAH(ta);
                if (!ah)
                {
+                       free(ta);
                        return NULL;
                }
                
                ta->name = CFStringCreateCopy(NULL, label);
                if (!ta->name)
                {
+                       CFRelease(ah);
                        free(ta);
                        return NULL;
                }
@@ -200,6 +204,7 @@ SecTransformAttributeRef Transform::getAH(SecTransformStringOrAttributeRef attri
                {
                        CFReleaseNull(ta->name);
                        free(ta);
+                       CFRelease(ah);
                        return NULL;
                }
                
@@ -265,7 +270,7 @@ bool Transform::HasNoOutboundConnections()
 {
        // make an array big enough to hold all of the attributes
        CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute));
+       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute*));
        
        if (attributes == NULL) {
                // No more memory, we assume it's orphaned
@@ -296,7 +301,7 @@ bool Transform::HasNoInboundConnections()
 {
        // make an array big enough to hold all of the attributes
        CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute));
+       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute*));
        
        if (attributes == NULL) {
                // No more memory, we assume it's orphaned
@@ -1622,7 +1627,7 @@ CFDictionaryRef Transform::GetAHDictForSaveState(SecTransformStringOrAttributeRe
 CFDictionaryRef Transform::CopyState()
 {
        CFIndex i, j, cnt = CFSetGetCount(mAttributes);
-       transform_attribute **attrs = (transform_attribute**)malloc(cnt*sizeof(transform_attribute));
+       transform_attribute **attrs = (transform_attribute**)malloc(cnt*sizeof(transform_attribute*));
        CFStringRef *names = (CFStringRef*)malloc(cnt*sizeof(CFStringRef));
        CFDictionaryRef *values = (CFDictionaryRef*)malloc(sizeof(CFDictionaryRef) * cnt);
     
@@ -1819,7 +1824,7 @@ CFErrorRef Transform::ProcessExternalize(CFMutableArrayRef transforms, CFMutable
        
        // now walk the attribute list
        CFIndex numAttributes = CFSetGetCount(mAttributes);
-       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute));
+       transform_attribute **attributes = (transform_attribute**)malloc(numAttributes*sizeof(transform_attribute*));
        
        if (attributes == NULL) {
                return GetNoMemoryErrorAndRetain();
index b33aea6424a3a256098469ab93f3869e93c69580..1e8e9cff01ea124754e346cf4b631c68293769a1 100644 (file)
@@ -26,7 +26,7 @@
 #include "SecTransform.h"
 #include "SecExternalSourceTransform.h"
 #include "SecNullTransform.h"
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 @implementation speed_test
 
index a86aa4c8a50ee7282b2b4190d43745d684ce775f..64a48631d7c03105cff110d32091b5279ba71d48 100644 (file)
@@ -255,7 +255,7 @@ CFURLRef __nullable SecTranslocateCreateSecureDirectoryForURL (CFURLRef pathToTr
     {
         string  sourcePath = cfString(pathToTranslocate); // returns an absolute path
         
-        Security::SecTranslocate::TranslocationPath toTranslocatePath(sourcePath);
+        Security::SecTranslocate::TranslocationPath toTranslocatePath(sourcePath, Security::SecTranslocate::TranslocationOptions::Default);
 
         if(!toTranslocatePath.shouldTranslocate())
         {
@@ -337,6 +337,49 @@ end:
     return result;
 }
 
+CFURLRef __nullable SecTranslocateCreateGeneric (CFURLRef pathToTranslocate,
+                                                 CFURLRef destinationPath,
+                                                 CFErrorRef* __nullable error)
+{
+    CFURLRef result = NULL;
+    CFIndex errorCode  = 0;
+    
+    try
+    {
+        string sourcePath = cfString(pathToTranslocate);
+        Security::SecTranslocate::GenericTranslocationPath path{sourcePath, Security::SecTranslocate::TranslocationOptions::Unveil};
+        
+        string dpath = cfString(destinationPath);
+        string out_path = Security::SecTranslocate::getTranslocator()->translocatePathForUser(path, dpath);
+        
+        if(!out_path.empty())
+        {
+            result = makeCFURL(out_path, true);
+        }
+        else
+        {
+            Syslog::error("SecTranslocateCreateGeneric: No mountpoint and no prior exception. Shouldn't be here");
+            UnixError::throwMe(EINVAL);
+        }
+        
+    }
+    catch (Security::UnixError err)
+    {
+        errorCode = err.unixError();
+    }
+    catch(...)
+    {
+        Syslog::critical("SecTranslocateCreateGeneric: uncaught exception during mountpoint creation");
+        errorCode = EACCES;
+    }
+    
+    if (error && errorCode)
+    {
+        *error = SecTranslocateMakePosixError(errorCode);
+    }
+    return result;
+}
+
 /* Decide whether we need to translocate */
 Boolean SecTranslocateURLShouldRunTranslocated(CFURLRef path, bool* shouldTranslocate, CFErrorRef* __nullable error)
 {
@@ -352,7 +395,7 @@ Boolean SecTranslocateURLShouldRunTranslocated(CFURLRef path, bool* shouldTransl
     try
     {
         string pathToCheck = cfString(path);
-        Security::SecTranslocate::TranslocationPath tPath(pathToCheck);
+        Security::SecTranslocate::TranslocationPath tPath(pathToCheck, Security::SecTranslocate::TranslocationOptions::Default);
         *shouldTranslocate = tPath.shouldTranslocate();
         result = true;
     }
index c01e4127d6646af1d73697078506c9d497455d18..ce31fb1f1b45e62eb232476aa5034b972ba6fd35 100644 (file)
@@ -98,6 +98,33 @@ __OSX_AVAILABLE(10.12);
 CFURLRef __nullable SecTranslocateCreateSecureDirectoryForURL (CFURLRef pathToTranslocate, CFURLRef __nullable destinationPath, CFErrorRef* __nullable error)
 __OSX_AVAILABLE(10.12);
 
+/*!
+    @function SecTranslocateCreateGeneric
+    @abstract Create a CFURL pointing to a translocated location from which to access the directory specified by pathToTranslocate.
+
+    @param pathToTranslocate URL of the directory to be accessed from a translocated location.
+    @param destinationPath URL where the directory of interest should be translocated
+    @param error On error will be populated with an error object describing the failure (a posix domain error such as EINVAL)
+
+    @result A CFURL pointing to the translocated location of the directory.
+
+    @discussion
+        Calls to this function, and the others dealng with creation / deletion of mounts are serialized to ensure only one call to either
+        is operating at a time.
+        Translocations will be created in specified destinationPath
+        pathToTranslocated is expected to be a folder
+        
+        If pathToTranslocate is in a quarantined mountpoint, the quarantine attributes will be propagated to the
+            translocated location.
+        pathToTranslocate will cause a failure if it doesn't resolve to a path that exists, or it exceeds MAXPATHLEN
+        This function can be run from any process. If the process is not the xpc server, then an xpc call is made.
+ */
+CFURLRef __nullable SecTranslocateCreateGeneric (CFURLRef pathToTranslocate, CFURLRef destinationPath, CFErrorRef* __nullable error)
+__OSX_AVAILABLE(10.16);
+
 /*!
     @function SecTranslocateAppLaunchCheckin
 
index 99095aa3defaf721565d520d40db71c123b7947b..3f15bcabc59a24ff06ca4af517450ce927868bf7 100644 (file)
@@ -91,15 +91,12 @@ TranslocatorClient::~TranslocatorClient()
     dispatch_release(syncQ);
 }
 
-string TranslocatorClient::translocatePathForUser(const TranslocationPath &originalPath, const string &destPath)
+string TranslocatorClient::requestTranslocation(const string& source,
+                                                const string& destination,
+                                                const TranslocationOptions flags)
 {
     string outPath;
-
-    if (!originalPath.shouldTranslocate())
-    {
-        return originalPath.getOriginalRealPath();  //return original path if we shouldn't translocate
-    }
-
+    
     //We should run translocated, so get a translocation point
     xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
 
@@ -111,10 +108,11 @@ string TranslocatorClient::translocatePathForUser(const TranslocationPath &origi
 
     xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageFunction, kSecTranslocateXPCFuncCreate);
     /* send the original real path rather than the calculated path to let the server do all the work */
-    xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageOriginalPath, originalPath.getOriginalRealPath().c_str());
-    if(!destPath.empty())
+    xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageOriginalPath, source.c_str());
+    xpc_dictionary_set_int64(msg, kSecTranslocateXPCMessageOptions, static_cast<int64_t>(flags));
+    if(!destination.empty())
     {
-        xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageDestinationPath, destPath.c_str());
+        xpc_dictionary_set_string(msg, kSecTranslocateXPCMessageDestinationPath, destination.c_str());
     }
 
     xpc_object_t reply = xpc_connection_send_message_with_reply_sync(service, msg);
@@ -166,6 +164,26 @@ string TranslocatorClient::translocatePathForUser(const TranslocationPath &origi
     return outPath;
 }
 
+string TranslocatorClient::translocatePathForUser(const TranslocationPath &originalPath, const string &destPath)
+{
+    if (!originalPath.shouldTranslocate())
+    {
+        return originalPath.getOriginalRealPath();  //return original path if we shouldn't translocate
+    }
+    
+    return requestTranslocation(originalPath.getOriginalRealPath(), destPath, TranslocationOptions::Default);
+}
+
+string TranslocatorClient::translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath)
+{
+    if (!originalPath.shouldTranslocate())
+    {
+        return originalPath.getOriginalRealPath();  //return original path if we shouldn't translocate
+    }
+    
+    return requestTranslocation(originalPath.getOriginalRealPath(), destPath, TranslocationOptions::Generic);
+}
+
 void TranslocatorClient::appLaunchCheckin(pid_t pid)
 {
     xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
index bff27ef0a6206bebf5f95395f4067bd857ec22bc..240acf1c221871062ba85f5ca5f45c06e854540d 100644 (file)
@@ -47,12 +47,16 @@ public:
     ~TranslocatorClient();
 
     string translocatePathForUser(const TranslocationPath &originalPath, const string &destPath) override;
+    string translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath) override;
     bool destroyTranslocatedPathForUser(const string &translocatedPath) override;
     void appLaunchCheckin(pid_t pid) override;
 
 private:
     TranslocatorClient() = delete;
     TranslocatorClient(const TranslocatorClient &that) = delete;
+    
+    string requestTranslocation(const string& source, const string& destination, const TranslocationOptions flags);
+    
     dispatch_queue_t syncQ;
     xpc_connection_t service;
 };
diff --git a/OSX/libsecurity_translocate/lib/SecTranslocateEnumUtils.hpp b/OSX/libsecurity_translocate/lib/SecTranslocateEnumUtils.hpp
new file mode 100644 (file)
index 0000000..fba90b9
--- /dev/null
@@ -0,0 +1,40 @@
+//
+//  SecTranslocateEnumUtils.h
+//  Security
+//
+//
+
+#ifndef SecTranslocateEnumUtils_h
+#define SecTranslocateEnumUtils_h
+
+#include <type_traits>
+
+template<typename Enum>
+Enum operator |(Enum lhs, Enum rhs)
+{
+    static_assert(std::is_enum<Enum>::value,
+                  "template parameter is not an enum type");
+
+    using underlying = typename std::underlying_type<Enum>::type;
+
+    return static_cast<Enum> (
+        static_cast<underlying>(lhs) |
+        static_cast<underlying>(rhs)
+    );
+}
+
+template<typename Enum>
+Enum operator &(Enum lhs, Enum rhs)
+{
+    static_assert(std::is_enum<Enum>::value,
+                  "template parameter is not an enum type");
+
+    using underlying = typename std::underlying_type<Enum>::type;
+
+    return static_cast<Enum> (
+        static_cast<underlying>(lhs) &
+        static_cast<underlying>(rhs)
+    );
+}
+
+#endif /* SecTranslocateEnumUtils_h */
index 8ed15544bbaf62dea93e6599dcf405a2db37f09d..7c187b0e79363843e35f7c401e64bb3403172602 100644 (file)
@@ -45,6 +45,7 @@ class Translocator
 public:
     virtual ~Translocator() {};
     virtual string translocatePathForUser(const TranslocationPath &originalPath, const string &destPath) = 0;
+    virtual string translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath) = 0;
     virtual bool destroyTranslocatedPathForUser(const string &translocatedPath) = 0;
     virtual void appLaunchCheckin(pid_t pid) = 0;
 };
index a515ba696671f3a35d2fe8f4d0a43b81e463ce33..8d93fe2c5e658b35e8022cfd696d303ca118e351 100644 (file)
@@ -103,6 +103,28 @@ string TranslocatorServer::translocatePathForUser(const TranslocationPath &origi
     return newPath;
 }
 
+string TranslocatorServer::translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath)
+{
+    __block string newPath;
+    __block exception_ptr exception(0);
+    
+    dispatch_sync(syncQ, ^{
+        try
+        {
+            newPath = Security::SecTranslocate::translocatePathForUser(originalPath,destPath);
+        }
+        catch (...)
+        {
+            exception = current_exception();
+        }
+    });
+    if (exception)
+    {
+        rethrow_exception(exception);
+    }
+    return newPath;
+}
+
 // This is intended for use by the host process of the server if necessary
 // Destroy the translocation mount at translocatedPath if allowed
 bool TranslocatorServer::destroyTranslocatedPathForUser(const string &translocatedPath)
index b8cf62ec522d837d5cdc77075defd28efb1f9e8e..b004431435e01ab7dabf6ad78c4652acabf53737 100644 (file)
@@ -52,6 +52,7 @@ public:
     ~TranslocatorServer();
 
     string translocatePathForUser(const TranslocationPath &originalPath, const string &destPath) override;
+    string translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath) override;
     bool destroyTranslocatedPathForUser(const string &translocatedPath) override;
     void appLaunchCheckin(pid_t pid) override;
     
index 9c1595aebbd1178f8040fe7043151ecb5d711a25..b217d343713d074a97db1140485d8ca3a4749a1e 100644 (file)
@@ -24,6 +24,7 @@
 #include <vector>
 #include <string>
 #include <exception>
+#include <memory>
 
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "SecTranslocateShared.hpp"
 #include "SecTranslocateUtilities.hpp"
+#include "SecTranslocateEnumUtils.hpp"
+
+#define NULLM_UNVEIL 0x1ULL << 2
+struct null_mount_conf {
+    uint64_t flags;
+};
 
 
 namespace Security {
@@ -62,6 +69,7 @@ const char* kSecTranslocateXPCFuncCheckIn = "check-in";
 const char* kSecTranslocateXPCMessageFunction = "function";
 const char* kSecTranslocateXPCMessageOriginalPath = "original";
 const char* kSecTranslocateXPCMessageDestinationPath = "dest";
+const char* kSecTranslocateXPCMessageOptions= "opts";
 const char* kSecTranslocateXPCMessagePid = "pid";
 
 /*XPC message reply keys */
@@ -83,7 +91,7 @@ static void cleanupTranslocationDirForUser(const string &userDir);
 static int removeMountPoint(const string &mountpoint, bool force = false);
 
 /* calculate whether a translocation should occur and where from */
-TranslocationPath::TranslocationPath(string originalPath)
+TranslocationPath::TranslocationPath(string originalPath, TranslocationOptions opts)
 {
 
     /* To support testing of translocation the policy is as follows:
@@ -114,7 +122,8 @@ TranslocationPath::TranslocationPath(string originalPath)
      */
 
     ExtendedAutoFileDesc fd(originalPath);
-
+    
+    options = opts;
     should = false;
     realOriginalPath = fd.getRealPath();
 
@@ -252,8 +261,25 @@ ExtendedAutoFileDesc TranslocationPath::findOuterMostCodeBundleForFD(ExtendedAut
     return ExtendedAutoFileDesc(joinPathUpTo(path, lastGoodIndex));
 }
 
+GenericTranslocationPath::GenericTranslocationPath(const string& path, TranslocationOptions opts) {
+    ExtendedAutoFileDesc fd(path);
+    realOriginalPath = fd.getRealPath();
+    should = false;
+    options = opts;
+    
+    /* don't translocate if it already is */
+    /* Nullfs can't translocate other mount's roots so abort if its a mountpoint */
+    if(fd.isFileSystemType(NULLFS_FSTYPE) || fd.isMountPoint()) {
+        return;
+    }
+    
+    componentNameToTranslocate = splitPath(path).back();
+    
+    should = true;
+}
+
 /* Given an fd to a translocated file, build the path to the original file
- Throws if the fd isn't in a nullfs mount for the calling user. */
+ Throws if the fd isn't in a nullfs mount. */
 string getOriginalPath(const ExtendedAutoFileDesc& fd, bool* isDir)
 {
     if (!fd.isFileSystemType(NULLFS_FSTYPE) ||
@@ -268,16 +294,6 @@ string getOriginalPath(const ExtendedAutoFileDesc& fd, bool* isDir)
         UnixError::throwMe(EINVAL);
     }
     
-    string translocationBaseDir = translocationDirForUser();
-    
-    if(!fd.isInPrefixDir(translocationBaseDir))
-    {
-        Syslog::error("SecTranslocate::getOriginal path called with path (%s) that doesn't belong to user (%d)",
-                      fd.getRealPath().c_str(),
-                      getuid());
-        UnixError::throwMe(EPERM);
-    }
-    
     *isDir = fd.isA(S_IFDIR);
     
     vector<string> mountFromPath = splitPath(fd.getMountFromPath());
@@ -456,6 +472,61 @@ static vector<struct statfs> getMountTableSnapshot()
     return mntInfo;
 }
 
+static bool pathExistsInMountTable(const GenericTranslocationPath& path, const string& mountpoint)
+{
+    vector <struct statfs> mntbuf = getMountTableSnapshot();
+
+    /* Save the untranslocated inode number*/
+    ExtendedAutoFileDesc::UnixStat untranslocatedStat;
+
+    if (stat(path.getOriginalRealPath().c_str(), &untranslocatedStat))
+    {
+        errno_t err = errno;
+        Syslog::warning("SecTranslocate: failed to stat original path (%d): %s",
+                        err,
+                        path.getOriginalRealPath().c_str());
+        UnixError::throwMe(err);
+    }
+
+    for (auto &i : mntbuf)
+    {
+        string mountOnName = i.f_mntonname;
+    
+        if (path.getOriginalRealPath() == i.f_mntfromname && //mount is for the requested path
+            mountpoint == mountOnName && //mount to is the same
+            strcmp(i.f_fstypename, NULLFS_FSTYPE) == 0 // mount is a nullfs mount
+            )
+        {
+            /*
+             find the inode number for mountOnName
+             */
+            string pathToTranslocatedApp = mountOnName+"/d/"+path.getComponentNameToTranslocate();
+
+            ExtendedAutoFileDesc::UnixStat oldTranslocatedStat;
+
+            if (stat(pathToTranslocatedApp.c_str(), &oldTranslocatedStat))
+            {
+                /* We should have access to this path and it should be real so complain if thats not true. */
+                errno_t err = errno;
+                Syslog::warning("SecTranslocate: expected app not inside mountpoint: %s (error: %d)", pathToTranslocatedApp.c_str(), err);
+                UnixError::throwMe(err);
+            }
+
+            if(untranslocatedStat.st_ino != oldTranslocatedStat.st_ino)
+            {
+                /* We have two Apps with the same name at the same path but different inodes. This means that the
+                   translocated path is broken and should be removed */
+                destroyTranslocatedPathForUser(pathToTranslocatedApp);
+                continue;
+            }
+            
+            return true;
+        }
+    }
+
+    return false;
+}
+
 /* Given the directory where app translocations go for this user, the path to the app to be translocated
  and an optional destination mountpoint path. Check the mount table to see if a mount point already
  user, for this app. If a destMountPoint is provided, make sure it is for this user, and that
@@ -721,13 +792,10 @@ static void setMountPointQuarantineIfNecessary(const string &mountPoint, const s
     }
 }
 
-/* Given the path to a new mountpoint and the original path to translocate, calculate the path
- to the desired app in the new mountpoint, and sanity check that calculation */
-static string newAppPath (const string &mountPoint, const TranslocationPath &originalPath)
+static string newAppPathFrom (const string &mountPoint, const string &outPath)
 {
     string midPath = mountPoint+"/d";
-    string outPath = originalPath.getTranslocatedPathToOriginalPath(midPath+"/"+originalPath.getComponentNameToTranslocate());
-
+    
     /* ExtendedAutoFileDesc will throw if one of these doesn't exist or isn't accessible */
     ExtendedAutoFileDesc mountFd(mountPoint);
     ExtendedAutoFileDesc midFd(midPath);
@@ -768,6 +836,34 @@ static string newAppPath (const string &mountPoint, const TranslocationPath &ori
     return outFd.getRealPath();
 }
 
+
+static string newAppPath (const string &mountPoint, const GenericTranslocationPath &originalPath)
+{
+    string outPath = mountPoint+"/d/"+originalPath.getComponentNameToTranslocate();
+    return newAppPathFrom(mountPoint, outPath);
+}
+
+/* Given the path to a new mountpoint and the original path to translocate, calculate the path
+to the desired app in the new mountpoint, and sanity check that calculation */
+static string newAppPath (const string &mountPoint, const TranslocationPath &originalPath)
+{
+    string outPath = originalPath.getTranslocatedPathToOriginalPath(mountPoint+"/d/"+originalPath.getComponentNameToTranslocate());
+    return newAppPathFrom(mountPoint, outPath);
+}
+
+static std::vector<char> getMountData(const string& toTranslocate, TranslocationOptions opts) {
+    std::vector<char> data;
+    data.reserve(sizeof(null_mount_conf) + toTranslocate.size() + 1);
+    null_mount_conf conf = {0};
+    if ((opts & TranslocationOptions::Unveil) == TranslocationOptions::Unveil) {
+        conf.flags = NULLM_UNVEIL;
+    }
+    data.insert(data.end(), reinterpret_cast<const char*>(&conf), reinterpret_cast<const char*>(&conf + 1));
+    data.insert(data.end(), toTranslocate.c_str(),  toTranslocate.c_str() + toTranslocate.size());
+    data.push_back('\0');
+    return data;
+}
+
 /* Create an app translocation point given the original path and an optional destination path.
  note the destination path can only be an outermost path (where the translocation would happen) and not a path to nested code
  synchronize the process on the dispatch queue. */
@@ -809,7 +905,8 @@ string translocatePathForUser(const TranslocationPath &originalPath, const strin
             mountpoint = destMountPoint;
         }
 
-        UnixError::check(mount(NULLFS_FSTYPE, mountpoint.c_str(), MNT_RDONLY, (void*)toTranslocate.c_str()));
+        auto mount_data = getMountData(toTranslocate, originalPath.getOptions());
+        UnixError::check(mount(NULLFS_FSTYPE, mountpoint.c_str(), MNT_RDONLY, mount_data.data()));
 
         setMountPointQuarantineIfNecessary(mountpoint, toTranslocate); //throws
 
@@ -854,6 +951,62 @@ string translocatePathForUser(const TranslocationPath &originalPath, const strin
     return newPath;
 }
 
+string translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath)
+{
+    string newPath;
+    exception_ptr exception(0);
+
+    string mountpoint = destPath;
+    bool owned = false;
+    try
+    {
+        const string &toTranslocate = originalPath.getOriginalRealPath();
+        if (pathExistsInMountTable(originalPath, destPath))
+        {
+            /* A mount point exists already so bail*/
+            newPath = newAppPath(mountpoint, originalPath);
+            return newPath; /* exit the block */
+        }
+
+        AutoFileDesc fd(getFDForDirectory(mountpoint, &owned)); //throws, makes the directory if it doesn't exist
+
+        validateMountpoint(mountpoint, owned); //throws
+
+        auto mount_data = getMountData(toTranslocate, originalPath.getOptions());
+        UnixError::check(mount(NULLFS_FSTYPE, mountpoint.c_str(), MNT_RDONLY, mount_data.data()));
+
+        setMountPointQuarantineIfNecessary(mountpoint, toTranslocate); //throws
+
+        newPath = newAppPath(mountpoint, originalPath); //throws
+
+        // log that we created a new mountpoint (we don't log when we are re-using)
+        Syslog::warning("SecTranslocateCreateGeneric: created %s",
+                        newPath.c_str());
+    }
+    catch (...)
+    {
+        exception = current_exception();
+
+        if (!mountpoint.empty())
+        {
+            if (owned)
+            {
+                /* try to unmount/delete (best effort)*/
+                unmount(mountpoint.c_str(), 0);
+                rmdir(mountpoint.c_str());
+            }
+        }
+    }
+
+    /* rethrow outside the dispatch block */
+    if (exception)
+    {
+        rethrow_exception(exception);
+    }
+
+    return newPath;
+}
+
 /* Loop through the directory in the specified user directory and delete any that aren't mountpoints */
 static void cleanupTranslocationDirForUser(const string &userDir)
 {
@@ -929,11 +1082,10 @@ bool destroyTranslocatedPathForUser(const string &translocatedPath)
     bool result = false;
     int error = 0;
     /* steps
-     1. verify the translocatedPath is for the user
-     2. verify it is a nullfs mountpoint (with app path)
-     3. unmount it
-     4. delete it
-     5. loop through all the other directories in the app translation directory looking for directories not mounted on and delete them.
+     1. verify it is a nullfs mountpoint (with app path)
+     2. unmount it
+     3. delete it
+     4. loop through all the other directories in the app translation directory looking for directories not mounted on and delete them.
      */
 
     string baseDirForUser = translocationDirForUser(); // throws
@@ -947,7 +1099,7 @@ bool destroyTranslocatedPathForUser(const string &translocatedPath)
          To support unmount when nested apps end, just make sure that the requested path is on a translocation
          point for this user, not that they asked for a translocation point to be removed.
          */
-        shouldUnmount = fd.isInPrefixDir(baseDirForUser) && fd.isFileSystemType(NULLFS_FSTYPE);
+        shouldUnmount = fd.isFileSystemType(NULLFS_FSTYPE);
     }
 
     if (shouldUnmount)
index a55961c50392e0ea1177a8fdac4b8b00c1659f4f..653eb14dd81d419421fa54a8dfc8f03e4c7e6db9 100644 (file)
@@ -48,22 +48,47 @@ extern const char* kSecTranslocateXPCFuncCheckIn;
 extern const char* kSecTranslocateXPCMessageFunction;
 extern const char* kSecTranslocateXPCMessageOriginalPath;
 extern const char* kSecTranslocateXPCMessageDestinationPath;
+extern const char* kSecTranslocateXPCMessageOptions;
 extern const char* kSecTranslocateXPCMessagePid;
 
 /*XPC message reply keys */
 extern const char* kSecTranslocateXPCReplyError;
 extern const char* kSecTranslocateXPCReplySecurePath;
 
+enum class TranslocationOptions : int64_t {
+    Default = 0,
+    Generic = 1 << 0,
+    Unveil  = 1 << 1
+};
+
+class GenericTranslocationPath
+{
+public:
+    GenericTranslocationPath(const string& path, TranslocationOptions opts);
+    inline bool shouldTranslocate() const { return should; };
+    inline const string & getOriginalRealPath() const { return realOriginalPath; };
+    inline const string & getComponentNameToTranslocate() const { return componentNameToTranslocate; };
+    inline TranslocationOptions getOptions() const { return options; };
+private:
+    GenericTranslocationPath() = delete;
+    
+    bool should;
+    string realOriginalPath;
+    string componentNameToTranslocate;
+    TranslocationOptions options;
+};
+
 class TranslocationPath
 {
 public:
-    TranslocationPath(string originalPath);
+    TranslocationPath(string originalPath, TranslocationOptions opts);
     inline bool shouldTranslocate() const { return should; };
     inline const string & getOriginalRealPath() const { return realOriginalPath; };
     inline const string & getPathToTranslocate() const { return pathToTranslocate; };
     inline const string & getPathInsideTranslocation() const { return pathInsideTranslocationPoint; };
     inline const string & getComponentNameToTranslocate() const { return componentNameToTranslocate; };
     string getTranslocatedPathToOriginalPath(const string &translocationPoint) const;
+    inline TranslocationOptions getOptions() const { return options; };
 private:
     TranslocationPath() = delete;
 
@@ -72,6 +97,7 @@ private:
     string pathToTranslocate;
     string componentNameToTranslocate; //the final component of pathToTranslocate
     string pathInsideTranslocationPoint;
+    TranslocationOptions options;
 
     ExtendedAutoFileDesc findOuterMostCodeBundleForFD(ExtendedAutoFileDesc &fd);
 };
@@ -81,6 +107,7 @@ string getOriginalPath(const ExtendedAutoFileDesc& fd, bool* isDir); //throws
 // For methods below, the caller is responsible for ensuring that only one thread is
 // accessing/modifying the mount table at a time
 string translocatePathForUser(const TranslocationPath &originalPath, const string &destPath); //throws
+string translocatePathForUser(const GenericTranslocationPath &originalPath, const string &destPath); //throws
 bool destroyTranslocatedPathForUser(const string &translocatedPath); //throws
 bool destroyTranslocatedPathsForUserOnVolume(const string &volumePath = ""); //throws
 void tryToDestroyUnusedTranslocationMounts();
@@ -88,4 +115,5 @@ void tryToDestroyUnusedTranslocationMounts();
 } //namespace SecTranslocate
 }// namespace Security
 
+
 #endif /* SecTranslocateShared_hpp */
index e2503e2d9fa18209b1f2c3114d2164e021752604..71c816555e5edd4e990fa49eaca0dfd66b8782bc 100644 (file)
@@ -91,7 +91,7 @@ void* checkedDlsym(void* handle, const char* symbol);
 //Path parsing functions
 vector<string> splitPath(const string &path);
 string joinPath(vector<string>& path);
-    string joinPathUpTo(vector<string> &path, size_t index);
+string joinPathUpTo(vector<string> &path, size_t index);
 
 //File system utlities
 string getRealPath(const string &path);
index 769f72ac3b570d101e1b4c7be216d987612a8522..f7c84c6faf72b1e2180f652c8291a543d5387986 100644 (file)
@@ -34,6 +34,7 @@
 #include "SecTranslocateXPCServer.hpp"
 #include "SecTranslocateUtilities.hpp"
 #include "SecTranslocateShared.hpp"
+#include "SecTranslocateEnumUtils.hpp"
 
 namespace Security {
 namespace SecTranslocate {
@@ -42,24 +43,36 @@ static void doCreate(xpc_object_t msg, xpc_object_t reply)
 {
     const char* original = xpc_dictionary_get_string(msg, kSecTranslocateXPCMessageOriginalPath);
     const char* dest = xpc_dictionary_get_string(msg, kSecTranslocateXPCMessageDestinationPath);
+    const int64_t opts = xpc_dictionary_get_int64(msg, kSecTranslocateXPCMessageOptions);
 
     string originalPath = original ? original : "";
     string destPath = dest ? dest: "";
+    TranslocationOptions options = static_cast<TranslocationOptions>(opts);
 
-    iforiginalPath.empty())
+    if (originalPath.empty())
     {
         Syslog::error("SecTranslocate: XPCServer, doCreate no path to translocate");
         UnixError::throwMe(EINVAL);
     }
 
-    TranslocationPath tPath(originalPath);
+    string result = originalPath;
+    
+    if ((options & TranslocationOptions::Generic) == TranslocationOptions::Generic) {
+        GenericTranslocationPath tPath(originalPath, TranslocationOptions::Unveil);
 
-    string result = tPath.getOriginalRealPath();
+        if(tPath.shouldTranslocate())
+        {
+            result = Security::SecTranslocate::translocatePathForUser(tPath, destPath);
+        }
+    } else {
+        TranslocationPath tPath(originalPath, TranslocationOptions::Default);
 
-    if(tPath.shouldTranslocate())
-    {
-        result = Security::SecTranslocate::translocatePathForUser(tPath, destPath);
+        if(tPath.shouldTranslocate())
+        {
+            result = Security::SecTranslocate::translocatePathForUser(tPath, destPath);
+        }
     }
+    
     xpc_dictionary_set_string(reply, kSecTranslocateXPCReplySecurePath, result.c_str());
 }
 
index 5d297087347a30401c16306fd96da364a11d3593..fed1a61064978b0b9d29efba8304caf2b2e7e8e4 100644 (file)
@@ -46,7 +46,7 @@ extern "C" size_t malloc_size(void *);
 //
 // Features of the Allocator root class
 //
-bool Allocator::operator == (const Allocator &alloc) const throw()
+bool Allocator::operator == (const Allocator &alloc) const _NOEXCEPT
 {
        return this == &alloc;
 }
@@ -63,14 +63,14 @@ Allocator::~Allocator()
 // pool). This is trivially achieved here by using singletons.
 //
 struct DefaultAllocator : public Allocator {
-       void *malloc(size_t size) throw(std::bad_alloc);
-       void free(void *addr) throw();
-       void *realloc(void *addr, size_t size) throw(std::bad_alloc);
+       void *malloc(size_t size);
+       void free(void *addr) _NOEXCEPT;
+       void *realloc(void *addr, size_t size);
 };
 
 struct SensitiveAllocator : public DefaultAllocator {
-    void free(void *addr) throw();
-    void *realloc(void *addr, size_t size) throw(std::bad_alloc);
+    void free(void *addr) _NOEXCEPT;
+    void *realloc(void *addr, size_t size);
 };
 
 struct DefaultAllocators {
@@ -93,33 +93,33 @@ Allocator &Allocator::standard(UInt32 request)
     }
 }
 
-void *DefaultAllocator::malloc(size_t size) throw(std::bad_alloc)
+void *DefaultAllocator::malloc(size_t size)
 {
        if (void *result = ::malloc(size))
                return result;
        throw std::bad_alloc();
 }
 
-void DefaultAllocator::free(void *addr) throw()
+void DefaultAllocator::free(void *addr) _NOEXCEPT
 {
        ::free(addr);
 }
 
-void *DefaultAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
+void *DefaultAllocator::realloc(void *addr, size_t newSize)
 {
        if (void *result = ::realloc(addr, newSize))
                return result;
        throw std::bad_alloc();
 }
 
-void SensitiveAllocator::free(void *addr) throw()
+void SensitiveAllocator::free(void *addr) _NOEXCEPT
 {
     size_t size = malloc_size(addr);
     ::memset_s(addr, size, 0, size);
     DefaultAllocator::free(addr);
 }
 
-void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_alloc)
+void *SensitiveAllocator::realloc(void *addr, size_t newSize)
 {
     size_t oldSize = malloc_size(addr);
     if (newSize < oldSize)
@@ -135,7 +135,7 @@ void *SensitiveAllocator::realloc(void *addr, size_t newSize) throw(std::bad_all
 // functions to safely free our (hidden) pointer without knowing about it.
 // An allocator argument of NULL is interpreted as the standard allocator.
 //
-void *CssmHeap::operator new (size_t size, Allocator *alloc) throw(std::bad_alloc)
+void *CssmHeap::operator new (size_t size, Allocator *alloc)
 {
     if (size > SIZE_T_MAX / 2) {
         throw std::bad_alloc();
@@ -150,12 +150,12 @@ void *CssmHeap::operator new (size_t size, Allocator *alloc) throw(std::bad_allo
        return addr;
 }
 
-void CssmHeap::operator delete (void *addr, size_t size, Allocator *alloc) throw()
+void CssmHeap::operator delete (void *addr, size_t size, Allocator *alloc) _NOEXCEPT
 {
        alloc->free(addr);      // as per C++ std, called (only) if construction fails
 }
 
-void CssmHeap::operator delete (void *addr, size_t size) throw()
+void CssmHeap::operator delete (void *addr, size_t size) _NOEXCEPT
 {
        void *end = increment(addr, alignUp(size, alignof_template<Allocator *>()));
        (*(Allocator **)end)->free(addr);
index 8d2762278a72a793353ed31b05f367609233c2ad..b77f945157cdd08d029ab837eef1930be85d8a59 100644 (file)
@@ -43,18 +43,18 @@ namespace Security
 class Allocator {
 public:
        virtual ~Allocator();
-       virtual void *malloc(size_t) throw(std::bad_alloc) = 0;
-       virtual void free(void *) throw() = 0;
-       virtual void *realloc(void *, size_t) throw(std::bad_alloc) = 0;
+       virtual void *malloc(size_t)= 0;
+       virtual void free(void *) _NOEXCEPT = 0;
+       virtual void *realloc(void *, size_t)= 0;
 
        //
        // Template versions for added expressiveness.
        // Note that the integers are element counts, not byte sizes.
        //
-       template <class T> T *alloc() throw(std::bad_alloc)
+       template <class T> T *alloc()
        { return reinterpret_cast<T *>(malloc(sizeof(T))); }
 
-       template <class T> T *alloc(UInt32 count) throw(std::bad_alloc)
+       template <class T> T *alloc(UInt32 count)
        {
         size_t bytes = 0;
         if (__builtin_mul_overflow(sizeof(T), count, &bytes)) {
@@ -64,7 +64,7 @@ public:
 
     }
 
-       template <class T> T *alloc(T *old, UInt32 count) throw(std::bad_alloc)
+       template <class T> T *alloc(T *old, UInt32 count)
        {
         size_t bytes = 0;
         if (__builtin_mul_overflow(sizeof(T), count, &bytes)) {
@@ -78,14 +78,14 @@ public:
        // Happier malloc/realloc for any type. Note that these still have
        // the original (byte-sized) argument profile.
        //
-       template <class T> T *malloc(size_t size) throw(std::bad_alloc)
+       template <class T> T *malloc(size_t size)
        { return reinterpret_cast<T *>(malloc(size)); }
        
-       template <class T> T *realloc(void *addr, size_t size) throw(std::bad_alloc)
+       template <class T> T *realloc(void *addr, size_t size)
        { return reinterpret_cast<T *>(realloc(addr, size)); }
 
        // All right, if you *really* have to have calloc...
-       void *calloc(size_t size, size_t count) throw(std::bad_alloc)
+       void *calloc(size_t size, size_t count)
        {
         size_t bytes = 0;
         if(__builtin_mul_overflow(size, count, &bytes)) {
@@ -98,7 +98,7 @@ public:
        }
        
        // compare Allocators for identity
-       virtual bool operator == (const Allocator &alloc) const throw();
+       virtual bool operator == (const Allocator &alloc) const _NOEXCEPT;
 
 public:
        // allocator chooser options
@@ -117,14 +117,14 @@ public:
 // Use this to cleanly destroy things.
 //
 template <class T>
-inline void destroy(T *obj, Allocator &alloc) throw()
+inline void destroy(T *obj, Allocator &alloc) _NOEXCEPT
 {
        obj->~T();
        alloc.free(obj);
 }
 
 // untyped (release memory only, no destructor call)
-inline void destroy(void *obj, Allocator &alloc) throw()
+inline void destroy(void *obj, Allocator &alloc) _NOEXCEPT
 {
        alloc.free(obj);
 }
@@ -145,17 +145,17 @@ inline void destroy(void *obj, Allocator &alloc) throw()
 //
 class CssmHeap {
 public:    
-       void *operator new (size_t size, Allocator *alloc = NULL) throw(std::bad_alloc);
-       void operator delete (void *addr, size_t size) throw();
-       void operator delete (void *addr, size_t size, Allocator *alloc) throw();
+       void *operator new (size_t size, Allocator *alloc = NULL);
+       void operator delete (void *addr, size_t size) _NOEXCEPT;
+       void operator delete (void *addr, size_t size, Allocator *alloc) _NOEXCEPT;
 };
 
 
 //
-// Here is a version of auto_ptr that works with Allocators. It is designed
+// Here is a version of unique_ptr that works with Allocators. It is designed
 // to be pretty much a drop-in replacement. It requires an allocator as a constructor
 // argument, of course.
-// Note that CssmAutoPtr<void> is perfectly valid, unlike its auto_ptr look-alike.
+// Note that CssmAutoPtr<void> is perfectly valid, unlike its unique_ptr look-alike.
 // You can't dereference it, naturally.
 //
 template <class T>
@@ -176,7 +176,7 @@ public:
        
        ~CssmAutoPtr()                          { allocator.free(mine); }
        
-       T *get() const throw()          { return mine; }
+       T *get() const _NOEXCEPT                { return mine; }
        T *release()                            { T *result = mine; mine = NULL; return result; }
        void reset()                            { allocator.free(mine); mine = NULL; }
 
@@ -203,7 +203,7 @@ public:
        
        ~CssmAutoPtr()                          { destroy(mine, allocator); }
        
-       void *get() throw()             { return mine; }
+       void *get() _NOEXCEPT           { return mine; }
        void *release()                         { void *result = mine; mine = NULL; return result; }
        void reset()                            { allocator.free(mine); mine = NULL; }
 
@@ -248,10 +248,10 @@ public:
 //
 // Global C++ allocation hooks to use Allocators (global namespace)
 //
-inline void *operator new (size_t size, Allocator &allocator) throw (std::bad_alloc)
+inline void *operator new (size_t size, Allocator &allocator)
 { return allocator.malloc(size); }
 
-inline void *operator new[] (size_t size, Allocator &allocator) throw (std::bad_alloc)
+inline void *operator new[] (size_t size, Allocator &allocator)
 { return allocator.malloc(size); }
 
 
index 530edb4b83632e50073126e177a2ccc352d3a9ba..6beabd295a1794d316cdba6b5310ea04adf2fd59 100644 (file)
@@ -89,7 +89,7 @@ CFClass::cleanupObject(intptr_t op, CFTypeRef cf, bool &zap)
 }
 
 uint32_t
-CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw()
+CFClass::refCountForType(intptr_t op, CFTypeRef cf) _NOEXCEPT
 {
     uint32_t result = 0;
     bool zap = false;
@@ -127,7 +127,7 @@ CFClass::refCountForType(intptr_t op, CFTypeRef cf) throw()
 
 
 void
-CFClass::finalizeType(CFTypeRef cf) throw()
+CFClass::finalizeType(CFTypeRef cf) _NOEXCEPT
 {
     /*
         We need to control the lifetime of the object.  This means
@@ -168,7 +168,7 @@ CFClass::finalizeType(CFTypeRef cf) throw()
 }
 
 Boolean
-CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw()
+CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) _NOEXCEPT
 {
        // CF checks for pointer equality and ensures type equality already
        try {
@@ -179,7 +179,7 @@ CFClass::equalType(CFTypeRef cf1, CFTypeRef cf2) throw()
 }
 
 CFHashCode
-CFClass::hashType(CFTypeRef cf) throw()
+CFClass::hashType(CFTypeRef cf) _NOEXCEPT
 {
        try {
                return SecCFObject::optional(cf)->hash();
@@ -189,7 +189,7 @@ CFClass::hashType(CFTypeRef cf) throw()
 }
 
 CFStringRef
-CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw()
+CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) _NOEXCEPT
 {
        try {
                return SecCFObject::optional(cf)->copyFormattingDesc(dict);
@@ -199,7 +199,7 @@ CFClass::copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw()
 }
 
 CFStringRef
-CFClass::copyDebugDescType(CFTypeRef cf) throw()
+CFClass::copyDebugDescType(CFTypeRef cf) _NOEXCEPT
 {
        try {
                return SecCFObject::optional(cf)->copyDebugDesc();
index 6203f112ee8a028513d28dbdd5073c8dcc020b50..1adbbe1820678d5d0b461a5a5ff110fa095464d3 100644 (file)
@@ -41,12 +41,12 @@ public:
        CFTypeID typeID;
 
 private:
-       static void finalizeType(CFTypeRef cf) throw();
-    static Boolean equalType(CFTypeRef cf1, CFTypeRef cf2) throw();
-    static CFHashCode hashType(CFTypeRef cf) throw();
-       static CFStringRef copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) throw();
-       static CFStringRef copyDebugDescType(CFTypeRef cf) throw();
-    static uint32_t refCountForType(intptr_t op, CFTypeRef cf) throw();
+       static void finalizeType(CFTypeRef cf) _NOEXCEPT;
+    static Boolean equalType(CFTypeRef cf1, CFTypeRef cf2) _NOEXCEPT;
+    static CFHashCode hashType(CFTypeRef cf) _NOEXCEPT;
+       static CFStringRef copyFormattingDescType(CFTypeRef cf, CFDictionaryRef dict) _NOEXCEPT;
+       static CFStringRef copyDebugDescType(CFTypeRef cf) _NOEXCEPT;
+    static uint32_t refCountForType(intptr_t op, CFTypeRef cf) _NOEXCEPT;
     static uint32_t cleanupObject(intptr_t op, CFTypeRef cf, bool &zap);
 };
 
index f26ccc72a6741ff09b29e9bca11502c779a3bf71..2854e600dc4222cb9a90c48ee87631aaa7c77352 100644 (file)
@@ -221,17 +221,21 @@ CFTypeRef CF_RETURNS_RETAINED CFMake::makedictionary()
                                return dict;
                } else
                        return NULL;    // bad syntax
-       } else
+    } else {
                dict = CFDictionaryCreateMutable(allocator, 0,
                        &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    if (dict == NULL)
+    }
+
+    if (dict == NULL) {
         return dict;
-       if (add(dict))
-               return dict;
-       else {
-               CFReleaseSafe(dict);
-               return NULL;
-       }
+    }
+
+    if (add(dict)) {
+        return dict;
+    } else {
+        CFReleaseSafe(dict);
+        return NULL;
+    }
 }
 
 CFDictionaryRef CFMake::add(CFMutableDictionaryRef dict)
index f06ced9842773ce5b6d9064b6dde7c65a5207b38..780174a76d453cc8fe5d48315704841b608ef2d6 100644 (file)
@@ -36,7 +36,6 @@
 namespace Security {
 namespace Daemon {
 
-
 //
 // Daemonize this process, the UNIX way.
 //
@@ -82,31 +81,5 @@ bool incarnate(bool doFork /*=true*/)
        return true;
 }
 
-
-//
-// Re-execute myself.
-// This is a pretty bad hack for libraries that are pretty broken and (essentially)
-// don't work after a fork() unless you also exec().
-//
-// WARNING: Don't even THINK of doing this in a setuid-anything program.
-//
-bool executeSelf(char **argv)
-{
-       static const char reExecEnv[] = "_RE_EXECUTE";
-       if (getenv(reExecEnv)) {                // was re-executed
-               secinfo("daemon", "self-execution complete");
-               unsetenv(reExecEnv);
-               return true;
-       } else {
-               setenv(reExecEnv, "go", 1);
-               secinfo("daemon", "self-executing (ouch!)");
-               execv(argv[0], argv);
-               perror("re-execution");
-               Syslog::error("Re-execution attempt failed");
-               return false;
-       }
-}
-
-
 } // end namespace Daemon
 } // end namespace Security
index 6e51747d4ee7a35e5c1d5ec06157fabf93911b94..e65800b582cdd99dace65271081c4696dcaefff6 100644 (file)
@@ -35,7 +35,6 @@ namespace Security {
 namespace Daemon {
 
 bool incarnate(bool doFork=true);
-bool executeSelf(char **argv);
 
 } // end namespace Daemon
 } // end namespace Security
index 55c74a7cd1a281bac2e031f36ab94e87a64b653f..c95c802eebd8cd26ca70857c6f6ebf0bcba69120 100644 (file)
@@ -218,9 +218,11 @@ void Target::message(const char *scope, const char *format, va_list args)
                // now stuff the message body in, slightly roasted
                size_t left = buffer + sizeof(buffer) - bufp - 1;       // reserve one
                size_t written = vsnprintf(bufp, left, format, args);
-        for (char *p = bufp; *p; p++)
-            if (!isprint(*p))
+        for (char *p = bufp; *p; p++) {
+            if (!isprint(*p)) {
                 *p = '?';
+            }
+        }
                if (written >= left) {  // snprintf overflowed
                        bufp += left;
                        strcpy(bufp - 3, "...");
index e715b11d3e93756c5903ddc5702c96319a2b034b..5072da2f3fa6103e56ff169927b89a26e43a7432 100644 (file)
@@ -60,7 +60,7 @@ CommonError::CommonError(const CommonError &source)
     strlcpy(whatBuffer, source.whatBuffer, whatBufferSize);
 }
 
-CommonError::~CommonError() throw ()
+CommonError::~CommonError() _NOEXCEPT
 {
 }
 
@@ -135,7 +135,7 @@ UnixError::UnixError(int err, bool suppresslogging) : error(err)
     }
 }
 
-const char *UnixError::what() const throw ()
+const char *UnixError::what() const _NOEXCEPT
 {
     return whatBuffer;
 }
@@ -175,7 +175,7 @@ MacOSError::MacOSError(int err) : error(err)
     }
 }
 
-const char *MacOSError::what() const throw ()
+const char *MacOSError::what() const _NOEXCEPT
 {
     return whatBuffer;
 }
@@ -219,7 +219,7 @@ CFError::CFError()
     LogBacktrace();
 }
 
-const char *CFError::what() const throw ()
+const char *CFError::what() const _NOEXCEPT
 { return "CoreFoundation error"; }
 
 OSStatus CFError::osStatus() const
index 4baae8f38c3524d745d50f6f11d371b32d9dd1b2..b0cf718d487983bbad069266524369fef2048846 100644 (file)
@@ -50,7 +50,7 @@ protected:
     CommonError();
     CommonError(const CommonError &source);
 public:
-    virtual ~CommonError() throw ();
+    virtual ~CommonError() _NOEXCEPT;
 
     virtual OSStatus osStatus() const = 0;
        virtual int unixError() const = 0;
@@ -74,7 +74,7 @@ public:
     const int error;
     virtual OSStatus osStatus() const;
        virtual int unixError() const;
-    virtual const char *what () const throw ();
+    virtual const char *what () const _NOEXCEPT;
     
     static void check(int result)              { if (result == -1) throwMe(); }
     static void throwMe(int err = errno) __attribute__((noreturn));
@@ -96,7 +96,7 @@ public:
     const int error;
     virtual OSStatus osStatus() const;
        virtual int unixError() const;
-    virtual const char *what () const throw ();
+    virtual const char *what () const _NOEXCEPT;
     
     static void check(OSStatus status) { if (status != errSecSuccess) throwMe(status); }
     static void throwMe(int err) __attribute__((noreturn));
@@ -120,7 +120,7 @@ protected:
 public:
        virtual OSStatus osStatus() const;
        virtual int unixError() const;
-       virtual const char *what () const throw ();
+       virtual const char *what () const _NOEXCEPT;
        
        template <class T>
        static void check(const T &p)           { if (!p) throwMe(); }
index df5af3bc008e358b8c070f4f811061dd388d17e8..7d8306a10fcc4f923eb1e65bb66be3cece64031e 100644 (file)
@@ -42,7 +42,7 @@
 //
 // The Error class thrown if Nexus operations fail
 //
-GlobalNexus::Error::~Error() throw()
+GlobalNexus::Error::~Error() _NOEXCEPT
 {
 }
 
@@ -80,7 +80,7 @@ ProcessNexusBase::ProcessNexusBase(const char *identifier)
 {
        const char *env = getenv(identifier);
        if (env == NULL) {      // perhaps we're first...
-               auto_ptr<Store> store(new Store);
+               unique_ptr<Store> store(new Store);
                char form[2*sizeof(Store *) + 2];
                sprintf(form, "*%p", &store);
                setenv(identifier, form, 0);    // do NOT overwrite...
index 5610cc8aaf7965ee93f9c8dec5dae71dd4fe81b5..db0e20ff73874d6b751d61ce0d680080bd1810a1 100644 (file)
@@ -47,10 +47,10 @@ class GlobalNexus {
 public:
     class Error : public std::exception {
     public:
-        virtual ~Error() throw();
+        virtual ~Error() _NOEXCEPT;
         const char * const message;
         Error(const char *m) : message(m) { }
-        const char *what() const throw() { return message; }
+        const char *what() const _NOEXCEPT { return message; }
     };
 };
 
index ab6bb98201d7c11ba8869c080688fd4bad6fd643..9708a823abd408e814c283dea458bad44fcabdf6 100644 (file)
@@ -47,7 +47,7 @@ Error::Error(kern_return_t err) : error(err)
     secnotice("security_exception", "mach error: %d", err);
 }
 
-Error::~Error() throw()
+Error::~Error() _NOEXCEPT
 { }
 
 
@@ -142,9 +142,10 @@ mach_port_t Port::cancelNotify(mach_msg_id_t type)
 {
     // Mach won't let us unset the DPN port if we are already dead
     // (EVEN if the DPN has already been sent!) So just ignore that case...
-    if (isDead())
+    if (isDead()) {
         return MACH_PORT_NULL;
-       return requestNotify(MACH_PORT_NULL, type);
+    }
+    return requestNotify(MACH_PORT_NULL, type);
 }
 
 mach_port_msgcount_t Port::qlimit() const
index dba14c3786629220ea476120aa977dc38ba9c4df..ba7f02b1746fa1423043d6ce8c005804db315c6e 100644 (file)
@@ -53,7 +53,7 @@ protected:
        // actually, kern_return_t can be just about any subsystem type return code
        Error(kern_return_t err);
 public:
-       virtual ~Error() throw();
+       virtual ~Error() _NOEXCEPT;
 
     virtual OSStatus osStatus() const;
        virtual int unixError() const;
@@ -107,8 +107,13 @@ public:
        // port allocation and management
        void allocate(mach_port_right_t right = MACH_PORT_RIGHT_RECEIVE)
        { check(mach_port_allocate(self(), right, &mPort)); }
-    void deallocate()  { check(mach_port_deallocate(self(), mPort)); mPort = MACH_PORT_NULL;}
-       void destroy()          { check(mach_port_destroy(self(), mPort)); mPort = MACH_PORT_NULL; }
+       /*
+        * (╯ರ ~ ರ)╯︵ ┻━┻
+        * mach_port_deallocate() only deallocates send, send-once, dead-name, or port-set.
+        * Since allocate() defaults to receive, allocate() and deallocate() do not actually
+        * balance each other; deallocate() will fail with an invalid-right error.
+        */
+       void deallocate()       { check(mach_port_deallocate(self(), mPort)); mPort = MACH_PORT_NULL;}
        
        void insertRight(mach_msg_type_name_t type)
        { check(mach_port_insert_right(self(), mPort, mPort, type)); }
@@ -134,25 +139,13 @@ protected:
 };
 
 
-//
-// A simple Port that deallocates itself on destruction.
-// If you need a subclass of Port, just assign it to a separate AutoPort.
-//
-class AutoPort : public Port {
-public:
-       AutoPort()      { }
-       AutoPort(mach_port_t port) : Port(port) { }
-       ~AutoPort()     { if (mPort != MACH_PORT_NULL) deallocate(); }
-};
-
-
 //
 // Ports representing PortSets
 //
 class PortSet : public Port {
 public:
        PortSet() { allocate(MACH_PORT_RIGHT_PORT_SET); }
-       ~PortSet() { destroy(); }
+       ~PortSet() { deallocate(); }
        
        void operator += (const Port &port)
        { check(mach_port_move_member(self(), port, mPort)); }
@@ -222,7 +215,7 @@ class ReceivePort : public Port {
 public:
        ReceivePort()   { allocate(); }
        ReceivePort(const char *name, const Bootstrap &bootstrap, bool tryCheckin = true);
-       ~ReceivePort()  { destroy(); }
+       ~ReceivePort()  { modRefs(MACH_PORT_RIGHT_RECEIVE, -1); }
 };
 
 
index 32836ab0cbc0ee107171f9cc9235f0141343d22c..f7f8c81d1f73cadcbf53c4027709b14a02d03c00 100644 (file)
@@ -768,11 +768,12 @@ const fat_arch *Universal::findArch(const Architecture &target) const
        // exact match
        for (const fat_arch *arch = mArchList; arch < end; ++arch)
                if (arch->cputype == target.cpuType()
-                       && arch->cpusubtype == target.cpuSubtype())
+                       && (arch->cpusubtype & ~CPU_SUBTYPE_MASK) == target.cpuSubtype())
                        return arch;
        // match for generic model of main architecture
        for (const fat_arch *arch = mArchList; arch < end; ++arch)
-               if (arch->cputype == target.cpuType() && arch->cpusubtype == 0)
+               if (arch->cputype == target.cpuType()
+                       && (arch->cpusubtype & ~CPU_SUBTYPE_MASK) == 0)
                        return arch;
        // match for any subarchitecture of the main architecture (questionable)
        for (const fat_arch *arch = mArchList; arch < end; ++arch)
@@ -790,7 +791,7 @@ MachO *Universal::findImage(const Architecture &target) const
        
 MachO* Universal::make(MachO* macho) const
 {
-       auto_ptr<MachO> mo(macho);                              // safe resource
+       unique_ptr<MachO> mo(macho);                            // safe resource
        uint32_t type = mo->type();
        if (type == 0)                                                  // not a recognized Mach-O type
                UnixError::throwMe(ENOEXEC);
@@ -829,7 +830,7 @@ void Universal::architectures(Architectures &archs) const
                for (unsigned n = 0; n < mArchCount; n++)
                        archs.insert(mArchList[n]);
        } else {
-               auto_ptr<MachO> macho(architecture());
+               unique_ptr<MachO> macho(architecture());
                archs.insert(macho->architecture());
        }
 }
@@ -880,7 +881,7 @@ bool Universal::isSuspicious() const
        Universal::Architectures archList;
        architectures(archList);
        for (Universal::Architectures::const_iterator it = archList.begin(); it != archList.end(); ++it) {
-               auto_ptr<MachO> macho(architecture(*it));
+               unique_ptr<MachO> macho(architecture(*it));
                if (macho->isSuspicious())
                        return true;
        }
index a58ec3097b30174aa43190d8f17fbc2709edb643..f479c686f410f1718d6aa23ebc14a980ab196a4c 100644 (file)
@@ -53,7 +53,7 @@ public:
        Architecture(const char *name);
 
        cpu_type_t cpuType() const { return this->first; }
-       cpu_subtype_t cpuSubtype() const { return this->second; }
+       cpu_subtype_t cpuSubtype() const { return this->second & ~CPU_SUBTYPE_MASK; }
        const char *name() const;                       // NULL if unknown
        std::string displayName() const;        // always display-able
        
index face9600e8fe5678015e11aa38580b79d868c530..5511fbd9d7e801931c1fe2b48b065ab0f93fd5d8 100644 (file)
@@ -45,7 +45,7 @@ Error::Error(MSC_RV err) : error(err)
 }
 
 
-const char *Error::what() const throw ()
+const char *Error::what() const _NOEXCEPT
 {
        return msc_error(error);
 }
@@ -92,7 +92,10 @@ void Connection::open(const PCSC::ReaderState &reader, unsigned share)
        strncpy(info.slotName, reader.name(), MAX_READERNAME);
        
        // set ATR in info
-       assert(reader.length() <= MAX_ATR_SIZE);
+    if (reader.length() > MAX_ATR_SIZE) {
+        Error::throwMe(MSC_INVALID_PARAMETER);
+    }
+    
        memcpy(info.tokenId, reader.data(), reader.length());
        info.tokenIdLength = (MSCULong32)reader.length();
        
index 016940ec62a17bddb836ba1d079a80d82b59e93e..4c32be90431bd6e83c8840a57ab535a465c491c1 100644 (file)
@@ -56,7 +56,7 @@ public:
     const MSC_RV error;
        OSStatus osStatus() const;
        int unixError() const;
-       const char *what () const throw ();
+       const char *what () const _NOEXCEPT;
        
        static void check(MSC_RV err) { if (err != MSC_SUCCESS) throwMe(err); }
        static void throwMe(MSC_RV err);
index 67161287ae3e1c4c020776ceb9929943b02578c7..2efb4c9649e4bb39557414a2169e1d3a5a652abd 100644 (file)
@@ -66,7 +66,7 @@ Error::Error(unsigned long err) : error(err)
 }
 
 
-const char *Error::what() const throw ()
+const char *Error::what() const _NOEXCEPT
 {
        return pcsc_stringify_error((int32_t)error);
 }
index 5ca469d7916b4b1ac5be92699315e571b48aaed6..b6eacebfdb4a4a7c0c945b5fdd0024df53fa679b 100644 (file)
@@ -60,7 +60,7 @@ public:
     const unsigned long error;
        OSStatus osStatus() const;
        int unixError() const;
-       const char *what () const throw ();
+       const char *what () const _NOEXCEPT;
        
        static void check(unsigned long err) { if (err != SCARD_S_SUCCESS) throwMe(err); }
        static void throwMe(unsigned long err);
index e94f565702342be65106b9932fb2fc2a95a611bf..71b8c203917c56d81a27f958f78ba20c1c80a7aa 100644 (file)
@@ -112,7 +112,7 @@ public:
        RefPointer& operator = (const RefPointer<Sub>& p) { setPointer(p.ptr); return *this; }
 
        // dereference operations
-    T* get () const                            { _check(); return ptr; }       // mimic auto_ptr
+    T* get () const                            { _check(); return ptr; }       // mimic unique_ptr
        operator T * () const           { _check(); return ptr; }
        T * operator -> () const        { _check(); return ptr; }
        T & operator * () const         { _check(); return *ptr; }
index 93185ffc660d49f6f4c3575a907659a3aa948966..04972e7c303951406e4446752c974e45785f782b 100644 (file)
@@ -112,7 +112,7 @@ void SecPointerBase::copy(SecCFObject * p)
 // SecCFObject
 //
 SecCFObject *
-SecCFObject::optional(CFTypeRef cfTypeRef) throw()
+SecCFObject::optional(CFTypeRef cfTypeRef) _NOEXCEPT
 {
        if (!cfTypeRef)
                return NULL;
@@ -131,7 +131,7 @@ SecCFObject::required(CFTypeRef cfTypeRef, OSStatus error)
 }
 
 void *
-SecCFObject::allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc)
+SecCFObject::allocate(size_t size, const CFClass &cfclass)
 {
        CFTypeRef p = _CFRuntimeCreateInstance(NULL, cfclass.typeID,
                size + kAlignedRuntimeSize - sizeof(CFRuntimeBase), NULL);
@@ -146,7 +146,7 @@ SecCFObject::allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc)
 }
 
 void
-SecCFObject::operator delete(void *object) throw()
+SecCFObject::operator delete(void *object) _NOEXCEPT
 {
        CFTypeRef cfType = reinterpret_cast<CFTypeRef>(reinterpret_cast<const uint8_t *>(object) - kAlignedRuntimeSize);
 
@@ -217,7 +217,7 @@ SecCFObject::copyDebugDesc()
 }
 
 CFTypeRef
-SecCFObject::handle(bool retain) throw()
+SecCFObject::handle(bool retain) _NOEXCEPT
 {
        CFTypeRef cfType = *this;
        if (retain && !isNew()) CFRetain(cfType);
index 29e9a5d3030929aea1ed684e452b5d43d5dd895c..6ea5445eee4bfdd99abc229a926a6466519457c9 100644 (file)
@@ -54,7 +54,7 @@ APIPTR handle(bool retain) \
 #define SECCFFUNCTIONS_CREATABLE(OBJTYPE, APIPTR, CFCLASS) \
 SECCFFUNCTIONS_BASE(OBJTYPE, APIPTR)\
 \
-void *operator new(size_t size) throw(std::bad_alloc) \
+void *operator new(size_t size)\
 { return SecCFObject::allocate(size, CFCLASS); }
 
 #define SECCFFUNCTIONS(OBJTYPE, APIPTR, ERRCODE, CFCLASS) \
@@ -79,7 +79,7 @@ struct SecRuntimeBase: CFRuntimeBase
 class SecCFObject
 {
 private:
-       void *operator new(size_t) throw(std::bad_alloc);
+       void *operator new(size_t);
 
        // Align up to a multiple of 16 bytes
        static const size_t kAlignedRuntimeSize = SECALIGNUP(sizeof(SecRuntimeBase), 4);
@@ -97,23 +97,23 @@ public:
         return !atomic_flag_test_and_set(&(base->isOld));
        }
 
-       static SecCFObject *optional(CFTypeRef) throw();
+       static SecCFObject *optional(CFTypeRef) _NOEXCEPT;
        static SecCFObject *required(CFTypeRef, OSStatus error);
-       static void *allocate(size_t size, const CFClass &cfclass) throw(std::bad_alloc);
+       static void *allocate(size_t size, const CFClass &cfclass);
 
     SecCFObject();
        virtual ~SecCFObject();
     uint32_t updateRetainCount(intptr_t direction, uint32_t *oldCount);
     uint32_t getRetainCount() {return updateRetainCount(0, NULL);}
 
-       static void operator delete(void *object) throw();
-       virtual operator CFTypeRef() const throw()
+       static void operator delete(void *object) _NOEXCEPT;
+       virtual operator CFTypeRef() const _NOEXCEPT
        {
                return reinterpret_cast<CFTypeRef>(reinterpret_cast<const uint8_t *>(this) - kAlignedRuntimeSize);
        }
 
        // This bumps up the retainCount by 1, by calling CFRetain(), iff retain is true
-       CFTypeRef handle(bool retain = true) throw();
+       CFTypeRef handle(bool retain = true) _NOEXCEPT;
 
     virtual bool equal(SecCFObject &other);
     virtual CFHashCode hash();
@@ -156,10 +156,12 @@ public:
        T *yield() { T *result = static_cast<T *>(ptr); ptr = NULL; return result; }
        
        // dereference operations
-    T* get () const                            { return static_cast<T*>(ptr); }        // mimic auto_ptr
+    T* get () const                            { return static_cast<T*>(ptr); }        // mimic unique_ptr
        operator T * () const           { return static_cast<T*>(ptr); }
        T * operator -> () const        { return static_cast<T*>(ptr); }
        T & operator * () const         { return *static_cast<T*>(ptr); }
+
+    SecPointer& operator=(const SecPointer& other) { SecPointerBase::operator=(other); return *this; }
 };
 
 template <class T>
index c4d09774df3e540472522e3ae8751a0fdc26a4ef..26f409341b1e9afdc6d86703acb72b80ae6ae0d9 100644 (file)
@@ -30,7 +30,7 @@
 #include "errors.h"
 #include <sys/param.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <stdexcept>
 #include <security_utilities/debugging.h>
 #include <CoreFoundation/CFData.h>
index 888fcc8eab9c66514e3c99a6aa14c30dedccb6b1..4f690c25a77b7ac8579de3c255ba68bcc0794304 100644 (file)
@@ -50,11 +50,11 @@ public:
        Error(Database &db);
        Error(int err) : error(err) { }
        Error(int err, const char *msg) : error(err), message(msg) { }
-       ~Error() throw () { }
+       ~Error() _NOEXCEPT { }
        const int error;
        const std::string message;
        
-       const char *what() const throw () { return message.c_str(); }
+       const char *what() const _NOEXCEPT { return message.c_str(); }
     OSStatus osStatus() const;
        int unixError() const;
        
index ba7a581138d10ce675aeb2279a4863b707beb2f8..ce20f30a7cc345926eae94f3d9725e4d7fc5974d 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <security_utilities/blob.h>
 #include <map>
+#include <sstream>
 #include <vector>
 
 namespace Security {
@@ -262,8 +263,10 @@ _BlobType *SuperBlobCore<_BlobType, _magic, _Type>::Maker::make() const
                pc += it->second->length();
                n++;
        }
-       secinfo("superblob", "Maker %p assembles %ld blob(s) into %p (size=%d)",
-               this, mPieces.size(), result, total);
+       ostringstream os;
+       os << "Maker " << this << " assembles " << mPieces.size() << " blob(s) into " << result
+          << " (size=" << total << ")";
+       secinfo("superblob", "%s", os.str().c_str());
        return result;
 }
 
index 33650037c194026f5fc601f0b62a2a6e6c27d4ba..bab8ab471f615facedff4b07949cb7bf5e4fd0db 100644 (file)
@@ -43,20 +43,20 @@ TrackingAllocator::~TrackingAllocator()
 // Standard allocation operations.
 // We pass them down to our subAllocator and keep track of what we've got.
 //
-void *TrackingAllocator::malloc(size_t inSize) throw(std::bad_alloc)
+void *TrackingAllocator::malloc(size_t inSize)
 {
        void *anAddress = subAllocator.malloc(inSize);
        mAllocSet.insert(anAddress);
        return anAddress;
 }
 
-void TrackingAllocator::free(void *inAddress) throw()
+void TrackingAllocator::free(void *inAddress) _NOEXCEPT
 {
        subAllocator.free(inAddress);
        mAllocSet.erase(inAddress);
 }
 
-void *TrackingAllocator::realloc(void *inAddress, size_t inNewSize) throw(std::bad_alloc)
+void *TrackingAllocator::realloc(void *inAddress, size_t inNewSize)
 {
        void *anAddress = subAllocator.realloc(inAddress, inNewSize);
        if (anAddress != inAddress)
index 01e2cccec5ceb07ed243ad912c157395b5230a78..09fbee4ec48d659837287319417d65efccc4ac85 100644 (file)
@@ -47,9 +47,9 @@ public:
        Allocator &subAllocator;
 
        // standard Allocator operations
-       void *malloc(size_t inSize) throw(std::bad_alloc);
-       void free(void *inAddress) throw();
-       void *realloc(void *inAddress, size_t inNewSize) throw(std::bad_alloc);
+       void *malloc(size_t inSize);
+       void free(void *inAddress) _NOEXCEPT;
+       void *realloc(void *inAddress, size_t inNewSize);
 
        // reset frees all memory; commit forgets about it all
        void reset();
index b41ccd7d533644b6b1945d1421ec8a1053301c2a..ed7be8be72d744ce2ba4c9a59f7b0269e34358f3 100644 (file)
@@ -96,6 +96,8 @@ public:
     FileDesc() : mFd(invalidFd), mAtEnd(false) { }
     FileDesc(int fd) : mFd(fd), mAtEnd(false) { }
 
+    FileDesc(const FileDesc& fd) : mFd(fd.mFd), mAtEnd(fd.mAtEnd) { }
+
        static const mode_t modeMissingOk = S_IFIFO;            // in mode means "do not throw on ENOENT"
     
     // implicit file system open() construction
index 9e1c9f7547cf7ebd078af71bfe384232dbd964cc..b6369d5cc633a437582f9597f41a0bec57bb32ac 100644 (file)
@@ -42,6 +42,7 @@
 #include <security_utilities/debugging.h>
 #include <signal.h>
 
+#include <sstream>
 
 namespace Security {
 namespace UnixPlusPlus {
@@ -371,7 +372,7 @@ bool Child::checkStatus(int options)
        secinfo("unixchild", "checking %p (pid %d)", this, this->pid());
        int status;
   again:
-       switch (IFDEBUG(pid_t pid =) ::wait4(this->pid(), &status, options, NULL)) {
+       switch (pid_t pid = ::wait4(this->pid(), &status, options, NULL)) {
        case pid_t(-1):
                switch (errno) {
                case EINTR:
@@ -420,7 +421,9 @@ void Child::checkChildren()
                } else if (!mChildren().empty()) {
                        int status;
                        while (pid_t pid = ::wait4(0, &status, WNOHANG, NULL)) {
-                               secinfo("unixchild", "universal child check (%ld children known alive)", mChildren().size());
+                               ostringstream os;
+                               os << "universal child check (" << mChildren().size() << " children known alive)";
+                               secinfo("unixchild", "%s", os.str().c_str());
                                switch (pid) {
                                case pid_t(-1):
                                        switch (errno) {
index 2bd28d5619cd1cd97fabbb1b6362befed6c8b1ea..b3bd7de17773506e72529bf0ab442d645b492e44 100644 (file)
@@ -35,6 +35,8 @@
 #include <string>
 #include <string.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 namespace Security
 {
 
index 7919078eb4d646f68e5461d0871475ea9174f35e..94611ebcbe82fd9b2cd4721361be79e23588c485 100644 (file)
@@ -29,7 +29,7 @@
 #define _H_UTILITY_CONFIG
 
 #include <CoreFoundation/CFBase.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 //
 // Decide what io apis we'll be using
index e3ae277a202743ead48dbc0354ea5a6fe725d165..2e72e06024f95d1ab3d05e74ba818f251872f973 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #include "sec_xdr.h"
 
index a0f710f1a1a945d94b07e2fca32e04360c75c74c..e5bcc87ac1149babd89e16898201efa6fbc71029 100644 (file)
@@ -72,7 +72,7 @@ static char *sccsid = "@(#)xdr_array.c    2.1 88/07/29 4.0 RPCSRC";
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #include "sec_xdr.h"
 
index 0ceadc0f6a6c5036a316459dfa6db72aab81ec18..e36a6da7187bce5440d678af5f764c27d9bcecf0 100644 (file)
@@ -59,7 +59,7 @@ static char *sccsid = "@(#)xdr_reference.c      2.1 88/07/29 4.0 RPCSRC";
 static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr_reference.c,v 1.11 2002/03/22 21:53:26 obrien Exp $";
 #endif
 #include <sys/cdefs.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 /*
  * xdr_reference.c, Generic XDR routines impelmentation.
  *
index 69ac9335a34e0b2616ff773a0c2e69430eb91935..a4539cab8423e075f83c14991af8fa6a9bbf1907 100644 (file)
@@ -26,7 +26,6 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 
 bool_t
 xdr_AuthorizationItem(XDR *xdrs, AuthorizationItem *objp)
index f74ce46eca56e1b762b319693e4f2ff636e68a76..e7200777bc211895a10cc9e8b7c77b222d41c531 100644 (file)
@@ -24,7 +24,7 @@
 #include <architecture/byte_order.h>
 #include <string.h>            /* bzero() */
 #include <stdlib.h>            /* exit() */
-#include <assert.h>            /* assert() */
+#include <security_utilities/simulatecrash_assert.h>           /* assert() */
 #include <stdio.h>             /* XXX/gh  because utilities/debugging.h doesn't */
 #include <security_utilities/debugging.h>
 
index a03e17e8f9fbfe5b6db96f0b4a59be3c064ed0ad..02666f3780b06fe5a3f501bf38a4097b234f3386 100644 (file)
@@ -82,12 +82,20 @@ bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error);
 
 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups);
 CFArrayRef SecAccessGroupsGetCurrent(void);
+void SecSecurityClientRegularToAppClip(void);
+void SecSecurityClientAppClipToRegular(void);
+void SecSecurityClientSetApplicationIdentifier(CFStringRef identifier);
 
 void SecServerSetTrustdMachServiceName(const char *name);
 
 // checkpw.c
 int checkpw_internal( const struct passwd* pw, const char* password );
 
+#ifdef __arm64__
+extern SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate) __asm("_SecCertificateCopyPublicKey");
+extern CFDataRef SecCertificateCopySerialNumber_ios(SecCertificateRef certificate) __asm("_SecCertificateCopySerialNumber");
+#endif
+
 #pragma clang diagnostic pop
 
 #endif /* macos_tapi_hack_h */
index 6c7b177da4941dd968330f722267879bdc056b26..bc53356d05cdb622619b13e3527fffc28659a124 100644 (file)
@@ -33,7 +33,6 @@ extern "C" {
 extern int test_strict_bats;
 extern int test_verbose;
 extern int test_check_leaks;
-extern char **test_skip_leaks_test;
 
 int tests_begin(int argc, char * const *argv);
 
index 8692ff3ce720d1ee07fe5123afb2b53bddedd483..f644cbe1d11514ffda05aaaf9470a18ef165a179 100644 (file)
@@ -59,7 +59,6 @@ int test_strict_bats = 1;
 int test_verbose = 0;
 int test_onebatstest = 0;
 int test_check_leaks = 0;
-char **test_skip_leaks_test = NULL;
 
 #ifdef NO_SERVER
 #include "keychain/securityd/spi.h"
@@ -210,34 +209,8 @@ static int tests_run_test(struct one_test_s *test, int argc, char * const *argv)
             free(cmd);
         }
         if (ret != 0) {
-            unsigned n = 0;
             fprintf(stdout, "leaks found in test %s\n", test->name);
-
-            if (test_skip_leaks_test) {
-                while (test_skip_leaks_test[n]) {
-                    if (strcmp(test_skip_leaks_test[n], test->name) == 0) {
-                        fprintf(stdout, "test %s known to be leaky, skipping\n", test->name);
-                        ret = 0;
-                        break;
-                    }
-                }
-            }
-            if (ret) {
-                token = "FAIL";
-            }
-        } else {
-            if (test_skip_leaks_test) {
-                unsigned n = 0;
-
-                while (test_skip_leaks_test[n]) {
-                    if (strcmp(test_skip_leaks_test[n], test->name) == 0) {
-                        fprintf(stdout, "leaks didn't find leak in test %s, yet it was ignore\n", test->name);
-                        token = "FAIL";
-                        break;
-                    }
-                }
-            }
-
+            token = "FAIL";
         }
     }
 
index 7bf5e726a5f727f8db172e7e457b5da75809e871..cea9ccdb39ec9b3b16f4f4d1e9c4cb4a59b1b02e 100644 (file)
@@ -41,12 +41,12 @@ __BEGIN_DECLS
 #define DISABLED_ONE_TEST(x) ONE_TEST(x)
 #define OFF_ONE_TEST(x) ONE_TEST(x)
 
-typedef int (*one_test_entry)(int argc, char *const *argv);
+typedef int (*_Nonnull one_test_entry)(int argc, char *_Nonnull const *_Nonnull argv);
 
 #define ONE_TEST_ENTRY(x) int x(int argc, char *const *argv)
 
 struct one_test_s {
-    char *name;            /* test name. */
+    const char * _Nonnull name; /* test name. */
     one_test_entry entry;  /* entry point. */
     int off;               /* off by default. */
     int sub_tests;         /* number of subtests. */
@@ -55,7 +55,7 @@ struct one_test_s {
     int todo_tests;        /* number of todo tests that failed as expected. */
     int actual_tests;      /* number of tests attempted. */
     int planned_tests;     /* number of planned tests. */
-    const char *plan_file; /* full path to file that called plan_tests() */
+    const char *_Nonnull plan_file; /* full path to file that called plan_tests() */
     int plan_line;         /* line number in plan_file at which plan_tests was called. */
     unsigned long duration; /* test duration in msecs. */
     /* add more later: timing, etc... */
@@ -215,22 +215,22 @@ static void test_failed_noreturn() __attribute((analyzer_noreturn)) {
 })
 
 
-extern const char *test_directive;
-extern const char *test_reason;
+extern const char * _Nonnull test_directive;
+extern const char * _Nonnull test_reason;
 
-void test_bail_out(const char *reason, const char *file, unsigned line);
-int test_diag(const char *directive, const char *reason,
-       const char *file, unsigned line, const char *fmt, ...) __attribute__((format(printf, 5, 6)));
-int test_ok(int passed, __attribute((cf_consumed)) CFStringRef description, const char *directive,
-       const char *reason, const char *file, unsigned line, const char *fmt, ...);
-void test_plan_skip_all(const char *reason);
-void test_plan_tests(int count, const char *file, unsigned line);
+void test_bail_out(const char * _Nonnull reason, const char * _Nonnull file, unsigned line);
+int test_diag(const char *_Nonnull directive, const char *_Nonnull reason,
+       const char *_Nonnull file, unsigned line, const char *_Nonnull fmt, ...) __attribute__((format(printf, 5, 6)));
+int test_ok(int passed, __attribute((cf_consumed)) CFStringRef _Nullable description, const char *_Nonnull directive,
+       const char *_Nonnull reason, const char *_Nonnull file, unsigned line, const char *_Nullable fmt, ...);
+void test_plan_skip_all(const char *_Nonnull reason);
+void test_plan_tests(int count, const char *_Nonnull file, unsigned line);
 int test_plan_ok(void);
-void test_plan_final(int *failed, int *todo_pass, int *todo, int *actual, int *planned, const char **file, int *line);
+void test_plan_final(int *_Nonnull failed, int *_Nonnull todo_pass, int *_Nonnull todo, int *_Nonnull actual, int *_Nonnull planned, const char *_Nonnull *_Nonnull file, int *_Nonnull line);
 
-void test_skip(const char *reason, int how_many, int unless);
+void test_skip(const char *_Nonnull reason, int how_many, int unless);
 
-const char *sec_errstr(int err);
+const char *_Nonnull sec_errstr(int err);
 
 __END_DECLS
 
diff --git a/OSX/sec/Security/AppleExternalRootCertificates.h b/OSX/sec/Security/AppleExternalRootCertificates.h
new file mode 100644 (file)
index 0000000..392314c
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * 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 _sec_AppleExternalRootCertificates_h
+#define _sec_AppleExternalRootCertificates_h
+
+#include <stdint.h>
+
+/* subject:/CN=Apple External EC Root/O=Apple Inc./C=US */
+/* issuer :/CN=Apple External EC Root/O=Apple Inc./C=US */
+uint8_t _AppleExternalECRootCA[519]={
+    0x30,0x82,0x02,0x03,0x30,0x82,0x01,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x76,
+    0xAD,0x18,0xDB,0x88,0x12,0xB0,0x56,0xA1,0x26,0x9D,0x44,0x91,0x4E,0xEB,0xD4,0x30,
+    0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x43,0x31,0x1F,0x30,
+    0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x70,0x70,0x6C,0x65,0x20,0x45,0x78,
+    0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x45,0x43,0x20,0x52,0x6F,0x6F,0x74,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
+    0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
+    0x30,0x1E,0x17,0x0D,0x32,0x30,0x30,0x31,0x32,0x33,0x30,0x30,0x34,0x36,0x34,0x38,
+    0x5A,0x17,0x0D,0x34,0x35,0x30,0x31,0x31,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,
+    0x30,0x43,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x0C,0x16,0x41,0x70,0x70,
+    0x6C,0x65,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x45,0x43,0x20,0x52,
+    0x6F,0x6F,0x74,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,
+    0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,0x30,0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,
+    0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x17,0xC7,0x4A,
+    0xDD,0xD2,0x3C,0xAF,0xB0,0x76,0xA3,0x2A,0x57,0x1E,0x2C,0x7F,0x38,0x0B,0x62,0x04,
+    0x75,0x54,0x36,0xBB,0x0E,0xB7,0xAA,0x2C,0x7B,0xF9,0xE8,0xB3,0xC5,0x09,0x08,0xB3,
+    0xDF,0x20,0x27,0xB1,0x95,0x96,0x16,0x63,0x46,0x6C,0xFF,0x24,0xA4,0x00,0xF2,0x87,
+    0xC1,0x7F,0xED,0xE7,0x28,0x49,0xB3,0x5A,0xBC,0x02,0xAA,0x93,0x47,0x62,0x9E,0x5F,
+    0x9F,0x43,0xC9,0xF2,0x25,0x89,0x83,0x62,0x60,0xBB,0x57,0x6A,0x59,0xA8,0x0B,0xB3,
+    0x32,0x25,0x75,0xD7,0x8B,0xEF,0xF1,0xD2,0x41,0xD3,0x57,0x90,0x4B,0xA3,0x42,0x30,
+    0x40,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,
+    0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3F,0xA4,0xC0,
+    0x94,0x20,0x70,0xCB,0x3B,0xDD,0xA8,0x54,0xE6,0x14,0x1E,0x29,0xCC,0x4D,0x14,0x38,
+    0x53,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,
+    0x06,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x68,0x00,
+    0x30,0x65,0x02,0x31,0x00,0x9D,0x4D,0x05,0x75,0x65,0x76,0xD8,0x70,0x03,0x14,0x39,
+    0x8E,0x41,0xC7,0xB2,0xFE,0x53,0xDC,0x6E,0xE6,0x13,0x18,0x51,0x0A,0x1F,0xC4,0xB5,
+    0xCF,0x22,0x40,0x75,0x79,0xCA,0x98,0x6E,0xB0,0xF5,0x88,0x71,0x11,0x3E,0x3B,0x7C,
+    0x38,0x35,0xD7,0x1F,0xB9,0x02,0x30,0x5B,0x7C,0x87,0xF3,0xF6,0xDD,0x51,0x96,0x6D,
+    0xF8,0x7E,0xF2,0x78,0x3A,0xC6,0xA6,0x85,0x55,0xE8,0xBD,0x20,0xAC,0xE1,0x58,0x79,
+    0x14,0x50,0x3D,0x54,0xC3,0xF1,0x22,0x15,0x18,0x87,0x95,0x67,0x9E,0x19,0x69,0x89,
+    0x51,0x2C,0xD0,0x55,0xEA,0x52,0x6C,
+};
+
+/* subject:/CN=Test Apple External EC Root/O=Apple Inc./C=US */
+/* issuer :/CN=Test Apple External EC Root/O=Apple Inc./C=US */
+uint8_t _TestAppleExternalECRootCA[530]={
+    0x30,0x82,0x02,0x0E,0x30,0x82,0x01,0x93,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x70,
+    0x1B,0x1A,0x15,0x07,0x97,0x6A,0x6A,0x8D,0xBD,0x23,0x36,0xF2,0x48,0x4A,0x4E,0x30,
+    0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x30,0x48,0x31,0x24,0x30,
+    0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,0x54,0x65,0x73,0x74,0x20,0x41,0x70,0x70,
+    0x6C,0x65,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x45,0x43,0x20,0x52,
+    0x6F,0x6F,0x74,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,
+    0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,0x30,0x35,0x31,
+    0x38,0x30,0x30,0x34,0x36,0x5A,0x17,0x0D,0x34,0x34,0x31,0x30,0x32,0x39,0x31,0x38,
+    0x30,0x30,0x34,0x36,0x5A,0x30,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,
+    0x0C,0x1B,0x54,0x65,0x73,0x74,0x20,0x41,0x70,0x70,0x6C,0x65,0x20,0x45,0x78,0x74,
+    0x65,0x72,0x6E,0x61,0x6C,0x20,0x45,0x43,0x20,0x52,0x6F,0x6F,0x74,0x31,0x13,0x30,
+    0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,
+    0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,
+    0x76,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x05,0x2B,0x81,
+    0x04,0x00,0x22,0x03,0x62,0x00,0x04,0x91,0xC2,0xB5,0xBC,0x6A,0x99,0x8B,0x68,0x5A,
+    0xCE,0xD4,0x8C,0x48,0xF1,0x0F,0xD2,0x00,0x8D,0x88,0x6A,0x14,0x53,0xEC,0xFA,0xE7,
+    0xCC,0x97,0x01,0x0A,0x64,0x9F,0x69,0xE2,0xF8,0xC8,0x54,0x0E,0xD2,0x7C,0x9A,0x22,
+    0xE5,0xEF,0xE1,0x56,0xF3,0x2A,0xB0,0x99,0xAD,0x88,0x4A,0xCE,0x2C,0xD4,0x60,0x90,
+    0xF1,0x90,0xA6,0xB0,0x45,0xC4,0x82,0x0B,0xB0,0x46,0xE5,0xE7,0x14,0xCC,0x98,0x9E,
+    0x13,0xD0,0x43,0x51,0x64,0x0C,0xCD,0xA6,0xAF,0x5C,0x14,0x52,0x5A,0xF2,0x08,0x8D,
+    0xE4,0x04,0x54,0x74,0x13,0x91,0x02,0xA3,0x42,0x30,0x40,0x30,0x0F,0x06,0x03,0x55,
+    0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x07,0x6B,0x07,0x47,0x33,0xE4,0x96,0xB4,0xFC,
+    0x6F,0xFA,0x32,0x2C,0x8E,0xBE,0x70,0xC2,0x8F,0x80,0x3C,0x30,0x0E,0x06,0x03,0x55,
+    0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0A,0x06,0x08,0x2A,
+    0x86,0x48,0xCE,0x3D,0x04,0x03,0x03,0x03,0x69,0x00,0x30,0x66,0x02,0x31,0x00,0xED,
+    0xC0,0xC6,0x05,0x62,0x3E,0x4C,0x76,0x0C,0x5B,0x62,0xF9,0x54,0x2E,0x90,0xC4,0xDB,
+    0x29,0xD1,0x2D,0x2F,0x30,0x15,0x8A,0xCF,0x9F,0xA0,0x5A,0x40,0x6C,0x6A,0x9F,0x76,
+    0xC1,0x5E,0xC3,0x37,0x40,0xA1,0x9B,0xA4,0x0D,0x31,0x9D,0x4C,0xBB,0x2B,0xAE,0x02,
+    0x31,0x00,0xDA,0xCB,0xE4,0x1D,0x12,0x4E,0x03,0x2F,0x91,0xCF,0x2A,0xB3,0xF4,0xB3,
+    0x8D,0x89,0x69,0xF2,0x9B,0xFC,0xB4,0x05,0x95,0x0B,0xCB,0x63,0x12,0xC8,0xAA,0x8D,
+    0x58,0xE8,0xF3,0x2A,0xF6,0x36,0x32,0xAC,0x0A,0x24,0x94,0x84,0x85,0x00,0x96,0x62,
+    0x62,0x57,
+};
+
+#endif /* _sec_AppleExternalRootCertificates_h */
index 0439e50aeebff695274887a5ebd64c2b0fc72b21..7165202808764b42dfa023d9ce7c461fad68fd84 100644 (file)
 #include <Security/SecOTRSession.h>
 #include <Security/SecInternal.h>
 #include <Security/SecBasePriv.h>
+#include <Security/SecKey.h>
+#include <Security/SecItem.h>
+#include <utilities/SecCFWrappers.h>
+#include <Security/SecOTRIdentityPriv.h>
 
 static void RegressionsLogError(CFErrorRef error) {
     if (error == NULL) {
@@ -52,13 +56,59 @@ static void RegressionsLogError(CFErrorRef error) {
     CFReleaseSafe(tempDictionary);
 }
 
-static int kTestTestCount = 18;
+static int kTestTestCount = 27;
+
+static void otr_00_identity_MessageProtectionKeys()
+{
+    // We create a MessageProtection-style key.
+    int32_t keysz32 = 256;
+    CFNumberRef ksizeNumber = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDictionaryRef dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                        kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom,
+                                                        kSecAttrKeyClass, kSecAttrKeyClassPrivate,
+                                                        kSecAttrKeySizeInBits, ksizeNumber,
+                                                        kSecAttrIsPermanent, kCFBooleanFalse, NULL);
+    
+    CFErrorRef error = NULL;
+    SecKeyRef testIdentityKey = SecKeyCreateRandomKey(dict, &error);
+    ok(testIdentityKey != NULL, "Failed to create test key.");
+    
+    CFReleaseSafe(ksizeNumber);
+    CFReleaseSafe(dict);
+    
+    SecOTRFullIdentityRef identity1 = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, testIdentityKey, &error);
+    ok(identity1->isMessageProtectionKey, "Should be MessageProtection Key");
+    ok(identity1->privateKeyPersistentRef == NULL, "MessageProtection key shouldn't have a peristent ref.");
+    
+    CFMutableDataRef serializeInto = CFDataCreateMutable(kCFAllocatorDefault, 100);
+    SecOTRFIAppendSerialization(identity1, serializeInto, &error);
+    
+    SecOTRFullIdentityRef identity2 = SecOTRFullIdentityCreateFromData(kCFAllocatorDefault, serializeInto, &error);
+    ok(identity2->isMessageProtectionKey, "Should still be a MessageProtection Key");
+    ok(identity2->privateKeyPersistentRef == NULL, "MessageProtection key shouldn't have a peristent ref.");
+    
+    CFDataRef serializedKey1 = SecKeyCopyExternalRepresentation(identity1->privateSigningKey, &error);
+    CFDataRef serializedKey2 = SecKeyCopyExternalRepresentation(identity2->privateSigningKey, &error);
+    
+    ok(CFEqual(serializedKey1, serializedKey2));
+    ok(error == NULL, "Testing shouldn't cause any errors");
+    
+    CFReleaseSafe(error);
+    CFReleaseSafe(serializedKey1);
+    CFReleaseSafe(serializedKey2);
+    CFReleaseSafe(identity1);
+    CFReleaseSafe(identity2);
+    CFReleaseSafe(testIdentityKey);
+    CFReleaseNull(serializeInto);
+}
+
 static void tests(void)
 {
     CFErrorRef testError = NULL;
     
     SecOTRFullIdentityRef idToPurge = SecOTRFullIdentityCreate(kCFAllocatorDefault, &testError);
     ok(idToPurge != NULL, "Make Identity: %@", testError);
+    ok(idToPurge->isMessageProtectionKey == false, "Keys shouldn't be defaulting to MessageProtection type");
     RegressionsLogError(testError);
     CFReleaseNull(testError);
 
@@ -70,6 +120,7 @@ static void tests(void)
     
     SecOTRFullIdentityRef purgeIdInflate = SecOTRFullIdentityCreateFromData(kCFAllocatorDefault, purgeExport, &testError);
     ok(purgeIdInflate != NULL, "Inflate Identity: %@", testError);
+    ok(idToPurge->isMessageProtectionKey == false, "Keys shouldn't be re-imported as MessageProtection types");
     RegressionsLogError(testError);
     CFReleaseNull(testError);
 
@@ -195,8 +246,12 @@ static void tests(void)
     CFReleaseSafe(failIDInflate2);
     CFReleaseSafe(testInteropImport);
     CFReleaseSafe(interopIDInflate);
+    
+    otr_00_identity_MessageProtectionKeys();
 }
 
+
+
 int otr_00_identity(int argc, char *const *argv)
 {
     plan_tests(kTestTestCount);
index 0e7e535071c0a99ccbb96693518bf95918fce979..a7a1d78ce8edaf2152518d55ae073ae79f61cb0f 100644 (file)
@@ -152,7 +152,7 @@ static void tests(void)
             "trust is kSecTrustResultOtherError");
     }
        SecKeyRef pub_key_leaf;
-       isnt(pub_key_leaf = SecTrustCopyPublicKey(trust), NULL, "get leaf pub key");
+       isnt(pub_key_leaf = SecTrustCopyKey(trust), NULL, "get leaf pub key");
     if (!pub_key_leaf) { goto errOut; }
     CFErrorRef error = NULL;
     ok(SecKeyVerifySignature(pub_key_leaf, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, sha1Data, signature, &error),
diff --git a/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c b/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.c
deleted file mode 100644 (file)
index bf63ea1..0000000
+++ /dev/null
@@ -1,696 +0,0 @@
-/*
- * Copyright (c) 2006-2018 Apple Inc. All Rights Reserved.
- */
-
-#include <AssertMacros.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTrustPriv.h>
-#include <utilities/array_size.h>
-#include <utilities/SecCFRelease.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "shared_regressions.h"
-
-#include "si-23-sectrust-ocsp.h"
-
-static void tests(void)
-{
-    SecTrustRef trust;
-    SecCertificateRef cert0, cert1;
-    isnt(cert0 = SecCertificateCreateWithBytes(NULL, _ocsp_c0, sizeof(_ocsp_c0)),
-           NULL, "create cert0");
-    isnt(cert1 = SecCertificateCreateWithBytes(NULL, _ocsp_c1, sizeof(_ocsp_c1)),
-           NULL, "create cert1");
-    CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-        &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(certs, cert0);
-    CFArrayAppendValue(certs, cert1);
-
-    SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
-    SecPolicyRef ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
-    const void *v_policies[] = { sslPolicy, ocspPolicy };
-    CFArrayRef policies = CFArrayCreate(NULL, v_policies,
-       array_size(v_policies), &kCFTypeArrayCallBacks);
-    CFRelease(sslPolicy);
-    CFRelease(ocspPolicy);
-    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
-        "create trust");
-    /* April 14, 2019 at 10:46:40 PM PDT */
-    CFDateRef date = CFDateCreate(NULL, 577000000.0);
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-
-    is(SecTrustGetVerifyTime(trust), 577000000.0, "get date");
-
-    SecTrustResultType trustResult;
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-               "trust is kSecTrustResultUnspecified");
-
-    /* Certificates are only EV if they are also CT. */
-    CFDictionaryRef info = SecTrustCopyInfo(trust);
-    CFBooleanRef ev = (CFBooleanRef)CFDictionaryGetValue(info,
-        kSecTrustInfoExtendedValidationKey);
-    ok(ev, "extended validation succeeded");
-
-    CFReleaseSafe(info);
-    CFReleaseSafe(trust);
-    CFReleaseSafe(policies);
-    CFReleaseSafe(certs);
-    CFReleaseSafe(cert0);
-    CFReleaseSafe(cert1);
-    CFReleaseSafe(date);
-}
-
-static void test_ocsp_responder_policy() {
-    SecCertificateRef leaf = NULL, subCA = NULL, responderCert = NULL;
-    CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-                                                   &kCFTypeArrayCallBacks);
-    SecTrustRef trust = NULL;
-    SecPolicyRef ocspSignerPolicy = NULL;
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-
-    /* August 14, 2018 at 9:26:40 PM PDT */
-    CFDateRef date = CFDateCreate(NULL, 556000000.0);
-
-    isnt(leaf = SecCertificateCreateWithBytes(NULL, valid_ist_certificate,
-                                                       sizeof(valid_ist_certificate)), NULL, "create ist leaf");
-    isnt(subCA = SecCertificateCreateWithBytes(NULL, ist_intermediate_certificate,
-                                                       sizeof(ist_intermediate_certificate)), NULL, "create ist subCA");
-    CFArrayAppendValue(certs, leaf);
-    CFArrayAppendValue(certs, subCA);
-
-    ok(ocspSignerPolicy = SecPolicyCreateOCSPSigner(),
-       "create ocspSigner policy");
-
-    ok_status(SecTrustCreateWithCertificates(certs, ocspSignerPolicy, &trust),
-              "create trust for c0 -> c1");
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
-              "trust is kSecTrustResultRecoverableTrustFailure");
-
-    isnt(responderCert = SecCertificateCreateWithBytes(NULL, _responderCert,
-                                                       sizeof(_responderCert)), NULL, "create responderCert");
-    CFArraySetValueAtIndex(certs, 0, responderCert);
-    ok_status(SecTrustCreateWithCertificates(certs, ocspSignerPolicy, &trust),
-              "create trust for ocspResponder -> c1");
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-              "trust is kSecTrustResultUnspecified");
-
-    CFReleaseNull(leaf);
-    CFReleaseNull(subCA);
-    CFReleaseNull(responderCert);
-    CFReleaseNull(certs);
-    CFReleaseNull(trust);
-    CFReleaseSafe(ocspSignerPolicy);
-    CFReleaseNull(date);
-}
-
-static void test_revocation() {
-    SecTrustRef trust;
-    SecCertificateRef rcert0, rcert1;
-    isnt(rcert0 = SecCertificateCreateWithBytes(NULL,
-         revoked_ist_certificate, sizeof(revoked_ist_certificate)),
-         NULL, "create rcert0");
-    isnt(rcert1 = SecCertificateCreateWithBytes(NULL,
-         ist_intermediate_certificate, sizeof(ist_intermediate_certificate)),
-         NULL, "create rcert1");
-    CFMutableArrayRef rcerts = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-                                                   &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(rcerts, rcert0);
-    CFArrayAppendValue(rcerts, rcert1);
-
-    SecPolicyRef sslPolicy = SecPolicyCreateSSL(true, CFSTR("revoked.geotrust-global-ca.test-pages.certificatemanager.apple.com"));
-    SecPolicyRef ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
-    const void *v_policies[] = { sslPolicy, ocspPolicy };
-    CFArrayRef policies = CFArrayCreate(NULL, v_policies,
-                                        array_size(v_policies), &kCFTypeArrayCallBacks);
-    CFRelease(sslPolicy);
-    CFRelease(ocspPolicy);
-    ok_status(SecTrustCreateWithCertificates(rcerts, policies, &trust),
-              "create trust");
-    /* Feb 5th 2015. */
-    CFDateRef date = CFDateCreate(NULL, 444900000);
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    CFReleaseSafe(date);
-
-    is(SecTrustGetVerifyTime(trust), 444900000, "get date");
-
-    SecTrustResultType trustResult;
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is((trustResult > kSecTrustResultUnspecified), true,
-       "trust is %d, expected value greater than 4", (int)trustResult);
-    CFDictionaryRef results = SecTrustCopyResult(trust);
-    CFTypeRef revoked = NULL;
-    if (results) {
-        CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
-        if (perCertResults) {
-            CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
-            if (leafResults) {
-                revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
-            }
-        }
-    }
-    is(revoked != NULL, true, "revoked result is %@", revoked);
-    CFReleaseSafe(results);
-
-
-    /* Now verify the cert at a date in the past relative to the previous
-       date, but still within the cert's validity period. Although the
-       cached response from our prior attempt will appear to have been
-       produced in the future, it should still be honored since it's
-       validly signed.
-     */
-    /* Dec 11th 2014. */
-    date = CFDateCreate(NULL, 440000000);
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    CFReleaseSafe(date);
-
-    is(SecTrustGetVerifyTime(trust), 440000000, "get date");
-
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is((trustResult > kSecTrustResultUnspecified), true,
-              "trust is %d, expected value greater than 4", (int)trustResult);
-    results = SecTrustCopyResult(trust);
-    revoked = NULL;
-    if (results) {
-        CFArrayRef perCertResults = CFDictionaryGetValue(results, CFSTR("TrustResultDetails"));
-        if (perCertResults) {
-            CFDictionaryRef leafResults = CFArrayGetValueAtIndex(perCertResults, 0);
-            if (leafResults) {
-                revoked = CFDictionaryGetValue(leafResults, CFSTR("Revocation"));
-            }
-        }
-    }
-    is(revoked != NULL, true, "revoked result is %@", revoked);
-    CFReleaseSafe(results);
-
-    CFReleaseSafe(trust);
-    CFReleaseSafe(policies);
-    CFReleaseSafe(rcerts);
-    CFReleaseSafe(rcert0);
-    CFReleaseSafe(rcert1);
-}
-
-static void test_forced_revocation()
-{
-    /*
-     *  Test verification requiring a positive response from the revocation server
-     */
-
-    OSStatus status;
-    SecCertificateRef smime_leaf_cert;
-    SecCertificateRef smime_CA_cert;
-    SecCertificateRef smime_root_cert;
-
-    // Import certificates from byte array above
-    isnt(smime_leaf_cert = SecCertificateCreateWithBytes(NULL, ocsp_smime_leaf_certificate, sizeof(ocsp_smime_leaf_certificate)),
-         NULL, "SMIME Leaf Cert");
-    isnt(smime_CA_cert   = SecCertificateCreateWithBytes(NULL, ocsp_smime_CA_certificate, sizeof(ocsp_smime_CA_certificate)),
-         NULL, "SMIME CA Cert");
-    isnt(smime_root_cert = SecCertificateCreateWithBytes(NULL, ocsp_smime_root_certificate, sizeof(ocsp_smime_root_certificate)),
-         NULL, "SMIME Root Cert");
-
-    SecPolicyRef smimePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleSMIME, NULL);
-    SecPolicyRef revocPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod | kSecRevocationRequirePositiveResponse);
-    isnt(smimePolicy, NULL, "SMIME Policy");
-    isnt(revocPolicy, NULL, "SMIME Revocation Policy");
-
-    // Default Policies
-    CFMutableArrayRef SMIMEDefaultPolicy = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(SMIMEDefaultPolicy, smimePolicy);
-
-    // Default Policies + explicit revocation
-    CFMutableArrayRef SMIMEDefaultPolicyWithRevocation = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(SMIMEDefaultPolicyWithRevocation, smimePolicy);
-    CFArrayAppendValue(SMIMEDefaultPolicyWithRevocation, revocPolicy);
-
-    // Valid chain of Cert (leaf + CA)
-    CFMutableArrayRef SMIMECertChain = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(SMIMECertChain, smime_leaf_cert);
-    CFArrayAppendValue(SMIMECertChain, smime_CA_cert);
-
-    // Valid anchor certs
-    CFMutableArrayRef SMIMEAnchors = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-    CFArrayAppendValue(SMIMEAnchors, smime_root_cert);
-
-    // Free Resources contained in arrays
-    CFReleaseSafe(smime_leaf_cert);
-    CFReleaseSafe(smime_CA_cert);
-    CFReleaseSafe(smime_root_cert);
-    CFReleaseSafe(smimePolicy);
-    CFReleaseSafe(revocPolicy);
-
-    CFDateRef VerifyDate;
-    isnt(VerifyDate = CFDateCreate(NULL, 332900000.0), NULL, "Create verify date");
-    if (!VerifyDate) { goto errOut; }
-
-    // Standard evaluation for the given verify date
-    {
-        SecTrustRef trust = NULL;
-        SecTrustResultType trust_result;
-
-        ok_status(status = SecTrustCreateWithCertificates(SMIMECertChain, SMIMEDefaultPolicy, &trust),
-                  "SecTrustCreateWithCertificates");
-        ok_status(SecTrustSetVerifyDate(trust, VerifyDate), "Set date");
-        ok_status(SecTrustSetAnchorCertificates(trust, SMIMEAnchors), "Set anchors");
-
-        ok_status(status = SecTrustEvaluate(trust, &trust_result), "SecTrustEvaluate");
-
-        // Check results
-        // NOTE: We now expect a fatal error, since the "TC TrustCenter Class 1 L1 CA IX" CA
-        // is revoked. That CA is no longer present in Valid since the TC root was removed
-        // from the trust store, and as of May 2018, its OCSP server no longer resolves in DNS.
-        // However, the OCSP URI for the CA's issuer is still active and reports the CA as revoked.
-        //
-        is_status(trust_result, kSecTrustResultFatalTrustFailure, "trust is kSecTrustResultFatalTrustFailure");
-
-        CFReleaseNull(trust);
-    }
-
-    // Revocation-required evaluation should fail, since this CA's servers no longer exist
-    // and no valid responses are available
-    {
-        SecTrustRef trust = NULL;
-        SecTrustResultType trust_result;
-
-        ok_status(status = SecTrustCreateWithCertificates(SMIMECertChain, SMIMEDefaultPolicyWithRevocation, &trust),
-                  "SecTrustCreateWithCertificates");
-        ok_status(SecTrustSetVerifyDate(trust, VerifyDate), "Set date");
-        ok_status(SecTrustSetAnchorCertificates(trust, SMIMEAnchors), "Set anchors");
-
-        ok_status(status = SecTrustEvaluate(trust, &trust_result), "SecTrustEvaluate");
-
-        // Check results
-        // NOTE: We now expect a fatal error, since the "TC TrustCenter Class 1 L1 CA IX" CA
-        // is revoked. That CA is no longer present in Valid since the TC root was removed
-        // from the trust store, and as of May 2018, its OCSP server no longer resolves in DNS.
-        // However, the OCSP URI for the CA's issuer is still active and reports the CA as revoked.
-        //
-        is_status(trust_result, kSecTrustResultFatalTrustFailure, "trust is kSecTrustResultFatalTrustFailure");
-
-        CFReleaseNull(trust);
-    }
-
-    // Free remaining resources
-errOut:
-    CFReleaseSafe(VerifyDate);
-    CFReleaseSafe(SMIMEDefaultPolicy);
-    CFReleaseSafe(SMIMEDefaultPolicyWithRevocation);
-    CFReleaseSafe(SMIMECertChain);
-    CFReleaseSafe(SMIMEAnchors);
-}
-
-#if 0
-static void hexdump(const uint8_t *bytes, size_t len) {
-       size_t ix;
-       printf("#anchor-sha1: ");
-       for (ix = 0; ix < len; ++ix) {
-               printf("%02X", bytes[ix]);
-       }
-       printf("\n");
-}
-
-static void datadump(const uint8_t *bytes, size_t len) {
-       size_t ix;
-       printf("#anchor-sha1: ");
-       for (ix = 0; ix < len; ++ix) {
-               printf("%c", bytes[ix]);
-       }
-       printf("\n");
-}
-
-static void display_anchor_digest(SecTrustRef trust) {
-    CFIndex count = SecTrustGetCertificateCount(trust);
-    SecCertificateRef anchor = SecTrustGetCertificateAtIndex(trust, count - 1);
-    CFDataRef digest = SecCertificateGetSHA1Digest(anchor);
-    CFDataRef xml = CFPropertyListCreateXMLData(NULL, digest);
-    datadump(CFDataGetBytePtr(xml), CFDataGetLength(xml));
-}
-#endif
-
-static void test_aia(void) {
-    SecCertificateRef ovh = NULL, comodo_ev = NULL, comodo_aia = NULL;
-    CFMutableArrayRef certs = NULL, policies = NULL;
-    SecPolicyRef sslPolicy = NULL, revPolicy = NULL;
-    CFDateRef verifyDate = NULL;
-    CFDictionaryRef info = NULL;
-    SecTrustRef trust = NULL;
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-    CFBooleanRef ev = NULL;
-
-    /* Initialize common variables */
-    isnt(ovh = SecCertificateCreateWithBytes(NULL, ovh_certificate,
-        sizeof(ovh_certificate)), NULL, "create ovh cert");
-    isnt(comodo_ev = SecCertificateCreateWithBytes(NULL, comodo_ev_certificate,
-        sizeof(comodo_ev_certificate)), NULL, "create comodo_ev cert");
-    isnt(comodo_aia = SecCertificateCreateWithBytes(NULL,
-        comodo_aia_certificate, sizeof(comodo_aia_certificate)), NULL,
-        "create comodo_aia cert");
-    certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-        &kCFTypeArrayCallBacks);
-    policies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-        &kCFTypeArrayCallBacks);
-    sslPolicy = SecPolicyCreateSSL(false, NULL); // For now, use SSL client policy to avoid SHA-1 deprecation
-    revPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
-    CFArrayAppendValue(policies, sslPolicy);
-    CFArrayAppendValue(policies, revPolicy);
-    /* May 9th 2018. */
-    verifyDate = CFDateCreate(NULL, 547600500);
-
-    /* First run with no intermediate and disallow network fetching.
-     * Evaluation should fail because it couldn't get the intermediate. */
-    CFArrayAppendValue(certs, ovh);
-    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
-              "create trust");
-    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
-    ok_status(SecTrustSetNetworkFetchAllowed(trust, false), "set no network");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
-       "trust is kSecTrustResultRecoverableTrustFailure");
-
-    /* Now allow networking. Evaluation should succeed after fetching
-     * the intermediate. */
-    ok_status(SecTrustSetNetworkFetchAllowed(trust, true), "set allow network");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-       "trust is kSecTrustResultUnspecified");
-    CFReleaseNull(trust);
-
-    /* Now run with the intermediate returned by the ssl server. */
-    CFArrayAppendValue(certs, comodo_ev);
-    ok_status(SecTrustCreateWithCertificates(certs, sslPolicy, &trust),
-        "create trust");
-    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-               "trust is kSecTrustResultUnspecified");
-    info = SecTrustCopyInfo(trust);
-    ev = (CFBooleanRef)CFDictionaryGetValue(info,
-        kSecTrustInfoExtendedValidationKey);
-    ok(ev, "extended validation succeeded due to caissuers fetch");
-    //display_anchor_digest(trust);
-    CFReleaseSafe(info);
-    CFReleaseSafe(trust);
-
-    /* Now run with the intermediate returned by following the url in the
-       Certificate Access Information Authority (AIA) extension of the ovh
-       leaf certificate. */
-    CFArrayAppendValue(certs, comodo_aia);
-    ok_status(SecTrustCreateWithCertificates(certs, sslPolicy, &trust),
-        "re-create trust with aia intermediate");
-    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-               "trust is kSecTrustResultUnspecified");
-    info = SecTrustCopyInfo(trust);
-    ev = (CFBooleanRef)CFDictionaryGetValue(info,
-        kSecTrustInfoExtendedValidationKey);
-    ok(ev, "extended validation succeeded");
-    //display_anchor_digest(trust);
-    CFReleaseSafe(info);
-    CFReleaseSafe(trust);
-
-    /* Now run with the intermediate returned by following the url in the
-       Certificate Access Information Authority (AIA) extension of the ovh
-       leaf certificate. */
-    CFArrayRemoveValueAtIndex(certs, 1);
-    ok_status(SecTrustCreateWithCertificates(certs, sslPolicy, &trust),
-        "re-create trust with aia intermediate");
-    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    is_status(trustResult, kSecTrustResultUnspecified,
-               "trust is kSecTrustResultUnspecified");
-    info = SecTrustCopyInfo(trust);
-    ev = (CFBooleanRef)CFDictionaryGetValue(info,
-        kSecTrustInfoExtendedValidationKey);
-    ok(ev, "extended validation succeeded");
-    //display_anchor_digest(trust);
-    CFReleaseSafe(info);
-    CFReleaseSafe(trust);
-
-    /* Common variable cleanup. */
-    CFReleaseSafe(sslPolicy);
-    CFReleaseSafe(revPolicy);
-    CFReleaseSafe(certs);
-    CFReleaseSafe(policies);
-    CFReleaseSafe(comodo_aia);
-    CFReleaseSafe(comodo_ev);
-    CFReleaseSafe(ovh);
-    CFReleaseSafe(verifyDate);
-}
-
-static void test_aia_https(void) {
-    SecCertificateRef leaf = NULL;
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    CFArrayRef certs = NULL;
-    CFDateRef verifyDate = NULL;
-    CFErrorRef error = NULL;
-
-    leaf = SecCertificateCreateWithBytes(NULL, _caissuer_https, sizeof(_caissuer_https));
-    const void *v_certs[] = { leaf };
-
-    certs = CFArrayCreate(NULL, v_certs, 1, &kCFTypeArrayCallBacks);
-    policy = SecPolicyCreateSSL(true, CFSTR("example.com"));
-    require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
-
-    verifyDate = CFDateCreate(NULL, 546700000.0); // April 29, 2018 at 6:06:40 AM PDT
-    require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
-    /* Evaluate trust. This cert does not chain to anything trusted and we can't fetch an
-     * intermediate because the URI is https. */
-    is(SecTrustEvaluateWithError(trust, &error), false, "leaf with missing intermediate and https CAIssuer URI succeeded");
-    if (error) {
-        is(CFErrorGetCode(error), errSecCreateChainFailed, "got wrong error code for revoked cert, got %ld, expected %d",
-           (long)CFErrorGetCode(error), errSecCreateChainFailed);
-    } else {
-        fail("expected trust evaluation to fail and it did not.");
-    }
-#pragma clang diagnostic pop
-
-errOut:
-    CFReleaseNull(leaf);
-    CFReleaseNull(policy);
-    CFReleaseNull(trust);
-    CFReleaseNull(certs);
-    CFReleaseNull(verifyDate);
-    CFReleaseNull(error);
-}
-
-static void test_results_dictionary_revocation_reason(void) {
-    SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    CFArrayRef certs = NULL, anchors = NULL;
-    CFDateRef verifyDate = NULL;
-    CFErrorRef error = NULL;
-    CFDataRef ocspResponse = NULL;
-
-    leaf = SecCertificateCreateWithBytes(NULL, _probablyRevokedLeaf, sizeof(_probablyRevokedLeaf));
-    subCA = SecCertificateCreateWithBytes(NULL, _digiCertSha2SubCA, sizeof(_digiCertSha2SubCA));
-    root = SecCertificateCreateWithBytes(NULL, _digiCertGlobalRoot, sizeof(_digiCertGlobalRoot));
-
-    const void *v_certs[] = { leaf, subCA };
-    const void *v_anchors[] = { root };
-
-    certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
-    policy = SecPolicyCreateSSL(true, CFSTR("revoked.badssl.com"));
-    require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
-
-    anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
-    require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
-
-    verifyDate = CFDateCreate(NULL, 543000000.0); // March 17, 2018 at 10:20:00 AM PDT
-    require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
-
-    /* Set the stapled response */
-    ocspResponse = CFDataCreate(NULL, _digicertOCSPResponse, sizeof(_digicertOCSPResponse));
-    ok_status(SecTrustSetOCSPResponse(trust, ocspResponse), "failed to set OCSP response");
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
-    /* Evaluate trust. This cert is revoked, but is only listed as "probably revoked" by valid.apple.com.
-     * This cert should come back as revoked. */
-    is(SecTrustEvaluateWithError(trust, &error), false, "revoked cert succeeded");
-    if (error) {
-        is(CFErrorGetCode(error), errSecCertificateRevoked, "got wrong error code for revoked cert, got %ld, expected %d",
-           (long)CFErrorGetCode(error), errSecCertificateRevoked);
-
-        /* Verify that the results dictionary contains all the right keys for a revoked cert */
-        CFDictionaryRef result = SecTrustCopyResult(trust);
-        isnt(result, NULL, "failed to copy result dictionary");
-        if (result) {
-            int64_t reason = -1;
-            CFNumberRef cfreason = CFNumberCreate(NULL, kCFNumberSInt64Type, &reason);
-            is(CFNumberCompare(cfreason, CFDictionaryGetValue(result, kSecTrustRevocationReason), NULL), kCFCompareEqualTo, "expected revocation reason -1");
-            CFReleaseNull(cfreason);
-        }
-        CFReleaseNull(result);
-    } else {
-        fail("expected trust evaluation to fail and it did not.");
-    }
-#pragma clang diagnostic pop
-
-errOut:
-    CFReleaseNull(leaf);
-    CFReleaseNull(subCA);
-    CFReleaseNull(root);
-    CFReleaseNull(policy);
-    CFReleaseNull(trust);
-    CFReleaseNull(certs);
-    CFReleaseNull(anchors);
-    CFReleaseNull(verifyDate);
-    CFReleaseNull(error);
-    CFReleaseNull(ocspResponse);
-}
-
-static void test_results_dictionary_revocation_checked(void) {
-    SecCertificateRef leaf = NULL, subCA = NULL, root = NULL;
-    SecPolicyRef sslPolicy = NULL, ocspPolicy = NULL;
-    SecTrustRef trust = NULL;
-    CFArrayRef certs = NULL, anchors = NULL, policies = NULL;
-    CFDateRef verifyDate = NULL;
-    CFErrorRef error = NULL;
-
-    leaf = SecCertificateCreateWithBytes(NULL, _ocsp_c0, sizeof(_ocsp_c0));
-    subCA = SecCertificateCreateWithBytes(NULL, _ocsp_c1, sizeof(_ocsp_c1));
-    root = SecCertificateCreateWithBytes(NULL, _ocsp_c2, sizeof(_ocsp_c2));
-
-    sslPolicy = SecPolicyCreateSSL(true, CFSTR("www.apple.com"));
-    ocspPolicy = SecPolicyCreateRevocation(kSecRevocationOCSPMethod);
-
-    const void *v_certs[] = { leaf, subCA };
-    const void *v_anchors[] = { root };
-    const void *v_policies[] = { sslPolicy, ocspPolicy };
-
-    certs = CFArrayCreate(NULL, v_certs, 2, &kCFTypeArrayCallBacks);
-    policies = CFArrayCreate(NULL, v_policies, 2, &kCFTypeArrayCallBacks);
-    require_noerr_action(SecTrustCreateWithCertificates(certs, policies, &trust), errOut, fail("failed to create trust object"));
-
-    anchors = CFArrayCreate(NULL, v_anchors, 1, &kCFTypeArrayCallBacks);
-    require_noerr_action(SecTrustSetAnchorCertificates(trust, anchors), errOut, fail("failed to set anchors"));
-
-    verifyDate = CFDateCreate(NULL, 577000000.0); // April 14, 2019 at 10:46:40 PM PDT
-    require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
-    is(SecTrustEvaluateWithError(trust, &error), true, "valid cert failed");
-
-    /* Verify that the results dictionary contains all the right keys for a valid cert where revocation checked */
-    CFDictionaryRef result = SecTrustCopyResult(trust);
-    isnt(result, NULL, "failed to copy result dictionary");
-    if (result) {
-        is(CFDictionaryGetValue(result, kSecTrustRevocationChecked), kCFBooleanTrue, "expected revocation checked flag");
-        CFDateRef validUntil = CFDictionaryGetValue(result, kSecTrustRevocationValidUntilDate);
-        isnt(validUntil, NULL, "expected revocation valid until date");
-        if (validUntil) {
-            ok(CFDateGetAbsoluteTime(validUntil) > CFAbsoluteTimeGetCurrent(), "expected valid until date in the future");
-        } else {
-            fail("did not get valid until date");
-        }
-    }
-    CFReleaseNull(result);
-#pragma clang diagnostic pop
-
-errOut:
-    CFReleaseNull(leaf);
-    CFReleaseNull(subCA);
-    CFReleaseNull(root);
-    CFReleaseNull(ocspPolicy);
-    CFReleaseNull(sslPolicy);
-    CFReleaseNull(trust);
-    CFReleaseNull(certs);
-    CFReleaseNull(anchors);
-    CFReleaseNull(policies);
-    CFReleaseNull(verifyDate);
-    CFReleaseNull(error);
-}
-
-static int ping_host(char *host_name){
-
-    struct sockaddr_in pin;
-    struct hostent *nlp_host;
-    int sd;
-    int port;
-    int retries = 5;
-
-    port=80;
-
-    //tries 5 times then give up
-    while ((nlp_host=gethostbyname(host_name))==0 && retries--){
-        printf("Resolve Error! (%s) %d\n", host_name, h_errno);
-        sleep(1);
-    }
-
-    if(nlp_host==0)
-        return 0;
-
-    bzero(&pin,sizeof(pin));
-    pin.sin_family=AF_INET;
-    pin.sin_addr.s_addr=htonl(INADDR_ANY);
-    pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
-    pin.sin_port=htons(port);
-
-    sd=socket(AF_INET,SOCK_STREAM,0);
-
-    if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
-        printf("connect error! (%s) %d\n", host_name, errno);
-        close(sd);
-        return 0;
-    }
-    else{
-        close(sd);
-        return 1;
-    }
-}
-
-int si_23_sectrust_ocsp(int argc, char *const *argv)
-{
-    char *hosts[] = {
-        "EVSecure-ocsp.verisign.com",
-        "EVIntl-ocsp.verisign.com",
-        "EVIntl-aia.verisign.com",
-        "ocsp.comodoca.com",
-        "crt.comodoca.com",
-        "ocsp.entrust.net",
-        "ocsp.digicert.com",
-    };
-
-    unsigned host_cnt = 0;
-
-    plan_tests(105);
-
-    for (host_cnt = 0; host_cnt < sizeof(hosts)/sizeof(hosts[0]); host_cnt ++) {
-        if(!ping_host(hosts[host_cnt])) {
-            printf("Accessing specific server (%s) failed, check the network!\n", hosts[host_cnt]);
-            return 0;
-        }
-    }
-
-    tests();
-    test_ocsp_responder_policy();
-    test_aia();
-    test_aia_https();
-    test_revocation();
-    test_forced_revocation();
-    test_results_dictionary_revocation_reason();
-    test_results_dictionary_revocation_checked();
-
-    return 0;
-}
diff --git a/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.h b/OSX/sec/Security/Regressions/secitem/si-23-sectrust-ocsp.h
deleted file mode 100644 (file)
index cc78fcf..0000000
+++ /dev/null
@@ -1,1603 +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@
- */
-
-
-#ifndef _SECURITY_SI_23_SECTRUST_OCSP_H_
-#define _SECURITY_SI_23_SECTRUST_OCSP_H_
-
-/* subject:/businessCategory=Private Organization/jurisdictionCountryName=US/jurisdictionStateOrProvinceName=California/serialNumber=C0806592/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Internet Services for Akamai/CN=www.apple.com */
-/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 Extended Validation Server CA */
-static const uint8_t _ocsp_c0[]={
-    0x30,0x82,0x06,0xF1,0x30,0x82,0x05,0xD9,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0F,
-    0x8E,0x4E,0x4C,0x9C,0xF5,0x5E,0xA5,0xFE,0x2E,0x9B,0x2B,0x7E,0xFF,0xDE,0x8F,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x75,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,
-    0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,
-    0x34,0x30,0x32,0x06,0x03,0x55,0x04,0x03,0x13,0x2B,0x44,0x69,0x67,0x69,0x43,0x65,
-    0x72,0x74,0x20,0x53,0x48,0x41,0x32,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,
-    0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,
-    0x65,0x72,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x39,0x30,0x33,0x30,0x37,0x30,
-    0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x30,0x30,0x33,0x30,0x37,0x31,0x32,
-    0x30,0x30,0x30,0x30,0x5A,0x30,0x81,0xEE,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,
-    0x0F,0x0C,0x14,0x50,0x72,0x69,0x76,0x61,0x74,0x65,0x20,0x4F,0x72,0x67,0x61,0x6E,
-    0x69,0x7A,0x61,0x74,0x69,0x6F,0x6E,0x31,0x13,0x30,0x11,0x06,0x0B,0x2B,0x06,0x01,
-    0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x03,0x13,0x02,0x55,0x53,0x31,0x1B,0x30,0x19,
-    0x06,0x0B,0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x02,0x13,0x0A,0x43,
-    0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x11,0x30,0x0F,0x06,0x03,0x55,
-    0x04,0x05,0x13,0x08,0x43,0x30,0x38,0x30,0x36,0x35,0x39,0x32,0x31,0x0B,0x30,0x09,
-    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
-    0x04,0x08,0x13,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,
-    0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x13,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,
-    0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x13,0x0A,0x41,0x70,0x70,
-    0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,
-    0x13,0x1C,0x49,0x6E,0x74,0x65,0x72,0x6E,0x65,0x74,0x20,0x53,0x65,0x72,0x76,0x69,
-    0x63,0x65,0x73,0x20,0x66,0x6F,0x72,0x20,0x41,0x6B,0x61,0x6D,0x61,0x69,0x31,0x16,
-    0x30,0x14,0x06,0x03,0x55,0x04,0x03,0x13,0x0D,0x77,0x77,0x77,0x2E,0x61,0x70,0x70,
-    0x6C,0x65,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,0xED,0x5E,0x5D,0xC6,0x85,0xBE,0xE5,0x2A,0x78,
-    0x7A,0x1F,0x77,0x1F,0x42,0x17,0xEA,0xC1,0xE3,0x75,0xAE,0xC9,0x38,0x7A,0xE0,0xCF,
-    0x9F,0xEB,0xBA,0x47,0x42,0xCF,0x63,0x75,0x26,0xD3,0x4C,0x8E,0x6C,0x2F,0xC7,0xBC,
-    0x1C,0xBB,0x37,0xC9,0xA5,0xA0,0xD3,0x8F,0xEA,0x3D,0x02,0xC8,0xE8,0x06,0xA1,0xA7,
-    0x2B,0x4C,0x7B,0x91,0x55,0xBC,0x51,0xAB,0xE7,0xC8,0xB8,0xA8,0xA6,0x49,0x3E,0x94,
-    0x45,0xF1,0x00,0x90,0x26,0xB9,0xB5,0xAF,0xB5,0xA0,0x22,0x41,0x2C,0x10,0x52,0x8B,
-    0xD9,0xF0,0x91,0xE5,0x40,0x76,0x60,0xFD,0xC2,0xB1,0xFE,0xD0,0x55,0xC3,0x4F,0x18,
-    0x7D,0x20,0x00,0x0C,0x8B,0x41,0x2C,0x2D,0xC1,0x0A,0xC0,0xE1,0x2E,0xDE,0xF8,0x47,
-    0x84,0xB2,0x36,0x4E,0x03,0x5F,0x77,0x90,0xF6,0xF5,0x60,0xD8,0xAA,0x25,0x10,0xEB,
-    0x37,0x38,0x03,0x7F,0x4B,0x46,0x36,0x76,0x2E,0x66,0xFE,0x18,0xE4,0x9B,0x31,0xEC,
-    0xD5,0x2A,0xDB,0x60,0x90,0xD7,0xA0,0xD5,0xAB,0x79,0x9C,0x01,0xF6,0xAC,0x87,0x88,
-    0x73,0x43,0x08,0xE0,0x48,0xF0,0x09,0xAC,0x41,0x40,0x60,0xE4,0x9C,0xA7,0xCC,0xBD,
-    0x2F,0xC7,0x5D,0x32,0x32,0x2E,0x42,0xD7,0x69,0x2F,0x46,0x30,0xD3,0x6E,0x17,0xBA,
-    0x1C,0xA6,0xBA,0xBC,0xB5,0x62,0x53,0x89,0xC7,0x4A,0xEF,0xB9,0xF8,0x0F,0x25,0x2F,
-    0xB4,0x7A,0x5C,0x05,0xFB,0xE4,0xFD,0x13,0x47,0x1B,0xFF,0x60,0x6F,0x40,0xF2,0x0F,
-    0x2D,0x53,0x38,0x3F,0x21,0x87,0x4D,0x08,0xB1,0x1B,0xD3,0xDA,0xAB,0xD5,0x9E,0x94,
-    0x69,0x43,0xA3,0xA2,0x5E,0xF1,0xE9,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03,0x01,
-    0x30,0x82,0x02,0xFD,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,
-    0x14,0x3D,0xD3,0x50,0xA5,0xD6,0xA0,0xAD,0xEE,0xF3,0x4A,0x60,0x0A,0x65,0xD3,0x21,
-    0xD4,0xF8,0xF8,0xD6,0x0F,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
-    0xD8,0xF5,0xFF,0x6D,0xDC,0x96,0x30,0x5C,0xAD,0x80,0x75,0xFF,0xCE,0xC5,0xF7,0x9D,
-    0x16,0x73,0xCB,0x16,0x30,0x2A,0x06,0x03,0x55,0x1D,0x11,0x04,0x23,0x30,0x21,0x82,
-    0x10,0x69,0x6D,0x61,0x67,0x65,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
-    0x6D,0x82,0x0D,0x77,0x77,0x77,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,
-    0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,
-    0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,
-    0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,
-    0x75,0x06,0x03,0x55,0x1D,0x1F,0x04,0x6E,0x30,0x6C,0x30,0x34,0xA0,0x32,0xA0,0x30,
-    0x86,0x2E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x33,0x2E,0x64,0x69,
-    0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x73,0x68,0x61,0x32,0x2D,
-    0x65,0x76,0x2D,0x73,0x65,0x72,0x76,0x65,0x72,0x2D,0x67,0x32,0x2E,0x63,0x72,0x6C,
-    0x30,0x34,0xA0,0x32,0xA0,0x30,0x86,0x2E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,
-    0x72,0x6C,0x34,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x73,0x68,0x61,0x32,0x2D,0x65,0x76,0x2D,0x73,0x65,0x72,0x76,0x65,0x72,0x2D,
-    0x67,0x32,0x2E,0x63,0x72,0x6C,0x30,0x4B,0x06,0x03,0x55,0x1D,0x20,0x04,0x44,0x30,
-    0x42,0x30,0x37,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xFD,0x6C,0x02,0x01,0x30,0x2A,
-    0x30,0x28,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1C,0x68,0x74,
-    0x74,0x70,0x73,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,
-    0x72,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x07,0x06,0x05,0x67,0x81,
-    0x0C,0x01,0x01,0x30,0x81,0x88,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,
-    0x04,0x7C,0x30,0x7A,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,
-    0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x64,0x69,
-    0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x52,0x06,0x08,0x2B,0x06,
-    0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x46,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,
-    0x61,0x63,0x65,0x72,0x74,0x73,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,
-    0x63,0x6F,0x6D,0x2F,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x53,0x48,0x41,0x32,
-    0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,
-    0x6F,0x6E,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,0x09,
-    0x06,0x03,0x55,0x1D,0x13,0x04,0x02,0x30,0x00,0x30,0x82,0x01,0x04,0x06,0x0A,0x2B,
-    0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x02,0x04,0x81,0xF5,0x04,0x81,0xF2,0x00,
-    0xF0,0x00,0x76,0x00,0xBB,0xD9,0xDF,0xBC,0x1F,0x8A,0x71,0xB5,0x93,0x94,0x23,0x97,
-    0xAA,0x92,0x7B,0x47,0x38,0x57,0x95,0x0A,0xAB,0x52,0xE8,0x1A,0x90,0x96,0x64,0x36,
-    0x8E,0x1E,0xD1,0x85,0x00,0x00,0x01,0x69,0x58,0x42,0xD1,0x06,0x00,0x00,0x04,0x03,
-    0x00,0x47,0x30,0x45,0x02,0x20,0x68,0x81,0x0C,0x54,0x88,0x45,0x7A,0xC6,0x84,0xB8,
-    0x65,0x9B,0xFD,0x9C,0x34,0x80,0xF6,0x38,0x91,0xEF,0xCF,0x58,0xF9,0xFD,0xF3,0x50,
-    0x6F,0xAD,0x8E,0xA0,0xAD,0xE8,0x02,0x21,0x00,0xCE,0x32,0x9D,0x5B,0x3D,0xA2,0x8B,
-    0xB6,0x04,0x48,0xEE,0x01,0x26,0x6C,0xD3,0x50,0xA1,0xEA,0x7F,0x25,0x0C,0x00,0x2A,
-    0x42,0x6D,0x42,0x0D,0x13,0xC0,0xA9,0x85,0xBC,0x00,0x76,0x00,0x56,0x14,0x06,0x9A,
-    0x2F,0xD7,0xC2,0xEC,0xD3,0xF5,0xE1,0xBD,0x44,0xB2,0x3E,0xC7,0x46,0x76,0xB9,0xBC,
-    0x99,0x11,0x5C,0xC0,0xEF,0x94,0x98,0x55,0xD6,0x89,0xD0,0xDD,0x00,0x00,0x01,0x69,
-    0x58,0x42,0xD1,0x44,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x4B,0xD4,
-    0x64,0x52,0xD3,0x52,0xF0,0x3E,0xD8,0xD4,0x3D,0xC5,0x40,0x72,0xED,0xC3,0x04,0x8C,
-    0x3C,0x16,0x46,0x5D,0x38,0x02,0xBA,0xA2,0x1E,0x52,0xAA,0xE1,0xDA,0xB6,0x02,0x21,
-    0x00,0xA3,0x5E,0x2F,0x6B,0xCC,0xB9,0x34,0xD9,0xA4,0x00,0x70,0xE1,0x3A,0x99,0xB4,
-    0x0D,0x25,0x6D,0xD3,0x59,0x77,0xC2,0x98,0x8C,0x6A,0xA0,0xAE,0xA7,0xE1,0x06,0x73,
-    0x32,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
-    0x03,0x82,0x01,0x01,0x00,0x3F,0xD9,0xA1,0x19,0xB3,0x7C,0x56,0xA5,0x89,0xE5,0xA2,
-    0x33,0x33,0xE3,0xFC,0xBB,0x29,0xDB,0xD7,0x69,0x76,0x31,0x2F,0x69,0x97,0x90,0xA1,
-    0x0C,0x11,0x0B,0x5A,0xCB,0xAB,0x41,0x66,0xB2,0x9B,0xDF,0x71,0xD6,0xDC,0x92,0x91,
-    0xB6,0x17,0x8B,0xD3,0x9C,0x83,0x3C,0xDC,0x7C,0xA7,0x29,0x5D,0xBA,0x38,0x97,0x9B,
-    0x0D,0x07,0xE0,0x46,0xCA,0x27,0x5F,0x41,0xA0,0xC0,0x84,0x1E,0x47,0x00,0xDC,0x87,
-    0x79,0xFD,0xAF,0x3E,0x34,0xC2,0x6D,0xB1,0x47,0x0C,0x52,0x14,0x81,0xAC,0xB2,0x6C,
-    0xB4,0x30,0xB2,0x41,0x61,0x77,0x07,0x96,0x05,0x5B,0x26,0x36,0xA2,0x94,0xC2,0x70,
-    0xC3,0xCD,0xC1,0x15,0xAC,0x33,0x0D,0x60,0x68,0xFA,0x19,0x95,0x3E,0x28,0x14,0xDE,
-    0x19,0x15,0xF2,0x4B,0x43,0xAB,0x00,0xBF,0x54,0xE3,0xAF,0x5A,0x29,0x0F,0x32,0xCB,
-    0xCC,0xBE,0x7F,0x07,0x30,0xF6,0xD9,0x49,0xE6,0x27,0x1F,0xC0,0x3B,0x9C,0x3D,0x2E,
-    0xD1,0x6C,0xC5,0xB6,0x0E,0x8D,0x17,0xDC,0x48,0x5C,0x1F,0xC1,0x7E,0x4B,0xBA,0x8C,
-    0x43,0xCA,0xAF,0x99,0x76,0x88,0x9B,0xA4,0x68,0x60,0xFA,0xC2,0xD3,0x87,0xEF,0x39,
-    0x16,0x8C,0x49,0x36,0x2C,0x09,0xF9,0x07,0x2A,0x2E,0x7B,0x61,0x3E,0x76,0x76,0xEF,
-    0x74,0x96,0xA5,0xAE,0xFF,0x6B,0x4C,0xF7,0x7F,0x96,0x41,0xBE,0x9C,0x09,0x41,0xBA,
-    0x8A,0x1C,0xFD,0xC2,0x4A,0xE1,0x0A,0xA8,0x7E,0x7B,0xA8,0x98,0xA8,0x01,0x5D,0xAB,
-    0xEF,0xDB,0x36,0xB3,0xE6,0x93,0x5D,0x27,0x0C,0x26,0xC3,0x33,0x93,0x74,0xAF,0x79,
-    0x81,0xE5,0xD4,0x46,0x4E,
-};
-
-/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert SHA2 Extended Validation Server CA */
-/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */
-static const uint8_t _ocsp_c1[]= {
-    0x30,0x82,0x04,0xB6,0x30,0x82,0x03,0x9E,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x0C,
-    0x79,0xA9,0x44,0xB0,0x8C,0x11,0x95,0x20,0x92,0x61,0x5F,0xE2,0x6B,0x1D,0x83,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x6C,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,
-    0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,
-    0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,
-    0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,
-    0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,
-    0x31,0x33,0x31,0x30,0x32,0x32,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,
-    0x38,0x31,0x30,0x32,0x32,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x30,0x75,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,
-    0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,
-    0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,
-    0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x34,0x30,
-    0x32,0x06,0x03,0x55,0x04,0x03,0x13,0x2B,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x53,0x48,0x41,0x32,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x56,
-    0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x72,0x76,0x65,0x72,
-    0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,
-    0x82,0x01,0x01,0x00,0xD7,0x53,0xA4,0x04,0x51,0xF8,0x99,0xA6,0x16,0x48,0x4B,0x67,
-    0x27,0xAA,0x93,0x49,0xD0,0x39,0xED,0x0C,0xB0,0xB0,0x00,0x87,0xF1,0x67,0x28,0x86,
-    0x85,0x8C,0x8E,0x63,0xDA,0xBC,0xB1,0x40,0x38,0xE2,0xD3,0xF5,0xEC,0xA5,0x05,0x18,
-    0xB8,0x3D,0x3E,0xC5,0x99,0x17,0x32,0xEC,0x18,0x8C,0xFA,0xF1,0x0C,0xA6,0x64,0x21,
-    0x85,0xCB,0x07,0x10,0x34,0xB0,0x52,0x88,0x2B,0x1F,0x68,0x9B,0xD2,0xB1,0x8F,0x12,
-    0xB0,0xB3,0xD2,0xE7,0x88,0x1F,0x1F,0xEF,0x38,0x77,0x54,0x53,0x5F,0x80,0x79,0x3F,
-    0x2E,0x1A,0xAA,0xA8,0x1E,0x4B,0x2B,0x0D,0xAB,0xB7,0x63,0xB9,0x35,0xB7,0x7D,0x14,
-    0xBC,0x59,0x4B,0xDF,0x51,0x4A,0xD2,0xA1,0xE2,0x0C,0xE2,0x90,0x82,0x87,0x6A,0xAE,
-    0xEA,0xD7,0x64,0xD6,0x98,0x55,0xE8,0xFD,0xAF,0x1A,0x50,0x6C,0x54,0xBC,0x11,0xF2,
-    0xFD,0x4A,0xF2,0x9D,0xBB,0x7F,0x0E,0xF4,0xD5,0xBE,0x8E,0x16,0x89,0x12,0x55,0xD8,
-    0xC0,0x71,0x34,0xEE,0xF6,0xDC,0x2D,0xEC,0xC4,0x87,0x25,0x86,0x8D,0xD8,0x21,0xE4,
-    0xB0,0x4D,0x0C,0x89,0xDC,0x39,0x26,0x17,0xDD,0xF6,0xD7,0x94,0x85,0xD8,0x04,0x21,
-    0x70,0x9D,0x6F,0x6F,0xFF,0x5C,0xBA,0x19,0xE1,0x45,0xCB,0x56,0x57,0x28,0x7E,0x1C,
-    0x0D,0x41,0x57,0xAA,0xB7,0xB8,0x27,0xBB,0xB1,0xE4,0xFA,0x2A,0xEF,0x21,0x23,0x75,
-    0x1A,0xAD,0x2D,0x9B,0x86,0x35,0x8C,0x9C,0x77,0xB5,0x73,0xAD,0xD8,0x94,0x2D,0xE4,
-    0xF3,0x0C,0x9D,0xEE,0xC1,0x4E,0x62,0x7E,0x17,0xC0,0x71,0x9E,0x2C,0xDE,0xF1,0xF9,
-    0x10,0x28,0x19,0x33,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x49,0x30,0x82,0x01,
-    0x45,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,
-    0x01,0xFF,0x02,0x01,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,
-    0x04,0x03,0x02,0x01,0x86,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,
-    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x03,0x02,0x30,0x34,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,
-    0x04,0x28,0x30,0x26,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,
-    0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x64,0x69,
-    0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x4B,0x06,0x03,0x55,0x1D,
-    0x1F,0x04,0x44,0x30,0x42,0x30,0x40,0xA0,0x3E,0xA0,0x3C,0x86,0x3A,0x68,0x74,0x74,
-    0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x34,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,
-    0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x48,0x69,
-    0x67,0x68,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x45,0x56,0x52,0x6F,0x6F,
-    0x74,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x3D,0x06,0x03,0x55,0x1D,0x20,0x04,0x36,
-    0x30,0x34,0x30,0x32,0x06,0x04,0x55,0x1D,0x20,0x00,0x30,0x2A,0x30,0x28,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1C,0x68,0x74,0x74,0x70,0x73,0x3A,
-    0x2F,0x2F,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,
-    0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
-    0x14,0x3D,0xD3,0x50,0xA5,0xD6,0xA0,0xAD,0xEE,0xF3,0x4A,0x60,0x0A,0x65,0xD3,0x21,
-    0xD4,0xF8,0xF8,0xD6,0x0F,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
-    0x80,0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,
-    0x02,0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
-    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x9D,0xB6,0xD0,0x90,0x86,0xE1,
-    0x86,0x02,0xED,0xC5,0xA0,0xF0,0x34,0x1C,0x74,0xC1,0x8D,0x76,0xCC,0x86,0x0A,0xA8,
-    0xF0,0x4A,0x8A,0x42,0xD6,0x3F,0xC8,0xA9,0x4D,0xAD,0x7C,0x08,0xAD,0xE6,0xB6,0x50,
-    0xB8,0xA2,0x1A,0x4D,0x88,0x07,0xB1,0x29,0x21,0xDC,0xE7,0xDA,0xC6,0x3C,0x21,0xE0,
-    0xE3,0x11,0x49,0x70,0xAC,0x7A,0x1D,0x01,0xA4,0xCA,0x11,0x3A,0x57,0xAB,0x7D,0x57,
-    0x2A,0x40,0x74,0xFD,0xD3,0x1D,0x85,0x18,0x50,0xDF,0x57,0x47,0x75,0xA1,0x7D,0x55,
-    0x20,0x2E,0x47,0x37,0x50,0x72,0x8C,0x7F,0x82,0x1B,0xD2,0x62,0x8F,0x2D,0x03,0x5A,
-    0xDA,0xC3,0xC8,0xA1,0xCE,0x2C,0x52,0xA2,0x00,0x63,0xEB,0x73,0xBA,0x71,0xC8,0x49,
-    0x27,0x23,0x97,0x64,0x85,0x9E,0x38,0x0E,0xAD,0x63,0x68,0x3C,0xBA,0x52,0x81,0x58,
-    0x79,0xA3,0x2C,0x0C,0xDF,0xDE,0x6D,0xEB,0x31,0xF2,0xBA,0xA0,0x7C,0x6C,0xF1,0x2C,
-    0xD4,0xE1,0xBD,0x77,0x84,0x37,0x03,0xCE,0x32,0xB5,0xC8,0x9A,0x81,0x1A,0x4A,0x92,
-    0x4E,0x3B,0x46,0x9A,0x85,0xFE,0x83,0xA2,0xF9,0x9E,0x8C,0xA3,0xCC,0x0D,0x5E,0xB3,
-    0x3D,0xCF,0x04,0x78,0x8F,0x14,0x14,0x7B,0x32,0x9C,0xC7,0x00,0xA6,0x5C,0xC4,0xB5,
-    0xA1,0x55,0x8D,0x5A,0x56,0x68,0xA4,0x22,0x70,0xAA,0x3C,0x81,0x71,0xD9,0x9D,0xA8,
-    0x45,0x3B,0xF4,0xE5,0xF6,0xA2,0x51,0xDD,0xC7,0x7B,0x62,0xE8,0x6F,0x0C,0x74,0xEB,
-    0xB8,0xDA,0xF8,0xBF,0x87,0x0D,0x79,0x50,0x91,0x90,0x9B,0x18,0x3B,0x91,0x59,0x27,
-    0xF1,0x35,0x28,0x13,0xAB,0x26,0x7E,0xD5,0xF7,0x7A,
-};
-
-/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */
-/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA */
-static const uint8_t _ocsp_c2[]= {
-    0x30,0x82,0x03,0xC5,0x30,0x82,0x02,0xAD,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x02,
-    0xAC,0x5C,0x26,0x6A,0x0B,0x40,0x9B,0x8F,0x0B,0x79,0xF2,0xAE,0x46,0x25,0x77,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x6C,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,
-    0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,
-    0x2B,0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,
-    0x72,0x74,0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,
-    0x65,0x20,0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,
-    0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x33,
-    0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x30,0x6C,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,
-    0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x49,
-    0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,0x77,0x77,
-    0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x2B,0x30,
-    0x29,0x06,0x03,0x55,0x04,0x03,0x13,0x22,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x48,0x69,0x67,0x68,0x20,0x41,0x73,0x73,0x75,0x72,0x61,0x6E,0x63,0x65,0x20,
-    0x45,0x56,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,
-    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,
-    0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC6,0xCC,0xE5,0x73,0xE6,
-    0xFB,0xD4,0xBB,0xE5,0x2D,0x2D,0x32,0xA6,0xDF,0xE5,0x81,0x3F,0xC9,0xCD,0x25,0x49,
-    0xB6,0x71,0x2A,0xC3,0xD5,0x94,0x34,0x67,0xA2,0x0A,0x1C,0xB0,0x5F,0x69,0xA6,0x40,
-    0xB1,0xC4,0xB7,0xB2,0x8F,0xD0,0x98,0xA4,0xA9,0x41,0x59,0x3A,0xD3,0xDC,0x94,0xD6,
-    0x3C,0xDB,0x74,0x38,0xA4,0x4A,0xCC,0x4D,0x25,0x82,0xF7,0x4A,0xA5,0x53,0x12,0x38,
-    0xEE,0xF3,0x49,0x6D,0x71,0x91,0x7E,0x63,0xB6,0xAB,0xA6,0x5F,0xC3,0xA4,0x84,0xF8,
-    0x4F,0x62,0x51,0xBE,0xF8,0xC5,0xEC,0xDB,0x38,0x92,0xE3,0x06,0xE5,0x08,0x91,0x0C,
-    0xC4,0x28,0x41,0x55,0xFB,0xCB,0x5A,0x89,0x15,0x7E,0x71,0xE8,0x35,0xBF,0x4D,0x72,
-    0x09,0x3D,0xBE,0x3A,0x38,0x50,0x5B,0x77,0x31,0x1B,0x8D,0xB3,0xC7,0x24,0x45,0x9A,
-    0xA7,0xAC,0x6D,0x00,0x14,0x5A,0x04,0xB7,0xBA,0x13,0xEB,0x51,0x0A,0x98,0x41,0x41,
-    0x22,0x4E,0x65,0x61,0x87,0x81,0x41,0x50,0xA6,0x79,0x5C,0x89,0xDE,0x19,0x4A,0x57,
-    0xD5,0x2E,0xE6,0x5D,0x1C,0x53,0x2C,0x7E,0x98,0xCD,0x1A,0x06,0x16,0xA4,0x68,0x73,
-    0xD0,0x34,0x04,0x13,0x5C,0xA1,0x71,0xD3,0x5A,0x7C,0x55,0xDB,0x5E,0x64,0xE1,0x37,
-    0x87,0x30,0x56,0x04,0xE5,0x11,0xB4,0x29,0x80,0x12,0xF1,0x79,0x39,0x88,0xA2,0x02,
-    0x11,0x7C,0x27,0x66,0xB7,0x88,0xB7,0x78,0xF2,0xCA,0x0A,0xA8,0x38,0xAB,0x0A,0x64,
-    0xC2,0xBF,0x66,0x5D,0x95,0x84,0xC1,0xA1,0x25,0x1E,0x87,0x5D,0x1A,0x50,0x0B,0x20,
-    0x12,0xCC,0x41,0xBB,0x6E,0x0B,0x51,0x38,0xB8,0x4B,0xCB,0x02,0x03,0x01,0x00,0x01,
-    0xA3,0x63,0x30,0x61,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
-    0x03,0x02,0x01,0x86,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,
-    0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
-    0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,0xEF,
-    0x63,0x64,0x2B,0xC3,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,
-    0x14,0xB1,0x3E,0xC3,0x69,0x03,0xF8,0xBF,0x47,0x01,0xD4,0x98,0x26,0x1A,0x08,0x02,
-    0xEF,0x63,0x64,0x2B,0xC3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,
-    0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x1C,0x1A,0x06,0x97,0xDC,0xD7,0x9C,
-    0x9F,0x3C,0x88,0x66,0x06,0x08,0x57,0x21,0xDB,0x21,0x47,0xF8,0x2A,0x67,0xAA,0xBF,
-    0x18,0x32,0x76,0x40,0x10,0x57,0xC1,0x8A,0xF3,0x7A,0xD9,0x11,0x65,0x8E,0x35,0xFA,
-    0x9E,0xFC,0x45,0xB5,0x9E,0xD9,0x4C,0x31,0x4B,0xB8,0x91,0xE8,0x43,0x2C,0x8E,0xB3,
-    0x78,0xCE,0xDB,0xE3,0x53,0x79,0x71,0xD6,0xE5,0x21,0x94,0x01,0xDA,0x55,0x87,0x9A,
-    0x24,0x64,0xF6,0x8A,0x66,0xCC,0xDE,0x9C,0x37,0xCD,0xA8,0x34,0xB1,0x69,0x9B,0x23,
-    0xC8,0x9E,0x78,0x22,0x2B,0x70,0x43,0xE3,0x55,0x47,0x31,0x61,0x19,0xEF,0x58,0xC5,
-    0x85,0x2F,0x4E,0x30,0xF6,0xA0,0x31,0x16,0x23,0xC8,0xE7,0xE2,0x65,0x16,0x33,0xCB,
-    0xBF,0x1A,0x1B,0xA0,0x3D,0xF8,0xCA,0x5E,0x8B,0x31,0x8B,0x60,0x08,0x89,0x2D,0x0C,
-    0x06,0x5C,0x52,0xB7,0xC4,0xF9,0x0A,0x98,0xD1,0x15,0x5F,0x9F,0x12,0xBE,0x7C,0x36,
-    0x63,0x38,0xBD,0x44,0xA4,0x7F,0xE4,0x26,0x2B,0x0A,0xC4,0x97,0x69,0x0D,0xE9,0x8C,
-    0xE2,0xC0,0x10,0x57,0xB8,0xC8,0x76,0x12,0x91,0x55,0xF2,0x48,0x69,0xD8,0xBC,0x2A,
-    0x02,0x5B,0x0F,0x44,0xD4,0x20,0x31,0xDB,0xF4,0xBA,0x70,0x26,0x5D,0x90,0x60,0x9E,
-    0xBC,0x4B,0x17,0x09,0x2F,0xB4,0xCB,0x1E,0x43,0x68,0xC9,0x07,0x27,0xC1,0xD2,0x5C,
-    0xF7,0xEA,0x21,0xB9,0x68,0x12,0x9C,0x3C,0x9C,0xBF,0x9E,0xFC,0x80,0x5C,0x9B,0x63,
-    0xCD,0xEC,0x47,0xAA,0x25,0x27,0x67,0xA0,0x37,0xF3,0x00,0x82,0x7D,0x54,0xD7,0xA9,
-    0xF8,0xE9,0x2E,0x13,0xA3,0x77,0xE8,0x1F,0x4A,
-};
-
-/* subject:/CN=Apple IST CA 2 OCSP Responder NL01/O=Apple Inc./C=US */
-/* issuer :/CN=Apple IST CA 2 - G1/OU=Certification Authority/O=Apple Inc./C=US */
-static const uint8_t _responderCert[]= {
-    0x30,0x82,0x03,0xBB,0x30,0x82,0x02,0xA3,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x5B,
-    0x1B,0xA7,0xF8,0x9D,0xF4,0x7B,0x7C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,
-    0x03,0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,
-    0x32,0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,
-    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
-    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,
-    0x30,0x38,0x31,0x31,0x30,0x30,0x34,0x36,0x35,0x33,0x5A,0x17,0x0D,0x31,0x38,0x30,
-    0x39,0x32,0x32,0x30,0x30,0x34,0x36,0x35,0x33,0x5A,0x30,0x4F,0x31,0x2B,0x30,0x29,
-    0x06,0x03,0x55,0x04,0x03,0x0C,0x22,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,
-    0x20,0x43,0x41,0x20,0x32,0x20,0x4F,0x43,0x53,0x50,0x20,0x52,0x65,0x73,0x70,0x6F,
-    0x6E,0x64,0x65,0x72,0x20,0x4E,0x4C,0x30,0x31,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
-    0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xA5,0x35,0xB2,0xC4,
-    0xF2,0xAB,0x4C,0xFE,0xAA,0x5D,0xC7,0x23,0x52,0x68,0x42,0xC7,0x77,0x27,0x78,0x4E,
-    0x80,0xFD,0x06,0xA3,0x51,0xA2,0x4F,0xF7,0x7A,0xD0,0x19,0x78,0xFD,0xEA,0x94,0xD8,
-    0xE3,0x0C,0x3C,0x50,0x17,0x30,0xDB,0x84,0x38,0x13,0xE1,0xCF,0x6C,0xA0,0x1F,0x01,
-    0xC7,0x12,0xC7,0x96,0x64,0x09,0x45,0x2F,0xA2,0x83,0xFE,0x4E,0x2C,0xF2,0x39,0x6F,
-    0x20,0x34,0x6D,0xEC,0xBE,0xF9,0x86,0xA3,0xEF,0x40,0x1B,0x61,0x2D,0xE1,0xA4,0xB9,
-    0xD4,0x3E,0x8E,0x65,0x7B,0x2F,0x26,0xD5,0x54,0xA6,0x12,0xC7,0x50,0xC8,0x89,0x94,
-    0x86,0xFA,0x41,0x48,0xCF,0xE2,0xF1,0xF8,0xF2,0x0E,0xCC,0x25,0x43,0x0C,0x66,0x85,
-    0xDC,0x88,0xA0,0x76,0x90,0x45,0xFC,0x4E,0x95,0x8F,0xA2,0x17,0x2F,0xAF,0x7C,0x41,
-    0x59,0xA0,0xA1,0x36,0x98,0x18,0x20,0x4D,0x07,0xF5,0x7F,0xD1,0x66,0x65,0xC6,0x74,
-    0xEA,0xBE,0xB8,0x20,0x88,0x29,0x27,0x5D,0x06,0x55,0xD0,0xB2,0x11,0xAF,0x52,0x58,
-    0xD1,0x8A,0x57,0x6E,0x85,0x8D,0x0C,0xBD,0x6A,0xD3,0x87,0x09,0xF6,0x0F,0x07,0x7B,
-    0x5C,0x8F,0x96,0x16,0xB5,0x89,0xB7,0x63,0xC4,0x33,0xDA,0x67,0x63,0xA3,0xC4,0x4B,
-    0x73,0xEF,0x57,0x96,0x4F,0x15,0x2F,0x1B,0xF7,0x8E,0x35,0x24,0x18,0x68,0x87,0x16,
-    0x0A,0x76,0x71,0x8B,0x94,0x11,0xB9,0xCC,0x02,0x97,0x2D,0x6F,0x94,0x00,0x1A,0x31,
-    0xA6,0x9A,0x6B,0x4A,0xD3,0x64,0xB0,0x0F,0xA2,0xB0,0x5E,0xC0,0x2A,0x13,0xD6,0x7C,
-    0x90,0xA6,0x5C,0xEE,0x7F,0x78,0xCA,0x7F,0x62,0x2F,0xF9,0x47,0x02,0x03,0x01,0x00,
-    0x01,0xA3,0x81,0x87,0x30,0x81,0x84,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,
-    0xFF,0x04,0x02,0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
-    0x80,0x14,0xD8,0x7A,0x94,0x44,0x7C,0x90,0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,0x01,
-    0x44,0x03,0x86,0xD6,0x2A,0x29,0x30,0x0F,0x06,0x09,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x30,0x01,0x05,0x04,0x02,0x05,0x00,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,
-    0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09,0x30,0x1D,0x06,0x03,
-    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x75,0xDB,0x74,0x13,0x4A,0xCB,0xCB,0x5A,0x6B,
-    0x78,0x40,0x5A,0x81,0x67,0x42,0xA5,0xD9,0xD0,0x4E,0x38,0x30,0x0E,0x06,0x03,0x55,
-    0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x0D,0x06,0x09,0x2A,
-    0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x3A,
-    0x7E,0x84,0xE2,0x58,0xED,0x07,0xDD,0xE5,0xBD,0x5E,0x88,0x55,0x06,0x23,0x16,0x20,
-    0xD1,0x85,0x89,0x60,0x83,0x19,0x21,0x04,0x9C,0x57,0xFE,0x91,0x30,0xBD,0x7C,0x83,
-    0x45,0xA3,0xA1,0x11,0x0A,0x29,0xCF,0x6C,0x55,0x47,0xC3,0x7B,0x8C,0xEE,0x43,0xFE,
-    0x42,0x0F,0xE6,0xCE,0xC7,0x24,0xAF,0x21,0x2E,0xC7,0xFD,0xFA,0xBA,0x7E,0xCE,0xA3,
-    0x9D,0x92,0x5B,0x54,0x4C,0x4F,0x14,0x55,0xD6,0x5F,0xB0,0xB0,0x73,0xFD,0x78,0x61,
-    0xDC,0xF6,0xA1,0xB6,0xFF,0xAF,0x3B,0x49,0x6F,0x62,0x95,0xD0,0x4E,0xA9,0x3F,0xE8,
-    0x5C,0xCD,0x36,0xEA,0xED,0x57,0x04,0x32,0xB6,0xB0,0x91,0xDC,0x32,0xA6,0xC7,0x84,
-    0x9C,0x3F,0x24,0x3A,0x64,0x56,0x62,0xA2,0x02,0x15,0xC9,0x63,0x96,0x8E,0x6C,0xF5,
-    0x3E,0xB1,0xE4,0x3C,0x79,0x63,0xE0,0x94,0xE8,0xD0,0x73,0x31,0x7B,0x3C,0x99,0x66,
-    0x82,0x2D,0x47,0x49,0x22,0x33,0xD4,0xD1,0x80,0x35,0xF1,0xB1,0xFD,0x01,0x92,0x07,
-    0x6B,0x1E,0xF1,0xD0,0x02,0x84,0x24,0xD6,0xDF,0x2F,0x10,0x06,0x0F,0x36,0x5D,0x4B,
-    0x1A,0xE3,0xDB,0x1F,0x8C,0x54,0x07,0x63,0x41,0x9E,0x74,0x6E,0x6F,0x9D,0xCE,0xCC,
-    0x36,0x7B,0xE0,0xC5,0xCB,0x04,0x12,0xFF,0xF3,0x09,0xD7,0x36,0x5D,0x09,0xD0,0xCD,
-    0xF2,0x73,0xAA,0x10,0x5D,0x0D,0xC2,0x12,0x21,0x00,0x89,0xE5,0x34,0x17,0x6C,0x76,
-    0xE2,0x2F,0xDA,0xBD,0xCA,0xFB,0x9D,0xF2,0x1C,0x3B,0x62,0xCA,0xC0,0x97,0x82,0x54,
-    0x92,0x4E,0x0C,0xD0,0x3B,0x79,0xD0,0x41,0x29,0x84,0xF5,0x75,0x40,0xB4,0xE8,
-};
-
-/* subject:/serialNumber=424761419/jurisdictionC=FR/businessCategory=Private Organization/C=FR/postalCode=59100/ST=Nord/L=Roubaix/street=2 rue Kellermann/O=OVH SAS/OU=IT/OU=COMODO EV SSL/CN=ovh.com */
-/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
-static unsigned char ovh_certificate[1884]={
-    0x30,0x82,0x07,0x58,0x30,0x82,0x06,0x40,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x40,
-    0x46,0x47,0xDC,0xC2,0x4B,0x04,0x42,0xD4,0x89,0x8D,0x08,0x4D,0x4B,0xC2,0x01,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,
-    0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
-    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
-    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
-    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
-    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
-    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,
-    0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,
-    0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,
-    0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,
-    0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x34,0x32,0x38,0x30,0x30,0x30,
-    0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x34,0x32,0x38,0x32,0x33,0x35,0x39,
-    0x35,0x39,0x5A,0x30,0x81,0xEA,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x05,0x13,
-    0x09,0x34,0x32,0x34,0x37,0x36,0x31,0x34,0x31,0x39,0x31,0x13,0x30,0x11,0x06,0x0B,
-    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x03,0x13,0x02,0x46,0x52,0x31,
-    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0F,0x13,0x14,0x50,0x72,0x69,0x76,0x61,0x74,
-    0x65,0x20,0x4F,0x72,0x67,0x61,0x6E,0x69,0x7A,0x61,0x74,0x69,0x6F,0x6E,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x46,0x52,0x31,0x0E,0x30,0x0C,0x06,
-    0x03,0x55,0x04,0x11,0x13,0x05,0x35,0x39,0x31,0x30,0x30,0x31,0x0D,0x30,0x0B,0x06,
-    0x03,0x55,0x04,0x08,0x13,0x04,0x4E,0x6F,0x72,0x64,0x31,0x10,0x30,0x0E,0x06,0x03,
-    0x55,0x04,0x07,0x13,0x07,0x52,0x6F,0x75,0x62,0x61,0x69,0x78,0x31,0x19,0x30,0x17,
-    0x06,0x03,0x55,0x04,0x09,0x13,0x10,0x32,0x20,0x72,0x75,0x65,0x20,0x4B,0x65,0x6C,
-    0x6C,0x65,0x72,0x6D,0x61,0x6E,0x6E,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,
-    0x13,0x07,0x4F,0x56,0x48,0x20,0x53,0x41,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x0B,0x13,0x02,0x49,0x54,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0B,0x13,
-    0x0D,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x56,0x20,0x53,0x53,0x4C,0x31,0x10,
-    0x30,0x0E,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x6F,0x76,0x68,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,0x93,0xA1,0x5D,0x05,0x5F,0x1A,0x26,0x56,0x3D,0xDC,0xC2,0x7C,0x1B,0xA1,0x7A,
-    0x63,0x16,0x4F,0xBD,0xE0,0x77,0x85,0x04,0xB0,0x9B,0x49,0xE9,0x2B,0x5C,0xB1,0x51,
-    0xFD,0x8A,0x14,0x51,0xC7,0xD9,0x50,0xDE,0x64,0x2F,0xFE,0x8C,0x27,0xC3,0x01,0x48,
-    0x64,0x7C,0x85,0x3F,0x93,0xD4,0x09,0xE6,0x42,0xDF,0xC1,0xE4,0xEB,0x6A,0xC0,0x87,
-    0x90,0xA5,0xF6,0x9C,0xD4,0x6B,0x08,0x77,0xFB,0x56,0x44,0x2B,0x8A,0xE0,0x05,0x73,
-    0x14,0x6B,0x02,0x7D,0x76,0x44,0x7B,0x3E,0xA6,0xE5,0x23,0xA9,0xE1,0x8F,0x99,0xDD,
-    0x15,0xCD,0xD9,0xD9,0x6D,0xB9,0x95,0x5B,0xE8,0xB6,0xE2,0x52,0xDD,0xF0,0xB0,0x80,
-    0x1B,0xC1,0x95,0x4B,0x2C,0x9D,0x5E,0x8D,0x02,0x6B,0x59,0x6C,0x26,0x8B,0xC3,0x19,
-    0x0D,0x3E,0xA8,0x34,0xD0,0x43,0x81,0xD7,0xBD,0xB3,0xA7,0x04,0xE1,0x05,0x82,0xA6,
-    0x1F,0x4D,0x70,0x67,0x05,0x96,0x88,0xE8,0xE9,0x2E,0x95,0xD2,0x36,0x75,0xD6,0xC8,
-    0x0C,0x59,0xBF,0x9F,0x1F,0x9F,0xB4,0xFF,0xF0,0x10,0x8C,0xC3,0xE6,0x8B,0x9F,0xE2,
-    0x8E,0x00,0x60,0x58,0xCB,0x6F,0xAD,0x84,0x7B,0xA5,0x36,0xDB,0xB2,0xA4,0xEB,0xC6,
-    0xC8,0xD8,0x61,0x6E,0x4A,0xDC,0x5C,0x3E,0x2C,0x33,0xCB,0x1E,0x16,0x8B,0x8C,0xA3,
-    0x5F,0x0F,0x30,0x4E,0x0A,0x5D,0xA0,0x53,0x7C,0xCE,0xAB,0x29,0x9A,0xC6,0x64,0xC5,
-    0x5A,0xD7,0x94,0x3D,0x81,0xB1,0x05,0x3F,0x2A,0x6D,0xD7,0xB8,0x9D,0xF1,0x6D,0x13,
-    0xFD,0x82,0xB4,0xF9,0x88,0x77,0xAB,0xB8,0x2C,0x7A,0x81,0x6E,0x68,0xFF,0x6E,0x04,
-    0xC1,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03,0x4E,0x30,0x82,0x03,0x4A,0x30,0x1F,
-    0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x39,0xDA,0xFF,0xCA,0x28,
-    0x14,0x8A,0xA8,0x74,0x13,0x08,0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,
-    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x0F,0xAD,0xA6,0xC3,0xBF,
-    0x98,0xA1,0xEC,0xCD,0x20,0xB3,0x2C,0x75,0x03,0x56,0x3A,0xA6,0xD3,0xE6,0x30,0x0E,
-    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x0C,
-    0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x1D,0x06,0x03,
-    0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,
-    0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,
-    0x1D,0x20,0x04,0x3F,0x30,0x3D,0x30,0x3B,0x06,0x0C,0x2B,0x06,0x01,0x04,0x01,0xB2,
-    0x31,0x01,0x02,0x01,0x05,0x01,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x02,0x01,0x16,0x1D,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,
-    0x63,0x75,0x72,0x65,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,
-    0x43,0x50,0x53,0x30,0x56,0x06,0x03,0x55,0x1D,0x1F,0x04,0x4F,0x30,0x4D,0x30,0x4B,
-    0xA0,0x49,0xA0,0x47,0x86,0x45,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,
-    0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,
-    0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x56,
-    0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x53,0x65,0x63,0x75,0x72,0x65,0x53,
-    0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x81,0x87,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x7B,0x30,0x79,0x30,0x51,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x45,0x68,0x74,0x74,0x70,0x3A,0x2F,
-    0x2F,0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,
-    0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x45,0x78,0x74,0x65,0x6E,
-    0x64,0x65,0x64,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x53,0x65,0x63,
-    0x75,0x72,0x65,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,
-    0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,
-    0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,
-    0x61,0x2E,0x63,0x6F,0x6D,0x30,0x1F,0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,
-    0x82,0x07,0x6F,0x76,0x68,0x2E,0x63,0x6F,0x6D,0x82,0x0B,0x77,0x77,0x77,0x2E,0x6F,
-    0x76,0x68,0x2E,0x63,0x6F,0x6D,0x30,0x82,0x01,0x7E,0x06,0x0A,0x2B,0x06,0x01,0x04,
-    0x01,0xD6,0x79,0x02,0x04,0x02,0x04,0x82,0x01,0x6E,0x04,0x82,0x01,0x6A,0x01,0x68,
-    0x00,0x76,0x00,0xA4,0xB9,0x09,0x90,0xB4,0x18,0x58,0x14,0x87,0xBB,0x13,0xA2,0xCC,
-    0x67,0x70,0x0A,0x3C,0x35,0x98,0x04,0xF9,0x1B,0xDF,0xB8,0xE3,0x77,0xCD,0x0E,0xC8,
-    0x0D,0xDC,0x10,0x00,0x00,0x01,0x5B,0xB5,0x7B,0xC8,0x2D,0x00,0x00,0x04,0x03,0x00,
-    0x47,0x30,0x45,0x02,0x21,0x00,0xD5,0x1B,0x6C,0xAE,0x75,0x46,0x62,0x0C,0x8B,0x2E,
-    0x14,0xB1,0xDE,0x7C,0xA5,0xFE,0x5C,0x4F,0x3E,0xB0,0xFF,0xFF,0x33,0xA2,0x84,0x58,
-    0x51,0x57,0x97,0x09,0xAF,0x09,0x02,0x20,0x49,0xD7,0x12,0x12,0x6C,0x2A,0x00,0x21,
-    0x5E,0x48,0xF8,0xD0,0xF2,0xA5,0x81,0x2A,0x4E,0xE9,0x22,0x0A,0x4E,0x46,0x8F,0xDB,
-    0xA5,0x9C,0x4B,0x43,0x7E,0x51,0x24,0xE4,0x00,0x76,0x00,0x56,0x14,0x06,0x9A,0x2F,
-    0xD7,0xC2,0xEC,0xD3,0xF5,0xE1,0xBD,0x44,0xB2,0x3E,0xC7,0x46,0x76,0xB9,0xBC,0x99,
-    0x11,0x5C,0xC0,0xEF,0x94,0x98,0x55,0xD6,0x89,0xD0,0xDD,0x00,0x00,0x01,0x5B,0xB5,
-    0x7B,0xC5,0xC8,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x36,0xA9,0x1D,
-    0x52,0x63,0x04,0x11,0x1F,0x65,0xC6,0x97,0x7C,0x17,0xFC,0x17,0x8D,0xDB,0x9D,0xA7,
-    0xB7,0x84,0x66,0x03,0x55,0x95,0x7D,0x42,0x39,0x98,0x60,0xDE,0x19,0x02,0x21,0x00,
-    0x8B,0xB7,0x16,0xC0,0x20,0x17,0xBF,0x31,0x36,0xBD,0xBC,0x1C,0x12,0x61,0x42,0xC0,
-    0x5C,0x19,0x97,0x0A,0xFA,0x85,0xDB,0x5D,0xC3,0x65,0xBE,0x18,0xBF,0x89,0x6F,0xB9,
-    0x00,0x76,0x00,0xEE,0x4B,0xBD,0xB7,0x75,0xCE,0x60,0xBA,0xE1,0x42,0x69,0x1F,0xAB,
-    0xE1,0x9E,0x66,0xA3,0x0F,0x7E,0x5F,0xB0,0x72,0xD8,0x83,0x00,0xC4,0x7B,0x89,0x7A,
-    0xA8,0xFD,0xCB,0x00,0x00,0x01,0x5B,0xB5,0x7B,0xC7,0xFA,0x00,0x00,0x04,0x03,0x00,
-    0x47,0x30,0x45,0x02,0x21,0x00,0xF8,0xFE,0x02,0xC9,0xAF,0x02,0x18,0xF4,0x12,0x00,
-    0x39,0x3C,0x15,0xE0,0x9C,0x78,0x04,0x19,0x55,0xAE,0x8F,0xB4,0x22,0xB9,0x08,0x66,
-    0x9E,0x21,0x3E,0xF0,0x7D,0xC6,0x02,0x20,0x47,0x45,0x31,0xC7,0x2C,0xC3,0xBE,0xC7,
-    0x5B,0xD8,0x31,0x0A,0xD6,0xAF,0x9D,0xAF,0x04,0x45,0xAA,0x51,0x7D,0x43,0xEF,0x35,
-    0x4D,0x81,0xB3,0x0A,0x2F,0x8D,0xD8,0x61,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6C,0x8E,0xB5,0x58,
-    0x8A,0xC5,0x66,0xAC,0x99,0x68,0xF9,0x80,0x68,0x8E,0xC5,0x10,0xF7,0xD7,0x37,0x5E,
-    0x09,0x8C,0x6B,0xCF,0x30,0x2B,0x98,0x3F,0x76,0x4D,0x69,0xBA,0xE8,0x61,0x1D,0xDE,
-    0x1A,0x14,0x4F,0x5A,0x0B,0x54,0x0F,0x66,0xEF,0xB9,0xB3,0x51,0x6C,0x9B,0x86,0x1D,
-    0xB9,0x13,0xC8,0x54,0x24,0x6C,0x82,0x6E,0x4B,0x3C,0x53,0xC7,0x7D,0x0B,0x40,0x4A,
-    0x7E,0x23,0xF2,0x79,0x6B,0xC3,0xFF,0x9D,0xDF,0xC0,0x16,0x7B,0xFF,0x7B,0x04,0xC9,
-    0xE0,0xEB,0x3F,0x28,0xC6,0xD2,0x79,0xEE,0xAE,0x7E,0x38,0x5F,0x0D,0xDF,0x71,0xE7,
-    0xAA,0x38,0x7E,0xF3,0x28,0xE8,0xB2,0xAC,0x69,0xB9,0x69,0xD4,0x05,0x8E,0xF1,0x00,
-    0x71,0x77,0x97,0x7F,0x94,0x36,0x45,0xE5,0x9C,0x15,0xA3,0xF1,0x40,0xD7,0xB5,0xEA,
-    0x95,0x56,0x75,0x60,0x86,0xFB,0xCD,0xB7,0x81,0x5A,0x34,0x1A,0x83,0x1E,0xC2,0x50,
-    0xA2,0x57,0x16,0x13,0x53,0x95,0xFA,0x95,0xD0,0x64,0x1E,0x09,0x45,0x50,0x05,0x63,
-    0x3A,0x86,0xB2,0x1D,0x9B,0x19,0x0E,0x89,0x7E,0x75,0x17,0xDA,0xC5,0x4D,0x4F,0x71,
-    0x55,0x82,0x3E,0x5F,0x41,0x25,0x2F,0x86,0x9E,0x3D,0xF1,0x32,0xFA,0x77,0x7C,0x30,
-    0x6C,0x50,0x2F,0xE7,0x11,0x7B,0xE1,0x3F,0xA8,0x2E,0xEF,0xAC,0x36,0x94,0x8F,0xF0,
-    0x92,0xB4,0xCA,0x1A,0x53,0x8E,0x12,0x26,0x48,0xC4,0xA8,0x25,0x19,0x96,0x19,0x11,
-    0xA2,0xA2,0x48,0xEB,0x8C,0x12,0x59,0x7F,0xCE,0xFC,0x4B,0xC9,0x19,0x10,0x61,0x2B,
-    0xB3,0xA6,0x6B,0xB4,0xBA,0x68,0xB9,0x22,0x58,0xE4,0x82,0x27,
-};
-
-/* This is the cert the ssl server returns to us. */
-/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
-/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */
-static unsigned char comodo_ev_certificate[1554]={
-    0x30,0x82,0x06,0x0E,0x30,0x82,0x03,0xF6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x06,
-    0xA7,0x43,0x80,0xD4,0xEB,0xFE,0xD4,0x35,0xB5,0xA3,0xF7,0xE1,0x6A,0xBD,0xD8,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81,
-    0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
-    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
-    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
-    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
-    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
-    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,
-    0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,
-    0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,
-    0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x32,0x30,0x32,0x31,0x32,
-    0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x32,0x31,0x31,0x32,
-    0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,
-    0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,
-    0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,
-    0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,
-    0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,
-    0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,
-    0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,
-    0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,
-    0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,
-    0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x95,0x56,0xDE,0x54,
-    0xB4,0xDF,0xD5,0x02,0x49,0x7B,0xD1,0x5B,0x5C,0xA2,0xB2,0x1E,0x8F,0x9C,0x2B,0x62,
-    0x4C,0x2B,0x8D,0x12,0x28,0xF3,0x1A,0x95,0xA3,0xC6,0x10,0xFD,0x29,0xDE,0xE1,0x9F,
-    0x0B,0x38,0x40,0x93,0xD1,0xEF,0x6E,0x95,0x10,0xFC,0xE1,0x90,0x17,0x77,0x2C,0xEE,
-    0x75,0x3E,0x7B,0x63,0xEC,0x61,0x92,0x6E,0x4F,0x3B,0xAB,0x80,0x49,0x6B,0xDF,0x00,
-    0xEA,0x03,0x00,0x7F,0x2F,0x75,0xD5,0x28,0x2F,0xEC,0x56,0x67,0x8F,0x80,0x83,0xA3,
-    0xBD,0xDC,0x03,0x99,0x93,0x8B,0x94,0x91,0x56,0x5B,0xA1,0xB8,0x6A,0x3A,0x3F,0x06,
-    0xBD,0x0E,0x92,0xCC,0x60,0x9C,0xFD,0xB5,0xE0,0x9F,0x66,0x30,0x5F,0xDB,0xE6,0x94,
-    0xF0,0x95,0x6A,0xAF,0xC8,0x8A,0xAF,0x80,0xD9,0xE6,0x88,0x39,0x01,0x7C,0x1C,0xC0,
-    0xC5,0x2A,0xF7,0x7B,0x95,0xA0,0xF2,0x76,0xAB,0x6D,0x9B,0x72,0x39,0x30,0xEB,0xD1,
-    0x57,0x55,0x01,0x9D,0x58,0x11,0x9D,0x7C,0x6D,0x84,0x8F,0x49,0xE8,0x9D,0x09,0xFC,
-    0x3C,0xFD,0x0A,0x4A,0x76,0x14,0x21,0x5C,0x16,0x73,0x40,0x23,0x19,0x74,0xC3,0xBA,
-    0x58,0x0A,0xA6,0x96,0x2E,0xDE,0x36,0xE5,0x9F,0xD0,0xC2,0xF0,0xE1,0xE0,0xC1,0x62,
-    0xE3,0xC2,0x18,0x45,0x19,0x51,0xAA,0x17,0x1E,0xE8,0x23,0x75,0xD4,0xC8,0xD0,0x96,
-    0x13,0xFF,0xC7,0x24,0xD1,0x8C,0x0B,0x27,0xAE,0x9E,0x7A,0xDC,0x3A,0x61,0x63,0x60,
-    0x88,0x97,0x2D,0x5D,0x05,0x0B,0xE5,0x3B,0xEB,0xAE,0xCE,0x3A,0x47,0x73,0x76,0xA8,
-    0xFA,0x2C,0xDD,0xC0,0x87,0x17,0xE9,0xAC,0x30,0x99,0xF8,0x1F,0x02,0x03,0x01,0x00,
-    0x01,0xA3,0x82,0x01,0x69,0x30,0x82,0x01,0x65,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
-    0x04,0x18,0x30,0x16,0x80,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,
-    0x8E,0xAD,0xEE,0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,
-    0x0E,0x04,0x16,0x04,0x14,0x39,0xDA,0xFF,0xCA,0x28,0x14,0x8A,0xA8,0x74,0x13,0x08,
-    0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
-    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
-    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x3E,0x06,
-    0x03,0x55,0x1D,0x20,0x04,0x37,0x30,0x35,0x30,0x33,0x06,0x04,0x55,0x1D,0x20,0x00,
-    0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1D,
-    0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,0x63,0x75,0x72,0x65,0x2E,0x63,
-    0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x4C,0x06,
-    0x03,0x55,0x1D,0x1F,0x04,0x45,0x30,0x43,0x30,0x41,0xA0,0x3F,0xA0,0x3D,0x86,0x3B,
-    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,
-    0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,
-    0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,
-    0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x71,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3B,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2F,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,
-    0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x41,0x64,0x64,0x54,0x72,0x75,
-    0x73,0x74,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,
-    0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x0D,
-    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,
-    0x01,0x00,0x44,0x42,0x9D,0x41,0x51,0x2B,0x48,0x88,0x5D,0x97,0x9B,0x79,0x5E,0x11,
-    0x01,0x4A,0x52,0x19,0x7B,0x41,0x2C,0xC7,0x89,0x3C,0xD0,0x72,0xDC,0x85,0xFA,0x58,
-    0xAF,0xD5,0x25,0xE4,0x13,0xF8,0x58,0x65,0x67,0x9F,0x0D,0xFF,0x57,0x8B,0xA9,0x85,
-    0x5E,0xCA,0xA6,0x4B,0xB0,0xA7,0xB2,0x2D,0xE0,0x8C,0x22,0xCD,0xFB,0xFF,0x79,0xA4,
-    0x8C,0x2B,0x8D,0xFE,0x02,0x3D,0x24,0xDE,0xA9,0x5D,0x5F,0xE4,0x0F,0x47,0xD0,0xDB,
-    0x66,0x25,0x3E,0x87,0x47,0x0C,0xAE,0x22,0xC5,0x50,0x22,0x84,0xD7,0xED,0x4A,0x59,
-    0x1A,0xF6,0x93,0xA5,0x93,0xB0,0xE0,0x1B,0x81,0xF2,0x56,0xC4,0xC8,0x10,0x53,0xE4,
-    0xD4,0x76,0xB1,0xD1,0x5B,0x69,0x4B,0x77,0xB2,0xE0,0x4F,0xC4,0x84,0xE7,0xD4,0xA0,
-    0x50,0xEE,0x3C,0xFA,0x44,0xFC,0xD0,0x57,0xB9,0xE1,0x28,0x53,0xFD,0x53,0xCD,0xDC,
-    0xB9,0x1F,0x7A,0x40,0xBD,0x30,0x3F,0xD8,0x6C,0xD2,0xF3,0xE7,0x07,0x9F,0x1F,0x22,
-    0xB5,0xEA,0x22,0x71,0xCB,0x2A,0xF0,0x56,0x7C,0xFE,0xAC,0xA8,0xD1,0x06,0x0F,0x14,
-    0x14,0x52,0x4C,0xFE,0x64,0x2B,0x0C,0x69,0x2A,0xB8,0x0D,0x50,0x6E,0x3E,0x04,0x07,
-    0xBF,0x7A,0x20,0x8B,0xF8,0xEE,0x65,0x09,0xE1,0xC7,0x49,0x08,0x32,0x3D,0x0D,0x28,
-    0x7E,0x49,0x1D,0xB7,0x4A,0xEF,0x02,0xE7,0x0D,0x80,0x17,0xC8,0x5C,0xE0,0x61,0x62,
-    0xCB,0xEC,0xB3,0x60,0x79,0x25,0xDA,0x1A,0x65,0x73,0x9C,0x38,0x10,0xA0,0x26,0x3A,
-    0xB0,0xC8,0x16,0x7D,0x93,0x31,0x22,0xEE,0x74,0x0B,0x88,0xC0,0x5C,0x89,0x41,0x00,
-    0x28,0xA9,0x47,0x31,0xDF,0x7D,0x49,0x45,0x9A,0xF5,0xE6,0xA7,0x45,0x1A,0xD2,0x8E,
-    0x13,0x10,0xDF,0x83,0xAF,0x9B,0x0D,0xAD,0x7E,0x7E,0x9D,0x35,0x50,0x34,0x04,0xCE,
-    0xE9,0x20,0xD6,0x9E,0xDB,0x9D,0xD4,0xA8,0xDA,0x64,0xB4,0xD1,0x2F,0x59,0x2E,0x5E,
-    0xA2,0x36,0x61,0xD4,0x24,0xA0,0x82,0x33,0x33,0x8A,0xA1,0xD1,0x6C,0xEF,0x61,0x68,
-    0xA3,0xE5,0xD2,0x56,0xAD,0xC5,0xFD,0x5E,0x62,0xEB,0x15,0xA8,0x74,0x12,0x4C,0x2F,
-    0x31,0x8C,0xE9,0xC1,0xDF,0x10,0x4B,0x01,0xEA,0xF6,0x54,0x1B,0xCD,0x7F,0x3B,0xBD,
-    0x5C,0x9F,0xC1,0xDB,0xCF,0x01,0xCA,0xF2,0xBA,0x60,0x12,0x21,0x31,0xED,0xA9,0x64,
-    0xB8,0xB2,0x49,0x58,0x17,0x6D,0x5A,0xD7,0xCD,0x8C,0x6D,0xBE,0x9E,0x7F,0xE2,0x02,
-    0x58,0xA7,0xDB,0xC3,0x2D,0x58,0xF6,0x74,0x06,0x6A,0x9A,0xF6,0x61,0xF9,0xF6,0x00,
-    0xB6,0x69,0xD8,0x3A,0x8B,0x31,0x59,0xDD,0x91,0xE6,0x7C,0x27,0x23,0x87,0xDD,0x03,
-    0x0F,0x8F,0x2A,0x8C,0x1E,0x83,0x01,0x4E,0x01,0x61,0x0C,0x52,0x73,0x6D,0xFC,0x08,
-    0xA2,0xB9,0x2A,0x66,0xE4,0x76,0x4D,0x31,0xA0,0x56,0x9B,0xD9,0x53,0x8D,0xA2,0xB6,
-    0x8F,0x02,0xC8,0xE6,0x3A,0xA6,0x04,0xD1,0x48,0xFB,0xC3,0x4A,0x02,0x76,0xFD,0x2F,
-    0xD2,0xBC,0x13,0xB6,0xE8,0x6D,0x34,0x24,0xFA,0x9D,0x29,0x8A,0xC7,0xA1,0x2B,0x14,
-    0xF1,0x96,0x00,0x73,0xB9,0x13,0xE9,0xC0,0xB9,0x3A,0x47,0x56,0x02,0x71,0x80,0x27,
-    0xA4,0xBC,0x25,0xB6,0xE9,0xBD,0xE4,0xE9,0x98,0x74,0x16,0xF1,0x37,0x84,0x81,0x07,
-    0xB4,0x82,
-};
-
-/* This is the cert we get when we get the url in the AIA extension of the ovh leaf. */
-/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
-/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */
-static unsigned char comodo_aia_certificate[1554]={
-    0x30,0x82,0x06,0x0E,0x30,0x82,0x03,0xF6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x06,
-    0xA7,0x43,0x80,0xD4,0xEB,0xFE,0xD4,0x35,0xB5,0xA3,0xF7,0xE1,0x6A,0xBD,0xD8,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81,
-    0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
-    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
-    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
-    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
-    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
-    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,
-    0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,
-    0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,
-    0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x32,0x30,0x32,0x31,0x32,
-    0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x32,0x31,0x31,0x32,
-    0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,
-    0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,
-    0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,
-    0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,
-    0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,
-    0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,
-    0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,
-    0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,
-    0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,
-    0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x95,0x56,0xDE,0x54,
-    0xB4,0xDF,0xD5,0x02,0x49,0x7B,0xD1,0x5B,0x5C,0xA2,0xB2,0x1E,0x8F,0x9C,0x2B,0x62,
-    0x4C,0x2B,0x8D,0x12,0x28,0xF3,0x1A,0x95,0xA3,0xC6,0x10,0xFD,0x29,0xDE,0xE1,0x9F,
-    0x0B,0x38,0x40,0x93,0xD1,0xEF,0x6E,0x95,0x10,0xFC,0xE1,0x90,0x17,0x77,0x2C,0xEE,
-    0x75,0x3E,0x7B,0x63,0xEC,0x61,0x92,0x6E,0x4F,0x3B,0xAB,0x80,0x49,0x6B,0xDF,0x00,
-    0xEA,0x03,0x00,0x7F,0x2F,0x75,0xD5,0x28,0x2F,0xEC,0x56,0x67,0x8F,0x80,0x83,0xA3,
-    0xBD,0xDC,0x03,0x99,0x93,0x8B,0x94,0x91,0x56,0x5B,0xA1,0xB8,0x6A,0x3A,0x3F,0x06,
-    0xBD,0x0E,0x92,0xCC,0x60,0x9C,0xFD,0xB5,0xE0,0x9F,0x66,0x30,0x5F,0xDB,0xE6,0x94,
-    0xF0,0x95,0x6A,0xAF,0xC8,0x8A,0xAF,0x80,0xD9,0xE6,0x88,0x39,0x01,0x7C,0x1C,0xC0,
-    0xC5,0x2A,0xF7,0x7B,0x95,0xA0,0xF2,0x76,0xAB,0x6D,0x9B,0x72,0x39,0x30,0xEB,0xD1,
-    0x57,0x55,0x01,0x9D,0x58,0x11,0x9D,0x7C,0x6D,0x84,0x8F,0x49,0xE8,0x9D,0x09,0xFC,
-    0x3C,0xFD,0x0A,0x4A,0x76,0x14,0x21,0x5C,0x16,0x73,0x40,0x23,0x19,0x74,0xC3,0xBA,
-    0x58,0x0A,0xA6,0x96,0x2E,0xDE,0x36,0xE5,0x9F,0xD0,0xC2,0xF0,0xE1,0xE0,0xC1,0x62,
-    0xE3,0xC2,0x18,0x45,0x19,0x51,0xAA,0x17,0x1E,0xE8,0x23,0x75,0xD4,0xC8,0xD0,0x96,
-    0x13,0xFF,0xC7,0x24,0xD1,0x8C,0x0B,0x27,0xAE,0x9E,0x7A,0xDC,0x3A,0x61,0x63,0x60,
-    0x88,0x97,0x2D,0x5D,0x05,0x0B,0xE5,0x3B,0xEB,0xAE,0xCE,0x3A,0x47,0x73,0x76,0xA8,
-    0xFA,0x2C,0xDD,0xC0,0x87,0x17,0xE9,0xAC,0x30,0x99,0xF8,0x1F,0x02,0x03,0x01,0x00,
-    0x01,0xA3,0x82,0x01,0x69,0x30,0x82,0x01,0x65,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
-    0x04,0x18,0x30,0x16,0x80,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,
-    0x8E,0xAD,0xEE,0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,
-    0x0E,0x04,0x16,0x04,0x14,0x39,0xDA,0xFF,0xCA,0x28,0x14,0x8A,0xA8,0x74,0x13,0x08,
-    0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
-    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
-    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x3E,0x06,
-    0x03,0x55,0x1D,0x20,0x04,0x37,0x30,0x35,0x30,0x33,0x06,0x04,0x55,0x1D,0x20,0x00,
-    0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1D,
-    0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,0x63,0x75,0x72,0x65,0x2E,0x63,
-    0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x4C,0x06,
-    0x03,0x55,0x1D,0x1F,0x04,0x45,0x30,0x43,0x30,0x41,0xA0,0x3F,0xA0,0x3D,0x86,0x3B,
-    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,
-    0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,
-    0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,
-    0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x71,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3B,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2F,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,
-    0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x41,0x64,0x64,0x54,0x72,0x75,
-    0x73,0x74,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,
-    0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x0D,
-    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,
-    0x01,0x00,0x44,0x42,0x9D,0x41,0x51,0x2B,0x48,0x88,0x5D,0x97,0x9B,0x79,0x5E,0x11,
-    0x01,0x4A,0x52,0x19,0x7B,0x41,0x2C,0xC7,0x89,0x3C,0xD0,0x72,0xDC,0x85,0xFA,0x58,
-    0xAF,0xD5,0x25,0xE4,0x13,0xF8,0x58,0x65,0x67,0x9F,0x0D,0xFF,0x57,0x8B,0xA9,0x85,
-    0x5E,0xCA,0xA6,0x4B,0xB0,0xA7,0xB2,0x2D,0xE0,0x8C,0x22,0xCD,0xFB,0xFF,0x79,0xA4,
-    0x8C,0x2B,0x8D,0xFE,0x02,0x3D,0x24,0xDE,0xA9,0x5D,0x5F,0xE4,0x0F,0x47,0xD0,0xDB,
-    0x66,0x25,0x3E,0x87,0x47,0x0C,0xAE,0x22,0xC5,0x50,0x22,0x84,0xD7,0xED,0x4A,0x59,
-    0x1A,0xF6,0x93,0xA5,0x93,0xB0,0xE0,0x1B,0x81,0xF2,0x56,0xC4,0xC8,0x10,0x53,0xE4,
-    0xD4,0x76,0xB1,0xD1,0x5B,0x69,0x4B,0x77,0xB2,0xE0,0x4F,0xC4,0x84,0xE7,0xD4,0xA0,
-    0x50,0xEE,0x3C,0xFA,0x44,0xFC,0xD0,0x57,0xB9,0xE1,0x28,0x53,0xFD,0x53,0xCD,0xDC,
-    0xB9,0x1F,0x7A,0x40,0xBD,0x30,0x3F,0xD8,0x6C,0xD2,0xF3,0xE7,0x07,0x9F,0x1F,0x22,
-    0xB5,0xEA,0x22,0x71,0xCB,0x2A,0xF0,0x56,0x7C,0xFE,0xAC,0xA8,0xD1,0x06,0x0F,0x14,
-    0x14,0x52,0x4C,0xFE,0x64,0x2B,0x0C,0x69,0x2A,0xB8,0x0D,0x50,0x6E,0x3E,0x04,0x07,
-    0xBF,0x7A,0x20,0x8B,0xF8,0xEE,0x65,0x09,0xE1,0xC7,0x49,0x08,0x32,0x3D,0x0D,0x28,
-    0x7E,0x49,0x1D,0xB7,0x4A,0xEF,0x02,0xE7,0x0D,0x80,0x17,0xC8,0x5C,0xE0,0x61,0x62,
-    0xCB,0xEC,0xB3,0x60,0x79,0x25,0xDA,0x1A,0x65,0x73,0x9C,0x38,0x10,0xA0,0x26,0x3A,
-    0xB0,0xC8,0x16,0x7D,0x93,0x31,0x22,0xEE,0x74,0x0B,0x88,0xC0,0x5C,0x89,0x41,0x00,
-    0x28,0xA9,0x47,0x31,0xDF,0x7D,0x49,0x45,0x9A,0xF5,0xE6,0xA7,0x45,0x1A,0xD2,0x8E,
-    0x13,0x10,0xDF,0x83,0xAF,0x9B,0x0D,0xAD,0x7E,0x7E,0x9D,0x35,0x50,0x34,0x04,0xCE,
-    0xE9,0x20,0xD6,0x9E,0xDB,0x9D,0xD4,0xA8,0xDA,0x64,0xB4,0xD1,0x2F,0x59,0x2E,0x5E,
-    0xA2,0x36,0x61,0xD4,0x24,0xA0,0x82,0x33,0x33,0x8A,0xA1,0xD1,0x6C,0xEF,0x61,0x68,
-    0xA3,0xE5,0xD2,0x56,0xAD,0xC5,0xFD,0x5E,0x62,0xEB,0x15,0xA8,0x74,0x12,0x4C,0x2F,
-    0x31,0x8C,0xE9,0xC1,0xDF,0x10,0x4B,0x01,0xEA,0xF6,0x54,0x1B,0xCD,0x7F,0x3B,0xBD,
-    0x5C,0x9F,0xC1,0xDB,0xCF,0x01,0xCA,0xF2,0xBA,0x60,0x12,0x21,0x31,0xED,0xA9,0x64,
-    0xB8,0xB2,0x49,0x58,0x17,0x6D,0x5A,0xD7,0xCD,0x8C,0x6D,0xBE,0x9E,0x7F,0xE2,0x02,
-    0x58,0xA7,0xDB,0xC3,0x2D,0x58,0xF6,0x74,0x06,0x6A,0x9A,0xF6,0x61,0xF9,0xF6,0x00,
-    0xB6,0x69,0xD8,0x3A,0x8B,0x31,0x59,0xDD,0x91,0xE6,0x7C,0x27,0x23,0x87,0xDD,0x03,
-    0x0F,0x8F,0x2A,0x8C,0x1E,0x83,0x01,0x4E,0x01,0x61,0x0C,0x52,0x73,0x6D,0xFC,0x08,
-    0xA2,0xB9,0x2A,0x66,0xE4,0x76,0x4D,0x31,0xA0,0x56,0x9B,0xD9,0x53,0x8D,0xA2,0xB6,
-    0x8F,0x02,0xC8,0xE6,0x3A,0xA6,0x04,0xD1,0x48,0xFB,0xC3,0x4A,0x02,0x76,0xFD,0x2F,
-    0xD2,0xBC,0x13,0xB6,0xE8,0x6D,0x34,0x24,0xFA,0x9D,0x29,0x8A,0xC7,0xA1,0x2B,0x14,
-    0xF1,0x96,0x00,0x73,0xB9,0x13,0xE9,0xC0,0xB9,0x3A,0x47,0x56,0x02,0x71,0x80,0x27,
-    0xA4,0xBC,0x25,0xB6,0xE9,0xBD,0xE4,0xE9,0x98,0x74,0x16,0xF1,0x37,0x84,0x81,0x07,
-    0xB4,0x82,
-};
-
-static unsigned char valid_ist_certificate[] = {
-    0x30,0x82,0x08,0x51,0x30,0x82,0x07,0x39,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x3A,
-    0xFC,0x35,0x65,0x26,0x40,0x12,0xAF,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,
-    0x03,0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,
-    0x32,0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,
-    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
-    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,
-    0x30,0x37,0x31,0x36,0x32,0x32,0x31,0x31,0x30,0x38,0x5A,0x17,0x0D,0x32,0x30,0x30,
-    0x38,0x31,0x34,0x32,0x32,0x31,0x31,0x30,0x38,0x5A,0x30,0x79,0x31,0x18,0x30,0x16,
-    0x06,0x03,0x55,0x04,0x03,0x0C,0x0F,0x76,0x61,0x6C,0x69,0x64,0x2E,0x61,0x70,0x70,
-    0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x0C,
-    0x1D,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,0x69,0x64,0x6D,0x73,
-    0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x31,0x32,0x30,0x38,0x39,0x32,0x30,0x31,0x13,
-    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
-    0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,
-    0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
-    0x06,0x13,0x02,0x55,0x53,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,0xC7,0x5F,0xAC,0x4A,0xAC,0x71,0xFC,0xF1,0x80,0x8D,
-    0x57,0xA1,0xDC,0x3B,0x48,0x4F,0x02,0x83,0xBA,0xE0,0x57,0x36,0xAB,0x53,0xB5,0x14,
-    0x47,0x8F,0x87,0x24,0xA6,0x7A,0x40,0x5C,0xC3,0x28,0x6E,0x29,0x6D,0x54,0x35,0x89,
-    0x79,0xA9,0x12,0xF3,0xD7,0x0A,0x4E,0xBE,0xC7,0xFB,0x75,0xF3,0x1B,0x92,0x6D,0x3F,
-    0x7B,0xCC,0x72,0x63,0xF5,0xE8,0x57,0xC8,0xD2,0x7A,0x36,0x98,0x6E,0x61,0x0F,0x48,
-    0xD1,0xC3,0x37,0xA4,0xB9,0x94,0x1C,0x66,0x18,0x75,0x97,0x34,0xED,0xFA,0x96,0x00,
-    0x24,0x1A,0x8D,0x2E,0xFB,0x98,0x48,0x85,0xA5,0x73,0x9E,0xED,0x7D,0x8E,0x3C,0xCF,
-    0xED,0xE9,0xE1,0x5F,0x1C,0x36,0xFF,0x20,0x2D,0x62,0x5C,0x0E,0x3D,0xCC,0x6E,0x3D,
-    0xDB,0xF8,0x5A,0x8A,0x5A,0x2A,0x75,0xDC,0x09,0xC4,0x21,0x45,0x55,0x04,0xE3,0xEC,
-    0x20,0xF0,0x5E,0xE3,0xC7,0x1A,0xD3,0x16,0x78,0x07,0xF1,0x65,0xF3,0xAD,0xB5,0x68,
-    0x4B,0x0E,0x5D,0xA9,0x37,0xEA,0x58,0xAA,0x19,0x1F,0xF4,0xB4,0xF3,0x01,0xB0,0xE0,
-    0xDC,0x25,0x4D,0x8A,0x2E,0xB1,0xC4,0xD3,0xE6,0x05,0x9E,0x23,0x8B,0x1E,0x8B,0xD0,
-    0x14,0xA1,0x7E,0xC7,0x98,0xF1,0x68,0x9C,0x2D,0x10,0xDE,0xF9,0x79,0x14,0x3E,0x98,
-    0x73,0x19,0x94,0x4B,0x4A,0xF7,0x52,0xDA,0x4D,0x98,0x26,0xAC,0xB2,0x76,0x1A,0x71,
-    0xB5,0xFA,0x0D,0xE8,0x93,0xEB,0x92,0xF8,0x77,0x82,0xE5,0xE9,0xD4,0x07,0x8C,0xFD,
-    0x20,0x8D,0xA0,0x25,0xD2,0x8A,0x6F,0xE2,0x33,0xA7,0x24,0x56,0x14,0x30,0x29,0x9D,
-    0x6B,0xAB,0x2A,0x33,0xF9,0xD3,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x04,0xF2,0x30,
-    0x82,0x04,0xEE,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,
-    0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xD8,0x7A,
-    0x94,0x44,0x7C,0x90,0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,0x01,0x44,0x03,0x86,0xD6,
-    0x2A,0x29,0x30,0x7E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x72,
-    0x30,0x70,0x30,0x34,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x28,
-    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x73,0x2E,0x61,0x70,0x70,
-    0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,0x63,
-    0x61,0x32,0x67,0x31,0x2E,0x64,0x65,0x72,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x30,0x01,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,
-    0x70,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,
-    0x30,0x33,0x2D,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,0x63,0x61,0x32,0x67,0x31,
-    0x32,0x30,0x30,0x43,0x06,0x03,0x55,0x1D,0x11,0x04,0x3C,0x30,0x3A,0x82,0x0F,0x76,
-    0x61,0x6C,0x69,0x64,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x13,
-    0x76,0x61,0x6C,0x69,0x64,0x2D,0x75,0x61,0x74,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,
-    0x63,0x6F,0x6D,0x82,0x12,0x76,0x61,0x6C,0x69,0x64,0x2D,0x71,0x61,0x2E,0x61,0x70,
-    0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x81,0xFF,0x06,0x03,0x55,0x1D,0x20,0x04,
-    0x81,0xF7,0x30,0x81,0xF4,0x30,0x81,0xF1,0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,
-    0x64,0x05,0x0B,0x04,0x30,0x81,0xE2,0x30,0x81,0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,
-    0x63,0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x65,0x72,0x74,0x69,
-    0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,0x20,0x61,0x6E,0x79,0x20,0x70,0x61,
-    0x72,0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,0x65,0x73,0x20,0x61,0x63,0x63,0x65,
-    0x70,0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,0x20,0x61,0x6E,0x79,0x20,0x61,0x70,
-    0x70,0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x74,0x65,0x72,0x6D,0x73,0x20,0x61,
-    0x6E,0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,
-    0x20,0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,0x6F,0x72,0x20,0x63,0x65,0x72,0x74,
-    0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x70,0x72,0x61,0x63,0x74,0x69,
-    0x63,0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x30,0x39,
-    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x2D,0x68,0x74,0x74,0x70,
-    0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x61,0x75,0x74,0x68,
-    0x6F,0x72,0x69,0x74,0x79,0x2F,0x72,0x70,0x61,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,
-    0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x37,0x06,0x03,0x55,0x1D,0x1F,0x04,
-    0x30,0x30,0x2E,0x30,0x2C,0xA0,0x2A,0xA0,0x28,0x86,0x26,0x68,0x74,0x74,0x70,0x3A,
-    0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,
-    0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,0x63,0x61,0x32,0x67,0x31,0x2E,0x63,0x72,
-    0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x55,0xF7,0x8E,0xC8,
-    0x40,0x19,0x7D,0x8B,0x19,0x80,0xA5,0xF5,0xC6,0x44,0x75,0x8A,0x04,0x1E,0x7D,0x48,
-    0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,
-    0x30,0x82,0x02,0x6D,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x02,
-    0x04,0x82,0x02,0x5D,0x04,0x82,0x02,0x59,0x02,0x57,0x00,0x75,0x00,0xBB,0xD9,0xDF,
-    0xBC,0x1F,0x8A,0x71,0xB5,0x93,0x94,0x23,0x97,0xAA,0x92,0x7B,0x47,0x38,0x57,0x95,
-    0x0A,0xAB,0x52,0xE8,0x1A,0x90,0x96,0x64,0x36,0x8E,0x1E,0xD1,0x85,0x00,0x00,0x01,
-    0x64,0xA5,0x2E,0xD8,0xFD,0x00,0x00,0x04,0x03,0x00,0x46,0x30,0x44,0x02,0x20,0x3E,
-    0xD8,0xAB,0x26,0x35,0xFC,0xAC,0xE8,0x97,0xE8,0x84,0x28,0x73,0x0D,0xFB,0x6F,0x7B,
-    0x02,0xF6,0x8E,0xB8,0xD1,0xAC,0xF3,0x9C,0xDF,0x37,0x2E,0x42,0x53,0x6B,0x3A,0x02,
-    0x20,0x73,0x9A,0xED,0x05,0x2C,0x5C,0xDD,0x5A,0x60,0x2D,0xF9,0xB3,0x5C,0x7B,0xB3,
-    0x95,0x0F,0xF1,0x21,0xD3,0xB5,0x1C,0x40,0xBC,0x50,0x79,0xE2,0xF3,0x19,0x89,0xAC,
-    0xE7,0x00,0x75,0x00,0x56,0x14,0x06,0x9A,0x2F,0xD7,0xC2,0xEC,0xD3,0xF5,0xE1,0xBD,
-    0x44,0xB2,0x3E,0xC7,0x46,0x76,0xB9,0xBC,0x99,0x11,0x5C,0xC0,0xEF,0x94,0x98,0x55,
-    0xD6,0x89,0xD0,0xDD,0x00,0x00,0x01,0x64,0xA5,0x2E,0xD9,0xA9,0x00,0x00,0x04,0x03,
-    0x00,0x46,0x30,0x44,0x02,0x20,0x2E,0x5B,0x93,0xD3,0xCA,0x9A,0x1E,0x80,0xC3,0x50,
-    0x1C,0xC1,0x37,0x6B,0x11,0x76,0x34,0xE8,0xE3,0xC7,0x8D,0x17,0xD0,0x4D,0x2E,0xA7,
-    0xD9,0x98,0x6E,0x15,0x3A,0xC3,0x02,0x20,0x18,0x2B,0xD6,0x7A,0x11,0x46,0xC0,0xE1,
-    0x99,0xDA,0x51,0x9C,0xBA,0xC5,0xC3,0x4C,0x3F,0x9A,0xB2,0xD1,0xDA,0xB7,0x6B,0x69,
-    0x33,0x81,0x23,0x46,0x6F,0x54,0xFF,0x3F,0x00,0x76,0x00,0xEE,0x4B,0xBD,0xB7,0x75,
-    0xCE,0x60,0xBA,0xE1,0x42,0x69,0x1F,0xAB,0xE1,0x9E,0x66,0xA3,0x0F,0x7E,0x5F,0xB0,
-    0x72,0xD8,0x83,0x00,0xC4,0x7B,0x89,0x7A,0xA8,0xFD,0xCB,0x00,0x00,0x01,0x64,0xA5,
-    0x2E,0xD9,0x25,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x5E,0x30,0x51,
-    0x55,0x80,0x59,0xEA,0x60,0x45,0x10,0x9D,0x8E,0x61,0x07,0x34,0xD4,0xC2,0x08,0x46,
-    0xEB,0xAC,0x4A,0xC3,0x72,0xC6,0x04,0x8E,0xF4,0x5D,0xF6,0xAF,0x51,0x02,0x21,0x00,
-    0xC0,0x20,0xF0,0x01,0x1F,0x74,0xD4,0x33,0x24,0xE3,0x70,0xB3,0x80,0x47,0xE9,0x8A,
-    0xB6,0x47,0xE4,0x65,0xA4,0x98,0x8D,0x6A,0xD8,0x75,0xE4,0xFE,0xC7,0x7A,0x89,0x5E,
-    0x00,0x77,0x00,0x55,0x81,0xD4,0xC2,0x16,0x90,0x36,0x01,0x4A,0xEA,0x0B,0x9B,0x57,
-    0x3C,0x53,0xF0,0xC0,0xE4,0x38,0x78,0x70,0x25,0x08,0x17,0x2F,0xA3,0xAA,0x1D,0x07,
-    0x13,0xD3,0x0C,0x00,0x00,0x01,0x64,0xA5,0x2E,0xD9,0x74,0x00,0x00,0x04,0x03,0x00,
-    0x48,0x30,0x46,0x02,0x21,0x00,0x94,0x79,0x39,0x0B,0x5F,0x59,0x89,0x4D,0xD4,0x09,
-    0x28,0xB4,0xE1,0x07,0xC0,0x58,0xDC,0xA3,0x86,0x07,0x68,0x29,0x02,0xDA,0x86,0xE6,
-    0x70,0xBE,0x32,0xB7,0xC6,0x33,0x02,0x21,0x00,0xA6,0x72,0x28,0x8B,0xC9,0x61,0xC4,
-    0xFB,0x53,0x98,0x8F,0x99,0x3F,0x92,0x7E,0x06,0x21,0x10,0xA1,0x58,0x1D,0x28,0x44,
-    0x80,0x29,0x91,0xC2,0xE6,0xBB,0xCE,0xCC,0x0E,0x00,0x76,0x00,0x87,0x75,0xBF,0xE7,
-    0x59,0x7C,0xF8,0x8C,0x43,0x99,0x5F,0xBD,0xF3,0x6E,0xFF,0x56,0x8D,0x47,0x56,0x36,
-    0xFF,0x4A,0xB5,0x60,0xC1,0xB4,0xEA,0xFF,0x5E,0xA0,0x83,0x0F,0x00,0x00,0x01,0x64,
-    0xA5,0x2E,0xD9,0x12,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x37,0x9C,
-    0x18,0xFC,0x24,0x63,0xAD,0x19,0xD6,0xA2,0x82,0xD9,0x47,0x82,0xAE,0x94,0x66,0x97,
-    0xE4,0x73,0xCC,0x36,0x40,0x8A,0x6F,0xA5,0xAA,0x3C,0x99,0x92,0x8D,0x8F,0x02,0x21,
-    0x00,0xF4,0x44,0x4A,0x8D,0x3A,0x18,0x31,0xDA,0xF5,0xDD,0xF4,0x37,0x4F,0xB3,0x1D,
-    0xF6,0x15,0xBD,0x8B,0xF5,0x75,0x53,0x12,0x35,0xE5,0xD5,0x4D,0x08,0x0E,0xA7,0xC2,
-    0x69,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
-    0x03,0x82,0x01,0x01,0x00,0x8F,0x46,0xED,0x04,0x6F,0xED,0xF7,0xAA,0xB9,0xE3,0x29,
-    0xF7,0x4A,0x9F,0x69,0xEB,0xB2,0x61,0xD0,0x37,0x68,0x8F,0xC8,0xCF,0xB2,0x4F,0x1F,
-    0x02,0x3E,0xF3,0x78,0x38,0x67,0xDB,0xD1,0xFA,0x60,0x16,0x70,0xDD,0xB7,0x44,0x12,
-    0x54,0x0A,0x8C,0x3E,0xEC,0xF2,0xE9,0xBC,0x78,0x11,0x8D,0x7F,0x44,0x16,0xF0,0x87,
-    0xD6,0xD8,0xA2,0x65,0xBC,0x11,0x32,0x4A,0xED,0xA9,0xF9,0xD7,0xB6,0xF7,0x9B,0x0F,
-    0xFF,0x82,0x06,0x12,0x04,0x77,0xB9,0x13,0x08,0xAB,0x98,0x5D,0x07,0x04,0x7C,0xDC,
-    0x43,0x1E,0x86,0x16,0x8C,0xF7,0xB2,0x67,0x42,0x65,0x43,0x40,0x9B,0x1F,0xC6,0x97,
-    0x18,0x41,0xCF,0x2F,0xA9,0xC8,0x4D,0x57,0x4E,0x84,0x28,0x0F,0xC9,0x3A,0xEF,0xB6,
-    0x3D,0x9C,0xE9,0x96,0x12,0xFA,0xF2,0x35,0xA0,0xF1,0xDB,0x9D,0x0A,0x65,0x23,0xBB,
-    0xC9,0x38,0xCC,0x39,0x7E,0x6B,0x17,0x80,0x48,0xF1,0xAC,0xF3,0x12,0x33,0x7B,0xBE,
-    0x5E,0x7B,0xC4,0x8D,0xC6,0xB9,0x9B,0x85,0x0A,0x8A,0x52,0x4F,0x5E,0xC7,0x1F,0x12,
-    0xDB,0xA5,0xBA,0x33,0x9E,0xA2,0x3A,0x9E,0x11,0x82,0x4E,0x42,0x0E,0x3F,0x82,0xDF,
-    0x36,0x91,0xF7,0x24,0xB6,0xFC,0x6D,0x00,0x19,0xF2,0xD0,0x31,0x70,0x1F,0xED,0xE6,
-    0x37,0xED,0x1D,0xB3,0xDB,0x06,0x01,0x90,0x0E,0x95,0x9B,0xD6,0x34,0x5F,0xFA,0xE6,
-    0xD1,0x34,0xA6,0xD9,0x61,0x63,0x3E,0x2D,0x59,0x7B,0xD4,0xA5,0x9E,0x3F,0xFE,0xFE,
-    0x58,0xC9,0x60,0xAE,0xA4,0xC2,0xCB,0xA6,0x50,0x9D,0x50,0xDB,0x38,0x80,0x2F,0xC9,
-    0x2A,0xC5,0xEF,0x98,0xCF,
-};
-
-static unsigned char revoked_ist_certificate[1515]={
-    0x30,0x82,0x05,0xE7,0x30,0x82,0x04,0xCF,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x7F,
-    0x00,0xCE,0x8A,0xD6,0x3F,0x5B,0x34,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,
-    0x03,0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,
-    0x32,0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,
-    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
-    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x0A,0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x34,
-    0x31,0x31,0x32,0x38,0x31,0x35,0x30,0x36,0x31,0x34,0x5A,0x17,0x0D,0x31,0x36,0x31,
-    0x32,0x32,0x37,0x31,0x35,0x30,0x36,0x31,0x34,0x5A,0x30,0x81,0xAB,0x31,0x4B,0x30,
-    0x49,0x06,0x03,0x55,0x04,0x03,0x0C,0x42,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x2E,
-    0x67,0x65,0x6F,0x74,0x72,0x75,0x73,0x74,0x2D,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2D,
-    0x63,0x61,0x2E,0x74,0x65,0x73,0x74,0x2D,0x70,0x61,0x67,0x65,0x73,0x2E,0x63,0x65,
-    0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,0x6E,0x61,0x67,0x65,0x72,
-    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x25,0x30,0x23,0x06,0x03,
-    0x55,0x04,0x0B,0x0C,0x1C,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,
-    0x69,0x64,0x6D,0x73,0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x31,0x37,0x36,0x33,0x39,
-    0x39,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
-    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
-    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,
-    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xA9,0xD7,0xE0,0x65,0x48,0x36,0x8A,
-    0x4B,0x6C,0xBB,0x16,0xAF,0xFD,0x09,0xA5,0x9C,0x30,0xDA,0xC5,0x9B,0x3D,0xD6,0xB4,
-    0x8E,0x6B,0xC2,0xF4,0xBF,0x30,0xA7,0xCC,0xF7,0xA1,0x23,0x58,0xA0,0x16,0xE8,0x31,
-    0x5F,0xE7,0xD2,0x21,0x3D,0x24,0x3D,0xF4,0x1E,0x82,0x46,0x45,0xA0,0xB8,0x2E,0xD7,
-    0xB6,0x86,0xD3,0x2A,0xBC,0x93,0x74,0x44,0xAB,0x1C,0x9F,0x86,0xBF,0x19,0xCE,0xA4,
-    0xD0,0xC9,0xB9,0x65,0x84,0x89,0x87,0xDE,0x77,0xDC,0xAE,0x85,0xA9,0xDE,0x5A,0xCF,
-    0xAF,0x46,0x80,0x45,0x72,0x68,0x87,0x55,0x5B,0x4D,0x49,0xE2,0x7B,0x25,0x31,0x22,
-    0x00,0x87,0xAB,0x72,0xEB,0x9A,0x2D,0x81,0x35,0x0E,0x76,0x82,0x5C,0x99,0x10,0xFB,
-    0xD6,0x3F,0x29,0xE8,0xFD,0x2E,0xAD,0xF6,0xF8,0xCF,0xC1,0x99,0x5F,0xDA,0xC1,0xB3,
-    0x90,0x70,0xA5,0x4B,0x23,0x4D,0xD6,0x1D,0xC9,0x73,0x27,0xD1,0xAE,0x38,0xA3,0xD0,
-    0x71,0x92,0xFF,0x89,0xA8,0xE5,0x51,0x3E,0x2F,0xB6,0xB4,0x02,0x20,0x54,0x62,0xA0,
-    0x69,0x6D,0xB6,0x10,0x8D,0xB7,0x13,0x2A,0x94,0x4E,0xED,0x73,0x8C,0x78,0x39,0xF6,
-    0x04,0xC0,0xF8,0x7A,0x75,0x2D,0x1E,0x82,0x7E,0x55,0x7B,0xE7,0xA7,0xFA,0x6E,0xB1,
-    0x53,0x81,0x75,0xB6,0x19,0xD8,0xD2,0xD3,0x8E,0x30,0x95,0x0D,0xD8,0xC9,0xBA,0x3F,
-    0x70,0x23,0xC3,0x7B,0xE2,0x6E,0xA9,0xA8,0x91,0x69,0x89,0x8D,0xEA,0x64,0x5D,0x8E,
-    0x49,0x43,0x30,0x99,0xBC,0x54,0x97,0xAC,0xEB,0x98,0x09,0x8C,0xE9,0xA7,0xE8,0xDC,
-    0xFC,0xE4,0xBE,0x20,0xDA,0xA1,0x88,0xB6,0x99,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,
-    0x02,0x55,0x30,0x82,0x02,0x51,0x30,0x48,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x01,0x01,0x04,0x3C,0x30,0x3A,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x30,0x01,0x86,0x2C,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,
-    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x34,
-    0x2D,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,0x63,0x61,0x32,0x67,0x31,0x30,0x31,
-    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x75,0x81,0x7F,0xDF,0xDE,
-    0x90,0xE2,0xFB,0x67,0xA8,0x04,0xC9,0x82,0xE1,0x2A,0x13,0x08,0x3D,0xCE,0x8E,0x30,
-    0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x1F,0x06,
-    0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xD8,0x7A,0x94,0x44,0x7C,0x90,
-    0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,0x01,0x44,0x03,0x86,0xD6,0x2A,0x29,0x30,0x81,
-    0xFF,0x06,0x03,0x55,0x1D,0x20,0x04,0x81,0xF7,0x30,0x81,0xF4,0x30,0x81,0xF1,0x06,
-    0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x05,0x0B,0x04,0x30,0x81,0xE2,0x30,0x81,
-    0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,
-    0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,0x63,0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,
-    0x73,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,
-    0x20,0x61,0x6E,0x79,0x20,0x70,0x61,0x72,0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,
-    0x65,0x73,0x20,0x61,0x63,0x63,0x65,0x70,0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,
-    0x20,0x61,0x6E,0x79,0x20,0x61,0x70,0x70,0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,
-    0x74,0x65,0x72,0x6D,0x73,0x20,0x61,0x6E,0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,
-    0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,0x20,0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,
-    0x6F,0x72,0x20,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,
-    0x20,0x70,0x72,0x61,0x63,0x74,0x69,0x63,0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,
-    0x65,0x6E,0x74,0x73,0x2E,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,
-    0x01,0x16,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x61,0x70,
-    0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,
-    0x61,0x74,0x65,0x61,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2F,0x72,0x70,0x61,
-    0x30,0x37,0x06,0x03,0x55,0x1D,0x1F,0x04,0x30,0x30,0x2E,0x30,0x2C,0xA0,0x2A,0xA0,
-    0x28,0x86,0x26,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,
-    0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,0x69,0x73,0x74,
-    0x63,0x61,0x32,0x67,0x31,0x2E,0x63,0x72,0x6C,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
-    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,
-    0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x4D,0x06,0x03,0x55,0x1D,0x11,0x04,
-    0x46,0x30,0x44,0x82,0x42,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x2E,0x67,0x65,0x6F,
-    0x74,0x72,0x75,0x73,0x74,0x2D,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2D,0x63,0x61,0x2E,
-    0x74,0x65,0x73,0x74,0x2D,0x70,0x61,0x67,0x65,0x73,0x2E,0x63,0x65,0x72,0x74,0x69,
-    0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,0x6E,0x61,0x67,0x65,0x72,0x2E,0x61,0x70,
-    0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC0,0x5B,0xA6,0xAF,0x2C,
-    0x27,0xBA,0x49,0x8D,0x41,0xF6,0xC4,0x02,0xEE,0x9D,0xB1,0x48,0xC3,0x34,0x7B,0xF2,
-    0xD2,0x82,0x49,0xA5,0x13,0x5A,0x66,0xAD,0xC9,0x73,0xBF,0x6B,0xC9,0x30,0x86,0xBA,
-    0x7A,0xD2,0x9D,0x61,0xFE,0x04,0x07,0x15,0x66,0xC2,0x25,0xF7,0x6C,0x88,0xB1,0x0E,
-    0x22,0x11,0xF9,0x26,0xA7,0x4E,0x88,0x96,0x20,0x99,0xA6,0x51,0xEE,0x02,0x96,0xC7,
-    0xA4,0xCA,0xD4,0xAB,0xFC,0x5F,0x96,0x16,0x0D,0x8D,0xA0,0xA1,0x17,0x6E,0x77,0x92,
-    0xC9,0x64,0xD9,0xA2,0x5A,0x00,0x08,0xA6,0x55,0x73,0x2C,0xDD,0xD3,0x0C,0xA5,0xCA,
-    0x68,0x48,0xAE,0xCE,0x5F,0xF2,0x56,0x4A,0x66,0x57,0xB2,0x2D,0xB5,0xC6,0xFF,0x50,
-    0xD8,0x36,0x9C,0x31,0x31,0xE8,0xB2,0x07,0xE2,0x7B,0xC0,0xCE,0x72,0xA4,0x60,0x91,
-    0xBB,0x84,0xA7,0xA8,0xC0,0x1D,0x42,0xE8,0x1D,0xF5,0xD9,0x6B,0x85,0x67,0x23,0x20,
-    0xA6,0xF8,0x0F,0xBA,0x83,0x63,0x49,0xE2,0x79,0x23,0x90,0xFF,0x6B,0xEF,0xFA,0xB4,
-    0x04,0xA8,0x99,0x1E,0x5D,0x5A,0xCD,0x8C,0xBC,0x8E,0x30,0x41,0x7E,0xE7,0x4E,0xDB,
-    0x6F,0x4E,0xB7,0xBA,0xE0,0x5B,0x31,0xC4,0xD2,0x2D,0xD3,0x5D,0x82,0x95,0x44,0x7D,
-    0x11,0x60,0x75,0xCE,0x6D,0x12,0xDA,0x89,0x71,0x23,0x80,0x75,0xC0,0x13,0x67,0x27,
-    0xE8,0xE8,0xCA,0xE0,0xE3,0xFC,0x72,0x23,0x98,0xFA,0xF0,0x96,0x05,0x23,0xC9,0x03,
-    0xC8,0x29,0xA4,0xB1,0xE5,0x07,0xE6,0xE8,0x09,0x26,0xD1,0x8C,0xAF,0xE0,0x53,0xBB,
-    0xB4,0x1E,0x4D,0x5E,0xEA,0x9A,0x1E,0xE9,0x42,0x87,0x9F,
-};
-
-static unsigned char ist_intermediate_certificate[1092]={
-    0x30,0x82,0x04,0x40,0x30,0x82,0x03,0x28,0xA0,0x03,0x02,0x01,0x02,0x02,0x03,0x02,
-    0x3A,0x74,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
-    0x00,0x30,0x42,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
-    0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0A,0x13,0x0D,0x47,0x65,0x6F,0x54,0x72,
-    0x75,0x73,0x74,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,
-    0x03,0x13,0x12,0x47,0x65,0x6F,0x54,0x72,0x75,0x73,0x74,0x20,0x47,0x6C,0x6F,0x62,
-    0x61,0x6C,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x34,0x30,0x36,0x31,0x36,0x31,
-    0x35,0x34,0x32,0x30,0x32,0x5A,0x17,0x0D,0x32,0x32,0x30,0x35,0x32,0x30,0x31,0x35,
-    0x34,0x32,0x30,0x32,0x5A,0x30,0x62,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x03,
-    0x13,0x13,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x53,0x54,0x20,0x43,0x41,0x20,0x32,
-    0x20,0x2D,0x20,0x47,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x13,0x17,
-    0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,
-    0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
-    0x13,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,
-    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,
-    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,
-    0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xD0,0x93,0xA1,0x1D,0x47,0x43,
-    0x20,0x16,0xB2,0x0B,0x6B,0xEB,0xC3,0xD5,0xB4,0xE8,0xC7,0x98,0xCD,0xF3,0xDE,0xBF,
-    0xE8,0x4D,0xE9,0xE3,0x36,0x80,0x07,0xFC,0x45,0x1B,0x6A,0x7C,0x45,0x86,0xAE,0x56,
-    0xD3,0xA4,0x09,0x7F,0x61,0x0D,0x6B,0x5D,0x7E,0x52,0x6B,0x7D,0xB4,0xC8,0x39,0xC4,
-    0xF4,0x67,0x3A,0xF7,0x83,0xCE,0x19,0x6F,0x86,0x2F,0x7E,0x45,0x7E,0x47,0x1C,0x67,
-    0x52,0xCA,0x95,0x05,0x5D,0xE2,0x36,0x51,0x85,0xC0,0xD4,0x67,0x80,0x35,0x6F,0x15,
-    0xDD,0x3E,0xFD,0x1D,0xD2,0xFD,0x8F,0x34,0x50,0xD8,0xEC,0x76,0x2A,0xBE,0xE3,0xD3,
-    0xDA,0xE4,0xFD,0xC8,0xEB,0x28,0x02,0x96,0x11,0x97,0x17,0x61,0x1C,0xE9,0xC4,0x59,
-    0x3B,0x42,0xDC,0x32,0xD1,0x09,0x1D,0xDA,0xA6,0xD1,0x43,0x86,0xFF,0x5E,0xB2,0xBC,
-    0x8C,0xCF,0x66,0xDB,0x01,0x8B,0x02,0xAE,0x94,0x48,0xF3,0x38,0x8F,0xFD,0xEA,0x32,
-    0xA8,0x08,0xEC,0x86,0x97,0x51,0x94,0x24,0x3E,0x49,0x49,0x96,0x53,0xE8,0x79,0xA1,
-    0x40,0x81,0xE9,0x05,0xBB,0x93,0x95,0x51,0xFC,0xE3,0xFD,0x7C,0x11,0x4B,0xF7,0x9E,
-    0x08,0xB3,0x15,0x49,0x15,0x07,0xF9,0xD1,0x37,0xA0,0x9B,0x4B,0x32,0xF6,0xB5,0xC4,
-    0xDC,0x6A,0xD1,0xFC,0x0A,0xED,0xF6,0xE0,0xC5,0x29,0xA0,0xA8,0x8B,0x71,0xFE,0x0D,
-    0x92,0xBC,0xFE,0x54,0x70,0x18,0x0A,0x6D,0xC7,0xED,0x0C,0xFB,0xC9,0x2D,0x06,0xC3,
-    0x8C,0x85,0xFC,0xCB,0x86,0x5C,0xD6,0x36,0x8E,0x12,0x8B,0x09,0x7F,0xFB,0x19,0x1A,
-    0x38,0xD5,0xF0,0x94,0x30,0x7A,0x0F,0xA6,0x8C,0xF3,0x02,0x03,0x01,0x00,0x01,0xA3,
-    0x82,0x01,0x1D,0x30,0x82,0x01,0x19,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,
-    0x30,0x16,0x80,0x14,0xC0,0x7A,0x98,0x68,0x8D,0x89,0xFB,0xAB,0x05,0x64,0x0C,0x11,
-    0x7D,0xAA,0x7D,0x65,0xB8,0xCA,0xCC,0x4E,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,
-    0x16,0x04,0x14,0xD8,0x7A,0x94,0x44,0x7C,0x90,0x70,0x90,0x16,0x9E,0xDD,0x17,0x9C,
-    0x01,0x44,0x03,0x86,0xD6,0x2A,0x29,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,
-    0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x0E,0x06,0x03,0x55,
-    0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x35,0x06,0x03,0x55,
-    0x1D,0x1F,0x04,0x2E,0x30,0x2C,0x30,0x2A,0xA0,0x28,0xA0,0x26,0x86,0x24,0x68,0x74,
-    0x74,0x70,0x3A,0x2F,0x2F,0x67,0x2E,0x73,0x79,0x6D,0x63,0x62,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x63,0x72,0x6C,0x73,0x2F,0x67,0x74,0x67,0x6C,0x6F,0x62,0x61,0x6C,0x2E,0x63,
-    0x72,0x6C,0x30,0x2E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x22,
-    0x30,0x20,0x30,0x1E,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x12,
-    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x67,0x2E,0x73,0x79,0x6D,0x63,0x64,0x2E,0x63,
-    0x6F,0x6D,0x30,0x4C,0x06,0x03,0x55,0x1D,0x20,0x04,0x45,0x30,0x43,0x30,0x41,0x06,
-    0x0A,0x60,0x86,0x48,0x01,0x86,0xF8,0x45,0x01,0x07,0x36,0x30,0x33,0x30,0x31,0x06,
-    0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x25,0x68,0x74,0x74,0x70,0x3A,
-    0x2F,0x2F,0x77,0x77,0x77,0x2E,0x67,0x65,0x6F,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,
-    0x6F,0x6D,0x2F,0x72,0x65,0x73,0x6F,0x75,0x72,0x63,0x65,0x73,0x2F,0x63,0x70,0x73,
-    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
-    0x82,0x01,0x01,0x00,0x16,0x47,0x73,0x6F,0x85,0xA2,0x62,0xE1,0xE7,0x2A,0x76,0xBB,
-    0x89,0x95,0x42,0x26,0x97,0xBC,0x4A,0xAC,0xAC,0x70,0x53,0x3A,0x3F,0x31,0x83,0x3D,
-    0x3C,0x1C,0xAB,0x9A,0xE2,0xB1,0x5D,0x1C,0x76,0x1A,0xA0,0x3C,0x0C,0x72,0x57,0xBE,
-    0xD3,0x9E,0x50,0xE0,0xC8,0x99,0xD6,0x58,0xD7,0x02,0xEA,0xCE,0x0D,0x29,0x54,0x7C,
-    0xCD,0xF5,0xC2,0xC6,0x90,0x29,0x55,0xA3,0x6F,0x14,0xA8,0x0B,0x42,0x0D,0x3A,0x98,
-    0x6D,0x06,0x78,0x9E,0xF0,0x6A,0xA3,0x1D,0x02,0x0A,0xA2,0x28,0xA4,0x8D,0xC2,0x81,
-    0x46,0x3E,0x6D,0x67,0xDA,0xDE,0x3F,0xFE,0x85,0x0E,0x42,0x2A,0x12,0xDE,0xB5,0xB7,
-    0xFB,0xB8,0x1B,0xA7,0x96,0xEC,0x77,0x9F,0xEC,0xD4,0x53,0x95,0x7A,0xFF,0x07,0xF4,
-    0xF2,0x0A,0x14,0xC0,0x51,0x52,0xB1,0xD6,0x8E,0x50,0x0B,0x1A,0x99,0x5C,0xBC,0x0B,
-    0xC9,0xBD,0xED,0xED,0xF8,0x5E,0xC1,0x56,0xDB,0x4D,0x7E,0x23,0xA4,0x11,0xA1,0x2C,
-    0xD4,0x1B,0x05,0x9A,0xE4,0x1B,0x52,0xF6,0x7C,0x38,0x99,0x05,0x4B,0xBA,0x72,0x8D,
-    0x42,0x89,0x60,0x04,0x66,0x2A,0xF4,0xFD,0x68,0xD7,0x6B,0xF7,0x99,0x41,0x28,0xD6,
-    0x6C,0x24,0xAB,0xE6,0x25,0x53,0x2E,0xC8,0x82,0x99,0xE2,0xA2,0x8F,0x23,0xBE,0x30,
-    0x83,0xB1,0x27,0x8B,0xFA,0x68,0x7F,0x01,0x49,0xE8,0xC6,0x98,0x6B,0x10,0x2E,0x98,
-    0x5E,0x8A,0xD7,0xCA,0x4B,0xB1,0xC7,0xC9,0x58,0x9A,0xD0,0x36,0xDB,0x96,0x95,0xEC,
-    0xB6,0x81,0xE4,0xF2,0xCD,0x6F,0x1B,0x79,0x87,0x4C,0x10,0x3C,0x89,0xE4,0x4D,0xFA,
-    0x54,0xDC,0xAA,0xA6,
-};
-
-unsigned char ocsp_smime_leaf_certificate[1338]={
-    0x30,0x82,0x05,0x36,0x30,0x82,0x04,0x1E,0xA0,0x03,0x02,0x01,0x02,0x02,0x0D,0x14,
-    0x00,0x01,0x00,0x02,0x9C,0xE1,0xB9,0xE0,0x7C,0xD1,0x7B,0xEC,0x30,0x0D,0x06,0x09,
-    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x7C,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,
-    0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,
-    0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,
-    0x0B,0x13,0x1C,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,
-    0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x4C,0x31,0x20,0x43,0x41,0x31,
-    0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75,
-    0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x31,
-    0x20,0x4C,0x31,0x20,0x43,0x41,0x20,0x49,0x58,0x30,0x1E,0x17,0x0D,0x31,0x30,0x31,
-    0x31,0x31,0x32,0x30,0x36,0x33,0x36,0x34,0x35,0x5A,0x17,0x0D,0x31,0x31,0x31,0x31,
-    0x31,0x33,0x30,0x36,0x33,0x36,0x34,0x35,0x5A,0x30,0x24,0x31,0x0B,0x30,0x09,0x06,
-    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,
-    0x03,0x13,0x0C,0x51,0x75,0x69,0x6E,0x6E,0x20,0x54,0x61,0x79,0x6C,0x6F,0x72,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,
-    0xC1,0x11,0xAA,0x04,0xCF,0x04,0xA0,0x07,0xF3,0x43,0x2A,0xB2,0x27,0x1A,0x13,0x35,
-    0x97,0x9A,0xBA,0x34,0xE5,0x84,0xF3,0xD5,0xE5,0xD9,0xAB,0x23,0x8D,0xB4,0x7E,0x68,
-    0x5C,0xF2,0x9A,0xF1,0x08,0x9B,0x04,0x34,0xC1,0x09,0x14,0x68,0xD8,0x9C,0xC1,0x6C,
-    0x27,0xF5,0x92,0x54,0xAF,0x66,0x65,0xF1,0x50,0xAA,0x7E,0xE3,0xFC,0xC1,0xB0,0x3E,
-    0xEF,0xAA,0x86,0x58,0x4F,0xE7,0x86,0x0A,0x74,0xA6,0x97,0xBD,0x7D,0xF6,0xCE,0xA6,
-    0x8B,0xF7,0xC0,0x90,0x6E,0x50,0x69,0x36,0x65,0x82,0x0F,0x65,0xA7,0x2C,0x16,0xFA,
-    0x6C,0xCA,0x54,0x45,0x7C,0x06,0x20,0x72,0xF0,0x00,0x7B,0xD7,0x17,0xCD,0x94,0x64,
-    0x6A,0xB7,0x28,0xF3,0x62,0xB1,0x29,0xAE,0x0C,0x8A,0x2F,0x3C,0x06,0x89,0xE8,0x81,
-    0x77,0xAD,0x1F,0x65,0xED,0x6F,0x51,0x64,0x65,0x68,0x76,0xD8,0xEE,0xEC,0xA6,0x28,
-    0xA9,0x1C,0x4F,0x98,0x4A,0x6D,0xD0,0xC8,0x5C,0x59,0x17,0x9B,0xF8,0x6D,0xF5,0x93,
-    0xD3,0x4C,0x2A,0x37,0x80,0x65,0xB4,0x34,0xBA,0x64,0x2F,0xA1,0x8E,0x1C,0x6A,0x88,
-    0x7C,0xA3,0xDB,0xDD,0x00,0x9B,0x78,0x51,0x7B,0xA6,0x8D,0xDD,0x43,0x9B,0xB2,0x2E,
-    0x4B,0x1E,0xB3,0x34,0x37,0x3F,0x63,0x08,0x8C,0xC8,0xCF,0xD0,0xB0,0x8C,0xBF,0x8F,
-    0xA7,0x49,0xBD,0x48,0x1D,0xB5,0x1E,0x6A,0x42,0x48,0x16,0x9A,0x7C,0xD3,0x55,0x6B,
-    0xFF,0xD6,0xBA,0x70,0xF3,0x5F,0x1F,0x57,0x16,0xE0,0x1C,0xF1,0x73,0x22,0xD9,0x33,
-    0xA7,0x20,0xE8,0xED,0x52,0x2A,0xE9,0x6F,0xCF,0xFB,0x76,0xAC,0xB8,0x5D,0x9B,0xAB,
-    0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0x0D,0x30,0x82,0x02,0x09,0x30,0x81,0xA5,
-    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x81,0x98,0x30,0x81,0x95,
-    0x30,0x51,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x45,0x68,0x74,
-    0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,
-    0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x65,0x72,0x74,0x73,0x65,0x72,0x76,
-    0x69,0x63,0x65,0x73,0x2F,0x63,0x61,0x63,0x65,0x72,0x74,0x73,0x2F,0x74,0x63,0x5F,
-    0x63,0x6C,0x61,0x73,0x73,0x31,0x5F,0x4C,0x31,0x5F,0x43,0x41,0x5F,0x49,0x58,0x2E,
-    0x63,0x72,0x74,0x30,0x40,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,
-    0x34,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x69,0x78,0x2E,
-    0x74,0x63,0x63,0x6C,0x61,0x73,0x73,0x31,0x2E,0x74,0x63,0x75,0x6E,0x69,0x76,0x65,
-    0x72,0x73,0x61,0x6C,0x2D,0x69,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,
-    0x65,0x72,0x2E,0x64,0x65,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
-    0x80,0x14,0xE9,0xB8,0x28,0x1D,0x46,0xCF,0xFC,0xCD,0xF8,0x4E,0x9B,0xC5,0xEE,0x4B,
-    0x60,0xEB,0xD8,0x3B,0x3F,0xD1,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,
-    0x04,0x02,0x30,0x00,0x30,0x4A,0x06,0x03,0x55,0x1D,0x20,0x04,0x43,0x30,0x41,0x30,
-    0x3F,0x06,0x09,0x2A,0x82,0x14,0x00,0x2C,0x01,0x01,0x01,0x01,0x30,0x32,0x30,0x30,
-    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x24,0x68,0x74,0x74,0x70,
-    0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,
-    0x65,0x72,0x2E,0x64,0x65,0x2F,0x67,0x75,0x69,0x64,0x65,0x6C,0x69,0x6E,0x65,0x73,
-    0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x04,0xF0,
-    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xF8,0x4D,0x7F,0xDE,0xFA,
-    0x21,0x2E,0xAF,0x96,0xBB,0xAA,0x9B,0x22,0x56,0x80,0xF0,0x8E,0xD4,0x6A,0x52,0x30,
-    0x62,0x06,0x03,0x55,0x1D,0x1F,0x04,0x5B,0x30,0x59,0x30,0x57,0xA0,0x55,0xA0,0x53,
-    0x86,0x51,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x69,0x78,0x2E,
-    0x74,0x63,0x63,0x6C,0x61,0x73,0x73,0x31,0x2E,0x74,0x63,0x75,0x6E,0x69,0x76,0x65,
-    0x72,0x73,0x61,0x6C,0x2D,0x69,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,
-    0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C,0x2F,0x76,0x32,0x2F,0x74,0x63,0x5F,
-    0x43,0x6C,0x61,0x73,0x73,0x31,0x5F,0x4C,0x31,0x5F,0x43,0x41,0x5F,0x49,0x58,0x2E,
-    0x63,0x72,0x6C,0x30,0x33,0x06,0x03,0x55,0x1D,0x25,0x04,0x2C,0x30,0x2A,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x03,0x04,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x07,0x06,0x0A,0x2B,0x06,
-    0x01,0x04,0x01,0x82,0x37,0x14,0x02,0x02,0x30,0x1C,0x06,0x03,0x55,0x1D,0x11,0x04,
-    0x15,0x30,0x13,0x81,0x11,0x71,0x74,0x61,0x79,0x6C,0x6F,0x72,0x40,0x61,0x70,0x70,
-    0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
-    0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x0D,0xCF,0x33,0xAB,0x3D,0xD3,
-    0xD2,0x06,0x2C,0x20,0x3C,0xEC,0x0C,0xE4,0xA5,0x19,0x86,0xB3,0xA7,0xA9,0xA6,0xE9,
-    0xDC,0xB4,0x35,0xBB,0x0D,0x67,0xD5,0xBD,0x5F,0x93,0xD9,0x2E,0xA0,0x05,0x2A,0xED,
-    0xAE,0x41,0xD9,0xEE,0x30,0xA8,0x82,0x50,0xD0,0x4B,0x04,0x6B,0x37,0xAE,0xC0,0x10,
-    0x89,0x05,0x68,0x82,0x91,0x2B,0x5B,0xE2,0x7D,0xA6,0x87,0xF7,0x26,0x96,0xBA,0x2A,
-    0x52,0x03,0x97,0xF6,0x2E,0x0D,0x81,0x65,0x24,0x10,0xD5,0x8C,0xB3,0xCD,0x19,0x58,
-    0xAF,0x3A,0x3D,0x2F,0x10,0x30,0x79,0x6A,0xD6,0x08,0x8F,0x8B,0x9D,0x1D,0xF8,0x19,
-    0xE4,0x24,0x2B,0xE0,0x7F,0x73,0xE1,0x50,0x9C,0x53,0xE1,0x46,0xC7,0xA7,0xBD,0x71,
-    0xCD,0xFF,0x39,0xA0,0x50,0xA5,0xA8,0xD9,0x50,0x39,0x6C,0x36,0x1C,0x13,0x89,0x8A,
-    0x0D,0x9D,0x06,0x1B,0xAA,0x59,0x40,0xC1,0xAF,0xED,0x66,0x31,0xB8,0xA0,0x9F,0xCF,
-    0xA6,0x8A,0x2E,0xC2,0x1A,0x4B,0xDB,0x62,0x15,0x6E,0x10,0x2F,0x82,0x3C,0xF8,0xA2,
-    0x18,0x63,0xCC,0x67,0x13,0x42,0x07,0x43,0xDB,0x20,0x13,0xC7,0xAC,0xCE,0xCB,0xEA,
-    0x7E,0x53,0xA6,0x01,0x81,0xB2,0x6E,0x92,0x2B,0x0C,0xF9,0x01,0x2C,0x11,0xC9,0x00,
-    0x10,0x58,0x64,0x56,0x91,0xAC,0xAA,0xF6,0xE0,0x73,0xC7,0x59,0xEC,0xCE,0x51,0x7E,
-    0xAD,0x9F,0x04,0xA4,0x38,0x74,0x65,0xD0,0x23,0xBD,0x6E,0xDF,0x64,0x79,0xE2,0xA3,
-    0x37,0x19,0x2F,0x8C,0x41,0x8B,0x5F,0x6D,0x84,0x61,0x54,0xD1,0x26,0x18,0x70,0xAD,
-    0xE5,0xF4,0xCD,0x59,0xED,0x9E,0xE0,0xC9,0x9F,0xD3,
-};
-
-unsigned char ocsp_smime_CA_certificate[1500]={
-    0x30,0x82,0x05,0xD8,0x30,0x82,0x04,0xC0,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x06,
-    0xE8,0x00,0x01,0x00,0x02,0x4A,0x96,0x2D,0x24,0x0C,0xFE,0xC5,0xC9,0x30,0x0D,0x06,
-    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x79,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,
-    0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,
-    0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,
-    0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,
-    0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,
-    0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,
-    0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,
-    0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x30,0x1E,0x17,0x0D,0x30,0x39,0x31,0x31,0x30,
-    0x33,0x31,0x34,0x30,0x38,0x31,0x39,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,
-    0x32,0x31,0x35,0x39,0x35,0x39,0x5A,0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,
-    0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,
-    0x47,0x6D,0x62,0x48,0x31,0x25,0x30,0x23,0x06,0x03,0x55,0x04,0x0B,0x13,0x1C,0x54,
-    0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,
-    0x61,0x73,0x73,0x20,0x31,0x20,0x4C,0x31,0x20,0x43,0x41,0x31,0x28,0x30,0x26,0x06,
-    0x03,0x55,0x04,0x03,0x13,0x1F,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,
-    0x6E,0x74,0x65,0x72,0x20,0x43,0x6C,0x61,0x73,0x73,0x20,0x31,0x20,0x4C,0x31,0x20,
-    0x43,0x41,0x20,0x49,0x58,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,0xBB,0xE6,0x90,0x6E,0xCF,0x62,0xE9,0xE9,0x0B,0xAA,
-    0xB6,0x10,0xD5,0x47,0xE5,0x7C,0x5D,0x2B,0x27,0x71,0x9A,0x68,0xCD,0x55,0x6D,0xE4,
-    0xA2,0xEF,0xE4,0xFE,0xF2,0x7A,0x63,0x11,0xC2,0x57,0x8A,0xC8,0x7D,0xCF,0x8E,0x66,
-    0x1F,0x65,0x45,0x4B,0xEB,0x80,0x62,0x69,0xBD,0x46,0x8E,0x8B,0xC5,0x6E,0x5A,0x95,
-    0x18,0x2A,0xDE,0xA7,0xF1,0x1F,0x75,0x1A,0x27,0xAB,0x6D,0x32,0x53,0xE3,0xFB,0x4D,
-    0x58,0x62,0x2C,0xFF,0x19,0xE5,0xC7,0xA0,0x0D,0x9A,0x2D,0x21,0x88,0x59,0x84,0xCD,
-    0x1D,0xF1,0xC3,0xC8,0x8A,0x3E,0xB0,0xE5,0xDE,0x08,0x24,0xCF,0xFC,0x40,0x2C,0xBA,
-    0x41,0x23,0x94,0xBB,0x80,0x12,0x89,0x35,0x48,0xB6,0x86,0x04,0xE0,0x01,0x4F,0x8C,
-    0xBA,0xA9,0x98,0xFC,0x1C,0x89,0xED,0x1F,0x8A,0xA1,0xC7,0x86,0x98,0x26,0x1E,0x72,
-    0x65,0x6B,0xFE,0xCF,0x65,0xD9,0x0C,0x64,0x4B,0x1A,0x09,0xF5,0x43,0x11,0x60,0x66,
-    0x26,0xE3,0x33,0x56,0x9A,0xC9,0x3D,0x3E,0x34,0x6A,0x78,0xC6,0xE5,0x50,0x4B,0xC8,
-    0xCD,0x88,0xE4,0x39,0x6C,0x50,0x26,0x9E,0x40,0x2C,0xB6,0x3B,0x7C,0x37,0xB2,0xA7,
-    0xF5,0xDD,0xDC,0xB3,0x51,0xCB,0xF4,0xDC,0x82,0x02,0xB8,0xD7,0x3A,0xDE,0xDA,0x30,
-    0x5C,0x0D,0xF5,0x42,0xDD,0x13,0x69,0x53,0x54,0xE9,0x80,0x26,0x42,0x33,0x1E,0xA5,
-    0xD7,0xCC,0x6E,0xCA,0x66,0x09,0x9F,0x86,0xF0,0x3D,0xBE,0xC6,0x8A,0x61,0x10,0xF3,
-    0xD1,0xFF,0x5B,0xE4,0xB2,0xDB,0x2D,0xB2,0x65,0x0C,0xA9,0x7D,0x17,0xAC,0xBA,0x27,
-    0x4D,0x42,0x5C,0xCE,0x09,0x4F,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x02,0x59,0x30,
-    0x82,0x02,0x55,0x30,0x81,0x9A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,
-    0x04,0x81,0x8D,0x30,0x81,0x8A,0x30,0x52,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x30,0x02,0x86,0x46,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x74,
-    0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x65,
-    0x72,0x74,0x73,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x2F,0x63,0x61,0x63,0x65,0x72,
-    0x74,0x73,0x2F,0x74,0x63,0x5F,0x75,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x5F,
-    0x72,0x6F,0x6F,0x74,0x5F,0x49,0x2E,0x63,0x72,0x74,0x30,0x34,0x06,0x08,0x2B,0x06,
-    0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x28,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,
-    0x63,0x73,0x70,0x2E,0x74,0x63,0x75,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x2D,
-    0x49,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,
-    0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x92,0xA4,0x75,
-    0x2C,0xA4,0x9E,0xBE,0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,
-    0x73,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,
-    0x01,0xFF,0x02,0x01,0x00,0x30,0x52,0x06,0x03,0x55,0x1D,0x20,0x04,0x4B,0x30,0x49,
-    0x30,0x06,0x06,0x04,0x55,0x1D,0x20,0x00,0x30,0x3F,0x06,0x09,0x2A,0x82,0x14,0x00,
-    0x2C,0x01,0x01,0x01,0x01,0x30,0x32,0x30,0x30,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
-    0x07,0x02,0x01,0x16,0x24,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,
-    0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x67,
-    0x75,0x69,0x64,0x65,0x6C,0x69,0x6E,0x65,0x73,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
-    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,
-    0x04,0x16,0x04,0x14,0xE9,0xB8,0x28,0x1D,0x46,0xCF,0xFC,0xCD,0xF8,0x4E,0x9B,0xC5,
-    0xEE,0x4B,0x60,0xEB,0xD8,0x3B,0x3F,0xD1,0x30,0x81,0xFD,0x06,0x03,0x55,0x1D,0x1F,
-    0x04,0x81,0xF5,0x30,0x81,0xF2,0x30,0x81,0xEF,0xA0,0x81,0xEC,0xA0,0x81,0xE9,0x86,
-    0x46,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x74,0x63,0x75,0x6E,
-    0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x2D,0x49,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,
-    0x65,0x6E,0x74,0x65,0x72,0x2E,0x64,0x65,0x2F,0x63,0x72,0x6C,0x2F,0x76,0x32,0x2F,
-    0x74,0x63,0x5F,0x75,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x5F,0x72,0x6F,0x6F,
-    0x74,0x5F,0x49,0x2E,0x63,0x72,0x6C,0x86,0x81,0x9E,0x6C,0x64,0x61,0x70,0x3A,0x2F,
-    0x2F,0x77,0x77,0x77,0x2E,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,0x65,0x72,
-    0x2E,0x64,0x65,0x2F,0x43,0x4E,0x3D,0x54,0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,
-    0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,0x32,0x30,0x55,0x6E,0x69,0x76,0x65,0x72,
-    0x73,0x61,0x6C,0x25,0x32,0x30,0x43,0x41,0x25,0x32,0x30,0x49,0x2C,0x4F,0x3D,0x54,
-    0x43,0x25,0x32,0x30,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x25,
-    0x32,0x30,0x47,0x6D,0x62,0x48,0x2C,0x4F,0x55,0x3D,0x72,0x6F,0x6F,0x74,0x63,0x65,
-    0x72,0x74,0x73,0x2C,0x44,0x43,0x3D,0x74,0x72,0x75,0x73,0x74,0x63,0x65,0x6E,0x74,
-    0x65,0x72,0x2C,0x44,0x43,0x3D,0x64,0x65,0x3F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,
-    0x63,0x61,0x74,0x65,0x52,0x65,0x76,0x6F,0x63,0x61,0x74,0x69,0x6F,0x6E,0x4C,0x69,
-    0x73,0x74,0x3F,0x62,0x61,0x73,0x65,0x3F,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x39,0xC8,0xC4,0x9B,
-    0xEE,0xBE,0x98,0xEE,0x48,0x72,0x6F,0x8D,0xE7,0x71,0xB6,0x0E,0x90,0x8C,0xD3,0xB2,
-    0xC1,0x15,0x21,0xA8,0x46,0x90,0x68,0x5F,0x4A,0x04,0xF1,0x3A,0xC9,0x68,0x84,0x21,
-    0xD8,0xA5,0xE6,0x04,0x75,0x5D,0x9F,0xD2,0xD4,0xF2,0x4B,0x77,0x43,0x32,0xDC,0x95,
-    0xCB,0x60,0xBF,0x02,0x55,0xD0,0xAC,0x1C,0xB0,0xC5,0x14,0x97,0x9B,0x65,0x0A,0xC3,
-    0x0F,0xA5,0x1D,0xEC,0xD8,0x49,0x39,0x95,0xB5,0xA9,0xBE,0xFA,0xF4,0x1E,0xAB,0x56,
-    0xE7,0xA6,0xE5,0x01,0x08,0x88,0x35,0x5F,0x67,0x05,0xDD,0x44,0x24,0x50,0x12,0x22,
-    0x44,0x63,0x79,0xF1,0x9B,0x57,0x69,0xCE,0xAB,0xD6,0x33,0x51,0x4F,0x8D,0xF0,0x70,
-    0x3B,0x8E,0xAD,0x51,0x3A,0x17,0x7F,0x35,0x96,0x6B,0x68,0x68,0x63,0xB6,0x1C,0x0A,
-    0xC9,0xF8,0xDF,0x1D,0x5E,0xCF,0x2B,0x11,0xA5,0x63,0xED,0xCC,0xD0,0xC6,0xD3,0x20,
-    0x6F,0xAA,0xFC,0x68,0x48,0x7E,0x6D,0x1E,0xB8,0x3A,0x45,0xAA,0x12,0x86,0xF3,0xC7,
-    0xBD,0x00,0xB5,0xEB,0xFE,0xEA,0x12,0x9F,0x73,0x33,0x78,0xE7,0x28,0x39,0x68,0xD3,
-    0xA5,0x6D,0xDA,0x76,0xD1,0x4E,0xE1,0x55,0x95,0x80,0xA6,0xE0,0x1B,0xB8,0xCD,0xAC,
-    0x56,0xEF,0x45,0x59,0x47,0x98,0x52,0xDB,0x3A,0x6E,0x26,0xB2,0x31,0x39,0x69,0x75,
-    0xB1,0x2E,0x24,0xF0,0xA4,0x9D,0x97,0x88,0x5E,0x33,0x29,0xC6,0xB5,0xBC,0x07,0x40,
-    0x3A,0x0C,0x3D,0xBA,0xCF,0x74,0x8C,0x4B,0x4E,0x7A,0x21,0xFA,0x1B,0x38,0xCD,0xC4,
-    0x43,0x2F,0x6F,0xB4,0xDF,0x78,0xEE,0x99,0x92,0xE7,0x3A,0x1C,
-};
-
-unsigned char ocsp_smime_root_certificate[993]={
-    0x30,0x82,0x03,0xDD,0x30,0x82,0x02,0xC5,0xA0,0x03,0x02,0x01,0x02,0x02,0x0E,0x1D,
-    0xA2,0x00,0x01,0x00,0x02,0xEC,0xB7,0x60,0x80,0x78,0x8D,0xB6,0x06,0x30,0x0D,0x06,
-    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x79,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,
-    0x03,0x55,0x04,0x0A,0x13,0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,
-    0x6E,0x74,0x65,0x72,0x20,0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,
-    0x04,0x0B,0x13,0x1B,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,
-    0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,
-    0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,
-    0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,
-    0x61,0x6C,0x20,0x43,0x41,0x20,0x49,0x30,0x1E,0x17,0x0D,0x30,0x36,0x30,0x33,0x32,
-    0x32,0x31,0x35,0x35,0x34,0x32,0x38,0x5A,0x17,0x0D,0x32,0x35,0x31,0x32,0x33,0x31,
-    0x32,0x32,0x35,0x39,0x35,0x39,0x5A,0x30,0x79,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x44,0x45,0x31,0x1C,0x30,0x1A,0x06,0x03,0x55,0x04,0x0A,0x13,
-    0x13,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,
-    0x47,0x6D,0x62,0x48,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x0B,0x13,0x1B,0x54,
-    0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,0x74,0x65,0x72,0x20,0x55,0x6E,
-    0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,0x31,0x26,0x30,0x24,0x06,0x03,
-    0x55,0x04,0x03,0x13,0x1D,0x54,0x43,0x20,0x54,0x72,0x75,0x73,0x74,0x43,0x65,0x6E,
-    0x74,0x65,0x72,0x20,0x55,0x6E,0x69,0x76,0x65,0x72,0x73,0x61,0x6C,0x20,0x43,0x41,
-    0x20,0x49,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,0xA4,0x77,0x23,0x96,0x44,0xAF,0x90,0xF4,0x31,0xA7,0x10,0xF4,0x26,
-    0x87,0x9C,0xF3,0x38,0xD9,0x0F,0x5E,0xDE,0xCF,0x41,0xE8,0x31,0xAD,0xC6,0x74,0x91,
-    0x24,0x96,0x78,0x1E,0x09,0xA0,0x9B,0x9A,0x95,0x4A,0x4A,0xF5,0x62,0x7C,0x02,0xA8,
-    0xCA,0xAC,0xFB,0x5A,0x04,0x76,0x39,0xDE,0x5F,0xF1,0xF9,0xB3,0xBF,0xF3,0x03,0x58,
-    0x55,0xD2,0xAA,0xB7,0xE3,0x04,0x22,0xD1,0xF8,0x94,0xDA,0x22,0x08,0x00,0x8D,0xD3,
-    0x7C,0x26,0x5D,0xCC,0x77,0x79,0xE7,0x2C,0x78,0x39,0xA8,0x26,0x73,0x0E,0xA2,0x5D,
-    0x25,0x69,0x85,0x4F,0x55,0x0E,0x9A,0xEF,0xC6,0xB9,0x44,0xE1,0x57,0x3D,0xDF,0x1F,
-    0x54,0x22,0xE5,0x6F,0x65,0xAA,0x33,0x84,0x3A,0xF3,0xCE,0x7A,0xBE,0x55,0x97,0xAE,
-    0x8D,0x12,0x0F,0x14,0x33,0xE2,0x50,0x70,0xC3,0x49,0x87,0x13,0xBC,0x51,0xDE,0xD7,
-    0x98,0x12,0x5A,0xEF,0x3A,0x83,0x33,0x92,0x06,0x75,0x8B,0x92,0x7C,0x12,0x68,0x7B,
-    0x70,0x6A,0x0F,0xB5,0x9B,0xB6,0x77,0x5B,0x48,0x59,0x9D,0xE4,0xEF,0x5A,0xAD,0xF3,
-    0xC1,0x9E,0xD4,0xD7,0x45,0x4E,0xCA,0x56,0x34,0x21,0xBC,0x3E,0x17,0x5B,0x6F,0x77,
-    0x0C,0x48,0x01,0x43,0x29,0xB0,0xDD,0x3F,0x96,0x6E,0xE6,0x95,0xAA,0x0C,0xC0,0x20,
-    0xB6,0xFD,0x3E,0x36,0x27,0x9C,0xE3,0x5C,0xCF,0x4E,0x81,0xDC,0x19,0xBB,0x91,0x90,
-    0x7D,0xEC,0xE6,0x97,0x04,0x1E,0x93,0xCC,0x22,0x49,0xD7,0x97,0x86,0xB6,0x13,0x0A,
-    0x3C,0x43,0x23,0x77,0x7E,0xF0,0xDC,0xE6,0xCD,0x24,0x1F,0x3B,0x83,0x9B,0x34,0x3A,
-    0x83,0x34,0xE3,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x1F,0x06,0x03,
-    0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE,
-    0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0F,0x06,
-    0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,
-    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x1D,
-    0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x92,0xA4,0x75,0x2C,0xA4,0x9E,0xBE,
-    0x81,0x44,0xEB,0x79,0xFC,0x8A,0xC5,0x95,0xA5,0xEB,0x10,0x75,0x73,0x30,0x0D,0x06,
-    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,
-    0x00,0x28,0xD2,0xE0,0x86,0xD5,0xE6,0xF8,0x7B,0xF0,0x97,0xDC,0x22,0x6B,0x3B,0x95,
-    0x14,0x56,0x0F,0x11,0x30,0xA5,0x9A,0x4F,0x3A,0xB0,0x3A,0xE0,0x06,0xCB,0x65,0xF5,
-    0xED,0xC6,0x97,0x27,0xFE,0x25,0xF2,0x57,0xE6,0x5E,0x95,0x8C,0x3E,0x64,0x60,0x15,
-    0x5A,0x7F,0x2F,0x0D,0x01,0xC5,0xB1,0x60,0xFD,0x45,0x35,0xCF,0xF0,0xB2,0xBF,0x06,
-    0xD9,0xEF,0x5A,0xBE,0xB3,0x62,0x21,0xB4,0xD7,0xAB,0x35,0x7C,0x53,0x3E,0xA6,0x27,
-    0xF1,0xA1,0x2D,0xDA,0x1A,0x23,0x9D,0xCC,0xDD,0xEC,0x3C,0x2D,0x9E,0x27,0x34,0x5D,
-    0x0F,0xC2,0x36,0x79,0xBC,0xC9,0x4A,0x62,0x2D,0xED,0x6B,0xD9,0x7D,0x41,0x43,0x7C,
-    0xB6,0xAA,0xCA,0xED,0x61,0xB1,0x37,0x82,0x15,0x09,0x1A,0x8A,0x16,0x30,0xD8,0xEC,
-    0xC9,0xD6,0x47,0x72,0x78,0x4B,0x10,0x46,0x14,0x8E,0x5F,0x0E,0xAF,0xEC,0xC7,0x2F,
-    0xAB,0x10,0xD7,0xB6,0xF1,0x6E,0xEC,0x86,0xB2,0xC2,0xE8,0x0D,0x92,0x73,0xDC,0xA2,
-    0xF4,0x0F,0x3A,0xBF,0x61,0x23,0x10,0x89,0x9C,0x48,0x40,0x6E,0x70,0x00,0xB3,0xD3,
-    0xBA,0x37,0x44,0x58,0x11,0x7A,0x02,0x6A,0x88,0xF0,0x37,0x34,0xF0,0x19,0xE9,0xAC,
-    0xD4,0x65,0x73,0xF6,0x69,0x8C,0x64,0x94,0x3A,0x79,0x85,0x29,0xB0,0x16,0x2B,0x0C,
-    0x82,0x3F,0x06,0x9C,0xC7,0xFD,0x10,0x2B,0x9E,0x0F,0x2C,0xB6,0x9E,0xE3,0x15,0xBF,
-    0xD9,0x36,0x1C,0xBA,0x25,0x1A,0x52,0x3D,0x1A,0xEC,0x22,0x0C,0x1C,0xE0,0xA4,0xA2,
-    0x3D,0xF0,0xE8,0x39,0xCF,0x81,0xC0,0x7B,0xED,0x5D,0x1F,0x6F,0xC5,0xD0,0x0B,0xD7,
-    0x98,
-};
-
-/* subject:/C=US/ST=California/L=Walnut Creek/O=Lucas Garron/CN=revoked.badssl.com */
-/* issuer :/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA */
-uint8_t _probablyRevokedLeaf[]={
-    0x30,0x82,0x06,0xA1,0x30,0x82,0x05,0x89,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x01,
-    0xAF,0x1E,0xFB,0xDD,0x5E,0xAE,0x09,0x52,0x32,0x0B,0x24,0xFE,0x6B,0x55,0x68,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x4D,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x13,0x1E,0x44,
-    0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x53,0x48,0x41,0x32,0x20,0x53,0x65,0x63,
-    0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x30,0x1E,0x17,
-    0x0D,0x31,0x36,0x30,0x39,0x30,0x32,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,
-    0x31,0x39,0x30,0x39,0x31,0x31,0x31,0x32,0x30,0x30,0x30,0x30,0x5A,0x30,0x6D,0x31,
-    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,
-    0x06,0x03,0x55,0x04,0x08,0x13,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,
-    0x61,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x07,0x13,0x0C,0x57,0x61,0x6C,0x6E,
-    0x75,0x74,0x20,0x43,0x72,0x65,0x65,0x6B,0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,
-    0x0A,0x13,0x0C,0x4C,0x75,0x63,0x61,0x73,0x20,0x47,0x61,0x72,0x72,0x6F,0x6E,0x31,
-    0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x03,0x13,0x12,0x72,0x65,0x76,0x6F,0x6B,0x65,
-    0x64,0x2E,0x62,0x61,0x64,0x73,0x73,0x6C,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,0xC7,0x31,0x65,
-    0xE4,0x55,0xCF,0x69,0x90,0x9F,0x6E,0x1F,0xD8,0x6A,0x13,0x7E,0x74,0xBF,0x13,0x3A,
-    0x54,0x64,0x0F,0x74,0x24,0x3D,0xDC,0x60,0xB8,0xA7,0x45,0x01,0xB7,0xC8,0x6A,0x03,
-    0xAC,0x64,0x4A,0x65,0xF0,0x7C,0x81,0x81,0x83,0x0A,0xD9,0xDD,0x31,0x20,0x82,0x48,
-    0xA6,0x33,0x63,0xEE,0x2B,0x74,0xEA,0xB4,0xE6,0xC7,0x1C,0xB2,0x5E,0xE4,0x28,0x3A,
-    0x7A,0x3D,0x20,0x19,0x03,0xB7,0x15,0x3F,0x4F,0xC9,0x26,0xEC,0xB7,0xCB,0xBF,0x48,
-    0x6E,0x5F,0x34,0x70,0x56,0xC4,0x86,0xC7,0xE3,0x52,0x9A,0x21,0x33,0x2F,0x10,0x13,
-    0xF3,0x25,0x0C,0x1E,0x94,0x35,0x2E,0xE8,0xD0,0xD1,0xB5,0xA0,0x77,0x40,0x91,0x2E,
-    0xE9,0xBA,0xF8,0xFF,0x4E,0xF5,0xFB,0xF2,0x7A,0x04,0xA7,0xE6,0xC6,0xCE,0x3F,0x0F,
-    0x10,0x18,0x32,0xC8,0x06,0xBC,0x15,0xB3,0xBE,0x69,0xAC,0x75,0x7D,0x42,0xA0,0x8C,
-    0x2E,0xC3,0xAC,0xE1,0x20,0x4F,0x1E,0x36,0x9C,0x9A,0x2E,0xA2,0xFD,0x79,0x80,0xB6,
-    0x62,0xF8,0xC0,0xB2,0x03,0xA9,0x29,0x50,0xCC,0xD5,0x25,0x8A,0x33,0x5E,0xE0,0x78,
-    0x13,0x18,0xC0,0x80,0x17,0x09,0x95,0xBD,0xA2,0xFE,0x92,0x15,0x07,0x20,0x7A,0x81,
-    0xCE,0xDB,0x0E,0x81,0x29,0x89,0xD4,0xC8,0xEC,0xB3,0xB3,0x79,0x0E,0xF2,0xCE,0x25,
-    0xE7,0xEE,0xBE,0x21,0x7D,0xAF,0x0C,0x13,0x94,0x29,0xDE,0x35,0x9A,0x1E,0xD8,0x84,
-    0x18,0x5A,0x5C,0x1A,0x94,0x82,0xCE,0x9A,0x61,0xD6,0x9D,0xEC,0xF8,0xEE,0xAD,0x3F,
-    0x09,0x5B,0x73,0xEC,0xA2,0x9B,0xFA,0xDC,0x62,0xF1,0x58,0x1F,0x7D,0x02,0x03,0x01,
-    0x00,0x01,0xA3,0x82,0x03,0x5B,0x30,0x82,0x03,0x57,0x30,0x1F,0x06,0x03,0x55,0x1D,
-    0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x0F,0x80,0x61,0x1C,0x82,0x31,0x61,0xD5,0x2F,
-    0x28,0xE7,0x8D,0x46,0x38,0xB4,0x2C,0xE1,0xC6,0xD9,0xE2,0x30,0x1D,0x06,0x03,0x55,
-    0x1D,0x0E,0x04,0x16,0x04,0x14,0xF4,0x48,0x7D,0x07,0x45,0x1A,0x32,0x07,0x90,0x91,
-    0xAC,0x05,0xB8,0x9F,0xA9,0x11,0xF0,0x7E,0x11,0x36,0x30,0x1D,0x06,0x03,0x55,0x1D,
-    0x11,0x04,0x16,0x30,0x14,0x82,0x12,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x2E,0x62,
-    0x61,0x64,0x73,0x73,0x6C,0x2E,0x63,0x6F,0x6D,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
-    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,
-    0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x6B,0x06,0x03,0x55,0x1D,0x1F,0x04,
-    0x64,0x30,0x62,0x30,0x2F,0xA0,0x2D,0xA0,0x2B,0x86,0x29,0x68,0x74,0x74,0x70,0x3A,
-    0x2F,0x2F,0x63,0x72,0x6C,0x33,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,
-    0x63,0x6F,0x6D,0x2F,0x73,0x73,0x63,0x61,0x2D,0x73,0x68,0x61,0x32,0x2D,0x67,0x35,
-    0x2E,0x63,0x72,0x6C,0x30,0x2F,0xA0,0x2D,0xA0,0x2B,0x86,0x29,0x68,0x74,0x74,0x70,
-    0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x34,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,
-    0x2E,0x63,0x6F,0x6D,0x2F,0x73,0x73,0x63,0x61,0x2D,0x73,0x68,0x61,0x32,0x2D,0x67,
-    0x35,0x2E,0x63,0x72,0x6C,0x30,0x4C,0x06,0x03,0x55,0x1D,0x20,0x04,0x45,0x30,0x43,
-    0x30,0x37,0x06,0x09,0x60,0x86,0x48,0x01,0x86,0xFD,0x6C,0x01,0x01,0x30,0x2A,0x30,
-    0x28,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1C,0x68,0x74,0x74,
-    0x70,0x73,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,
-    0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x08,0x06,0x06,0x67,0x81,0x0C,
-    0x01,0x02,0x03,0x30,0x7C,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,
-    0x70,0x30,0x6E,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,
-    0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x64,0x69,0x67,
-    0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x46,0x06,0x08,0x2B,0x06,0x01,
-    0x05,0x05,0x07,0x30,0x02,0x86,0x3A,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x61,
-    0x63,0x65,0x72,0x74,0x73,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,
-    0x6F,0x6D,0x2F,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x53,0x48,0x41,0x32,0x53,
-    0x65,0x63,0x75,0x72,0x65,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,
-    0x74,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
-    0x82,0x01,0x7E,0x06,0x0A,0x2B,0x06,0x01,0x04,0x01,0xD6,0x79,0x02,0x04,0x02,0x04,
-    0x82,0x01,0x6E,0x04,0x82,0x01,0x6A,0x01,0x68,0x00,0x75,0x00,0xA4,0xB9,0x09,0x90,
-    0xB4,0x18,0x58,0x14,0x87,0xBB,0x13,0xA2,0xCC,0x67,0x70,0x0A,0x3C,0x35,0x98,0x04,
-    0xF9,0x1B,0xDF,0xB8,0xE3,0x77,0xCD,0x0E,0xC8,0x0D,0xDC,0x10,0x00,0x00,0x01,0x56,
-    0xEC,0xA1,0x37,0xDA,0x00,0x00,0x04,0x03,0x00,0x46,0x30,0x44,0x02,0x20,0x3F,0x6C,
-    0xA8,0xF5,0xC4,0x7C,0x01,0x4C,0xC3,0x5A,0x28,0x27,0x50,0x47,0x63,0xD9,0xAC,0xE1,
-    0xBE,0x2D,0xBF,0x87,0x78,0xCB,0x3A,0x80,0x97,0x24,0x74,0xCD,0x16,0xF7,0x02,0x20,
-    0x71,0xFF,0x93,0xA2,0xB5,0x54,0x7E,0x7F,0x53,0x45,0x7F,0x59,0x5A,0x60,0x18,0x21,
-    0x5C,0xAB,0x7D,0x1F,0x08,0xB2,0x54,0xA0,0xB3,0xC4,0x88,0xA5,0x83,0xD2,0x63,0x55,
-    0x00,0x77,0x00,0x68,0xF6,0x98,0xF8,0x1F,0x64,0x82,0xBE,0x3A,0x8C,0xEE,0xB9,0x28,
-    0x1D,0x4C,0xFC,0x71,0x51,0x5D,0x67,0x93,0xD4,0x44,0xD1,0x0A,0x67,0xAC,0xBB,0x4F,
-    0x4F,0xFB,0xC4,0x00,0x00,0x01,0x56,0xEC,0xA1,0x37,0xA1,0x00,0x00,0x04,0x03,0x00,
-    0x48,0x30,0x46,0x02,0x21,0x00,0xFE,0x59,0x97,0x22,0x4C,0x6C,0x0F,0x39,0x05,0xD9,
-    0xE4,0xCA,0x7E,0x3B,0xD3,0xB3,0x47,0x1B,0x61,0x72,0xB6,0x3A,0x4F,0xD6,0xF2,0xA3,
-    0x57,0x49,0x48,0x4F,0x6A,0x6D,0x02,0x21,0x00,0x8F,0x14,0x1B,0x3C,0x1B,0x89,0xA3,
-    0x1D,0x70,0xEC,0xD4,0xD7,0x11,0xBC,0xF9,0x0B,0x3C,0x60,0xAC,0x8C,0x84,0x73,0x24,
-    0x6B,0x0E,0x37,0x6E,0x53,0x7F,0x9D,0x7F,0x34,0x00,0x76,0x00,0x56,0x14,0x06,0x9A,
-    0x2F,0xD7,0xC2,0xEC,0xD3,0xF5,0xE1,0xBD,0x44,0xB2,0x3E,0xC7,0x46,0x76,0xB9,0xBC,
-    0x99,0x11,0x5C,0xC0,0xEF,0x94,0x98,0x55,0xD6,0x89,0xD0,0xDD,0x00,0x00,0x01,0x56,
-    0xEC,0xA1,0x38,0x7F,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x0E,0xBF,
-    0x53,0x59,0x17,0x0C,0xEC,0x66,0x0C,0x5E,0x87,0xBB,0x8F,0x5F,0xB6,0x76,0x86,0xF2,
-    0x5C,0xFC,0xBC,0xA8,0xB9,0xC0,0xDF,0xBC,0x1A,0x3B,0xEE,0x11,0xF2,0xD0,0x02,0x21,
-    0x00,0x87,0x25,0x39,0xE4,0x32,0x99,0x48,0xCA,0x20,0x1B,0x13,0x96,0x1D,0xC3,0x2C,
-    0x98,0x6B,0x1B,0xC0,0xCC,0xE5,0x67,0x22,0xBD,0x92,0x14,0xE9,0x68,0xCD,0x95,0x82,
-    0x32,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
-    0x03,0x82,0x01,0x01,0x00,0x5A,0xA0,0x49,0x88,0xAD,0x60,0x1F,0x08,0x53,0x4C,0xD9,
-    0xB8,0xDC,0xF5,0x40,0x41,0xAD,0xEF,0xC8,0x7B,0x01,0x3B,0x13,0x70,0x44,0x99,0xF6,
-    0x5C,0x23,0x46,0xF7,0x3A,0xC8,0x7D,0xC9,0x21,0xAD,0x3A,0x49,0x45,0x82,0x1E,0x5D,
-    0x3B,0x1E,0x9B,0x6A,0x0A,0x3E,0x61,0x2D,0xF6,0xB1,0x99,0x74,0x2F,0x91,0xF9,0xD5,
-    0xF1,0x9F,0xAE,0x74,0x26,0x8B,0x3C,0xA7,0x8C,0xBE,0x28,0xFE,0xAC,0x3B,0x70,0xAE,
-    0x08,0x56,0x71,0xAC,0x55,0x7C,0x40,0x89,0x02,0x2D,0x61,0x2A,0xFD,0x54,0x72,0xBF,
-    0x1A,0x5C,0x70,0x19,0x90,0x15,0xA4,0x76,0xA0,0x7F,0x56,0x1C,0xC1,0xF0,0x8D,0x5E,
-    0x99,0x3D,0x83,0x41,0x54,0x68,0xE5,0x62,0xC1,0x5A,0xA2,0x64,0x8C,0x01,0x64,0x7A,
-    0x23,0xB9,0x3F,0xBF,0x22,0xCF,0x1F,0xC0,0x47,0x80,0x1F,0x94,0xD5,0xF2,0x30,0x84,
-    0xFB,0x07,0x02,0xFA,0x5B,0xA0,0xBA,0x09,0x04,0x98,0x4E,0xF3,0x25,0x56,0x4C,0xC4,
-    0x7E,0xE0,0x27,0xD8,0xE8,0x32,0x8F,0xB3,0x3C,0x5A,0x92,0x4B,0xC0,0x77,0x2D,0xB0,
-    0xE5,0xAE,0x1F,0xAF,0x1D,0x7F,0x21,0x9C,0x65,0x26,0xBE,0x0C,0xBA,0xE8,0x0D,0xC1,
-    0xD2,0x67,0xB4,0xB9,0x33,0xD1,0x4A,0xEE,0xFC,0xB8,0xAF,0x03,0x5B,0xC8,0x3E,0xBC,
-    0xFA,0x09,0x9D,0x04,0xCE,0x3E,0xA6,0xB5,0xC4,0x74,0x3B,0x31,0x7A,0xF3,0x2C,0x42,
-    0xB3,0xC7,0x73,0xDB,0xAA,0x75,0x2E,0x8D,0x8A,0x9E,0x79,0x33,0xBE,0xD7,0xB6,0x14,
-    0x9B,0x26,0xAB,0x7B,0x9E,0x14,0xB3,0x55,0xE6,0x4B,0xBB,0x86,0x94,0x11,0x74,0x02,
-    0x35,0xB4,0x52,0x70,0x9B,
-};
-
-/* subject:/C=US/O=DigiCert Inc/CN=DigiCert SHA2 Secure Server CA */
-/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */
-uint8_t _digiCertSha2SubCA[] ={
-    0x30,0x82,0x04,0x94,0x30,0x82,0x03,0x7C,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x01,
-    0xFD,0xA3,0xEB,0x6E,0xCA,0x75,0xC8,0x88,0x43,0x8B,0x72,0x4B,0xCF,0xBC,0x91,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x61,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,
-    0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,
-    0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65,
-    0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,
-    0x41,0x30,0x1E,0x17,0x0D,0x31,0x33,0x30,0x33,0x30,0x38,0x31,0x32,0x30,0x30,0x30,
-    0x30,0x5A,0x17,0x0D,0x32,0x33,0x30,0x33,0x30,0x38,0x31,0x32,0x30,0x30,0x30,0x30,
-    0x5A,0x30,0x4D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
-    0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,
-    0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,
-    0x13,0x1E,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x20,0x53,0x48,0x41,0x32,0x20,
-    0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,
-    0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
-    0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,
-    0x00,0xDC,0xAE,0x58,0x90,0x4D,0xC1,0xC4,0x30,0x15,0x90,0x35,0x5B,0x6E,0x3C,0x82,
-    0x15,0xF5,0x2C,0x5C,0xBD,0xE3,0xDB,0xFF,0x71,0x43,0xFA,0x64,0x25,0x80,0xD4,0xEE,
-    0x18,0xA2,0x4D,0xF0,0x66,0xD0,0x0A,0x73,0x6E,0x11,0x98,0x36,0x17,0x64,0xAF,0x37,
-    0x9D,0xFD,0xFA,0x41,0x84,0xAF,0xC7,0xAF,0x8C,0xFE,0x1A,0x73,0x4D,0xCF,0x33,0x97,
-    0x90,0xA2,0x96,0x87,0x53,0x83,0x2B,0xB9,0xA6,0x75,0x48,0x2D,0x1D,0x56,0x37,0x7B,
-    0xDA,0x31,0x32,0x1A,0xD7,0xAC,0xAB,0x06,0xF4,0xAA,0x5D,0x4B,0xB7,0x47,0x46,0xDD,
-    0x2A,0x93,0xC3,0x90,0x2E,0x79,0x80,0x80,0xEF,0x13,0x04,0x6A,0x14,0x3B,0xB5,0x9B,
-    0x92,0xBE,0xC2,0x07,0x65,0x4E,0xFC,0xDA,0xFC,0xFF,0x7A,0xAE,0xDC,0x5C,0x7E,0x55,
-    0x31,0x0C,0xE8,0x39,0x07,0xA4,0xD7,0xBE,0x2F,0xD3,0x0B,0x6A,0xD2,0xB1,0xDF,0x5F,
-    0xFE,0x57,0x74,0x53,0x3B,0x35,0x80,0xDD,0xAE,0x8E,0x44,0x98,0xB3,0x9F,0x0E,0xD3,
-    0xDA,0xE0,0xD7,0xF4,0x6B,0x29,0xAB,0x44,0xA7,0x4B,0x58,0x84,0x6D,0x92,0x4B,0x81,
-    0xC3,0xDA,0x73,0x8B,0x12,0x97,0x48,0x90,0x04,0x45,0x75,0x1A,0xDD,0x37,0x31,0x97,
-    0x92,0xE8,0xCD,0x54,0x0D,0x3B,0xE4,0xC1,0x3F,0x39,0x5E,0x2E,0xB8,0xF3,0x5C,0x7E,
-    0x10,0x8E,0x86,0x41,0x00,0x8D,0x45,0x66,0x47,0xB0,0xA1,0x65,0xCE,0xA0,0xAA,0x29,
-    0x09,0x4E,0xF3,0x97,0xEB,0xE8,0x2E,0xAB,0x0F,0x72,0xA7,0x30,0x0E,0xFA,0xC7,0xF4,
-    0xFD,0x14,0x77,0xC3,0xA4,0x5B,0x28,0x57,0xC2,0xB3,0xF9,0x82,0xFD,0xB7,0x45,0x58,
-    0x9B,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x5A,0x30,0x82,0x01,0x56,0x30,0x12,
-    0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,
-    0x01,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,
-    0x01,0x86,0x30,0x34,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x28,
-    0x30,0x26,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,
-    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x64,0x69,0x67,0x69,
-    0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x30,0x7B,0x06,0x03,0x55,0x1D,0x1F,0x04,
-    0x74,0x30,0x72,0x30,0x37,0xA0,0x35,0xA0,0x33,0x86,0x31,0x68,0x74,0x74,0x70,0x3A,
-    0x2F,0x2F,0x63,0x72,0x6C,0x33,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,
-    0x63,0x6F,0x6D,0x2F,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,0x47,0x6C,0x6F,0x62,
-    0x61,0x6C,0x52,0x6F,0x6F,0x74,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x37,0xA0,0x35,
-    0xA0,0x33,0x86,0x31,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x34,0x2E,
-    0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x44,0x69,0x67,
-    0x69,0x43,0x65,0x72,0x74,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x52,0x6F,0x6F,0x74,0x43,
-    0x41,0x2E,0x63,0x72,0x6C,0x30,0x3D,0x06,0x03,0x55,0x1D,0x20,0x04,0x36,0x30,0x34,
-    0x30,0x32,0x06,0x04,0x55,0x1D,0x20,0x00,0x30,0x2A,0x30,0x28,0x06,0x08,0x2B,0x06,
-    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1C,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,
-    0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,
-    0x2F,0x43,0x50,0x53,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0F,
-    0x80,0x61,0x1C,0x82,0x31,0x61,0xD5,0x2F,0x28,0xE7,0x8D,0x46,0x38,0xB4,0x2C,0xE1,
-    0xC6,0xD9,0xE2,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
-    0x03,0xDE,0x50,0x35,0x56,0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,
-    0xB2,0x3D,0xD1,0x55,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
-    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x23,0x3E,0xDF,0x4B,0xD2,0x31,0x42,0xA5,
-    0xB6,0x7E,0x42,0x5C,0x1A,0x44,0xCC,0x69,0xD1,0x68,0xB4,0x5D,0x4B,0xE0,0x04,0x21,
-    0x6C,0x4B,0xE2,0x6D,0xCC,0xB1,0xE0,0x97,0x8F,0xA6,0x53,0x09,0xCD,0xAA,0x2A,0x65,
-    0xE5,0x39,0x4F,0x1E,0x83,0xA5,0x6E,0x5C,0x98,0xA2,0x24,0x26,0xE6,0xFB,0xA1,0xED,
-    0x93,0xC7,0x2E,0x02,0xC6,0x4D,0x4A,0xBF,0xB0,0x42,0xDF,0x78,0xDA,0xB3,0xA8,0xF9,
-    0x6D,0xFF,0x21,0x85,0x53,0x36,0x60,0x4C,0x76,0xCE,0xEC,0x38,0xDC,0xD6,0x51,0x80,
-    0xF0,0xC5,0xD6,0xE5,0xD4,0x4D,0x27,0x64,0xAB,0x9B,0xC7,0x3E,0x71,0xFB,0x48,0x97,
-    0xB8,0x33,0x6D,0xC9,0x13,0x07,0xEE,0x96,0xA2,0x1B,0x18,0x15,0xF6,0x5C,0x4C,0x40,
-    0xED,0xB3,0xC2,0xEC,0xFF,0x71,0xC1,0xE3,0x47,0xFF,0xD4,0xB9,0x00,0xB4,0x37,0x42,
-    0xDA,0x20,0xC9,0xEA,0x6E,0x8A,0xEE,0x14,0x06,0xAE,0x7D,0xA2,0x59,0x98,0x88,0xA8,
-    0x1B,0x6F,0x2D,0xF4,0xF2,0xC9,0x14,0x5F,0x26,0xCF,0x2C,0x8D,0x7E,0xED,0x37,0xC0,
-    0xA9,0xD5,0x39,0xB9,0x82,0xBF,0x19,0x0C,0xEA,0x34,0xAF,0x00,0x21,0x68,0xF8,0xAD,
-    0x73,0xE2,0xC9,0x32,0xDA,0x38,0x25,0x0B,0x55,0xD3,0x9A,0x1D,0xF0,0x68,0x86,0xED,
-    0x2E,0x41,0x34,0xEF,0x7C,0xA5,0x50,0x1D,0xBF,0x3A,0xF9,0xD3,0xC1,0x08,0x0C,0xE6,
-    0xED,0x1E,0x8A,0x58,0x25,0xE4,0xB8,0x77,0xAD,0x2D,0x6E,0xF5,0x52,0xDD,0xB4,0x74,
-    0x8F,0xAB,0x49,0x2E,0x9D,0x3B,0x93,0x34,0x28,0x1F,0x78,0xCE,0x94,0xEA,0xC7,0xBD,
-    0xD3,0xC9,0x6D,0x1C,0xDE,0x5C,0x32,0xF3,
-};
-
-/* subject:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */
-/* issuer :/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert Global Root CA */
-uint8_t _digiCertGlobalRoot[] ={
-    0x30,0x82,0x03,0xAF,0x30,0x82,0x02,0x97,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x08,
-    0x3B,0xE0,0x56,0x90,0x42,0x46,0xB1,0xA1,0x75,0x6A,0xC9,0x59,0x91,0xC7,0x4A,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x61,
-    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x15,0x30,
-    0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,0x65,0x72,0x74,
-    0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,0x13,0x10,0x77,
-    0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x31,
-    0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,0x69,0x43,0x65,
-    0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,
-    0x41,0x30,0x1E,0x17,0x0D,0x30,0x36,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,
-    0x30,0x5A,0x17,0x0D,0x33,0x31,0x31,0x31,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
-    0x5A,0x30,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
-    0x31,0x15,0x30,0x13,0x06,0x03,0x55,0x04,0x0A,0x13,0x0C,0x44,0x69,0x67,0x69,0x43,
-    0x65,0x72,0x74,0x20,0x49,0x6E,0x63,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x0B,
-    0x13,0x10,0x77,0x77,0x77,0x2E,0x64,0x69,0x67,0x69,0x63,0x65,0x72,0x74,0x2E,0x63,
-    0x6F,0x6D,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x13,0x17,0x44,0x69,0x67,
-    0x69,0x43,0x65,0x72,0x74,0x20,0x47,0x6C,0x6F,0x62,0x61,0x6C,0x20,0x52,0x6F,0x6F,
-    0x74,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,
-    0x02,0x82,0x01,0x01,0x00,0xE2,0x3B,0xE1,0x11,0x72,0xDE,0xA8,0xA4,0xD3,0xA3,0x57,
-    0xAA,0x50,0xA2,0x8F,0x0B,0x77,0x90,0xC9,0xA2,0xA5,0xEE,0x12,0xCE,0x96,0x5B,0x01,
-    0x09,0x20,0xCC,0x01,0x93,0xA7,0x4E,0x30,0xB7,0x53,0xF7,0x43,0xC4,0x69,0x00,0x57,
-    0x9D,0xE2,0x8D,0x22,0xDD,0x87,0x06,0x40,0x00,0x81,0x09,0xCE,0xCE,0x1B,0x83,0xBF,
-    0xDF,0xCD,0x3B,0x71,0x46,0xE2,0xD6,0x66,0xC7,0x05,0xB3,0x76,0x27,0x16,0x8F,0x7B,
-    0x9E,0x1E,0x95,0x7D,0xEE,0xB7,0x48,0xA3,0x08,0xDA,0xD6,0xAF,0x7A,0x0C,0x39,0x06,
-    0x65,0x7F,0x4A,0x5D,0x1F,0xBC,0x17,0xF8,0xAB,0xBE,0xEE,0x28,0xD7,0x74,0x7F,0x7A,
-    0x78,0x99,0x59,0x85,0x68,0x6E,0x5C,0x23,0x32,0x4B,0xBF,0x4E,0xC0,0xE8,0x5A,0x6D,
-    0xE3,0x70,0xBF,0x77,0x10,0xBF,0xFC,0x01,0xF6,0x85,0xD9,0xA8,0x44,0x10,0x58,0x32,
-    0xA9,0x75,0x18,0xD5,0xD1,0xA2,0xBE,0x47,0xE2,0x27,0x6A,0xF4,0x9A,0x33,0xF8,0x49,
-    0x08,0x60,0x8B,0xD4,0x5F,0xB4,0x3A,0x84,0xBF,0xA1,0xAA,0x4A,0x4C,0x7D,0x3E,0xCF,
-    0x4F,0x5F,0x6C,0x76,0x5E,0xA0,0x4B,0x37,0x91,0x9E,0xDC,0x22,0xE6,0x6D,0xCE,0x14,
-    0x1A,0x8E,0x6A,0xCB,0xFE,0xCD,0xB3,0x14,0x64,0x17,0xC7,0x5B,0x29,0x9E,0x32,0xBF,
-    0xF2,0xEE,0xFA,0xD3,0x0B,0x42,0xD4,0xAB,0xB7,0x41,0x32,0xDA,0x0C,0xD4,0xEF,0xF8,
-    0x81,0xD5,0xBB,0x8D,0x58,0x3F,0xB5,0x1B,0xE8,0x49,0x28,0xA2,0x70,0xDA,0x31,0x04,
-    0xDD,0xF7,0xB2,0x16,0xF2,0x4C,0x0A,0x4E,0x07,0xA8,0xED,0x4A,0x3D,0x5E,0xB5,0x7F,
-    0xA3,0x90,0xC3,0xAF,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,0x30,0x0E,
-    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x86,0x30,0x0F,
-    0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,
-    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x03,0xDE,0x50,0x35,0x56,0xD1,
-    0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,0x1F,
-    0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x03,0xDE,0x50,0x35,0x56,
-    0xD1,0x4C,0xBB,0x66,0xF0,0xA3,0xE2,0x1B,0x1B,0xC3,0x97,0xB2,0x3D,0xD1,0x55,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,
-    0x01,0x01,0x00,0xCB,0x9C,0x37,0xAA,0x48,0x13,0x12,0x0A,0xFA,0xDD,0x44,0x9C,0x4F,
-    0x52,0xB0,0xF4,0xDF,0xAE,0x04,0xF5,0x79,0x79,0x08,0xA3,0x24,0x18,0xFC,0x4B,0x2B,
-    0x84,0xC0,0x2D,0xB9,0xD5,0xC7,0xFE,0xF4,0xC1,0x1F,0x58,0xCB,0xB8,0x6D,0x9C,0x7A,
-    0x74,0xE7,0x98,0x29,0xAB,0x11,0xB5,0xE3,0x70,0xA0,0xA1,0xCD,0x4C,0x88,0x99,0x93,
-    0x8C,0x91,0x70,0xE2,0xAB,0x0F,0x1C,0xBE,0x93,0xA9,0xFF,0x63,0xD5,0xE4,0x07,0x60,
-    0xD3,0xA3,0xBF,0x9D,0x5B,0x09,0xF1,0xD5,0x8E,0xE3,0x53,0xF4,0x8E,0x63,0xFA,0x3F,
-    0xA7,0xDB,0xB4,0x66,0xDF,0x62,0x66,0xD6,0xD1,0x6E,0x41,0x8D,0xF2,0x2D,0xB5,0xEA,
-    0x77,0x4A,0x9F,0x9D,0x58,0xE2,0x2B,0x59,0xC0,0x40,0x23,0xED,0x2D,0x28,0x82,0x45,
-    0x3E,0x79,0x54,0x92,0x26,0x98,0xE0,0x80,0x48,0xA8,0x37,0xEF,0xF0,0xD6,0x79,0x60,
-    0x16,0xDE,0xAC,0xE8,0x0E,0xCD,0x6E,0xAC,0x44,0x17,0x38,0x2F,0x49,0xDA,0xE1,0x45,
-    0x3E,0x2A,0xB9,0x36,0x53,0xCF,0x3A,0x50,0x06,0xF7,0x2E,0xE8,0xC4,0x57,0x49,0x6C,
-    0x61,0x21,0x18,0xD5,0x04,0xAD,0x78,0x3C,0x2C,0x3A,0x80,0x6B,0xA7,0xEB,0xAF,0x15,
-    0x14,0xE9,0xD8,0x89,0xC1,0xB9,0x38,0x6C,0xE2,0x91,0x6C,0x8A,0xFF,0x64,0xB9,0x77,
-    0x25,0x57,0x30,0xC0,0x1B,0x24,0xA3,0xE1,0xDC,0xE9,0xDF,0x47,0x7C,0xB5,0xB4,0x24,
-    0x08,0x05,0x30,0xEC,0x2D,0xBD,0x0B,0xBF,0x45,0xBF,0x50,0xB9,0xA9,0xF3,0xEB,0x98,
-    0x01,0x12,0xAD,0xC8,0x88,0xC6,0x98,0x34,0x5F,0x8D,0x0A,0x3C,0xC6,0xE9,0xD5,0x95,
-    0x95,0x6D,0xDE,
-};
-
-uint8_t _digicertOCSPResponse[] = {
-    0x30,0x82,0x01,0xe6,0x0a,0x01,0x00,0xa0,0x82,0x01,0xdf,0x30,0x82,0x01,0xdb,0x06,0x09,0x2b,0x06,0x01,
-    0x05,0x05,0x07,0x30,0x01,0x01,0x04,0x82,0x01,0xcc,0x30,0x82,0x01,0xc8,0x30,0x81,0xb1,0xa2,0x16,0x04,
-    0x14,0x0f,0x80,0x61,0x1c,0x82,0x31,0x61,0xd5,0x2f,0x28,0xe7,0x8d,0x46,0x38,0xb4,0x2c,0xe1,0xc6,0xd9,
-    0xe2,0x18,0x0f,0x32,0x30,0x31,0x38,0x30,0x34,0x32,0x35,0x31,0x37,0x34,0x37,0x34,0x33,0x5a,0x30,0x81,
-    0x85,0x30,0x81,0x82,0x30,0x49,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14,0x10,
-    0x5f,0xa6,0x7a,0x80,0x08,0x9d,0xb5,0x27,0x9f,0x35,0xce,0x83,0x0b,0x43,0x88,0x9e,0xa3,0xc7,0x0d,0x04,
-    0x14,0x0f,0x80,0x61,0x1c,0x82,0x31,0x61,0xd5,0x2f,0x28,0xe7,0x8d,0x46,0x38,0xb4,0x2c,0xe1,0xc6,0xd9,
-    0xe2,0x02,0x10,0x01,0xaf,0x1e,0xfb,0xdd,0x5e,0xae,0x09,0x52,0x32,0x0b,0x24,0xfe,0x6b,0x55,0x68,0xa1,
-    0x11,0x18,0x0f,0x32,0x30,0x31,0x36,0x30,0x39,0x30,0x32,0x32,0x31,0x32,0x38,0x34,0x38,0x5a,0x18,0x0f,
-    0x32,0x30,0x31,0x38,0x30,0x34,0x32,0x35,0x31,0x37,0x34,0x37,0x34,0x33,0x5a,0xa0,0x11,0x18,0x0f,0x32,
-    0x30,0x31,0x38,0x30,0x35,0x30,0x32,0x31,0x37,0x30,0x32,0x34,0x33,0x5a,0x30,0x0d,0x06,0x09,0x2a,0x86,
-    0x48,0x86,0xf7,0x0d,0x01,0x01,0x0b,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x9c,0x3d,0xb9,0xc6,0xfd,0x97,
-    0x21,0xb0,0x04,0xc1,0x62,0x4b,0xc7,0x74,0x7a,0x37,0x01,0xa6,0x22,0xb2,0xd2,0xce,0xbb,0xd4,0x67,0xcd,
-    0xda,0x66,0xb6,0x53,0xbc,0x81,0xd4,0x09,0x9c,0xa0,0x3e,0x95,0x6d,0x90,0x0a,0xe6,0x39,0x24,0xb0,0x42,
-    0x17,0xc1,0x02,0x62,0x57,0xc8,0x04,0x07,0x66,0x1f,0xc4,0x75,0x75,0xe6,0x82,0x7e,0xd3,0x28,0x46,0xde,
-    0xaa,0xb8,0xd7,0x2d,0xd5,0x17,0x70,0xb7,0xbf,0xd6,0xcc,0xa3,0x14,0xe9,0x5f,0x9d,0x40,0xf2,0x5f,0x29,
-    0xb2,0xde,0x8a,0x9f,0x02,0x79,0x2a,0xe9,0xa0,0xc0,0x0f,0xb1,0xc3,0xf8,0xaa,0xb1,0x9d,0xaf,0x15,0x78,
-    0xf1,0x98,0x6c,0xd2,0xf2,0x1f,0x8d,0x75,0xd4,0xb6,0x91,0xc4,0xb8,0x13,0x18,0xd2,0x30,0xa1,0xb1,0x1e,
-    0x81,0x1a,0xef,0x2a,0x42,0x52,0x2a,0xd4,0xec,0xc5,0x8a,0x87,0x9c,0x7b,0x38,0x81,0xf9,0x6e,0xfe,0x60,
-    0x3d,0xc7,0xfe,0x77,0x64,0x99,0x3d,0x1c,0xf5,0x92,0xe9,0xe5,0x45,0xf3,0x7e,0x98,0x74,0xfa,0x5a,0xd9,
-    0xf4,0x79,0xf3,0xf7,0x6c,0x99,0xce,0x52,0x47,0xc0,0x4a,0x87,0x20,0xed,0x3b,0x76,0x2a,0x58,0x3f,0x8b,
-    0xb3,0xcb,0x9f,0xd4,0x11,0x26,0xc4,0x43,0xce,0xd1,0x6f,0x48,0xe4,0xd0,0x2f,0xa1,0x95,0x5a,0xb9,0x93,
-    0x25,0xf9,0xd4,0x1a,0xe9,0x75,0x7d,0xcf,0xfb,0xc5,0xa5,0x78,0x98,0x68,0xfb,0x12,0xbd,0x53,0xdc,0x98,
-    0x1d,0xd6,0xc7,0xa1,0x28,0x3f,0x5b,0x82,0x39,0x18,0x85,0xfd,0x91,0x8f,0x80,0xa2,0x30,0xd9,0xee,0xc4,
-    0x23,0x48,0x3c,0x50,0x18,0x7e,0xc7,0x1d,0xc1,0x5a
-};
-
-uint8_t _caissuer_https[] = {
-    0x30,0x82,0x04,0x68,0x30,0x82,0x03,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x7A,
-    0x22,0xA1,0x88,0x18,0x9E,0x75,0x77,0xE6,0xEF,0x7E,0xC0,0x33,0x8E,0xE8,0x90,0xE8,
-    0x7B,0xC4,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
-    0x00,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
-    0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,
-    0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,
-    0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,
-    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
-    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
-    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x15,
-    0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x0C,0x0C,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,
-    0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x38,0x30,0x34,0x32,0x38,0x32,
-    0x30,0x32,0x31,0x34,0x31,0x5A,0x17,0x0D,0x31,0x39,0x30,0x34,0x32,0x38,0x32,0x30,
-    0x32,0x31,0x34,0x31,0x5A,0x30,0x81,0x8D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
-    0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,
-    0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,
-    0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,
-    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
-    0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,
-    0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,
-    0x6E,0x67,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,0x48,0x54,0x54,
-    0x50,0x53,0x20,0x43,0x41,0x49,0x73,0x73,0x75,0x65,0x72,0x20,0x54,0x65,0x73,0x74,
-    0x20,0x43,0x65,0x72,0x74,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,0xC1,0x68,0xC2,0x47,0x1E,0x07,0x82,0x66,0x47,0xC9,
-    0x5C,0x22,0xDD,0x8B,0x93,0x6A,0xA7,0x22,0x00,0xB8,0xDA,0x8C,0x3C,0x52,0xA7,0x47,
-    0x73,0xBB,0x7A,0xD7,0x8C,0x1E,0xAE,0xDA,0x34,0x25,0x4E,0xEB,0x1F,0x33,0x0B,0x8A,
-    0xC7,0x6D,0x2A,0x93,0xDB,0x0D,0xD0,0x47,0x85,0x9C,0x14,0xD5,0x23,0xE3,0xE4,0x94,
-    0xE0,0x17,0x9F,0x56,0x64,0x8E,0xE0,0x08,0xE9,0x1B,0x4C,0x7C,0x77,0xF9,0x35,0x74,
-    0x52,0x43,0x90,0x13,0xFA,0x51,0x9A,0xA2,0x93,0x47,0x94,0xE7,0xBD,0x07,0xE5,0xFB,
-    0x67,0x8B,0xF0,0xE2,0x0C,0x97,0xFD,0x29,0x51,0xBD,0x85,0x6C,0xBE,0x36,0xFD,0xDD,
-    0xCC,0x99,0x4D,0x68,0x37,0x96,0xB2,0x20,0x85,0x55,0xA5,0x99,0xA4,0x7E,0xD7,0x19,
-    0x06,0x15,0x20,0x10,0x50,0x51,0x2E,0x74,0x5C,0x43,0x49,0x94,0x6B,0x0E,0x9E,0xFB,
-    0xDF,0xB2,0xEB,0xD9,0x28,0xA8,0xF1,0x25,0x49,0xC8,0xFE,0x3B,0xE1,0x45,0x95,0x47,
-    0xD1,0x53,0xCD,0x34,0x9A,0x6F,0xC4,0x3F,0x63,0xC2,0x60,0xC6,0x40,0xBB,0xF7,0x20,
-    0x8A,0xB8,0xB7,0xD7,0xC2,0xBB,0x48,0x24,0x64,0xA2,0x4A,0xE4,0x2A,0x17,0x68,0xE2,
-    0xAC,0x47,0x2D,0xCC,0xBD,0xB7,0xCE,0x73,0xDF,0x96,0x8C,0x12,0x56,0xE3,0x29,0xE3,
-    0x4D,0xB4,0x55,0x28,0xAB,0x28,0x24,0x45,0x7F,0x55,0x66,0xCD,0x46,0x29,0x89,0x58,
-    0xFF,0xA6,0xD1,0x67,0xAC,0x50,0xEE,0x55,0x6D,0x6A,0x2A,0xCF,0xD6,0x09,0xE9,0xDA,
-    0x22,0xB0,0xAF,0x90,0xD7,0x02,0xB2,0xCE,0x5F,0x09,0x96,0x5E,0x88,0xAE,0xB5,0xB6,
-    0xA1,0xC3,0x9D,0x1A,0x2F,0x2D,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xCA,0x30,0x81,
-    0xC7,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
-    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,0x80,0x30,
-    0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x03,0x01,0x30,0x16,0x06,0x03,0x55,0x1D,0x11,0x04,0x0F,0x30,0x0D,0x82,
-    0x0B,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,
-    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xDF,0xC7,0x68,0x26,0x64,0x95,0x5D,0x73,0x36,
-    0x84,0xE8,0xE3,0x1D,0xC8,0x28,0x5E,0xA8,0x27,0x73,0x8C,0x30,0x1F,0x06,0x03,0x55,
-    0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xB5,0xA9,0x53,0x08,0x10,0x38,0x1A,0xA5,
-    0xB3,0x84,0xC9,0xEE,0xC4,0xAB,0x0F,0xB8,0x5F,0x68,0x10,0xA2,0x30,0x3A,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x2E,0x30,0x2C,0x30,0x2A,0x06,0x08,
-    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x1E,0x68,0x74,0x74,0x70,0x73,0x3A,
-    0x2F,0x2F,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x74,0x65,
-    0x73,0x74,0x43,0x41,0x2E,0x64,0x65,0x72,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC4,0x48,0xDF,0x5E,
-    0x73,0xD1,0x43,0x28,0x7D,0x69,0x71,0x32,0x1F,0xCC,0x1A,0xEB,0x5B,0x98,0x9D,0xCE,
-    0xFF,0xCA,0x16,0xA9,0x96,0xE7,0x4D,0xC4,0xAE,0x53,0xE2,0x5D,0xDB,0xDA,0x40,0x80,
-    0xE5,0xFB,0xF3,0xD7,0x21,0x9A,0x77,0x1D,0x67,0xFC,0x04,0x62,0x18,0xFF,0x10,0x59,
-    0xF4,0xDD,0xF4,0xC6,0x8F,0xB4,0xEF,0x9F,0x05,0xA6,0xF1,0xCB,0x44,0x24,0x02,0x19,
-    0x75,0xF9,0x3C,0x28,0x8A,0xAA,0x57,0x6B,0xFF,0x64,0xFF,0xD7,0xE2,0x62,0x67,0x70,
-    0x20,0x4D,0xAE,0xD2,0x67,0xED,0x92,0xA4,0xFA,0x8A,0xC3,0x24,0x9C,0x2F,0x4D,0x2C,
-    0xA9,0xA5,0x92,0x5E,0x5C,0x6F,0xDB,0xAB,0x96,0xA6,0xB1,0x5B,0xF1,0x8D,0x97,0x08,
-    0xBC,0x5B,0x27,0xD5,0x9E,0x2D,0xF0,0x49,0x68,0xA6,0x92,0x00,0x13,0xAD,0x60,0x9E,
-    0x78,0x72,0xC2,0x18,0xB8,0xE5,0x9D,0x72,0xA5,0x87,0x61,0xA8,0x95,0x8A,0x2B,0xB2,
-    0xCC,0xCA,0x7F,0x1E,0x1E,0xC5,0xFB,0x5A,0x0C,0x77,0x17,0xB0,0xBE,0x7B,0x5A,0x50,
-    0x05,0x32,0x40,0x98,0x3A,0x8B,0x22,0x3F,0x3B,0xA5,0xA8,0xA9,0x59,0x3B,0x55,0x92,
-    0xD1,0x8A,0x34,0x73,0xA6,0xD6,0x5D,0x5E,0x85,0x59,0x00,0xD5,0x55,0x94,0x80,0xC1,
-    0xB9,0xF1,0xCA,0x2B,0xC5,0x96,0xEE,0x49,0x6A,0x2C,0xDD,0x62,0x98,0xB3,0x74,0x09,
-    0x09,0xDE,0x3D,0x59,0x5B,0x21,0x76,0x6E,0x27,0x66,0xED,0x7B,0x74,0x7F,0xE7,0xA9,
-    0xAE,0xEB,0x40,0x83,0xB9,0xBC,0xE6,0x0C,0x1E,0x53,0xB2,0xEA,0x79,0xC4,0xA9,0x30,
-    0x2B,0x1F,0xC4,0x34,0x82,0x3E,0xFC,0x1E,0x2D,0x66,0x75,0xD0,
-};
-
-#endif /* _SECURITY_SI_23_SECTRUST_OCSP_H_ */
index 5b4fe130e9f310d3b1ac80ca37f2139860a84079..dd4c0c19aaf028b96ad5231ba564ad7d2907d5bb 100644 (file)
@@ -151,7 +151,7 @@ static void tests(void)
                "trust is kSecTrustResultUnspecified");
     is(SecTrustGetCertificateCount(trust), 2, "cert count is 2");
        SecKeyRef pub_key_leaf;
-       isnt(pub_key_leaf = SecTrustCopyPublicKey(trust), NULL, "get leaf pub key");
+       isnt(pub_key_leaf = SecTrustCopyKey(trust), NULL, "get leaf pub key");
     if (!pub_key_leaf) { goto errOut; }
     CFErrorRef error = NULL;
     ok(SecKeyVerifySignature(pub_key_leaf, kSecKeyAlgorithmRSASignatureDigestPKCS1v15SHA1, sha1Data, signature, &error),
index 9119beb26d617551121687f06859c3647d02706b..8a1a2856d1f8ba1ba12e42904f1fec32af75e745 100644 (file)
@@ -365,7 +365,7 @@ static void print_cert(SecCertificateRef cert, bool verbose) {
     }
 
     print_plist(plist);
-    CFRelease(plist);
+    CFReleaseNull(plist);
 }
 
 static void tests(void)
@@ -412,12 +412,7 @@ static void tests(void)
     properties = SecCertificateCopyProperties(leaf);
     isnt(properties, NULL, "leaf properties returned");
     CFReleaseNull(properties);
-    // Xcode doesn't have a SDK for 10.15.1 so we need to work around this.
-    // rdar://problem/55890533
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
     properties = SecCertificateCopyLocalizedProperties(leaf, true);
-#pragma clang diagnostic pop
     isnt(properties, NULL, "localized leaf properties returned");
     CFReleaseNull(properties);
 
diff --git a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.h
deleted file mode 100644 (file)
index e379eb3..0000000
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- * Copyright (c) 2016 Apple Inc. All Rights Reserved.
- */
-
-#ifndef si_28_sectrustsettings_h
-#define si_28_sectrustsettings_h
-
-/* subject:/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
-/* issuer :/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
-unsigned char _trustSettingsRoot[1008]={
-    0x30,0x82,0x03,0xEC,0x30,0x82,0x02,0xD4,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
-    0xEE,0xAD,0xE6,0x5E,0x2C,0x5C,0x7C,0x40,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x91,0x31,0x0B,0x30,0x09,0x06,0x03,
-    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
-    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
-    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
-    0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,
-    0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
-    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
-    0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,
-    0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,
-    0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,
-    0x36,0x30,0x33,0x31,0x39,0x32,0x33,0x33,0x30,0x34,0x34,0x5A,0x17,0x0D,0x32,0x36,
-    0x30,0x33,0x31,0x37,0x32,0x33,0x33,0x30,0x34,0x34,0x5A,0x30,0x81,0x91,0x31,0x0B,
-    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,
-    0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,
-    0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,
-    0x74,0x69,0x6E,0x6F,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,
-    0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,
-    0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,
-    0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,
-    0x04,0x03,0x0C,0x1B,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,
-    0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,
-    0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,
-    0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,
-    0xC6,0xB5,0x94,0x9F,0x10,0xC7,0x49,0x4F,0xAF,0xA5,0xE4,0x98,0xEE,0xEB,0x9C,0x39,
-    0xCA,0xF0,0x47,0x54,0xCA,0x26,0x4A,0xDD,0x6E,0x1E,0x33,0x4F,0x5E,0xF5,0x9F,0x4A,
-    0x41,0x3F,0xC3,0xCF,0xEB,0x30,0x51,0xD8,0x85,0xAB,0xD6,0xDD,0x45,0xBF,0x0D,0x67,
-    0x0D,0xDA,0x88,0x07,0xD8,0xB2,0x6D,0x6C,0x56,0xEE,0x27,0x74,0xDE,0x81,0xAC,0x35,
-    0x9F,0xBC,0x9E,0x4A,0x97,0x0E,0xB4,0x84,0xA4,0xFA,0x24,0x21,0xBE,0x74,0x40,0xB4,
-    0x9E,0xFC,0x81,0x9B,0xE6,0x82,0xB8,0xB6,0xAD,0x33,0x88,0xEC,0x30,0x5B,0x88,0x56,
-    0x7E,0x3D,0x03,0x7A,0xC7,0xC2,0x58,0xF9,0x7C,0x68,0x77,0x75,0x8B,0x59,0x82,0x28,
-    0xFC,0x0B,0x69,0x25,0x61,0x1E,0xCA,0x1F,0x7C,0x4D,0x3E,0x74,0xE5,0xE1,0xA0,0xDD,
-    0xB3,0xD8,0xBD,0x11,0x4A,0x57,0xB9,0xAA,0xB3,0x92,0x53,0x9C,0x2A,0xE5,0x91,0xD8,
-    0x57,0xCC,0xAD,0xB9,0x7F,0x4B,0x94,0x0F,0xCD,0xE0,0xEF,0xF7,0xE9,0x2A,0xE4,0x90,
-    0xEF,0xA2,0x69,0x53,0x46,0x68,0x5D,0x39,0xD5,0x08,0x24,0x33,0x3D,0x81,0xF5,0x34,
-    0xCD,0x06,0xC4,0xDB,0xC7,0x59,0xF9,0x9C,0xD9,0x00,0xD1,0x33,0x8F,0xE5,0x9D,0xF5,
-    0x7A,0xD0,0x91,0x3A,0x1F,0xE2,0x5C,0x24,0xB4,0xFD,0xF1,0x86,0x04,0x66,0x10,0xEC,
-    0x8F,0xB5,0x50,0xEF,0xBC,0x13,0xC2,0x32,0x52,0xFD,0x55,0x8D,0x9A,0x3E,0xB1,0xA0,
-    0x94,0x02,0x96,0xF4,0x64,0xE3,0x23,0x4F,0x18,0x19,0xAF,0x82,0xD0,0x25,0xA2,0x8C,
-    0x76,0x6B,0xDA,0xBA,0xF9,0xE8,0x0D,0xBA,0x32,0x74,0xF1,0x2F,0xB9,0xE3,0xD2,0x93,
-    0x02,0x03,0x01,0x00,0x01,0xA3,0x45,0x30,0x43,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
-    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,
-    0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,
-    0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x31,0x64,0x1E,0x5C,0x68,0x6A,0x83,
-    0xBD,0x39,0x22,0x44,0xF6,0xD3,0x6C,0x70,0xF7,0xDD,0x22,0x53,0x30,0x0D,0x06,0x09,
-    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
-    0x01,0xDF,0xE1,0x02,0xED,0x2A,0x55,0xC3,0xFF,0x9A,0xD7,0x43,0xCF,0xD9,0x5F,0x3C,
-    0xD5,0xAF,0xB1,0xEF,0x1F,0xF1,0x15,0x88,0x17,0x37,0x69,0x25,0xC1,0x42,0xFC,0xE3,
-    0x18,0xBC,0x02,0x6A,0x0B,0xAD,0xDB,0x49,0xE0,0xCB,0xBE,0x84,0xC0,0xF8,0x26,0xD0,
-    0xA6,0x4C,0xCB,0x3D,0xF4,0x52,0xBA,0xF2,0x3B,0x2C,0x3F,0xD6,0x46,0xAA,0xC8,0xE7,
-    0xE5,0x4A,0x41,0x7D,0xCA,0xC3,0x3A,0xEF,0xD0,0xFF,0xA2,0x1A,0x07,0x4E,0x18,0x70,
-    0xC6,0xBD,0xA2,0x37,0xD9,0x72,0xFB,0x95,0xC9,0x0A,0x4E,0x39,0x0D,0x67,0x45,0xF2,
-    0x92,0x34,0x2E,0x94,0x02,0x51,0x97,0x96,0x82,0x75,0x1C,0x7D,0x14,0x40,0x15,0x38,
-    0xB5,0x4D,0x17,0xBE,0xCE,0xDB,0x54,0x12,0x68,0xF6,0xCE,0xFA,0xE0,0x73,0xD3,0x3B,
-    0x7B,0x01,0xDC,0x43,0x17,0x46,0x00,0x2F,0x82,0x1F,0x4D,0x09,0x78,0x22,0x84,0x76,
-    0x2B,0xB6,0xA4,0xA8,0x87,0xC3,0x3F,0x13,0x4D,0x99,0xEF,0x23,0x52,0x92,0xCE,0x65,
-    0x1C,0x00,0x4A,0xCC,0xEE,0x3B,0x73,0xEB,0x52,0x86,0xA3,0xBC,0x22,0xAF,0xE2,0x88,
-    0x5A,0xED,0x34,0x51,0xC4,0x67,0x9F,0xA2,0x7E,0x4B,0xCC,0x65,0xFC,0xD6,0x38,0x42,
-    0x5A,0x24,0xB8,0x02,0x6F,0x99,0xA0,0xF7,0x38,0x86,0x8A,0x02,0xCD,0x28,0x9B,0xEA,
-    0xD9,0xA0,0x24,0x57,0x1E,0x40,0x02,0x89,0x29,0x4C,0x3F,0xF5,0xEF,0x8F,0xE7,0x4C,
-    0xDB,0x42,0xFA,0x8D,0x4C,0xD3,0x30,0xF7,0x71,0x7F,0xC2,0x41,0x66,0x19,0x7D,0x47,
-    0x99,0x26,0xF5,0x74,0x39,0xFE,0xB8,0xDF,0x60,0x36,0x02,0x0E,0x77,0x28,0x12,0x84,
-};
-
-/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
-/* issuer :/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
-unsigned char _trustSettingsInt[1016]={
-    0x30,0x82,0x03,0xF4,0x30,0x82,0x02,0xDC,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
-    0xBE,0x29,0xEC,0x6D,0x40,0x7E,0x44,0x9A,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x91,0x31,0x0B,0x30,0x09,0x06,0x03,
-    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
-    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
-    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
-    0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,
-    0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
-    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
-    0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,
-    0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,
-    0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,
-    0x36,0x30,0x33,0x31,0x39,0x32,0x33,0x34,0x30,0x31,0x33,0x5A,0x17,0x0D,0x31,0x37,
-    0x30,0x33,0x31,0x39,0x32,0x33,0x34,0x30,0x31,0x33,0x5A,0x30,0x7C,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,
-    0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,
-    0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,
-    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
-    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
-    0x72,0x69,0x6E,0x67,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,
-    0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,
-    0x73,0x74,0x20,0x53,0x75,0x62,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,
-    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,
-    0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC3,0x98,0xDB,0xB7,0x52,0xC3,
-    0xC9,0xD3,0xB8,0x35,0x57,0xAE,0xF4,0x93,0x21,0xDD,0xAD,0x17,0xA8,0xE3,0x39,0xB0,
-    0x27,0xF3,0x9F,0x12,0x77,0xF3,0xF0,0x03,0xED,0xAE,0xE7,0x79,0x86,0x17,0x07,0x1C,
-    0xDE,0x34,0x41,0x25,0x39,0xCA,0xFE,0xD1,0x13,0x3B,0xBB,0x7E,0x77,0x7E,0x32,0x99,
-    0xDD,0xEB,0xBA,0xDC,0x6D,0xB9,0xF5,0x8A,0x1C,0x19,0x71,0xE3,0xE4,0x7F,0x39,0x0C,
-    0x3F,0x09,0x46,0x22,0x28,0x60,0x1A,0x42,0xA2,0x6E,0xE4,0x64,0xCF,0x02,0x68,0xAC,
-    0x74,0xD1,0xBD,0xE4,0xC7,0x69,0x90,0xA5,0xA4,0x4F,0x1C,0x6E,0x08,0x79,0x28,0xE8,
-    0x3E,0xE3,0x62,0x15,0xF8,0xB9,0xC1,0x56,0x1A,0xB0,0xE3,0x27,0x02,0xC6,0x29,0x20,
-    0x7B,0x34,0x54,0xCC,0x0F,0xDB,0x5B,0x5E,0x81,0x0F,0x20,0xB7,0xB4,0x43,0xB3,0x29,
-    0xE7,0xB7,0x83,0xCB,0x01,0xB3,0x57,0x3E,0x7B,0xBC,0x21,0x2F,0xED,0x24,0x99,0xB4,
-    0xCD,0x64,0x9F,0x47,0xA3,0x5E,0x7B,0x99,0x69,0x8D,0xEB,0x6C,0x9D,0x60,0x7C,0x2F,
-    0x2D,0xF5,0xC9,0x9D,0x11,0x7B,0x61,0x4A,0x0D,0x70,0x11,0x14,0x6C,0xE1,0xCB,0xC1,
-    0x20,0xAF,0x55,0xBF,0xBE,0x8B,0xB6,0x9A,0x03,0x6C,0xFD,0x7A,0xCF,0xFB,0x92,0xD1,
-    0x85,0xEE,0x5B,0x1E,0xEA,0xDC,0x58,0xF3,0xF1,0x0B,0x88,0x9E,0xA5,0xB4,0xD2,0xCD,
-    0x74,0x47,0x18,0xA8,0xE3,0xFD,0x45,0xC2,0xE1,0x4D,0x97,0x77,0x89,0x48,0xF9,0x66,
-    0xA4,0xEF,0x9E,0x33,0x3E,0xF0,0xED,0x55,0xF7,0x92,0xF4,0x1B,0xF7,0xF6,0xF9,0x90,
-    0xCE,0xD5,0xA1,0x3F,0xE7,0xB7,0x2E,0x33,0x8F,0x9D,0x02,0x03,0x01,0x00,0x01,0xA3,
-    0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,
-    0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
-    0x03,0x02,0x02,0x04,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xFD,
-    0x26,0x89,0x9C,0xA6,0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,0x2F,0xA6,0xC8,
-    0x22,0x30,0x70,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
-    0x68,0x31,0x64,0x1E,0x5C,0x68,0x6A,0x83,0xBD,0x39,0x22,0x44,0xF6,0xD3,0x6C,0x70,
-    0xF7,0xDD,0x22,0x53,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
-    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA0,0xCA,0xAB,0x34,0xCF,0x6A,0x97,0x40,
-    0x58,0x49,0xEE,0xA5,0x03,0x98,0xDB,0x6B,0x8D,0x19,0x11,0x83,0x5C,0x52,0xA5,0xD0,
-    0xA2,0x3B,0x5E,0x59,0x13,0x53,0xCA,0xAA,0x6B,0x26,0x6D,0x14,0x4A,0x6D,0x8A,0x61,
-    0xA7,0xDD,0x3E,0x2D,0x8B,0x4A,0x62,0xA4,0x3D,0x06,0xEE,0x76,0xB5,0x6F,0x93,0x30,
-    0xD1,0x29,0xEA,0x34,0x01,0xB3,0x6B,0x1A,0xF3,0xCA,0x26,0x1E,0x76,0x2E,0x46,0xB3,
-    0x73,0xE1,0x97,0x95,0x2F,0x16,0xC8,0x1F,0xF8,0x79,0x0E,0xEA,0x36,0xB0,0xEA,0x49,
-    0xBE,0x5A,0x40,0xFE,0x83,0x51,0x94,0x78,0x74,0xD0,0x22,0x87,0x34,0xF5,0xEE,0x44,
-    0x55,0x4B,0x4A,0xFF,0xF9,0xCD,0x84,0x68,0x32,0x94,0x98,0xCF,0xE0,0x51,0x66,0xEC,
-    0x93,0x12,0x26,0x37,0xBD,0xA1,0x71,0x3B,0xF6,0x7A,0x40,0x48,0x62,0xC8,0xDD,0xE8,
-    0x74,0x2C,0x14,0x09,0x18,0xDA,0x23,0x85,0xFF,0x2A,0x65,0xBF,0x0E,0x72,0x32,0xE2,
-    0xD8,0x89,0x36,0x99,0x51,0x00,0xBD,0x16,0x48,0x46,0xFB,0x02,0xFA,0x7A,0xC3,0x73,
-    0xBC,0x3B,0xB4,0x34,0x1C,0xBD,0x63,0x8D,0x12,0x97,0x66,0x8E,0x89,0x6C,0x79,0x8C,
-    0xA9,0x77,0x49,0x92,0x7E,0xB2,0xF8,0xDE,0x58,0xB9,0xF1,0xEA,0xAF,0x74,0x94,0x46,
-    0x1A,0x7B,0x5F,0x65,0x8D,0x08,0x38,0xBA,0xE4,0xB2,0xC2,0x27,0x05,0x76,0x38,0x1F,
-    0x2B,0xFD,0x29,0x86,0xDA,0x38,0xB3,0x1E,0x37,0x38,0xE4,0x6F,0x81,0x35,0xA7,0x82,
-    0x85,0xF5,0x8B,0xEC,0x24,0xD1,0xA1,0x12,0xFB,0x54,0xC4,0x51,0xA4,0x97,0xF2,0x0B,
-    0xD4,0xE5,0x79,0x49,0x60,0x27,0x0D,0x5D,
-};
-
-/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test SSL Leaf */
-/* issuer :/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
-unsigned char _trustSettingsSSLLeaf[1059]={
-    0x30,0x82,0x04,0x1F,0x30,0x82,0x03,0x07,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
-    0x81,0x94,0x54,0x10,0xDC,0xA5,0x98,0x17,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
-    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,
-    0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,
-    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
-    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
-    0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,0x72,0x75,0x73,0x74,
-    0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,
-    0x75,0x62,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x33,0x32,0x30,0x30,
-    0x30,0x31,0x30,0x35,0x37,0x5A,0x17,0x0D,0x31,0x37,0x30,0x33,0x32,0x30,0x30,0x30,
-    0x31,0x30,0x35,0x37,0x5A,0x30,0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,
-    0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,
-    0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,0x03,0x55,
-    0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,
-    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
-    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x25,
-    0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x20,0x53,
-    0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,0x53,0x4C,
-    0x20,0x4C,0x65,0x61,0x66,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,0xBC,0x1C,0xAC,0x0E,0x78,0xFC,0xFA,0x63,0x97,0x5B,
-    0xE3,0xFB,0xE9,0x31,0x60,0x9C,0xAE,0x81,0x9F,0xE1,0x19,0x95,0xF1,0xE2,0x27,0x14,
-    0x33,0x86,0xA3,0x11,0x16,0x35,0x36,0x93,0x05,0xB6,0x88,0xC1,0x97,0x52,0xAB,0x0D,
-    0xA6,0x22,0xF2,0x5E,0xDF,0x9E,0x27,0x9F,0x82,0x4F,0x0B,0xAD,0x96,0x9D,0xD4,0x7A,
-    0x85,0xEA,0x62,0x89,0x6E,0xD5,0xC1,0x0D,0xCD,0x0D,0x15,0x4D,0x66,0x1F,0xA9,0xA8,
-    0xB3,0xFA,0xC1,0x59,0x74,0x69,0xE6,0xA5,0x4A,0xF2,0xA3,0xC9,0x5F,0x29,0x7D,0x9E,
-    0x49,0x5B,0x02,0x41,0x11,0x80,0x5C,0xD0,0x69,0x41,0x7C,0x05,0xFB,0xBA,0x0B,0xB6,
-    0x10,0x6D,0x30,0xF3,0xB7,0x76,0x4A,0x32,0xCE,0xF0,0x50,0x74,0x70,0x1C,0x7A,0xE7,
-    0x05,0x2A,0x01,0x00,0xB0,0xBB,0x22,0xB0,0xAD,0x7C,0x19,0xFD,0x5A,0xE3,0xC5,0xCD,
-    0x51,0x15,0x97,0xF4,0xE4,0xEF,0x60,0x56,0x2C,0x92,0xB1,0xD4,0x9D,0xF9,0x26,0x1F,
-    0x0C,0x11,0x2F,0x2F,0xA5,0xFA,0xD6,0x8E,0x87,0x1D,0xCC,0xA7,0xA0,0x3C,0x23,0xBB,
-    0x52,0x30,0x11,0x13,0x43,0x7C,0xFE,0x63,0xEE,0xAE,0xAF,0xE6,0xED,0x07,0xD2,0x89,
-    0xCB,0xC0,0xFE,0xF1,0xBF,0x75,0x18,0xA8,0xFF,0x34,0x9A,0x5C,0x28,0xEC,0x18,0x55,
-    0x68,0xF7,0x24,0x30,0x94,0x49,0x23,0xCB,0xF1,0xE3,0xBE,0x1D,0x51,0xA3,0x2B,0x21,
-    0x7D,0xFC,0x6E,0x93,0x19,0xE7,0xA5,0x26,0xFE,0xE2,0x5D,0xED,0x4A,0xD4,0xB9,0x60,
-    0xE4,0xE7,0x77,0xA8,0xFF,0x13,0x06,0x0D,0x58,0x82,0x25,0x6D,0xEB,0xAC,0xA9,0x56,
-    0xF9,0x2C,0x60,0xBB,0x66,0x77,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xA1,0x30,0x81,
-    0x9E,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
-    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,
-    0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x1F,
-    0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,0x82,0x14,0x74,0x65,0x73,0x74,0x73,
-    0x65,0x72,0x76,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,
-    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC6,0xED,0xD2,0x4E,0x23,0xC9,
-    0xA9,0xC8,0x64,0x3A,0x55,0x51,0x0F,0x27,0x52,0xD6,0x18,0x12,0x66,0xC8,0x30,0x1F,
-    0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xFD,0x26,0x89,0x9C,0xA6,
-    0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,0x2F,0xA6,0xC8,0x22,0x30,0x70,0x30,
-    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,
-    0x01,0x01,0x00,0xB1,0x56,0x55,0xC7,0x1F,0xF6,0x15,0x59,0xA6,0x0B,0xC4,0xBB,0x48,
-    0x53,0x1B,0xE7,0xC1,0x7F,0x72,0x65,0x0E,0xE9,0x08,0x22,0xF6,0x30,0x9C,0xB3,0xCA,
-    0xCF,0xDE,0x16,0x2C,0x90,0x30,0x59,0xC4,0xB2,0xE7,0x1E,0xD2,0xF3,0xD6,0x29,0x94,
-    0xA3,0xD5,0xFA,0x98,0xC1,0xBF,0xD7,0xC3,0x52,0xBC,0xFF,0x6D,0xB6,0xE1,0xCE,0x1A,
-    0x59,0xF9,0x68,0x6D,0x98,0x8B,0x48,0x7D,0xE6,0xD0,0x1F,0xFE,0xF7,0x9C,0x73,0x09,
-    0x73,0x9B,0x5D,0xAF,0x88,0x37,0x35,0x1C,0x3F,0x9A,0x07,0xE0,0x3B,0x29,0x24,0x7F,
-    0x04,0x9A,0xD2,0x3F,0xDE,0xF3,0x68,0x1D,0x16,0x8D,0xD0,0x4F,0xB6,0x83,0x19,0x70,
-    0xBB,0x1F,0x21,0x91,0x49,0x3F,0x12,0x89,0xF6,0x88,0x8A,0x2F,0xDC,0x55,0x54,0xBE,
-    0x78,0xDD,0x2F,0xC9,0x0C,0x7B,0x8C,0xA8,0x33,0x33,0x1D,0xA0,0x6D,0xA4,0xA6,0x6A,
-    0xA4,0x49,0xD6,0x37,0x6D,0x95,0x15,0x0C,0xFA,0xA5,0xCF,0x5A,0x28,0xD9,0x37,0x5D,
-    0xC5,0xC5,0x3A,0x30,0x8D,0x54,0xE4,0xAB,0x19,0x7A,0xF0,0x33,0xAE,0x64,0xA9,0x42,
-    0x83,0xD2,0xF2,0x68,0x39,0xA2,0xE1,0x71,0x68,0x19,0x81,0x5A,0x9B,0xB4,0xDD,0xBC,
-    0xA6,0xC7,0x19,0x40,0x87,0x50,0x6F,0x49,0xD2,0xC1,0x92,0x57,0xE4,0x5B,0x5F,0x41,
-    0x85,0x22,0x33,0x8D,0xC7,0x0B,0x3F,0x55,0xC1,0x46,0x2C,0xB6,0xDE,0xF7,0x80,0x54,
-    0xA5,0x62,0x0E,0xA3,0x24,0x14,0x9B,0xF1,0xEE,0x9D,0x7F,0x65,0xA2,0x1D,0x0C,0x32,
-    0x86,0x81,0xDE,0xDC,0xD7,0xB6,0x06,0x3A,0xF6,0xF0,0x81,0x6A,0xBE,0xC4,0xA0,0x87,
-    0xEA,0x6A,0x6C,
-};
-
-/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test SMIME Leaf */
-/* issuer :/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
-unsigned char _trustSettingsSMIMELeaf[1050]={
-    0x30,0x82,0x04,0x16,0x30,0x82,0x02,0xFE,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
-    0x81,0x94,0x54,0x10,0xDC,0xA5,0x98,0x18,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
-    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
-    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,
-    0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,
-    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
-    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
-    0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,0x72,0x75,0x73,0x74,
-    0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,
-    0x75,0x62,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x33,0x32,0x30,0x30,
-    0x30,0x31,0x31,0x35,0x32,0x5A,0x17,0x0D,0x31,0x37,0x30,0x33,0x32,0x30,0x30,0x30,
-    0x31,0x31,0x35,0x32,0x5A,0x30,0x81,0x80,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
-    0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,
-    0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,0x03,
-    0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,
-    0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,
-    0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,
-    0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x0C,0x1E,0x54,0x72,0x75,0x73,0x74,0x20,
-    0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,0x4D,
-    0x49,0x4D,0x45,0x20,0x4C,0x65,0x61,0x66,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,0xE7,0x42,0xF7,0x3B,0x41,0xB4,0x91,
-    0xF6,0xC3,0x4F,0x5B,0x52,0x9C,0x4D,0x1E,0x0D,0x1F,0x1A,0xE8,0x07,0x14,0x00,0x48,
-    0x00,0x18,0x13,0xA6,0xD0,0xC4,0x49,0x6A,0xC7,0x47,0xBE,0xC6,0x07,0x9F,0xED,0x81,
-    0xC8,0x49,0x7C,0xC8,0x69,0x14,0x2D,0xAD,0xD4,0x98,0x58,0x1A,0x6D,0xCC,0x28,0x54,
-    0xA1,0x13,0xAF,0x2A,0xB5,0xF5,0x4B,0x6F,0x97,0x85,0x33,0xE0,0x12,0xF8,0x06,0x95,
-    0xA0,0x57,0x81,0xD1,0x51,0x4E,0x1B,0x29,0x80,0x9F,0x3C,0x49,0x34,0x28,0x61,0x59,
-    0x6A,0x56,0xA1,0x13,0x52,0x1B,0x41,0x6E,0xE2,0xA7,0xE1,0x6E,0x10,0xCC,0x07,0x48,
-    0x0C,0x36,0x25,0x35,0xD3,0xBB,0x8F,0x45,0xF9,0x37,0x4D,0xB4,0xC7,0x9E,0xFA,0x7F,
-    0x99,0xFC,0xB5,0x35,0xD7,0x96,0xC6,0xF7,0xF0,0x19,0x34,0xB6,0xD9,0x3C,0x82,0x38,
-    0xBF,0x23,0x04,0x21,0x4A,0xFC,0xC1,0x8C,0x89,0xB1,0x45,0xFC,0x9B,0x4D,0xAE,0x28,
-    0x4F,0xF6,0xD3,0x69,0xBB,0x3B,0xC5,0x5F,0x72,0xC7,0xD3,0xDF,0x70,0x97,0x7B,0xEE,
-    0xD6,0x09,0xD6,0x21,0xF3,0xCF,0x8D,0x50,0xAF,0x48,0xDA,0x2C,0xEB,0x90,0x8E,0x1D,
-    0xEE,0x94,0xA7,0xAB,0x21,0x0E,0xC8,0xE2,0xA1,0x7F,0x36,0x98,0x1A,0x99,0xDD,0x85,
-    0x3A,0xEE,0xF0,0xE6,0x34,0x15,0x98,0x6D,0xA8,0x22,0x4E,0x4F,0x54,0x06,0xF1,0x1F,
-    0xE0,0xDD,0x8E,0xB1,0xA5,0x94,0xA2,0xC5,0xD2,0xA3,0xEA,0xD9,0xD9,0x28,0x1B,0x4B,
-    0x98,0x82,0x89,0x18,0x2D,0x7B,0x17,0xD6,0x92,0x5F,0x20,0x44,0xAF,0xD5,0x27,0x02,
-    0x2C,0x2E,0x8F,0x14,0x20,0x70,0xA1,0xD4,0x65,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,
-    0x95,0x30,0x81,0x92,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,
-    0x30,0x00,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x03,0x04,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,
-    0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x11,0x04,0x16,
-    0x30,0x14,0x81,0x12,0x75,0x73,0x65,0x72,0x6E,0x61,0x6D,0x65,0x40,0x61,0x70,0x70,
-    0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
-    0x14,0xC6,0xD8,0x0B,0xD7,0xD4,0x9E,0x84,0x41,0xB3,0x59,0x05,0x41,0xDF,0xC3,0x2A,
-    0x77,0xBB,0x41,0x20,0x85,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
-    0x80,0x14,0xFD,0x26,0x89,0x9C,0xA6,0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,
-    0x2F,0xA6,0xC8,0x22,0x30,0x70,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
-    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4B,0x02,0x37,0x7F,0xBA,0x3D,
-    0xD5,0xDF,0xE9,0xD6,0x52,0x6D,0x39,0x23,0x83,0x1B,0xFB,0x17,0x15,0x1A,0x45,0x9E,
-    0xF2,0x55,0xA3,0x2C,0x18,0xF1,0x01,0xA1,0x2D,0xAA,0x78,0x39,0xA8,0x5A,0xD5,0x9E,
-    0x37,0xE4,0x50,0x31,0x7A,0x07,0x61,0xD8,0xE9,0x2A,0x32,0x1F,0x04,0x3F,0x27,0x03,
-    0xDC,0x77,0x7F,0x1B,0xD7,0x45,0x55,0x1F,0x5B,0xCC,0x7A,0xF1,0x5C,0x74,0x9E,0xA5,
-    0x2A,0xA3,0xAC,0x63,0xBE,0x8B,0xEB,0x38,0x39,0xEC,0x53,0x9E,0x09,0x5A,0x86,0x2D,
-    0x25,0x9C,0x78,0x85,0x02,0x07,0xE5,0xE2,0x98,0xB3,0x70,0x50,0x1A,0xAE,0x4F,0xF4,
-    0x9F,0x89,0xA9,0x84,0xBF,0x6F,0x03,0x42,0x6B,0x12,0x0A,0x15,0x73,0x3F,0xC6,0x8B,
-    0x32,0xDA,0x52,0x17,0xC5,0xC2,0x96,0x68,0xF7,0x31,0x1B,0x5D,0xB1,0x49,0x4C,0x2D,
-    0xE7,0x3E,0x42,0xD6,0xF1,0x14,0xA9,0xBE,0x2F,0xD9,0x65,0xEB,0x0F,0x51,0x58,0x09,
-    0x7D,0x4D,0x07,0x4B,0xE4,0x49,0x13,0x8B,0x70,0xA9,0x90,0x6C,0x9F,0x10,0xD2,0x8B,
-    0x90,0xBE,0x63,0xF9,0x8E,0xF8,0x73,0x22,0xBE,0x54,0xEE,0x96,0x56,0x66,0xBC,0x2F,
-    0x2A,0xC6,0x6B,0x84,0x67,0x4D,0xD8,0xF7,0xBA,0xCD,0x75,0x3B,0x73,0xEF,0x05,0x46,
-    0x52,0xA4,0xF9,0xA7,0x03,0x29,0xA4,0x9A,0x11,0xAE,0x79,0xE5,0x53,0x3E,0xC5,0xD7,
-    0x75,0x39,0x2D,0x82,0xC3,0x60,0x5F,0x12,0x9B,0x90,0x19,0xD6,0xB1,0xA4,0xF7,0x8B,
-    0x62,0xF9,0x44,0x4E,0x15,0xA5,0xD3,0xFF,0x75,0x4E,0x44,0x84,0x78,0xCF,0x68,0x18,
-    0xFE,0x46,0xEB,0xFE,0x0E,0x11,0xCB,0x34,0x53,0xAB,
-};
-
-/* subject:/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
-/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
-uint8_t _corporateRoot[] = {
-    0x30,0x82,0x03,0xB1,0x30,0x82,0x02,0x99,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x14,
-    0x99,0x6B,0x4A,0x6A,0xE4,0x40,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
-    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
-    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
-    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
-    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
-    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
-    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
-    0x17,0x0D,0x31,0x33,0x30,0x37,0x31,0x36,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x17,
-    0x0D,0x32,0x39,0x30,0x37,0x31,0x37,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x30,0x66,
-    0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,
-    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,
-    0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,
-    0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,
-    0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,
-    0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
-    0x04,0x06,0x13,0x02,0x55,0x53,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,0xB5,0x3B,0xE3,0x9F,0x6A,0x1D,0x0E,0x46,0x51,
-    0x1E,0xD0,0xB5,0x17,0x6B,0x06,0x4B,0x92,0xAF,0x38,0x10,0x25,0xA1,0xEE,0x1E,0x4E,
-    0xEF,0x19,0xE0,0x73,0xB5,0x37,0x33,0x72,0x21,0x21,0xCB,0x62,0x4A,0x3D,0xA9,0x68,
-    0xD8,0x07,0xB4,0xEB,0x8D,0x0A,0xDB,0x30,0x33,0x21,0x2F,0x6F,0xD3,0xF7,0x5D,0xCE,
-    0x20,0x0A,0x04,0xDB,0xFF,0xBF,0x75,0x08,0x42,0x3F,0x3E,0xD8,0xC8,0xEF,0xA4,0xF8,
-    0x56,0x7B,0x13,0x64,0x6B,0xF3,0xA2,0x38,0x10,0xFA,0xEE,0x9D,0x83,0x93,0x1D,0xFB,
-    0xEF,0x13,0x6C,0x38,0x49,0xDD,0xEB,0x71,0xA6,0x92,0x58,0x04,0xDE,0x01,0x41,0x2B,
-    0x99,0x5E,0xBD,0x24,0x3F,0x69,0xA8,0x44,0xF2,0xAA,0x01,0x78,0xB9,0x38,0x06,0x10,
-    0x77,0x36,0xF8,0xF2,0xA3,0x3E,0xD9,0x5F,0xEA,0xF5,0x8B,0x6A,0xA6,0x5F,0xE6,0x51,
-    0xD0,0x9B,0x50,0xA0,0x1E,0xF5,0x85,0x9E,0x49,0x50,0x4A,0x61,0x78,0xDA,0x29,0xA7,
-    0x33,0x72,0x8B,0x83,0xEE,0x7B,0xA7,0x79,0x4E,0x8E,0x02,0x6F,0x9D,0x25,0x97,0x26,
-    0x86,0x0C,0x82,0xC5,0x8C,0x16,0x7E,0x49,0x61,0xFD,0xFF,0x1A,0xA0,0x0D,0x28,0xE1,
-    0x68,0xF5,0xAE,0x85,0x72,0xF3,0xAB,0xE0,0x74,0x75,0xCC,0x57,0x64,0x3C,0x2C,0x55,
-    0x05,0xC9,0x8D,0xAA,0xB3,0xEC,0xC8,0x62,0x88,0x15,0x2A,0xC4,0x59,0x60,0x37,0xC1,
-    0xED,0x6B,0xCE,0xE9,0xCA,0xAF,0xB0,0xA5,0x45,0xBA,0xFF,0x16,0x32,0xAA,0x92,0x86,
-    0xD9,0xB9,0xA1,0x13,0x75,0x95,0x9B,0x97,0x5C,0x2D,0xB5,0x12,0xCA,0x6B,0x6B,0x39,
-    0xD6,0x9B,0x4B,0x34,0x47,0xAB,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,
-    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x35,0x20,0x26,0xCE,0x85,
-    0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,
-    0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,
-    0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,
-    0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,
-    0xF5,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,
-    0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
-    0x03,0x82,0x01,0x01,0x00,0x73,0x02,0x4A,0xA6,0x77,0x02,0xA7,0xE1,0xCB,0x52,0x97,
-    0x9D,0x89,0x11,0xA0,0x8F,0xBC,0xF3,0x8F,0x14,0x01,0x29,0xF3,0xA5,0x45,0x17,0x06,
-    0xF8,0x04,0xF2,0x6D,0xD5,0xC3,0x77,0xB8,0x00,0xC2,0x0A,0x1A,0x09,0x32,0x36,0x36,
-    0x69,0xC1,0x2A,0xF0,0x44,0x37,0xBC,0x7E,0x5F,0x15,0xF7,0x08,0x9C,0x19,0x27,0x1D,
-    0x70,0x4F,0xDC,0x17,0x94,0x3C,0xBB,0x24,0xB4,0xE6,0xFC,0x71,0x9A,0xD4,0xCF,0x2C,
-    0x12,0xBA,0xF0,0xB6,0x8F,0x78,0x99,0xAA,0x8C,0x17,0x7E,0x94,0x0C,0x6A,0x37,0x5B,
-    0x35,0x91,0x52,0xFA,0x64,0xA3,0x33,0x34,0x99,0x37,0x00,0x3C,0xB4,0x4E,0x6E,0x63,
-    0xED,0xC3,0x1D,0x37,0x5B,0x45,0xB4,0xDF,0x82,0xCD,0xFE,0xAA,0x92,0x64,0xC8,0x2F,
-    0xD6,0x2D,0x2E,0xB1,0xED,0x6A,0x04,0xF1,0xC2,0x48,0x8D,0x4B,0xB4,0x84,0x39,0xA3,
-    0x31,0x4D,0xF6,0x63,0xB4,0xC3,0x6E,0xA1,0xA5,0x2F,0xD2,0x1E,0xB0,0xC6,0x0C,0xD1,
-    0x04,0x3A,0x31,0xBC,0x87,0x49,0xF8,0x26,0x0B,0xD3,0x0C,0x08,0x29,0xBB,0x9F,0x4D,
-    0x08,0xF0,0x9C,0x11,0xD3,0xA5,0x2C,0x8D,0x98,0xB1,0x1B,0xB1,0x57,0xD3,0x69,0xAE,
-    0x9E,0x2D,0xD5,0x64,0x38,0x58,0xC9,0xB2,0x84,0x04,0xAB,0x10,0x1D,0xCA,0x6B,0x29,
-    0xA5,0xAB,0xCC,0xFE,0xBB,0x74,0xF4,0x35,0x03,0x8F,0x65,0x2A,0x0B,0xBB,0xC7,0x17,
-    0x6A,0x49,0x34,0x83,0x30,0x92,0x8D,0xD7,0xAE,0x95,0xD0,0xD7,0x23,0xA7,0xE3,0x29,
-    0x09,0xA1,0xB1,0x34,0xC3,0x95,0x49,0xC3,0xA4,0xF1,0x36,0x00,0x09,0xD3,0xA4,0x09,
-    0xAD,0xF2,0x5C,0x97,0xB2,
-};
-
-/* subject:/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
-/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
-uint8_t _corporateServerCA[] = {
-    0x30,0x82,0x04,0x40,0x30,0x82,0x03,0x28,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x0D,
-    0x5D,0xDF,0x69,0x27,0x9B,0x23,0x11,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
-    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
-    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
-    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
-    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
-    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
-    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
-    0x17,0x0D,0x31,0x34,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x17,
-    0x0D,0x32,0x39,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x30,0x6A,
-    0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,
-    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,
-    0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,
-    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
-    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xE3,0xE9,0x68,0xA1,0xE7,
-    0x9B,0xBC,0xF7,0x87,0x48,0x22,0x9B,0x09,0x5F,0xC8,0xC9,0xA6,0x9A,0xCC,0xCD,0x40,
-    0x16,0xF8,0xA1,0xD0,0xF6,0x27,0x15,0x4C,0xE7,0xD3,0xC1,0x6E,0xDF,0x11,0x06,0x9A,
-    0x63,0xC5,0x87,0x55,0xDA,0xDF,0xAF,0x15,0x31,0x98,0x45,0xF4,0x8C,0xC2,0x3C,0x93,
-    0xA2,0x1C,0xC0,0xF0,0x2A,0x77,0xF4,0x19,0x94,0x96,0xF4,0x7B,0x52,0x74,0x84,0x86,
-    0x5A,0x66,0x7D,0x68,0x92,0xA1,0x5E,0xE1,0xA9,0x21,0xE0,0x14,0x38,0x84,0x21,0x32,
-    0x8B,0x21,0x95,0x47,0x27,0x17,0xA0,0xBA,0x7B,0xD7,0xD8,0xD7,0x25,0x20,0x77,0xCB,
-    0x62,0x8B,0xC6,0x0F,0xC1,0x49,0xC6,0x2B,0x42,0xE9,0x02,0x70,0x9E,0x99,0x44,0x77,
-    0x51,0x05,0x62,0x78,0xBC,0xB0,0xD2,0xA7,0xA6,0x91,0x71,0x25,0x58,0x13,0x8D,0x8A,
-    0xC8,0x46,0x41,0xDB,0x89,0x41,0xC5,0x23,0x7D,0x84,0xE9,0x02,0xB0,0x1A,0xF8,0x5D,
-    0x66,0xD0,0xE1,0xE1,0x72,0xF4,0xA4,0x65,0x79,0x97,0x0A,0x7B,0xC0,0xE3,0x24,0x74,
-    0x83,0x4A,0x81,0x5E,0xC3,0xA2,0xBF,0x51,0x32,0x96,0x8F,0x28,0x32,0x08,0x49,0xFB,
-    0x02,0x43,0x62,0x42,0xB3,0x84,0x84,0x30,0x1B,0x28,0xE4,0x05,0xB9,0xBB,0xD6,0xB5,
-    0xC4,0xA2,0xAB,0x8E,0x57,0x53,0x29,0xBC,0x0B,0x4F,0xD6,0x1E,0xA4,0x52,0xDC,0x16,
-    0x1C,0x95,0xC2,0x8D,0x97,0x6B,0xBB,0x3E,0xC8,0x93,0xC7,0x01,0x97,0x1E,0x18,0x09,
-    0x59,0x39,0x0F,0x5D,0x73,0x4E,0xA9,0x8F,0x49,0xFD,0x49,0x16,0xBD,0x25,0xEC,0xD9,
-    0x05,0xEA,0xE3,0xB0,0x04,0x0E,0xD9,0x09,0x9E,0xC0,0xB7,0x02,0x03,0x01,0x00,0x01,
-    0xA3,0x81,0xED,0x30,0x81,0xEA,0x30,0x41,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x01,0x01,0x04,0x35,0x30,0x33,0x30,0x31,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x30,0x01,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,
-    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x34,
-    0x2D,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,
-    0x04,0x16,0x04,0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,
-    0xD0,0xAD,0x5C,0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,
-    0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
-    0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,
-    0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,0x32,0x06,0x03,0x55,0x1D,
-    0x1F,0x04,0x2B,0x30,0x29,0x30,0x27,0xA0,0x25,0xA0,0x23,0x86,0x21,0x68,0x74,0x74,
-    0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
-    0x6D,0x2F,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x0E,
-    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x10,
-    0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x06,0x18,0x04,0x04,0x02,0x05,0x00,
-    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
-    0x82,0x01,0x01,0x00,0x0D,0x34,0x2F,0xB2,0xC2,0xF1,0xF0,0xDC,0xA2,0x9F,0x8F,0x41,
-    0x9C,0x84,0xCA,0x66,0xDC,0x90,0x9C,0xC4,0x90,0xC9,0xDA,0xD9,0x37,0x4F,0xAE,0xC9,
-    0xD9,0xCF,0xE2,0x4B,0x8E,0x59,0x47,0x9A,0x83,0x32,0xDF,0xA7,0x97,0x45,0x9D,0x1E,
-    0x46,0x58,0x5D,0xD7,0x1C,0x17,0xC5,0x1C,0x9E,0xA2,0x74,0xF6,0x73,0x77,0xF9,0x35,
-    0xAD,0x67,0xC3,0x3C,0xD5,0x87,0x1E,0x96,0x16,0x3D,0x8B,0x40,0x51,0xA8,0x16,0xA0,
-    0x53,0x1C,0xF5,0xCB,0x32,0xC4,0xA8,0xC5,0x2A,0x3A,0x21,0xD9,0xFD,0x51,0x81,0x59,
-    0x6F,0x1B,0xF9,0x40,0x86,0x96,0xCF,0xA0,0x73,0xA3,0x5B,0x60,0x02,0xB6,0x21,0xAD,
-    0x39,0xF5,0xFA,0xFC,0xA8,0x6E,0x34,0x01,0x7C,0x59,0xF3,0x73,0xFC,0xBA,0xBE,0xF4,
-    0x4E,0x16,0x36,0x9E,0x51,0x77,0x80,0xF5,0xA1,0xC7,0xAE,0xFF,0x04,0x71,0x6B,0xB3,
-    0xBE,0x3E,0xA7,0xD1,0x74,0x2B,0x4D,0x58,0x58,0x3B,0x94,0x74,0xA3,0x65,0x27,0xC1,
-    0x74,0xA9,0xD2,0xF9,0x8A,0x81,0xB3,0x47,0xB3,0x06,0x8E,0x9C,0xE6,0x42,0x86,0x77,
-    0xF8,0x96,0x99,0x1F,0xED,0x30,0x8F,0x4B,0xD5,0x0F,0x5E,0x71,0x6C,0xAC,0xDB,0x48,
-    0xE3,0x3C,0x58,0x2B,0xE8,0x9B,0x9E,0x24,0x8A,0x5D,0xCD,0x56,0x5F,0xA9,0x07,0xEA,
-    0xCD,0x2C,0x94,0x3D,0xA7,0x7F,0x1B,0xE8,0x10,0xB8,0xD2,0x1E,0x43,0x5A,0x0D,0x13,
-    0xDA,0xF5,0x3F,0x10,0x9D,0x2D,0x1F,0xE6,0x94,0x11,0x2F,0x40,0xFF,0x5F,0x21,0x96,
-    0x02,0xF0,0x5F,0x54,0x56,0x32,0x90,0xD5,0x67,0xAE,0x29,0x0E,0x22,0x70,0xE3,0x2B,
-    0x7A,0x95,0xC0,0xC7,
-};
-
-/* subject:/CN=bbasile-test.scv.apple.com/OU=management:idms.group.631731/O=Apple Inc./ST=California/C=US */
-/* issuer :/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
-uint8_t _corporateServerCert[] = {
-    0x30,0x82,0x05,0xF4,0x30,0x82,0x04,0xDC,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x54,
-    0x32,0x9C,0xE6,0xE6,0xD7,0x87,0x7E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
-    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x6A,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,
-    0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
-    0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,
-    0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,
-    0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,
-    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
-    0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
-    0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,0x30,0x39,0x32,0x37,0x30,0x34,0x32,0x30,
-    0x34,0x31,0x5A,0x17,0x0D,0x32,0x30,0x31,0x30,0x32,0x36,0x30,0x34,0x32,0x30,0x34,
-    0x31,0x5A,0x30,0x81,0x83,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,
-    0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,
-    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x25,0x30,0x23,0x06,0x03,
-    0x55,0x04,0x0B,0x0C,0x1C,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,
-    0x69,0x64,0x6D,0x73,0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x36,0x33,0x31,0x37,0x33,
-    0x31,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
-    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
-    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,
-    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xAF,0x8C,0xB9,0x3F,0x56,0x41,0xF9,
-    0xA5,0x93,0x89,0x95,0x58,0x31,0x90,0x84,0xD5,0x3E,0xBB,0xE4,0x7C,0x68,0xD4,0x5B,
-    0x95,0x97,0x04,0xEF,0xE6,0x3C,0x8E,0x6A,0x98,0xD0,0xAD,0xDD,0x7A,0xF1,0x5E,0x4D,
-    0xCF,0x40,0xEF,0x05,0xF7,0x02,0x8C,0x01,0x0B,0x74,0x9D,0x0C,0x7E,0xD1,0xF8,0x80,
-    0x6E,0xAA,0xBF,0x96,0xB3,0x50,0x8F,0xB4,0x68,0x0C,0xFA,0xD0,0xDB,0xE7,0x93,0xA0,
-    0x6A,0x84,0xF2,0xA3,0x90,0x62,0x54,0xBD,0xB0,0xB3,0x1F,0xD6,0x0E,0xD1,0x2B,0xBA,
-    0x13,0x38,0x0A,0xD1,0x84,0x36,0x75,0x77,0xFB,0x3B,0x1E,0x61,0x1B,0x85,0x22,0xA9,
-    0xF9,0x42,0xD6,0xA2,0x9B,0xCB,0x34,0x76,0xC0,0xAE,0x2B,0xB0,0x64,0x95,0x5B,0xC7,
-    0x61,0x2A,0x0B,0x81,0xE0,0x01,0x34,0xB8,0x50,0xDC,0x26,0x77,0x55,0xF7,0x95,0xE1,
-    0xEC,0x01,0x4F,0xA8,0x0E,0x89,0x25,0xFE,0x8E,0xAB,0x40,0x6E,0x17,0x14,0xAA,0xA8,
-    0x6C,0x79,0x52,0xDC,0xE3,0xDA,0x15,0xBF,0xAF,0x3C,0x96,0x2B,0xA3,0x4D,0xFA,0xC5,
-    0xB5,0x36,0xCD,0x2F,0x88,0xFF,0xD1,0x1E,0xB1,0xE6,0x7C,0x0E,0xBD,0x60,0x0A,0x78,
-    0xF7,0x8A,0x22,0x86,0xAD,0xC7,0x43,0x73,0xD7,0x22,0x64,0x32,0xA8,0xEC,0xEB,0x4F,
-    0x41,0x90,0xCC,0x2F,0xB5,0x1A,0xA4,0xE6,0x91,0x34,0x86,0xCA,0x0A,0x17,0x0B,0x28,
-    0x5F,0x94,0xAE,0x4C,0xDB,0x94,0x7A,0xD9,0xC3,0x4A,0x09,0x11,0xFA,0x33,0x6A,0x99,
-    0x85,0x66,0x12,0x0A,0x70,0x7D,0x99,0x88,0xBE,0xC8,0x4E,0xCF,0x01,0xD8,0xD1,0x54,
-    0x46,0x85,0x66,0x31,0x37,0xB3,0x7E,0x0F,0x45,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,
-    0x02,0x82,0x30,0x82,0x02,0x7E,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,
-    0x04,0x02,0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,
-    0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,0xD0,0xAD,0x5C,
-    0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x81,0x83,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x01,0x01,0x04,0x77,0x30,0x75,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
-    0x30,0x02,0x86,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x73,
-    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,
-    0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x2E,0x64,0x65,
-    0x72,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x2C,0x68,
-    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x61,0x70,0x70,0x6C,0x65,
-    0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x33,0x2D,0x63,0x6F,0x72,0x70,
-    0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x30,0x34,0x30,0x25,0x06,0x03,0x55,
-    0x1D,0x11,0x04,0x1E,0x30,0x1C,0x82,0x1A,0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,
-    0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,
-    0x6F,0x6D,0x30,0x82,0x01,0x12,0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x09,0x30,
-    0x82,0x01,0x05,0x30,0x82,0x01,0x01,0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,
-    0x05,0x0F,0x02,0x30,0x81,0xF2,0x30,0x81,0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
-    0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,0x63,
-    0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x65,0x72,0x74,0x69,0x66,
-    0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,0x20,0x61,0x6E,0x79,0x20,0x70,0x61,0x72,
-    0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,0x65,0x73,0x20,0x61,0x63,0x63,0x65,0x70,
-    0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,0x20,0x61,0x6E,0x79,0x20,0x61,0x70,0x70,
-    0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x74,0x65,0x72,0x6D,0x73,0x20,0x61,0x6E,
-    0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,0x20,
-    0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,0x6F,0x72,0x20,0x63,0x65,0x72,0x74,0x69,
-    0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x70,0x72,0x61,0x63,0x74,0x69,0x63,
-    0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x30,0x49,0x06,
-    0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x3D,0x68,0x74,0x74,0x70,0x73,
-    0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,
-    0x6E,0x61,0x67,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,
-    0x23,0x68,0x65,0x6C,0x70,0x2F,0x70,0x6F,0x6C,0x69,0x63,0x69,0x65,0x73,0x2F,0x63,
-    0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,
-    0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,
-    0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x3C,0x06,0x03,0x55,0x1D,0x1F,0x04,0x35,
-    0x30,0x33,0x30,0x31,0xA0,0x2F,0xA0,0x2D,0x86,0x2B,0x68,0x74,0x74,0x70,0x3A,0x2F,
-    0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,
-    0x70,0x70,0x6C,0x65,0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,
-    0x31,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
-    0x62,0xF3,0x37,0xB1,0x58,0x48,0x8F,0x49,0xEA,0x12,0x39,0x93,0x4C,0x17,0x91,0x07,
-    0x2F,0x71,0x09,0x4B,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
-    0x03,0x02,0x05,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
-    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xE3,0xCE,0x7C,0xAC,0x0A,0xDE,0x21,0xB9,
-    0xB0,0x9E,0x1C,0xE9,0x6B,0xD5,0xBC,0xB7,0x53,0xE7,0x16,0x62,0xB0,0x1D,0x3E,0x53,
-    0xFE,0x47,0x1A,0x1A,0xA3,0x7A,0x69,0xC5,0xC0,0x8B,0xC9,0x0B,0xE1,0xBC,0xF6,0xE6,
-    0xAC,0x7E,0x05,0x60,0xC2,0xC2,0x3C,0xBA,0xB4,0x39,0xF7,0xDD,0xA4,0x60,0xC8,0x5B,
-    0x29,0x90,0x59,0x29,0xCF,0xC1,0x6D,0x38,0x38,0x83,0x81,0xFA,0x8A,0xB6,0x13,0xE6,
-    0xC6,0xDA,0x64,0xD5,0x19,0x40,0x82,0x8C,0x38,0xC9,0xBE,0xC4,0x81,0xBA,0x88,0xC6,
-    0x62,0xEC,0x42,0xED,0xCE,0x22,0xD2,0x52,0xE2,0x96,0x8C,0x3C,0xBC,0xCA,0xD4,0xF0,
-    0xC8,0x24,0x09,0xA1,0xC6,0xD3,0x44,0x4F,0x22,0x36,0xF8,0x6F,0x28,0x20,0x9C,0x0C,
-    0x71,0x10,0xCC,0x13,0x46,0x40,0xCF,0x15,0xF6,0x16,0x59,0xB2,0xC4,0xE6,0xDA,0x3D,
-    0x9C,0xB4,0x01,0x33,0x4E,0x01,0x87,0xFC,0xEB,0x4B,0x45,0x0E,0x6C,0x14,0x93,0x48,
-    0xA0,0x78,0xFA,0x0C,0x01,0xB0,0xEB,0xF1,0x6F,0x7B,0xE9,0xF4,0xED,0x42,0x92,0x07,
-    0x3B,0xFC,0x14,0x15,0x69,0xE7,0x1E,0x33,0xD8,0x7C,0xE1,0xD6,0x37,0xBB,0x13,0x50,
-    0x3E,0x3C,0x4A,0xD4,0x29,0xC7,0x29,0x3B,0x99,0x79,0xD5,0x92,0x96,0x64,0x28,0x0A,
-    0x7A,0x4F,0x8C,0x4A,0x32,0xC6,0x49,0x9D,0x05,0x0E,0x25,0x2F,0x46,0x6D,0x60,0x83,
-    0xA6,0x06,0x05,0x07,0x3F,0x50,0xFF,0x01,0x6C,0x3E,0xE2,0x71,0x09,0x74,0xD2,0x94,
-    0xEB,0x17,0xF4,0xE7,0x2B,0xB0,0xFD,0x41,0x52,0xEF,0x25,0x71,0x9C,0x1C,0x36,0xA6,
-    0x05,0x15,0xA6,0xD5,0x1E,0x23,0xB7,0xC2,
-};
-
-#endif /* si_28_sectrustsettings_h */
diff --git a/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m b/OSX/sec/Security/Regressions/secitem/si-28-sectrustsettings.m
deleted file mode 100644 (file)
index 3e24ded..0000000
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (c) 2008-2010,2012,2016 Apple Inc. All Rights Reserved.
- */
-
-#include <Foundation/Foundation.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecItem.h>
-#include <Security/SecItemPriv.h>
-#include <Security/SecPolicy.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTrust.h>
-#include <Security/SecTrustSettings.h>
-#include <Security/SecTrustSettingsPriv.h>
-#include <Security/SecTrustPriv.h>
-#include <utilities/SecCFRelease.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#if TARGET_OS_IPHONE
-#include <Security/SecTrustStore.h>
-#else
-#include <Security/SecKeychain.h>
-#endif
-
-#include "shared_regressions.h"
-
-#include "si-28-sectrustsettings.h"
-
-/* Of course, the interface is different for OS X and iOS. */
-/* each call is 1 test */
-#define kNumberSetTSTests 1
-#if TARGET_OS_IPHONE
-#define setTS(cert, settings) \
-{ \
-    ok_status(SecTrustStoreSetTrustSettings(defaultStore, cert, settings), \
-        "set trust settings"); \
-}
-#else
-/* Use admin store on OS X to avoid user prompts.
- * Sleep a little so trustd has time to get the KeychainEvent. */
-#define setTS(cert, settings) \
-{ \
-    ok_status(SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin, \
-        settings), "set trust settings"); \
-    usleep(20000); \
-}
-#endif
-
-#if TARGET_OS_IPHONE
-#define setTSFail(cert, settings) \
-{ \
-    is(SecTrustStoreSetTrustSettings(defaultStore, cert, settings), errSecParam, \
-        "set trust settings"); \
-}
-#else
-#define setTSFail(cert, settings) \
-{ \
-    is(SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin, \
-        settings), errSecParam, "set trust settings"); \
-}
-#endif
-
-/* each call is 1 test */
-#define kNumberRemoveTSTests 1
-#if TARGET_OS_IPHONE
-#define removeTS(cert) \
-{ \
-    ok_status(SecTrustStoreRemoveCertificate(defaultStore, cert), \
-        "remove trust settings"); \
-}
-#else
-#define removeTS(cert) \
-{ \
-    ok_status(SecTrustSettingsRemoveTrustSettings(cert, kSecTrustSettingsDomainAdmin), \
-        "remove trust settings"); \
-}
-#endif
-
-/* each call is 4 tests */
-#define kNumberCheckTrustTests 4
-#define check_trust(certs, policy, valid_date, expected) \
-{ \
-    SecTrustRef trust = NULL; \
-    SecTrustResultType trust_result; \
-    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), \
-        "create trust with " #policy " policy"); \
-    ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)valid_date), \
-        "set trust verify date"); \
-    ok_status(SecTrustEvaluate(trust, &trust_result), "evaluate trust"); \
-    is(trust_result, expected, \
-        "check trust result for " #policy " policy"); \
-    CFReleaseSafe(trust); \
-}
-
-static SecCertificateRef cert0 = NULL;
-static SecCertificateRef cert1 = NULL;
-static SecCertificateRef cert2 = NULL;
-static SecCertificateRef cert3 = NULL;
-static SecPolicyRef sslPolicy = NULL;
-static SecPolicyRef smimePolicy = NULL;
-static SecPolicyRef basicPolicy = NULL;
-static CFArrayRef sslChain = NULL;
-static CFArrayRef smimeChain = NULL;
-static NSDate *verify_date = nil;
-
-#if TARGET_OS_IPHONE
-static SecTrustStoreRef defaultStore = NULL;
-#else
-#define kSystemLoginKeychainPath "/Library/Keychains/System.keychain"
-static NSMutableArray *deleteMeCertificates = NULL;
-#endif
-
-
-static void setup_globals(void) {
-
-    cert0 = SecCertificateCreateWithBytes(NULL, _trustSettingsRoot, sizeof(_trustSettingsRoot));
-    cert1 = SecCertificateCreateWithBytes(NULL, _trustSettingsInt, sizeof(_trustSettingsInt));
-    cert2 = SecCertificateCreateWithBytes(NULL, _trustSettingsSSLLeaf, sizeof(_trustSettingsSSLLeaf));
-    cert3 = SecCertificateCreateWithBytes(NULL, _trustSettingsSMIMELeaf, sizeof(_trustSettingsSMIMELeaf));
-
-    sslPolicy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com"));
-    smimePolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("username@apple.com"));
-    basicPolicy = SecPolicyCreateBasicX509();
-
-    const void *v_certs1[] = { cert2, cert1, cert0 };
-    sslChain = CFArrayCreate(NULL, v_certs1, sizeof(v_certs1)/sizeof(*v_certs1), &kCFTypeArrayCallBacks);
-
-    const void *v_certs2[] = { cert3, cert1, cert0 };
-    smimeChain = CFArrayCreate(NULL, v_certs2, sizeof(v_certs2)/sizeof(*v_certs2), &kCFTypeArrayCallBacks);
-
-    verify_date = [NSDate dateWithTimeIntervalSinceReferenceDate:482000000.0]; // Apr 10 2016
-
-#if TARGET_OS_IPHONE
-    defaultStore = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
-#else
-    /* Since we're putting trust settings in the admin domain,
-     * we need to add the certs to the system keychain. */
-    SecKeychainRef kcRef = NULL;
-    CFArrayRef certRef = NULL;
-    NSDictionary *attrs = nil;
-
-    SecKeychainOpen(kSystemLoginKeychainPath, &kcRef);
-    if (!kcRef) {
-        goto out;
-    }
-
-    deleteMeCertificates = [[NSMutableArray alloc] init];
-
-    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)cert0,
-              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
-              (__bridge NSString*)kSecReturnPersistentRef: @YES};
-    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
-        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
-    CFReleaseNull(certRef);
-
-    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)cert1,
-              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
-              (__bridge NSString*)kSecReturnPersistentRef: @YES};
-    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
-        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
-    CFReleaseNull(certRef);
-
-    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)cert2,
-                             (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
-                             (__bridge NSString*)kSecReturnPersistentRef: @YES};
-    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
-        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
-    CFReleaseNull(certRef);
-
-    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)cert3,
-              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
-              (__bridge NSString*)kSecReturnPersistentRef: @YES};
-    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
-        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
-    CFReleaseNull(certRef);
-
-    out:
-    CFReleaseNull(kcRef);
-#endif
-}
-
-static void cleanup_globals(void) {
-#if !TARGET_OS_IPHONE
-    [deleteMeCertificates enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
-        SecItemDelete((CFDictionaryRef)@{ (__bridge NSString*)kSecValuePersistentRef: [obj objectAtIndex:0]});
-    }];
-#endif
-
-    CFReleaseNull(cert0);
-    CFReleaseNull(cert1);
-    CFReleaseNull(cert2);
-    CFReleaseNull(cert3);
-    CFReleaseNull(sslPolicy);
-    CFReleaseNull(smimePolicy);
-    CFReleaseNull(basicPolicy);
-    CFReleaseNull(sslChain);
-    CFReleaseNull(smimeChain);
-}
-
-#define kNumberNoConstraintsTests (17+7*4)
-static void test_no_constraints(void) {
-    /* root with the default TrustRoot result succeeds */
-    setTS(cert0, NULL);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-
-    /* intermediate with the default TrustRoot result fails */
-    setTSFail(cert1, NULL);
-
-    /* root with TrustRoot result succeeds */
-    NSDictionary *trustRoot = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
-    setTS(cert0, (__bridge CFDictionaryRef)trustRoot);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-
-    /* intermediate with TrustRoot fails to set */
-    setTSFail(cert1, (__bridge CFDictionaryRef)trustRoot);
-
-    /* root with TrustAsRoot fails to set */
-    NSDictionary *trustAsRoot = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
-    setTSFail(cert0, (__bridge CFDictionaryRef)trustAsRoot);
-
-    /* intermediate with TrustAsRoot result succeeds */
-    setTS(cert1, (__bridge CFDictionaryRef)trustAsRoot);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert1);
-
-    /* trusting the root but denying the intermediate fails */
-    NSDictionary *deny = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)};
-    setTS(cert0, NULL);
-    setTS(cert1, (__bridge CFDictionaryRef)deny);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultDeny);
-    removeTS(cert1);
-    removeTS(cert0);
-
-    /* the unspecified result gives us default behavior */
-    NSDictionary *unspecified = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
-    setTS(cert1, (__bridge CFDictionaryRef)unspecified);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert1);
-
-    /* trusting one leaf doesn't make other leaf trusted */
-    setTS(cert2, (__bridge CFDictionaryRef)trustAsRoot);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    check_trust(smimeChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert2);
-}
-
-#define kNumberPolicyConstraintsTests (2+3*4)
-static void test_policy_constraints(void) {
-    /* Trust only for SSL server. SSL server policy succeeds. */
-    NSDictionary *sslServerAllowed = @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                        (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) };
-    setTS(cert1, (__bridge CFDictionaryRef)sslServerAllowed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
-
-    /* SSL client policy fails. */
-    SecPolicyRef sslClient = SecPolicyCreateSSL(false, NULL);
-    check_trust(sslChain, sslClient, verify_date, kSecTrustResultRecoverableTrustFailure);
-    CFReleaseNull(sslClient);
-
-    /* Basic policy fails */
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert1);
-}
-
-#define kNumberPolicyStringConstraintsTests (4+6*4)
-static void test_policy_string_constraints(void) {
-    NSArray *hostnameAllowed = @[ @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                     (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongname.apple.com"),
-                                     (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) },
-                                  @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                     (__bridge NSString*)kSecTrustSettingsPolicyString: @("testserver.apple.com"),
-                                     (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) }
-                                  ];
-    setTS(cert2, (__bridge CFArrayRef)hostnameAllowed);
-    /* evaluating against trusted hostname passes */
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
-
-    /* evaluating against hostname not in trust settings is recoverable failure */
-    SecPolicyRef weirdnamePolicy = SecPolicyCreateSSL(true, CFSTR("weirdname.apple.com"));
-    check_trust(sslChain, weirdnamePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    CFReleaseNull(weirdnamePolicy);
-
-    /* evaluating against hostname denied by trust settings is denied */
-    SecPolicyRef wrongnamePolicy = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
-    check_trust(sslChain, wrongnamePolicy, verify_date, kSecTrustResultDeny);
-    CFReleaseNull(wrongnamePolicy);
-    removeTS(cert2);
-
-    NSArray *emailAllowed = @[ @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)smimePolicy,
-                                  (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongemail@apple.com"),
-                                  (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) },
-                               @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)smimePolicy,
-                                  (__bridge NSString*)kSecTrustSettingsPolicyString: @("username@apple.com"),
-                                  (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) }
-                               ];
-    setTS(cert3, (__bridge CFArrayRef)emailAllowed);
-    /* evaluating against trusted email passes */
-    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultProceed);
-
-    /* evaluating against hostname not in trust settings is recoverable failure */
-    SecPolicyRef weirdemailPolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("weirdemail@apple.com"));
-    check_trust(smimeChain, weirdemailPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    CFReleaseNull(weirdemailPolicy);
-
-    /* evaluating against hostname denied by trust settings is denied */
-    SecPolicyRef wrongemailPolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("wrongemail@apple.com"));
-    check_trust(smimeChain, wrongemailPolicy, verify_date, kSecTrustResultDeny);
-    CFReleaseNull(wrongemailPolicy);
-    removeTS(cert3);
-}
-
-#if TARGET_OS_IPHONE
-#define kNumberApplicationsConstraintsTests 0
-static void test_application_constraints(void) {}
-#else
-#include <Security/SecTrustedApplicationPriv.h>
-#define kNumberApplicationsConstraintsTests (2+4+2*4)
-static void test_application_constraints(void) {
-    SecTrustedApplicationRef thisApp = NULL, someOtherApp = NULL;
-
-    ok_status(SecTrustedApplicationCreateFromPath(NULL, &thisApp),
-              "create TrustedApplicationRef for this app");
-    ok_status(SecTrustedApplicationCreateFromPath("/Applications/Safari.app", &someOtherApp),
-              "create TrustedApplicationRef for Safari");
-
-    NSDictionary *thisAppTS = @{ (__bridge NSString*)kSecTrustSettingsApplication: (__bridge id)thisApp,
-                                 (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
-
-    NSDictionary *someOtherAppTS = @{ (__bridge NSString*)kSecTrustSettingsApplication: (__bridge id)someOtherApp,
-                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
-
-    /* This application Trust Setting succeeds */
-    setTS(cert0, (__bridge CFDictionaryRef)thisAppTS);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-
-    /* Some other application Trust Setting fails */
-    setTS(cert0, (__bridge CFDictionaryRef)someOtherAppTS);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert0);
-
-    CFReleaseNull(thisApp);
-    CFReleaseNull(someOtherApp);
-}
-#endif
-
-#define kNumberKeyUsageConstraintsTests (14+11*4)
-static void test_key_usage_constraints(void) {
-    /* any key usage succeeds */
-    NSDictionary *anyKeyUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseAny),
-                                 (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
-    setTS(cert0, (__bridge CFDictionaryRef)anyKeyUse);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-
-    /* signCert key usage on an intermediate or root succeeds */
-    NSDictionary *signCertUseRoot = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignCert),
-                                   (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
-    setTS(cert0, (__bridge CFDictionaryRef)signCertUseRoot);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0)
-
-    NSDictionary *signCertUseInt = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignCert),
-                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
-    setTS(cert1, (__bridge CFDictionaryRef)signCertUseInt);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert1);
-
-    /* intermediate without signCert key usage fails */
-    NSDictionary *signatureUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignature),
-                                   (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
-    setTS(cert1, (__bridge CFDictionaryRef)signatureUse);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert1);
-
-    /* brief interlude to create a bunch of SMIME policies with different key usages */
-    SecPolicyRef smimeSignature = SecPolicyCreateSMIME(kSecSignSMIMEUsage, CFSTR("username@apple.com"));
-    SecPolicyRef smimeDataEncrypt = SecPolicyCreateSMIME(kSecDataEncryptSMIMEUsage, CFSTR("username@apple.com"));
-    SecPolicyRef smimeKeyEncrypt = SecPolicyCreateSMIME(kSecKeyEncryptSMIMEUsage, CFSTR("username@apple.com"));
-    SecPolicyRef smimeKeyExchange = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, CFSTR("username@apple.com"));
-    SecPolicyRef smimeMultiple = SecPolicyCreateSMIME((kSecSignSMIMEUsage | kSecKeyEncryptSMIMEUsage),
-                                                      CFSTR("username@apple.com"));
-
-    /* signature smime policy passes for signature use TS*/
-    setTS(cert3, (__bridge CFDictionaryRef)signatureUse);
-    check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultProceed);
-
-    /* any use policy fails for signature use TS */
-    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-
-    /* multiple use smime policy against signature use */
-    check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert3);
-
-    /* key encrypt smime policy passes for key encrypt use */
-    NSDictionary *keyEncryptUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseEnDecryptKey),
-                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
-    setTS(cert3, (__bridge CFDictionaryRef)keyEncryptUse);
-    check_trust(smimeChain, smimeKeyEncrypt, verify_date, kSecTrustResultProceed);
-    removeTS(cert3);
-
-    /* multiple use smime policy against multiple uses */
-    NSDictionary *multipleUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseEnDecryptKey |
-                                       kSecTrustSettingsKeyUseSignature),
-                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
-    setTS(cert3, (__bridge CFDictionaryRef)multipleUse)
-    check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultProceed);
-
-    /* signature smime policy against multiple uses */
-    check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultRecoverableTrustFailure);
-
-    /* any use smime policy against multiple uses */
-    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert3);
-
-    CFReleaseNull(smimeSignature);
-    CFReleaseNull(smimeDataEncrypt);
-    CFReleaseNull(smimeKeyEncrypt);
-    CFReleaseNull(smimeKeyExchange);
-    CFReleaseNull(smimeMultiple);
-}
-
-#define kNumberAllowedErrorsTests (14+8*4)
-static void test_allowed_errors(void) {
-    setTS(cert0, NULL);
-
-    /* allow expired errors */
-    NSDate *expired_date = [NSDate dateWithTimeIntervalSinceReferenceDate:520000000.0]; // Jun 24 2017
-    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultRecoverableTrustFailure);
-
-    NSDictionary *allowExpired = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147409654),
-                                    (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
-    setTS(cert1, (__bridge CFDictionaryRef)allowExpired)
-    setTS(cert2, (__bridge CFDictionaryRef)allowExpired);
-    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultProceed);
-    removeTS(cert2);
-    removeTS(cert1);
-
-    /* allow hostname mismatch errors */
-    SecPolicyRef wrongNameSSL = NULL;
-    wrongNameSSL = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
-    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultRecoverableTrustFailure);
-
-    NSDictionary *allowHostnameMismatch = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408896),
-                                             (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) };
-    setTS(cert2, (__bridge CFDictionaryRef)allowHostnameMismatch);
-    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
-    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed);
-    removeTS(cert2);
-    CFReleaseNull(wrongNameSSL);
-
-    /* allow email mismatch errors */
-    SecPolicyRef wrongNameSMIME = NULL;
-    wrongNameSMIME = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("test@apple.com"));
-    check_trust(smimeChain, wrongNameSMIME, verify_date, kSecTrustResultRecoverableTrustFailure);
-
-    NSDictionary *allowEmailMismatch = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408872),
-                                          (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) };
-    setTS(cert3, (__bridge CFDictionaryRef)allowEmailMismatch);
-    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
-    check_trust(smimeChain, wrongNameSMIME, verify_date, kSecTrustResultProceed);
-    removeTS(cert3);
-    CFReleaseNull(wrongNameSMIME);
-
-    /* allowed error with a policy constraint */
-    NSDictionary *allowExpiredConstrained = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147409654),
-                                               (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
-    setTS(cert1, (__bridge CFDictionaryRef)allowExpiredConstrained)
-    setTS(cert2, (__bridge CFDictionaryRef)allowExpiredConstrained);
-    check_trust(sslChain, sslPolicy, expired_date, kSecTrustResultProceed);
-    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert2);
-    removeTS(cert1);
-
-    removeTS(cert0);
-}
-
-#define kNumberMultipleConstraintsTests (8+9*4)
-static void test_multiple_constraints(void) {
-    /* deny all but */
-    NSArray *denyAllBut = @[
-                            @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy ,
-                              (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)},
-                            @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) }
-                            ];
-    setTS(cert0, (__bridge CFArrayRef)denyAllBut);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultDeny);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-
-    /* allow all but */
-    NSArray *allowAllBut = @[
-                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy ,
-                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
-                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
-                             ];
-    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert0);
-
-    /* different results for specific policies */
-    NSArray *specifyPolicyResult = @[
-                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)},
-                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)basicPolicy,
-                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
-                                     ];
-    setTS(cert0, (__bridge CFArrayRef)specifyPolicyResult);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultDeny);
-    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert0);
-
-    /* different results for additional constraint with same policy */
-    NSArray *policyConstraintResult = @[
-                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                       (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongname.apple.com"),
-                                       (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408896),
-                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)},
-                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy,
-                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) }
-                                     ];
-    SecPolicyRef wrongNameSSL = NULL;
-    wrongNameSSL = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
-    setTS(cert2, (__bridge CFArrayRef)policyConstraintResult);
-    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
-    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-    removeTS(cert2);
-    CFReleaseNull(wrongNameSSL);
-
-}
-
-#define kNumberChangeConstraintsTests (2*kNumberSetTSTests + kNumberRemoveTSTests + 4*kNumberCheckTrustTests)
-static void test_change_constraints(void) {
-    /* allow all but */
-    NSArray *allowAllBut = @[
-                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy ,
-                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
-                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
-                             ];
-    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
-
-    /* Don't clear trust settings. Just change them. */
-
-    /* root with the default TrustRoot result succeeds */
-    setTS(cert0, NULL);
-    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
-    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
-    removeTS(cert0);
-}
-
-#define kNumberPolicyNamePinnningConstraintsTests (kNumberSetTSTests + kNumberRemoveTSTests + 5)
-static void test_policy_name_pinning_constraints(void) {
-    /* allow all but */
-    NSArray *allowAllBut = @[
-                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslPolicy ,
-                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
-                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
-                             ];
-    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
-
-    SecTrustRef trust = NULL;
-    SecTrustResultType trust_result;
-    ok_status(SecTrustCreateWithCertificates(sslChain, sslPolicy, &trust), "create trust with ssl policy");
-    ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verify_date), "set trust verify date");
-    ok_status(SecTrustSetPinningPolicyName(trust, CFSTR("not-a-db-policy-name")), "set policy name");
-    ok_status(SecTrustEvaluate(trust, &trust_result), "evaluate trust");
-    is(trust_result, kSecTrustResultRecoverableTrustFailure, "check trust result for sslServer policy with policy name");
-    CFReleaseSafe(trust);
-
-    removeTS(cert0);
-}
-
-
-int si_28_sectrustsettings(int argc, char *const *argv)
-{
-    plan_tests(kNumberNoConstraintsTests
-               + kNumberPolicyConstraintsTests
-               + kNumberPolicyStringConstraintsTests
-               + kNumberApplicationsConstraintsTests
-               + kNumberKeyUsageConstraintsTests
-               + kNumberAllowedErrorsTests
-               + kNumberMultipleConstraintsTests
-               + kNumberChangeConstraintsTests
-               + kNumberPolicyNamePinnningConstraintsTests
-               );
-
-#if !TARGET_OS_IPHONE
-    if (getuid() != 0) {
-        printf("Test must be run as root on OS X");
-        return 0;
-    }
-#endif
-
-    @autoreleasepool {
-        setup_globals();
-        test_no_constraints();
-        test_policy_constraints();
-        test_policy_string_constraints();
-        test_application_constraints();
-        test_key_usage_constraints();
-        test_allowed_errors();
-        test_multiple_constraints();
-        test_change_constraints();
-        test_policy_name_pinning_constraints();
-        cleanup_globals();
-    }
-
-    return 0;
-}
index f66bb236c2d7de42c48cbb2e729667782174ffb0..e2555dd7998bf9768f0e3619ed1e48a558c8928a 100644 (file)
 #ifndef _SECURITY_SI_32_SECTRUST_PINNING_REQUIRED_H_
 #define _SECURITY_SI_32_SECTRUST_PINNING_REQUIRED_H_
 
-/* subject:/CN=profile.ess.apple.com/O=Apple Inc./ST=California/C=US */
+/* subject:/CN=init.ess.apple.com/O=Apple Inc./ST=California/C=US */
 /* issuer :/CN=Test Apple Server Authentication CA/OU=Certification Authority/O=Apple Inc./C=US */
 uint8_t _ids_test[]={
-    0x30,0x82,0x04,0x76,0x30,0x82,0x03,0x5E,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x24,
-    0x1F,0x1C,0x82,0xF4,0x25,0x42,0xB4,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x30,0x82,0x04,0x87,0x30,0x82,0x03,0x6F,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x72,
+    0xA1,0xD2,0xCA,0x8B,0x32,0x32,0xCB,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
     0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x72,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,
     0x03,0x0C,0x23,0x54,0x65,0x73,0x74,0x20,0x41,0x70,0x70,0x6C,0x65,0x20,0x53,0x65,
     0x72,0x76,0x65,0x72,0x20,0x41,0x75,0x74,0x68,0x65,0x6E,0x74,0x69,0x63,0x61,0x74,
@@ -36,69 +36,70 @@ uint8_t _ids_test[]={
     0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
     0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
     0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
-    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,
-    0x30,0x38,0x30,0x37,0x30,0x31,0x30,0x35,0x33,0x37,0x5A,0x17,0x0D,0x31,0x39,0x30,
-    0x39,0x30,0x36,0x30,0x31,0x30,0x35,0x33,0x37,0x5A,0x30,0x57,0x31,0x1E,0x30,0x1C,
-    0x06,0x03,0x55,0x04,0x03,0x0C,0x15,0x70,0x72,0x6F,0x66,0x69,0x6C,0x65,0x2E,0x65,
-    0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x13,0x30,0x11,
-    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
-    0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,
-    0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
-    0x02,0x55,0x53,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,0xDA,0xEE,0xCE,0x4F,0x0A,0x31,0xF5,0x6A,0x6C,0xD8,0xD8,0xF9,
-    0x1E,0x4D,0x85,0x38,0x17,0x42,0x45,0xBA,0xF2,0x8C,0x16,0xC2,0xEC,0x29,0x84,0x88,
-    0xC2,0xC2,0x45,0xCB,0x79,0xF6,0x7F,0x89,0x65,0x3D,0x98,0xED,0xE7,0x21,0xA8,0xAB,
-    0x4C,0xE2,0x75,0x7C,0x5B,0x26,0x00,0xC4,0x4C,0x81,0xE4,0xFF,0xA4,0xBB,0xA6,0x0F,
-    0x80,0x9D,0xD9,0xD5,0xA3,0xD2,0x5C,0xA1,0x25,0xE1,0x9F,0xB5,0x53,0xF3,0x31,0x3B,
-    0xCB,0x55,0xC2,0x75,0xFB,0xC7,0x3B,0x3C,0x07,0x6B,0x29,0xAF,0x43,0x90,0x1E,0x9B,
-    0xC3,0x47,0x0C,0x09,0xDF,0x07,0x9C,0xA8,0x12,0x3E,0x9E,0xFE,0x29,0xE7,0x11,0x06,
-    0xA1,0x1D,0x8C,0xEA,0x99,0x73,0xD5,0x13,0x66,0x51,0x0D,0x3D,0x6B,0x67,0x38,0x68,
-    0x04,0x40,0xE8,0x1E,0x50,0x56,0x59,0x77,0x5A,0xF3,0x12,0xAC,0x2B,0x93,0xF8,0xBC,
-    0x87,0xA6,0x70,0x3F,0xB8,0x8F,0xE2,0xEC,0x38,0x5F,0xB4,0x73,0xE6,0x95,0x38,0xD1,
-    0x31,0x16,0xFE,0xFF,0x77,0x01,0xD2,0xD0,0x2F,0xF4,0xF7,0x3A,0x21,0x5B,0xA8,0x36,
-    0xC4,0xE4,0x58,0x26,0x3D,0x6F,0xFF,0xA0,0x39,0x45,0x83,0xCB,0x66,0xF5,0x4C,0xC6,
-    0x43,0x67,0x1C,0x58,0x72,0x5B,0xCC,0xAA,0x15,0x91,0x4D,0xE6,0x24,0xF6,0x18,0xFE,
-    0xF5,0xEF,0x75,0xB4,0x5B,0xF1,0x86,0x2F,0x67,0x0A,0x5B,0x7D,0x8E,0x22,0x1B,0x2F,
-    0xFA,0xE2,0xB1,0x41,0x37,0x4D,0x26,0xD6,0x9B,0x13,0x66,0x5F,0xE5,0xCD,0x4B,0xC9,
-    0x91,0x62,0xF9,0x98,0x8E,0x7F,0xB6,0x6F,0x7A,0xFF,0x95,0xF1,0x0B,0x1C,0x1F,0xFB,
-    0xD1,0x49,0xB7,0xFD,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x29,0x30,0x82,0x01,
-    0x25,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
-    0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xA8,0xCA,0x7A,0x9B,
-    0xA8,0x37,0x71,0x9E,0x3D,0xEC,0x5A,0xAB,0x66,0x2E,0xDC,0xD7,0x14,0x3D,0x7B,0xF2,
-    0x30,0x52,0x06,0x03,0x55,0x1D,0x11,0x04,0x4B,0x30,0x49,0x82,0x18,0x6F,0x70,0x65,
-    0x6E,0x6D,0x61,0x72,0x6B,0x65,0x74,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,
-    0x65,0x2E,0x63,0x6F,0x6D,0x82,0x16,0x69,0x64,0x65,0x6E,0x74,0x69,0x74,0x79,0x2E,
-    0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x15,0x70,
-    0x72,0x6F,0x66,0x69,0x6C,0x65,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,
-    0x2E,0x63,0x6F,0x6D,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,
-    0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x49,0x06,0x03,0x55,0x1D,0x1F,
-    0x04,0x42,0x30,0x40,0x30,0x3E,0xA0,0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,0x70,
-    0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x75,0x61,0x74,0x2E,0x63,0x6F,0x72,0x70,0x2E,
-    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x74,0x65,0x73,0x74,0x61,0x70,
-    0x70,0x6C,0x65,0x73,0x65,0x72,0x76,0x65,0x72,0x61,0x75,0x74,0x68,0x63,0x61,0x31,
-    0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x3F,
-    0x0C,0x0D,0xC7,0x17,0x81,0x02,0x61,0x50,0x18,0xFC,0xAF,0xBD,0xA0,0xA8,0x4E,0x78,
-    0xA7,0xFB,0xF1,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,
-    0x02,0x05,0xA0,0x30,0x11,0x06,0x0B,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x06,0x1B,
-    0x04,0x02,0x04,0x02,0x05,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
-    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x53,0x88,0x1A,0x2C,0x60,0xFB,
-    0x15,0x08,0x83,0x06,0xE4,0xF7,0x23,0x38,0x50,0xA6,0xD3,0xA7,0xBD,0x06,0xB4,0xAF,
-    0x87,0x4F,0x13,0xC6,0x1B,0x79,0x2C,0x80,0x30,0x7E,0x23,0x0D,0x4E,0x6A,0xC3,0x9B,
-    0xF8,0x73,0x1E,0x7B,0xD7,0x14,0xB0,0x5F,0xA8,0xEC,0xB4,0x0D,0xBD,0x3B,0x40,0x87,
-    0x9A,0x4D,0x1D,0x2D,0x8F,0x00,0xCE,0x72,0xDE,0xAF,0x2E,0x73,0x82,0x54,0xBA,0x0E,
-    0x3A,0xC2,0xAB,0x7C,0x09,0xE8,0xBE,0x0B,0x26,0x0F,0xC3,0x80,0xCD,0x9C,0x85,0x09,
-    0xA3,0xD3,0xB5,0xCE,0x7D,0x63,0xB3,0x33,0x32,0x06,0xD9,0xAE,0xA9,0x7D,0x1E,0x2F,
-    0xF9,0x1B,0x60,0x3F,0x1F,0xFA,0x57,0x17,0xC6,0x5A,0x28,0x44,0x24,0x36,0xF4,0x77,
-    0xE6,0x91,0x7D,0xED,0x45,0x28,0x59,0x3E,0xA1,0x03,0x3E,0x45,0x3F,0x41,0x8E,0x62,
-    0x0A,0x21,0xD8,0x47,0xED,0xFA,0x53,0x4F,0x07,0x7D,0xF6,0xFC,0xE1,0x98,0xC0,0x0C,
-    0xAA,0x68,0xD2,0xB7,0xCD,0x7D,0xF5,0x55,0xD7,0x56,0x55,0x78,0x56,0x80,0x8A,0x30,
-    0x89,0x30,0x2C,0xA9,0x8A,0x71,0xD1,0x4E,0x05,0x4A,0x5E,0xDB,0x23,0x2F,0xC9,0xA1,
-    0x45,0xF9,0xF1,0x16,0xE1,0x72,0xA5,0xD7,0xB1,0x32,0xB3,0x90,0x4B,0xF8,0x72,0xD6,
-    0xF3,0x65,0x84,0x0F,0xB6,0x23,0x41,0x4D,0xE3,0xDD,0xC0,0x5B,0xB7,0xF8,0x1C,0xF2,
-    0x1F,0xB5,0x5D,0xD0,0xFB,0xB9,0x7D,0x0D,0x34,0xC4,0x61,0x42,0x8E,0xD4,0xED,0x4C,
-    0xA4,0x83,0x9C,0x8D,0xBA,0xE3,0x49,0x45,0x07,0xE4,0x0E,0x0E,0x01,0x10,0x93,0xCF,
-    0x49,0x39,0x4C,0x1C,0x0A,0x88,0xC3,0x2E,0x7C,0x64,
+    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,0x17,0x0D,0x32,0x30,
+    0x30,0x39,0x31,0x33,0x32,0x33,0x34,0x30,0x31,0x37,0x5A,0x17,0x0D,0x32,0x31,0x31,
+    0x30,0x31,0x33,0x32,0x33,0x34,0x30,0x31,0x37,0x5A,0x30,0x54,0x31,0x1B,0x30,0x19,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x12,0x69,0x6E,0x69,0x74,0x2E,0x65,0x73,0x73,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
+    0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,
+    0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
+    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,0xA0,0x86,0xAC,0xB1,0xE9,0xAE,0xD2,0x94,0x23,0x46,0x80,0x95,0x7E,0x25,0x89,
+    0x43,0x0F,0x8B,0xA2,0x60,0x49,0xCB,0x1C,0xA4,0x33,0x3C,0x7E,0x27,0x7C,0xA2,0x04,
+    0x88,0x90,0xD0,0x1D,0xCA,0x67,0x6F,0xFE,0xF0,0xB9,0x68,0xF9,0x7A,0x7E,0xD3,0xA2,
+    0x96,0x27,0xFD,0x42,0x1F,0x67,0x27,0x72,0x31,0x68,0x71,0x98,0x71,0x58,0x62,0x05,
+    0x83,0xCC,0xC8,0x48,0x96,0x3C,0x96,0x73,0x13,0x4C,0x5B,0x22,0x12,0xBF,0x42,0xEB,
+    0x1F,0x4B,0x7F,0x2F,0xC9,0x92,0x08,0x41,0x2A,0xFD,0xF9,0xA7,0xF2,0x36,0xC6,0x7D,
+    0xAB,0x25,0xA1,0x5B,0x26,0x30,0x7F,0x4A,0x19,0xEE,0xDB,0x26,0x5C,0x22,0x68,0x1D,
+    0xFC,0x81,0x7D,0x1B,0x76,0xFA,0x98,0x16,0xDE,0x3B,0xC3,0x6F,0x8B,0x14,0x01,0xDF,
+    0xD8,0x34,0x37,0x4A,0x2A,0x2A,0xE9,0xCE,0x78,0x58,0x40,0x41,0x14,0x1F,0xDD,0x86,
+    0x30,0xD3,0xBD,0xA5,0x02,0x5E,0xFD,0x40,0xDF,0x2D,0xDA,0x6C,0x1C,0xD8,0x7F,0x92,
+    0xBB,0xA4,0xF9,0x8B,0x3A,0xDE,0xAE,0xA7,0x23,0x5C,0x2B,0x9C,0x2F,0x9A,0xFD,0x0E,
+    0xF5,0xFE,0x40,0x7F,0x5C,0x7C,0xA9,0x01,0xE2,0x11,0x21,0x96,0xFA,0xEF,0x2B,0x0C,
+    0x95,0x7E,0x96,0x2D,0xA0,0xA9,0x15,0x7A,0x82,0x25,0x83,0x12,0xD6,0x83,0x0A,0x91,
+    0xA5,0xD7,0xF2,0xCB,0xC3,0x18,0x4E,0xF4,0xA1,0xA1,0x0A,0xD1,0x7E,0x88,0x1C,0xB1,
+    0x10,0xA9,0x83,0xE3,0xAD,0xF7,0xFF,0xEA,0xDC,0x20,0xEB,0x74,0x94,0xE0,0x89,0xDF,
+    0x34,0x25,0x28,0x58,0xE9,0xC8,0x93,0x84,0x2D,0x24,0xB0,0xDC,0xD2,0x46,0x09,0x63,
+    0x5F,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x01,0x3D,0x30,0x82,0x01,0x39,0x30,0x0C,
+    0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x1F,0x06,0x03,
+    0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xA8,0xCA,0x7A,0x9B,0xA8,0x37,0x71,
+    0x9E,0x3D,0xEC,0x5A,0xAB,0x66,0x2E,0xDC,0xD7,0x14,0x3D,0x7B,0xF2,0x30,0x66,0x06,
+    0x03,0x55,0x1D,0x11,0x04,0x5F,0x30,0x5D,0x82,0x15,0x70,0x72,0x6F,0x66,0x69,0x6C,
+    0x65,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,
+    0x18,0x6F,0x70,0x65,0x6E,0x6D,0x61,0x72,0x6B,0x65,0x74,0x2E,0x65,0x73,0x73,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x82,0x16,0x69,0x64,0x65,0x6E,0x74,
+    0x69,0x74,0x79,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
+    0x6D,0x82,0x12,0x69,0x6E,0x69,0x74,0x2E,0x65,0x73,0x73,0x2E,0x61,0x70,0x70,0x6C,
+    0x65,0x2E,0x63,0x6F,0x6D,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,
+    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x49,0x06,0x03,0x55,0x1D,
+    0x1F,0x04,0x42,0x30,0x40,0x30,0x3E,0xA0,0x3C,0xA0,0x3A,0x86,0x38,0x68,0x74,0x74,
+    0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2D,0x75,0x61,0x74,0x2E,0x63,0x6F,0x72,0x70,
+    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x74,0x65,0x73,0x74,0x61,
+    0x70,0x70,0x6C,0x65,0x73,0x65,0x72,0x76,0x65,0x72,0x61,0x75,0x74,0x68,0x63,0x61,
+    0x31,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
+    0x74,0x05,0xFF,0xDB,0xBE,0x4A,0xC9,0x3B,0x54,0x77,0xAE,0x4E,0x60,0xB2,0xD1,0x47,
+    0x70,0xCE,0x35,0xDB,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
+    0x03,0x02,0x05,0xA0,0x30,0x11,0x06,0x0B,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x06,
+    0x1B,0x04,0x02,0x04,0x02,0x05,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xAB,0x83,0x22,0x06,0x14,
+    0x92,0x90,0x4F,0xFF,0x87,0x9F,0xF5,0x69,0xFE,0x87,0x14,0xAD,0x58,0x47,0x86,0x17,
+    0x48,0x90,0xAA,0x34,0x37,0x23,0x7E,0x37,0x93,0x5D,0xCA,0xFF,0xEF,0x97,0x13,0x2B,
+    0xFF,0x82,0x51,0xCA,0x87,0xF0,0xE1,0x1C,0x8C,0x95,0xE3,0x96,0x2D,0x69,0x6B,0x8C,
+    0xFA,0xCC,0x57,0x20,0x35,0x98,0x31,0x83,0x30,0xF3,0x62,0xE8,0xD0,0xAB,0xBE,0xE3,
+    0xFB,0x68,0xB4,0xBD,0x10,0xFC,0xDD,0x4B,0x5A,0x07,0x51,0x91,0x29,0xA6,0x6F,0x84,
+    0x42,0xD8,0xAE,0xF2,0x3A,0xD2,0xA2,0xB4,0xB6,0xAB,0x32,0x24,0xE3,0xFD,0x57,0x8E,
+    0x53,0xDD,0x53,0x7D,0x6E,0xE4,0x76,0x80,0x13,0xB9,0xF4,0x12,0x03,0xB4,0xB6,0x6D,
+    0x3C,0xCA,0x9C,0x08,0x37,0xF2,0xD8,0x97,0x62,0x1C,0xC9,0xFF,0x4B,0x8E,0x7A,0xA4,
+    0x07,0x66,0x98,0xB9,0x95,0xB2,0xA2,0xD4,0xF1,0x4E,0x0B,0xC9,0xC1,0xEB,0x10,0x21,
+    0xA3,0xFD,0x69,0xF4,0x64,0xF0,0x55,0x7E,0xFB,0x3C,0x5D,0x4A,0xF2,0x65,0xB1,0x67,
+    0x68,0x59,0xE6,0xE1,0x9F,0x93,0xDD,0x2A,0x44,0x76,0x85,0x16,0x82,0x6A,0x1E,0xA6,
+    0x37,0xE8,0xD0,0x16,0x73,0x03,0xBE,0x88,0xBC,0x50,0x97,0xA3,0xC2,0xB9,0x65,0xF1,
+    0x64,0x92,0x57,0x04,0xAD,0xE6,0x77,0x3F,0x1B,0xA4,0xE3,0xF2,0xBE,0x41,0xA6,0x66,
+    0x9E,0xC6,0xF5,0x07,0xE8,0x9B,0x13,0x34,0x06,0x55,0x45,0x37,0x88,0x65,0x4F,0x4C,
+    0x11,0xE0,0x02,0xD7,0xE8,0xC3,0x1B,0x4D,0xCD,0x31,0x59,0x55,0x90,0xA3,0x6A,0x40,
+    0x31,0xAD,0x92,0x86,0xFE,0x53,0xC5,0xB8,0x5E,0xA3,0x02,
 };
 
 /* subject:/CN=Test Apple Server Authentication CA/OU=Certification Authority/O=Apple Inc./C=US */
index 4e44d3142e23d95808891ca48fc13c730a349f09..d55365383519969e5e22689dbd100e433fcb801f 100644 (file)
@@ -47,7 +47,7 @@ static void setup_globals(void) {
 
     certs = @[(__bridge id)leaf,(__bridge id)intermediate];
     root = @[(__bridge id)rootcert];
-    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:560000000.0]; //September 30, 2018 at 4:33:20 AM PDT
+    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:622000000.0]; //September 16, 2020 at 6:46:40 PM PDT
 
     CFReleaseNull(leaf);
     CFReleaseNull(intermediate);
@@ -84,11 +84,12 @@ static void tests(void)
 {
     SecPolicyRef policy = NULL;
 
-    policy = SecPolicyCreateSSL(true, CFSTR("openmarket.ess.apple.com"));
+    // init domains are excluded from IDS pinning rules
+    policy = SecPolicyCreateSSL(true, CFSTR("init.ess.apple.com"));
     SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
     is(test_with_policy(policy), kSecTrustResultRecoverableTrustFailure, "Unpinned connection succeeeded when pinning required");
 
-    policy = SecPolicyCreateAppleIDSServiceContext(CFSTR("openmarket.ess.apple.com"), NULL);
+    policy = SecPolicyCreateAppleIDSServiceContext(CFSTR("init.ess.apple.com"), NULL);
     SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
     is(test_with_policy(policy), kSecTrustResultUnspecified, "Policy pinned connection failed when pinning required");
 
@@ -97,14 +98,14 @@ static void tests(void)
     is(test_with_policy(policy), kSecTrustResultUnspecified, "Systemwide hostname pinned connection failed when pinning required");
 
     NSDictionary *policy_properties = @{
-                                        (__bridge NSString *)kSecPolicyName : @"openmarket.ess.apple.com",
+                                        (__bridge NSString *)kSecPolicyName : @"init.ess.apple.com",
                                         (__bridge NSString *)kSecPolicyPolicyName : @"IDS",
                                         };
     policy = SecPolicyCreateWithProperties(kSecPolicyAppleSSL, (__bridge CFDictionaryRef)policy_properties);
     SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
     is(test_with_policy(policy), kSecTrustResultUnspecified, "Systemwide policy name pinned connection failed when pinning required");
 
-    policy = SecPolicyCreateSSL(true, CFSTR("openmarket.ess.apple.com"));
+    policy = SecPolicyCreateSSL(true, CFSTR("init.ess.apple.com"));
     SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
     is(test_with_policy_exception(policy, true), kSecTrustResultUnspecified, "Unpinned connection failed when pinning exception set");
 
index af261c722c3f3bd428b8546a7213fe0514c18576..d06ddf5bc24fc5cd81b3d1ebde52d9706108f159 100644 (file)
@@ -174,18 +174,16 @@ exit:
     CFReleaseNull(identity);
 }
 
-static int ping_host(char *host_name){
-
+static int ping_host(char *host_name) {
     struct sockaddr_in pin;
     struct hostent *nlp_host;
+    struct in_addr addr;
     int sd;
-    int port;
-    int retries = 5;
-
-    port=80;
+    int port = 80;
+    int retries = 5; // tries 5 times then gived up
+    char **h_addr_list = NULL;
 
-    //tries 5 times then give up
-    while ((nlp_host=gethostbyname(host_name))==0 && retries--){
+    while ((nlp_host=gethostbyname(host_name)) == 0 && retries--) {
         printf("Resolve Error! (%s) %d\n", host_name, h_errno);
         sleep(1);
     }
@@ -196,20 +194,23 @@ static int ping_host(char *host_name){
     bzero(&pin,sizeof(pin));
     pin.sin_family=AF_INET;
     pin.sin_addr.s_addr=htonl(INADDR_ANY);
-    pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
+    h_addr_list = malloc(nlp_host->h_length * sizeof(char *));
+    memcpy(h_addr_list, nlp_host->h_addr_list, nlp_host->h_length * sizeof(char *));
+    memcpy(&addr, h_addr_list[0], sizeof(struct in_addr));
+    pin.sin_addr.s_addr=addr.s_addr;
     pin.sin_port=htons(port);
 
     sd=socket(AF_INET,SOCK_STREAM,0);
 
-    if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
+    if (connect(sd,(struct sockaddr*)&pin,sizeof(pin)) == -1) {
         printf("connect error! (%s) %d\n", host_name, errno);
         close(sd);
+        free(h_addr_list);
         return 0;
     }
-    else{
-        close(sd);
-        return 1;
-    }
+    close(sd);
+    free(h_addr_list);
+    return 1;
 }
 
 int si_34_cms_timestamp(int argc, char * const *argv) {
index 0ad24d90bb7bc728ab371d1624f9066649915f0a..6e61e2db331467377693f7f6d270aa952da92306 100644 (file)
@@ -1805,6 +1805,79 @@ unsigned char __9148843_bin[] = {
 };
 unsigned int __9148843_bin_len = 4326;
 
+/* subject:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */
+/* issuer :/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root */
+const uint8_t __9148843_root[] = {
+    0x30,0x82,0x04,0x36,0x30,0x82,0x03,0x1E,0xA0,0x03,0x02,0x01,0x02,0x02,0x01,0x01,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,
+    0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,0x14,
+    0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,0x73,
+    0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,
+    0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30,0x20,
+    0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,
+    0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,
+    0x30,0x1E,0x17,0x0D,0x30,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,
+    0x5A,0x17,0x0D,0x32,0x30,0x30,0x35,0x33,0x30,0x31,0x30,0x34,0x38,0x33,0x38,0x5A,
+    0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,0x45,0x31,
+    0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,0x72,0x75,
+    0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,0x13,0x1D,
+    0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,
+    0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x22,0x30,
+    0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,
+    0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,0x6F,0x6F,
+    0x74,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,0xB7,0xF7,0x1A,0x33,0xE6,0xF2,0x00,0x04,0x2D,0x39,0xE0,0x4E,0x5B,0xED,
+    0x1F,0xBC,0x6C,0x0F,0xCD,0xB5,0xFA,0x23,0xB6,0xCE,0xDE,0x9B,0x11,0x33,0x97,0xA4,
+    0x29,0x4C,0x7D,0x93,0x9F,0xBD,0x4A,0xBC,0x93,0xED,0x03,0x1A,0xE3,0x8F,0xCF,0xE5,
+    0x6D,0x50,0x5A,0xD6,0x97,0x29,0x94,0x5A,0x80,0xB0,0x49,0x7A,0xDB,0x2E,0x95,0xFD,
+    0xB8,0xCA,0xBF,0x37,0x38,0x2D,0x1E,0x3E,0x91,0x41,0xAD,0x70,0x56,0xC7,0xF0,0x4F,
+    0x3F,0xE8,0x32,0x9E,0x74,0xCA,0xC8,0x90,0x54,0xE9,0xC6,0x5F,0x0F,0x78,0x9D,0x9A,
+    0x40,0x3C,0x0E,0xAC,0x61,0xAA,0x5E,0x14,0x8F,0x9E,0x87,0xA1,0x6A,0x50,0xDC,0xD7,
+    0x9A,0x4E,0xAF,0x05,0xB3,0xA6,0x71,0x94,0x9C,0x71,0xB3,0x50,0x60,0x0A,0xC7,0x13,
+    0x9D,0x38,0x07,0x86,0x02,0xA8,0xE9,0xA8,0x69,0x26,0x18,0x90,0xAB,0x4C,0xB0,0x4F,
+    0x23,0xAB,0x3A,0x4F,0x84,0xD8,0xDF,0xCE,0x9F,0xE1,0x69,0x6F,0xBB,0xD7,0x42,0xD7,
+    0x6B,0x44,0xE4,0xC7,0xAD,0xEE,0x6D,0x41,0x5F,0x72,0x5A,0x71,0x08,0x37,0xB3,0x79,
+    0x65,0xA4,0x59,0xA0,0x94,0x37,0xF7,0x00,0x2F,0x0D,0xC2,0x92,0x72,0xDA,0xD0,0x38,
+    0x72,0xDB,0x14,0xA8,0x45,0xC4,0x5D,0x2A,0x7D,0xB7,0xB4,0xD6,0xC4,0xEE,0xAC,0xCD,
+    0x13,0x44,0xB7,0xC9,0x2B,0xDD,0x43,0x00,0x25,0xFA,0x61,0xB9,0x69,0x6A,0x58,0x23,
+    0x11,0xB7,0xA7,0x33,0x8F,0x56,0x75,0x59,0xF5,0xCD,0x29,0xD7,0x46,0xB7,0x0A,0x2B,
+    0x65,0xB6,0xD3,0x42,0x6F,0x15,0xB2,0xB8,0x7B,0xFB,0xEF,0xE9,0x5D,0x53,0xD5,0x34,
+    0x5A,0x27,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xDC,0x30,0x81,0xD9,0x30,0x1D,0x06,
+    0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4,0x26,0xF7,
+    0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0x30,0x0B,0x06,0x03,
+    0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,
+    0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x81,0x99,0x06,0x03,0x55,
+    0x1D,0x23,0x04,0x81,0x91,0x30,0x81,0x8E,0x80,0x14,0xAD,0xBD,0x98,0x7A,0x34,0xB4,
+    0x26,0xF7,0xFA,0xC4,0x26,0x54,0xEF,0x03,0xBD,0xE0,0x24,0xCB,0x54,0x1A,0xA1,0x73,
+    0xA4,0x71,0x30,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x53,
+    0x45,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x13,0x0B,0x41,0x64,0x64,0x54,
+    0x72,0x75,0x73,0x74,0x20,0x41,0x42,0x31,0x26,0x30,0x24,0x06,0x03,0x55,0x04,0x0B,
+    0x13,0x1D,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,
+    0x6E,0x61,0x6C,0x20,0x54,0x54,0x50,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,
+    0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x03,0x13,0x19,0x41,0x64,0x64,0x54,0x72,0x75,
+    0x73,0x74,0x20,0x45,0x78,0x74,0x65,0x72,0x6E,0x61,0x6C,0x20,0x43,0x41,0x20,0x52,
+    0x6F,0x6F,0x74,0x82,0x01,0x01,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
+    0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB0,0x9B,0xE0,0x85,0x25,0xC2,
+    0xD6,0x23,0xE2,0x0F,0x96,0x06,0x92,0x9D,0x41,0x98,0x9C,0xD9,0x84,0x79,0x81,0xD9,
+    0x1E,0x5B,0x14,0x07,0x23,0x36,0x65,0x8F,0xB0,0xD8,0x77,0xBB,0xAC,0x41,0x6C,0x47,
+    0x60,0x83,0x51,0xB0,0xF9,0x32,0x3D,0xE7,0xFC,0xF6,0x26,0x13,0xC7,0x80,0x16,0xA5,
+    0xBF,0x5A,0xFC,0x87,0xCF,0x78,0x79,0x89,0x21,0x9A,0xE2,0x4C,0x07,0x0A,0x86,0x35,
+    0xBC,0xF2,0xDE,0x51,0xC4,0xD2,0x96,0xB7,0xDC,0x7E,0x4E,0xEE,0x70,0xFD,0x1C,0x39,
+    0xEB,0x0C,0x02,0x51,0x14,0x2D,0x8E,0xBD,0x16,0xE0,0xC1,0xDF,0x46,0x75,0xE7,0x24,
+    0xAD,0xEC,0xF4,0x42,0xB4,0x85,0x93,0x70,0x10,0x67,0xBA,0x9D,0x06,0x35,0x4A,0x18,
+    0xD3,0x2B,0x7A,0xCC,0x51,0x42,0xA1,0x7A,0x63,0xD1,0xE6,0xBB,0xA1,0xC5,0x2B,0xC2,
+    0x36,0xBE,0x13,0x0D,0xE6,0xBD,0x63,0x7E,0x79,0x7B,0xA7,0x09,0x0D,0x40,0xAB,0x6A,
+    0xDD,0x8F,0x8A,0xC3,0xF6,0xF6,0x8C,0x1A,0x42,0x05,0x51,0xD4,0x45,0xF5,0x9F,0xA7,
+    0x62,0x21,0x68,0x15,0x20,0x43,0x3C,0x99,0xE7,0x7C,0xBD,0x24,0xD8,0xA9,0x91,0x17,
+    0x73,0x88,0x3F,0x56,0x1B,0x31,0x38,0x18,0xB4,0x71,0x0F,0x9A,0xCD,0xC8,0x0E,0x9E,
+    0x8E,0x2E,0x1B,0xE1,0x8C,0x98,0x83,0xCB,0x1F,0x31,0xF1,0x44,0x4C,0xC6,0x04,0x73,
+    0x49,0x76,0x60,0x0F,0xC7,0xF8,0xBD,0x17,0x80,0x6B,0x2E,0xE9,0xCC,0x4C,0x0E,0x5A,
+    0x9A,0x79,0x0F,0x20,0x0A,0x2E,0xD5,0x9E,0x63,0x26,0x1E,0x55,0x92,0x94,0xD8,0x82,
+    0x17,0x5A,0x7B,0xD0,0xBC,0xC7,0x8F,0x4E,0x86,0x04,
+};
+
 unsigned char __9639569_bin[] = {
     0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
     0x03, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x02, 0x31, 0x82, 0x02, 0x60,
@@ -2627,13 +2700,18 @@ static void tests(void)
                                                 __9148843_txt, __9148843_txt_len, kCFAllocatorNull);
     ok_status(SecCMSVerifySignedData(sig, eml, policy, &trust, NULL, NULL, NULL),
               "validate message, not signer");
-    // set date to Thu, 17 Mar 2011 00:59:48 +0000
+    // SecCMS sets date to Thu, 17 Mar 2011 00:59:48 +0000
+    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, __9148843_root, sizeof(__9148843_root));
+    CFArrayRef anchor = CFArrayCreate(NULL, (const void **)&root, 1, &kCFTypeArrayCallBacks);
+    ok_status(SecTrustSetAnchorCertificates(trust, anchor));
     ok_status(SecTrustEvaluate(trust, &result), "validate signer");
     is_status(result, kSecTrustResultUnspecified, "valid");
     CFReleaseNull(eml);
     CFReleaseNull(sig);
     CFReleaseNull(policy);
     CFReleaseNull(trust);
+    CFReleaseNull(root);
+    CFReleaseNull(anchor);
 
     CFDataRef msg = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, __9639569_bin, __9639569_bin_len, kCFAllocatorNull);
     CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist.c
deleted file mode 100644 (file)
index e263aff..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2011-2014 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 <CoreFoundation/CoreFoundation.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTrust.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "si-67-sectrust-blocklist/Global Trustee.cer.h"
-#include "si-67-sectrust-blocklist/login.yahoo.com.1.cer.h"
-#include "si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h"
-#include "si-67-sectrust-blocklist/login.yahoo.com.2.cer.h"
-#include "si-67-sectrust-blocklist/addons.mozilla.org.cer.h"
-#include "si-67-sectrust-blocklist/login.yahoo.com.cer.h"
-#include "si-67-sectrust-blocklist/login.live.com.cer.h"
-#include "si-67-sectrust-blocklist/mail.google.com.cer.h"
-#include "si-67-sectrust-blocklist/login.skype.com.cer.h"
-#include "si-67-sectrust-blocklist/www.google.com.cer.h"
-
-#include "shared_regressions.h"
-
-static void validate_one_cert(uint8_t *data, size_t len, int chain_length, SecTrustResultType trust_result)
-{
-    SecTrustRef trust;
-       SecCertificateRef cert;
-    SecPolicyRef policy = SecPolicyCreateSSL(false, NULL);
-    CFArrayRef certs;
-
-       isnt(cert = SecCertificateCreateWithBytes(NULL, data, len),
-               NULL, "create cert");
-    certs = CFArrayCreate(NULL, (const void **)&cert, 1, NULL);
-    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
-        "create trust with single cert");
-       //CFDateRef date = CFDateCreate(NULL, 1301008576);
-    //ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    //CFRelease(date);
-
-       SecTrustResultType trustResult;
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-       is(SecTrustGetCertificateCount(trust), chain_length, "cert count");
-    is_status(trustResult, trust_result, "correct trustResult");
-    CFRelease(trust);
-    CFRelease(policy);
-    CFRelease(certs);
-    CFRelease(cert);
-}
-
-static void tests(void)
-{
-    validate_one_cert(Global_Trustee_cer, sizeof(Global_Trustee_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(login_yahoo_com_1_cer, sizeof(login_yahoo_com_1_cer), 2, kSecTrustResultFatalTrustFailure);
-    /* this is the root, which isn't ok for ssl and fails here, but at the
-       same time it proves that kSecTrustResultFatalTrustFailure isn't
-       returned for policy failures that aren't blocklisting */
-    validate_one_cert(login_yahoo_com_2_cer, sizeof(login_yahoo_com_2_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(addons_mozilla_org_cer, sizeof(addons_mozilla_org_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(login_yahoo_com_cer, sizeof(login_yahoo_com_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(login_live_com_cer, sizeof(login_live_com_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(mail_google_com_cer, sizeof(mail_google_com_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(login_skype_com_cer, sizeof(login_skype_com_cer), 2, kSecTrustResultFatalTrustFailure);
-    validate_one_cert(www_google_com_cer, sizeof(www_google_com_cer), 2, kSecTrustResultFatalTrustFailure);
-}
-
-static int ping_host(char *host_name){
-    
-    struct sockaddr_in pin;
-    struct hostent *nlp_host;
-    int sd;
-    int port;
-    int retries = 5;
-    
-    port=80;
-    
-    while ((nlp_host=gethostbyname(host_name))==0 && retries--){
-        printf("Resolve Error! (%s) %d\n", host_name, h_errno);
-        sleep(1);
-    }
-
-    if(nlp_host==0)
-        return 0;
-    
-    bzero(&pin,sizeof(pin));
-    pin.sin_family=AF_INET;
-    pin.sin_addr.s_addr=htonl(INADDR_ANY);
-    pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
-    pin.sin_port=htons(port);
-    
-    sd=socket(AF_INET,SOCK_STREAM,0);
-    
-    if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1){
-        printf("connect error! (%s) %d\n", host_name, errno);
-        close(sd);
-        return 0;
-    }
-    else{
-        close(sd);
-        return 1;
-    }
-}
-int si_67_sectrust_blocklist(int argc, char *const *argv)
-{
-    char *hosts[] = {
-        "EVSecure-ocsp.verisign.com",
-        "EVIntl-ocsp.verisign.com",
-        "EVIntl-aia.verisign.com",
-        "ocsp.comodoca.com",
-        "crt.comodoca.com",
-    };
-    
-    unsigned host_cnt = 0;
-
-    plan_tests(45);
-
-    for (host_cnt = 0; host_cnt < sizeof(hosts)/sizeof(hosts[0]); host_cnt ++)
-        if(ping_host(hosts[host_cnt]) == 0){
-            printf("Accessing specific server (%s) failed, check the network!\n", hosts[host_cnt]);
-            return 0;
-        }
-
-       tests();
-
-       return 0;
-}
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/Global Trustee.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/Global Trustee.cer.h
deleted file mode 100644 (file)
index 4253e07..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-unsigned char Global_Trustee_cer[] = {
-  0x30, 0x82, 0x06, 0xdd, 0x30, 0x82, 0x05, 0xc5, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0xd8, 0xf3, 0x5f, 0x4e, 0xb7, 0x87, 0x2b, 0x2d,
-  0xab, 0x06, 0x92, 0xe3, 0x15, 0x38, 0x2f, 0xb0, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xe3, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x0e, 0x30, 0x0c, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x05, 0x54, 0x61, 0x6d, 0x70, 0x61, 0x31,
-  0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e, 0x53, 0x65,
-  0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20, 0x31, 0x30,
-  0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x47,
-  0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74, 0x65,
-  0x65, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0e,
-  0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
-  0x65, 0x65, 0x31, 0x28, 0x30, 0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
-  0x1f, 0x48, 0x6f, 0x73, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47,
-  0x54, 0x49, 0x20, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72,
-  0x70, 0x6f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12,
-  0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69,
-  0x6e, 0x75, 0x6d, 0x53, 0x53, 0x4c, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03,
-  0x55, 0x04, 0x03, 0x13, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20,
-  0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x30, 0x82, 0x02, 0x22, 0x30,
-  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
-  0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02,
-  0x82, 0x02, 0x01, 0x00, 0xd9, 0x74, 0xf2, 0xaa, 0x41, 0x1d, 0xdf, 0xf5,
-  0xc2, 0x16, 0x43, 0x49, 0x5c, 0x29, 0xbf, 0xb6, 0x89, 0x74, 0x29, 0xbc,
-  0x9c, 0x8d, 0x0c, 0x46, 0x4f, 0x59, 0x7e, 0xb2, 0x41, 0x17, 0x66, 0x34,
-  0x0c, 0x65, 0x89, 0xe1, 0x6c, 0x25, 0xe3, 0x86, 0x0a, 0x9e, 0x22, 0x45,
-  0x22, 0x8c, 0xdd, 0x9d, 0xe6, 0xa3, 0x95, 0xde, 0xdc, 0x88, 0x02, 0x55,
-  0x5c, 0xe3, 0x5b, 0x91, 0x75, 0xeb, 0x26, 0x69, 0x63, 0xb9, 0x2e, 0xc6,
-  0xca, 0x2e, 0x27, 0xdf, 0x88, 0xba, 0x02, 0x20, 0x6e, 0xfe, 0xb9, 0x0b,
-  0x29, 0xd7, 0xa7, 0xd6, 0xd7, 0x48, 0x1a, 0x1c, 0xce, 0xdd, 0x1f, 0xa9,
-  0x27, 0x0e, 0x62, 0x4f, 0xa1, 0x96, 0x1e, 0xdd, 0x54, 0x3a, 0x34, 0x63,
-  0x4a, 0x76, 0xf5, 0x77, 0x7d, 0x59, 0x67, 0xd8, 0x10, 0xd4, 0xb5, 0x0f,
-  0x3a, 0x43, 0x22, 0x98, 0xdb, 0xf4, 0x09, 0xc4, 0x0a, 0x70, 0xce, 0xdd,
-  0x90, 0xd4, 0x2f, 0xef, 0x74, 0x13, 0xc3, 0xcd, 0xc2, 0x89, 0x39, 0x62,
-  0x15, 0x9d, 0xe6, 0x74, 0xa8, 0xe8, 0x9b, 0xf0, 0x63, 0x6e, 0x9c, 0x89,
-  0xb6, 0x0e, 0xad, 0x9b, 0xf7, 0xcc, 0x82, 0xe8, 0xe8, 0x2d, 0xb8, 0x0b,
-  0xda, 0x22, 0xec, 0x49, 0x85, 0x07, 0x88, 0x99, 0x98, 0x3f, 0xf4, 0x74,
-  0xa9, 0x09, 0xf7, 0x81, 0x7c, 0x97, 0x0b, 0x59, 0x99, 0x18, 0x72, 0x8b,
-  0xdb, 0x94, 0x82, 0x2b, 0xa7, 0xe8, 0xaa, 0x6b, 0x97, 0xbf, 0x88, 0x7e,
-  0x75, 0xb0, 0x8b, 0x45, 0x45, 0x0c, 0xc7, 0xa8, 0x09, 0xea, 0x1b, 0x41,
-  0x58, 0x30, 0x3b, 0x5f, 0x78, 0x65, 0x15, 0x34, 0xd2, 0xe4, 0x3c, 0x34,
-  0x0d, 0x1d, 0xd8, 0x64, 0x3c, 0x8a, 0xa5, 0x56, 0x49, 0x99, 0x28, 0x2d,
-  0x4b, 0xf2, 0xcf, 0xcd, 0xd9, 0x6e, 0x49, 0x64, 0x9b, 0xa9, 0x79, 0x90,
-  0x77, 0x55, 0xa9, 0x08, 0x1b, 0xad, 0x1a, 0x74, 0x9e, 0xe0, 0x03, 0x93,
-  0x0a, 0x09, 0xb7, 0xad, 0xa7, 0xb4, 0x5c, 0xef, 0x83, 0x6c, 0xb7, 0x9a,
-  0xb4, 0xc6, 0x68, 0x40, 0x80, 0x1d, 0x42, 0xd1, 0x6e, 0x79, 0x9b, 0xa9,
-  0x19, 0x21, 0x9a, 0x9c, 0xf9, 0x86, 0x2d, 0x00, 0xd1, 0x34, 0xfe, 0xe0,
-  0xb6, 0xf9, 0x55, 0xb6, 0xf5, 0x26, 0xc5, 0x95, 0x16, 0xa5, 0x7c, 0x73,
-  0x9f, 0x0a, 0x29, 0x89, 0xac, 0x3a, 0x98, 0xf7, 0x9b, 0x74, 0x67, 0xb7,
-  0x90, 0xb7, 0x5d, 0x09, 0x23, 0x6a, 0x6a, 0xed, 0x2c, 0x10, 0xee, 0x53,
-  0x0a, 0x10, 0xf0, 0x16, 0x1f, 0x57, 0xb3, 0xb1, 0x0d, 0x79, 0x91, 0x19,
-  0xb0, 0xeb, 0xcd, 0x30, 0x3f, 0xa0, 0x14, 0x5f, 0xb3, 0xc6, 0xfd, 0x5c,
-  0x33, 0xa7, 0xb0, 0xff, 0x98, 0xb0, 0x55, 0x8c, 0xb9, 0xa5, 0xf2, 0x6f,
-  0x47, 0x24, 0x49, 0x21, 0x69, 0xcc, 0x42, 0xa2, 0x51, 0x00, 0x40, 0x85,
-  0x8c, 0x82, 0x82, 0xab, 0x32, 0xa5, 0xcb, 0x9a, 0xdc, 0xd0, 0xd9, 0x18,
-  0x0d, 0xdf, 0x19, 0xf4, 0xaf, 0x83, 0x0d, 0xc1, 0x3e, 0x31, 0xdb, 0x24,
-  0x48, 0xb6, 0x75, 0x80, 0xa1, 0xe1, 0xc9, 0x77, 0x64, 0x1e, 0xa7, 0xe5,
-  0x8b, 0x7f, 0x15, 0x4d, 0x4b, 0xa7, 0xc2, 0xd0, 0xed, 0x79, 0x95, 0x5e,
-  0x91, 0x31, 0xec, 0x18, 0xff, 0x4e, 0x9f, 0x48, 0x14, 0xea, 0x75, 0xba,
-  0x21, 0xce, 0x29, 0x76, 0xe9, 0x1f, 0x4e, 0x51, 0x87, 0x2e, 0xb3, 0xcc,
-  0x04, 0x60, 0xba, 0x23, 0x1f, 0x1f, 0x65, 0xb2, 0x0a, 0xb8, 0xd5, 0x6e,
-  0x8f, 0x4b, 0x42, 0x89, 0x47, 0xa9, 0x81, 0x90, 0x5b, 0x2b, 0xb2, 0xb6,
-  0xae, 0xe6, 0xa0, 0x70, 0x7b, 0x78, 0x90, 0x0a, 0x7a, 0xc5, 0xe5, 0xe7,
-  0xc5, 0xfb, 0x0a, 0xf6, 0x2f, 0x69, 0x8c, 0x8c, 0x1f, 0x57, 0xe0, 0x06,
-  0x99, 0xff, 0x11, 0xd5, 0x52, 0x32, 0x20, 0x97, 0x27, 0x98, 0xee, 0x65,
-  0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd4, 0x30, 0x82, 0x01,
-  0xd0, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
-  0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98, 0x43, 0x95, 0x5d,
-  0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3, 0x45, 0x30, 0x1d,
-  0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb7, 0xc3, 0xde,
-  0x1a, 0x43, 0xed, 0x41, 0x97, 0xa9, 0x8f, 0x29, 0x78, 0x9c, 0x03, 0xb9,
-  0xac, 0x40, 0x42, 0x00, 0xac, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f,
-  0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c, 0x06,
-  0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30,
-  0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08,
-  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d,
-  0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c, 0x2b, 0x06, 0x01,
-  0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04, 0x30, 0x2b, 0x30,
-  0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
-  0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
-  0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x63,
-  0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06, 0x03, 0x55, 0x1d,
-  0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36, 0xa0, 0x34, 0x86,
-  0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
-  0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d,
-  0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
-  0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e,
-  0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32, 0x86, 0x30, 0x68,
-  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f,
-  0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f, 0x55, 0x54, 0x4e,
-  0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48,
-  0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30,
-  0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
-  0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
-  0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61,
-  0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41, 0x64, 0x64, 0x54,
-  0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
-  0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-  0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
-  0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f,
-  0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x19, 0x06, 0x03, 0x55, 0x1d,
-  0x11, 0x04, 0x12, 0x30, 0x10, 0x82, 0x0e, 0x67, 0x6c, 0x6f, 0x62, 0x61,
-  0x6c, 0x20, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x65, 0x30, 0x0d, 0x06,
-  0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00,
-  0x03, 0x82, 0x01, 0x01, 0x00, 0x8f, 0xba, 0x75, 0xba, 0x39, 0xd4, 0x26,
-  0xd3, 0x70, 0x0f, 0xc4, 0xb3, 0x02, 0xa7, 0xc5, 0x12, 0x23, 0x71, 0xc9,
-  0xfe, 0x63, 0xe9, 0xa3, 0x62, 0x78, 0x24, 0x44, 0x4f, 0xd4, 0xb9, 0x11,
-  0x3e, 0x1f, 0xc7, 0x28, 0xe7, 0x55, 0x6b, 0xee, 0xf4, 0xe1, 0x00, 0x91,
-  0x86, 0x8a, 0xc9, 0x09, 0x6b, 0x9f, 0x2e, 0xa4, 0x45, 0x39, 0xd1, 0x61,
-  0x62, 0x5e, 0x93, 0xa5, 0x05, 0x45, 0x78, 0x9f, 0x60, 0x12, 0x2c, 0xf4,
-  0x6c, 0x65, 0x65, 0x0d, 0xcc, 0x46, 0x34, 0x8b, 0x28, 0xba, 0xa0, 0xc6,
-  0xf4, 0x99, 0x71, 0x64, 0xf3, 0x22, 0x76, 0xac, 0x4f, 0xf3, 0x62, 0xc9,
-  0xa7, 0x33, 0x5a, 0x07, 0x1f, 0x3d, 0xc9, 0x86, 0x80, 0xdc, 0xdb, 0x04,
-  0x2f, 0x87, 0x27, 0xe8, 0xbf, 0x48, 0x44, 0x81, 0xc0, 0xf0, 0x49, 0x23,
-  0x6e, 0x1f, 0xe5, 0xe4, 0x03, 0x86, 0x24, 0x13, 0xa2, 0x85, 0x62, 0x7c,
-  0x58, 0x04, 0xca, 0xe6, 0x8d, 0x13, 0x72, 0x0a, 0xba, 0x56, 0x44, 0xa2,
-  0x0f, 0xbc, 0xfb, 0xa0, 0x3d, 0x0d, 0x2a, 0x7f, 0xfb, 0x9e, 0xa9, 0x09,
-  0x3d, 0xb7, 0x5a, 0xd4, 0x8a, 0x8d, 0xe1, 0x25, 0xe8, 0xa4, 0x09, 0x84,
-  0x70, 0xad, 0x12, 0x44, 0xb9, 0xcf, 0xb9, 0x33, 0x7a, 0xba, 0x5c, 0xe6,
-  0x4b, 0xa6, 0xbb, 0x05, 0x06, 0x98, 0xff, 0xf2, 0x98, 0x52, 0x7b, 0x77,
-  0x80, 0x27, 0x4a, 0xd9, 0xe2, 0xfa, 0xb9, 0x52, 0xd4, 0xfb, 0xfb, 0xe6,
-  0xd6, 0x2d, 0x9e, 0x8f, 0xc1, 0x15, 0x44, 0x8d, 0x9b, 0x74, 0x2f, 0xee,
-  0x94, 0x5a, 0x4e, 0xd3, 0xc4, 0x8b, 0x8a, 0xac, 0x43, 0x9d, 0x73, 0xf6,
-  0xae, 0x0c, 0x87, 0x89, 0xad, 0x87, 0xc9, 0xc9, 0xc7, 0xdd, 0xba, 0x14,
-  0x60, 0x7a, 0xf8, 0xb5, 0x35, 0x9d, 0xc2, 0x8d, 0xc6, 0x96, 0x81, 0x0d,
-  0xa9, 0x52, 0x8a, 0x29, 0x40, 0x04, 0xe9, 0x19, 0xb4
-};
-unsigned int Global_Trustee_cer_len = 1761;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/UTN-USERFirst-Hardware.cer.h
deleted file mode 100644 (file)
index 320e0e3..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-unsigned char UTN_USERFirst_Hardware_cer[] = {
-  0x30, 0x82, 0x04, 0x74, 0x30, 0x82, 0x03, 0x5c, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x10, 0x44, 0xbe, 0x0c, 0x8b, 0x50, 0x00, 0x24, 0xb4, 0x11,
-  0xd3, 0x36, 0x2a, 0xfe, 0x65, 0x0a, 0xfd, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
-  0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-  0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-  0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07,
-  0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65, 0x20,
-  0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
-  0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
-  0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-  0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x68,
-  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73,
-  0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
-  0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54,
-  0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d,
-  0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d,
-  0x39, 0x39, 0x30, 0x37, 0x30, 0x39, 0x31, 0x38, 0x31, 0x30, 0x34, 0x32,
-  0x5a, 0x17, 0x0d, 0x31, 0x39, 0x30, 0x37, 0x30, 0x39, 0x31, 0x38, 0x31,
-  0x39, 0x32, 0x32, 0x5a, 0x30, 0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06,
-  0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30,
-  0x15, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74,
-  0x20, 0x4c, 0x61, 0x6b, 0x65, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e,
-  0x30, 0x1c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65,
-  0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e,
-  0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03,
-  0x55, 0x04, 0x0b, 0x13, 0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
-  0x77, 0x77, 0x77, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73,
-  0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55,
-  0x04, 0x03, 0x13, 0x16, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 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, 0xb1,
-  0xf7, 0xc3, 0x38, 0x3f, 0xb4, 0xa8, 0x7f, 0xcf, 0x39, 0x82, 0x51, 0x67,
-  0xd0, 0x6d, 0x9f, 0xd2, 0xff, 0x58, 0xf3, 0xe7, 0x9f, 0x2b, 0xec, 0x0d,
-  0x89, 0x54, 0x99, 0xb9, 0x38, 0x99, 0x16, 0xf7, 0xe0, 0x21, 0x79, 0x48,
-  0xc2, 0xbb, 0x61, 0x74, 0x12, 0x96, 0x1d, 0x3c, 0x6a, 0x72, 0xd5, 0x3c,
-  0x10, 0x67, 0x3a, 0x39, 0xed, 0x2b, 0x13, 0xcd, 0x66, 0xeb, 0x95, 0x09,
-  0x33, 0xa4, 0x6c, 0x97, 0xb1, 0xe8, 0xc6, 0xec, 0xc1, 0x75, 0x79, 0x9c,
-  0x46, 0x5e, 0x8d, 0xab, 0xd0, 0x6a, 0xfd, 0xb9, 0x2a, 0x55, 0x17, 0x10,
-  0x54, 0xb3, 0x19, 0xf0, 0x9a, 0xf6, 0xf1, 0xb1, 0x5d, 0xb6, 0xa7, 0x6d,
-  0xfb, 0xe0, 0x71, 0x17, 0x6b, 0xa2, 0x88, 0xfb, 0x00, 0xdf, 0xfe, 0x1a,
-  0x31, 0x77, 0x0c, 0x9a, 0x01, 0x7a, 0xb1, 0x32, 0xe3, 0x2b, 0x01, 0x07,
-  0x38, 0x6e, 0xc3, 0xa5, 0x5e, 0x23, 0xbc, 0x45, 0x9b, 0x7b, 0x50, 0xc1,
-  0xc9, 0x30, 0x8f, 0xdb, 0xe5, 0x2b, 0x7a, 0xd3, 0x5b, 0xfb, 0x33, 0x40,
-  0x1e, 0xa0, 0xd5, 0x98, 0x17, 0xbc, 0x8b, 0x87, 0xc3, 0x89, 0xd3, 0x5d,
-  0xa0, 0x8e, 0xb2, 0xaa, 0xaa, 0xf6, 0x8e, 0x69, 0x88, 0x06, 0xc5, 0xfa,
-  0x89, 0x21, 0xf3, 0x08, 0x9d, 0x69, 0x2e, 0x09, 0x33, 0x9b, 0x29, 0x0d,
-  0x46, 0x0f, 0x8c, 0xcc, 0x49, 0x34, 0xb0, 0x69, 0x51, 0xbd, 0xf9, 0x06,
-  0xcd, 0x68, 0xad, 0x66, 0x4c, 0xbc, 0x3e, 0xac, 0x61, 0xbd, 0x0a, 0x88,
-  0x0e, 0xc8, 0xdf, 0x3d, 0xee, 0x7c, 0x04, 0x4c, 0x9d, 0x0a, 0x5e, 0x6b,
-  0x91, 0xd6, 0xee, 0xc7, 0xed, 0x28, 0x8d, 0xab, 0x4d, 0x87, 0x89, 0x73,
-  0xd0, 0x6e, 0xa4, 0xd0, 0x1e, 0x16, 0x8b, 0x14, 0xe1, 0x76, 0x44, 0x03,
-  0x7f, 0x63, 0xac, 0xe4, 0xcd, 0x49, 0x9c, 0xc5, 0x92, 0xf4, 0xab, 0x32,
-  0xa1, 0x48, 0x5b, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xb9, 0x30,
-  0x81, 0xb6, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
-  0x02, 0x01, 0xc6, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
-  0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1d, 0x06, 0x03,
-  0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b,
-  0x28, 0x98, 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b,
-  0xd2, 0xc3, 0x45, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x3d,
-  0x30, 0x3b, 0x30, 0x39, 0xa0, 0x37, 0xa0, 0x35, 0x86, 0x33, 0x68, 0x74,
-  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x75, 0x73, 0x65,
-  0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72,
-  0x6c, 0x30, 0x31, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x2a, 0x30, 0x28,
-  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08,
-  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x05, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x03, 0x06, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-  0x05, 0x07, 0x03, 0x07, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-  0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00,
-  0x47, 0x19, 0x0f, 0xde, 0x74, 0xc6, 0x99, 0x97, 0xaf, 0xfc, 0xad, 0x28,
-  0x5e, 0x75, 0x8e, 0xeb, 0x2d, 0x67, 0xee, 0x4e, 0x7b, 0x2b, 0xd7, 0x0c,
-  0xff, 0xf6, 0xde, 0xcb, 0x55, 0xa2, 0x0a, 0xe1, 0x4c, 0x54, 0x65, 0x93,
-  0x60, 0x6b, 0x9f, 0x12, 0x9c, 0xad, 0x5e, 0x83, 0x2c, 0xeb, 0x5a, 0xae,
-  0xc0, 0xe4, 0x2d, 0xf4, 0x00, 0x63, 0x1d, 0xb8, 0xc0, 0x6c, 0xf2, 0xcf,
-  0x49, 0xbb, 0x4d, 0x93, 0x6f, 0x06, 0xa6, 0x0a, 0x22, 0xb2, 0x49, 0x62,
-  0x08, 0x4e, 0xff, 0xc8, 0xc8, 0x14, 0xb2, 0x88, 0x16, 0x5d, 0xe7, 0x01,
-  0xe4, 0x12, 0x95, 0xe5, 0x45, 0x34, 0xb3, 0x8b, 0x69, 0xbd, 0xcf, 0xb4,
-  0x85, 0x8f, 0x75, 0x51, 0x9e, 0x7d, 0x3a, 0x38, 0x3a, 0x14, 0x48, 0x12,
-  0xc6, 0xfb, 0xa7, 0x3b, 0x1a, 0x8d, 0x0d, 0x82, 0x40, 0x07, 0xe8, 0x04,
-  0x08, 0x90, 0xa1, 0x89, 0xcb, 0x19, 0x50, 0xdf, 0xca, 0x1c, 0x01, 0xbc,
-  0x1d, 0x04, 0x19, 0x7b, 0x10, 0x76, 0x97, 0x3b, 0xee, 0x90, 0x90, 0xca,
-  0xc4, 0x0e, 0x1f, 0x16, 0x6e, 0x75, 0xef, 0x33, 0xf8, 0xd3, 0x6f, 0x5b,
-  0x1e, 0x96, 0xe3, 0xe0, 0x74, 0x77, 0x74, 0x7b, 0x8a, 0xa2, 0x6e, 0x2d,
-  0xdd, 0x76, 0xd6, 0x39, 0x30, 0x82, 0xf0, 0xab, 0x9c, 0x52, 0xf2, 0x2a,
-  0xc7, 0xaf, 0x49, 0x5e, 0x7e, 0xc7, 0x68, 0xe5, 0x82, 0x81, 0xc8, 0x6a,
-  0x27, 0xf9, 0x27, 0x88, 0x2a, 0xd5, 0x58, 0x50, 0x95, 0x1f, 0xf0, 0x3b,
-  0x1c, 0x57, 0xbb, 0x7d, 0x14, 0x39, 0x62, 0x2b, 0x9a, 0xc9, 0x94, 0x92,
-  0x2a, 0xa3, 0x22, 0x0c, 0xff, 0x89, 0x26, 0x7d, 0x5f, 0x23, 0x2b, 0x47,
-  0xd7, 0x15, 0x1d, 0xa9, 0x6a, 0x9e, 0x51, 0x0d, 0x2a, 0x51, 0x9e, 0x81,
-  0xf9, 0xd4, 0x3b, 0x5e, 0x70, 0x12, 0x7f, 0x10, 0x32, 0x9c, 0x1e, 0xbb,
-  0x9d, 0xf8, 0x66, 0xa8
-};
-unsigned int UTN_USERFirst_Hardware_cer_len = 1144;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/addons.mozilla.org.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/addons.mozilla.org.cer.h
deleted file mode 100644 (file)
index ae288d3..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-unsigned char addons_mozilla_org_cer[] = {
-  0x30, 0x82, 0x05, 0xf8, 0x30, 0x82, 0x04, 0xe0, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0x92, 0x39, 0xd5, 0x34, 0x8f, 0x40, 0xd1, 0x69,
-  0x5a, 0x74, 0x54, 0x70, 0xe1, 0xf2, 0x3f, 0x43, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xe2, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73,
-  0x68, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e,
-  0x53, 0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20,
-  0x31, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-  0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e,
-  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54,
-  0x65, 0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30,
-  0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74,
-  0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72,
-  0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
-  0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
-  0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53,
-  0x4c, 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x12,
-  0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x6d, 0x6f, 0x7a, 0x69, 0x6c,
-  0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 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, 0xab, 0xc6, 0x6d, 0x36, 0xf3, 0x15, 0x73, 0x78, 0x83,
-  0x73, 0xce, 0x74, 0x85, 0xd5, 0xae, 0xec, 0xb2, 0xf0, 0xe0, 0x24, 0x1f,
-  0x13, 0x83, 0xb8, 0x20, 0xac, 0xbb, 0x9a, 0xfe, 0x88, 0xbb, 0xab, 0xa1,
-  0x1d, 0x0b, 0x1f, 0x45, 0x00, 0xaa, 0x49, 0xb7, 0x35, 0x37, 0x0c, 0x6a,
-  0xef, 0x47, 0x4c, 0xb9, 0xd1, 0xbe, 0xe3, 0x57, 0x12, 0x04, 0x8d, 0x92,
-  0xc7, 0xb6, 0xec, 0x01, 0xbc, 0xb6, 0xda, 0xc7, 0x81, 0x38, 0x20, 0xad,
-  0x72, 0x85, 0xe6, 0x0e, 0xfc, 0x81, 0x6c, 0x07, 0xad, 0x68, 0x76, 0x38,
-  0xc5, 0x44, 0xd7, 0xcc, 0xc6, 0x4a, 0xc5, 0x97, 0x3e, 0x64, 0xf4, 0x51,
-  0xe6, 0xf0, 0x7e, 0xb2, 0xec, 0x56, 0xf7, 0x25, 0x82, 0x4d, 0x49, 0x98,
-  0xcb, 0x16, 0x98, 0xdd, 0x23, 0xf1, 0x89, 0x91, 0xd1, 0x17, 0x97, 0x40,
-  0x99, 0x26, 0xd6, 0xe2, 0xa2, 0x2b, 0x5e, 0xdf, 0xbd, 0x89, 0xf2, 0x1b,
-  0x1a, 0x53, 0x2d, 0xcc, 0x50, 0x41, 0x7a, 0xd0, 0x3d, 0x2a, 0x0c, 0x55,
-  0x70, 0x14, 0x01, 0xe9, 0x58, 0x49, 0x10, 0x7a, 0x0b, 0x93, 0x82, 0x8b,
-  0xe1, 0x1e, 0xed, 0x3a, 0x80, 0x10, 0x82, 0xce, 0x96, 0x8a, 0x34, 0xf0,
-  0xcc, 0xd7, 0xd3, 0xb9, 0xb4, 0x50, 0x87, 0x55, 0x54, 0x09, 0xb8, 0x9d,
-  0x42, 0x28, 0x55, 0x00, 0xe5, 0x8c, 0x35, 0x54, 0xbf, 0xdd, 0x25, 0x91,
-  0x46, 0xb7, 0x0d, 0xe5, 0x5d, 0x83, 0xa8, 0xe5, 0x8b, 0xfb, 0x84, 0xe4,
-  0x3c, 0xae, 0x76, 0xda, 0xc4, 0x43, 0x2b, 0x5b, 0x74, 0x0b, 0xf8, 0xbe,
-  0x5d, 0x68, 0xf1, 0x78, 0x5b, 0xb5, 0xce, 0x7d, 0xf1, 0x5d, 0x99, 0x40,
-  0xda, 0xca, 0xee, 0x38, 0x81, 0x50, 0xbe, 0x98, 0xa1, 0x6c, 0xb8, 0x24,
-  0xad, 0xf3, 0xaf, 0x8c, 0x0f, 0xd7, 0x11, 0x28, 0x2c, 0x84, 0x18, 0x4c,
-  0x7d, 0xb5, 0xd9, 0x8f, 0x30, 0xb5, 0x1b, 0x02, 0x03, 0x01, 0x00, 0x01,
-  0xa3, 0x82, 0x01, 0xf0, 0x30, 0x82, 0x01, 0xec, 0x30, 0x1f, 0x06, 0x03,
-  0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f,
-  0x26, 0x1b, 0x28, 0x98, 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96,
-  0x9d, 0x4b, 0xd2, 0xc3, 0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
-  0x04, 0x16, 0x04, 0x14, 0xdd, 0x80, 0xd2, 0x54, 0x3d, 0xf7, 0x4c, 0x70,
-  0xca, 0xa3, 0xb0, 0xdd, 0x34, 0x7a, 0x32, 0xe4, 0xe8, 0x3b, 0x5a, 0x3b,
-  0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04,
-  0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
-  0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
-  0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
-  0x02, 0x30, 0x46, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d,
-  0x30, 0x3b, 0x06, 0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01,
-  0x02, 0x01, 0x03, 0x04, 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70,
-  0x73, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63,
-  0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50,
-  0x53, 0x30, 0x7b, 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72,
-  0x30, 0x38, 0xa0, 0x36, 0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d,
-  0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61,
-  0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36,
-  0xa0, 0x34, 0xa0, 0x32, 0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
-  0x2f, 0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e,
-  0x6e, 0x65, 0x74, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b,
-  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63,
-  0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
-  0x55, 0x54, 0x4e, 0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53,
-  0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30,
-  0x24, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86,
-  0x18, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f,
-  0x6d, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x2e, 0x30, 0x2c,
-  0x82, 0x12, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x6d, 0x6f, 0x7a,
-  0x69, 0x6c, 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x16, 0x77, 0x77,
-  0x77, 0x2e, 0x61, 0x64, 0x64, 0x6f, 0x6e, 0x73, 0x2e, 0x6d, 0x6f, 0x7a,
-  0x69, 0x6c, 0x6c, 0x61, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
-  0x82, 0x01, 0x01, 0x00, 0x33, 0x3b, 0x63, 0x15, 0xfc, 0xb1, 0xec, 0x14,
-  0x2c, 0x93, 0xdd, 0x75, 0x94, 0xde, 0x81, 0x5a, 0xd9, 0x4e, 0x99, 0xbe,
-  0xfb, 0x4a, 0xa4, 0x39, 0x55, 0x4d, 0xa1, 0x40, 0x7a, 0xde, 0x13, 0x2a,
-  0x87, 0xa9, 0x37, 0xcf, 0xe8, 0xd5, 0xfb, 0xad, 0xd1, 0x7b, 0x6d, 0x6f,
-  0x8c, 0x20, 0x87, 0x82, 0x54, 0xe6, 0x57, 0x49, 0xbc, 0x20, 0x28, 0x84,
-  0xcd, 0xd6, 0x01, 0xd9, 0x93, 0x8b, 0x17, 0x6e, 0x23, 0x66, 0xe5, 0x84,
-  0xc8, 0x80, 0x3f, 0xc6, 0xa1, 0x70, 0x80, 0xe4, 0xec, 0x4d, 0x1d, 0xf9,
-  0xfc, 0x91, 0x5a, 0x73, 0x62, 0x29, 0x9a, 0xf7, 0x20, 0x1c, 0x61, 0xe0,
-  0x8b, 0x39, 0x9f, 0xca, 0xbc, 0x7e, 0x8d, 0xdd, 0xbc, 0xd9, 0xb1, 0xe3,
-  0x9f, 0x9e, 0xdf, 0x15, 0x53, 0x91, 0x21, 0x52, 0x0b, 0xd9, 0x1a, 0x23,
-  0x0f, 0x66, 0x36, 0xdb, 0xac, 0x93, 0x96, 0x4a, 0xa3, 0xa5, 0x22, 0xcf,
-  0x29, 0xf7, 0xa2, 0x99, 0xa8, 0xf6, 0xb6, 0xd9, 0x40, 0xae, 0xd9, 0x7e,
-  0xb6, 0xf6, 0x58, 0x2e, 0x9b, 0xac, 0x36, 0xca, 0x64, 0x8f, 0x65, 0x52,
-  0xdc, 0x86, 0x9c, 0x82, 0xab, 0x6e, 0x50, 0x4b, 0xda, 0x5f, 0xfa, 0x05,
-  0x00, 0x88, 0x30, 0x0e, 0xde, 0x8d, 0x56, 0xbf, 0x81, 0x47, 0x8d, 0x3d,
-  0x06, 0xe2, 0xb2, 0x62, 0x92, 0x67, 0x8f, 0x9e, 0xc8, 0x9a, 0xb2, 0xe5,
-  0x06, 0xb8, 0x70, 0x24, 0xb8, 0x77, 0x7c, 0x23, 0x0a, 0x38, 0xc3, 0x79,
-  0x08, 0xd8, 0xb1, 0x51, 0x9d, 0xac, 0x95, 0x11, 0xc7, 0x40, 0x17, 0x9e,
-  0xa3, 0x1c, 0x8f, 0xf2, 0x11, 0xa7, 0x68, 0x27, 0xda, 0x49, 0x05, 0x84,
-  0x18, 0x7c, 0x58, 0x2d, 0x01, 0x67, 0x5c, 0xe5, 0x9f, 0xa1, 0x29, 0xbb,
-  0x4a, 0x39, 0x45, 0x2f, 0xbf, 0x11, 0xaa, 0x79, 0xa2, 0xed, 0xb4, 0xd4,
-  0xb5, 0x65, 0x43, 0xb7, 0x93, 0x46, 0x8a, 0xd3
-};
-unsigned int addons_mozilla_org_cer_len = 1532;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.live.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.live.com.cer.h
deleted file mode 100644 (file)
index fb39259..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-unsigned char login_live_com_cer[] = {
-  0x30, 0x82, 0x05, 0xec, 0x30, 0x82, 0x04, 0xd4, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0xb0, 0xb7, 0x13, 0x3e, 0xd0, 0x96, 0xf9, 0xb5,
-  0x6f, 0xae, 0x91, 0xc8, 0x74, 0xbd, 0x3a, 0xc0, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xde, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73,
-  0x68, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e,
-  0x53, 0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20,
-  0x31, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-  0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e,
-  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54,
-  0x65, 0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30,
-  0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74,
-  0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72,
-  0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
-  0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
-  0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53,
-  0x4c, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e,
-  0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x6c, 0x69, 0x76, 0x65, 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, 0xf3,
-  0xfc, 0x2b, 0x2f, 0xef, 0xe1, 0xad, 0x59, 0xf0, 0x42, 0x3c, 0xc2, 0xf1,
-  0x82, 0xbf, 0x2c, 0x41, 0x93, 0xd1, 0xf6, 0x98, 0x33, 0x95, 0x4c, 0xbc,
-  0x62, 0xf1, 0x95, 0x58, 0x08, 0xb6, 0xe9, 0x7b, 0x77, 0x48, 0xb0, 0xd3,
-  0xdc, 0x17, 0x3f, 0xbc, 0x6e, 0xe6, 0xec, 0x1e, 0xec, 0x8d, 0x17, 0xfe,
-  0x1c, 0x24, 0xc6, 0x3e, 0x67, 0x3d, 0x92, 0x95, 0xa2, 0x30, 0xc0, 0xa7,
-  0x57, 0x20, 0xcf, 0x70, 0x88, 0x97, 0x4a, 0x05, 0x93, 0x79, 0x93, 0x42,
-  0x97, 0x2f, 0x3e, 0xff, 0xc4, 0x14, 0x14, 0x28, 0xa2, 0x13, 0x36, 0xb4,
-  0xf8, 0xee, 0xbe, 0x1d, 0xbc, 0x78, 0x5d, 0x61, 0x93, 0x5f, 0xeb, 0x88,
-  0xd7, 0xd1, 0xe4, 0x2b, 0x9a, 0xcd, 0x58, 0xe2, 0x07, 0x45, 0x9f, 0x4f,
-  0xb8, 0xb9, 0x40, 0x6a, 0x33, 0x2c, 0x5b, 0x21, 0x03, 0x5a, 0x4a, 0x94,
-  0xf2, 0x7a, 0x97, 0x59, 0x1b, 0xa8, 0xb5, 0x42, 0xd8, 0x83, 0x00, 0xaa,
-  0x34, 0xcc, 0xa7, 0x76, 0xd0, 0x47, 0x03, 0x5f, 0x05, 0xaf, 0x3b, 0xe1,
-  0xb9, 0xa1, 0x34, 0x25, 0xb7, 0x6c, 0x5f, 0x9a, 0x30, 0x84, 0x98, 0xc2,
-  0xc2, 0xd7, 0xf2, 0xb8, 0x42, 0x4a, 0x10, 0x55, 0xbd, 0xfa, 0x53, 0x81,
-  0x5d, 0x8d, 0x68, 0x66, 0x45, 0x2c, 0x52, 0x7e, 0xe5, 0xc4, 0x04, 0xc3,
-  0x54, 0xe7, 0xc3, 0x39, 0xda, 0x7a, 0x4a, 0xc5, 0xb9, 0x98, 0x82, 0x20,
-  0xe1, 0x2c, 0x60, 0x57, 0xbf, 0xba, 0xf2, 0x46, 0x00, 0xbc, 0x5f, 0x3a,
-  0xdc, 0xe3, 0x33, 0x97, 0xf8, 0x4a, 0x98, 0xb9, 0xec, 0x33, 0x4f, 0x2d,
-  0x60, 0x6c, 0x15, 0x92, 0xa6, 0x81, 0x4a, 0x0b, 0xe9, 0xec, 0x76, 0x70,
-  0x34, 0x31, 0x17, 0x70, 0xe6, 0x70, 0x4b, 0x8e, 0x8b, 0xd3, 0x75, 0xcb,
-  0x78, 0x49, 0xab, 0x66, 0x9b, 0x86, 0x9f, 0x8f, 0xa9, 0xc4, 0x01, 0xe8,
-  0xca, 0x1b, 0xe7, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xe8,
-  0x30, 0x82, 0x01, 0xe4, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-  0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-  0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3,
-  0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-  0xd4, 0x64, 0xf6, 0xa9, 0xe8, 0xa5, 0x7e, 0xd7, 0xbf, 0x63, 0x52, 0x03,
-  0x83, 0x53, 0xdb, 0xc5, 0x41, 0x8d, 0xea, 0x80, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0,
-  0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
-  0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
-  0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
-  0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06,
-  0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c,
-  0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04,
-  0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
-  0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06,
-  0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36,
-  0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
-  0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e,
-  0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32,
-  0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
-  0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
-  0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63,
-  0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41,
-  0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
-  0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
-  0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2d, 0x06,
-  0x03, 0x55, 0x1d, 0x11, 0x04, 0x26, 0x30, 0x24, 0x82, 0x0e, 0x6c, 0x6f,
-  0x67, 0x69, 0x6e, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
-  0x82, 0x12, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2e,
-  0x6c, 0x69, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03,
-  0x82, 0x01, 0x01, 0x00, 0x54, 0xe3, 0xa4, 0x9a, 0x24, 0xd2, 0xf3, 0x1d,
-  0x42, 0xad, 0x1b, 0xf0, 0x1e, 0xab, 0xfb, 0xda, 0xd5, 0xaa, 0xe9, 0xcf,
-  0x5a, 0xb3, 0x1e, 0x57, 0x7b, 0x31, 0xf2, 0x6e, 0x57, 0x4b, 0x31, 0xaf,
-  0x33, 0xbb, 0xb6, 0x0d, 0x15, 0xc7, 0x5e, 0x59, 0x01, 0xce, 0x44, 0xb5,
-  0xb7, 0xbf, 0x09, 0xc9, 0xd5, 0xdc, 0x69, 0x84, 0xe9, 0xc5, 0x1a, 0xb7,
-  0xf0, 0x3e, 0xd4, 0xc0, 0x24, 0xbd, 0x29, 0x5f, 0xb4, 0xe9, 0xd6, 0x58,
-  0xeb, 0x45, 0x11, 0x89, 0x34, 0x34, 0xd3, 0x11, 0xeb, 0x34, 0xce, 0x2a,
-  0x4f, 0x00, 0x3d, 0xf6, 0x72, 0xef, 0x69, 0x66, 0xc0, 0x9f, 0x9a, 0xac,
-  0x7e, 0x70, 0x50, 0xac, 0x55, 0x47, 0xda, 0xbe, 0x43, 0x5b, 0xec, 0x8b,
-  0xc8, 0xc5, 0x23, 0x84, 0xc9, 0x9f, 0xb6, 0x52, 0x08, 0xcf, 0x91, 0x1b,
-  0x2f, 0x80, 0x69, 0xe6, 0x34, 0x33, 0xe6, 0xb3, 0x9f, 0xa4, 0xe5, 0x0d,
-  0x9a, 0x15, 0xf9, 0x57, 0xfc, 0x0b, 0xa9, 0x41, 0x0b, 0xf5, 0xff, 0x58,
-  0x41, 0x92, 0x22, 0x27, 0x66, 0x12, 0x06, 0xc7, 0x2a, 0xd8, 0x59, 0xa7,
-  0xc6, 0xdf, 0x44, 0x12, 0x4f, 0xc0, 0xa8, 0x7f, 0xa7, 0x41, 0xc8, 0xc8,
-  0x69, 0xff, 0xba, 0x05, 0x2e, 0x97, 0xad, 0x3b, 0xd0, 0xeb, 0xf3, 0x15,
-  0x6d, 0x7e, 0x1b, 0xe5, 0xba, 0xdd, 0x34, 0xbe, 0x22, 0x11, 0xec, 0x68,
-  0x98, 0x33, 0x81, 0x02, 0x6a, 0x0b, 0x13, 0x55, 0x79, 0x31, 0x75, 0x4e,
-  0x3a, 0xc8, 0xb6, 0x13, 0xbd, 0x97, 0x6f, 0x37, 0x0a, 0x0b, 0x2d, 0x88,
-  0x0e, 0xde, 0x67, 0x90, 0xc2, 0xb3, 0xca, 0x20, 0xca, 0x9a, 0x51, 0xf4,
-  0x64, 0x3e, 0xdb, 0xf4, 0x2e, 0x45, 0xf2, 0xc7, 0x47, 0x17, 0xa8, 0xf4,
-  0xfa, 0x90, 0x5a, 0x7f, 0x80, 0xa6, 0x82, 0xac, 0xe4, 0x6c, 0x81, 0x46,
-  0xbb, 0x52, 0x85, 0x20, 0x24, 0xf8, 0x80, 0xea
-};
-unsigned int login_live_com_cer_len = 1520;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.skype.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.skype.com.cer.h
deleted file mode 100644 (file)
index 0ffd13a..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-unsigned char login_skype_com_cer[] = {
-  0x30, 0x82, 0x05, 0xef, 0x30, 0x82, 0x04, 0xd7, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0xe9, 0x02, 0x8b, 0x95, 0x78, 0xe4, 0x15, 0xdc,
-  0x1a, 0x71, 0x0a, 0x2b, 0x88, 0x15, 0x44, 0x47, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xdf, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73,
-  0x68, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e,
-  0x53, 0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20,
-  0x31, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-  0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e,
-  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54,
-  0x65, 0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30,
-  0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74,
-  0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72,
-  0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
-  0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
-  0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53,
-  0x4c, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f,
-  0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x73, 0x6b, 0x79, 0x70, 0x65, 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,
-  0xb0, 0x78, 0x99, 0x86, 0x0e, 0xa2, 0x73, 0x23, 0xd4, 0x5a, 0xc3, 0x49,
-  0xeb, 0xb1, 0x36, 0x8c, 0x7c, 0xca, 0x84, 0xae, 0x3c, 0xaf, 0x38, 0x88,
-  0x28, 0x99, 0x8d, 0x2d, 0x58, 0x13, 0xb1, 0x97, 0x78, 0x3e, 0x52, 0x20,
-  0x67, 0xac, 0x5b, 0x73, 0x98, 0x6c, 0x32, 0x55, 0xc9, 0x70, 0xd1, 0xd9,
-  0xaa, 0x15, 0xe8, 0x2e, 0x26, 0x85, 0x81, 0xbc, 0x56, 0xe4, 0xbc, 0x80,
-  0x63, 0xdb, 0x4e, 0xd7, 0xf5, 0x02, 0xbe, 0x51, 0x63, 0x1e, 0x3c, 0xdb,
-  0xdf, 0xd7, 0x00, 0x5d, 0x5a, 0xb9, 0xe5, 0x7b, 0x6a, 0xea, 0x38, 0x20,
-  0xb2, 0x3b, 0xb6, 0xee, 0x75, 0x54, 0x84, 0xf9, 0xa6, 0xca, 0x38, 0x70,
-  0xdd, 0xbf, 0xb0, 0xff, 0xa5, 0x85, 0x5d, 0xb4, 0x41, 0xfe, 0xdd, 0x3d,
-  0xd9, 0x2a, 0xe1, 0x30, 0x43, 0x1a, 0x98, 0x79, 0x93, 0xa0, 0x5f, 0xe0,
-  0x67, 0x6c, 0x95, 0xfa, 0x3e, 0x7a, 0xae, 0x71, 0x7b, 0xe3, 0x6d, 0x88,
-  0x42, 0x3f, 0x25, 0xd4, 0xee, 0xbe, 0x68, 0x68, 0xac, 0xad, 0xac, 0x60,
-  0xe0, 0x20, 0xa3, 0x39, 0x83, 0xb9, 0x5b, 0x28, 0xa3, 0x93, 0x6d, 0xa1,
-  0xbd, 0x76, 0x0a, 0xe3, 0xeb, 0xae, 0x87, 0x27, 0x0e, 0x54, 0x8f, 0xb4,
-  0x48, 0x0c, 0x9a, 0x54, 0xf4, 0x5d, 0x8e, 0x37, 0x50, 0xdc, 0x5e, 0xa4,
-  0x8b, 0x6b, 0x4b, 0xdc, 0xa6, 0xf3, 0x34, 0xbe, 0x77, 0x59, 0x22, 0x88,
-  0xff, 0x19, 0x2b, 0x6d, 0x76, 0x64, 0x73, 0xda, 0x0c, 0x87, 0x07, 0x2b,
-  0x9a, 0x37, 0x3a, 0xd0, 0xe2, 0x8c, 0xf6, 0x36, 0x32, 0x6b, 0x9a, 0x79,
-  0xcc, 0xd2, 0x3b, 0x93, 0x6f, 0x1a, 0x4d, 0x6c, 0xe6, 0xc1, 0x9d, 0x40,
-  0xac, 0x2d, 0x74, 0xc3, 0xbe, 0xea, 0x5c, 0x73, 0x65, 0x01, 0x29, 0xb1,
-  0x2a, 0xbf, 0x70, 0x59, 0xc1, 0xce, 0xc6, 0xc3, 0xa2, 0xc8, 0x45, 0x5f,
-  0xba, 0x67, 0x3d, 0x0f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01,
-  0xea, 0x30, 0x82, 0x01, 0xe6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
-  0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28,
-  0x98, 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2,
-  0xc3, 0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
-  0x14, 0xd5, 0x8e, 0x5a, 0x51, 0x13, 0xb4, 0x29, 0x0d, 0x31, 0xb6, 0x1c,
-  0x8d, 0x3e, 0x51, 0x51, 0x31, 0x0a, 0x33, 0xaa, 0x81, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05,
-  0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
-  0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
-  0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01,
-  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46,
-  0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06,
-  0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03,
-  0x04, 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
-  0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f,
-  0x64, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b,
-  0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0,
-  0x36, 0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
-  0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61,
-  0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45,
-  0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77,
-  0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0,
-  0x32, 0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72,
-  0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74,
-  0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
-  0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e,
-  0x63, 0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f,
-  0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e,
-  0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
-  0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08,
-  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74,
-  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f,
-  0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2f,
-  0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x28, 0x30, 0x26, 0x82, 0x0f, 0x6c,
-  0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x73, 0x6b, 0x79, 0x70, 0x65, 0x2e, 0x63,
-  0x6f, 0x6d, 0x82, 0x13, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x6f, 0x67, 0x69,
-  0x6e, 0x2e, 0x73, 0x6b, 0x79, 0x70, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
-  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-  0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x08, 0xf2, 0x81, 0x75, 0x91,
-  0xbb, 0xce, 0x12, 0x04, 0x18, 0xc2, 0x4d, 0x5a, 0xfb, 0x46, 0x90, 0x0a,
-  0x54, 0x44, 0xf4, 0xf2, 0xdd, 0x07, 0x81, 0xf0, 0x1f, 0xa6, 0x7a, 0x6f,
-  0x9f, 0xcf, 0xb8, 0x0e, 0x2c, 0x4f, 0x9c, 0xc4, 0x9a, 0xf5, 0xa8, 0xf6,
-  0xba, 0xa4, 0xc9, 0x7a, 0x5d, 0xb1, 0xe2, 0x5a, 0xca, 0x3c, 0xfa, 0x60,
-  0xa8, 0x68, 0x3e, 0xcb, 0xba, 0x2d, 0xe2, 0xcd, 0xd6, 0xb6, 0xe4, 0x92,
-  0x3c, 0x69, 0xad, 0x57, 0xea, 0xa8, 0x2f, 0x38, 0x10, 0x84, 0x72, 0xe5,
-  0x68, 0x71, 0xed, 0xbe, 0xeb, 0x6e, 0x18, 0xef, 0x63, 0x7a, 0xbe, 0xe7,
-  0x24, 0xff, 0xc0, 0x63, 0xfd, 0x58, 0x3b, 0x4c, 0x81, 0x92, 0xd8, 0x29,
-  0xab, 0x8e, 0x35, 0x5d, 0xd7, 0xd3, 0x09, 0x6b, 0x85, 0xd3, 0xd5, 0x73,
-  0x05, 0x44, 0xe2, 0xe5, 0xbb, 0x83, 0x53, 0x10, 0xcb, 0xf2, 0xcf, 0xb7,
-  0x6e, 0xe1, 0x69, 0xb7, 0xa1, 0x92, 0x64, 0xc5, 0xcf, 0xcd, 0x82, 0xbb,
-  0x36, 0xa0, 0x38, 0xad, 0xd7, 0x24, 0xdf, 0x53, 0xfc, 0x3f, 0x62, 0xb7,
-  0xb7, 0xd5, 0xc7, 0x57, 0xe3, 0x93, 0x31, 0x70, 0x8e, 0x24, 0x89, 0x86,
-  0xca, 0x63, 0x2b, 0x39, 0xba, 0x5d, 0xd9, 0x6a, 0x60, 0xec, 0xa1, 0x4e,
-  0x8a, 0xfe, 0x53, 0xf8, 0x5e, 0x92, 0xdf, 0x2f, 0x5c, 0x26, 0x17, 0x6d,
-  0x03, 0x7d, 0x02, 0x0f, 0x0f, 0xaa, 0x43, 0x67, 0x6d, 0xb0, 0x62, 0xbf,
-  0x7e, 0x53, 0xdd, 0xcc, 0xec, 0x78, 0x73, 0x95, 0xe5, 0xa5, 0xf6, 0x00,
-  0xa3, 0x04, 0xfd, 0x3f, 0x04, 0x2a, 0xb3, 0x98, 0xc5, 0xb7, 0x03, 0x1c,
-  0xdb, 0xc9, 0x50, 0xab, 0xb0, 0x05, 0x1d, 0x1e, 0xbe, 0x56, 0xb4, 0xcf,
-  0x3e, 0x42, 0x13, 0x94, 0x9e, 0xf9, 0xe7, 0x01, 0x81, 0xa5, 0x78, 0x6f,
-  0x0c, 0x7a, 0x76, 0xac, 0x05, 0x86, 0xec, 0xac, 0xc2, 0x11, 0xac
-};
-unsigned int login_skype_com_cer_len = 1523;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.1.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.1.cer.h
deleted file mode 100644 (file)
index 5c1a3ee..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-unsigned char login_yahoo_com_1_cer[] = {
-  0x30, 0x82, 0x05, 0xd9, 0x30, 0x82, 0x04, 0xc1, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x10, 0x39, 0x2a, 0x43, 0x4f, 0x0e, 0x07, 0xdf, 0x1f, 0x8a,
-  0xa3, 0x05, 0xde, 0x34, 0xe0, 0xc2, 0x29, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
-  0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-  0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-  0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07,
-  0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65, 0x20,
-  0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
-  0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
-  0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-  0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x68,
-  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73,
-  0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
-  0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54,
-  0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d,
-  0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d,
-  0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33, 0x35,
-  0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xdf, 0x31, 0x0b, 0x30, 0x09, 0x06,
-  0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c,
-  0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37, 0x37,
-  0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x46,
-  0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68,
-  0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e, 0x53,
-  0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20, 0x31,
-  0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b,
-  0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31,
-  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54, 0x65,
-  0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30, 0x26,
-  0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74, 0x65,
-  0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72, 0x6f,
-  0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
-  0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
-  0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53, 0x4c,
-  0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x6c,
-  0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 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, 0xa1,
-  0xa4, 0x05, 0x3d, 0xed, 0x85, 0x45, 0x93, 0x8a, 0x18, 0x4d, 0xc6, 0x03,
-  0x00, 0x57, 0xe2, 0x40, 0x77, 0xf0, 0x1c, 0xeb, 0xd0, 0x19, 0xdf, 0x22,
-  0x5d, 0x08, 0x7f, 0xd1, 0x07, 0x3c, 0x41, 0x89, 0x46, 0x17, 0xa3, 0x09,
-  0xfa, 0xfc, 0xf8, 0xa9, 0x04, 0xd1, 0x96, 0x8f, 0xab, 0xd7, 0x4f, 0x3c,
-  0xf9, 0xad, 0x18, 0xa9, 0x74, 0x81, 0xc4, 0x57, 0x0a, 0x3a, 0x26, 0x16,
-  0xce, 0x62, 0x3e, 0xbc, 0x3f, 0x6c, 0x21, 0xee, 0x93, 0x8d, 0xcb, 0x0d,
-  0xa0, 0x1f, 0x9a, 0x96, 0xd0, 0x8f, 0xad, 0xf5, 0x93, 0x93, 0x82, 0xee,
-  0x72, 0x0c, 0xa1, 0x75, 0x15, 0xa3, 0x7b, 0x84, 0x56, 0xb8, 0xad, 0xff,
-  0x52, 0x11, 0x71, 0x84, 0xbc, 0x3a, 0x30, 0x0b, 0x7e, 0x98, 0xa8, 0xe1,
-  0xa8, 0x3f, 0x37, 0x52, 0xd0, 0xf1, 0x7c, 0x6f, 0x90, 0xd8, 0x45, 0x0a,
-  0xac, 0x39, 0x72, 0x6a, 0x61, 0xd5, 0xbb, 0xc3, 0x8c, 0xf9, 0xc2, 0xcc,
-  0xdf, 0xfd, 0x3a, 0x71, 0xb9, 0xaf, 0xbc, 0xdc, 0x3a, 0xdc, 0x0c, 0xb6,
-  0xb1, 0xd2, 0xd1, 0x89, 0xbb, 0x41, 0xb6, 0xf2, 0xde, 0x57, 0xd5, 0x15,
-  0xdf, 0xfc, 0xfd, 0xe2, 0x31, 0xc5, 0xdf, 0xca, 0xc1, 0xd8, 0x8f, 0x2c,
-  0xbf, 0xf0, 0x0e, 0x5b, 0x71, 0xe0, 0x34, 0x71, 0xc3, 0xc5, 0x4d, 0x7d,
-  0x7a, 0xd4, 0xfa, 0xed, 0x30, 0x4b, 0x2f, 0xea, 0xb6, 0x2e, 0x9e, 0x93,
-  0x3c, 0xe2, 0x3a, 0xf8, 0x42, 0xa2, 0x1a, 0xee, 0xdc, 0xdf, 0xcd, 0x0f,
-  0xa9, 0xf6, 0x79, 0x84, 0x1a, 0x8e, 0x6c, 0x02, 0xb6, 0x86, 0xe5, 0xbf,
-  0x51, 0x6a, 0x66, 0xf8, 0xf3, 0x9c, 0xd3, 0x59, 0x0c, 0x7b, 0xa5, 0x99,
-  0x78, 0xcd, 0x7c, 0x99, 0xfa, 0xc6, 0x96, 0x47, 0xd8, 0x32, 0xd4, 0x74,
-  0x76, 0x0e, 0x77, 0x4b, 0x20, 0x74, 0xa4, 0xb7, 0x89, 0x75, 0x92, 0x4a,
-  0xb4, 0x5b, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd5,
-  0x30, 0x82, 0x01, 0xd1, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-  0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-  0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3,
-  0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-  0x86, 0x49, 0x45, 0xfc, 0x33, 0x19, 0x33, 0xd4, 0x04, 0xed, 0x27, 0x61,
-  0xee, 0xe8, 0x01, 0xc9, 0x0c, 0x7f, 0x2f, 0x7e, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0,
-  0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
-  0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
-  0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
-  0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06,
-  0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c,
-  0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04,
-  0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
-  0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06,
-  0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36,
-  0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
-  0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e,
-  0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32,
-  0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
-  0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
-  0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63,
-  0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41,
-  0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
-  0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
-  0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1a, 0x06,
-  0x03, 0x55, 0x1d, 0x11, 0x04, 0x13, 0x30, 0x11, 0x82, 0x0f, 0x6c, 0x6f,
-  0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
-  0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-  0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x57, 0x62, 0xe1,
-  0x77, 0xeb, 0xfc, 0x1f, 0xbf, 0x88, 0x53, 0xaf, 0x58, 0xd3, 0xd4, 0xd6,
-  0x6d, 0x67, 0x30, 0x17, 0x40, 0xbe, 0xe0, 0x1f, 0x64, 0xde, 0x87, 0x15,
-  0xcc, 0xe0, 0xa4, 0x56, 0xa9, 0xd1, 0x9f, 0xf9, 0x01, 0xfe, 0x02, 0xb1,
-  0xb1, 0xea, 0xe2, 0x5f, 0xee, 0x71, 0x16, 0x31, 0xf9, 0x08, 0xd5, 0xc2,
-  0xd7, 0x9a, 0x9b, 0xb2, 0x5a, 0x38, 0xd7, 0xa9, 0x7f, 0xe9, 0x87, 0x6b,
-  0x31, 0xf9, 0x0b, 0xac, 0xd9, 0xfd, 0x50, 0x71, 0xe0, 0xdb, 0x82, 0x92,
-  0x0f, 0x81, 0x9c, 0x8d, 0x77, 0xe9, 0xeb, 0x2e, 0xea, 0xd4, 0x23, 0x41,
-  0x87, 0xec, 0x2d, 0xb2, 0x78, 0xb3, 0x8e, 0xb1, 0x67, 0xd2, 0xee, 0x71,
-  0x03, 0x08, 0x12, 0x99, 0xb3, 0x02, 0x29, 0x6f, 0xde, 0x8b, 0xde, 0xc1,
-  0xa9, 0x03, 0x0a, 0x5a, 0x33, 0x1c, 0x3d, 0x11, 0x03, 0xc6, 0x48, 0x0c,
-  0x98, 0x9c, 0x15, 0x2e, 0xd9, 0xa6, 0x85, 0x52, 0xe7, 0x05, 0x8a, 0xae,
-  0x30, 0x23, 0xeb, 0xed, 0x28, 0x6c, 0x60, 0xe9, 0x2d, 0x7f, 0x8f, 0x47,
-  0x8b, 0x2f, 0xd0, 0xdc, 0xe6, 0xbb, 0x0f, 0x7e, 0x5f, 0xf2, 0x48, 0x81,
-  0x8e, 0x50, 0x04, 0x63, 0xb1, 0x51, 0x80, 0x75, 0x9a, 0xa9, 0xb6, 0x10,
-  0x1c, 0x10, 0x5f, 0x6f, 0x18, 0x6f, 0xe0, 0x0e, 0x96, 0x45, 0xce, 0xee,
-  0xf1, 0xb5, 0x20, 0xdb, 0xef, 0xda, 0x6e, 0xc8, 0x95, 0xe3, 0xf6, 0x45,
-  0xfd, 0xca, 0xfc, 0xa5, 0x5f, 0x49, 0x6d, 0x06, 0x1e, 0xd2, 0xde, 0x61,
-  0x3d, 0x15, 0x7d, 0x37, 0xe5, 0x1c, 0x35, 0x8e, 0x06, 0xc2, 0x6b, 0xf7,
-  0xb4, 0xa8, 0x28, 0x2c, 0x31, 0xcb, 0xaa, 0xb4, 0xa7, 0x97, 0x4f, 0x9d,
-  0x8a, 0xf6, 0xaf, 0x7e, 0x37, 0xb9, 0x7b, 0x3d, 0xdf, 0x92, 0x66, 0x8b,
-  0x8f, 0x4e, 0x9d, 0xc6, 0x36, 0xe7, 0x5c, 0xa6, 0xab, 0x12, 0x0f, 0xd6,
-  0xcf
-};
-unsigned int login_yahoo_com_1_cer_len = 1501;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.2.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.2.cer.h
deleted file mode 100644 (file)
index 107dd15..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-unsigned char login_yahoo_com_2_cer[] = {
-  0x30, 0x82, 0x05, 0xd9, 0x30, 0x82, 0x04, 0xc1, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x10, 0x3e, 0x75, 0xce, 0xd4, 0x6b, 0x69, 0x30, 0x21, 0x21,
-  0x88, 0x30, 0xae, 0x86, 0xa8, 0x2a, 0x71, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
-  0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-  0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-  0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07,
-  0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65, 0x20,
-  0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
-  0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
-  0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-  0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x68,
-  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73,
-  0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
-  0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54,
-  0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d,
-  0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d,
-  0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33, 0x35,
-  0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xdf, 0x31, 0x0b, 0x30, 0x09, 0x06,
-  0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c,
-  0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37, 0x37,
-  0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x46,
-  0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68,
-  0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e, 0x53,
-  0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20, 0x31,
-  0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b,
-  0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31,
-  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54, 0x65,
-  0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30, 0x26,
-  0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74, 0x65,
-  0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72, 0x6f,
-  0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
-  0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
-  0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53, 0x4c,
-  0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x6c,
-  0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 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, 0xa1,
-  0xa4, 0x05, 0x3d, 0xed, 0x85, 0x45, 0x93, 0x8a, 0x18, 0x4d, 0xc6, 0x03,
-  0x00, 0x57, 0xe2, 0x40, 0x77, 0xf0, 0x1c, 0xeb, 0xd0, 0x19, 0xdf, 0x22,
-  0x5d, 0x08, 0x7f, 0xd1, 0x07, 0x3c, 0x41, 0x89, 0x46, 0x17, 0xa3, 0x09,
-  0xfa, 0xfc, 0xf8, 0xa9, 0x04, 0xd1, 0x96, 0x8f, 0xab, 0xd7, 0x4f, 0x3c,
-  0xf9, 0xad, 0x18, 0xa9, 0x74, 0x81, 0xc4, 0x57, 0x0a, 0x3a, 0x26, 0x16,
-  0xce, 0x62, 0x3e, 0xbc, 0x3f, 0x6c, 0x21, 0xee, 0x93, 0x8d, 0xcb, 0x0d,
-  0xa0, 0x1f, 0x9a, 0x96, 0xd0, 0x8f, 0xad, 0xf5, 0x93, 0x93, 0x82, 0xee,
-  0x72, 0x0c, 0xa1, 0x75, 0x15, 0xa3, 0x7b, 0x84, 0x56, 0xb8, 0xad, 0xff,
-  0x52, 0x11, 0x71, 0x84, 0xbc, 0x3a, 0x30, 0x0b, 0x7e, 0x98, 0xa8, 0xe1,
-  0xa8, 0x3f, 0x37, 0x52, 0xd0, 0xf1, 0x7c, 0x6f, 0x90, 0xd8, 0x45, 0x0a,
-  0xac, 0x39, 0x72, 0x6a, 0x61, 0xd5, 0xbb, 0xc3, 0x8c, 0xf9, 0xc2, 0xcc,
-  0xdf, 0xfd, 0x3a, 0x71, 0xb9, 0xaf, 0xbc, 0xdc, 0x3a, 0xdc, 0x0c, 0xb6,
-  0xb1, 0xd2, 0xd1, 0x89, 0xbb, 0x41, 0xb6, 0xf2, 0xde, 0x57, 0xd5, 0x15,
-  0xdf, 0xfc, 0xfd, 0xe2, 0x31, 0xc5, 0xdf, 0xca, 0xc1, 0xd8, 0x8f, 0x2c,
-  0xbf, 0xf0, 0x0e, 0x5b, 0x71, 0xe0, 0x34, 0x71, 0xc3, 0xc5, 0x4d, 0x7d,
-  0x7a, 0xd4, 0xfa, 0xed, 0x30, 0x4b, 0x2f, 0xea, 0xb6, 0x2e, 0x9e, 0x93,
-  0x3c, 0xe2, 0x3a, 0xf8, 0x42, 0xa2, 0x1a, 0xee, 0xdc, 0xdf, 0xcd, 0x0f,
-  0xa9, 0xf6, 0x79, 0x84, 0x1a, 0x8e, 0x6c, 0x02, 0xb6, 0x86, 0xe5, 0xbf,
-  0x51, 0x6a, 0x66, 0xf8, 0xf3, 0x9c, 0xd3, 0x59, 0x0c, 0x7b, 0xa5, 0x99,
-  0x78, 0xcd, 0x7c, 0x99, 0xfa, 0xc6, 0x96, 0x47, 0xd8, 0x32, 0xd4, 0x74,
-  0x76, 0x0e, 0x77, 0x4b, 0x20, 0x74, 0xa4, 0xb7, 0x89, 0x75, 0x92, 0x4a,
-  0xb4, 0x5b, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xd5,
-  0x30, 0x82, 0x01, 0xd1, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-  0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-  0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3,
-  0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-  0x86, 0x49, 0x45, 0xfc, 0x33, 0x19, 0x33, 0xd4, 0x04, 0xed, 0x27, 0x61,
-  0xee, 0xe8, 0x01, 0xc9, 0x0c, 0x7f, 0x2f, 0x7e, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0,
-  0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
-  0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
-  0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
-  0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06,
-  0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c,
-  0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04,
-  0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
-  0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06,
-  0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36,
-  0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
-  0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e,
-  0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32,
-  0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
-  0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
-  0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63,
-  0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41,
-  0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
-  0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
-  0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1a, 0x06,
-  0x03, 0x55, 0x1d, 0x11, 0x04, 0x13, 0x30, 0x11, 0x82, 0x0f, 0x6c, 0x6f,
-  0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f,
-  0x6d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-  0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x53, 0x69, 0x98,
-  0x8e, 0x28, 0x4e, 0x9c, 0x2b, 0x5b, 0x1d, 0xcc, 0x6b, 0x77, 0x28, 0x3d,
-  0xbb, 0xfa, 0xa5, 0x4e, 0x7e, 0x56, 0x29, 0xa4, 0xea, 0x10, 0xe2, 0xf4,
-  0xe6, 0x2d, 0x06, 0xd1, 0x84, 0xdb, 0x23, 0xce, 0x97, 0xf3, 0x68, 0xb6,
-  0x0f, 0x3a, 0xde, 0x15, 0x0b, 0x24, 0x1d, 0x91, 0xe3, 0x6c, 0x2e, 0x30,
-  0xb7, 0xe9, 0x70, 0xb0, 0xc3, 0x46, 0x80, 0xf0, 0xd3, 0xb1, 0x51, 0xbf,
-  0x4f, 0xd6, 0x78, 0xa0, 0xfc, 0xac, 0xc6, 0xcf, 0x31, 0x04, 0x63, 0xe2,
-  0x34, 0x55, 0x05, 0x4a, 0x3d, 0xf6, 0x30, 0xba, 0xf3, 0x33, 0xe5, 0xba,
-  0xd2, 0x96, 0xf3, 0xd5, 0xb1, 0xb6, 0x93, 0x89, 0x1a, 0xa4, 0x68, 0xbe,
-  0x7e, 0xed, 0x63, 0xb4, 0x1a, 0x48, 0xc0, 0x53, 0xe4, 0xa3, 0xf0, 0x39,
-  0x0c, 0x32, 0x92, 0xc7, 0x43, 0x0d, 0x1a, 0x71, 0xed, 0xd0, 0x46, 0x93,
-  0xbf, 0x93, 0x62, 0x6c, 0x33, 0x4b, 0xcd, 0x36, 0x0d, 0x69, 0x5e, 0xbb,
-  0x6c, 0x96, 0x99, 0x21, 0x69, 0xc4, 0x4b, 0x67, 0x72, 0xdb, 0x6c, 0x6a,
-  0xb8, 0xf7, 0x68, 0xed, 0xc5, 0x8f, 0xad, 0x63, 0x65, 0x95, 0x0a, 0x4c,
-  0xe0, 0xf9, 0x0f, 0x7e, 0x37, 0x3d, 0xaa, 0xd4, 0x93, 0xba, 0x67, 0x09,
-  0xc3, 0xa5, 0xa4, 0x0d, 0x03, 0x5a, 0x6d, 0xd5, 0x0b, 0xfe, 0xf0, 0x40,
-  0x14, 0xb4, 0xf6, 0xb8, 0x69, 0x7c, 0x6d, 0xc2, 0x32, 0x4b, 0x9f, 0xb5,
-  0x1a, 0xe7, 0x46, 0xae, 0x4c, 0x5a, 0x2b, 0xaa, 0x7a, 0x5e, 0x90, 0x57,
-  0x95, 0xfa, 0xdb, 0x66, 0x02, 0x20, 0x1e, 0x6a, 0x69, 0x66, 0x15, 0x9c,
-  0xc2, 0xb6, 0xf5, 0xbc, 0x50, 0xb5, 0xfd, 0x45, 0xc7, 0x1f, 0x68, 0xb4,
-  0x47, 0x59, 0xac, 0xc4, 0x1b, 0x28, 0x93, 0x4e, 0x52, 0x53, 0x12, 0x03,
-  0x58, 0x4b, 0x71, 0x83, 0x9f, 0x66, 0xe6, 0xac, 0x79, 0x48, 0xfe, 0xfe,
-  0x47
-};
-unsigned int login_yahoo_com_2_cer_len = 1501;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/login.yahoo.com.cer.h
deleted file mode 100644 (file)
index 4f5ba04..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-unsigned char login_yahoo_com_cer[] = {
-  0x30, 0x82, 0x05, 0xef, 0x30, 0x82, 0x04, 0xd7, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0xd7, 0x55, 0x8f, 0xda, 0xf5, 0xf1, 0x10, 0x5b,
-  0xb2, 0x13, 0x28, 0x2b, 0x70, 0x77, 0x29, 0xa3, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xdf, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73,
-  0x68, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e,
-  0x53, 0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20,
-  0x31, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-  0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e,
-  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54,
-  0x65, 0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30,
-  0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74,
-  0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72,
-  0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
-  0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
-  0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53,
-  0x4c, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f,
-  0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 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,
-  0xa1, 0xa4, 0x05, 0x3d, 0xed, 0x85, 0x45, 0x93, 0x8a, 0x18, 0x4d, 0xc6,
-  0x03, 0x00, 0x57, 0xe2, 0x40, 0x77, 0xf0, 0x1c, 0xeb, 0xd0, 0x19, 0xdf,
-  0x22, 0x5d, 0x08, 0x7f, 0xd1, 0x07, 0x3c, 0x41, 0x89, 0x46, 0x17, 0xa3,
-  0x09, 0xfa, 0xfc, 0xf8, 0xa9, 0x04, 0xd1, 0x96, 0x8f, 0xab, 0xd7, 0x4f,
-  0x3c, 0xf9, 0xad, 0x18, 0xa9, 0x74, 0x81, 0xc4, 0x57, 0x0a, 0x3a, 0x26,
-  0x16, 0xce, 0x62, 0x3e, 0xbc, 0x3f, 0x6c, 0x21, 0xee, 0x93, 0x8d, 0xcb,
-  0x0d, 0xa0, 0x1f, 0x9a, 0x96, 0xd0, 0x8f, 0xad, 0xf5, 0x93, 0x93, 0x82,
-  0xee, 0x72, 0x0c, 0xa1, 0x75, 0x15, 0xa3, 0x7b, 0x84, 0x56, 0xb8, 0xad,
-  0xff, 0x52, 0x11, 0x71, 0x84, 0xbc, 0x3a, 0x30, 0x0b, 0x7e, 0x98, 0xa8,
-  0xe1, 0xa8, 0x3f, 0x37, 0x52, 0xd0, 0xf1, 0x7c, 0x6f, 0x90, 0xd8, 0x45,
-  0x0a, 0xac, 0x39, 0x72, 0x6a, 0x61, 0xd5, 0xbb, 0xc3, 0x8c, 0xf9, 0xc2,
-  0xcc, 0xdf, 0xfd, 0x3a, 0x71, 0xb9, 0xaf, 0xbc, 0xdc, 0x3a, 0xdc, 0x0c,
-  0xb6, 0xb1, 0xd2, 0xd1, 0x89, 0xbb, 0x41, 0xb6, 0xf2, 0xde, 0x57, 0xd5,
-  0x15, 0xdf, 0xfc, 0xfd, 0xe2, 0x31, 0xc5, 0xdf, 0xca, 0xc1, 0xd8, 0x8f,
-  0x2c, 0xbf, 0xf0, 0x0e, 0x5b, 0x71, 0xe0, 0x34, 0x71, 0xc3, 0xc5, 0x4d,
-  0x7d, 0x7a, 0xd4, 0xfa, 0xed, 0x30, 0x4b, 0x2f, 0xea, 0xb6, 0x2e, 0x9e,
-  0x93, 0x3c, 0xe2, 0x3a, 0xf8, 0x42, 0xa2, 0x1a, 0xee, 0xdc, 0xdf, 0xcd,
-  0x0f, 0xa9, 0xf6, 0x79, 0x84, 0x1a, 0x8e, 0x6c, 0x02, 0xb6, 0x86, 0xe5,
-  0xbf, 0x51, 0x6a, 0x66, 0xf8, 0xf3, 0x9c, 0xd3, 0x59, 0x0c, 0x7b, 0xa5,
-  0x99, 0x78, 0xcd, 0x7c, 0x99, 0xfa, 0xc6, 0x96, 0x47, 0xd8, 0x32, 0xd4,
-  0x74, 0x76, 0x0e, 0x77, 0x4b, 0x20, 0x74, 0xa4, 0xb7, 0x89, 0x75, 0x92,
-  0x4a, 0xb4, 0x5b, 0x55, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01,
-  0xea, 0x30, 0x82, 0x01, 0xe6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
-  0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28,
-  0x98, 0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2,
-  0xc3, 0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04,
-  0x14, 0x86, 0x49, 0x45, 0xfc, 0x33, 0x19, 0x33, 0xd4, 0x04, 0xed, 0x27,
-  0x61, 0xee, 0xe8, 0x01, 0xc9, 0x0c, 0x7f, 0x2f, 0x7e, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05,
-  0xa0, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
-  0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
-  0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01,
-  0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46,
-  0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06,
-  0x0c, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03,
-  0x04, 0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f,
-  0x2f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f,
-  0x64, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b,
-  0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0,
-  0x36, 0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
-  0x63, 0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61,
-  0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45,
-  0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77,
-  0x61, 0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0,
-  0x32, 0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72,
-  0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74,
-  0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72,
-  0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e,
-  0x63, 0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
-  0x07, 0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f,
-  0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e,
-  0x41, 0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76,
-  0x65, 0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08,
-  0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74,
-  0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f,
-  0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2f,
-  0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x28, 0x30, 0x26, 0x82, 0x0f, 0x6c,
-  0x6f, 0x67, 0x69, 0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63,
-  0x6f, 0x6d, 0x82, 0x13, 0x77, 0x77, 0x77, 0x2e, 0x6c, 0x6f, 0x67, 0x69,
-  0x6e, 0x2e, 0x79, 0x61, 0x68, 0x6f, 0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
-  0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
-  0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x3d, 0x57, 0xc9, 0x48, 0x24,
-  0x5c, 0xee, 0x64, 0x81, 0xf5, 0xae, 0xbe, 0x55, 0x29, 0x16, 0xff, 0x2a,
-  0x2f, 0x84, 0xed, 0xd9, 0xf8, 0xa3, 0x03, 0xc8, 0x30, 0x66, 0xbb, 0xc8,
-  0xd4, 0x81, 0x2d, 0x21, 0xf7, 0x08, 0xf7, 0xac, 0x96, 0x42, 0x9a, 0x41,
-  0x75, 0x7a, 0xba, 0x5d, 0x10, 0x23, 0xcb, 0x92, 0x42, 0x61, 0xfa, 0x8a,
-  0xda, 0x6d, 0x65, 0x34, 0x19, 0xe5, 0xa9, 0xd6, 0x2d, 0x13, 0x78, 0xd7,
-  0x81, 0x44, 0x92, 0xa9, 0x6e, 0x80, 0x63, 0x15, 0xcb, 0xfe, 0x35, 0x1f,
-  0x02, 0xd1, 0x8a, 0x14, 0xb0, 0xa8, 0xcc, 0x94, 0x20, 0x3b, 0xa8, 0x1a,
-  0xf0, 0x5d, 0x36, 0x50, 0xdb, 0x0d, 0xae, 0xe9, 0x64, 0xe4, 0xf6, 0x8d,
-  0x69, 0x7d, 0x30, 0xc8, 0x14, 0x17, 0x00, 0x4a, 0xe5, 0xa6, 0x35, 0xfb,
-  0x7d, 0x0d, 0x22, 0x9d, 0x79, 0x76, 0x52, 0x2c, 0xbc, 0x97, 0x06, 0x88,
-  0x9a, 0x15, 0xf4, 0x73, 0xe6, 0xf1, 0xf5, 0x98, 0xa5, 0xcd, 0x07, 0x44,
-  0x91, 0xb8, 0xa7, 0x68, 0x67, 0x45, 0xd2, 0x72, 0x11, 0x60, 0xe2, 0x71,
-  0xb7, 0x50, 0x55, 0xe2, 0x8a, 0xa9, 0x0d, 0xd6, 0x92, 0xee, 0x04, 0x2a,
-  0x8b, 0x30, 0xa0, 0xa2, 0x05, 0x46, 0x34, 0x6d, 0x92, 0xc6, 0x3b, 0xaa,
-  0x4d, 0xa0, 0xd0, 0xab, 0x01, 0x19, 0x0a, 0x32, 0xb7, 0xe8, 0xe3, 0xcf,
-  0xf1, 0xd2, 0x97, 0x49, 0x7b, 0xac, 0xa4, 0x97, 0xf7, 0xf0, 0x57, 0xae,
-  0x63, 0x77, 0x9a, 0x7f, 0x96, 0xda, 0x4d, 0xfd, 0xbe, 0xdc, 0x07, 0x36,
-  0xe3, 0x25, 0xbd, 0x89, 0x79, 0x8e, 0x29, 0x12, 0x13, 0x8b, 0x88, 0x07,
-  0xfb, 0x6b, 0xdb, 0xa4, 0xcd, 0xb3, 0x2d, 0x27, 0xe9, 0xd4, 0xca, 0x60,
-  0xd7, 0x85, 0x53, 0xfb, 0x74, 0xc6, 0x5c, 0x35, 0x8c, 0x70, 0x1f, 0xf9,
-  0xb2, 0xb7, 0x92, 0x27, 0x20, 0xc7, 0x94, 0xd5, 0x67, 0x14, 0x30
-};
-unsigned int login_yahoo_com_cer_len = 1523;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/mail.google.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/mail.google.com.cer.h
deleted file mode 100644 (file)
index 21f5c08..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-unsigned char mail_google_com_cer[] = {
-  0x30, 0x82, 0x05, 0xee, 0x30, 0x82, 0x04, 0xd6, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x10, 0x04, 0x7e, 0xcb, 0xe9, 0xfc, 0xa5, 0x5f, 0x7b, 0xd0,
-  0x9e, 0xae, 0x36, 0xe1, 0x0c, 0xae, 0x1e, 0x30, 0x0d, 0x06, 0x09, 0x2a,
-  0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x81,
-  0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-  0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13,
-  0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x07,
-  0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65, 0x20,
-  0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55, 0x04,
-  0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54,
-  0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b,
-  0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x68,
-  0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75, 0x73,
-  0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x31,
-  0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55, 0x54,
-  0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74, 0x2d,
-  0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17, 0x0d,
-  0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33, 0x35,
-  0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xdf, 0x31, 0x0b, 0x30, 0x09, 0x06,
-  0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30, 0x0c,
-  0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37, 0x37,
-  0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07, 0x46,
-  0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73, 0x68,
-  0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e, 0x53,
-  0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20, 0x31,
-  0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0b,
-  0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e, 0x31,
-  0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54, 0x65,
-  0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30, 0x26,
-  0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74, 0x65,
-  0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72, 0x6f,
-  0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
-  0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13,
-  0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53, 0x4c,
-  0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0f, 0x6d,
-  0x61, 0x69, 0x6c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 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, 0xb0,
-  0x73, 0xf0, 0xf2, 0x04, 0xee, 0xc2, 0xa2, 0x46, 0xca, 0x34, 0x2a, 0xaa,
-  0xbb, 0x60, 0x23, 0xd1, 0x11, 0x76, 0x1f, 0x1f, 0x3a, 0xd0, 0x65, 0x83,
-  0x4e, 0x9a, 0x45, 0xa8, 0x43, 0x70, 0x85, 0x76, 0xf0, 0x1f, 0x87, 0x00,
-  0x02, 0x1f, 0x6e, 0x3b, 0x17, 0x17, 0xc4, 0xb5, 0xe9, 0x19, 0x46, 0xa2,
-  0x92, 0x25, 0x8d, 0x62, 0x2a, 0xb4, 0x63, 0x30, 0x1f, 0xb9, 0x85, 0xf8,
-  0x35, 0xe1, 0x16, 0x5a, 0x76, 0x49, 0xcc, 0x50, 0x48, 0x53, 0x39, 0x59,
-  0x89, 0xd6, 0x84, 0x02, 0xfb, 0x9a, 0xec, 0x1b, 0xc7, 0x51, 0xd5, 0x76,
-  0x95, 0x90, 0xd4, 0x3a, 0x2a, 0xb8, 0xa6, 0xde, 0x02, 0x4d, 0x06, 0xfb,
-  0xcd, 0xed, 0xa5, 0x46, 0x41, 0x5f, 0x55, 0x74, 0xe5, 0xec, 0x7e, 0x40,
-  0xdc, 0x50, 0x9c, 0xb5, 0xe4, 0x35, 0x5d, 0x1e, 0x68, 0x20, 0xf8, 0xe9,
-  0xde, 0xa3, 0x6a, 0x28, 0xbf, 0x41, 0xd2, 0xa1, 0xb3, 0xe2, 0x25, 0x8d,
-  0x0c, 0x1b, 0xca, 0x3d, 0x93, 0x0c, 0x18, 0xae, 0xdf, 0xc5, 0xbc, 0xfd,
-  0xbc, 0x82, 0xba, 0x68, 0x00, 0xd7, 0x16, 0x32, 0x71, 0x9f, 0x65, 0xb5,
-  0x11, 0xda, 0x68, 0x59, 0xd0, 0xa6, 0x57, 0x64, 0x1b, 0xc9, 0xfe, 0x98,
-  0xe5, 0xf5, 0xa5, 0x65, 0xea, 0xe1, 0xdb, 0xee, 0xf4, 0xb3, 0x9d, 0xb3,
-  0x8e, 0xea, 0x87, 0xae, 0x16, 0xd2, 0x1e, 0xa0, 0x7c, 0x7c, 0x69, 0x3f,
-  0x29, 0x16, 0x85, 0x01, 0x53, 0xa7, 0x6c, 0xf1, 0x60, 0xab, 0xdd, 0xa2,
-  0xfc, 0x25, 0x47, 0xd4, 0x32, 0xd1, 0x12, 0xdd, 0xf7, 0x48, 0x12, 0xe0,
-  0xfc, 0x9c, 0xa2, 0x77, 0x98, 0xe9, 0x89, 0x99, 0xb8, 0xf8, 0x38, 0xf1,
-  0x8c, 0x06, 0xc2, 0x7a, 0x23, 0x36, 0x6d, 0x9b, 0x9d, 0xcd, 0x30, 0xc8,
-  0xc7, 0x34, 0x17, 0x1e, 0xbb, 0x7d, 0x42, 0xc8, 0xab, 0xe7, 0x15, 0x16,
-  0xf6, 0x73, 0xb5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xea,
-  0x30, 0x82, 0x01, 0xe6, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-  0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-  0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3,
-  0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-  0x18, 0x2a, 0xa2, 0xc8, 0xd4, 0x7a, 0x3f, 0x7b, 0xad, 0x04, 0x8b, 0xbd,
-  0x6f, 0x9e, 0x10, 0x46, 0x13, 0x78, 0x71, 0x9d, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0,
-  0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
-  0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
-  0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
-  0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06,
-  0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c,
-  0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04,
-  0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
-  0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06,
-  0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36,
-  0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
-  0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e,
-  0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32,
-  0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
-  0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
-  0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63,
-  0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41,
-  0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
-  0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
-  0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x2f, 0x06,
-  0x03, 0x55, 0x1d, 0x11, 0x04, 0x28, 0x30, 0x26, 0x82, 0x0f, 0x6d, 0x61,
-  0x69, 0x6c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
-  0x6d, 0x82, 0x13, 0x77, 0x77, 0x77, 0x2e, 0x6d, 0x61, 0x69, 0x6c, 0x2e,
-  0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x0d,
-  0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
-  0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x67, 0x06, 0x08, 0x0a, 0x27, 0xc5,
-  0x93, 0x6e, 0x02, 0xf2, 0xde, 0x17, 0x3f, 0xd0, 0xd3, 0x1b, 0x7c, 0xff,
-  0xb5, 0xcd, 0x7a, 0xc7, 0x77, 0xc7, 0xbe, 0xdf, 0x12, 0xca, 0x19, 0xde,
-  0xb0, 0x13, 0x57, 0x0c, 0x03, 0x91, 0xc4, 0x79, 0x52, 0xcf, 0x7f, 0xb7,
-  0x5e, 0x55, 0x20, 0x84, 0x49, 0xdd, 0xf5, 0xd0, 0x29, 0x2f, 0x0e, 0x04,
-  0xda, 0x59, 0x9e, 0x0e, 0x13, 0x9f, 0xf4, 0xc0, 0x32, 0x9b, 0xff, 0xa1,
-  0x11, 0x24, 0x2a, 0x97, 0xa3, 0xf2, 0x3f, 0x3d, 0x2a, 0x6b, 0xa8, 0xad,
-  0x8c, 0x19, 0x75, 0x95, 0x0e, 0x1d, 0x25, 0xfd, 0x4f, 0xc4, 0x7a, 0x15,
-  0xc3, 0x1d, 0xc7, 0x13, 0x40, 0xc8, 0x0d, 0xbe, 0x97, 0x60, 0x72, 0xa6,
-  0xfe, 0x25, 0xbe, 0x8f, 0xec, 0xd5, 0xa6, 0x86, 0xc3, 0x21, 0x5c, 0x59,
-  0x52, 0xd9, 0x6a, 0x0b, 0x5c, 0x9f, 0x4b, 0xde, 0xb5, 0xf9, 0xec, 0xe2,
-  0xf4, 0xc5, 0xcc, 0x62, 0x53, 0x76, 0x89, 0x65, 0xe4, 0x29, 0xda, 0xb7,
-  0xbf, 0x96, 0xe0, 0x60, 0x8d, 0x0d, 0xb7, 0x09, 0x55, 0xd6, 0x40, 0x55,
-  0x1d, 0xc1, 0xf2, 0x96, 0x21, 0x75, 0xaf, 0x89, 0x86, 0x1f, 0x5d, 0x81,
-  0x97, 0x29, 0x28, 0x1e, 0x29, 0xd7, 0x96, 0xc1, 0x20, 0x03, 0x32, 0x7b,
-  0x00, 0x3b, 0x6a, 0x37, 0x17, 0x5a, 0xa3, 0xb3, 0x1a, 0x6f, 0x32, 0x3b,
-  0x6e, 0xf1, 0xa3, 0x5d, 0xab, 0xab, 0xcc, 0x2a, 0xcb, 0x30, 0x0c, 0x1f,
-  0x35, 0x23, 0x8b, 0x69, 0x44, 0x5c, 0xea, 0xac, 0x28, 0x60, 0xed, 0xab,
-  0x6b, 0x63, 0x9e, 0xf6, 0x92, 0xbc, 0xbd, 0x9a, 0x5a, 0x26, 0x4c, 0xc5,
-  0x98, 0xb8, 0x0e, 0x19, 0x3e, 0xfc, 0x05, 0x31, 0xe3, 0x16, 0xd9, 0xfd,
-  0x90, 0x05, 0x03, 0x86, 0xc6, 0x57, 0x01, 0x1f, 0x7f, 0x78, 0xa0, 0xcf,
-  0x33, 0x6a, 0xaa, 0x66, 0x6b, 0x22, 0xd0, 0xa7, 0x49, 0x23
-};
-unsigned int mail_google_com_cer_len = 1522;
diff --git a/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/www.google.com.cer.h b/OSX/sec/Security/Regressions/secitem/si-67-sectrust-blocklist/www.google.com.cer.h
deleted file mode 100644 (file)
index 0754b97..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-unsigned char www_google_com_cer[] = {
-  0x30, 0x82, 0x05, 0xe4, 0x30, 0x82, 0x04, 0xcc, 0xa0, 0x03, 0x02, 0x01,
-  0x02, 0x02, 0x11, 0x00, 0xf5, 0xc8, 0x6a, 0xf3, 0x61, 0x62, 0xf1, 0x3a,
-  0x64, 0xf5, 0x4f, 0x6d, 0xc9, 0x58, 0x7c, 0x06, 0x30, 0x0d, 0x06, 0x09,
-  0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
-  0x81, 0x97, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-  0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
-  0x13, 0x02, 0x55, 0x54, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04,
-  0x07, 0x13, 0x0e, 0x53, 0x61, 0x6c, 0x74, 0x20, 0x4c, 0x61, 0x6b, 0x65,
-  0x20, 0x43, 0x69, 0x74, 0x79, 0x31, 0x1e, 0x30, 0x1c, 0x06, 0x03, 0x55,
-  0x04, 0x0a, 0x13, 0x15, 0x54, 0x68, 0x65, 0x20, 0x55, 0x53, 0x45, 0x52,
-  0x54, 0x52, 0x55, 0x53, 0x54, 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72,
-  0x6b, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18,
-  0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x75,
-  0x73, 0x65, 0x72, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,
-  0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x16, 0x55,
-  0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73, 0x74,
-  0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x30, 0x1e, 0x17,
-  0x0d, 0x31, 0x31, 0x30, 0x33, 0x31, 0x35, 0x30, 0x30, 0x30, 0x30, 0x30,
-  0x30, 0x5a, 0x17, 0x0d, 0x31, 0x34, 0x30, 0x33, 0x31, 0x34, 0x32, 0x33,
-  0x35, 0x39, 0x35, 0x39, 0x5a, 0x30, 0x81, 0xde, 0x31, 0x0b, 0x30, 0x09,
-  0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0e, 0x30,
-  0x0c, 0x06, 0x03, 0x55, 0x04, 0x11, 0x13, 0x05, 0x33, 0x38, 0x34, 0x37,
-  0x37, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x07,
-  0x46, 0x6c, 0x6f, 0x72, 0x69, 0x64, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06,
-  0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x45, 0x6e, 0x67, 0x6c, 0x69, 0x73,
-  0x68, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x09, 0x13, 0x0e,
-  0x53, 0x65, 0x61, 0x20, 0x56, 0x69, 0x6c, 0x6c, 0x61, 0x67, 0x65, 0x20,
-  0x31, 0x30, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13,
-  0x0b, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x20, 0x4c, 0x74, 0x64, 0x2e,
-  0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x54,
-  0x65, 0x63, 0x68, 0x20, 0x44, 0x65, 0x70, 0x74, 0x2e, 0x31, 0x28, 0x30,
-  0x26, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1f, 0x48, 0x6f, 0x73, 0x74,
-  0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x47, 0x54, 0x49, 0x20, 0x47, 0x72,
-  0x6f, 0x75, 0x70, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74,
-  0x69, 0x6f, 0x6e, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0b,
-  0x13, 0x0b, 0x50, 0x6c, 0x61, 0x74, 0x69, 0x6e, 0x75, 0x6d, 0x53, 0x53,
-  0x4c, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0e,
-  0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 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, 0xb0,
-  0x73, 0xf0, 0xf2, 0x04, 0xee, 0xc2, 0xa2, 0x46, 0xca, 0x34, 0x2a, 0xaa,
-  0xbb, 0x60, 0x23, 0xd1, 0x11, 0x76, 0x1f, 0x1f, 0x3a, 0xd0, 0x65, 0x83,
-  0x4e, 0x9a, 0x45, 0xa8, 0x43, 0x70, 0x85, 0x76, 0xf0, 0x1f, 0x87, 0x00,
-  0x02, 0x1f, 0x6e, 0x3b, 0x17, 0x17, 0xc4, 0xb5, 0xe9, 0x19, 0x46, 0xa2,
-  0x92, 0x25, 0x8d, 0x62, 0x2a, 0xb4, 0x63, 0x30, 0x1f, 0xb9, 0x85, 0xf8,
-  0x35, 0xe1, 0x16, 0x5a, 0x76, 0x49, 0xcc, 0x50, 0x48, 0x53, 0x39, 0x59,
-  0x89, 0xd6, 0x84, 0x02, 0xfb, 0x9a, 0xec, 0x1b, 0xc7, 0x51, 0xd5, 0x76,
-  0x95, 0x90, 0xd4, 0x3a, 0x2a, 0xb8, 0xa6, 0xde, 0x02, 0x4d, 0x06, 0xfb,
-  0xcd, 0xed, 0xa5, 0x46, 0x41, 0x5f, 0x55, 0x74, 0xe5, 0xec, 0x7e, 0x40,
-  0xdc, 0x50, 0x9c, 0xb5, 0xe4, 0x35, 0x5d, 0x1e, 0x68, 0x20, 0xf8, 0xe9,
-  0xde, 0xa3, 0x6a, 0x28, 0xbf, 0x41, 0xd2, 0xa1, 0xb3, 0xe2, 0x25, 0x8d,
-  0x0c, 0x1b, 0xca, 0x3d, 0x93, 0x0c, 0x18, 0xae, 0xdf, 0xc5, 0xbc, 0xfd,
-  0xbc, 0x82, 0xba, 0x68, 0x00, 0xd7, 0x16, 0x32, 0x71, 0x9f, 0x65, 0xb5,
-  0x11, 0xda, 0x68, 0x59, 0xd0, 0xa6, 0x57, 0x64, 0x1b, 0xc9, 0xfe, 0x98,
-  0xe5, 0xf5, 0xa5, 0x65, 0xea, 0xe1, 0xdb, 0xee, 0xf4, 0xb3, 0x9d, 0xb3,
-  0x8e, 0xea, 0x87, 0xae, 0x16, 0xd2, 0x1e, 0xa0, 0x7c, 0x7c, 0x69, 0x3f,
-  0x29, 0x16, 0x85, 0x01, 0x53, 0xa7, 0x6c, 0xf1, 0x60, 0xab, 0xdd, 0xa2,
-  0xfc, 0x25, 0x47, 0xd4, 0x32, 0xd1, 0x12, 0xdd, 0xf7, 0x48, 0x12, 0xe0,
-  0xfc, 0x9c, 0xa2, 0x77, 0x98, 0xe9, 0x89, 0x99, 0xb8, 0xf8, 0x38, 0xf1,
-  0x8c, 0x06, 0xc2, 0x7a, 0x23, 0x36, 0x6d, 0x9b, 0x9d, 0xcd, 0x30, 0xc8,
-  0xc7, 0x34, 0x17, 0x1e, 0xbb, 0x7d, 0x42, 0xc8, 0xab, 0xe7, 0x15, 0x16,
-  0xf6, 0x73, 0xb5, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xe0,
-  0x30, 0x82, 0x01, 0xdc, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04,
-  0x18, 0x30, 0x16, 0x80, 0x14, 0xa1, 0x72, 0x5f, 0x26, 0x1b, 0x28, 0x98,
-  0x43, 0x95, 0x5d, 0x07, 0x37, 0xd5, 0x85, 0x96, 0x9d, 0x4b, 0xd2, 0xc3,
-  0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
-  0x18, 0x2a, 0xa2, 0xc8, 0xd4, 0x7a, 0x3f, 0x7b, 0xad, 0x04, 0x8b, 0xbd,
-  0x6f, 0x9e, 0x10, 0x46, 0x13, 0x78, 0x71, 0x9d, 0x30, 0x0e, 0x06, 0x03,
-  0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0,
-  0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
-  0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16, 0x30,
-  0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06,
-  0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x46, 0x06,
-  0x03, 0x55, 0x1d, 0x20, 0x04, 0x3f, 0x30, 0x3d, 0x30, 0x3b, 0x06, 0x0c,
-  0x2b, 0x06, 0x01, 0x04, 0x01, 0xb2, 0x31, 0x01, 0x02, 0x01, 0x03, 0x04,
-  0x30, 0x2b, 0x30, 0x29, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x02, 0x01, 0x16, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f,
-  0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x50, 0x53, 0x30, 0x7b, 0x06,
-  0x03, 0x55, 0x1d, 0x1f, 0x04, 0x74, 0x30, 0x72, 0x30, 0x38, 0xa0, 0x36,
-  0xa0, 0x34, 0x86, 0x32, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
-  0x72, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e,
-  0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52,
-  0x46, 0x69, 0x72, 0x73, 0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61,
-  0x72, 0x65, 0x2e, 0x63, 0x72, 0x6c, 0x30, 0x36, 0xa0, 0x34, 0xa0, 0x32,
-  0x86, 0x30, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c,
-  0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64, 0x6f, 0x2e, 0x6e, 0x65, 0x74, 0x2f,
-  0x55, 0x54, 0x4e, 0x2d, 0x55, 0x53, 0x45, 0x52, 0x46, 0x69, 0x72, 0x73,
-  0x74, 0x2d, 0x48, 0x61, 0x72, 0x64, 0x77, 0x61, 0x72, 0x65, 0x2e, 0x63,
-  0x72, 0x6c, 0x30, 0x71, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
-  0x01, 0x01, 0x04, 0x65, 0x30, 0x63, 0x30, 0x3b, 0x06, 0x08, 0x2b, 0x06,
-  0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2f, 0x68, 0x74, 0x74, 0x70,
-  0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x6f, 0x64,
-  0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x55, 0x54, 0x4e, 0x41,
-  0x64, 0x64, 0x54, 0x72, 0x75, 0x73, 0x74, 0x53, 0x65, 0x72, 0x76, 0x65,
-  0x72, 0x43, 0x41, 0x2e, 0x63, 0x72, 0x74, 0x30, 0x24, 0x06, 0x08, 0x2b,
-  0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
-  0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x63, 0x6f, 0x6d,
-  0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x25, 0x06,
-  0x03, 0x55, 0x1d, 0x11, 0x04, 0x1e, 0x30, 0x1c, 0x82, 0x0e, 0x77, 0x77,
-  0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
-  0x82, 0x0a, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
-  0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-  0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x71, 0xc0, 0x99, 0x3f,
-  0x5e, 0xf6, 0xbd, 0x33, 0xff, 0x9e, 0x16, 0xcb, 0xa8, 0xbf, 0xdd, 0x70,
-  0xf9, 0xd2, 0x53, 0x3b, 0x36, 0xae, 0xc9, 0x17, 0xc8, 0xae, 0x5e, 0x4d,
-  0xdd, 0x62, 0xf7, 0xb7, 0xd3, 0x3e, 0x77, 0xa3, 0xfe, 0xc0, 0x7b, 0x32,
-  0xb5, 0xc9, 0x94, 0x05, 0x52, 0x50, 0xf2, 0x5f, 0x3d, 0x79, 0x84, 0x49,
-  0x4f, 0x5d, 0x6c, 0xb0, 0xd7, 0x59, 0xbd, 0xd4, 0x6c, 0x88, 0xfa, 0xfc,
-  0xc5, 0x65, 0x86, 0xeb, 0x28, 0x52, 0xa2, 0x42, 0xf6, 0x7c, 0xbc, 0x6a,
-  0xc7, 0x07, 0x2e, 0x25, 0xd1, 0x90, 0x62, 0x20, 0xc6, 0x8d, 0x51, 0xc2,
-  0x2c, 0x45, 0x39, 0x4e, 0x03, 0xda, 0xf7, 0x18, 0xe8, 0xcc, 0x0a, 0x3a,
-  0xd9, 0x45, 0xd8, 0x6c, 0x6e, 0x34, 0x8b, 0x62, 0x9c, 0x4e, 0x15, 0xf9,
-  0x43, 0xee, 0xe5, 0x97, 0xc0, 0x3f, 0xad, 0x35, 0x13, 0xc5, 0x2b, 0x06,
-  0xc7, 0x41, 0xfd, 0xe2, 0xf7, 0x7e, 0x45, 0xad, 0x9b, 0xd1, 0xe1, 0x66,
-  0xed, 0xf8, 0x7a, 0x4b, 0x94, 0x39, 0x7a, 0x2f, 0xeb, 0xe8, 0x3f, 0x43,
-  0xd8, 0x35, 0xd6, 0x56, 0xfa, 0x74, 0xe7, 0x6d, 0xe6, 0xed, 0xac, 0x65,
-  0x84, 0xfe, 0xd0, 0x4d, 0x06, 0x12, 0xde, 0xda, 0x59, 0x00, 0x3c, 0x09,
-  0x5c, 0xcf, 0x88, 0x4b, 0xe8, 0x3d, 0xb4, 0x15, 0x21, 0x92, 0xcc, 0x6d,
-  0xa6, 0x51, 0xe2, 0x8e, 0x97, 0xf1, 0xf4, 0x82, 0x46, 0xcb, 0xc4, 0x53,
-  0x5e, 0xda, 0x5c, 0x9d, 0x65, 0x92, 0x01, 0x65, 0x89, 0x00, 0xe5, 0xb6,
-  0x99, 0xff, 0x26, 0x40, 0xf1, 0x2f, 0x19, 0x31, 0x08, 0x1a, 0xb1, 0x67,
-  0x55, 0x86, 0x0d, 0xae, 0x35, 0x33, 0x86, 0xbc, 0x97, 0x48, 0x92, 0xd7,
-  0x96, 0x60, 0xf8, 0xce, 0xfc, 0x96, 0xeb, 0x87, 0xc4, 0x73, 0xcc, 0x94,
-  0x9b, 0x58, 0x5b, 0xf3, 0x7a, 0xa4, 0x27, 0x13, 0xd6, 0x4f, 0xf4, 0x69
-};
-unsigned int www_google_com_cer_len = 1512;
diff --git a/OSX/sec/Security/Regressions/secitem/si-74-OTAPKISigner.c b/OSX/sec/Security/Regressions/secitem/si-74-OTAPKISigner.c
deleted file mode 100644 (file)
index 006dc95..0000000
+++ /dev/null
@@ -1,1007 +0,0 @@
-/*
- * Copyright (c) 2013-2014 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 <CoreFoundation/CoreFoundation.h>
-#include <Security/SecCertificate.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecItem.h>
-#include <Security/SecItemPriv.h>
-#include <Security/SecIdentityPriv.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecPolicy.h>
-#include <Security/SecPolicyPriv.h>
-#include <Security/SecTrust.h>
-#include <Security/SecTrustPriv.h>
-#include <Security/SecCMS.h>
-#include <utilities/SecCFRelease.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "shared_regressions.h"
-
-static const UInt8 kSignedPList[] = {
-       0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30,
-       0x80, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
-       0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-       0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x36, 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30,
-       0xd1, 0x01, 0x02, 0x53, 0x66, 0x6f, 0x6f, 0x53, 0x62, 0x61, 0x72, 0x08, 0x0b, 0x0f, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x30, 0x82, 0x07, 0xab, 0x30, 0x82, 0x05, 0x93, 0xa0, 0x03,
-       0x02, 0x01, 0x02, 0x02, 0x08, 0x04, 0x2e, 0x97, 0xbb, 0x62, 0x84, 0xd9, 0x1c, 0x30, 0x0d, 0x06,
-       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31,
-       0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
-       0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f,
-       0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
-       0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55,
-       0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
-       0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74,
-       0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c,
-       0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
-       0x02, 0x55, 0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x36, 0x32, 0x35, 0x30, 0x30, 0x30,
-       0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x36, 0x32, 0x31, 0x30, 0x30, 0x30, 0x39,
-       0x33, 0x38, 0x5a, 0x30, 0x59, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a,
-       0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
-       0x67, 0x73, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03,
-       0x55, 0x04, 0x0b, 0x0c, 0x07, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x4f, 0x53, 0x31, 0x13, 0x30, 0x11,
-       0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63,
-       0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x82,
-       0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
-       0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xad,
-       0xef, 0x52, 0xc8, 0xda, 0x8e, 0x3c, 0xcc, 0x06, 0xcf, 0xfc, 0xed, 0xdb, 0x92, 0xb3, 0xa8, 0xe0,
-       0x3b, 0x14, 0x40, 0x34, 0xad, 0x91, 0xf3, 0xbe, 0x1a, 0x00, 0xbb, 0x06, 0xa2, 0xd7, 0x24, 0x6f,
-       0xd5, 0xd3, 0xdf, 0xd9, 0xff, 0x0b, 0x4d, 0x6d, 0xc5, 0xdd, 0x7a, 0x37, 0xfa, 0x08, 0x49, 0x0e,
-       0x36, 0x5e, 0xab, 0x83, 0x8d, 0xeb, 0x83, 0x00, 0xf9, 0xaa, 0xe4, 0x88, 0x09, 0x87, 0x05, 0x6b,
-       0x01, 0x6e, 0x49, 0x54, 0xa1, 0x3b, 0x5c, 0xfc, 0x2b, 0x0f, 0x1f, 0xa9, 0x7c, 0xc1, 0xc5, 0xe1,
-       0x32, 0xd7, 0x86, 0x49, 0x80, 0x0f, 0xf8, 0xe3, 0x3b, 0xa3, 0x12, 0x06, 0x5d, 0xf4, 0x43, 0xc0,
-       0xb2, 0xc7, 0xcf, 0xb4, 0x14, 0x2c, 0x50, 0x70, 0x57, 0xb9, 0xb2, 0xe7, 0x72, 0x9a, 0x9f, 0x45,
-       0x0b, 0x0d, 0xe5, 0xab, 0x3e, 0x23, 0x91, 0xe0, 0x88, 0x84, 0x3a, 0xec, 0xaa, 0x80, 0xab, 0x37,
-       0xa3, 0x0c, 0x63, 0x99, 0x1c, 0xde, 0x1b, 0x29, 0x95, 0x4b, 0xff, 0xcd, 0x92, 0x10, 0xa3, 0x50,
-       0x93, 0x89, 0x4f, 0xdc, 0x30, 0x0d, 0x29, 0x2a, 0x80, 0x04, 0x32, 0xb3, 0xb9, 0xa7, 0x79, 0x5f,
-       0x18, 0xce, 0xc1, 0x90, 0xe6, 0xd6, 0x0c, 0xeb, 0x91, 0x27, 0x6f, 0x17, 0xd2, 0x93, 0xda, 0xa1,
-       0xa8, 0x3f, 0x20, 0xe9, 0xeb, 0x54, 0x37, 0xd7, 0x54, 0xfd, 0x44, 0xa2, 0x8d, 0xa4, 0x30, 0x6e,
-       0xbf, 0xd0, 0xbd, 0xc4, 0x7d, 0x93, 0xeb, 0xf6, 0xfa, 0x1e, 0xc1, 0xd5, 0xee, 0xfe, 0xb7, 0x56,
-       0x51, 0xb3, 0x0b, 0x3f, 0xf4, 0xb1, 0x77, 0x75, 0xaf, 0x10, 0x14, 0x98, 0x74, 0x41, 0x40, 0xdb,
-       0xe4, 0x6b, 0x3f, 0x49, 0xce, 0xb8, 0x80, 0x20, 0x72, 0x92, 0xcb, 0x63, 0x63, 0x44, 0x4e, 0xe8,
-       0xe4, 0xde, 0xe9, 0xc3, 0x0a, 0x75, 0xd8, 0xbf, 0xc5, 0x8e, 0xcb, 0xcf, 0xec, 0x65, 0x49, 0x56,
-       0xa1, 0x9f, 0xb6, 0x39, 0x53, 0x69, 0xb4, 0x04, 0xe8, 0xd0, 0x28, 0xc6, 0x69, 0xde, 0xdb, 0x30,
-       0xa7, 0xb0, 0xbf, 0x6f, 0xfe, 0x7b, 0x45, 0x87, 0x07, 0xf0, 0x85, 0x34, 0x71, 0xca, 0xe5, 0x07,
-       0x61, 0xce, 0x53, 0xf3, 0xd6, 0x69, 0x70, 0x5a, 0x4b, 0x7e, 0xda, 0x9b, 0x77, 0x17, 0x65, 0x6c,
-       0x4d, 0xd5, 0x59, 0x00, 0x6f, 0x47, 0x65, 0x30, 0x98, 0xd9, 0x7b, 0xa7, 0x51, 0x8b, 0x47, 0x7d,
-       0x8f, 0x5a, 0x91, 0x72, 0xe4, 0x86, 0x4f, 0xb0, 0xb4, 0x12, 0x42, 0x55, 0x95, 0x59, 0xa3, 0xc6,
-       0xdf, 0xba, 0x20, 0x0e, 0x5d, 0x0f, 0x6a, 0x6a, 0xc2, 0x08, 0x93, 0x9f, 0x0e, 0x8b, 0x61, 0x20,
-       0x9e, 0x2b, 0x64, 0x26, 0x15, 0x52, 0x9b, 0xef, 0x34, 0x7c, 0x12, 0xa4, 0xe4, 0xf7, 0xfc, 0x9a,
-       0xa6, 0xe6, 0xe9, 0x6f, 0xfc, 0xbb, 0x16, 0xc4, 0x0f, 0x0b, 0xac, 0x84, 0x9d, 0xc8, 0xe9, 0x98,
-       0xe1, 0xf4, 0x35, 0xfb, 0x97, 0x63, 0x14, 0x6c, 0x15, 0x51, 0x51, 0x5b, 0xc8, 0x64, 0x25, 0x46,
-       0x44, 0x6d, 0xbd, 0x17, 0xdd, 0x17, 0x4d, 0x34, 0x77, 0xa8, 0x6d, 0x4b, 0x97, 0x4b, 0x77, 0xf5,
-       0x77, 0x07, 0x1b, 0x93, 0x18, 0xf3, 0x44, 0x4e, 0x79, 0xe2, 0xfc, 0x96, 0x76, 0x5e, 0x69, 0x85,
-       0xf6, 0xb6, 0x97, 0xbb, 0xb0, 0x41, 0x1f, 0x03, 0x8b, 0xcb, 0xc0, 0xa9, 0x10, 0x67, 0x8f, 0x6f,
-       0x67, 0xab, 0xb0, 0xbd, 0x1f, 0xc7, 0x11, 0xfd, 0xb8, 0x29, 0x47, 0x41, 0xd4, 0x34, 0x0f, 0x5b,
-       0x9d, 0x64, 0xfb, 0x8f, 0x5f, 0x37, 0xd1, 0x9a, 0x4a, 0x2d, 0x62, 0xd1, 0x74, 0x2e, 0x6b, 0x7f,
-       0xdf, 0xb3, 0xea, 0x5f, 0xfa, 0x63, 0xd4, 0x4f, 0xb3, 0x89, 0x76, 0x67, 0x36, 0x71, 0xcd, 0xaf,
-       0xd7, 0x9c, 0x95, 0xa8, 0xce, 0xee, 0x29, 0x25, 0xb1, 0x2a, 0xac, 0x99, 0x10, 0x9b, 0x03, 0x02,
-       0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x49, 0x30, 0x82, 0x02, 0x45, 0x30, 0x1d, 0x06, 0x03,
-       0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcd, 0xbf, 0x6f, 0x14, 0xff, 0x8b, 0xb7, 0xf7, 0x29,
-       0xcd, 0xa4, 0x8c, 0xc1, 0xb1, 0x30, 0x92, 0x37, 0x8b, 0xd4, 0xef, 0x30, 0x0c, 0x06, 0x03, 0x55,
-       0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23,
-       0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35, 0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e,
-       0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6, 0x1c, 0x30, 0x82, 0x01, 0xe3, 0x06, 0x03,
-       0x55, 0x1d, 0x20, 0x01, 0x01, 0xff, 0x04, 0x82, 0x01, 0xd7, 0x30, 0x82, 0x01, 0xd3, 0x30, 0x82,
-       0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x05, 0x01, 0x30, 0x82, 0x01,
-       0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30,
-       0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x69, 0x00,
-       0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00,
-       0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00,
-       0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
-       0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00, 0x20, 0x00,
-       0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x73, 0x00,
-       0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x63, 0x00,
-       0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00,
-       0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00,
-       0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00,
-       0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00,
-       0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00,
-       0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00,
-       0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x69, 0x00,
-       0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00,
-       0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00,
-       0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00,
-       0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x79, 0x00,
-       0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00,
-       0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00,
-       0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00,
-       0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00,
-       0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x30, 0x35, 0x06,
-       0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a,
-       0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
-       0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6f,
-       0x72, 0x69, 0x74, 0x79, 0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x05,
-       0x0d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07,
-       0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
-       0x03, 0x82, 0x02, 0x01, 0x00, 0xc3, 0xd1, 0x52, 0x94, 0x51, 0xa7, 0x6d, 0xe9, 0xf8, 0x1a, 0xba,
-       0x15, 0x2c, 0x38, 0x6b, 0xd6, 0xba, 0xcf, 0x12, 0x20, 0x1d, 0x46, 0xef, 0x99, 0x48, 0x95, 0x9d,
-       0x1e, 0x49, 0x1b, 0xe7, 0x95, 0xde, 0x73, 0x28, 0xc1, 0x90, 0xfe, 0xeb, 0x39, 0xe1, 0xa8, 0xa8,
-       0x5c, 0x4e, 0x71, 0x03, 0x1b, 0x22, 0x37, 0x07, 0xed, 0x24, 0xa4, 0xee, 0x5d, 0x0a, 0xf8, 0x04,
-       0xf8, 0xba, 0x34, 0x50, 0xc0, 0x49, 0xd7, 0xa4, 0x4f, 0xdd, 0x06, 0x81, 0x33, 0x3a, 0x69, 0x4e,
-       0x43, 0x85, 0x15, 0xde, 0x05, 0x37, 0xf5, 0xb3, 0xd5, 0x68, 0x4c, 0x30, 0x6a, 0x52, 0x35, 0x6a,
-       0xb0, 0x2b, 0x8e, 0xe1, 0xde, 0xa6, 0xd2, 0xfc, 0xe2, 0x9f, 0xdc, 0x95, 0x65, 0x13, 0x45, 0x91,
-       0xc1, 0x7b, 0xff, 0x90, 0x6a, 0x4c, 0xd3, 0x20, 0x5c, 0x1b, 0x99, 0xea, 0x82, 0xec, 0xfd, 0x0b,
-       0x89, 0x25, 0x6c, 0x31, 0x3d, 0xa8, 0x52, 0xba, 0x8e, 0xdf, 0x20, 0xcb, 0x5f, 0x00, 0xf8, 0x6b,
-       0xf2, 0x63, 0x5d, 0x2a, 0x55, 0xc6, 0xee, 0x34, 0xa4, 0x86, 0xab, 0x47, 0x89, 0xcd, 0xb6, 0xaa,
-       0xe0, 0x5c, 0x9a, 0x57, 0x7d, 0x3e, 0xaa, 0x8b, 0x74, 0xfc, 0x94, 0xc7, 0x9d, 0x0e, 0xa2, 0x92,
-       0xa9, 0xc5, 0xdd, 0x71, 0x53, 0x54, 0x38, 0xb0, 0x22, 0x88, 0xdc, 0x46, 0xcd, 0x45, 0xc7, 0x33,
-       0xc7, 0x2f, 0xed, 0x5f, 0x4d, 0x05, 0x9d, 0xba, 0x2e, 0xf7, 0xa4, 0xb5, 0xfa, 0x79, 0x11, 0x41,
-       0xd1, 0x1b, 0x50, 0xab, 0xef, 0xdf, 0xa8, 0x5c, 0x28, 0xc7, 0x8e, 0x86, 0xa2, 0x85, 0x8a, 0x90,
-       0xf4, 0xda, 0x71, 0x1f, 0xff, 0x7f, 0x02, 0x4c, 0x24, 0x95, 0x0d, 0x31, 0xa3, 0x8b, 0x62, 0xae,
-       0x45, 0xe2, 0x44, 0x6c, 0x01, 0x1d, 0xdc, 0x67, 0xbe, 0xfb, 0x16, 0x4f, 0x4c, 0xf0, 0x81, 0xa8,
-       0xbd, 0xe1, 0x29, 0x6f, 0x1c, 0xff, 0xa4, 0x82, 0x96, 0xa3, 0x67, 0xad, 0xa6, 0x99, 0xd6, 0x29,
-       0x02, 0x7f, 0xfc, 0xe3, 0x8d, 0xe3, 0x0d, 0x17, 0x91, 0x84, 0xcf, 0x4b, 0x05, 0xdd, 0x29, 0x96,
-       0xb4, 0x58, 0x56, 0x9b, 0x65, 0x17, 0xdd, 0x16, 0x1f, 0xf8, 0x59, 0x8d, 0xfb, 0xa0, 0xb0, 0xc7,
-       0x0b, 0x74, 0x64, 0xef, 0x8c, 0xcb, 0xba, 0x10, 0x48, 0x37, 0x28, 0xc9, 0x7f, 0x17, 0xac, 0x5f,
-       0x04, 0xa0, 0x50, 0x6d, 0x18, 0x5f, 0x23, 0xe3, 0x9c, 0xb6, 0xe0, 0x6c, 0xc0, 0xe1, 0x5e, 0xba,
-       0x8f, 0x70, 0xf1, 0xca, 0xc5, 0x97, 0x95, 0xf7, 0x4c, 0xdd, 0x6c, 0x8c, 0xbb, 0x4d, 0x68, 0x18,
-       0x59, 0xb3, 0x1b, 0x6f, 0x81, 0xe7, 0xd8, 0x44, 0xdc, 0x6e, 0x84, 0xce, 0x5b, 0x0c, 0x66, 0xef,
-       0xc4, 0x72, 0x00, 0xf2, 0x5a, 0xef, 0x82, 0x63, 0x18, 0xf7, 0xd3, 0xb8, 0x25, 0xc4, 0x91, 0x80,
-       0x04, 0x54, 0x61, 0x5b, 0xf5, 0xe2, 0xda, 0xfb, 0x1d, 0xd4, 0x19, 0x99, 0x18, 0xbd, 0x9a, 0x1e,
-       0x96, 0xe9, 0x1c, 0xd5, 0xd0, 0x06, 0xf5, 0x37, 0x91, 0x3b, 0x4d, 0xa5, 0x2a, 0xda, 0x3c, 0xcd,
-       0xa6, 0xda, 0x53, 0xb8, 0x4a, 0x1e, 0xb9, 0x51, 0xed, 0xc3, 0x47, 0xc6, 0xfa, 0xdc, 0x2e, 0xb3,
-       0xdd, 0x63, 0x65, 0xba, 0x17, 0xdb, 0x65, 0x8b, 0x63, 0x77, 0x31, 0x6d, 0xd9, 0xb7, 0x18, 0x33,
-       0x91, 0xa1, 0x1f, 0xed, 0x0d, 0x49, 0x7f, 0x29, 0xd6, 0xd4, 0xf6, 0x12, 0x0f, 0xb2, 0x0c, 0xc9,
-       0x0f, 0x61, 0xb1, 0x48, 0x58, 0x52, 0xac, 0x80, 0x92, 0xb4, 0x2d, 0x4c, 0xa8, 0x94, 0xf6, 0x99,
-       0xc8, 0xb7, 0x1a, 0x7f, 0x3a, 0x52, 0x49, 0x9f, 0x44, 0xff, 0x0d, 0x38, 0x27, 0x3f, 0xad, 0xf6,
-       0xa4, 0x8f, 0xd9, 0x4b, 0x30, 0x6f, 0xe0, 0xb8, 0x20, 0x94, 0x82, 0x4c, 0x96, 0xea, 0x27, 0x28,
-       0x61, 0x1a, 0x41, 0x6d, 0xd4, 0x30, 0x82, 0x07, 0xca, 0x30, 0x82, 0x05, 0xb2, 0xa0, 0x03, 0x02,
-       0x01, 0x02, 0x02, 0x08, 0x4e, 0xa1, 0x31, 0xe7, 0xca, 0x50, 0xb8, 0x97, 0x30, 0x0d, 0x06, 0x09,
-       0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38,
-       0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50,
-       0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74,
-       0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
-       0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04,
-       0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
-       0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65,
-       0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
-       0x55, 0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x36, 0x32, 0x34, 0x32, 0x33, 0x33, 0x33,
-       0x33, 0x39, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x36, 0x31, 0x37, 0x32, 0x33, 0x33, 0x33, 0x33,
-       0x39, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f,
-       0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
-       0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
-       0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
-       0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
-       0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a,
-       0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09,
-       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06,
-       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f,
-       0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xce, 0x15, 0xf7, 0x6f, 0xd8, 0x42,
-       0x0c, 0x6f, 0x45, 0xb4, 0x04, 0x59, 0x24, 0xcb, 0x70, 0x88, 0x84, 0x77, 0xa1, 0x91, 0x54, 0xf4,
-       0x87, 0x61, 0xb3, 0xd3, 0xfc, 0xbe, 0xb6, 0x05, 0x3c, 0xb9, 0xb7, 0x7d, 0x7c, 0xbc, 0x0b, 0xe8,
-       0x87, 0x07, 0xcf, 0x20, 0xbe, 0xaa, 0xeb, 0x24, 0xc5, 0xe4, 0x5c, 0xcd, 0xcb, 0x89, 0x9f, 0x7a,
-       0xea, 0xb4, 0x5d, 0x3b, 0x29, 0x6c, 0xba, 0x4d, 0x15, 0xfb, 0x59, 0xd0, 0x5a, 0xea, 0x41, 0x4e,
-       0x0d, 0x1d, 0xf7, 0x66, 0x77, 0xa2, 0x96, 0x56, 0xed, 0xd1, 0x16, 0x7b, 0xea, 0xf5, 0x60, 0xdf,
-       0x32, 0x9c, 0xa9, 0xfd, 0xbf, 0xb8, 0x34, 0x6f, 0x57, 0x17, 0xe6, 0x04, 0x37, 0x71, 0x07, 0xc0,
-       0xe9, 0x0f, 0x3c, 0xed, 0x4f, 0x31, 0x87, 0x05, 0xa4, 0xed, 0xab, 0xac, 0xd6, 0x50, 0x05, 0x5b,
-       0xca, 0xd3, 0xf9, 0xd6, 0xaa, 0xaa, 0x88, 0x57, 0x66, 0xf6, 0x6d, 0x8d, 0x4b, 0x71, 0x29, 0xd4,
-       0x3d, 0x1d, 0xbc, 0x82, 0x6e, 0x81, 0xe9, 0x19, 0xf5, 0xe1, 0x12, 0x9f, 0x47, 0xdb, 0x5c, 0xed,
-       0x88, 0xba, 0x51, 0xe7, 0x3a, 0xa0, 0x77, 0x2d, 0xe6, 0xcc, 0xb4, 0x34, 0xdf, 0xad, 0xbd, 0x7b,
-       0xf8, 0xa7, 0x79, 0x51, 0x2d, 0xe6, 0xc2, 0xee, 0xd2, 0x96, 0xfa, 0x60, 0x60, 0x32, 0x40, 0x41,
-       0x37, 0x12, 0xeb, 0x63, 0x99, 0x3d, 0xf3, 0x21, 0xbe, 0xdf, 0xa1, 0x77, 0xe6, 0x81, 0xa9, 0x99,
-       0x0c, 0x4b, 0x43, 0x0c, 0x05, 0x6a, 0x6b, 0x8f, 0x05, 0x02, 0xd9, 0x43, 0xab, 0x72, 0x76, 0xca,
-       0xa7, 0x75, 0x63, 0x85, 0xe3, 0xa5, 0x5c, 0xc0, 0xd6, 0xd4, 0x1c, 0xeb, 0xac, 0x2c, 0x9a, 0x15,
-       0x6b, 0x4e, 0x99, 0x74, 0x7d, 0xd2, 0x69, 0x9f, 0xa8, 0xf7, 0x65, 0xde, 0xeb, 0x36, 0x85, 0xd5,
-       0x7e, 0x4a, 0x7a, 0x8a, 0xeb, 0x7c, 0xcd, 0x43, 0x9e, 0x05, 0xdb, 0x34, 0xc3, 0x69, 0xbd, 0xc2,
-       0xe7, 0xfb, 0xa0, 0x43, 0xb3, 0xd7, 0x15, 0x28, 0x8a, 0x91, 0xce, 0xd7, 0xa7, 0xa4, 0xcc, 0xf4,
-       0x1b, 0x37, 0x33, 0x76, 0xc4, 0x58, 0xb9, 0x2d, 0x89, 0xe2, 0xb6, 0x2c, 0x56, 0x10, 0x96, 0xcc,
-       0xa6, 0x07, 0x79, 0x11, 0x7d, 0x26, 0xd2, 0x85, 0x22, 0x19, 0x20, 0xb7, 0xef, 0xc3, 0xd9, 0x4e,
-       0x18, 0xf3, 0xaa, 0x05, 0xce, 0x87, 0x99, 0xde, 0x76, 0x90, 0x08, 0x74, 0xac, 0x61, 0x31, 0xf8,
-       0x51, 0xa0, 0xc9, 0x70, 0xfc, 0xb9, 0x22, 0xfe, 0xd2, 0x0d, 0xc8, 0x49, 0x64, 0x00, 0xe4, 0xf1,
-       0x53, 0xfd, 0xa1, 0xe6, 0xff, 0x8e, 0xd6, 0xde, 0x9e, 0xcc, 0x3d, 0x37, 0x3a, 0x10, 0x62, 0x59,
-       0xb2, 0x34, 0x8a, 0x1d, 0xf7, 0x9e, 0xa0, 0xbb, 0xf4, 0x53, 0xd9, 0xb8, 0x18, 0x88, 0x12, 0x5c,
-       0x92, 0x0d, 0xc9, 0x94, 0x7f, 0x24, 0xb9, 0x9f, 0xda, 0x07, 0xb6, 0x79, 0x77, 0x09, 0xa3, 0x29,
-       0x3a, 0x70, 0x63, 0x3b, 0x22, 0x42, 0x14, 0xd0, 0xf9, 0x7b, 0x90, 0x52, 0x2b, 0x3f, 0x7f, 0xb7,
-       0x41, 0x20, 0x0d, 0x7e, 0x70, 0xd7, 0x88, 0x36, 0xa2, 0xe9, 0x81, 0x77, 0xf4, 0xb0, 0x15, 0x43,
-       0x9c, 0x5f, 0x4d, 0x3e, 0x4f, 0x83, 0x79, 0x06, 0x73, 0x7a, 0xe7, 0xcb, 0x79, 0x1d, 0xec, 0xa3,
-       0xce, 0x93, 0x5c, 0x68, 0xbf, 0x5a, 0xe6, 0x4c, 0x23, 0x86, 0x41, 0x7f, 0xb4, 0xfc, 0xd0, 0x2c,
-       0x1b, 0x64, 0x39, 0x64, 0xb7, 0xd2, 0x1d, 0xd0, 0x2d, 0x16, 0x77, 0xfe, 0x4d, 0xad, 0xf0, 0x4f,
-       0x38, 0xb3, 0xf9, 0x5a, 0xee, 0x0e, 0x1d, 0xb6, 0xf9, 0x3f, 0xba, 0x77, 0x5a, 0x20, 0xd2, 0x74,
-       0x1a, 0x4b, 0x5a, 0xaf, 0x62, 0xb5, 0xd3, 0xef, 0x37, 0x49, 0xfe, 0x1e, 0xcd, 0xb5, 0xba, 0xb5,
-       0xa6, 0x46, 0x7b, 0x38, 0x63, 0x62, 0x3c, 0x18, 0x7d, 0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
-       0x82, 0x02, 0x3c, 0x30, 0x82, 0x02, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
-       0x04, 0x14, 0x35, 0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8,
-       0x48, 0xe8, 0x8f, 0x61, 0xb6, 0x1c, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
-       0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18,
-       0x30, 0x16, 0x80, 0x14, 0x35, 0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65,
-       0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6, 0x1c, 0x30, 0x82, 0x01, 0xd3, 0x06, 0x03, 0x55, 0x1d,
-       0x20, 0x04, 0x82, 0x01, 0xca, 0x30, 0x82, 0x01, 0xc6, 0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a,
-       0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x05, 0x01, 0x30, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78,
-       0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82,
-       0x01, 0x66, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63,
-       0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69,
-       0x00, 0x73, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66,
-       0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79,
-       0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72,
-       0x00, 0x74, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d,
-       0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70,
-       0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66,
-       0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65,
-       0x00, 0x6e, 0x00, 0x20, 0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63,
-       0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61,
-       0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65,
-       0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20,
-       0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f,
-       0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73,
-       0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69,
-       0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70,
-       0x00, 0x6f, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e,
-       0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66,
-       0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20,
-       0x00, 0x70, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65,
-       0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65,
-       0x00, 0x6e, 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
-       0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
-       0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69,
-       0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30,
-       0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30,
-       0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82,
-       0x02, 0x01, 0x00, 0x6f, 0x8a, 0xb7, 0x35, 0x73, 0x5a, 0xc5, 0x34, 0xf7, 0x8c, 0xf0, 0xd1, 0x4a,
-       0x17, 0x52, 0x1c, 0x70, 0xf0, 0xe0, 0x53, 0xb4, 0x16, 0xde, 0x81, 0xda, 0x2a, 0xa4, 0xf9, 0x5b,
-       0x0e, 0xa6, 0x17, 0x86, 0x52, 0xc6, 0x70, 0x73, 0xf3, 0x3f, 0x1c, 0x87, 0x94, 0xdd, 0xfe, 0x02,
-       0x0b, 0x85, 0xc9, 0xb9, 0xcf, 0x15, 0x91, 0x05, 0x2e, 0x7e, 0xeb, 0xe6, 0xce, 0x0e, 0x4e, 0xd1,
-       0xf7, 0xe2, 0xd7, 0xf4, 0x60, 0xd2, 0xfc, 0x1d, 0xbf, 0xad, 0x61, 0x28, 0xf8, 0x53, 0x31, 0xb3,
-       0x92, 0xef, 0xa4, 0x05, 0x34, 0x97, 0x57, 0x97, 0x56, 0x3b, 0x12, 0x20, 0x2d, 0x88, 0x76, 0x81,
-       0x0e, 0x77, 0x85, 0xf1, 0x37, 0xc6, 0x19, 0x8b, 0x23, 0xc2, 0x42, 0x55, 0x40, 0xc9, 0x91, 0x5c,
-       0x78, 0xc5, 0xe6, 0x77, 0xfe, 0x72, 0x5f, 0xb2, 0x2c, 0x00, 0xf2, 0xe6, 0x8c, 0xcc, 0x02, 0x49,
-       0xd9, 0x78, 0x20, 0xae, 0xbd, 0x75, 0x61, 0x6a, 0xaa, 0xc5, 0x71, 0x3e, 0x5d, 0x02, 0xdf, 0xd2,
-       0x91, 0x5c, 0x0a, 0x85, 0xc9, 0x59, 0x7d, 0x4e, 0x89, 0x21, 0x59, 0x59, 0xe3, 0xc7, 0xdc, 0xff,
-       0x1e, 0x62, 0x1e, 0xb9, 0x62, 0x2c, 0x34, 0x49, 0x15, 0xd9, 0xdf, 0x47, 0x99, 0x39, 0xcc, 0x1a,
-       0x01, 0xc0, 0xda, 0x48, 0x44, 0xd4, 0x8b, 0xd3, 0x17, 0x7e, 0x39, 0xf9, 0x00, 0xe1, 0x2a, 0x46,
-       0xaa, 0x14, 0x22, 0xa1, 0x38, 0x09, 0x0b, 0xb7, 0x0c, 0x88, 0xa5, 0x73, 0xfd, 0xc4, 0x6b, 0xee,
-       0x07, 0xb4, 0x1b, 0xb3, 0x4a, 0xab, 0xae, 0xf6, 0xe7, 0x04, 0x61, 0x4b, 0x34, 0x7a, 0xe4, 0xff,
-       0xf9, 0x30, 0x28, 0x61, 0x92, 0x52, 0x58, 0x10, 0x15, 0x3a, 0x9f, 0x0a, 0xaf, 0x15, 0x29, 0x6c,
-       0x67, 0xc4, 0xb4, 0xcf, 0xe6, 0xf9, 0x46, 0x68, 0xe2, 0x2a, 0x97, 0x29, 0x16, 0xed, 0x1a, 0x9b,
-       0x9a, 0x45, 0x70, 0x3c, 0xf2, 0xdf, 0x29, 0x20, 0x9e, 0x33, 0x4b, 0x5b, 0x8d, 0xf6, 0x19, 0xec,
-       0x4b, 0xae, 0x1a, 0x2f, 0x53, 0x03, 0x9a, 0xfd, 0x68, 0x39, 0x58, 0xf7, 0x2e, 0x07, 0x9c, 0xf1,
-       0x3c, 0x1b, 0x47, 0x43, 0x19, 0x81, 0x0e, 0x0a, 0xbb, 0x84, 0xa0, 0xda, 0x87, 0xbc, 0x8a, 0x2a,
-       0xb7, 0x9c, 0xe1, 0xf9, 0xeb, 0x37, 0xb0, 0x11, 0x20, 0x7e, 0x4c, 0x11, 0x2e, 0x54, 0x30, 0xce,
-       0xaf, 0x63, 0xed, 0x6a, 0x63, 0x1f, 0x1e, 0x61, 0x62, 0x04, 0xf3, 0x3a, 0x5f, 0x26, 0x6c, 0x5c,
-       0xd7, 0xba, 0x4f, 0xf2, 0x61, 0x26, 0x29, 0x99, 0xea, 0x61, 0x84, 0x0d, 0x68, 0xa2, 0x5d, 0x9b,
-       0x5c, 0xe7, 0x86, 0x1d, 0xef, 0xf4, 0x6f, 0x3b, 0x6c, 0x67, 0xf0, 0x70, 0xe9, 0xc5, 0xdc, 0x0a,
-       0x9d, 0x0f, 0xdc, 0xcc, 0x0e, 0x7b, 0xf8, 0xc4, 0xee, 0x64, 0xe4, 0xd9, 0x3f, 0x14, 0xae, 0x8f,
-       0xc8, 0x18, 0x4d, 0xa1, 0xe4, 0x40, 0x2c, 0xe9, 0x13, 0xc6, 0xc1, 0xe0, 0xb9, 0x13, 0xbe, 0xd9,
-       0x93, 0x66, 0x56, 0x35, 0x5c, 0xc1, 0x38, 0x7d, 0xa1, 0xbb, 0x87, 0xa5, 0x90, 0x33, 0x4f, 0xea,
-       0xb6, 0x37, 0x19, 0x61, 0x81, 0x40, 0xba, 0xd7, 0x07, 0x69, 0x05, 0x15, 0x96, 0xe9, 0xde, 0x4f,
-       0x8a, 0x2b, 0x99, 0x5a, 0x17, 0x3f, 0x9f, 0xcf, 0x86, 0xf5, 0x37, 0x0a, 0xa1, 0x0e, 0x25, 0x65,
-       0x2d, 0x52, 0xce, 0x87, 0x10, 0x0f, 0x25, 0xc2, 0x1e, 0x0f, 0x71, 0x93, 0xb5, 0xc0, 0xb3, 0xb4,
-       0xd1, 0x65, 0xa8, 0xb4, 0xf6, 0xa5, 0x71, 0xad, 0x45, 0xdb, 0xdf, 0xec, 0xe3, 0x2a, 0x7e, 0x99,
-       0x96, 0x5a, 0x5d, 0x69, 0xfa, 0xdb, 0x13, 0x39, 0xb8, 0xf5, 0x58, 0xbb, 0x87, 0x69, 0x8d, 0x2c,
-       0x6d, 0x39, 0xff, 0x26, 0xce, 0x2c, 0xa8, 0x5a, 0x7e, 0x4b, 0x3f, 0xed, 0xac, 0x5f, 0xf0, 0xef,
-       0x48, 0xd3, 0xf8, 0x00, 0x00, 0x31, 0x82, 0x03, 0x28, 0x30, 0x82, 0x03, 0x24, 0x02, 0x01, 0x01,
-       0x30, 0x81, 0x91, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-       0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69,
-       0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
-       0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65,
-       0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
-       0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
-       0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30,
-       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x02, 0x08, 0x04, 0x2e, 0x97, 0xbb,
-       0x62, 0x84, 0xd9, 0x1c, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
-       0x01, 0x05, 0x00, 0xa0, 0x69, 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, 0x33, 0x30, 0x36, 0x32, 0x35, 0x30, 0x30, 0x33, 0x39, 0x33, 0x33, 0x5a, 0x30, 0x2f, 0x06,
-       0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x22, 0x04, 0x20, 0x40, 0xe5,
-       0x7f, 0xba, 0xdb, 0xb7, 0xe8, 0x35, 0xa0, 0x59, 0xd4, 0xa0, 0x57, 0x5c, 0x60, 0x53, 0x98, 0x48,
-       0xda, 0x3b, 0x79, 0xf4, 0x73, 0x63, 0xd7, 0x90, 0xf0, 0x10, 0x2b, 0x71, 0x6e, 0x36, 0x30, 0x0d,
-       0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02,
-       0x00, 0x6a, 0x51, 0xe7, 0xdc, 0x34, 0x87, 0x3c, 0x45, 0xd1, 0xeb, 0x6d, 0x20, 0x26, 0xcd, 0x53,
-       0x01, 0x82, 0x71, 0x25, 0x73, 0xce, 0xe3, 0x9f, 0xfb, 0xca, 0x4c, 0x89, 0x01, 0x96, 0x6a, 0x1c,
-       0x02, 0x57, 0xb1, 0xd1, 0x99, 0x43, 0x29, 0x4e, 0xfc, 0xf3, 0x30, 0x9e, 0xbc, 0x7e, 0xc4, 0x04,
-       0xa3, 0x5d, 0x1a, 0x3c, 0x54, 0xc2, 0xba, 0x38, 0xdc, 0x8d, 0x12, 0xaf, 0xb4, 0x12, 0xe4, 0xeb,
-       0x8a, 0x03, 0xb0, 0xc7, 0xaa, 0x72, 0xf4, 0x8b, 0x87, 0xd0, 0x0e, 0xd7, 0x9f, 0x45, 0xcb, 0xa5,
-       0x0f, 0x4c, 0x60, 0x2b, 0xe5, 0xf7, 0xe8, 0xf1, 0x0a, 0xc0, 0x29, 0x0f, 0xe0, 0xa7, 0x0a, 0xc0,
-       0x4b, 0xd9, 0x16, 0x04, 0xde, 0x4d, 0xc1, 0x5c, 0xbd, 0xad, 0x84, 0xb3, 0x8e, 0x72, 0x7d, 0xcc,
-       0x73, 0x77, 0xe9, 0xeb, 0x3a, 0x36, 0xbc, 0xbd, 0x58, 0x0b, 0x97, 0x12, 0xd2, 0x9c, 0x3b, 0xd1,
-       0x32, 0x2d, 0xbd, 0xe7, 0x40, 0xc8, 0x4c, 0x82, 0xbb, 0xe4, 0x49, 0xbc, 0x64, 0x50, 0xe3, 0x8b,
-       0xba, 0xa2, 0xac, 0x31, 0xdb, 0xcd, 0x57, 0x79, 0xeb, 0x91, 0x87, 0xc7, 0x52, 0x70, 0xfe, 0xaa,
-       0xd0, 0x7d, 0xd2, 0x78, 0x48, 0x77, 0xbc, 0xd9, 0xa7, 0x2b, 0x01, 0x20, 0x36, 0xd0, 0x99, 0x61,
-       0x90, 0xfc, 0xb2, 0x8a, 0xfd, 0x02, 0xad, 0x60, 0xb6, 0x89, 0x82, 0xca, 0x8a, 0xc3, 0x6f, 0xd7,
-       0x91, 0xb1, 0x4c, 0x25, 0x6a, 0x00, 0x59, 0xaa, 0x2c, 0xa0, 0xfc, 0x8b, 0x54, 0x64, 0xbd, 0x04,
-       0x46, 0x8f, 0x7c, 0x1d, 0x53, 0xd4, 0x57, 0x9c, 0x06, 0x1f, 0xd8, 0x8e, 0x8b, 0x79, 0x0a, 0xe6,
-       0xf5, 0xf3, 0xab, 0x10, 0x8c, 0xe1, 0x65, 0xd7, 0x0f, 0xf1, 0x9f, 0xe3, 0xf7, 0xd1, 0xca, 0xb2,
-       0x6d, 0xcb, 0x6b, 0x50, 0x94, 0x1f, 0x1f, 0x4d, 0x55, 0xd1, 0xcb, 0x99, 0x86, 0xfe, 0xa4, 0xe5,
-       0x05, 0x6c, 0x09, 0x54, 0x3a, 0xc7, 0x1c, 0x6e, 0xa5, 0x9c, 0x49, 0x69, 0xbb, 0xc3, 0x24, 0x8c,
-       0x94, 0xf6, 0x67, 0xbd, 0x7b, 0xe9, 0x71, 0x31, 0x14, 0xcf, 0xf3, 0xf4, 0xdc, 0xd9, 0xdf, 0x99,
-       0x31, 0x3d, 0x6f, 0xda, 0xba, 0x7c, 0x62, 0xbd, 0x2c, 0x01, 0x2c, 0x03, 0xa5, 0xfb, 0x22, 0xac,
-       0x55, 0x60, 0x89, 0xe4, 0xf2, 0xb4, 0xb7, 0xed, 0x18, 0x9d, 0xa5, 0xe9, 0x55, 0xe6, 0xef, 0xbb,
-       0x79, 0xe6, 0xf9, 0xd0, 0xf0, 0x62, 0x71, 0x30, 0x12, 0xdf, 0xde, 0x15, 0x42, 0x46, 0x2c, 0x5a,
-       0x81, 0x6f, 0x3c, 0x38, 0x7f, 0x75, 0x00, 0x95, 0x68, 0xea, 0x43, 0x1c, 0x6a, 0xf9, 0x81, 0xde,
-       0xb5, 0x0c, 0x0e, 0x50, 0xb5, 0x67, 0x9a, 0xea, 0x37, 0x6d, 0x9d, 0xd3, 0xd0, 0x69, 0x89, 0x5c,
-       0x51, 0x27, 0x37, 0x10, 0x6f, 0x6e, 0x13, 0xdb, 0xb8, 0xb8, 0xe9, 0xd0, 0x84, 0x12, 0xf2, 0x3d,
-       0x71, 0xc9, 0x7c, 0xe6, 0x9a, 0x1c, 0x50, 0xee, 0x43, 0x25, 0xff, 0x0b, 0x31, 0x88, 0x5b, 0xfa,
-       0xc9, 0x84, 0x31, 0xb8, 0x6f, 0x67, 0x37, 0x7f, 0xa5, 0x0c, 0xaf, 0x15, 0x2a, 0x15, 0x04, 0xbd,
-       0x1c, 0x76, 0xcb, 0x34, 0xb2, 0x38, 0x77, 0x2f, 0x1a, 0x09, 0x8b, 0x01, 0x44, 0xf5, 0x5f, 0x47,
-       0x40, 0x64, 0x2a, 0x21, 0x4a, 0x88, 0xa2, 0xdd, 0xe6, 0xc5, 0xc4, 0x9d, 0xfd, 0x7c, 0x3d, 0xe3,
-       0x1a, 0x79, 0x30, 0x90, 0xda, 0x17, 0x4d, 0x92, 0x86, 0xe6, 0xf7, 0x19, 0x93, 0x58, 0x1f, 0x21,
-       0x16, 0x60, 0x01, 0x6a, 0xbb, 0x69, 0xc4, 0xfd, 0x29, 0xfc, 0xac, 0x04, 0xcb, 0x97, 0x7b, 0x47,
-       0x51, 0xf6, 0x29, 0xca, 0x48, 0x52, 0x02, 0xb6, 0x27, 0x1c, 0xf2, 0x96, 0x06, 0x48, 0x23, 0x9d,
-       0xf6, 0x93, 0xda, 0x5d, 0x83, 0x61, 0x2b, 0xbd, 0x52, 0x0c, 0x4d, 0x89, 0xf3, 0x2f, 0xa2, 0x67,
-       0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 
-};
-
-static const UInt8 kSignedManifestData[] = {
-       0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30,
-       0x80, 0x02, 0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
-       0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-       0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x82, 0x01, 0xeb, 0x62, 0x70, 0x6c, 0x69, 0x73, 0x74,
-       0x30, 0x30, 0xd8, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
-       0x0e, 0x0f, 0x10, 0x5d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65,
-       0x72, 0x5d, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x5f,
-       0x10, 0x0f, 0x63, 0x65, 0x72, 0x74, 0x73, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x2e, 0x64, 0x61, 0x74,
-       0x61, 0x5d, 0x45, 0x56, 0x52, 0x6f, 0x6f, 0x74, 0x73, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x5f,
-       0x10, 0x14, 0x47, 0x72, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x73,
-       0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x10, 0x12, 0x41, 0x73, 0x73, 0x65, 0x74, 0x56, 0x65,
-       0x72, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x10, 0x0f, 0x63, 0x65,
-       0x72, 0x74, 0x73, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x10, 0x19,
-       0x41, 0x70, 0x70, 0x6c, 0x65, 0x45, 0x53, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
-       0x74, 0x65, 0x73, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x77, 0xfc, 0xe6, 0x2c, 0x4f, 0x10,
-       0x20, 0x08, 0x89, 0x3f, 0xe7, 0x83, 0xdf, 0x07, 0x61, 0xaf, 0x65, 0x58, 0x66, 0xce, 0x74, 0xb5,
-       0x46, 0x56, 0xc2, 0x03, 0x35, 0x4a, 0xd4, 0x88, 0xa7, 0x32, 0x6e, 0xdd, 0xcb, 0xb9, 0xb5, 0x21,
-       0x6c, 0x4f, 0x10, 0x20, 0x2e, 0xa3, 0x40, 0x44, 0x60, 0xdb, 0x4f, 0x51, 0x3c, 0x06, 0x27, 0x4e,
-       0x00, 0x7b, 0x25, 0x35, 0x13, 0x9a, 0x61, 0xc4, 0xa8, 0x0a, 0xaa, 0xcd, 0x70, 0xe7, 0x75, 0x7e,
-       0x4d, 0x52, 0xbb, 0x24, 0x4f, 0x10, 0x20, 0x41, 0x11, 0x04, 0x71, 0xcb, 0x9b, 0xfb, 0xaf, 0xcf,
-       0x6f, 0x1d, 0xee, 0x8e, 0x14, 0x3c, 0x1d, 0x39, 0x64, 0x68, 0xc8, 0x48, 0xb1, 0xee, 0x8a, 0xd1,
-       0x05, 0x62, 0x40, 0x4f, 0x79, 0x22, 0x30, 0x4f, 0x10, 0x20, 0xa5, 0x0a, 0x89, 0x37, 0xf0, 0xa8,
-       0x87, 0x2b, 0xcc, 0x33, 0xc1, 0x5a, 0xe6, 0xd3, 0x01, 0x43, 0x83, 0x50, 0x8d, 0x49, 0x84, 0x96,
-       0x22, 0xaf, 0x3e, 0x26, 0x10, 0x78, 0x8a, 0x3a, 0x0c, 0x78, 0x4f, 0x10, 0x20, 0x6c, 0xcb, 0x07,
-       0xc1, 0x68, 0x6f, 0xf9, 0xa3, 0x0c, 0x12, 0xd7, 0xb8, 0xe2, 0x51, 0x3d, 0xe2, 0xd5, 0x43, 0xeb,
-       0xb5, 0x6d, 0x80, 0x6d, 0x8c, 0xca, 0x17, 0xd5, 0x31, 0x1a, 0x65, 0x48, 0x15, 0x4f, 0x10, 0x20,
-       0xa6, 0x4c, 0x19, 0xd2, 0xb8, 0xe4, 0xbf, 0x59, 0x9a, 0x68, 0xe5, 0x34, 0x08, 0xc3, 0x61, 0x91,
-       0xf9, 0x06, 0xf1, 0x16, 0x02, 0x1c, 0xfd, 0xaf, 0x46, 0xfb, 0xad, 0xc7, 0xb4, 0x57, 0x1d, 0x54,
-       0x4f, 0x10, 0x20, 0x94, 0x47, 0xd4, 0x5d, 0xaf, 0x6a, 0x4f, 0xba, 0xc4, 0xe8, 0x6b, 0x10, 0x32,
-       0x2a, 0x37, 0x90, 0x3c, 0x5a, 0x5b, 0x9f, 0x33, 0x48, 0x59, 0xd3, 0x1d, 0xf5, 0x57, 0x90, 0xde,
-       0xb3, 0x5b, 0xf6, 0x00, 0x08, 0x00, 0x19, 0x00, 0x27, 0x00, 0x35, 0x00, 0x47, 0x00, 0x55, 0x00,
-       0x6c, 0x00, 0x81, 0x00, 0x93, 0x00, 0xaf, 0x00, 0xb4, 0x00, 0xd7, 0x00, 0xfa, 0x01, 0x1d, 0x01,
-       0x40, 0x01, 0x63, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x01, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x30, 0x82, 0x07,
-       0xab, 0x30, 0x82, 0x05, 0x93, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x04, 0x2e, 0x97, 0xbb,
-       0x62, 0x84, 0xd9, 0x1c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-       0x0b, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
-       0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69,
-       0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
-       0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79,
-       0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65,
-       0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41,
-       0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
-       0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30,
-       0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33,
-       0x30, 0x36, 0x32, 0x35, 0x30, 0x30, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30,
-       0x36, 0x32, 0x31, 0x30, 0x30, 0x30, 0x39, 0x33, 0x38, 0x5a, 0x30, 0x59, 0x31, 0x23, 0x30, 0x21,
-       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49,
-       0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e,
-       0x67, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x07, 0x43, 0x6f, 0x72, 0x65,
-       0x20, 0x4f, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70,
-       0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
-       0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
-       0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02,
-       0x0a, 0x02, 0x82, 0x02, 0x01, 0x00, 0xad, 0xef, 0x52, 0xc8, 0xda, 0x8e, 0x3c, 0xcc, 0x06, 0xcf,
-       0xfc, 0xed, 0xdb, 0x92, 0xb3, 0xa8, 0xe0, 0x3b, 0x14, 0x40, 0x34, 0xad, 0x91, 0xf3, 0xbe, 0x1a,
-       0x00, 0xbb, 0x06, 0xa2, 0xd7, 0x24, 0x6f, 0xd5, 0xd3, 0xdf, 0xd9, 0xff, 0x0b, 0x4d, 0x6d, 0xc5,
-       0xdd, 0x7a, 0x37, 0xfa, 0x08, 0x49, 0x0e, 0x36, 0x5e, 0xab, 0x83, 0x8d, 0xeb, 0x83, 0x00, 0xf9,
-       0xaa, 0xe4, 0x88, 0x09, 0x87, 0x05, 0x6b, 0x01, 0x6e, 0x49, 0x54, 0xa1, 0x3b, 0x5c, 0xfc, 0x2b,
-       0x0f, 0x1f, 0xa9, 0x7c, 0xc1, 0xc5, 0xe1, 0x32, 0xd7, 0x86, 0x49, 0x80, 0x0f, 0xf8, 0xe3, 0x3b,
-       0xa3, 0x12, 0x06, 0x5d, 0xf4, 0x43, 0xc0, 0xb2, 0xc7, 0xcf, 0xb4, 0x14, 0x2c, 0x50, 0x70, 0x57,
-       0xb9, 0xb2, 0xe7, 0x72, 0x9a, 0x9f, 0x45, 0x0b, 0x0d, 0xe5, 0xab, 0x3e, 0x23, 0x91, 0xe0, 0x88,
-       0x84, 0x3a, 0xec, 0xaa, 0x80, 0xab, 0x37, 0xa3, 0x0c, 0x63, 0x99, 0x1c, 0xde, 0x1b, 0x29, 0x95,
-       0x4b, 0xff, 0xcd, 0x92, 0x10, 0xa3, 0x50, 0x93, 0x89, 0x4f, 0xdc, 0x30, 0x0d, 0x29, 0x2a, 0x80,
-       0x04, 0x32, 0xb3, 0xb9, 0xa7, 0x79, 0x5f, 0x18, 0xce, 0xc1, 0x90, 0xe6, 0xd6, 0x0c, 0xeb, 0x91,
-       0x27, 0x6f, 0x17, 0xd2, 0x93, 0xda, 0xa1, 0xa8, 0x3f, 0x20, 0xe9, 0xeb, 0x54, 0x37, 0xd7, 0x54,
-       0xfd, 0x44, 0xa2, 0x8d, 0xa4, 0x30, 0x6e, 0xbf, 0xd0, 0xbd, 0xc4, 0x7d, 0x93, 0xeb, 0xf6, 0xfa,
-       0x1e, 0xc1, 0xd5, 0xee, 0xfe, 0xb7, 0x56, 0x51, 0xb3, 0x0b, 0x3f, 0xf4, 0xb1, 0x77, 0x75, 0xaf,
-       0x10, 0x14, 0x98, 0x74, 0x41, 0x40, 0xdb, 0xe4, 0x6b, 0x3f, 0x49, 0xce, 0xb8, 0x80, 0x20, 0x72,
-       0x92, 0xcb, 0x63, 0x63, 0x44, 0x4e, 0xe8, 0xe4, 0xde, 0xe9, 0xc3, 0x0a, 0x75, 0xd8, 0xbf, 0xc5,
-       0x8e, 0xcb, 0xcf, 0xec, 0x65, 0x49, 0x56, 0xa1, 0x9f, 0xb6, 0x39, 0x53, 0x69, 0xb4, 0x04, 0xe8,
-       0xd0, 0x28, 0xc6, 0x69, 0xde, 0xdb, 0x30, 0xa7, 0xb0, 0xbf, 0x6f, 0xfe, 0x7b, 0x45, 0x87, 0x07,
-       0xf0, 0x85, 0x34, 0x71, 0xca, 0xe5, 0x07, 0x61, 0xce, 0x53, 0xf3, 0xd6, 0x69, 0x70, 0x5a, 0x4b,
-       0x7e, 0xda, 0x9b, 0x77, 0x17, 0x65, 0x6c, 0x4d, 0xd5, 0x59, 0x00, 0x6f, 0x47, 0x65, 0x30, 0x98,
-       0xd9, 0x7b, 0xa7, 0x51, 0x8b, 0x47, 0x7d, 0x8f, 0x5a, 0x91, 0x72, 0xe4, 0x86, 0x4f, 0xb0, 0xb4,
-       0x12, 0x42, 0x55, 0x95, 0x59, 0xa3, 0xc6, 0xdf, 0xba, 0x20, 0x0e, 0x5d, 0x0f, 0x6a, 0x6a, 0xc2,
-       0x08, 0x93, 0x9f, 0x0e, 0x8b, 0x61, 0x20, 0x9e, 0x2b, 0x64, 0x26, 0x15, 0x52, 0x9b, 0xef, 0x34,
-       0x7c, 0x12, 0xa4, 0xe4, 0xf7, 0xfc, 0x9a, 0xa6, 0xe6, 0xe9, 0x6f, 0xfc, 0xbb, 0x16, 0xc4, 0x0f,
-       0x0b, 0xac, 0x84, 0x9d, 0xc8, 0xe9, 0x98, 0xe1, 0xf4, 0x35, 0xfb, 0x97, 0x63, 0x14, 0x6c, 0x15,
-       0x51, 0x51, 0x5b, 0xc8, 0x64, 0x25, 0x46, 0x44, 0x6d, 0xbd, 0x17, 0xdd, 0x17, 0x4d, 0x34, 0x77,
-       0xa8, 0x6d, 0x4b, 0x97, 0x4b, 0x77, 0xf5, 0x77, 0x07, 0x1b, 0x93, 0x18, 0xf3, 0x44, 0x4e, 0x79,
-       0xe2, 0xfc, 0x96, 0x76, 0x5e, 0x69, 0x85, 0xf6, 0xb6, 0x97, 0xbb, 0xb0, 0x41, 0x1f, 0x03, 0x8b,
-       0xcb, 0xc0, 0xa9, 0x10, 0x67, 0x8f, 0x6f, 0x67, 0xab, 0xb0, 0xbd, 0x1f, 0xc7, 0x11, 0xfd, 0xb8,
-       0x29, 0x47, 0x41, 0xd4, 0x34, 0x0f, 0x5b, 0x9d, 0x64, 0xfb, 0x8f, 0x5f, 0x37, 0xd1, 0x9a, 0x4a,
-       0x2d, 0x62, 0xd1, 0x74, 0x2e, 0x6b, 0x7f, 0xdf, 0xb3, 0xea, 0x5f, 0xfa, 0x63, 0xd4, 0x4f, 0xb3,
-       0x89, 0x76, 0x67, 0x36, 0x71, 0xcd, 0xaf, 0xd7, 0x9c, 0x95, 0xa8, 0xce, 0xee, 0x29, 0x25, 0xb1,
-       0x2a, 0xac, 0x99, 0x10, 0x9b, 0x03, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x49, 0x30,
-       0x82, 0x02, 0x45, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xcd, 0xbf,
-       0x6f, 0x14, 0xff, 0x8b, 0xb7, 0xf7, 0x29, 0xcd, 0xa4, 0x8c, 0xc1, 0xb1, 0x30, 0x92, 0x37, 0x8b,
-       0xd4, 0xef, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
-       0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35, 0x07, 0x82,
-       0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6,
-       0x1c, 0x30, 0x82, 0x01, 0xe3, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x01, 0x01, 0xff, 0x04, 0x82, 0x01,
-       0xd7, 0x30, 0x82, 0x01, 0xd3, 0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-       0x63, 0x64, 0x05, 0x01, 0x30, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06,
-       0x01, 0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52,
-       0x00, 0x65, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20,
-       0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20,
-       0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63,
-       0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61,
-       0x00, 0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79,
-       0x00, 0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73,
-       0x00, 0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61,
-       0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74,
-       0x00, 0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20,
-       0x00, 0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62,
-       0x00, 0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64,
-       0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d,
-       0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f,
-       0x00, 0x6e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73,
-       0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c,
-       0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69,
-       0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c,
-       0x00, 0x69, 0x00, 0x63, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20,
-       0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63,
-       0x00, 0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72,
-       0x00, 0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73,
-       0x00, 0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74,
-       0x00, 0x73, 0x00, 0x2e, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01,
-       0x16, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70,
-       0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
-       0x74, 0x65, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x0b, 0x06, 0x09, 0x2a,
-       0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x05, 0x0d, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
-       0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-       0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0xc3, 0xd1, 0x52, 0x94,
-       0x51, 0xa7, 0x6d, 0xe9, 0xf8, 0x1a, 0xba, 0x15, 0x2c, 0x38, 0x6b, 0xd6, 0xba, 0xcf, 0x12, 0x20,
-       0x1d, 0x46, 0xef, 0x99, 0x48, 0x95, 0x9d, 0x1e, 0x49, 0x1b, 0xe7, 0x95, 0xde, 0x73, 0x28, 0xc1,
-       0x90, 0xfe, 0xeb, 0x39, 0xe1, 0xa8, 0xa8, 0x5c, 0x4e, 0x71, 0x03, 0x1b, 0x22, 0x37, 0x07, 0xed,
-       0x24, 0xa4, 0xee, 0x5d, 0x0a, 0xf8, 0x04, 0xf8, 0xba, 0x34, 0x50, 0xc0, 0x49, 0xd7, 0xa4, 0x4f,
-       0xdd, 0x06, 0x81, 0x33, 0x3a, 0x69, 0x4e, 0x43, 0x85, 0x15, 0xde, 0x05, 0x37, 0xf5, 0xb3, 0xd5,
-       0x68, 0x4c, 0x30, 0x6a, 0x52, 0x35, 0x6a, 0xb0, 0x2b, 0x8e, 0xe1, 0xde, 0xa6, 0xd2, 0xfc, 0xe2,
-       0x9f, 0xdc, 0x95, 0x65, 0x13, 0x45, 0x91, 0xc1, 0x7b, 0xff, 0x90, 0x6a, 0x4c, 0xd3, 0x20, 0x5c,
-       0x1b, 0x99, 0xea, 0x82, 0xec, 0xfd, 0x0b, 0x89, 0x25, 0x6c, 0x31, 0x3d, 0xa8, 0x52, 0xba, 0x8e,
-       0xdf, 0x20, 0xcb, 0x5f, 0x00, 0xf8, 0x6b, 0xf2, 0x63, 0x5d, 0x2a, 0x55, 0xc6, 0xee, 0x34, 0xa4,
-       0x86, 0xab, 0x47, 0x89, 0xcd, 0xb6, 0xaa, 0xe0, 0x5c, 0x9a, 0x57, 0x7d, 0x3e, 0xaa, 0x8b, 0x74,
-       0xfc, 0x94, 0xc7, 0x9d, 0x0e, 0xa2, 0x92, 0xa9, 0xc5, 0xdd, 0x71, 0x53, 0x54, 0x38, 0xb0, 0x22,
-       0x88, 0xdc, 0x46, 0xcd, 0x45, 0xc7, 0x33, 0xc7, 0x2f, 0xed, 0x5f, 0x4d, 0x05, 0x9d, 0xba, 0x2e,
-       0xf7, 0xa4, 0xb5, 0xfa, 0x79, 0x11, 0x41, 0xd1, 0x1b, 0x50, 0xab, 0xef, 0xdf, 0xa8, 0x5c, 0x28,
-       0xc7, 0x8e, 0x86, 0xa2, 0x85, 0x8a, 0x90, 0xf4, 0xda, 0x71, 0x1f, 0xff, 0x7f, 0x02, 0x4c, 0x24,
-       0x95, 0x0d, 0x31, 0xa3, 0x8b, 0x62, 0xae, 0x45, 0xe2, 0x44, 0x6c, 0x01, 0x1d, 0xdc, 0x67, 0xbe,
-       0xfb, 0x16, 0x4f, 0x4c, 0xf0, 0x81, 0xa8, 0xbd, 0xe1, 0x29, 0x6f, 0x1c, 0xff, 0xa4, 0x82, 0x96,
-       0xa3, 0x67, 0xad, 0xa6, 0x99, 0xd6, 0x29, 0x02, 0x7f, 0xfc, 0xe3, 0x8d, 0xe3, 0x0d, 0x17, 0x91,
-       0x84, 0xcf, 0x4b, 0x05, 0xdd, 0x29, 0x96, 0xb4, 0x58, 0x56, 0x9b, 0x65, 0x17, 0xdd, 0x16, 0x1f,
-       0xf8, 0x59, 0x8d, 0xfb, 0xa0, 0xb0, 0xc7, 0x0b, 0x74, 0x64, 0xef, 0x8c, 0xcb, 0xba, 0x10, 0x48,
-       0x37, 0x28, 0xc9, 0x7f, 0x17, 0xac, 0x5f, 0x04, 0xa0, 0x50, 0x6d, 0x18, 0x5f, 0x23, 0xe3, 0x9c,
-       0xb6, 0xe0, 0x6c, 0xc0, 0xe1, 0x5e, 0xba, 0x8f, 0x70, 0xf1, 0xca, 0xc5, 0x97, 0x95, 0xf7, 0x4c,
-       0xdd, 0x6c, 0x8c, 0xbb, 0x4d, 0x68, 0x18, 0x59, 0xb3, 0x1b, 0x6f, 0x81, 0xe7, 0xd8, 0x44, 0xdc,
-       0x6e, 0x84, 0xce, 0x5b, 0x0c, 0x66, 0xef, 0xc4, 0x72, 0x00, 0xf2, 0x5a, 0xef, 0x82, 0x63, 0x18,
-       0xf7, 0xd3, 0xb8, 0x25, 0xc4, 0x91, 0x80, 0x04, 0x54, 0x61, 0x5b, 0xf5, 0xe2, 0xda, 0xfb, 0x1d,
-       0xd4, 0x19, 0x99, 0x18, 0xbd, 0x9a, 0x1e, 0x96, 0xe9, 0x1c, 0xd5, 0xd0, 0x06, 0xf5, 0x37, 0x91,
-       0x3b, 0x4d, 0xa5, 0x2a, 0xda, 0x3c, 0xcd, 0xa6, 0xda, 0x53, 0xb8, 0x4a, 0x1e, 0xb9, 0x51, 0xed,
-       0xc3, 0x47, 0xc6, 0xfa, 0xdc, 0x2e, 0xb3, 0xdd, 0x63, 0x65, 0xba, 0x17, 0xdb, 0x65, 0x8b, 0x63,
-       0x77, 0x31, 0x6d, 0xd9, 0xb7, 0x18, 0x33, 0x91, 0xa1, 0x1f, 0xed, 0x0d, 0x49, 0x7f, 0x29, 0xd6,
-       0xd4, 0xf6, 0x12, 0x0f, 0xb2, 0x0c, 0xc9, 0x0f, 0x61, 0xb1, 0x48, 0x58, 0x52, 0xac, 0x80, 0x92,
-       0xb4, 0x2d, 0x4c, 0xa8, 0x94, 0xf6, 0x99, 0xc8, 0xb7, 0x1a, 0x7f, 0x3a, 0x52, 0x49, 0x9f, 0x44,
-       0xff, 0x0d, 0x38, 0x27, 0x3f, 0xad, 0xf6, 0xa4, 0x8f, 0xd9, 0x4b, 0x30, 0x6f, 0xe0, 0xb8, 0x20,
-       0x94, 0x82, 0x4c, 0x96, 0xea, 0x27, 0x28, 0x61, 0x1a, 0x41, 0x6d, 0xd4, 0x30, 0x82, 0x07, 0xca,
-       0x30, 0x82, 0x05, 0xb2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x4e, 0xa1, 0x31, 0xe7, 0xca,
-       0x50, 0xb8, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d,
-       0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f,
-       0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e,
-       0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
-       0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
-       0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
-       0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a,
-       0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09,
-       0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30,
-       0x36, 0x32, 0x34, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d, 0x34, 0x33, 0x30, 0x36,
-       0x31, 0x37, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36,
-       0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49,
-       0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43,
-       0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74,
-       0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
-       0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61,
-       0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13,
-       0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49,
-       0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
-       0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
-       0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a, 0x02, 0x82, 0x02, 0x01,
-       0x00, 0xce, 0x15, 0xf7, 0x6f, 0xd8, 0x42, 0x0c, 0x6f, 0x45, 0xb4, 0x04, 0x59, 0x24, 0xcb, 0x70,
-       0x88, 0x84, 0x77, 0xa1, 0x91, 0x54, 0xf4, 0x87, 0x61, 0xb3, 0xd3, 0xfc, 0xbe, 0xb6, 0x05, 0x3c,
-       0xb9, 0xb7, 0x7d, 0x7c, 0xbc, 0x0b, 0xe8, 0x87, 0x07, 0xcf, 0x20, 0xbe, 0xaa, 0xeb, 0x24, 0xc5,
-       0xe4, 0x5c, 0xcd, 0xcb, 0x89, 0x9f, 0x7a, 0xea, 0xb4, 0x5d, 0x3b, 0x29, 0x6c, 0xba, 0x4d, 0x15,
-       0xfb, 0x59, 0xd0, 0x5a, 0xea, 0x41, 0x4e, 0x0d, 0x1d, 0xf7, 0x66, 0x77, 0xa2, 0x96, 0x56, 0xed,
-       0xd1, 0x16, 0x7b, 0xea, 0xf5, 0x60, 0xdf, 0x32, 0x9c, 0xa9, 0xfd, 0xbf, 0xb8, 0x34, 0x6f, 0x57,
-       0x17, 0xe6, 0x04, 0x37, 0x71, 0x07, 0xc0, 0xe9, 0x0f, 0x3c, 0xed, 0x4f, 0x31, 0x87, 0x05, 0xa4,
-       0xed, 0xab, 0xac, 0xd6, 0x50, 0x05, 0x5b, 0xca, 0xd3, 0xf9, 0xd6, 0xaa, 0xaa, 0x88, 0x57, 0x66,
-       0xf6, 0x6d, 0x8d, 0x4b, 0x71, 0x29, 0xd4, 0x3d, 0x1d, 0xbc, 0x82, 0x6e, 0x81, 0xe9, 0x19, 0xf5,
-       0xe1, 0x12, 0x9f, 0x47, 0xdb, 0x5c, 0xed, 0x88, 0xba, 0x51, 0xe7, 0x3a, 0xa0, 0x77, 0x2d, 0xe6,
-       0xcc, 0xb4, 0x34, 0xdf, 0xad, 0xbd, 0x7b, 0xf8, 0xa7, 0x79, 0x51, 0x2d, 0xe6, 0xc2, 0xee, 0xd2,
-       0x96, 0xfa, 0x60, 0x60, 0x32, 0x40, 0x41, 0x37, 0x12, 0xeb, 0x63, 0x99, 0x3d, 0xf3, 0x21, 0xbe,
-       0xdf, 0xa1, 0x77, 0xe6, 0x81, 0xa9, 0x99, 0x0c, 0x4b, 0x43, 0x0c, 0x05, 0x6a, 0x6b, 0x8f, 0x05,
-       0x02, 0xd9, 0x43, 0xab, 0x72, 0x76, 0xca, 0xa7, 0x75, 0x63, 0x85, 0xe3, 0xa5, 0x5c, 0xc0, 0xd6,
-       0xd4, 0x1c, 0xeb, 0xac, 0x2c, 0x9a, 0x15, 0x6b, 0x4e, 0x99, 0x74, 0x7d, 0xd2, 0x69, 0x9f, 0xa8,
-       0xf7, 0x65, 0xde, 0xeb, 0x36, 0x85, 0xd5, 0x7e, 0x4a, 0x7a, 0x8a, 0xeb, 0x7c, 0xcd, 0x43, 0x9e,
-       0x05, 0xdb, 0x34, 0xc3, 0x69, 0xbd, 0xc2, 0xe7, 0xfb, 0xa0, 0x43, 0xb3, 0xd7, 0x15, 0x28, 0x8a,
-       0x91, 0xce, 0xd7, 0xa7, 0xa4, 0xcc, 0xf4, 0x1b, 0x37, 0x33, 0x76, 0xc4, 0x58, 0xb9, 0x2d, 0x89,
-       0xe2, 0xb6, 0x2c, 0x56, 0x10, 0x96, 0xcc, 0xa6, 0x07, 0x79, 0x11, 0x7d, 0x26, 0xd2, 0x85, 0x22,
-       0x19, 0x20, 0xb7, 0xef, 0xc3, 0xd9, 0x4e, 0x18, 0xf3, 0xaa, 0x05, 0xce, 0x87, 0x99, 0xde, 0x76,
-       0x90, 0x08, 0x74, 0xac, 0x61, 0x31, 0xf8, 0x51, 0xa0, 0xc9, 0x70, 0xfc, 0xb9, 0x22, 0xfe, 0xd2,
-       0x0d, 0xc8, 0x49, 0x64, 0x00, 0xe4, 0xf1, 0x53, 0xfd, 0xa1, 0xe6, 0xff, 0x8e, 0xd6, 0xde, 0x9e,
-       0xcc, 0x3d, 0x37, 0x3a, 0x10, 0x62, 0x59, 0xb2, 0x34, 0x8a, 0x1d, 0xf7, 0x9e, 0xa0, 0xbb, 0xf4,
-       0x53, 0xd9, 0xb8, 0x18, 0x88, 0x12, 0x5c, 0x92, 0x0d, 0xc9, 0x94, 0x7f, 0x24, 0xb9, 0x9f, 0xda,
-       0x07, 0xb6, 0x79, 0x77, 0x09, 0xa3, 0x29, 0x3a, 0x70, 0x63, 0x3b, 0x22, 0x42, 0x14, 0xd0, 0xf9,
-       0x7b, 0x90, 0x52, 0x2b, 0x3f, 0x7f, 0xb7, 0x41, 0x20, 0x0d, 0x7e, 0x70, 0xd7, 0x88, 0x36, 0xa2,
-       0xe9, 0x81, 0x77, 0xf4, 0xb0, 0x15, 0x43, 0x9c, 0x5f, 0x4d, 0x3e, 0x4f, 0x83, 0x79, 0x06, 0x73,
-       0x7a, 0xe7, 0xcb, 0x79, 0x1d, 0xec, 0xa3, 0xce, 0x93, 0x5c, 0x68, 0xbf, 0x5a, 0xe6, 0x4c, 0x23,
-       0x86, 0x41, 0x7f, 0xb4, 0xfc, 0xd0, 0x2c, 0x1b, 0x64, 0x39, 0x64, 0xb7, 0xd2, 0x1d, 0xd0, 0x2d,
-       0x16, 0x77, 0xfe, 0x4d, 0xad, 0xf0, 0x4f, 0x38, 0xb3, 0xf9, 0x5a, 0xee, 0x0e, 0x1d, 0xb6, 0xf9,
-       0x3f, 0xba, 0x77, 0x5a, 0x20, 0xd2, 0x74, 0x1a, 0x4b, 0x5a, 0xaf, 0x62, 0xb5, 0xd3, 0xef, 0x37,
-       0x49, 0xfe, 0x1e, 0xcd, 0xb5, 0xba, 0xb5, 0xa6, 0x46, 0x7b, 0x38, 0x63, 0x62, 0x3c, 0x18, 0x7d,
-       0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x3c, 0x30, 0x82, 0x02, 0x38, 0x30, 0x1d,
-       0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x35, 0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5,
-       0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6, 0x1c, 0x30, 0x0f, 0x06,
-       0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x1f,
-       0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35, 0x07, 0x82, 0xfe, 0x0e,
-       0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6, 0x1c, 0x30,
-       0x82, 0x01, 0xd3, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0xca, 0x30, 0x82, 0x01, 0xc6,
-       0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63, 0x64, 0x05, 0x01, 0x30,
-       0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02,
-       0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52, 0x00, 0x65, 0x00, 0x6c, 0x00,
-       0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x6e, 0x00,
-       0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00,
-       0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00,
-       0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x79, 0x00,
-       0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00,
-       0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00, 0x20, 0x00, 0x61, 0x00,
-       0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00,
-       0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00,
-       0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x61, 0x00, 0x70, 0x00,
-       0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x65, 0x00,
-       0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x61, 0x00, 0x72, 0x00,
-       0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00, 0x73, 0x00, 0x20, 0x00,
-       0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x64, 0x00,
-       0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x20, 0x00, 0x6f, 0x00,
-       0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x63, 0x00,
-       0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00,
-       0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00,
-       0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x65, 0x00,
-       0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00,
-       0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72, 0x00, 0x61, 0x00, 0x63, 0x00,
-       0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00,
-       0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x73, 0x00, 0x2e, 0x30,
-       0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x29, 0x68, 0x74, 0x74,
-       0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
-       0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x61, 0x75, 0x74,
-       0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
-       0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-       0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x6f, 0x8a, 0xb7, 0x35, 0x73, 0x5a,
-       0xc5, 0x34, 0xf7, 0x8c, 0xf0, 0xd1, 0x4a, 0x17, 0x52, 0x1c, 0x70, 0xf0, 0xe0, 0x53, 0xb4, 0x16,
-       0xde, 0x81, 0xda, 0x2a, 0xa4, 0xf9, 0x5b, 0x0e, 0xa6, 0x17, 0x86, 0x52, 0xc6, 0x70, 0x73, 0xf3,
-       0x3f, 0x1c, 0x87, 0x94, 0xdd, 0xfe, 0x02, 0x0b, 0x85, 0xc9, 0xb9, 0xcf, 0x15, 0x91, 0x05, 0x2e,
-       0x7e, 0xeb, 0xe6, 0xce, 0x0e, 0x4e, 0xd1, 0xf7, 0xe2, 0xd7, 0xf4, 0x60, 0xd2, 0xfc, 0x1d, 0xbf,
-       0xad, 0x61, 0x28, 0xf8, 0x53, 0x31, 0xb3, 0x92, 0xef, 0xa4, 0x05, 0x34, 0x97, 0x57, 0x97, 0x56,
-       0x3b, 0x12, 0x20, 0x2d, 0x88, 0x76, 0x81, 0x0e, 0x77, 0x85, 0xf1, 0x37, 0xc6, 0x19, 0x8b, 0x23,
-       0xc2, 0x42, 0x55, 0x40, 0xc9, 0x91, 0x5c, 0x78, 0xc5, 0xe6, 0x77, 0xfe, 0x72, 0x5f, 0xb2, 0x2c,
-       0x00, 0xf2, 0xe6, 0x8c, 0xcc, 0x02, 0x49, 0xd9, 0x78, 0x20, 0xae, 0xbd, 0x75, 0x61, 0x6a, 0xaa,
-       0xc5, 0x71, 0x3e, 0x5d, 0x02, 0xdf, 0xd2, 0x91, 0x5c, 0x0a, 0x85, 0xc9, 0x59, 0x7d, 0x4e, 0x89,
-       0x21, 0x59, 0x59, 0xe3, 0xc7, 0xdc, 0xff, 0x1e, 0x62, 0x1e, 0xb9, 0x62, 0x2c, 0x34, 0x49, 0x15,
-       0xd9, 0xdf, 0x47, 0x99, 0x39, 0xcc, 0x1a, 0x01, 0xc0, 0xda, 0x48, 0x44, 0xd4, 0x8b, 0xd3, 0x17,
-       0x7e, 0x39, 0xf9, 0x00, 0xe1, 0x2a, 0x46, 0xaa, 0x14, 0x22, 0xa1, 0x38, 0x09, 0x0b, 0xb7, 0x0c,
-       0x88, 0xa5, 0x73, 0xfd, 0xc4, 0x6b, 0xee, 0x07, 0xb4, 0x1b, 0xb3, 0x4a, 0xab, 0xae, 0xf6, 0xe7,
-       0x04, 0x61, 0x4b, 0x34, 0x7a, 0xe4, 0xff, 0xf9, 0x30, 0x28, 0x61, 0x92, 0x52, 0x58, 0x10, 0x15,
-       0x3a, 0x9f, 0x0a, 0xaf, 0x15, 0x29, 0x6c, 0x67, 0xc4, 0xb4, 0xcf, 0xe6, 0xf9, 0x46, 0x68, 0xe2,
-       0x2a, 0x97, 0x29, 0x16, 0xed, 0x1a, 0x9b, 0x9a, 0x45, 0x70, 0x3c, 0xf2, 0xdf, 0x29, 0x20, 0x9e,
-       0x33, 0x4b, 0x5b, 0x8d, 0xf6, 0x19, 0xec, 0x4b, 0xae, 0x1a, 0x2f, 0x53, 0x03, 0x9a, 0xfd, 0x68,
-       0x39, 0x58, 0xf7, 0x2e, 0x07, 0x9c, 0xf1, 0x3c, 0x1b, 0x47, 0x43, 0x19, 0x81, 0x0e, 0x0a, 0xbb,
-       0x84, 0xa0, 0xda, 0x87, 0xbc, 0x8a, 0x2a, 0xb7, 0x9c, 0xe1, 0xf9, 0xeb, 0x37, 0xb0, 0x11, 0x20,
-       0x7e, 0x4c, 0x11, 0x2e, 0x54, 0x30, 0xce, 0xaf, 0x63, 0xed, 0x6a, 0x63, 0x1f, 0x1e, 0x61, 0x62,
-       0x04, 0xf3, 0x3a, 0x5f, 0x26, 0x6c, 0x5c, 0xd7, 0xba, 0x4f, 0xf2, 0x61, 0x26, 0x29, 0x99, 0xea,
-       0x61, 0x84, 0x0d, 0x68, 0xa2, 0x5d, 0x9b, 0x5c, 0xe7, 0x86, 0x1d, 0xef, 0xf4, 0x6f, 0x3b, 0x6c,
-       0x67, 0xf0, 0x70, 0xe9, 0xc5, 0xdc, 0x0a, 0x9d, 0x0f, 0xdc, 0xcc, 0x0e, 0x7b, 0xf8, 0xc4, 0xee,
-       0x64, 0xe4, 0xd9, 0x3f, 0x14, 0xae, 0x8f, 0xc8, 0x18, 0x4d, 0xa1, 0xe4, 0x40, 0x2c, 0xe9, 0x13,
-       0xc6, 0xc1, 0xe0, 0xb9, 0x13, 0xbe, 0xd9, 0x93, 0x66, 0x56, 0x35, 0x5c, 0xc1, 0x38, 0x7d, 0xa1,
-       0xbb, 0x87, 0xa5, 0x90, 0x33, 0x4f, 0xea, 0xb6, 0x37, 0x19, 0x61, 0x81, 0x40, 0xba, 0xd7, 0x07,
-       0x69, 0x05, 0x15, 0x96, 0xe9, 0xde, 0x4f, 0x8a, 0x2b, 0x99, 0x5a, 0x17, 0x3f, 0x9f, 0xcf, 0x86,
-       0xf5, 0x37, 0x0a, 0xa1, 0x0e, 0x25, 0x65, 0x2d, 0x52, 0xce, 0x87, 0x10, 0x0f, 0x25, 0xc2, 0x1e,
-       0x0f, 0x71, 0x93, 0xb5, 0xc0, 0xb3, 0xb4, 0xd1, 0x65, 0xa8, 0xb4, 0xf6, 0xa5, 0x71, 0xad, 0x45,
-       0xdb, 0xdf, 0xec, 0xe3, 0x2a, 0x7e, 0x99, 0x96, 0x5a, 0x5d, 0x69, 0xfa, 0xdb, 0x13, 0x39, 0xb8,
-       0xf5, 0x58, 0xbb, 0x87, 0x69, 0x8d, 0x2c, 0x6d, 0x39, 0xff, 0x26, 0xce, 0x2c, 0xa8, 0x5a, 0x7e,
-       0x4b, 0x3f, 0xed, 0xac, 0x5f, 0xf0, 0xef, 0x48, 0xd3, 0xf8, 0x00, 0x00, 0x31, 0x82, 0x03, 0x28,
-       0x30, 0x82, 0x03, 0x24, 0x02, 0x01, 0x01, 0x30, 0x81, 0x91, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30,
-       0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b,
-       0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20,
-       0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
-       0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b,
-       0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-       0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31,
-       0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
-       0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
-       0x53, 0x02, 0x08, 0x04, 0x2e, 0x97, 0xbb, 0x62, 0x84, 0xd9, 0x1c, 0x30, 0x0d, 0x06, 0x09, 0x60,
-       0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa0, 0x69, 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, 0x33, 0x30, 0x36, 0x32, 0x38, 0x31, 0x37, 0x35,
-       0x35, 0x32, 0x34, 0x5a, 0x30, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09,
-       0x04, 0x31, 0x22, 0x04, 0x20, 0x7f, 0xe5, 0xca, 0xfa, 0x9e, 0x7f, 0xd9, 0x3b, 0xec, 0x98, 0x25,
-       0x4f, 0x65, 0x73, 0x30, 0x1f, 0x7a, 0xe3, 0x51, 0xd3, 0xa4, 0xa9, 0x18, 0x7e, 0xeb, 0x6f, 0xdb,
-       0x13, 0xcb, 0x2f, 0x82, 0x4b, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
-       0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x00, 0x5e, 0xc2, 0x3f, 0x3d, 0x74, 0x0e, 0x23, 0x44,
-       0xec, 0x4f, 0x51, 0x96, 0x08, 0x28, 0x05, 0xe1, 0x2e, 0xd6, 0xba, 0x3a, 0x51, 0xf4, 0x46, 0xff,
-       0x2c, 0x96, 0x4a, 0x05, 0xa0, 0xa1, 0x89, 0xc8, 0x8d, 0x28, 0xb8, 0x1d, 0xc2, 0xc7, 0xa3, 0x6e,
-       0x43, 0x9b, 0xa0, 0xe8, 0xcb, 0x3a, 0x5e, 0xa7, 0xa7, 0xe7, 0x34, 0x93, 0xc9, 0x31, 0xf7, 0xde,
-       0x92, 0x55, 0x95, 0x22, 0x96, 0xdf, 0xbb, 0x6e, 0xb3, 0xb1, 0x8c, 0x20, 0x9f, 0x6f, 0x20, 0x85,
-       0xae, 0x3a, 0x48, 0x69, 0xfe, 0x5d, 0xd9, 0xf0, 0xe9, 0xd1, 0x86, 0x74, 0xc8, 0x13, 0x58, 0x27,
-       0xc6, 0xb5, 0x00, 0x76, 0xa3, 0x75, 0x01, 0x53, 0xfe, 0x8f, 0x7d, 0xe4, 0x69, 0x51, 0x3b, 0x19,
-       0x4b, 0xef, 0x34, 0x6e, 0x33, 0xf1, 0x03, 0x4d, 0xfc, 0x08, 0xd9, 0xe3, 0x47, 0x19, 0x83, 0x83,
-       0xb9, 0xa1, 0x83, 0x14, 0x5a, 0x70, 0x4f, 0xf7, 0x72, 0x2c, 0x00, 0x04, 0xce, 0x3f, 0x5d, 0xf2,
-       0xd3, 0xd8, 0x03, 0x7d, 0xe6, 0xb7, 0xf3, 0xe5, 0x88, 0x44, 0x91, 0x3e, 0x2f, 0x15, 0x51, 0x36,
-       0xbd, 0x16, 0xcb, 0x96, 0xc0, 0xda, 0x33, 0xa5, 0x82, 0x07, 0xc0, 0x6f, 0x20, 0x81, 0x0a, 0x5a,
-       0x14, 0xc9, 0x35, 0xe3, 0xf7, 0x08, 0x7a, 0x10, 0x80, 0x66, 0x08, 0xa5, 0x88, 0x22, 0xf6, 0xab,
-       0x37, 0xbc, 0xc0, 0x75, 0x2c, 0xca, 0xed, 0x5b, 0x83, 0x0c, 0x4b, 0xed, 0x11, 0x05, 0xb1, 0xf9,
-       0x91, 0x2b, 0x2a, 0x3e, 0x0f, 0xa7, 0x1e, 0xfe, 0x68, 0xb9, 0x88, 0x02, 0x0b, 0x51, 0xf2, 0x38,
-       0x3c, 0xc1, 0xb7, 0x56, 0x57, 0x20, 0x7b, 0xcf, 0xfa, 0x19, 0x85, 0x1f, 0x64, 0x2f, 0x55, 0xb8,
-       0xde, 0x80, 0xee, 0x04, 0x99, 0xa9, 0x53, 0x42, 0x15, 0x27, 0x27, 0x22, 0x2e, 0xae, 0xee, 0x98,
-       0x17, 0x3e, 0xd6, 0xcf, 0xc7, 0x1c, 0x8c, 0x1a, 0xb9, 0x6a, 0x0c, 0x34, 0xe7, 0xb2, 0x4f, 0xa3,
-       0x25, 0xbc, 0xe6, 0x12, 0xae, 0x51, 0xe8, 0xa3, 0x25, 0x6f, 0xc7, 0x10, 0x3e, 0xcf, 0x74, 0x7c,
-       0x97, 0x4a, 0x4d, 0xaf, 0xa2, 0x60, 0x9c, 0x99, 0xc7, 0x2a, 0x17, 0x86, 0x13, 0x7b, 0xc6, 0xde,
-       0xf1, 0x72, 0xdd, 0x7d, 0x4a, 0x61, 0xce, 0x08, 0xb1, 0x04, 0x6e, 0xcf, 0xc0, 0x50, 0xfd, 0xe9,
-       0x80, 0x04, 0xed, 0xb9, 0xbf, 0xc6, 0xcd, 0xa1, 0xad, 0xe7, 0x34, 0x8f, 0x31, 0xb2, 0x6e, 0x25,
-       0xba, 0x54, 0x22, 0x23, 0x19, 0x06, 0xe6, 0xea, 0xe7, 0x06, 0x9f, 0x64, 0x44, 0x39, 0x71, 0xc1,
-       0xaa, 0xa6, 0xa4, 0xef, 0xaa, 0xdb, 0x6b, 0x9e, 0xce, 0x29, 0x97, 0x55, 0x2f, 0x06, 0x5c, 0x6c,
-       0x10, 0xe6, 0xa5, 0x8c, 0x30, 0xf6, 0x81, 0x65, 0xee, 0x74, 0xb3, 0x40, 0xaa, 0x3b, 0x70, 0xcb,
-       0x80, 0x50, 0x22, 0x01, 0x0d, 0x12, 0x11, 0x72, 0x6d, 0x10, 0x54, 0x6e, 0xa4, 0x9e, 0x5e, 0xcd,
-       0xcc, 0xa0, 0x30, 0xf8, 0x61, 0xab, 0x36, 0x4a, 0x3a, 0xf0, 0x5a, 0xe3, 0xf5, 0x38, 0x70, 0x05,
-       0xdd, 0x04, 0x2e, 0x2b, 0x3a, 0xf8, 0x9a, 0x39, 0x48, 0x5f, 0x3f, 0xc6, 0x60, 0xaf, 0x9e, 0xca,
-       0x47, 0xb9, 0xfa, 0xb0, 0x1e, 0x45, 0x56, 0x47, 0xe0, 0xf1, 0x00, 0x47, 0x60, 0xb0, 0xca, 0x06,
-       0xef, 0xe8, 0xe9, 0x3b, 0xcd, 0x61, 0x8f, 0xc3, 0x14, 0xbc, 0x61, 0x9b, 0x08, 0x4e, 0xf5, 0x4a,
-       0xf9, 0x9a, 0x35, 0x5f, 0x84, 0x97, 0x43, 0x24, 0x62, 0x60, 0xd2, 0xa7, 0xd7, 0xe6, 0x10, 0xe7,
-       0xf1, 0xe4, 0xd0, 0x96, 0x1f, 0x7c, 0x93, 0xbc, 0x3a, 0x28, 0x59, 0x10, 0x3e, 0x32, 0x71, 0xa4,
-       0x9f, 0xab, 0xf6, 0x30, 0x07, 0xca, 0x7e, 0xcd, 0x35, 0xdb, 0xc1, 0xa2, 0x99, 0x8e, 0x7f, 0x85,
-       0xba, 0x92, 0xf6, 0x76, 0x99, 0xa3, 0xbc, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static const UInt8 kApplePKISettingsRootCACert[] = {
-       0x30, 0x82, 0x07, 0xca, 0x30, 0x82, 0x05, 0xb2, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x4e,
-       0xa1, 0x31, 0xe7, 0xca, 0x50, 0xb8, 0x97, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
-       0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x30, 0x81, 0x84, 0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55,
-       0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65,
-       0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74,
-       0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72,
-       0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70,
-       0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
-       0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06,
-       0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e,
-       0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x30, 0x1e, 0x17,
-       0x0d, 0x31, 0x33, 0x30, 0x36, 0x32, 0x34, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x17, 0x0d,
-       0x34, 0x33, 0x30, 0x36, 0x31, 0x37, 0x32, 0x33, 0x33, 0x33, 0x33, 0x39, 0x5a, 0x30, 0x81, 0x84,
-       0x31, 0x38, 0x30, 0x36, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65,
-       0x20, 0x50, 0x4b, 0x49, 0x20, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x20, 0x52, 0x6f,
-       0x6f, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
-       0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x26, 0x30, 0x24, 0x06, 0x03,
-       0x55, 0x04, 0x0b, 0x0c, 0x1d, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
-       0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69,
-       0x74, 0x79, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0a, 0x41, 0x70, 0x70,
-       0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
-       0x13, 0x02, 0x55, 0x53, 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
-       0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00, 0x30, 0x82, 0x02, 0x0a,
-       0x02, 0x82, 0x02, 0x01, 0x00, 0xce, 0x15, 0xf7, 0x6f, 0xd8, 0x42, 0x0c, 0x6f, 0x45, 0xb4, 0x04,
-       0x59, 0x24, 0xcb, 0x70, 0x88, 0x84, 0x77, 0xa1, 0x91, 0x54, 0xf4, 0x87, 0x61, 0xb3, 0xd3, 0xfc,
-       0xbe, 0xb6, 0x05, 0x3c, 0xb9, 0xb7, 0x7d, 0x7c, 0xbc, 0x0b, 0xe8, 0x87, 0x07, 0xcf, 0x20, 0xbe,
-       0xaa, 0xeb, 0x24, 0xc5, 0xe4, 0x5c, 0xcd, 0xcb, 0x89, 0x9f, 0x7a, 0xea, 0xb4, 0x5d, 0x3b, 0x29,
-       0x6c, 0xba, 0x4d, 0x15, 0xfb, 0x59, 0xd0, 0x5a, 0xea, 0x41, 0x4e, 0x0d, 0x1d, 0xf7, 0x66, 0x77,
-       0xa2, 0x96, 0x56, 0xed, 0xd1, 0x16, 0x7b, 0xea, 0xf5, 0x60, 0xdf, 0x32, 0x9c, 0xa9, 0xfd, 0xbf,
-       0xb8, 0x34, 0x6f, 0x57, 0x17, 0xe6, 0x04, 0x37, 0x71, 0x07, 0xc0, 0xe9, 0x0f, 0x3c, 0xed, 0x4f,
-       0x31, 0x87, 0x05, 0xa4, 0xed, 0xab, 0xac, 0xd6, 0x50, 0x05, 0x5b, 0xca, 0xd3, 0xf9, 0xd6, 0xaa,
-       0xaa, 0x88, 0x57, 0x66, 0xf6, 0x6d, 0x8d, 0x4b, 0x71, 0x29, 0xd4, 0x3d, 0x1d, 0xbc, 0x82, 0x6e,
-       0x81, 0xe9, 0x19, 0xf5, 0xe1, 0x12, 0x9f, 0x47, 0xdb, 0x5c, 0xed, 0x88, 0xba, 0x51, 0xe7, 0x3a,
-       0xa0, 0x77, 0x2d, 0xe6, 0xcc, 0xb4, 0x34, 0xdf, 0xad, 0xbd, 0x7b, 0xf8, 0xa7, 0x79, 0x51, 0x2d,
-       0xe6, 0xc2, 0xee, 0xd2, 0x96, 0xfa, 0x60, 0x60, 0x32, 0x40, 0x41, 0x37, 0x12, 0xeb, 0x63, 0x99,
-       0x3d, 0xf3, 0x21, 0xbe, 0xdf, 0xa1, 0x77, 0xe6, 0x81, 0xa9, 0x99, 0x0c, 0x4b, 0x43, 0x0c, 0x05,
-       0x6a, 0x6b, 0x8f, 0x05, 0x02, 0xd9, 0x43, 0xab, 0x72, 0x76, 0xca, 0xa7, 0x75, 0x63, 0x85, 0xe3,
-       0xa5, 0x5c, 0xc0, 0xd6, 0xd4, 0x1c, 0xeb, 0xac, 0x2c, 0x9a, 0x15, 0x6b, 0x4e, 0x99, 0x74, 0x7d,
-       0xd2, 0x69, 0x9f, 0xa8, 0xf7, 0x65, 0xde, 0xeb, 0x36, 0x85, 0xd5, 0x7e, 0x4a, 0x7a, 0x8a, 0xeb,
-       0x7c, 0xcd, 0x43, 0x9e, 0x05, 0xdb, 0x34, 0xc3, 0x69, 0xbd, 0xc2, 0xe7, 0xfb, 0xa0, 0x43, 0xb3,
-       0xd7, 0x15, 0x28, 0x8a, 0x91, 0xce, 0xd7, 0xa7, 0xa4, 0xcc, 0xf4, 0x1b, 0x37, 0x33, 0x76, 0xc4,
-       0x58, 0xb9, 0x2d, 0x89, 0xe2, 0xb6, 0x2c, 0x56, 0x10, 0x96, 0xcc, 0xa6, 0x07, 0x79, 0x11, 0x7d,
-       0x26, 0xd2, 0x85, 0x22, 0x19, 0x20, 0xb7, 0xef, 0xc3, 0xd9, 0x4e, 0x18, 0xf3, 0xaa, 0x05, 0xce,
-       0x87, 0x99, 0xde, 0x76, 0x90, 0x08, 0x74, 0xac, 0x61, 0x31, 0xf8, 0x51, 0xa0, 0xc9, 0x70, 0xfc,
-       0xb9, 0x22, 0xfe, 0xd2, 0x0d, 0xc8, 0x49, 0x64, 0x00, 0xe4, 0xf1, 0x53, 0xfd, 0xa1, 0xe6, 0xff,
-       0x8e, 0xd6, 0xde, 0x9e, 0xcc, 0x3d, 0x37, 0x3a, 0x10, 0x62, 0x59, 0xb2, 0x34, 0x8a, 0x1d, 0xf7,
-       0x9e, 0xa0, 0xbb, 0xf4, 0x53, 0xd9, 0xb8, 0x18, 0x88, 0x12, 0x5c, 0x92, 0x0d, 0xc9, 0x94, 0x7f,
-       0x24, 0xb9, 0x9f, 0xda, 0x07, 0xb6, 0x79, 0x77, 0x09, 0xa3, 0x29, 0x3a, 0x70, 0x63, 0x3b, 0x22,
-       0x42, 0x14, 0xd0, 0xf9, 0x7b, 0x90, 0x52, 0x2b, 0x3f, 0x7f, 0xb7, 0x41, 0x20, 0x0d, 0x7e, 0x70,
-       0xd7, 0x88, 0x36, 0xa2, 0xe9, 0x81, 0x77, 0xf4, 0xb0, 0x15, 0x43, 0x9c, 0x5f, 0x4d, 0x3e, 0x4f,
-       0x83, 0x79, 0x06, 0x73, 0x7a, 0xe7, 0xcb, 0x79, 0x1d, 0xec, 0xa3, 0xce, 0x93, 0x5c, 0x68, 0xbf,
-       0x5a, 0xe6, 0x4c, 0x23, 0x86, 0x41, 0x7f, 0xb4, 0xfc, 0xd0, 0x2c, 0x1b, 0x64, 0x39, 0x64, 0xb7,
-       0xd2, 0x1d, 0xd0, 0x2d, 0x16, 0x77, 0xfe, 0x4d, 0xad, 0xf0, 0x4f, 0x38, 0xb3, 0xf9, 0x5a, 0xee,
-       0x0e, 0x1d, 0xb6, 0xf9, 0x3f, 0xba, 0x77, 0x5a, 0x20, 0xd2, 0x74, 0x1a, 0x4b, 0x5a, 0xaf, 0x62,
-       0xb5, 0xd3, 0xef, 0x37, 0x49, 0xfe, 0x1e, 0xcd, 0xb5, 0xba, 0xb5, 0xa6, 0x46, 0x7b, 0x38, 0x63,
-       0x62, 0x3c, 0x18, 0x7d, 0x57, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x02, 0x3c, 0x30, 0x82,
-       0x02, 0x38, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x35, 0x07, 0x82,
-       0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f, 0x61, 0xb6,
-       0x1c, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
-       0x01, 0xff, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x35,
-       0x07, 0x82, 0xfe, 0x0e, 0x8f, 0xf5, 0xa0, 0x7c, 0x2e, 0xf9, 0x65, 0x7b, 0xa8, 0x48, 0xe8, 0x8f,
-       0x61, 0xb6, 0x1c, 0x30, 0x82, 0x01, 0xd3, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x82, 0x01, 0xca,
-       0x30, 0x82, 0x01, 0xc6, 0x30, 0x82, 0x01, 0xc2, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x63,
-       0x64, 0x05, 0x01, 0x30, 0x82, 0x01, 0xb3, 0x30, 0x82, 0x01, 0x78, 0x06, 0x08, 0x2b, 0x06, 0x01,
-       0x05, 0x05, 0x07, 0x02, 0x02, 0x30, 0x82, 0x01, 0x6a, 0x1e, 0x82, 0x01, 0x66, 0x00, 0x52, 0x00,
-       0x65, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00,
-       0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x69, 0x00, 0x73, 0x00, 0x20, 0x00,
-       0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
-       0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x62, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00,
-       0x6e, 0x00, 0x79, 0x00, 0x20, 0x00, 0x70, 0x00, 0x61, 0x00, 0x72, 0x00, 0x74, 0x00, 0x79, 0x00,
-       0x20, 0x00, 0x61, 0x00, 0x73, 0x00, 0x73, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x73, 0x00,
-       0x20, 0x00, 0x61, 0x00, 0x63, 0x00, 0x63, 0x00, 0x65, 0x00, 0x70, 0x00, 0x74, 0x00, 0x61, 0x00,
-       0x6e, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x74, 0x00,
-       0x68, 0x00, 0x65, 0x00, 0x20, 0x00, 0x74, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x20, 0x00,
-       0x61, 0x00, 0x70, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x62, 0x00,
-       0x6c, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00,
-       0x61, 0x00, 0x72, 0x00, 0x64, 0x00, 0x20, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x6d, 0x00,
-       0x73, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00, 0x63, 0x00, 0x6f, 0x00,
-       0x6e, 0x00, 0x64, 0x00, 0x69, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x73, 0x00,
-       0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x65, 0x00, 0x2c, 0x00,
-       0x20, 0x00, 0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00,
-       0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x20, 0x00, 0x70, 0x00, 0x6f, 0x00, 0x6c, 0x00,
-       0x69, 0x00, 0x63, 0x00, 0x79, 0x00, 0x20, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x20, 0x00,
-       0x63, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66, 0x00, 0x69, 0x00, 0x63, 0x00,
-       0x61, 0x00, 0x74, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00, 0x70, 0x00, 0x72, 0x00,
-       0x61, 0x00, 0x63, 0x00, 0x74, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x73, 0x00,
-       0x74, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x74, 0x00,
-       0x73, 0x00, 0x2e, 0x30, 0x35, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16,
-       0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c,
-       0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
-       0x65, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
-       0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
-       0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x00, 0x6f, 0x8a,
-       0xb7, 0x35, 0x73, 0x5a, 0xc5, 0x34, 0xf7, 0x8c, 0xf0, 0xd1, 0x4a, 0x17, 0x52, 0x1c, 0x70, 0xf0,
-       0xe0, 0x53, 0xb4, 0x16, 0xde, 0x81, 0xda, 0x2a, 0xa4, 0xf9, 0x5b, 0x0e, 0xa6, 0x17, 0x86, 0x52,
-       0xc6, 0x70, 0x73, 0xf3, 0x3f, 0x1c, 0x87, 0x94, 0xdd, 0xfe, 0x02, 0x0b, 0x85, 0xc9, 0xb9, 0xcf,
-       0x15, 0x91, 0x05, 0x2e, 0x7e, 0xeb, 0xe6, 0xce, 0x0e, 0x4e, 0xd1, 0xf7, 0xe2, 0xd7, 0xf4, 0x60,
-       0xd2, 0xfc, 0x1d, 0xbf, 0xad, 0x61, 0x28, 0xf8, 0x53, 0x31, 0xb3, 0x92, 0xef, 0xa4, 0x05, 0x34,
-       0x97, 0x57, 0x97, 0x56, 0x3b, 0x12, 0x20, 0x2d, 0x88, 0x76, 0x81, 0x0e, 0x77, 0x85, 0xf1, 0x37,
-       0xc6, 0x19, 0x8b, 0x23, 0xc2, 0x42, 0x55, 0x40, 0xc9, 0x91, 0x5c, 0x78, 0xc5, 0xe6, 0x77, 0xfe,
-       0x72, 0x5f, 0xb2, 0x2c, 0x00, 0xf2, 0xe6, 0x8c, 0xcc, 0x02, 0x49, 0xd9, 0x78, 0x20, 0xae, 0xbd,
-       0x75, 0x61, 0x6a, 0xaa, 0xc5, 0x71, 0x3e, 0x5d, 0x02, 0xdf, 0xd2, 0x91, 0x5c, 0x0a, 0x85, 0xc9,
-       0x59, 0x7d, 0x4e, 0x89, 0x21, 0x59, 0x59, 0xe3, 0xc7, 0xdc, 0xff, 0x1e, 0x62, 0x1e, 0xb9, 0x62,
-       0x2c, 0x34, 0x49, 0x15, 0xd9, 0xdf, 0x47, 0x99, 0x39, 0xcc, 0x1a, 0x01, 0xc0, 0xda, 0x48, 0x44,
-       0xd4, 0x8b, 0xd3, 0x17, 0x7e, 0x39, 0xf9, 0x00, 0xe1, 0x2a, 0x46, 0xaa, 0x14, 0x22, 0xa1, 0x38,
-       0x09, 0x0b, 0xb7, 0x0c, 0x88, 0xa5, 0x73, 0xfd, 0xc4, 0x6b, 0xee, 0x07, 0xb4, 0x1b, 0xb3, 0x4a,
-       0xab, 0xae, 0xf6, 0xe7, 0x04, 0x61, 0x4b, 0x34, 0x7a, 0xe4, 0xff, 0xf9, 0x30, 0x28, 0x61, 0x92,
-       0x52, 0x58, 0x10, 0x15, 0x3a, 0x9f, 0x0a, 0xaf, 0x15, 0x29, 0x6c, 0x67, 0xc4, 0xb4, 0xcf, 0xe6,
-       0xf9, 0x46, 0x68, 0xe2, 0x2a, 0x97, 0x29, 0x16, 0xed, 0x1a, 0x9b, 0x9a, 0x45, 0x70, 0x3c, 0xf2,
-       0xdf, 0x29, 0x20, 0x9e, 0x33, 0x4b, 0x5b, 0x8d, 0xf6, 0x19, 0xec, 0x4b, 0xae, 0x1a, 0x2f, 0x53,
-       0x03, 0x9a, 0xfd, 0x68, 0x39, 0x58, 0xf7, 0x2e, 0x07, 0x9c, 0xf1, 0x3c, 0x1b, 0x47, 0x43, 0x19,
-       0x81, 0x0e, 0x0a, 0xbb, 0x84, 0xa0, 0xda, 0x87, 0xbc, 0x8a, 0x2a, 0xb7, 0x9c, 0xe1, 0xf9, 0xeb,
-       0x37, 0xb0, 0x11, 0x20, 0x7e, 0x4c, 0x11, 0x2e, 0x54, 0x30, 0xce, 0xaf, 0x63, 0xed, 0x6a, 0x63,
-       0x1f, 0x1e, 0x61, 0x62, 0x04, 0xf3, 0x3a, 0x5f, 0x26, 0x6c, 0x5c, 0xd7, 0xba, 0x4f, 0xf2, 0x61,
-       0x26, 0x29, 0x99, 0xea, 0x61, 0x84, 0x0d, 0x68, 0xa2, 0x5d, 0x9b, 0x5c, 0xe7, 0x86, 0x1d, 0xef,
-       0xf4, 0x6f, 0x3b, 0x6c, 0x67, 0xf0, 0x70, 0xe9, 0xc5, 0xdc, 0x0a, 0x9d, 0x0f, 0xdc, 0xcc, 0x0e,
-       0x7b, 0xf8, 0xc4, 0xee, 0x64, 0xe4, 0xd9, 0x3f, 0x14, 0xae, 0x8f, 0xc8, 0x18, 0x4d, 0xa1, 0xe4,
-       0x40, 0x2c, 0xe9, 0x13, 0xc6, 0xc1, 0xe0, 0xb9, 0x13, 0xbe, 0xd9, 0x93, 0x66, 0x56, 0x35, 0x5c,
-       0xc1, 0x38, 0x7d, 0xa1, 0xbb, 0x87, 0xa5, 0x90, 0x33, 0x4f, 0xea, 0xb6, 0x37, 0x19, 0x61, 0x81,
-       0x40, 0xba, 0xd7, 0x07, 0x69, 0x05, 0x15, 0x96, 0xe9, 0xde, 0x4f, 0x8a, 0x2b, 0x99, 0x5a, 0x17,
-       0x3f, 0x9f, 0xcf, 0x86, 0xf5, 0x37, 0x0a, 0xa1, 0x0e, 0x25, 0x65, 0x2d, 0x52, 0xce, 0x87, 0x10,
-       0x0f, 0x25, 0xc2, 0x1e, 0x0f, 0x71, 0x93, 0xb5, 0xc0, 0xb3, 0xb4, 0xd1, 0x65, 0xa8, 0xb4, 0xf6,
-       0xa5, 0x71, 0xad, 0x45, 0xdb, 0xdf, 0xec, 0xe3, 0x2a, 0x7e, 0x99, 0x96, 0x5a, 0x5d, 0x69, 0xfa,
-       0xdb, 0x13, 0x39, 0xb8, 0xf5, 0x58, 0xbb, 0x87, 0x69, 0x8d, 0x2c, 0x6d, 0x39, 0xff, 0x26, 0xce,
-       0x2c, 0xa8, 0x5a, 0x7e, 0x4b, 0x3f, 0xed, 0xac, 0x5f, 0xf0, 0xef, 0x48, 0xd3, 0xf8      
-};
-
-static const UInt8 kBasePList[] = {
-       0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd1, 0x01, 0x02, 0x53, 0x66, 0x6f, 0x6f, 0x53,
-       0x62, 0x61, 0x72, 0x08, 0x0b, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x13
-};
-
-static const UInt8 kBaseManifestData[] = {
-       0x3c, 0x3f, 0x78, 0x6d, 0x6c, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31,
-       0x2e, 0x30, 0x22, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x3d, 0x22, 0x55, 0x54,
-       0x46, 0x2d, 0x38, 0x22, 0x3f, 0x3e, 0x0a, 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45,
-       0x20, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x20, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x20, 0x22, 0x2d,
-       0x2f, 0x2f, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x2f, 0x2f, 0x44, 0x54, 0x44, 0x20, 0x50, 0x4c, 0x49,
-       0x53, 0x54, 0x20, 0x31, 0x2e, 0x30, 0x2f, 0x2f, 0x45, 0x4e, 0x22, 0x20, 0x22, 0x68, 0x74, 0x74,
-       0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
-       0x6d, 0x2f, 0x44, 0x54, 0x44, 0x73, 0x2f, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x4c,
-       0x69, 0x73, 0x74, 0x2d, 0x31, 0x2e, 0x30, 0x2e, 0x64, 0x74, 0x64, 0x22, 0x3e, 0x0a, 0x3c, 0x70,
-       0x6c, 0x69, 0x73, 0x74, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x31, 0x2e,
-       0x30, 0x22, 0x3e, 0x0a, 0x3c, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79,
-       0x3e, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x45, 0x53, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
-       0x61, 0x74, 0x65, 0x73, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e,
-       0x0a, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x6c, 0x45, 0x66, 0x55, 0x58, 0x61,
-       0x39, 0x71, 0x54, 0x37, 0x72, 0x45, 0x36, 0x47, 0x73, 0x51, 0x4d, 0x69, 0x6f, 0x33, 0x6b, 0x44,
-       0x78, 0x61, 0x57, 0x35, 0x38, 0x7a, 0x53, 0x46, 0x6e, 0x54, 0x48, 0x66, 0x56, 0x58, 0x6b, 0x4e,
-       0x36, 0x7a, 0x57, 0x2f, 0x59, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a,
-       0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x41, 0x73, 0x73, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69,
-       0x6f, 0x6e, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09,
-       0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x62, 0x4d, 0x73, 0x48, 0x77, 0x57, 0x68, 0x76,
-       0x2b, 0x61, 0x4d, 0x4d, 0x45, 0x74, 0x65, 0x34, 0x34, 0x6c, 0x45, 0x39, 0x34, 0x74, 0x56, 0x44,
-       0x36, 0x37, 0x56, 0x74, 0x67, 0x47, 0x32, 0x4d, 0x79, 0x68, 0x66, 0x56, 0x4d, 0x52, 0x70, 0x6c,
-       0x53, 0x42, 0x55, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x3c,
-       0x6b, 0x65, 0x79, 0x3e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x2e, 0x70, 0x6c, 0x69, 0x73,
-       0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a,
-       0x09, 0x43, 0x49, 0x6b, 0x2f, 0x35, 0x34, 0x50, 0x66, 0x42, 0x32, 0x47, 0x76, 0x5a, 0x56, 0x68,
-       0x6d, 0x7a, 0x6e, 0x53, 0x31, 0x52, 0x6c, 0x62, 0x43, 0x41, 0x7a, 0x56, 0x4b, 0x31, 0x49, 0x69,
-       0x6e, 0x4d, 0x6d, 0x37, 0x64, 0x79, 0x37, 0x6d, 0x31, 0x49, 0x57, 0x77, 0x3d, 0x0a, 0x09, 0x3c,
-       0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x45, 0x56, 0x52,
-       0x6f, 0x6f, 0x74, 0x73, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e,
-       0x0a, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x51, 0x52, 0x45, 0x45, 0x63, 0x63,
-       0x75, 0x62, 0x2b, 0x36, 0x2f, 0x50, 0x62, 0x78, 0x33, 0x75, 0x6a, 0x68, 0x51, 0x38, 0x48, 0x54,
-       0x6c, 0x6b, 0x61, 0x4d, 0x68, 0x49, 0x73, 0x65, 0x36, 0x4b, 0x30, 0x51, 0x56, 0x69, 0x51, 0x45,
-       0x39, 0x35, 0x49, 0x6a, 0x41, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a,
-       0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x47, 0x72, 0x61, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x65, 0x64,
-       0x4b, 0x65, 0x79, 0x73, 0x2e, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e,
-       0x0a, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x70, 0x51, 0x71, 0x4a, 0x4e, 0x2f,
-       0x43, 0x6f, 0x68, 0x79, 0x76, 0x4d, 0x4d, 0x38, 0x46, 0x61, 0x35, 0x74, 0x4d, 0x42, 0x51, 0x34,
-       0x4e, 0x51, 0x6a, 0x55, 0x6d, 0x45, 0x6c, 0x69, 0x4b, 0x76, 0x50, 0x69, 0x59, 0x51, 0x65, 0x49,
-       0x6f, 0x36, 0x44, 0x48, 0x67, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a,
-       0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x4e, 0x75, 0x6d,
-       0x62, 0x65, 0x72, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x69, 0x6e, 0x74, 0x65,
-       0x67, 0x65, 0x72, 0x3e, 0x32, 0x30, 0x31, 0x33, 0x30, 0x36, 0x32, 0x37, 0x30, 0x30, 0x3c, 0x2f,
-       0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63,
-       0x65, 0x72, 0x74, 0x73, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3c, 0x2f,
-       0x6b, 0x65, 0x79, 0x3e, 0x0a, 0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x70, 0x6b,
-       0x77, 0x5a, 0x30, 0x72, 0x6a, 0x6b, 0x76, 0x31, 0x6d, 0x61, 0x61, 0x4f, 0x55, 0x30, 0x43, 0x4d,
-       0x4e, 0x68, 0x6b, 0x66, 0x6b, 0x47, 0x38, 0x52, 0x59, 0x43, 0x48, 0x50, 0x32, 0x76, 0x52, 0x76,
-       0x75, 0x74, 0x78, 0x37, 0x52, 0x58, 0x48, 0x56, 0x51, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61,
-       0x74, 0x61, 0x3e, 0x0a, 0x09, 0x3c, 0x6b, 0x65, 0x79, 0x3e, 0x63, 0x65, 0x72, 0x74, 0x73, 0x54,
-       0x61, 0x62, 0x6c, 0x65, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x3c, 0x2f, 0x6b, 0x65, 0x79, 0x3e, 0x0a,
-       0x09, 0x3c, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x09, 0x4c, 0x71, 0x4e, 0x41, 0x52, 0x47, 0x44,
-       0x62, 0x54, 0x31, 0x45, 0x38, 0x42, 0x69, 0x64, 0x4f, 0x41, 0x48, 0x73, 0x6c, 0x4e, 0x52, 0x4f,
-       0x61, 0x59, 0x63, 0x53, 0x6f, 0x43, 0x71, 0x72, 0x4e, 0x63, 0x4f, 0x64, 0x31, 0x66, 0x6b, 0x31,
-       0x53, 0x75, 0x79, 0x51, 0x3d, 0x0a, 0x09, 0x3c, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x3e, 0x0a, 0x3c,
-       0x2f, 0x64, 0x69, 0x63, 0x74, 0x3e, 0x0a, 0x3c, 0x2f, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x3e, 0x0a
-};
-static void test_OTA_PKI()
-{
-       CFDataRef signed_plist_data = NULL;
-       isnt(signed_plist_data = CFDataCreate(kCFAllocatorDefault, kSignedPList, sizeof(kSignedPList)), 
-               NULL, "create CMS signed message from kSignedPList");
-               
-       SecPolicyRef policy = NULL;
-       SecTrustRef trustRef = NULL;
-       CFDataRef payload = NULL;
-       isnt(policy = SecPolicyCreateOTAPKISigner(), NULL, "create the OTAPKISigner policy");
-       ok_status(SecCMSVerifyCopyDataAndAttributes(signed_plist_data, NULL, policy, &trustRef, &payload, NULL));
-       isnt(payload, NULL, "payload from the CMS message (plist)");
-       isnt(trustRef, NULL, "trustRef from the CMS message (plist)");
-       
-       CFDataRef apple_pki_settings_root_certificate_authority_cert_data = NULL;
-       isnt(apple_pki_settings_root_certificate_authority_cert_data = CFDataCreate(kCFAllocatorDefault, kApplePKISettingsRootCACert, sizeof(kApplePKISettingsRootCACert)), 
-               NULL, "Get the Apple PKI Settings Root Certification Authority Cert Data");
-       
-       SecCertificateRef       apple_pki_settings_root_certificate_authority_cert = NULL;
-       isnt(apple_pki_settings_root_certificate_authority_cert = SecCertificateCreateWithBytes(kCFAllocatorDefault,
-                                                                kApplePKISettingsRootCACert, sizeof(kApplePKISettingsRootCACert)),
-               NULL, "Get the Apple PKI Settings Root Certification Authority Cert");
-    
-       CFArrayRef anchors = CFArrayCreate(kCFAllocatorDefault, (const void **)&apple_pki_settings_root_certificate_authority_cert, 1, &kCFTypeArrayCallBacks);
-       CFReleaseNull(apple_pki_settings_root_certificate_authority_cert);
-       apple_pki_settings_root_certificate_authority_cert = NULL;
-               
-       SecTrustSetAnchorCertificates(trustRef,  anchors);
-               
-       SecTrustResultType trust_result = kSecTrustResultRecoverableTrustFailure;
-    
-    ok_status(SecTrustEvaluate(trustRef, &trust_result), "Evaluate trust of the CMS message (plist)");
-    
-    is_status(trust_result, kSecTrustResultUnspecified, "trust is kSecTrustResultRecoverableTrustFailure (plist)");
-       
-       CFPropertyListFormat plist_format;
-       CFErrorRef error = NULL;
-       CFPropertyListRef propertyRef = NULL;
-       isnt(propertyRef = CFPropertyListCreateWithData(kCFAllocatorDefault, payload, 0, &plist_format, &error), 
-               NULL, "create Plist object from the payload");
-       is(error, NULL, "error returned from CFPropertyListCreateWithData (payload plist)");
-               
-       CFDataRef base_plist_data = NULL;
-       isnt(base_plist_data = CFDataCreate(kCFAllocatorDefault, kBasePList, sizeof(kBasePList)), 
-               NULL, "create base plist data object");
-               
-       CFPropertyListRef base_propertyRef = NULL;
-       isnt(base_propertyRef = CFPropertyListCreateWithData(kCFAllocatorDefault, base_plist_data, 0, &plist_format, &error), 
-               NULL, "create base Plist object from the payload");
-       is(error, NULL, "error returned from CFPropertyListCreateWithData (base plist)");
-               
-       ok(CFEqual(base_propertyRef, propertyRef));     
-       
-       CFReleaseSafe(signed_plist_data);
-       
-       CFReleaseSafe(trustRef);
-       CFReleaseSafe(payload);
-       CFReleaseSafe(propertyRef);
-       CFReleaseSafe(base_plist_data);
-       CFReleaseSafe(base_propertyRef);        
-       
-       // Now do this same test with a 'real' manifest file
-       CFDataRef signed_manifest_data = NULL;
-       isnt(signed_manifest_data = CFDataCreate(kCFAllocatorDefault, kSignedManifestData, sizeof(kSignedManifestData)), 
-               NULL, "create CMS signed message from kSignedManifestData");
-       
-       trustRef = NULL;
-       payload = NULL;
-       
-       ok_status(SecCMSVerifyCopyDataAndAttributes(signed_manifest_data, NULL, policy, &trustRef, &payload, NULL));
-    CFReleaseSafe(signed_manifest_data);
-       isnt(payload, NULL, "payload from the CMS message (manifest)");
-       isnt(trustRef, NULL, "trustRef from the CMS message (manifest)");
-       SecTrustSetAnchorCertificates(trustRef,  anchors);
-       trust_result = kSecTrustResultRecoverableTrustFailure;
-       
-       ok_status(SecTrustEvaluate(trustRef, &trust_result), "Evaluate trust of the CMS message (plist)");
-    
-    is_status(trust_result, kSecTrustResultUnspecified, "trust is kSecTrustResultRecoverableTrustFailure (plist)");
-
-       CFPropertyListRef manifestRef = NULL;
-               
-       isnt(manifestRef = CFPropertyListCreateWithData(kCFAllocatorDefault, payload, 0, &plist_format, &error), 
-               NULL, "create manifest plist object from the payload"); 
-       is(error, NULL, "error returned from CFPropertyListCreateWithData (manifest plist)");
-       
-       CFDataRef base_manifest_data = NULL;
-       isnt(base_manifest_data = CFDataCreate(kCFAllocatorDefault, kBaseManifestData, sizeof(kBaseManifestData)), 
-               NULL, "create base manifest data object");
-               
-       CFPropertyListRef base_manifestRef = NULL;
-       isnt(base_manifestRef = CFPropertyListCreateWithData(kCFAllocatorDefault, base_manifest_data, 0, &plist_format, &error), 
-               NULL, "create base manifest object from the payload");
-       is(error, NULL, "error returned from CFPropertyListCreateWithData (manifest plist)");
-       
-       ok(CFEqual(base_manifestRef, manifestRef));     
-               
-       CFReleaseSafe(policy);
-       CFReleaseSafe(trustRef);
-       CFReleaseSafe(payload);
-       CFReleaseSafe(manifestRef);
-       CFReleaseSafe(base_manifest_data);
-       CFReleaseSafe(base_manifestRef);
-    CFReleaseSafe(anchors);
-    CFReleaseSafe(apple_pki_settings_root_certificate_authority_cert_data);
-       
-}
-
-static void tests(void)
-{
-    test_OTA_PKI();
-}
-
-int si_74_OTA_PKI_Signer(int argc, char *const *argv)
-{
-       
-//#if defined(NO_SERVER) && NO_SERVER == 1
-       plan_tests(27);
-
-       tests();
-//#endif
-
-       return 0;
-}
-
index 1863bf1f3503fb14b431a8b9102734e7c3ae793d..0ec84b4c793678c11bf48e52521383c364550581 100644 (file)
@@ -10,6 +10,7 @@
 #include <Security/SecBase.h>
 #include <utilities/array_size.h>
 #include <utilities/SecCFWrappers.h>
+#include <os/feature_private.h>
 
 #include "Security_regressions.h"
 
@@ -20,7 +21,11 @@ static void tests(void) {
     CFDictionaryAddValue(dict, kSecAttrAccessGroup, kSecAttrAccessGroupToken);
 
     is_status(SecItemAdd(dict, NULL), errSecMissingEntitlement);
-    is_status(SecItemCopyMatching(dict, NULL), errSecItemNotFound);
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        is_status(SecItemCopyMatching(dict, NULL), errSecItemNotFound);
+    } else {
+        is_status(SecItemCopyMatching(dict, NULL), errSecMissingEntitlement);
+    }
 
     CFRelease(dict);
 }
diff --git a/OSX/sec/Security/Regressions/secitem/si-84-sectrust-allowlist.m b/OSX/sec/Security/Regressions/secitem/si-84-sectrust-allowlist.m
deleted file mode 100644 (file)
index ab4ed0e..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-/*
- *  si-84-sectrust-allowlist.c
- *  Security
- *
- * Copyright (c) 2015-2017 Apple Inc. All Rights Reserved.
- */
-
-#include <AssertMacros.h>
-#import <Foundation/Foundation.h>
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecPolicyPriv.h>
-#include <utilities/SecCFRelease.h>
-#include <AssertMacros.h>
-
-#include "shared_regressions.h"
-
-#include "si-84-sectrust-allowlist/cnnic_certs.h"
-#include "si-84-sectrust-allowlist/wosign_certs.h"
-#include "si-84-sectrust-allowlist/date_testing_certs.h"
-
-/* Define this symbol for testing updated allowlist workaround. */
-#define RADAR_32792206 1
-
-
-static SecCertificateRef createCertFromStaticData(const UInt8 *certData, CFIndex certLength)
-{
-    SecCertificateRef cert = NULL;
-    CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, certData, certLength, kCFAllocatorNull);
-    if (data) {
-        cert = SecCertificateCreateWithData(NULL, data);
-        CFRelease(data);
-    }
-    return cert;
-}
-
-static void TestLeafOnAllowList()
-{
-    SecCertificateRef certs[4];
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    CFDateRef date = NULL;
-    CFArrayRef certArray = NULL;
-    CFArrayRef anchorsArray = NULL;
-
-    isnt(certs[0] = createCertFromStaticData(leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)),
-         NULL, "allowlist: create leaf cert");
-    isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
-         NULL, "allowlist: create intermediate ca 1");
-    isnt(certs[2] = createCertFromStaticData(ca2_Cert, sizeof(ca2_Cert)),
-         NULL, "allowlist: create intermediate ca 2");
-    isnt(certs[3] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
-         NULL, "allowlist: create root");
-
-    isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 4, &kCFTypeArrayCallBacks),
-         NULL, "allowlist: create cert array");
-
-    /* create a trust reference with ssl policy */
-    isnt(policy = SecPolicyCreateSSL(true, CFSTR("telegram.im")), NULL, "allowlist: create policy");
-    ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "allowlist: create trust");
-
-    /* set evaluate date: September 12, 2016 at 1:30:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "allowlist: create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "allowlist: set verify date");
-
-    /* use a known root CA at this point in time to anchor the chain */
-    isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[3], 1, &kCFTypeArrayCallBacks),
-         NULL, "allowlist: create anchors array");
-    ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "allowlist: set anchors");
-
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-    ok_status(SecTrustEvaluate(trust, &trustResult), "allowlist: evaluate");
-
-#if 0
-    /* expected result is kSecTrustResultUnspecified since cert is on allow list and its issuer chains to a trusted root */
-    ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
-       (int)trustResult);
-#else
-    #if RADAR_32792206
-    /* this certificate was on the allow list prior to v5, and list hasn't yet updated. */
-    if (trustResult == kSecTrustResultUnspecified) {
-        trustResult = kSecTrustResultRecoverableTrustFailure;
-    }
-    #endif
-    /* this certificate is no longer on the allow list: <rdar://32792206> */
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-       or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-
-    /* clean up */
-    for(CFIndex idx=0; idx < 4; idx++) {
-        if (certs[idx]) { CFRelease(certs[idx]); }
-    }
-    if (policy) { CFRelease(policy); }
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-    if (certArray) { CFRelease(certArray); }
-    if (anchorsArray) { CFRelease(anchorsArray); }
-}
-
-static void TestLeafNotOnAllowList()
-{
-    SecCertificateRef certs[4];
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    CFDateRef date = NULL;
-    CFArrayRef certArray = NULL;
-    CFArrayRef anchorsArray = NULL;
-
-    isnt(certs[0] = createCertFromStaticData(leafNotOnAllowList_Cert, sizeof(leafNotOnAllowList_Cert)),
-         NULL, "!allowlist: create leaf cert");
-    isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
-         NULL, "!allowlist: create intermediate ca 1");
-    isnt(certs[2] = createCertFromStaticData(ca2_Cert, sizeof(ca2_Cert)),
-         NULL, "!allowlist: create intermediate ca 2");
-    isnt(certs[3] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
-         NULL, "!allowlist: create root");
-
-    isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 4, &kCFTypeArrayCallBacks),
-         NULL, "!allowlist: create cert array");
-
-    /* create a trust reference with basic policy */
-    isnt(policy = SecPolicyCreateBasicX509(), NULL, "!allowlist: create policy");
-    ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "!allowlist: create trust");
-
-    /* set evaluate date: September 7, 2016 at 9:00:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495000000.0), NULL, "!allowlist: create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "!allowlist: set verify date");
-
-    /* use a known root CA at this point in time to anchor the chain */
-    isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[3], 1, &kCFTypeArrayCallBacks),
-         NULL, "allowlist: create anchors array");
-    ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "!allowlist: set anchors");
-
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-    ok_status(SecTrustEvaluate(trust, &trustResult), "!allowlist: evaluate");
-
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-
-    /* clean up */
-    for(CFIndex idx=0; idx < 4; idx++) {
-        if (certs[idx]) { CFRelease(certs[idx]); }
-    }
-    if (policy) { CFRelease(policy); }
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-    if (certArray) { CFRelease(certArray); }
-    if (anchorsArray) { CFRelease(anchorsArray); }
-}
-
-static void TestAllowListForRootCA(void)
-{
-    SecCertificateRef test0[2] = {NULL,NULL};
-    SecCertificateRef test1[2] = {NULL,NULL};
-    SecCertificateRef test1e[2] = {NULL,NULL};
-    SecCertificateRef test2[2] = {NULL,NULL};
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    CFDateRef date = NULL;
-    SecTrustResultType trustResult;
-
-    isnt(test0[0] = createCertFromStaticData(cert0, sizeof(cert0)),
-            NULL, "create first leaf");
-    isnt(test1[0] = createCertFromStaticData(cert1, sizeof(cert1)),
-         NULL, "create second leaf");
-    isnt(test1e[0] = createCertFromStaticData(cert1_expired, sizeof(cert1_expired)),
-         NULL, "create second leaf (expired)");
-    isnt(test2[0] = createCertFromStaticData(cert2, sizeof(cert2)),
-         NULL, "create third leaf");
-
-    isnt(test0[1] = createCertFromStaticData(intermediate0, sizeof(intermediate0)),
-         NULL, "create intermediate");
-    isnt(test1[1] = createCertFromStaticData(intermediate1, sizeof(intermediate1)),
-         NULL, "create intermediate");
-    isnt(test1e[1] = createCertFromStaticData(intermediate1, sizeof(intermediate1)),
-         NULL, "create intermediate");
-    isnt(test2[1] = createCertFromStaticData(intermediate2, sizeof(intermediate2)),
-         NULL, "create intermediate");
-
-    CFArrayRef certs0 = CFArrayCreate(kCFAllocatorDefault, (const void **)test0, 2, &kCFTypeArrayCallBacks);
-    CFArrayRef certs1 = CFArrayCreate(kCFAllocatorDefault, (const void **)test1, 2, &kCFTypeArrayCallBacks);
-    CFArrayRef certs1e = CFArrayCreate(kCFAllocatorDefault, (const void **)test1e, 2, &kCFTypeArrayCallBacks);
-    CFArrayRef certs2 = CFArrayCreate(kCFAllocatorDefault, (const void **)test2, 2, &kCFTypeArrayCallBacks);
-
-    /*
-     * Allowlisted certificates issued by untrusted root CA.
-     */
-    isnt(policy = SecPolicyCreateBasicX509(), NULL, "create policy");
-    ok_status(SecTrustCreateWithCertificates(certs0, policy, &trust), "create trust");
-    /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-#if 0
-    /* successful trust result expected since this is on the allow list */
-    ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
-       (int)trustResult);
-#else
-    #if RADAR_32792206
-    /* this certificate was on the allow list prior to v5, and list hasn't yet updated. */
-    if (trustResult == kSecTrustResultUnspecified) {
-        trustResult = kSecTrustResultRecoverableTrustFailure;
-    }
-    #endif
-    /* this certificate is no longer on the allow list: <rdar://32792206> */
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-
-    ok_status(SecTrustCreateWithCertificates(certs1, policy, &trust), "create trust");
-    /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-#if 0
-    /* Note: this certificate has expired and was removed from the allowlist,
-       so we currently expect a revoked trust failure despite the verify date. */
-    ok(trustResult == kSecTrustResultFatalTrustFailure, "trustResult 6 expected (got %d)",
-       (int)trustResult);
-#else
-    /* there is no longer an allowlist: <rdar://32792206> */
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-
-    ok_status(SecTrustCreateWithCertificates(certs2, policy, &trust), "create trust");
-    /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-#if 0
-    /* successful trust result expected since this is on the allow list */
-    ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
-       (int)trustResult);
-#else
-    #if RADAR_32792206
-    /* this certificate was on the allow list prior to v5, and list hasn't yet updated. */
-    if (trustResult == kSecTrustResultUnspecified) {
-        trustResult = kSecTrustResultRecoverableTrustFailure;
-    }
-    #endif
-    /* this certificate is no longer on the allow list: <rdar://32792206> */
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-
-    /*
-     * Same certificate, on allow list but past expiration. Expect to fail.
-     */
-    if (date) { CFRelease(date); }
-    isnt(date = CFDateCreate(NULL, 667680000.0), NULL, "create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set date to far future so certs are expired");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-#if 0
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure, "trustResult 5 expected (got %d)",
-       (int)trustResult);
-#else
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-
-    /*
-     * Expired certificate not on allow list. Expect to fail.
-     */
-    ok_status(SecTrustCreateWithCertificates(certs1e, policy, &trust), "create trust");
-    /* set evaluate date within validity range: September 12, 2016 at 1:30:00 PM PDT */
-    isnt(date = CFDateCreate(NULL, 495405000.0), NULL, "create date");
-    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "set verify date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-#if 0
-    /* Note: because this certificate is not on the allow list, and the allow list is complete,
-       we now expect it to be treated as revoked regardless of expiration status. */
-    ok(trustResult == kSecTrustResultFatalTrustFailure, "trustResult 6 expected (got %d)",
-       (int)trustResult);
-#else
-    /* there is no longer an allowlist: <rdar://32792206> */
-    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
-     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure ||
-       trustResult == kSecTrustResultFatalTrustFailure,
-       "trustResult 5 or 6 expected (got %d)", (int)trustResult);
-#endif
-    if (trust) { CFRelease(trust); }
-    if (date) { CFRelease(date); }
-
-
-    /* Clean up. */
-    if (policy) { CFRelease(policy); }
-    if (certs0) { CFRelease(certs0); }
-    if (certs1) { CFRelease(certs1); }
-    if (certs1e) { CFRelease(certs1e); }
-    if (certs2) { CFRelease(certs2); }
-
-    if (test0[0]) { CFRelease(test0[0]); }
-    if (test0[1]) { CFRelease(test0[1]); }
-    if (test1[0]) { CFRelease(test1[0]); }
-    if (test1[1]) { CFRelease(test1[1]); }
-    if (test1e[0]) { CFRelease(test1e[0]); }
-    if (test1e[1]) { CFRelease(test1e[1]); }
-    if (test2[0]) { CFRelease(test2[0]); }
-    if (test2[1]) { CFRelease(test2[1]); }
-}
-
-static void TestDateBasedAllowListForRootCA(void) {
-    SecCertificateRef root = NULL, beforeInt = NULL, afterInt = NULL,
-    beforeLeaf = NULL, afterLeaf = NULL;
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    NSArray *anchors = nil, *certs = nil;
-    NSDate *verifyDate = nil;
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-
-    require(root = SecCertificateCreateWithBytes(NULL, _datetest_root, sizeof(_datetest_root)), out);
-    require(beforeInt = SecCertificateCreateWithBytes(NULL, _datetest_before_int, sizeof(_datetest_before_int)), out);
-    require(afterInt = SecCertificateCreateWithBytes(NULL, _datetest_after_int, sizeof(_datetest_after_int)), out);
-    require(beforeLeaf = SecCertificateCreateWithBytes(NULL, _datetest_before_leaf, sizeof(_datetest_before_leaf)), out);
-    require(afterLeaf = SecCertificateCreateWithBytes(NULL, _datetest_after_leaf, sizeof(_datetest_after_leaf)), out);
-
-    anchors = @[(__bridge id)root];
-    require(policy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com")), out);
-    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:504000000.0];  /* 21 Dec 2016 */
-
-    /* Leaf issued before cutoff should pass */
-    certs = @[(__bridge id)beforeLeaf, (__bridge id)beforeInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation");
-    CFReleaseNull(trust);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Leaf issued after cutoff should fail */
-    certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation");
-    CFReleaseNull(trust);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Intermediate issued after cutoff should fail (even for leaf issued before) */
-    certs = @[(__bridge id)beforeLeaf, (__bridge id)afterInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued after cutoff succeeded evaluation");
-    CFReleaseNull(trust);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Intermediate issued after cutoff should fail */
-    certs = @[(__bridge id)afterLeaf, (__bridge id)afterInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued before cutoff succeeded evaluation");
-    CFReleaseNull(trust);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Leaf issued before cutoff should choose acceptable path */
-    certs = @[(__bridge id)beforeLeaf, (__bridge id) afterInt, (__bridge id)beforeInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation (multi-path)");
-    CFReleaseNull(trust);
-    trustResult = kSecTrustResultInvalid;
-
-    /* No good path for leaf issued after cutoff */
-    certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt, (__bridge id)afterInt];
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation (multi-path)");
-
-out:
-    CFReleaseNull(root);
-    CFReleaseNull(beforeInt);
-    CFReleaseNull(afterInt);
-    CFReleaseNull(beforeLeaf);
-    CFReleaseNull(afterLeaf);
-    CFReleaseNull(policy);
-    CFReleaseNull(trust);
-}
-
-static void TestLeafOnAllowListOtherFailures(void)
-{
-    SecCertificateRef certs[4];
-    SecPolicyRef policy = NULL;
-    SecTrustRef trust = NULL;
-    NSArray *anchors = nil, *certArray = nil;
-    NSDate *verifyDate = nil;
-    SecTrustResultType trustResult = kSecTrustResultInvalid;
-
-    memset(certs, 0, 4 * sizeof(SecCertificateRef));
-
-    require(certs[0] = SecCertificateCreateWithBytes(NULL, leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)), out);
-    require(certs[1] = SecCertificateCreateWithBytes(NULL, ca1_Cert, sizeof(ca1_Cert)), out);
-    require(certs[2] = SecCertificateCreateWithBytes(NULL, ca2_Cert, sizeof(ca2_Cert)), out);
-    require(certs[3] = SecCertificateCreateWithBytes(NULL, root_Cert, sizeof(root_Cert)), out);
-
-    anchors = @[(__bridge id)certs[3]];
-    certArray = @[(__bridge id)certs[0], (__bridge id)certs[1], (__bridge id)certs[2], (__bridge id)certs[3]];
-    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:495405000.0];
-
-    /* Mismatched hostname, should fail */
-    require(policy = SecPolicyCreateSSL(true, (__bridge CFStringRef)@"wrong.hostname.com"), out);
-    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certArray, policy, &trust), out);
-    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
-    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
-       "hostname failure with cert on allow list succeeded evaluation");
-    CFReleaseNull(policy);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Wrong EKU, should fail */
-    require(policy = SecPolicyCreateCodeSigning(), out);
-    require_noerr(SecTrustSetPolicies(trust, policy), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
-       "EKU failure with cert on allow list succeeded evaluation");
-    CFReleaseNull(policy);
-    trustResult = kSecTrustResultInvalid;
-
-    /* Apple pinning policy, should fail */
-    require(policy = SecPolicyCreateAppleSSLPinned((__bridge CFStringRef)@"aPolicy",
-                                                   (__bridge CFStringRef)@"telegram.im", NULL,
-                                                   (__bridge CFStringRef)@"1.2.840.113635.100.6.27.12"), out);
-    require_noerr(SecTrustSetPolicies(trust, policy), out);
-    require_noerr(SecTrustEvaluate(trust, &trustResult), out);
-    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
-       "Apple pinning policy with cert on allow list succeeded evaluation");
-
-    out:
-    CFReleaseNull(certs[0]);
-    CFReleaseNull(certs[1]);
-    CFReleaseNull(certs[2]);
-    CFReleaseNull(certs[3]);
-    CFReleaseNull(policy);
-    CFReleaseNull(trust);
-}
-
-static void tests(void)
-{
-    TestAllowListForRootCA();
-    TestLeafOnAllowList();
-    TestLeafNotOnAllowList();
-    TestDateBasedAllowListForRootCA();
-    TestLeafOnAllowListOtherFailures();
-}
-
-int si_84_sectrust_allowlist(int argc, char *const *argv)
-{
-    plan_tests(68);
-    tests();
-
-    return 0;
-}
index 6aed79c3f434ad3dbb5c685365eb6998a5cf2fca..285e7ff34b4b2569493d24d7a082e84330f90c75 100644 (file)
@@ -368,7 +368,7 @@ static void sign_tests(SecIdentityRef identity, bool isRSA) {
     is(sign_please(identity, SEC_OID_SHA1, false, (isRSA) ? rsa_sha1 : NULL,
                    (isRSA) ? sizeof(rsa_sha1) : 0),
        errSecSuccess, "Signed with SHA-1");
-    is(sign_please(identity, SEC_OID_SHA256, false, (isRSA) ? rsa_sha256 : NULL,
+    is(sign_please(identity, SEC_OID_SHA256, false, (isRSA) ? new_sig_alg_rsa_sha256 : NULL,
                    (isRSA) ? sizeof(rsa_sha256) : 0),
        errSecSuccess, "Signed with SHA-256");
     is(sign_please(identity, SEC_OID_SHA384, false, NULL, 0), errSecSuccess, "Signed with SHA-384");
index 371b8f69bdf8d5fa2effe8371f7239003c0131b3..c7ad36b937ead3900c51b941ecc247ef98919e7c 100644 (file)
@@ -465,7 +465,7 @@ unsigned char rsa_sha1[] = {
     0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
     0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65,
     0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
-    0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00,
+    0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00,
     0x29, 0xbb, 0xc2, 0xc1, 0x17, 0xb9, 0x7d, 0x8b, 0x43, 0xc6, 0x25, 0xad, 0xf1, 0xae, 0xb6, 0x26, 0x78, 0x9c, 0x92, 0x47,
     0x77, 0xf8, 0xac, 0x53, 0xca, 0x17, 0x58, 0x4a, 0x8d, 0x66, 0x44, 0x99, 0x14, 0x3f, 0x63, 0x98, 0x3a, 0x7c, 0xe6, 0x65,
     0xf0, 0x2a, 0x5e, 0x49, 0xbe, 0xdd, 0x40, 0x6e, 0x21, 0x43, 0xe1, 0xb9, 0x13, 0xa8, 0x31, 0xbf, 0x12, 0xb2, 0x78, 0x97,
@@ -565,6 +565,89 @@ unsigned char rsa_sha256[] = {
     0x45, 0xc2, 0x99, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
+unsigned char new_sig_alg_rsa_sha256[] = {
+    0x30, 0x80, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01,
+    0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x80, 0x06,
+    0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x80, 0x24, 0x80, 0x04, 0x29, 0x54, 0x68, 0x69, 0x73,
+    0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x69, 0x73, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x2e, 0x20,
+    0x41, 0x69, 0x6e, 0x27, 0x74, 0x20, 0x69, 0x74, 0x20, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x3f, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0xa0, 0x82, 0x03, 0xe5, 0x30, 0x82, 0x03, 0xe1, 0x30, 0x82, 0x02, 0xc9, 0xa0, 0x03, 0x02, 0x01, 0x02,
+    0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
+    0x00, 0x30, 0x81, 0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53, 0x20, 0x52,
+    0x53, 0x41, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+    0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70, 0x70, 0x6c,
+    0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25, 0x53, 0x65,
+    0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61,
+    0x6e, 0x64, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06,
+    0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f,
+    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d,
+    0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31,
+    0x34, 0x30, 0x30, 0x31, 0x38, 0x32, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x34, 0x31, 0x33, 0x30, 0x30, 0x31, 0x38,
+    0x32, 0x39, 0x5a, 0x30, 0x81, 0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53,
+    0x20, 0x52, 0x53, 0x41, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
+    0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70,
+    0x70, 0x6c, 0x65, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25,
+    0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
+    0x20, 0x61, 0x6e, 0x64, 0x20, 0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30,
+    0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21,
+    0x30, 0x1f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e,
+    0x61, 0x6d, 0x65, 0x40, 0x61, 0x70, 0x70, 0x6c, 0x65, 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, 0xe2, 0x9b, 0xcb, 0x6c, 0x77, 0xb7, 0xd1, 0x05, 0xa0, 0xae, 0x86, 0x20, 0x45, 0xd3,
+    0xf4, 0x24, 0x8d, 0x25, 0x34, 0x31, 0xa9, 0xe2, 0x10, 0x36, 0xf5, 0x0a, 0x0b, 0x90, 0x4a, 0xa5, 0x6b, 0x5c, 0x16, 0xcd,
+    0xb0, 0x72, 0xe9, 0xa9, 0x80, 0x5f, 0x6d, 0xb2, 0x4d, 0xd9, 0x58, 0x16, 0x9f, 0x68, 0x81, 0x9a, 0x6b, 0xeb, 0xd5, 0x4b,
+    0xf7, 0x7d, 0x59, 0xe9, 0x46, 0x2b, 0x5b, 0x8f, 0xe4, 0xec, 0xab, 0x5c, 0x07, 0x74, 0xa2, 0x0e, 0x59, 0xbb, 0xfc, 0xd3,
+    0xcf, 0xf7, 0x21, 0x88, 0x6c, 0x88, 0xd9, 0x6b, 0xa3, 0xa3, 0x4e, 0x5b, 0xd1, 0x1c, 0xfb, 0x04, 0xf5, 0xb2, 0x12, 0x0e,
+    0x54, 0x59, 0x4d, 0xce, 0x0a, 0xe0, 0x26, 0x24, 0x06, 0xeb, 0xc8, 0xa2, 0xc6, 0x41, 0x28, 0xf9, 0x79, 0xe4, 0xb1, 0x4e,
+    0x00, 0x6f, 0x6e, 0xf8, 0x96, 0x9e, 0x45, 0x28, 0x70, 0xec, 0xc7, 0xdc, 0xa2, 0xdd, 0x92, 0xab, 0xdd, 0x6f, 0xd8, 0x57,
+    0xba, 0xcc, 0x29, 0xbe, 0xb7, 0x00, 0x1e, 0x8d, 0x13, 0x3f, 0x47, 0x34, 0x3c, 0xd0, 0xc6, 0xc8, 0x17, 0xdf, 0x74, 0x8a,
+    0xb1, 0xc3, 0x68, 0xd5, 0xba, 0x76, 0x60, 0x55, 0x5f, 0x8d, 0xfa, 0xbd, 0xe7, 0x11, 0x9e, 0x59, 0x96, 0xe5, 0x93, 0x70,
+    0xad, 0x41, 0xfb, 0x61, 0x46, 0x70, 0xc4, 0x05, 0x12, 0x23, 0x23, 0xc0, 0x9d, 0xc8, 0xc5, 0xf5, 0x96, 0xe5, 0x48, 0x10,
+    0x86, 0x8a, 0x1e, 0x3b, 0x83, 0xd1, 0x47, 0x3a, 0x27, 0x00, 0x71, 0x10, 0xa3, 0x52, 0xba, 0xae, 0x01, 0x43, 0x87, 0x9c,
+    0x6a, 0x1b, 0xea, 0x1a, 0x44, 0x4f, 0x4a, 0xac, 0xd4, 0x82, 0x55, 0xee, 0x1f, 0x25, 0x9c, 0x55, 0xca, 0xd2, 0xd0, 0x3a,
+    0x0b, 0x70, 0x90, 0x60, 0x49, 0x47, 0x02, 0xfd, 0x89, 0x2c, 0x9a, 0x26, 0x36, 0x34, 0x8f, 0x24, 0x39, 0x8c, 0xe9, 0xa2,
+    0x52, 0x8f, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x13, 0x30, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
+    0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
+    0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4c, 0xed, 0x5b, 0xaf, 0x13, 0x16, 0x5d, 0xe2, 0xdd, 0x5c, 0x48, 0x1c,
+    0xd5, 0x6e, 0x8b, 0x04, 0x51, 0xd6, 0x38, 0x80, 0xfd, 0x52, 0x4a, 0x34, 0xdc, 0x13, 0x35, 0x6e, 0x64, 0x39, 0x39, 0x39,
+    0x09, 0xa7, 0x6c, 0x2d, 0x39, 0xf2, 0x04, 0x21, 0xe3, 0xea, 0x8f, 0xf8, 0xbe, 0x46, 0x0e, 0x20, 0x82, 0xd0, 0xc5, 0x60,
+    0xbf, 0x57, 0x6f, 0xd8, 0x29, 0xb4, 0x66, 0xdb, 0xbf, 0x92, 0xc9, 0xdc, 0x90, 0x97, 0x0f, 0x2f, 0x59, 0xa0, 0x13, 0xf3,
+    0xa4, 0xca, 0xde, 0x3f, 0x80, 0x2a, 0x99, 0xb4, 0xee, 0x71, 0xc3, 0x56, 0x71, 0x51, 0x37, 0x55, 0xa1, 0x60, 0x89, 0xab,
+    0x94, 0x0e, 0xb9, 0x70, 0xa5, 0x55, 0xf3, 0x1a, 0x87, 0xa4, 0x41, 0x4c, 0x45, 0xba, 0xb6, 0x56, 0xd6, 0x45, 0x56, 0x12,
+    0x60, 0xe5, 0x91, 0xec, 0xf7, 0xbe, 0x39, 0xa4, 0x80, 0x08, 0x9f, 0xea, 0x17, 0x12, 0x0e, 0xa6, 0xe6, 0xef, 0x09, 0xf7,
+    0x61, 0x51, 0x57, 0x73, 0xe3, 0x57, 0x88, 0xd7, 0xf8, 0x5f, 0xaf, 0x5d, 0xaf, 0x88, 0x32, 0xb4, 0x09, 0x3e, 0x7c, 0x25,
+    0x77, 0x35, 0xe9, 0x3e, 0x6e, 0x0a, 0xb9, 0xb4, 0xa3, 0x06, 0x07, 0x0f, 0x7e, 0x93, 0x26, 0x16, 0x38, 0x1e, 0x4e, 0x72,
+    0xaf, 0x06, 0x44, 0x1e, 0x8d, 0x96, 0xa6, 0x15, 0x9c, 0x82, 0x6d, 0x71, 0x99, 0x84, 0x8d, 0x12, 0x46, 0xf2, 0xbb, 0xa7,
+    0x63, 0x7a, 0x32, 0xda, 0xa9, 0xde, 0xb6, 0x34, 0x14, 0xfb, 0x07, 0x0c, 0xab, 0x3b, 0x0a, 0xa1, 0x8b, 0xda, 0x15, 0xb3,
+    0x63, 0xf3, 0x5c, 0x45, 0x2f, 0x0b, 0x6e, 0xc7, 0x27, 0x72, 0xc1, 0x37, 0x56, 0x30, 0xe3, 0x26, 0xbb, 0x19, 0x4f, 0x91,
+    0xa1, 0xd0, 0x30, 0x29, 0x5b, 0x79, 0x79, 0x5c, 0xe6, 0x4f, 0xed, 0xcf, 0x81, 0xb2, 0x50, 0x35, 0x96, 0x23, 0xb2, 0x9f,
+    0xca, 0x3f, 0xb5, 0x54, 0x31, 0x82, 0x01, 0xdc, 0x30, 0x82, 0x01, 0xd8, 0x02, 0x01, 0x01, 0x30, 0x81, 0xb0, 0x30, 0x81,
+    0xa7, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x11, 0x43, 0x4d, 0x53, 0x20, 0x52, 0x53, 0x41, 0x20,
+    0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02,
+    0x55, 0x53, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0b, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x2c, 0x20,
+    0x49, 0x6e, 0x63, 0x2e, 0x31, 0x2e, 0x30, 0x2c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x25, 0x53, 0x65, 0x63, 0x75, 0x72,
+    0x69, 0x74, 0x79, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x6e, 0x64, 0x20,
+    0x41, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
+    0x08, 0x0c, 0x0a, 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x09, 0x2a,
+    0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x12, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x40, 0x61,
+    0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x04, 0x74, 0x3f, 0x1d, 0x98, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+    0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
+    0x01, 0x0b, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xc9, 0x25, 0xbe, 0xb8, 0xf2, 0x2c, 0x7f, 0xc8, 0x3a, 0xc3, 0xc2, 0x4b,
+    0xac, 0x54, 0xcf, 0xa6, 0x75, 0xaa, 0xeb, 0x40, 0x68, 0xee, 0xe2, 0xb1, 0xa8, 0x70, 0x9e, 0xe9, 0x8b, 0xf1, 0x0a, 0x85,
+    0x88, 0x40, 0xef, 0xb8, 0xa5, 0x04, 0x87, 0x63, 0x03, 0xf5, 0x41, 0x81, 0x29, 0x42, 0x7f, 0x31, 0x8f, 0x5b, 0xde, 0xe8,
+    0x15, 0xc1, 0xa3, 0x45, 0xf1, 0xbc, 0xff, 0x81, 0x58, 0xbd, 0xac, 0x4c, 0xa5, 0xb3, 0x30, 0x9a, 0xb8, 0x9e, 0x69, 0x10,
+    0xad, 0x44, 0x7b, 0x93, 0x28, 0xba, 0xca, 0x6f, 0x2e, 0xf8, 0x1b, 0x03, 0xc2, 0x0a, 0x4a, 0x06, 0x32, 0x4d, 0x30, 0x50,
+    0xb7, 0x9c, 0x57, 0x4d, 0x4b, 0x6c, 0x34, 0x53, 0xd8, 0xf5, 0xca, 0x91, 0xa5, 0xdf, 0xa6, 0x67, 0x0a, 0x2e, 0x02, 0x47,
+    0x1c, 0x1c, 0xd6, 0x2b, 0xe2, 0x85, 0xc1, 0xda, 0x79, 0xa2, 0xe2, 0x1e, 0xf8, 0x5e, 0xf9, 0x76, 0x55, 0xaf, 0x61, 0xaf,
+    0xde, 0x0a, 0x7b, 0xeb, 0xa1, 0xa8, 0xc6, 0xef, 0x76, 0x2f, 0x50, 0xd1, 0x0a, 0xce, 0xdb, 0x14, 0xc3, 0x13, 0x72, 0xe5,
+    0x26, 0x67, 0x90, 0x19, 0x15, 0x7b, 0x79, 0x05, 0xeb, 0x20, 0xb3, 0x5a, 0x4e, 0x78, 0xae, 0x2d, 0x9c, 0xd1, 0x31, 0xfd,
+    0x2e, 0xcb, 0x84, 0xb9, 0x67, 0xea, 0xaf, 0xb3, 0xc2, 0x5f, 0xf5, 0xcd, 0x7b, 0x66, 0x3f, 0xdf, 0xf7, 0xe7, 0x76, 0x46,
+    0x57, 0xd9, 0xee, 0x4b, 0xb2, 0xc8, 0x7b, 0xf9, 0x88, 0xab, 0x8e, 0xca, 0xfc, 0x39, 0xd1, 0x8e, 0x1c, 0xba, 0x3e, 0x63,
+    0xb7, 0xe8, 0x0e, 0x2f, 0xde, 0x6b, 0x76, 0x81, 0xbf, 0x78, 0x26, 0x0c, 0xa0, 0x2c, 0x35, 0x21, 0xde, 0xb4, 0x45, 0x0a,
+    0x84, 0xea, 0x68, 0xa5, 0x37, 0xe8, 0x4a, 0xbc, 0xa6, 0xcf, 0x24, 0x85, 0x46, 0x33, 0x9e, 0xd9, 0xba, 0x58, 0x75, 0xd7,
+    0x45, 0xc2, 0x99, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
 /*
  * MARK: RSA-signed messages (with attributes)
  */
@@ -726,7 +809,7 @@ unsigned char rsa_sha1_attr[] = {
     0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x33, 0x31, 0x38, 0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5a, 0x30,
     0x23, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x16, 0x04, 0x14, 0xef, 0x53, 0x0b, 0xfa,
     0xcf, 0x34, 0x18, 0xb3, 0x30, 0xff, 0xf8, 0x9e, 0x09, 0xb3, 0xb6, 0x21, 0xd6, 0x83, 0xb9, 0xe9, 0x30, 0x0d, 0x06, 0x09,
-    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x52, 0xbd, 0xa1, 0x0a, 0x41,
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x52, 0xbd, 0xa1, 0x0a, 0x41,
     0xce, 0xc1, 0xe8, 0xe8, 0x2f, 0x2e, 0x1f, 0x73, 0xd1, 0x2f, 0x2e, 0x53, 0x53, 0x21, 0xec, 0x88, 0x30, 0x6a, 0x9d, 0x58,
     0x64, 0x95, 0xef, 0xf2, 0x20, 0x55, 0xb0, 0x15, 0x64, 0x02, 0x1d, 0xf9, 0x44, 0xdd, 0xcb, 0x7a, 0x9c, 0x50, 0x10, 0xea,
     0xfa, 0x6f, 0x07, 0x64, 0xaf, 0x30, 0x6e, 0xe2, 0xc1, 0x34, 0x55, 0xd0, 0x6a, 0x6e, 0xe1, 0x09, 0x91, 0xb7, 0xe3, 0x7b,
@@ -814,7 +897,7 @@ unsigned char rsa_sha256_attr[] = {
     0x31, 0x33, 0x32, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04,
     0x31, 0x22, 0x04, 0x20, 0x33, 0x1f, 0x3a, 0xc4, 0x95, 0x97, 0x64, 0x1c, 0x99, 0x9b, 0x37, 0xc8, 0xf2, 0xba, 0xd0, 0xb4,
     0x38, 0xa5, 0x9c, 0x3a, 0xa3, 0x78, 0xf9, 0xfb, 0x66, 0x28, 0x4e, 0x6a, 0x90, 0xcc, 0x0e, 0x4c, 0x30, 0x0d, 0x06, 0x09,
-    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xae, 0x6d, 0xa9, 0xa7, 0xee,
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0xae, 0x6d, 0xa9, 0xa7, 0xee,
     0x0c, 0x94, 0x1b, 0xf3, 0x93, 0x40, 0x43, 0x11, 0x41, 0x20, 0x11, 0x60, 0xd9, 0x4e, 0xb6, 0x2d, 0x3e, 0x98, 0xfe, 0x06,
     0xd2, 0xc4, 0xe4, 0x0a, 0x66, 0xdc, 0xbb, 0xbd, 0x4d, 0x8e, 0xcb, 0xe1, 0x87, 0x39, 0x3f, 0xb3, 0x4b, 0xf8, 0xe7, 0x18,
     0x6f, 0x39, 0xad, 0x01, 0xd4, 0xe8, 0x85, 0x8c, 0x84, 0x96, 0x2c, 0x3a, 0xd4, 0xcf, 0x3c, 0xe5, 0x05, 0xdd, 0xc7, 0xc0,
index 44b57a7d060b3e91ba0bde51f271920d14b3bc58..3abf319cf50e3394ffd583895f35aba77f6e97f2 100644 (file)
@@ -411,8 +411,8 @@ static bool merge_der_in_to_data(const void *der1, size_t der1_len, const void *
     CFPropertyListRef dict1 = NULL;
     CFPropertyListRef dict2 = NULL;
 
-    der_decode_plist(NULL, kCFPropertyListImmutable, &dict1, NULL, der1, der1 + der1_len);
-    der_decode_plist(NULL, kCFPropertyListImmutable, &dict2, NULL, der2, der2 + der2_len);
+    der_decode_plist(NULL, &dict1, NULL, der1, der1 + der1_len);
+    der_decode_plist(NULL, &dict2, NULL, der2, der2 + der2_len);
     if (dict1 && dict2) {
         CFMutableDictionaryRef result_dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, dict1);
         CFDictionaryForEach(dict2, ^(const void *key, const void *value) {
@@ -463,7 +463,7 @@ static int aks_crypt_acl(CFTypeRef operation, keybag_handle_t keybag,
         require_action_string(der, out, aks_return = kAKSReturnError, "aks_ref_key_decrypt failed");
 
         CFPropertyListRef decoded_data = NULL;
-        der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len);
+        der_decode_plist(kCFAllocatorDefault, &decoded_data, NULL, der, der + der_len);
         require_action_string(decoded_data, out, aks_return = kAKSReturnError, "der_decode_plist failed");
         if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) {
             CFDataSetLength(dest, 0);
index 089c59ee4790ce209d76b0db6085a37d2f78cfa9..fed522299d706155ad6e87f930511af157d879a2 100644 (file)
 //these are copies of SecDH_gp() and SecDH_priv()
 static inline ccdh_gp_t vmdh_gp(struct vmdh *dh)
 {
-    return  (ccdh_gp_t)dh;
+    return (ccdh_gp_t)dh;
 }
 
 static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh)
 {
     ccdh_gp_t gp = vmdh_gp(dh);
     cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
-    ccdh_full_ctx_t priv = (ccdh_full_ctx_t)((char *) dh + ccdh_gp_size(s));
-
-    return priv;
+    return (ccdh_full_ctx_t)cc_pad_align((uintptr_t)dh + ccdh_gp_size(s));
 }
 
 static uint32_t param_g = 5;
index 3c79e75ec7508a1015a9c9881593488e4372aaa2..ded731c7fed81b0512203f58e83079331e98c19d 100644 (file)
 //these are copies of SecDH_gp() and SecDH_priv()
 static inline ccdh_gp_t vmdh_gp(struct vmdh *dh)
 {
-    return  (ccdh_gp_t)dh;
+    return (ccdh_gp_t)dh;
 }
 
 static inline ccdh_full_ctx_t vmdh_priv(struct vmdh *dh)
 {
     ccdh_gp_t gp = vmdh_gp(dh);
     cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
-    ccdh_full_ctx_t priv = (ccdh_full_ctx_t)((char *) dh + ccdh_gp_size(s));
-    return priv;
+    return (ccdh_full_ctx_t)cc_pad_align((uintptr_t)dh + ccdh_gp_size(s));
 }
 
 static uint32_t param_g = 5;
index 652e72e833702736069d5260c074dc113516dcba..e9ef95c61fc131c45a6d772dde69b2885a9e4bd8 100644 (file)
@@ -478,7 +478,7 @@ SecAccessControlRef SecAccessControlCreateFromData(CFAllocatorRef allocator, CFD
     CFPropertyListRef plist;
     const uint8_t *der = CFDataGetBytePtr(data);
     const uint8_t *der_end = der + CFDataGetLength(data);
-    require_quiet(der = der_decode_plist(0, kCFPropertyListMutableContainers, &plist, error, der, der_end), errOut);
+    require_quiet(der = der_decode_plist(0, &plist, error, der, der_end), errOut);
     if (der != der_end) {
         SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data"));
         goto errOut;
index b92d8dba5450bd16455e7e9f9c0a0ba769be74d3..1c67bb985a30c0c380b2e26c82ed58bc06d57194 100644 (file)
@@ -43,7 +43,7 @@
 
 #include "SecBase64.h"
 
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <string.h>
 #include <stdbool.h>
 
index 9d43e27a6d67e866ce29340223c0b0c489ce4b4a..fd0a9a6fc4c3c64a7abad91d5c5aeaffdaeaa1ee 100644 (file)
@@ -353,6 +353,13 @@ out:
     return TRUE;
 }
 
+static Boolean SecCTKKeyIsEqual(SecKeyRef key1, SecKeyRef key2) {
+    SecCTKKeyData *kd1 = key1->key;
+    SecCTKKeyData *kd2 = key2->key;
+
+    return CFEqual(kd1->token_id, kd2->token_id) && CFEqual(kd1->object_id, kd2->object_id);
+}
+
 static SecKeyDescriptor kSecCTKKeyDescriptor = {
     .version = kSecKeyDescriptorVersion,
     .name = "CTKKey",
@@ -365,6 +372,7 @@ static SecKeyDescriptor kSecCTKKeyDescriptor = {
     .getAlgorithmID = SecCTKGetAlgorithmID,
     .copyPublic = SecCTKKeyCopyPublicOctets,
     .copyOperationResult = SecCTKKeyCopyOperationResult,
+    .isEqual = SecCTKKeyIsEqual,
     .createDuplicate = SecCTKKeyCreateDuplicate,
     .setParameter = SecCTKKeySetParameter,
 };
@@ -401,14 +409,6 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib
         CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrIsPrivate, kCFBooleanTrue);
     }
 
-    // Convert some attributes which are stored as numbers in iOS keychain but a lot of code counts that the values
-    // are actually strings as specified by kSecAttrXxx constants.
-    static const CFStringRef *numericAttributes[] = {
-        &kSecAttrKeyType,
-        &kSecAttrKeyClass,
-        NULL,
-    };
-
     CFMutableDictionaryRef attrs = NULL;
     if (kd->token == NULL) {
         require_quiet(kd->token = SecCTKKeyCopyToken(key, error), out);
@@ -432,6 +432,14 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib
         require_quiet(kd->token != NULL && kd->object_id != NULL, out);
     }
 
+    // Convert some attributes which are stored as numbers in iOS keychain but a lot of code counts that the values
+    // are actually strings as specified by kSecAttrXxx constants.
+    static const CFStringRef *numericAttributes[] = {
+        &kSecAttrKeyType,
+        &kSecAttrKeyClass,
+        NULL,
+    };
+
     for (const CFStringRef **attrName = &numericAttributes[0]; *attrName != NULL; attrName++) {
         CFTypeRef value = CFDictionaryGetValue(kd->attributes.dictionary, **attrName);
         if (value != NULL && CFGetTypeID(value) == CFNumberGetTypeID()) {
@@ -445,6 +453,11 @@ SecKeyRef SecKeyCreateCTKKey(CFAllocatorRef allocator, CFDictionaryRef refAttrib
             }
         }
     }
+
+    // Sanitize some important attributes.
+    CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecClass, kSecClassKey);
+    CFDictionarySetValue(SecCFDictionaryCOWGetMutable(&kd->attributes), kSecAttrKeyClass, kSecAttrKeyClassPrivate);
+
     result = (SecKeyRef)CFRetain(key);
 
 out:
@@ -523,7 +536,17 @@ SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef
     static const uint8_t uikProposedObjectIDBytes[] = { 0x04, 22, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'u', 'i', 'k', 'p' };
 
     static const uint8_t casdObjectIDBytes[] = { 0x04, 27, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 'c', 'e', 'l', 'e', 'm', 't', 'o', 'k', 'e', 'n', '.', 'c', 'a', 's', 'd' };
-    
+
+    // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.oikc" dataUsingEncoding:NSUTF8StringEncoding]].data
+    static const uint8_t oikCommittedObjectIDBytes[] = { 0x04, 22, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'o', 'i', 'k', 'c' };
+    // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.oikp" dataUsingEncoding:NSUTF8StringEncoding]].data
+    static const uint8_t oikProposedObjectIDBytes[] = { 0x04, 22, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'o', 'i', 'k', 'p' };
+
+    // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.dakc" dataUsingEncoding:NSUTF8StringEncoding]].data
+    static const uint8_t dakCommittedObjectIDBytes[] = { 0x04, 22, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'd', 'a', 'k', 'c' };
+    // [[TKTLVBERRecord alloc] initWithPropertyList:[@"com.apple.setoken.dakp" dataUsingEncoding:NSUTF8StringEncoding]].data
+    static const uint8_t dakProposedObjectIDBytes[] = { 0x04, 22, 'c', 'o', 'm', '.', 'a', 'p', 'p', 'l', 'e', '.', 's', 'e', 't', 'o', 'k', 'e', 'n', '.', 'd', 'a', 'k', 'p' };
+
     CFStringRef token = kSecAttrTokenIDAppleKeyStore;
     
     switch (keyType) {
@@ -543,6 +566,18 @@ SecKeyRef SecKeyCopyAttestationKey(SecKeyAttestationKeyType keyType, CFErrorRef
             object_id = CFDataCreate(kCFAllocatorDefault, casdObjectIDBytes, sizeof(casdObjectIDBytes));
             token = kSecAttrTokenIDSecureElement;
             break;
+        case kSecKeyAttestationKeyTypeOIKCommitted:
+            object_id = CFDataCreate(kCFAllocatorDefault, oikCommittedObjectIDBytes, sizeof(uikCommittedObjectIDBytes));
+            break;
+        case kSecKeyAttestationKeyTypeOIKProposed:
+            object_id = CFDataCreate(kCFAllocatorDefault, oikProposedObjectIDBytes, sizeof(uikProposedObjectIDBytes));
+            break;
+        case kSecKeyAttestationKeyTypeDAKCommitted:
+            object_id = CFDataCreate(kCFAllocatorDefault, dakCommittedObjectIDBytes, sizeof(uikCommittedObjectIDBytes));
+            break;
+        case kSecKeyAttestationKeyTypeDAKProposed:
+            object_id = CFDataCreate(kCFAllocatorDefault, dakProposedObjectIDBytes, sizeof(uikProposedObjectIDBytes));
+            break;
         default:
             SecError(errSecParam, error, CFSTR("unexpected attestation key type %d"), (int)keyType);
             goto out;
@@ -639,10 +674,6 @@ Boolean SecKeyControlLifetime(SecKeyRef key, SecKeyControlLifetimeType type, CFE
     }, NULL);
 }
 
-#if TKTOKEN_CLIENT_INTERFACE_VERSION < 5
-#define kTKTokenCreateAttributeTestMode "testmode"
-#endif
-
 void SecCTKKeySetTestMode(CFStringRef tokenID, CFTypeRef enable) {
     CFErrorRef error = NULL;
     CFDictionaryRef options = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecAttrTokenID, tokenID, @kTKTokenCreateAttributeTestMode, enable, nil);
index 204ec41a73f349199dfa8dda5bb1167fa4c21830..dd5f50d4fe4a3a47645943220462720f629398bf 100644 (file)
@@ -71,6 +71,8 @@
 #include "AppleiPhoneDeviceCACertificates.h"
 #include <ipc/securityd_client.h>
 #include <Security/SecKeyInternal.h>
+#include "AppleExternalRootCertificates.h"
+#include <Security/SecInternalReleasePriv.h>
 
 #pragma clang diagnostic ignored "-Wformat=2"
 
 #define IPv4ADDRLEN     4   // 4 octets
 #define IPv6ADDRLEN     16  // 16 octets
 
+#define MAX_EXTENSIONS 10000
+#define MAX_ATTRIBUTE_TYPE_AND_VALUES 1024
+#define MAX_CRL_DPS 1024
+#define MAX_CERTIFICATE_POLICIES 8192
+#define MAX_POLICY_MAPPINGS 8192
+#define MAX_EKUS 8192
+#define MAX_AIAS 1024
+
 typedef struct SecCertificateExtension {
        DERItem extnID;
     bool critical;
@@ -300,8 +310,6 @@ static CFHashCode SecCertificateHash(CFTypeRef cf) {
        return (hashCode + der_length + sig_length);
 }
 
-#if 1
-
 /************************************************************************/
 /************************* General Name Parsing *************************/
 /************************************************************************/
@@ -390,159 +398,15 @@ OSStatus SecCertificateParseGeneralNames(const DERItem *generalNames, void *cont
     DERDecodedInfo generalNamesContent;
     DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
     require_noerr_quiet(drtn, badDER);
+    // GeneralNames ::= SEQUENCE SIZE (1..MAX)
     require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
+    require_quiet(generalNamesContent.content.length > 0, badDER); // not defining a max due to use of large number of SANs
     return parseGeneralNamesContent(&generalNamesContent.content, context,
                callback);
 badDER:
        return errSecInvalidCertificate;
 }
 
-#else
-
-/*
-      GeneralName ::= CHOICE {
-           otherName                       [0]     OtherName,
-           rfc822Name                      [1]     IA5String,
-           dNSName                         [2]     IA5String,
-           x400Address                     [3]     ORAddress,
-           directoryName                   [4]     Name,
-           ediPartyName                    [5]     EDIPartyName,
-           uniformResourceIdentifier       [6]     IA5String,
-           iPAddress                       [7]     OCTET STRING,
-           registeredID                    [8]     OBJECT IDENTIFIER}
-
-      EDIPartyName ::= SEQUENCE {
-           nameAssigner            [0]     DirectoryString OPTIONAL,
-           partyName               [1]     DirectoryString }
- */
-static OSStatus parseGeneralNameContentProperty(DERTag tag,
-       const DERItem *generalNameContent, SecCEGeneralName *generalName) {
-       switch (tag) {
-       case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0:
-               generalName->nameType = GNT_OtherName;
-               generalName->berEncoded = true;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | 1:
-               /* IA5String. */
-               generalName->nameType = GNT_RFC822Name;
-               generalName->berEncoded = false;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | 2:
-               /* IA5String. */
-               generalName->nameType = GNT_DNSName;
-               generalName->berEncoded = false;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3:
-               generalName->nameType = GNT_X400Address;
-               generalName->berEncoded = true;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 4:
-               generalName->nameType = GNT_DirectoryName;
-               generalName->berEncoded = true;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 5:
-               generalName->nameType = GNT_EdiPartyName;
-               generalName->berEncoded = true;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 6:
-       {
-               /* Technically I don't think this is valid, but there are certs out
-                  in the wild that use a constructed IA5String.   In particular the
-                  VeriSign Time Stamping Authority CA.cer does this.  */
-               DERDecodedInfo decoded;
-               require_noerr(DERDecodeItem(generalNameContent, &decoded), badDER);
-               require(decoded.tag == ASN1_IA5_STRING, badDER);
-               generalName->nameType = GNT_URI;
-               generalName->berEncoded = false;
-               generalName->name = decoded.content;
-               break;
-       }
-       case ASN1_CONTEXT_SPECIFIC | 6:
-               generalName->nameType = GNT_URI;
-               generalName->berEncoded = false;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | 7:
-               /* @@@ This is the IP Address as an OCTECT STRING. For IPv4 it's
-                  8 octects, addr/mask for ipv6 it's 32.  */
-               generalName->nameType = GNT_IPAddress;
-               generalName->berEncoded = false;
-               generalName->name = *generalNameContent;
-               break;
-       case ASN1_CONTEXT_SPECIFIC | 8:
-               /* name is the content of an OID. */
-               generalName->nameType = GNT_RegisteredID;
-               generalName->berEncoded = false;
-               generalName->name = *generalNameContent;
-               break;
-       default:
-               goto badDER;
-               break;
-       }
-       return errSecSuccess;
-badDER:
-       return errSecInvalidCertificate;
-}
-
-/*
-      GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
- */
-static OSStatus parseGeneralNamesContent(const DERItem *generalNamesContent,
-       CFIndex *count, SecCEGeneralName **name) {
-       SecCEGeneralName *generalNames = NULL;
-    DERSequence gnSeq;
-    DERReturn drtn = DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
-    require_noerr_quiet(drtn, badDER);
-    DERDecodedInfo generalNameContent;
-       CFIndex generalNamesCount = 0;
-    while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
-               DR_Success) {
-               ++generalNamesCount;
-       }
-    require_quiet(drtn == DR_EndOfSequence, badDER);
-
-       require(generalNames = calloc(generalNamesCount, sizeof(SecCEGeneralName)),
-               badDER);
-    DERDecodeSeqContentInit(generalNamesContent, &gnSeq);
-       CFIndex ix = 0;
-    while ((drtn = DERDecodeSeqNext(&gnSeq, &generalNameContent)) ==
-               DR_Success) {
-               if (!parseGeneralNameContentProperty(generalNameContent.tag,
-                       &generalNameContent.content, &generalNames[ix])) {
-                       goto badDER;
-               }
-               ++ix;
-    }
-       *count = generalNamesCount;
-       *name = generalNames;
-       return errSecSuccess;
-
-badDER:
-       if (generalNames)
-               free(generalNames);
-       return errSecInvalidCertificate;
-}
-
-static OSStatus parseGeneralNames(const DERItem *generalNames,
-       CFIndex *count, SecCEGeneralName **name) {
-    DERDecodedInfo generalNamesContent;
-    DERReturn drtn = DERDecodeItem(generalNames, &generalNamesContent);
-    require_noerr_quiet(drtn, badDER);
-    require_quiet(generalNamesContent.tag == ASN1_CONSTR_SEQUENCE,
-        badDER);
-    parseGeneralNamesContent(&generalNamesContent.content, count, name);
-    return errSecSuccess;
-badDER:
-       return errSecInvalidCertificate;
-}
-#endif
-
 /************************************************************************/
 /************************** X.509 Name Parsing **************************/
 /************************************************************************/
@@ -579,25 +443,30 @@ badDER:
 }
 
 static OSStatus parseX501NameContent(const DERItem *x501NameContent, void *context,
-       parseX501NameCallback callback, bool localized) {
-       DERSequence derSeq;
-       DERReturn drtn = DERDecodeSeqContentInit(x501NameContent, &derSeq);
-       require_noerr_quiet(drtn, badDER);
-       DERDecodedInfo currDecoded;
-       while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
-               require_quiet(currDecoded.tag == ASN1_CONSTR_SET, badDER);
-               OSStatus status = parseRDNContent(&currDecoded.content, context,
-                       callback, localized);
-               if (status) {
-                       return status;
-               }
-       }
-       require_quiet(drtn == DR_EndOfSequence, badDER);
+                                     parseX501NameCallback callback, bool localized) {
+    DERSequence derSeq;
+    DERReturn drtn = DERDecodeSeqContentInit(x501NameContent, &derSeq);
+    require_noerr_quiet(drtn, badDER);
+    DERDecodedInfo currDecoded;
+    int atv_count = 0;
+    while ((drtn = DERDecodeSeqNext(&derSeq, &currDecoded)) == DR_Success) {
+        /*  RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue */
+        require_quiet(currDecoded.tag == ASN1_CONSTR_SET, badDER);
+        require_quiet(currDecoded.content.length > 0, badDER);
+        OSStatus status = parseRDNContent(&currDecoded.content, context,
+                                          callback, localized);
+        if (status) {
+            return status;
+        }
+        atv_count++;
+        require_quiet(atv_count < MAX_ATTRIBUTE_TYPE_AND_VALUES, badDER);
+    }
+    require_quiet(drtn == DR_EndOfSequence, badDER);
 
-       return errSecSuccess;
+    return errSecSuccess;
 
 badDER:
-       return errSecInvalidCertificate;
+    return errSecInvalidCertificate;
 }
 
 static OSStatus parseX501Name(const DERItem *x501Name, void *context,
@@ -676,11 +545,23 @@ static bool SecCEPPrivateKeyUsagePeriod(SecCertificateRef certificate,
     return true;
 }
 
+static OSStatus verifySubjectAltGeneralName(void *context, SecCEGeneralNameType type,
+                                            const DERItem *value) {
+    // Nothing to do for now
+    return errSecSuccess;
+}
+
 static bool SecCEPSubjectAltName(SecCertificateRef certificate,
        const SecCertificateExtension *extn) {
        secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
+    // Make sure that the SAN is parse-able
+    require_noerr_quiet(SecCertificateParseGeneralNames(&extn->extnValue, NULL, verifySubjectAltGeneralName), badDER);
        certificate->_subjectAltName = extn;
     return true;
+badDER:
+    certificate->_subjectAltName = NULL;
+    secwarning("Invalid SubjectAltName Extension");
+    return false;
 }
 
 static bool SecCEPIssuerAltName(SecCertificateRef certificate,
@@ -849,7 +730,9 @@ static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate,
     DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &crlDPSeq);
     require_noerr_quiet(drtn, badDER);
     require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
+    require_quiet(crlDPSeq.nextItem != crlDPSeq.end, badDER);
     DERDecodedInfo dpContent;
+    int crldp_count = 0;
     while ((drtn = DERDecodeSeqNext(&crlDPSeq, &dpContent)) == DR_Success) {
         require_quiet(dpContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
         DERDistributionPoint dp;
@@ -879,6 +762,8 @@ static bool SecCEPCrlDistributionPoints(SecCertificateRef certificate,
                                                    appendCRLDPFromGeneralNames);
             require_noerr_quiet(drtn, badDER);
         }
+        crldp_count++;
+        require_quiet(crldp_count < MAX_CRL_DPS, badDER);
     }
     require_quiet(drtn == DR_EndOfSequence, badDER);
     return true;
@@ -901,8 +786,6 @@ badDER:
         policyQualifierId  PolicyQualifierId,
         qualifier          ANY DEFINED BY policyQualifierId }
 */
-/* maximum number of policies of 8192 seems more than adequate */
-#define MAX_CERTIFICATE_POLICIES 8192
 static bool SecCEPCertificatePolicies(SecCertificateRef certificate,
        const SecCertificateExtension *extn) {
        secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
@@ -920,14 +803,14 @@ static bool SecCEPCertificatePolicies(SecCertificateRef certificate,
         policy_count++;
     }
     require_quiet(drtn == DR_EndOfSequence, badDER);
-    require_quiet(policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation)
-                                                * (policy_count > 0 ? policy_count : 1)),
+    require_quiet(policy_count > 0, badDER);
+    require_quiet(policies = (SecCEPolicyInformation *)malloc(sizeof(SecCEPolicyInformation) * policy_count),
                   badDER);
     drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &piSeq);
     require_noerr_quiet(drtn, badDER);
     DERSize policy_ix = 0;
-    while ((policy_ix < (policy_count > 0 ? policy_count : 1)) &&
-           (drtn = DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
+    while ((policy_ix < policy_count) &&
+           (DERDecodeSeqNext(&piSeq, &piContent)) == DR_Success) {
         DERPolicyInformation pi;
         drtn = DERParseSequenceContent(&piContent.content,
             DERNumPolicyInformationItemSpecs,
@@ -957,7 +840,6 @@ badDER:
         issuerDomainPolicy      CertPolicyId,
         subjectDomainPolicy     CertPolicyId }
 */
-#define MAX_POLICY_MAPPINGS 8192
 static bool SecCEPPolicyMappings(SecCertificateRef certificate,
        const SecCertificateExtension *extn) {
        secdebug("cert", "critical: %s", extn->critical ? "yes" : "no");
@@ -975,14 +857,14 @@ static bool SecCEPPolicyMappings(SecCertificateRef certificate,
         mapping_count++;
     }
     require_quiet(drtn == DR_EndOfSequence, badDER);
-    require_quiet(mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping)
-                                            * (mapping_count > 0 ? mapping_count : 1)),
+    require_quiet(mapping_count > 0, badDER); // PolicyMappings ::= SEQUENCE SIZE (1..MAX)
+    require_quiet(mappings = (SecCEPolicyMapping *)malloc(sizeof(SecCEPolicyMapping) * mapping_count),
                   badDER);
     drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &pmSeq);
     require_noerr_quiet(drtn, badDER);
     DERSize mapping_ix = 0;
-    while ((mapping_ix < (mapping_count > 0 ? mapping_count : 1)) &&
-           (drtn = DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) {
+    while ((mapping_ix < mapping_count) &&
+           (DERDecodeSeqNext(&pmSeq, &pmContent)) == DR_Success) {
         require_quiet(pmContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
         DERPolicyMapping pm;
         drtn = DERParseSequenceContent(&pmContent.content,
@@ -1003,7 +885,7 @@ badDER:
         free(mappings);
     }
     certificate->_policyMappings.present = false;
-       secwarning("Invalid CertificatePolicies Extension");
+       secwarning("Invalid PolicyMappings Extension");
     return false;
 }
 
@@ -1085,9 +967,13 @@ static bool SecCEPExtendedKeyUsage(SecCertificateRef certificate,
     DERTag ekuTag;
     DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &ekuTag, &ekuSeq);
     require_quiet((drtn == DR_Success) && (ekuTag == ASN1_CONSTR_SEQUENCE), badDER);
+    require_quiet(ekuSeq.nextItem != ekuSeq.end, badDER); // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
     DERDecodedInfo ekuContent;
+    int eku_count = 0;
     while ((drtn = DERDecodeSeqNext(&ekuSeq, &ekuContent)) == DR_Success) {
         require_quiet(ekuContent.tag == ASN1_OBJECT_ID, badDER);
+        eku_count++;
+        require_quiet(eku_count < MAX_EKUS, badDER);
     }
     require_quiet(drtn == DR_EndOfSequence, badDER);
     return true;
@@ -1144,7 +1030,9 @@ static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate,
     DERReturn drtn = DERDecodeSeqInit(&extn->extnValue, &tag, &adSeq);
     require_noerr_quiet(drtn, badDER);
     require_quiet(tag == ASN1_CONSTR_SEQUENCE, badDER);
+    require_quiet(adSeq.nextItem != adSeq.end, badDER);
     DERDecodedInfo adContent;
+    int aia_count = 0;
     while ((drtn = DERDecodeSeqNext(&adSeq, &adContent)) == DR_Success) {
         require_quiet(adContent.tag == ASN1_CONSTR_SEQUENCE, badDER);
                DERAccessDescription ad;
@@ -1153,6 +1041,8 @@ static bool SecCEPAuthorityInfoAccess(SecCertificateRef certificate,
                        DERAccessDescriptionItemSpecs,
                        &ad, sizeof(ad));
                require_noerr_quiet(drtn, badDER);
+        aia_count++;
+        require_quiet(aia_count < MAX_AIAS, badDER);
         CFMutableArrayRef *urls;
         if (DEROidCompare(&ad.accessMethod, &oidAdOCSP))
             urls = &certificate->_ocspResponders;
@@ -1818,9 +1708,10 @@ static bool SecCertificateParse(SecCertificateRef certificate)
             extensionCount++;
         }
         require_quiet(drtn == DR_EndOfSequence, badCert);
+        require_quiet(extensionCount > 0, badCert); // Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
 
         /* Put some upper limit on the number of extensions allowed. */
-        require_quiet(extensionCount < 10000, badCert);
+        require_quiet(extensionCount < MAX_EXTENSIONS, badCert);
         certificate->_extensionCount = extensionCount;
         certificate->_extensions = malloc(sizeof(SecCertificateExtension) * (extensionCount > 0 ? extensionCount : 1));
         require_quiet(certificate->_extensions, badCert);
@@ -3008,7 +2899,7 @@ static void appendSerialNumberProperty(CFMutableArrayRef parent, CFStringRef lab
 
 static void appendBitStringContentNames(CFMutableArrayRef properties,
     CFStringRef label, const DERItem *bitStringContent,
-    const CFStringRef *names, CFIndex namesCount,
+    const __nonnull CFStringRef *names, CFIndex namesCount,
     bool localized) {
     DERSize len = bitStringContent->length - 1;
     require_quiet(len == 1 || len == 2, badDER);
@@ -3039,7 +2930,7 @@ static void appendBitStringContentNames(CFMutableArrayRef properties,
                 string = s;
             } else {
                 string = localizedName;
-                CFRetain(string);
+                CFRetainSafe(string);
             }
         }
         mask >>= 1;
@@ -3056,7 +2947,7 @@ badDER:
 
 static void appendBitStringNames(CFMutableArrayRef properties,
     CFStringRef label, const DERItem *bitString,
-    const CFStringRef *names, CFIndex namesCount,
+    const __nonnull CFStringRef *names, CFIndex namesCount,
     bool localized) {
     DERDecodedInfo bitStringContent;
     DERReturn drtn = DERDecodeItem(bitString, &bitStringContent);
@@ -4429,10 +4320,20 @@ CFDataRef SecCertificateCopySerialNumberData(
        return certificate->_serialNumber;
 }
 
+#if TARGET_OS_OSX && TARGET_CPU_ARM64
+/* force this implementation to be _SecCertificateCopySerialNumber on arm64 macOS.
+   note: the legacy function in SecCertificate.cpp is now _SecCertificateCopySerialNumber$LEGACYMAC
+   when both TARGET_OS_OSX and TARGET_CPU_ARM64 are true.
+ */
+extern CFDataRef SecCertificateCopySerialNumber_ios(SecCertificateRef certificate) __asm("_SecCertificateCopySerialNumber");
+CFDataRef SecCertificateCopySerialNumber_ios(SecCertificateRef certificate) {
+    return SecCertificateCopySerialNumberData(certificate, NULL);
+}
+#endif
+
 #if !TARGET_OS_OSX
-/* On iOS, the SecCertificateCopySerialNumber API takes one argument. */
-CFDataRef SecCertificateCopySerialNumber(
-               SecCertificateRef certificate) {
+CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate)
+{
        return SecCertificateCopySerialNumberData(certificate, NULL);
 }
 #endif
@@ -4653,69 +4554,59 @@ CFDataRef SecFrameworkCopyIPAddressData(CFStringRef string) {
     return data;
 }
 
-static OSStatus appendIPAddressesFromGeneralNames(void *context,
-       SecCEGeneralNameType gnType, const DERItem *generalName) {
-       CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context;
-       if (gnType == GNT_IPAddress) {
-               CFStringRef string = copyIPAddressContentDescription(
-                       kCFAllocatorDefault, generalName);
-               if (string) {
-                       CFArrayAppendValue(ipAddresses, string);
-                       CFRelease(string);
-               } else {
-                       return errSecInvalidCertificate;
-               }
-       }
-       return errSecSuccess;
+static OSStatus appendIPAddressesFromGeneralNames(void *context, SecCEGeneralNameType gnType, const DERItem *generalName) {
+    CFMutableArrayRef ipAddresses = (CFMutableArrayRef)context;
+    if (gnType == GNT_IPAddress) {
+        if (generalName->length == IPv4ADDRLEN || generalName->length == IPv6ADDRLEN) {
+            CFDataRef address = CFDataCreate(NULL, generalName->data, generalName->length);
+            CFArrayAppendValue(ipAddresses, address);
+            CFReleaseNull(address);
+        } else {
+            return errSecInvalidCertificate;
+        }
+    }
+    return errSecSuccess;
 }
 
 CFArrayRef SecCertificateCopyIPAddresses(SecCertificateRef certificate) {
-       /* These can only exist in the subject alt name. */
-       if (!certificate->_subjectAltName)
-               return NULL;
-
-       CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault,
-               0, &kCFTypeArrayCallBacks);
-       OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
-               ipAddresses, appendIPAddressesFromGeneralNames);
-       if (status || CFArrayGetCount(ipAddresses) == 0) {
-               CFRelease(ipAddresses);
-               ipAddresses = NULL;
-       }
-       return ipAddresses;
-}
+    CFArrayRef ipAddresses = SecCertificateCopyIPAddressDatas(certificate);
+    if (!ipAddresses) {
+        return NULL;
+    }
 
-static OSStatus appendIPAddressesFromX501Name(void *context, const DERItem *type,
-                                              const DERItem *value, CFIndex rdnIX,
-                                              bool localized) {
-    CFMutableArrayRef addrs = (CFMutableArrayRef)context;
-    if (DEROidCompare(type, &oidCommonName)) {
-        CFStringRef string = copyDERThingDescription(kCFAllocatorDefault,
-                                                     value, true, localized);
+    // Convert data IP addresses to strings
+    __block CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    CFArrayForEach(ipAddresses, ^(const void *value) {
+        CFDataRef address = (CFDataRef)value;
+        DERItem der_address = { (unsigned char *)CFDataGetBytePtr(address), CFDataGetLength(address) };
+        CFStringRef string = copyIPAddressContentDescription(NULL, &der_address);
         if (string) {
-            CFDataRef data = NULL;
-            if (convertIPAddress(string, &data)) {
-                CFArrayAppendValue(addrs, data);
-                CFReleaseNull(data);
-            }
+            CFArrayAppendValue(result, string);
             CFRelease(string);
-        } else {
-            return errSecInvalidCertificate;
         }
+    });
+    CFReleaseNull(ipAddresses);
+    if (CFArrayGetCount(result) == 0) {
+        CFReleaseNull(result);
     }
-    return errSecSuccess;
+
+    return result;
 }
 
-CFArrayRef SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate) {
-    CFMutableArrayRef addrs = CFArrayCreateMutable(kCFAllocatorDefault,
-                                                      0, &kCFTypeArrayCallBacks);
-    OSStatus status = parseX501NameContent(&certificate->_subject, addrs,
-                                           appendIPAddressesFromX501Name, true);
-    if (status || CFArrayGetCount(addrs) == 0) {
-        CFReleaseNull(addrs);
+CFArrayRef SecCertificateCopyIPAddressDatas(SecCertificateRef certificate) {
+    /* These can only exist in the subject alt name. */
+    if (!certificate->_subjectAltName)
         return NULL;
+
+    CFMutableArrayRef ipAddresses = CFArrayCreateMutable(kCFAllocatorDefault,
+        0, &kCFTypeArrayCallBacks);
+    OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
+        ipAddresses, appendIPAddressesFromGeneralNames);
+    if (status || CFArrayGetCount(ipAddresses) == 0) {
+        CFRelease(ipAddresses);
+        ipAddresses = NULL;
     }
-    return addrs;
+    return ipAddresses;
 }
 
 static OSStatus appendDNSNamesFromGeneralNames(void *context, SecCEGeneralNameType gnType,
@@ -4840,21 +4731,12 @@ static OSStatus appendDNSNamesFromX501Name(void *context, const DERItem *type,
        return errSecSuccess;
 }
 
-CFArrayRef SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate) {
-    CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
-                                                      0, &kCFTypeArrayCallBacks);
-    OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
-                                          appendDNSNamesFromX501Name, true);
-    if (status || CFArrayGetCount(dnsNames) == 0) {
-        CFReleaseNull(dnsNames);
-        return NULL;
-    }
-
-    /* appendDNSNamesFromX501Name allows IP addresses, we don't want those for this function */
+static CF_RETURNS_RETAINED CFArrayRef filterIPAddresses(CFArrayRef CF_CONSUMED dnsNames)
+{
     __block CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     CFArrayForEach(dnsNames, ^(const void *value) {
         CFStringRef name = (CFStringRef)value;
-        if (!convertIPAddress(name, NULL)) {
+        if (!SecFrameworkIsIPAddress(name)) {
             CFArrayAppendValue(result, name);
         }
     });
@@ -4869,50 +4751,56 @@ CFArrayRef SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate)
 CFArrayRef SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate) {
     CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
                                                       0, &kCFTypeArrayCallBacks);
-    OSStatus status = errSecSuccess;
     if (certificate->_subjectAltName) {
-        status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
-                                                 dnsNames, appendDNSNamesFromGeneralNames);
+        if (SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
+                                            dnsNames, appendDNSNamesFromGeneralNames) != errSecSuccess) {
+            CFReleaseNull(dnsNames);
+            return NULL;
+        }
     }
 
-    if (status || CFArrayGetCount(dnsNames) == 0) {
-        CFReleaseNull(dnsNames);
-    }
-    return dnsNames;
+    /* appendDNSNamesFromGeneralNames allows IP addresses, we don't want those for this function */
+    return filterIPAddresses(dnsNames);
 }
 
 /* Not everything returned by this function is going to be a proper DNS name,
    we also return the certificates common name entries from the subject,
-   assuming they look like dns names as specified in RFC 1035. */
+   assuming they look like dns names as specified in RFC 1035.
+
+   To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSAN
+   because that function filters out IP Addresses. This function is Private, but
+   SecCertificateCopyValues uses it and that's Public. */
 CFArrayRef SecCertificateCopyDNSNames(SecCertificateRef certificate) {
-       /* These can exist in the subject alt name or in the subject. */
-    CFArrayRef sanNames = SecCertificateCopyDNSNamesFromSAN(certificate);
-    if (sanNames && CFArrayGetCount(sanNames) > 0) {
-        return sanNames;
-    }
-    CFReleaseNull(sanNames);
-
-       /* RFC 2818 section 3.1.  Server Identity
-         [...]
-         If a subjectAltName extension of type dNSName is present, that MUST
-         be used as the identity. Otherwise, the (most specific) Common Name
-         field in the Subject field of the certificate MUST be used. Although
-         the use of the Common Name is existing practice, it is deprecated and
-         Certification Authorities are encouraged to use the dNSName instead.
-         [...]
-
-         This implies that if we found 1 or more DNSNames in the
-         subjectAltName, we should not use the Common Name of the subject as
-         a DNSName.
-       */
-
-    /* To preserve bug for bug compatibility, we can't use SecCertificateCopyDNSNamesFromSubject
-     * because that function filters out IP Addresses. This function is Private, but
-     * SecCertificateCopyValues uses it and that's Public. */
+    /* RFC 2818 section 3.1.  Server Identity
+     [...]
+     If a subjectAltName extension of type dNSName is present, that MUST
+     be used as the identity. Otherwise, the (most specific) Common Name
+     field in the Subject field of the certificate MUST be used. Although
+     the use of the Common Name is existing practice, it is deprecated and
+     Certification Authorities are encouraged to use the dNSName instead.
+     [...]
+
+     This implies that if we found 1 or more DNSNames in the
+     subjectAltName, we should not use the Common Name of the subject as
+     a DNSName.
+     */
+
+    /* return SAN DNS names if they exist */
+    if (certificate->_subjectAltName) {
+        CFMutableArrayRef sanNames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+        OSStatus status = SecCertificateParseGeneralNames(&certificate->_subjectAltName->extnValue,
+                                                          sanNames, appendDNSNamesFromGeneralNames);
+        if (status == errSecSuccess && sanNames && CFArrayGetCount(sanNames) > 0) {
+            return sanNames;
+        }
+        CFReleaseNull(sanNames);
+    }
+
+    /* fall back to return DNS names in the Common Name */
     CFMutableArrayRef dnsNames = CFArrayCreateMutable(kCFAllocatorDefault,
                                                       0, &kCFTypeArrayCallBacks);
     OSStatus status = parseX501NameContent(&certificate->_subject, dnsNames,
-            appendDNSNamesFromX501Name, true);
+                                           appendDNSNamesFromX501Name, true);
     if (status || CFArrayGetCount(dnsNames) == 0) {
         CFReleaseNull(dnsNames);
     }
@@ -5133,6 +5021,37 @@ CFArrayRef SecCertificateCopyCountry(SecCertificateRef certificate) {
     return countries;
 }
 
+typedef struct {
+    DERItem *attributeOID;
+    CFStringRef *result;
+} ATV_Context;
+
+static OSStatus copyAttributeValueFromX501Name(void *context, const DERItem *type, const DERItem *value, CFIndex rdnIX, bool localized) {
+    ATV_Context *ctx = (ATV_Context *)context;
+    if (DEROidCompare(type, ctx->attributeOID)) {
+        CFStringRef string = copyDERThingDescription(kCFAllocatorDefault, value, true, localized);
+        if (string) {
+            CFAssignRetained(*ctx->result, string);
+        } else {
+            return errSecInvalidCertificate;
+        }
+    }
+    return errSecSuccess;
+}
+
+CFStringRef SecCertificateCopySubjectAttributeValue(SecCertificateRef cert, DERItem *attributeOID) {
+    CFStringRef result = NULL;
+    ATV_Context context = {
+        .attributeOID = attributeOID,
+        .result = &result,
+    };
+    OSStatus status = parseX501NameContent(&cert->_subject, &context, copyAttributeValueFromX501Name, false);
+    if (status) {
+        CFReleaseNull(result);
+    }
+    return result;
+}
+
 const SecCEBasicConstraints *
 SecCertificateGetBasicConstraints(SecCertificateRef certificate) {
        if (certificate->_basicConstraints.present)
@@ -5389,11 +5308,15 @@ const DERItem *SecCertificateGetPublicKeyData(SecCertificateRef certificate) {
 }
 
 #if TARGET_OS_OSX
-/* There is already a SecCertificateCopyPublicKey with different args on OS X,
-   so we will refer to this one internally as SecCertificateCopyPublicKey_ios.
+#if TARGET_CPU_ARM64
+/* force this implementation to be _SecCertificateCopyPublicKey on arm64 macOS.
+   note: the legacy function in SecCertificate.cpp is now _SecCertificateCopyPublicKey$LEGACYMAC
+   when both TARGET_OS_OSX and TARGET_CPU_ARM64 are true.
  */
+extern __nullable SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate) __asm("_SecCertificateCopyPublicKey");
+#endif /* TARGET_CPU_ARM64 */
 __nullable SecKeyRef SecCertificateCopyPublicKey_ios(SecCertificateRef certificate)
-#else
+#else /* !TARGET_OS_OSX */
 __nullable SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
 #endif
 {
@@ -6132,8 +6055,10 @@ static void check_for_marker(const void *key, const void *value, void *context)
 
     CFDataRef key_data = SecCertificateCreateOidDataFromString(NULL, key_string);
 
-    if (!isData(key_data))
+    if (!isData(key_data)) {
+        CFReleaseNull(key_data);
         return;
+    }
 
     if (cert_contains_marker_extension_value(search_ctx->certificate, key_data, value_ref))
         search_ctx->found = true;
@@ -6715,71 +6640,76 @@ SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA256, "SignatureDigestSHA256");
 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA384, "SignatureDigestSHA284");
 SEC_CONST_DECL (kSecSignatureDigestAlgorithmSHA512, "SignatureDigestSHA512");
 
+SecSignatureHashAlgorithm SecSignatureHashAlgorithmForAlgorithmOid(const DERItem *algOid)
+{
+    SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown;
+    while (algOid) {
+        if (!algOid->data || !algOid->length) {
+            break;
+        }
+        /* classify the signature algorithm OID into one of our known types */
+        if (DEROidCompare(algOid, &oidSha512Ecdsa) ||
+            DEROidCompare(algOid, &oidSha512Rsa) ||
+            DEROidCompare(algOid, &oidSha512)) {
+            result = kSecSignatureHashAlgorithmSHA512;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidSha384Ecdsa) ||
+            DEROidCompare(algOid, &oidSha384Rsa) ||
+            DEROidCompare(algOid, &oidSha384)) {
+            result = kSecSignatureHashAlgorithmSHA384;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidSha256Ecdsa) ||
+            DEROidCompare(algOid, &oidSha256Rsa) ||
+            DEROidCompare(algOid, &oidSha256)) {
+            result = kSecSignatureHashAlgorithmSHA256;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidSha224Ecdsa) ||
+            DEROidCompare(algOid, &oidSha224Rsa) ||
+            DEROidCompare(algOid, &oidSha224)) {
+            result = kSecSignatureHashAlgorithmSHA224;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidSha1Ecdsa) ||
+            DEROidCompare(algOid, &oidSha1Rsa) ||
+            DEROidCompare(algOid, &oidSha1Dsa) ||
+            DEROidCompare(algOid, &oidSha1DsaOIW) ||
+            DEROidCompare(algOid, &oidSha1DsaCommonOIW) ||
+            DEROidCompare(algOid, &oidSha1RsaOIW) ||
+            DEROidCompare(algOid, &oidSha1Fee) ||
+            DEROidCompare(algOid, &oidSha1)) {
+            result = kSecSignatureHashAlgorithmSHA1;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidMd5Rsa) ||
+            DEROidCompare(algOid, &oidMd5Fee) ||
+            DEROidCompare(algOid, &oidMd5)) {
+            result = kSecSignatureHashAlgorithmMD5;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidMd4Rsa) ||
+            DEROidCompare(algOid, &oidMd4)) {
+            result = kSecSignatureHashAlgorithmMD4;
+            break;
+        }
+        if (DEROidCompare(algOid, &oidMd2Rsa) ||
+            DEROidCompare(algOid, &oidMd2)) {
+            result = kSecSignatureHashAlgorithmMD2;
+            break;
+        }
+        break;
+    }
+
+    return result;
+}
+
 SecSignatureHashAlgorithm SecCertificateGetSignatureHashAlgorithm(SecCertificateRef certificate)
 {
-       SecSignatureHashAlgorithm result = kSecSignatureHashAlgorithmUnknown;
        DERAlgorithmId *algId = (certificate) ? &certificate->_tbsSigAlg : NULL;
        const DERItem *algOid = (algId) ? &algId->oid : NULL;
-       while (algOid) {
-               if (!algOid->data || !algOid->length) {
-                       break;
-               }
-               /* classify the signature algorithm OID into one of our known types */
-               if (DEROidCompare(algOid, &oidSha512Ecdsa) ||
-                       DEROidCompare(algOid, &oidSha512Rsa) ||
-                       DEROidCompare(algOid, &oidSha512)) {
-                       result = kSecSignatureHashAlgorithmSHA512;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidSha384Ecdsa) ||
-                       DEROidCompare(algOid, &oidSha384Rsa) ||
-                       DEROidCompare(algOid, &oidSha384)) {
-                       result = kSecSignatureHashAlgorithmSHA384;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidSha256Ecdsa) ||
-                       DEROidCompare(algOid, &oidSha256Rsa) ||
-                       DEROidCompare(algOid, &oidSha256)) {
-                       result = kSecSignatureHashAlgorithmSHA256;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidSha224Ecdsa) ||
-                       DEROidCompare(algOid, &oidSha224Rsa) ||
-                       DEROidCompare(algOid, &oidSha224)) {
-                       result = kSecSignatureHashAlgorithmSHA224;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidSha1Ecdsa) ||
-                       DEROidCompare(algOid, &oidSha1Rsa) ||
-                       DEROidCompare(algOid, &oidSha1Dsa) ||
-                       DEROidCompare(algOid, &oidSha1DsaOIW) ||
-                       DEROidCompare(algOid, &oidSha1DsaCommonOIW) ||
-                       DEROidCompare(algOid, &oidSha1RsaOIW) ||
-                       DEROidCompare(algOid, &oidSha1Fee) ||
-                       DEROidCompare(algOid, &oidSha1)) {
-                       result = kSecSignatureHashAlgorithmSHA1;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidMd5Rsa) ||
-                       DEROidCompare(algOid, &oidMd5Fee) ||
-                       DEROidCompare(algOid, &oidMd5)) {
-                       result = kSecSignatureHashAlgorithmMD5;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidMd4Rsa) ||
-                       DEROidCompare(algOid, &oidMd4)) {
-                       result = kSecSignatureHashAlgorithmMD4;
-                       break;
-               }
-               if (DEROidCompare(algOid, &oidMd2Rsa) ||
-                       DEROidCompare(algOid, &oidMd2)) {
-                       result = kSecSignatureHashAlgorithmMD2;
-                       break;
-               }
-               break;
-       }
-
-       return result;
+    return SecSignatureHashAlgorithmForAlgorithmOid(algOid);
 }
 
 CFArrayRef SecCertificateCopyiPhoneDeviceCAChain(void) {
@@ -6833,3 +6763,25 @@ CFIndex SecCertificateGetUnparseableKnownExtension(SecCertificateRef certificate
     }
     return certificate->_unparseableKnownExtensionIndex;
 }
+
+CFArrayRef SecCertificateCopyAppleExternalRoots(void) {
+    CFMutableArrayRef result = NULL;
+    SecCertificateRef appleExternalECRoot = NULL, testAppleExternalECRoot = NULL;
+
+    require_quiet(appleExternalECRoot = SecCertificateCreateWithBytes(NULL, _AppleExternalECRootCA, sizeof(_AppleExternalECRootCA)),
+                  errOut);
+    require_quiet(testAppleExternalECRoot = SecCertificateCreateWithBytes(NULL, _TestAppleExternalECRootCA,
+                                                                          sizeof(_TestAppleExternalECRootCA)),
+                  errOut);
+
+    require_quiet(result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), errOut);
+    CFArrayAppendValue(result, appleExternalECRoot);
+    if (SecIsInternalRelease()) {
+        CFArrayAppendValue(result, testAppleExternalECRoot);
+    }
+
+errOut:
+    CFReleaseNull(appleExternalECRoot);
+    CFReleaseNull(testAppleExternalECRoot);
+    return result;
+}
index 46ea84a592c2fe36d91aee84391f0bc80708c9e0..048050e6da116a853b27600bbaba14ac0fe4055f 100644 (file)
@@ -90,6 +90,8 @@ typedef struct {
 
 __BEGIN_DECLS
 
+SecSignatureHashAlgorithm SecSignatureHashAlgorithmForAlgorithmOid(const DERItem *algOid);
+
 CFDataRef SecCertificateGetAuthorityKeyID(SecCertificateRef certificate);
 CFDataRef SecCertificateGetSubjectKeyID(SecCertificateRef certificate);
 
@@ -245,11 +247,9 @@ bool SecCertificateIsOidString(CFStringRef oid);
 
 DERItem *SecCertificateGetExtensionValue(SecCertificateRef certificate, CFTypeRef oid);
 
-CFArrayRef SecCertificateCopyDNSNamesFromSubject(SecCertificateRef certificate);
-CFArrayRef SecCertificateCopyIPAddressesFromSubject(SecCertificateRef certificate);
 CFArrayRef SecCertificateCopyRFC822NamesFromSubject(SecCertificateRef certificate);
-
 CFArrayRef SecCertificateCopyDNSNamesFromSAN(SecCertificateRef certificate);
+CFArrayRef SecCertificateCopyIPAddressDatas(SecCertificateRef certificate);
 
 CFIndex SecCertificateGetUnparseableKnownExtension(SecCertificateRef certificate);
 
index dad68a9e7f2704173dedac649663ff07896b40b1..0d19b393536e04cc416cf7ac5c6c250ccc4304e2 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2008-2009,2012-2017 Apple Inc. All Rights Reserved.
- * 
+ * Copyright (c) 2008-2009,2012-2020 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,
@@ -17,7 +17,7 @@
  * 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@
  *
  */
@@ -111,7 +111,7 @@ static uint8_t * mod128_oid_encoding_ptr(uint8_t *ptr, uint32_t src, bool final)
 {
     if (src > 128)
         ptr = mod128_oid_encoding_ptr(ptr, src / 128, false);
-    
+
     unsigned char octet = src % 128;
     if (!final)
         octet |= 128;
@@ -170,16 +170,16 @@ Consider using IA5String for email address
 static inline bool printable_string(CFStringRef string)
 {
     bool result = true;
-    
-    CFCharacterSetRef printable_charset = 
+
+    CFCharacterSetRef printable_charset =
         CFCharacterSetCreateWithCharactersInString(kCFAllocatorDefault,
             CFSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                     "abcdefghijklmnopqrstuvwxyz"
                     "0123456789 '()+,-./:=?"));
-    CFCharacterSetRef not_printable_charset = 
+    CFCharacterSetRef not_printable_charset =
         CFCharacterSetCreateInvertedSet(kCFAllocatorDefault, printable_charset);
     CFRange found;
-    if (CFStringFindCharacterFromSet(string, not_printable_charset, 
+    if (CFStringFindCharacterFromSet(string, not_printable_charset,
         CFRangeMake(0, CFStringGetLength(string)), 0, &found))
             result = false;
 
@@ -189,7 +189,7 @@ static inline bool printable_string(CFStringRef string)
     return result;
 }
 
-static bool make_nss_atv(PRArenaPool *poolp, 
+static bool make_nss_atv(PRArenaPool *poolp,
     CFTypeRef oid, const void * value, const unsigned char type_in, NSS_ATV *nss_atv)
 {
     size_t length = 0;
@@ -210,7 +210,7 @@ static bool make_nss_atv(PRArenaPool *poolp,
         else {
             if (!type || type == SecASN1PrintableString) {
                 if (!printable_string(value))
-                    type = SEC_ASN1_IA5_STRING;
+                    type = SEC_ASN1_UTF8_STRING;
                 else
                     type = SEC_ASN1_PRINTABLE_STRING;
             }
@@ -245,8 +245,8 @@ static bool make_nss_atv(PRArenaPool *poolp,
         /* will remain valid for the duration of the operation, still maybe copy into pool */
         oid_length = CFDataGetLength(oid);
         oid_data = (uint8_t *)CFDataGetBytePtr(oid);
-    }    
-    NSS_ATV stage_nss_atv = { { oid_length, oid_data }, 
+    }
+    NSS_ATV stage_nss_atv = { { oid_length, oid_data },
         { { length, (uint8_t*)buffer }, type } };
     *nss_atv = stage_nss_atv;
     return true;
@@ -270,7 +270,7 @@ static NSS_RDN **make_subject(PRArenaPool *poolp, CFArrayRef subject)
         for (atv_ix = 0; atv_ix < atv_count; atv_ix++) {
             rdns[rdn_ix].atvs[atv_ix] = &atvs[atv_ix];
             CFArrayRef atv = CFArrayGetValueAtIndex(rdn, atv_ix);
-            if ((CFArrayGetCount(atv) != 2) 
+            if ((CFArrayGetCount(atv) != 2)
                 || !make_nss_atv(poolp, CFArrayGetValueAtIndex(atv, 0),
                         CFArrayGetValueAtIndex(atv, 1), 0, &atvs[atv_ix]))
                 return NULL;
@@ -302,7 +302,7 @@ static void make_general_names(const void *key, const void *value, void *context
     }
 
     require(entry_count > 0, out);
-    
+
     require(key,out);
     require(CFGetTypeID(key) == CFStringGetTypeID(), out);
 
@@ -312,7 +312,7 @@ static void make_general_names(const void *key, const void *value, void *context
             capacity *= 2;
         else
             capacity = 10;
-        
+
         void * new_array = PORT_ArenaZNewArray(gn->poolp, SecAsn1Item, capacity);
         if (gn->names)
             memcpy(new_array, gn->names, gn->capacity);
@@ -389,7 +389,7 @@ static void make_general_names(const void *key, const void *value, void *context
        }
        else
         goto out;
-    
+
     if (gn_values) {
         for (entry_ix = 0; entry_ix < entry_count; entry_ix++) {
             CFTypeRef entry_value = CFArrayGetValueAtIndex(gn_values, entry_ix);
@@ -419,7 +419,7 @@ out:
 static SecAsn1Item make_subjectAltName_extension(PRArenaPool *poolp, CFDictionaryRef subjectAltNames)
 {
     SecAsn1Item subjectAltExt = {};
-    
+
     struct make_general_names_context context = { poolp, NULL, 0 };
     CFDictionaryApplyFunction(subjectAltNames, make_general_names, &context);
 
@@ -498,7 +498,7 @@ extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
     if (basic_contraints_num) {
         NSS_BasicConstraints basic_contraints = { asn1_true, {} };
         uint8_t path_len;
-        
+
         int basic_contraints_path_len = 0;
         require(CFNumberGetValue(basic_contraints_num, kCFNumberIntType, &basic_contraints_path_len), out);
         if (basic_contraints_path_len >= 0 && basic_contraints_path_len < 256) {
@@ -506,12 +506,12 @@ extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
             basic_contraints.pathLenConstraint.Length = sizeof(path_len);
             basic_contraints.pathLenConstraint.Data = &path_len;
         }
-        
+
         csr_extension[num_extensions].extnId.Data = oidBasicConstraints.data;
         csr_extension[num_extensions].extnId.Length = oidBasicConstraints.length;
         csr_extension[num_extensions].critical = asn1_true;
-        
-        SEC_ASN1EncodeItem(poolp, &csr_extension[num_extensions].value, &basic_contraints, 
+
+        SEC_ASN1EncodeItem(poolp, &csr_extension[num_extensions].value, &basic_contraints,
             kSecAsn1BasicConstraintsTemplate);
         require(num_extensions++ < max_extensions, out);
     }
@@ -532,7 +532,7 @@ extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
         int key_usage_value;
         require(CFNumberGetValue(key_usage_requested, kCFNumberIntType, &key_usage_value), out);
         if (key_usage_value > 0) {
-            uint32_t key_usage_value_be = 0, key_usage_mask = 1<<31;
+            uint32_t key_usage_value_be = 0, key_usage_mask = (uint32_t)0x80000000; // 1L<<31
             uint32_t key_usage_value_max_bitlen = 9, key_usage_value_bitlen = 0;
             while(key_usage_value_max_bitlen) {
                 if (key_usage_value & 1) {
@@ -544,7 +544,7 @@ extensions_from_parameters(PRArenaPool *poolp, CFDictionaryRef parameters)
                 key_usage_mask >>= 1;
             }
 
-            SecAsn1Item key_usage_input = { key_usage_value_bitlen, 
+            SecAsn1Item key_usage_input = { key_usage_value_bitlen,
                 ((uint8_t*)&key_usage_value_be) + 3 - (key_usage_value_bitlen >> 3) };
             SEC_ASN1EncodeItem(poolp, &key_usage_asn1_value, &key_usage_input, kSecAsn1BitStringTemplate);
 
@@ -603,14 +603,14 @@ NSS_Attribute **nss_attributes_from_parameters_dict(PRArenaPool *poolp, CFDictio
        whenever possible.  If internationalization issues make this
        impossible, the UTF8String alternative SHOULD be used.  PKCS #9-
        attribute processing systems MUST be able to recognize and process
-       all string types in DirectoryString values. 
-       
+       all string types in DirectoryString values.
+
        Upperbound of 255 defined for all PKCS#9 attributes.
-       
+
        pkcs-9 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840)
                                         rsadsi(113549) pkcs(1) 9}
        pkcs-9-at-challengePassword   OBJECT IDENTIFIER ::= {pkcs-9 7}
-       
+
     */
     if (!parameters)
         return NULL;
@@ -631,11 +631,11 @@ NSS_Attribute **nss_attributes_from_parameters_dict(PRArenaPool *poolp, CFDictio
             if (!printable_string(challenge))
                 utf8 = true;
 
-        SecAsn1Item *challenge_password_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);        
+        SecAsn1Item *challenge_password_value = PORT_ArenaZNewArray(poolp, SecAsn1Item, 1);
         SecAsn1Item challenge_password_raw = { strlen(buffer), (uint8_t*)buffer };
-        SEC_ASN1EncodeItem(poolp, challenge_password_value, &challenge_password_raw, 
+        SEC_ASN1EncodeItem(poolp, challenge_password_value, &challenge_password_raw,
             utf8 ? kSecAsn1UTF8StringTemplate : kSecAsn1PrintableStringTemplate);
-        SecAsn1Item **challenge_password_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);        
+        SecAsn1Item **challenge_password_values = PORT_ArenaZNewArray(poolp, SecAsn1Item *, 2);
         challenge_password_values[0] = challenge_password_value;
         challenge_password_attr.attrType.Length = sizeof(pkcs9ChallengePassword);
         challenge_password_attr.attrType.Data = (uint8_t*)&pkcs9ChallengePassword;
@@ -656,7 +656,7 @@ NSS_Attribute **nss_attributes_from_parameters_dict(PRArenaPool *poolp, CFDictio
         extensions_requested_attr.attrValue = extensions_requested_values;
         num_attrs++;
     }
-    
+
     NSS_Attribute **attributes_ptr = PORT_ArenaZNewArray(poolp, NSS_Attribute *, num_attrs + 1);
     NSS_Attribute *attributes = PORT_ArenaZNewArray(poolp, NSS_Attribute, num_attrs);
     if (challenge_password_attr.attrType.Length) {
@@ -783,7 +783,7 @@ static CF_RETURNS_RETAINED CFDataRef make_signature (void *data_pointer, size_t
     return signature;
 }
 
-CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject, 
+CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
     CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
 {
     if (subject == NULL || *subject == NULL) {
@@ -796,12 +796,13 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
     SecKeyRef realPublicKey = NULL; /* We calculate this from the private key rather than
                                      * trusting the caller to give us the right one. */
     PRArenaPool *poolp = PORT_NewArena(1024);
-    
-    if (!poolp)
+
+    if (!poolp) {
         return NULL;
+    }
 
-       NSSCertRequest certReq;
-       memset(&certReq, 0, sizeof(certReq));
+    NSSCertRequest certReq;
+    memset(&certReq, 0, sizeof(certReq));
 
     /* version */
     unsigned char version = 0;
@@ -831,7 +832,7 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
         rdnps[rdn_num] = &rdns[rdn_num];
         rdn_num++;
         for (one_atv = *one_rdn; one_atv->oid; one_atv++) {
-            if (!make_nss_atv(poolp, one_atv->oid, one_atv->value, 
+            if (!make_nss_atv(poolp, one_atv->oid, one_atv->value,
                     one_atv->type, &atvs[atv_num]))
                 goto out;
             atvps[atv_num] = &atvs[atv_num];
@@ -841,7 +842,7 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
     }
     rdnps[rdn_num] = NULL;
     certReq.reqInfo.subject.rdns = rdnps;
-    
+
     /* public key info */
     realPublicKey = SecKeyCopyPublicKey(privateKey);
     if (!realPublicKey) {
@@ -852,7 +853,7 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
     require_quiet(realPublicKey, out);
     publicKeyData = make_public_key(realPublicKey, &certReq.reqInfo.subjectPublicKeyInfo, &allocated_parameters);
     require_quiet(publicKeyData, out);
-    
+
     certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
     SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
 
@@ -869,13 +870,13 @@ CFDataRef SecGenerateCertificateRequestWithParameters(SecRDN *subject,
     require_quiet(signature, out);
     certReq.signature.Data = (uint8_t *)CFDataGetBytePtr(signature);
     certReq.signature.Length = 8 * CFDataGetLength(signature);
-    
+
     /* encode csr */
     SecAsn1Item cert_request = {};
-    require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq, 
+    require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
         kSecAsn1CertRequestTemplate), out);
     csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
-    
+
 out:
     if (allocated_parameters) {
         free(certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Data);
@@ -892,7 +893,7 @@ out:
     return csr;
 }
 
-CFDataRef SecGenerateCertificateRequest(CFArrayRef subject, 
+CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
     CFDictionaryRef parameters, SecKeyRef publicKey, SecKeyRef privateKey)
 {
     CFDataRef csr = NULL;
@@ -901,12 +902,13 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
     SecKeyRef realPublicKey = NULL; /* We calculate this from the private key rather than
                                      * trusting the caller to give us the right one. */
     bool allocated_parameters = false;
-    
-    if (!poolp)
+
+    if (!poolp) {
         return NULL;
+    }
 
-       NSSCertRequest certReq;
-       memset(&certReq, 0, sizeof(certReq));
+    NSSCertRequest certReq;
+    memset(&certReq, 0, sizeof(certReq));
 
     /* version */
     unsigned char version = 0;
@@ -915,7 +917,7 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
 
     /* subject */
     certReq.reqInfo.subject.rdns = make_subject(poolp, (CFArrayRef)subject);
-    
+
     /* public key info */
     realPublicKey = SecKeyCopyPublicKey(privateKey);
     if (!realPublicKey) {
@@ -926,7 +928,7 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
     require_quiet(realPublicKey, out);
     publicKeyData = make_public_key(realPublicKey, &certReq.reqInfo.subjectPublicKeyInfo, &allocated_parameters);
     require_quiet(publicKeyData, out);
-    
+
     certReq.reqInfo.attributes = nss_attributes_from_parameters_dict(poolp, parameters);
     SecCmsArraySortByDER((void **)certReq.reqInfo.attributes, kSecAsn1AttributeTemplate, NULL);
 
@@ -943,13 +945,13 @@ CFDataRef SecGenerateCertificateRequest(CFArrayRef subject,
     require_quiet(signature, out);
     certReq.signature.Data = (uint8_t *)CFDataGetBytePtr(signature);
     certReq.signature.Length = 8 * CFDataGetLength(signature);
-    
+
     /* encode csr */
     SecAsn1Item cert_request = {};
-    require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq, 
+    require_quiet(SEC_ASN1EncodeItem(poolp, &cert_request, &certReq,
         kSecAsn1CertRequestTemplate), out);
     csr = CFDataCreate(kCFAllocatorDefault, cert_request.Data, cert_request.Length);
-    
+
 out:
     if (allocated_parameters) {
         free(certReq.reqInfo.subjectPublicKeyInfo.algorithm.parameters.Data);
@@ -1057,9 +1059,9 @@ bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef *publicKey,
                                        undecodedCertReq.certRequestBlob.Length, kCFAllocatorNull);
     require_quiet(alg && signature && data, out);
     require_quiet(SecKeyVerifySignature(candidatePublicKey, alg, data, signature, NULL), out);
-        
+
     SecAsn1Item subject_item = { 0 }, extensions_item = { 0 }, challenge_item = { 0 };
-    require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item, 
+    require_quiet(SEC_ASN1EncodeItem(poolp, &subject_item,
         &decodedCertReq.reqInfo.subject, kSecAsn1NameTemplate), out);
 
     if (*decodedCertReq.reqInfo.attributes) {
@@ -1074,7 +1076,7 @@ bool SecVerifyCertificateRequest(CFDataRef csr, SecKeyRef *publicKey,
                     extensions_item = *attr->attrValue[0];
         }
     }
-    
+
     if (subject && subject_item.Length)
         *subject = CFDataCreate(kCFAllocatorDefault, subject_item.Data, subject_item.Length);
     if (extensions && extensions_item.Length)
@@ -1105,19 +1107,19 @@ out:
     return valid;
 }
 
-#define HIDIGIT(v) (((v) / 10) + '0')    
-#define LODIGIT(v) (((v) % 10) + '0')     
+#define HIDIGIT(v) (((v) / 10) + '0')
+#define LODIGIT(v) (((v) % 10) + '0')
 
 static OSStatus
 DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTime)
 {
     unsigned char *d;
-    
+
     utcTime->Length = 13;
     utcTime->Data = d = PORT_ArenaAlloc(poolp, 13);
     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) {
@@ -1125,15 +1127,15 @@ DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTi
     });
     if (!result)
         return SECFailure;
-    
+
     /* UTC time does not handle the years before 1950 */
     if (year < 1950)
         return SECFailure;
-    
+
     /* remove the century since it's added to the year by the
      CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
     year %= 100;
-    
+
     d[0] = HIDIGIT(year);
     d[1] = LODIGIT(year);
     d[2] = HIDIGIT(month);
@@ -1151,7 +1153,7 @@ DER_CFDateToUTCTime(PRArenaPool *poolp, CFAbsoluteTime date, SecAsn1Item * utcTi
 }
 
 SecCertificateRef
-SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters, 
+SecGenerateSelfSignedCertificate(CFArrayRef subject, CFDictionaryRef parameters,
     SecKeyRef __unused publicKey, SecKeyRef privateKey)
 {
     SecCertificateRef cert = NULL;
@@ -1276,7 +1278,7 @@ SecIdentitySignCertificateWithAlgorithm(SecIdentityRef issuer, CFDataRef serialn
     require_noerr(SecIdentityCopyCertificate(issuer, &issuer_cert), out);
     CFDataRef issuer_name = SecCertificateCopySubjectSequence(issuer_cert);
     SecAsn1Item issuer_item = { CFDataGetLength(issuer_name), (uint8_t*)CFDataGetBytePtr(issuer_name) };
-    require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.issuer.rdns, 
+    require_noerr_action_quiet(SEC_ASN1DecodeItem(poolp, &cert_tmpl.tbs.issuer.rdns,
         kSecAsn1NameTemplate, &issuer_item), out, CFReleaseNull(issuer_name));
     CFReleaseNull(issuer_name);
 
index 0f5689e03de633406a9a1f62add7708be58537ea..ecd60a526d8ad7b9d4adb94c9e2cb5f7afed0ccd 100644 (file)
 
 static inline ccdh_gp_t SecDH_gp(SecDHContext dh)
 {
-    return  (ccdh_gp_t)dh;
+    return (ccdh_gp_t)dh;
 }
 
 static inline ccdh_full_ctx_t SecDH_priv(SecDHContext dh)
 {
     ccdh_gp_t gp = SecDH_gp(dh);
     cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
-    ccdh_full_ctx_t priv = (ccdh_full_ctx_t)((char *) dh + ccdh_gp_size(s));
-    return priv;
+    return (ccdh_full_ctx_t)cc_pad_align((uintptr_t)dh + ccdh_gp_size(s));
 }
 
 size_t SecDHGetMaxKeyLength(SecDHContext dh) {
 
     ccdh_gp_t gp = SecDH_gp(dh);
-    cc_size s = ccn_sizeof_n(ccdh_gp_n(gp));
-
-    return s;
+    return ccn_sizeof_n(ccdh_gp_n(gp));
 }
 
-
 static inline size_t SecDH_context_size(size_t p_len)
 {
-    cc_size n = ccn_nof_size(p_len);
-    cc_size real_p_len = ccn_sizeof_n(n);
-    size_t context_size = ccdh_gp_size(real_p_len)+ccdh_full_ctx_size(real_p_len);
-    return context_size;
+    cc_size real_p_len = ccn_sizeof_size(p_len);
+
+    // Add padding to allow proper alignment of the ccdh_full_ctx.
+    return ccdh_gp_size(real_p_len) + (CC_MAX_ALIGNMENT - 1) + ccdh_full_ctx_size(real_p_len);
 }
 
 /* Shared static functions. */
@@ -210,7 +205,7 @@ OSStatus SecDHCreateFromParameters(const uint8_t *params,
     }
     cc_size n = ccn_nof_size(decodedParams.p.length);
     cc_size p_len = ccn_sizeof_n(n);
-    size_t context_size = ccdh_gp_size(p_len)+ccdh_full_ctx_size(p_len);
+    size_t context_size = SecDH_context_size(p_len);
     void *context = malloc(context_size);
     if(context==NULL)
         return errSecAllocate;
index 4e9b26d64a5b2d8d99dbb895784e66d324b13eb5..5b343f6b2844274caf7c339cb5c479f5236c5528 100644 (file)
@@ -96,6 +96,10 @@ static ccoid_t ccoid_secp224r1 = CC_EC_OID_SECP224R1;
 static ccoid_t ccoid_secp384r1 = CC_EC_OID_SECP384R1;
 static ccoid_t ccoid_secp521r1 = CC_EC_OID_SECP521R1;
 
+// <rdar://problem/66864716> OID_CERTICOM is wrong
+static ccoid_t ccoid_libder_secp384r1 = ((unsigned char *)"\x06\x04\x2B\x84\x00\x22");
+static ccoid_t ccoid_libder_secp521r1 = ((unsigned char *)"\x06\x04\x2B\x84\x00\x23");
+
 static ccec_const_cp_t ccec_cp_for_oid(const unsigned char *oid)
 {
     if (oid!=NULL) {
@@ -105,9 +109,9 @@ static ccec_const_cp_t ccec_cp_for_oid(const unsigned char *oid)
             return ccec_cp_256();
         } else if (ccoid_equal(oid, ccoid_secp224r1)) {
             return ccec_cp_224();
-        } else if (ccoid_equal(oid, ccoid_secp384r1)) {
+        } else if (ccoid_equal(oid, ccoid_secp384r1) || ccoid_equal(oid, ccoid_libder_secp384r1)) {
             return ccec_cp_384();
-        } else if (ccoid_equal(oid, ccoid_secp521r1)) {
+        } else if (ccoid_equal(oid, ccoid_secp521r1) || ccoid_equal(oid, ccoid_libder_secp521r1)) {
             return ccec_cp_521();
         }
     }
@@ -128,10 +132,11 @@ static OSStatus SecECPublicKeyInit(SecKeyRef key,
             break;
         }
 
-        ccec_const_cp_t cp = getCPForPublicSize(derKey->keyLength);
+        require_action_quiet(derKey->parameters && derKey->parametersLength > 2 &&
+                             derKey->parameters[1] <= derKey->parametersLength - 2, errOut, err = errSecDecode);
+        ccec_const_cp_t cp = ccec_cp_for_oid(derKey->parameters);
         require_action_quiet(cp, errOut, err = errSecDecode);
 
-        /* TODO: Parse and use real params from passed in derKey->algId.params */
         err = (ccec_import_pub(cp, derKey->keyLength, derKey->key, pubkey)
                ? errSecDecode : errSecSuccess);
         break;
index d5f821526ff8e006318b8bde7fafad43d28a093d..2320866d38245a6487b820312c0486671b1b30d2 100644 (file)
@@ -71,7 +71,6 @@ __P_DO_EXPORT_##ISPUBLIC(NAME)
 #if TARGET_OS_OSX
 _kSecPolicyAppleiChat
 #endif
-_kSecPolicyAppleIDValidationRecordSigningPolicy
 _kSecPolicyMacAppStoreReceipt
 _kSecPolicyNameAppleAIDCService
 _kSecPolicyNameAppleAMPService
@@ -87,6 +86,7 @@ _kSecPolicyNameAppleIDSService
 _kSecPolicyNameAppleMapsService
 _kSecPolicyNameAppleMMCSService
 _kSecPolicyNameAppleParsecService
+_kSecPolicyNameApplePushCertPortal
 _kSecPolicyNameApplePPQService
 _kSecPolicyNameApplePushService
 _kSecPolicyNameAppleSiriService
@@ -138,6 +138,9 @@ _kSecPolicyKU_NonRepudiation
 #endif
 
 _SecDNSIsTLD
+_CreateCFDataFromBase64CFString
+_parseNSPinnedDomains
+_SecPolicyReconcilePinningRequiredIfInfoSpecified
 
 #undef POLICYCHECKMACRO
 #define __PC_DO_EXPORT_(NAME)
@@ -157,7 +160,6 @@ _SecPolicySetName
 _SecPolicySetOptionsValue
 #if TARGET_OS_OSX
 _SecPolicyCopy
-_SecPolicyCopyAll
 _SecPolicyCreateAppleTimeStampingAndRevocationPolicies
 _SecPolicyCreateItemImplInstance
 _SecPolicyCreateWithOID
@@ -222,6 +224,7 @@ _SecTrustCopyFailureDescription
 _SecTrustCopyFilteredDetails
 _SecTrustCopyInfo
 _SecTrustCopyInputCertificates
+_SecTrustCopyKey
 _SecTrustCopyPolicies
 _SecTrustCopyProperties
 _SecTrustCopyPublicKey
@@ -267,6 +270,7 @@ _SecTrustSetPolicies
 _SecTrustSetSignedCertificateTimestamps
 _SecTrustSetTrustedLogs
 _SecTrustSetVerifyDate
+_SecTrustTriggerValidUpdate
 #if TARGET_OS_OSX
 _SecTrustCopyAnchorCertificates
 _SecTrustCopyExtendedResult
@@ -292,15 +296,18 @@ _SecTrustSettingsCopyCertificatesForUserAdminDomains
 _SecTrustSettingsCopyModificationDate
 _SecTrustSettingsCopyQualifiedCerts
 _SecTrustSettingsCopyTrustSettings
+_SecTrustSettingsCopyTrustSettings_Cached
 _SecTrustSettingsCopyUnrestrictedRoots
 _SecTrustSettingsCreateExternalRepresentation
 _SecTrustSettingsEvaluateCert
 _SecTrustSettingsImportExternalRepresentation
+_SecTrustSettingsPurgeCache
 _SecTrustSettingsPurgeUserAdminCertsCache
 _SecTrustSettingsRemoveTrustSettings
 _SecTrustSettingsSetTrustSettings
 _SecTrustSettingsSetTrustSettingsExternal
 _SecTrustSettingsSetTrustedCertificateForSSLHost
+_SecTrustSettingsUserAdminDomainsContain
 _SecTrustedApplicationCopyData
 _SecTrustedApplicationCopyExternalRepresentation
 _SecTrustedApplicationCopyRequirement
@@ -318,7 +325,6 @@ _SecTrustedApplicationValidateWithPath
 
 #endif
 
-#if TARGET_OS_IPHONE
 _SecTrustStoreContains
 _SecTrustStoreCopyAll
 _SecTrustStoreCopyUsageConstraints
@@ -327,15 +333,21 @@ _SecTrustStoreGetSettingsVersionNumber
 _SecTrustStoreGetSettingsAssetVersionNumber
 _SecTrustStoreRemoveCertificate
 _SecTrustStoreSetTrustSettings
+#if TARGET_OS_IPHONE
 _SecTrustGetExceptionResetCount
 _SecTrustIncrementExceptionResetCount
 #endif
 _SecTrustStoreSetCTExceptions
 _SecTrustStoreCopyCTExceptions
+_SecTrustStoreSetCARevocationAdditions
+_SecTrustStoreCopyCARevocationAdditions
 _kSecCTExceptionsCAsKey
 _kSecCTExceptionsDomainsKey
 _kSecCTExceptionsHashAlgorithmKey
 _kSecCTExceptionsSPKIHashKey
+_kSecCARevocationAdditionsKey
+_kSecCARevocationHashAlgorithmKey
+_kSecCARevocationSPKIHashKey
 
 //
 // Identity
@@ -355,6 +367,7 @@ _kSecCertificateDetailSHA1Digest
 _kSecCertificateEscrowFileName
 _kSecCertificateProductionEscrowKey
 _kSecCertificateProductionPCSEscrowKey
+_SecCertificateCopyAppleExternalRoots
 _SecCertificateCopyAttributeDictionary
 _SecCertificateCopyCommonName
 _SecCertificateCopyCommonNames
@@ -364,7 +377,6 @@ _SecCertificateCopyCountry
 _SecCertificateCopyCTLogForKeyID
 _SecCertificateCopyDNSNames
 _SecCertificateCopyDNSNamesFromSAN
-_SecCertificateCopyDNSNamesFromSubject
 _SecCertificateCopyData
 _SecCertificateCopyEmailAddresses
 _SecCertificateCopyEscrowRoots
@@ -372,8 +384,8 @@ _SecCertificateCopyExtendedKeyUsage
 _SecCertificateCopyExtensionValue
 _SecCertificateCopyiAPAuthCapabilities
 _SecCertificateCopyiAPSWAuthCapabilities
+_SecCertificateCopyIPAddressDatas
 _SecCertificateCopyIPAddresses
-_SecCertificateCopyIPAddressesFromSubject
 _SecCertificateCopyiPhoneDeviceCAChain
 _SecCertificateCopyIssuerSHA1Digest
 _SecCertificateCopyIssuerSequence
@@ -391,13 +403,20 @@ _SecCertificateCopyOrganizationalUnit
 _SecCertificateCopyPrecertTBS
 _SecCertificateCopyProperties
 _SecCertificateCopyPublicKey
+#if TARGET_OS_OSX && TARGET_CPU_ARM64
+_SecCertificateCopyPublicKey$LEGACYMAC
+#endif
 _SecCertificateCopyPublicKeySHA1Digest
 _SecCertificateCopyRFC822Names
 _SecCertificateCopyRFC822NamesFromSubject
 _SecCertificateCopySerialNumber
 _SecCertificateCopySerialNumberData
+#if TARGET_OS_OSX && TARGET_CPU_ARM64
+_SecCertificateCopySerialNumber$LEGACYMAC
+#endif
 _SecCertificateCopySHA256Digest
 _SecCertificateCopySignedCertificateTimestamps
+_SecCertificateCopySubjectAttributeValue
 _SecCertificateCopySubjectPublicKeyInfoSHA1Digest
 _SecCertificateCopySubjectPublicKeyInfoSHA256Digest
 _SecCertificateCopySubjectSequence
@@ -462,6 +481,7 @@ _SecCertificateShow
 _SecCertificateVersion
 _SecDistinguishedNameCopyNormalizedContent
 _SecDistinguishedNameCopyNormalizedSequence
+_SecSignatureHashAlgorithmForAlgorithmOid
 
 _SecCertificateArrayCopyXPCArray
 _SecCertificateAppendToXPCArray
@@ -504,16 +524,6 @@ _SecCertificateSetPreference
 _SecCertificateSetPreferred
 #endif
 
-//
-// CertificateBundle
-//
-
-#if TARGET_OS_OSX
-_SecCertifcateBundleExport
-_SecCertificateBundleExport
-_SecCertificateBundleImport
-#endif /* TARGET_OS_OSX */
-
 #if TARGET_OS_IPHONE
 //
 // SCEP
@@ -561,7 +571,6 @@ _SecGenerateCertificateRequestSubject
 //
 
 _SecOTRPacketTypeString
-_SecOTRSEndSession
 _SecOTRSPrecalculateKeys
 _SecOTRSessionCreateRemote
 _SecOTRSessionProcessPacketRemote
@@ -621,6 +630,7 @@ _AES_CTR_IV0_Transform
 
 _SecOTRSessionIsSessionInAwaitingState
 _SecOTRFullIdentityCreateFromSecKeyRef
+_SecOTRFullIdentityCreateFromSecKeyRefSOS
 _SecOTRSIsForKeys
 _SecOTRPublicIdentityCreateFromSecKeyRef
 _SecOTRSAppendRestartPacket
@@ -1526,6 +1536,13 @@ _kSecAttrPCSPlaintextPublicKey
 _kSecAttrPCSPlaintextPublicIdentity
 _kSecAttrSHA1
 
+_kSecDataInetExtraNotes
+_kSecDataInetExtraHistory
+_kSecDataInetExtraClientDefined0
+_kSecDataInetExtraClientDefined1
+_kSecDataInetExtraClientDefined2
+_kSecDataInetExtraClientDefined3
+
 #include "keychain/SecureObjectSync/SOSViews.exp-in"
 
 _kSecClass
@@ -1566,7 +1583,6 @@ _kSecReturnPersistentRef
 _kSecReturnRef
 _SecItemAdd
 _SecItemCertificateExists
-_SecItemCopyDisplayNames
 _SecItemCopyMatching
 _SecItemCopyParentCertificates_ios
 _SecItemDelete
@@ -1595,18 +1611,18 @@ __SecKeychainWriteBackupToFileDescriptor
 __SecKeychainCopyKeybagUUIDFromFileDescriptor
 
 _SecItemBackupWithRegisteredBackups
+_SecItemBackupWithRegisteredViewBackup
 _SecItemBackupSetConfirmedManifest
 _SecItemBackupRestore
 _SecBackupKeybagAdd
 _SecBackupKeybagDelete
-_SecItemBackupCopyMatching
 _SecItemBackupCreateManifest
 _SecItemBackupWithChanges
 _SecBackupKeybagAdd
 _SecBackupKeybagDelete
 
 __SecKeychainRollKeys
-#if TARGET_OS_IPHONE
+#if TARGET_OS_IPHONE || TARGET_OS_OSX || TARGET_OS_MACCATALYST
 
 _SecAddSharedWebCredential
 _SecRequestSharedWebCredential
@@ -1620,7 +1636,7 @@ __SecSecuritydCopyWhoAmI
 __SecSyncBubbleTransfer
 __SecSystemKeychainTransfer
 __SecSyncDeleteUserViews
-_SecItemUpdateTokenItems
+_SecItemUpdateTokenItemsForAccessGroups
 _SecItemDeleteAllWithAccessGroups
 _SecTokenItemValueCopy
 
@@ -1647,6 +1663,7 @@ _SecCopyDecryptedForServer
 _sSecDERErrorDomain
 _der_sizeof_plist
 _der_encode_plist
+_der_encode_plist_repair
 _der_decode_plist
 _CFPropertyListCreateDERData
 _CFPropertyListCreateWithDERData
@@ -1746,10 +1763,9 @@ _sec_protocol_options_access_handle
 _sec_protocol_metadata_access_handle
 _sec_protocol_metadata_get_server_name
 _sec_protocol_options_set_output_handler_access_block
-_sec_protocol_options_set_tls_SIKE503_exchange_enabled
-_sec_protocol_options_set_tls_HRSS_exchange_enabled
 _sec_protocol_options_set_eddsa_enabled
 _sec_protocol_options_set_tls_grease_enabled
+_sec_protocol_options_set_allow_unknown_alpn_protos
 _sec_protocol_options_set_tls_delegated_credentials_enabled
 _sec_protocol_options_set_tls_ticket_request_count
 _sec_protocol_options_set_local_certificates
@@ -1763,6 +1779,8 @@ _sec_protocol_options_set_quic_transport_parameters
 _sec_protocol_options_set_session_state
 _sec_protocol_options_set_session_update_block
 _sec_protocol_options_add_tls_application_protocol
+_sec_protocol_options_add_transport_specific_application_protocol
+_sec_protocol_options_copy_transport_specific_application_protocol
 _sec_protocol_options_append_tls_ciphersuite
 _sec_protocol_options_append_tls_ciphersuite_group
 _sec_protocol_options_add_tls_ciphersuite
@@ -1789,6 +1807,7 @@ _sec_protocol_options_set_tls_is_fallback_attempt
 _sec_protocol_options_set_verify_block
 _sec_protocol_options_set_tls_diffie_hellman_parameters
 _sec_protocol_options_set_peer_authentication_required
+_sec_protocol_options_set_peer_authentication_optional
 _sec_protocol_options_set_experiment_identifier
 _sec_protocol_metadata_get_experiment_identifier
 _sec_protocol_options_create_config
@@ -1813,6 +1832,7 @@ _sec_protocol_configuration_tls_required_for_address
 _sec_protocol_configuration_builder_create
 _sec_protocol_configuration_create_with_builder
 _sec_protocol_options_set_tls_encryption_secret_update_block
+_sec_protocol_options_set_tls_encryption_level_update_block
 _sec_protocol_options_append_tls_key_exchange_group
 _sec_protocol_options_append_tls_key_exchange_group_set
 _sec_protocol_options_add_tls_key_exchange_group
@@ -1829,6 +1849,11 @@ _sec_protocol_metadata_access_pre_shared_keys
 _sec_protocol_metadata_copy_connection_id
 _sec_protocol_options_set_pre_shared_key_selection_block
 _sec_protocol_helper_ciphersuite_group_to_ciphersuite_list
+_sec_protocol_helper_ciphersuite_group_contains_ciphersuite
+_sec_protocol_helper_ciphersuite_minimum_TLS_version
+_sec_protocol_helper_ciphersuite_maximum_TLS_version
+_sec_protocol_helper_get_ciphersuite_name
+_sec_protocol_options_set_tls_block_length_padding
 _sec_release
 _sec_retain
 _sec_trust_copy_ref
@@ -1853,7 +1878,3 @@ _sec_experiment_set_sampling_disabled
 _SSLCiphersuiteGroupToCiphersuiteList
 _SSLCiphersuiteMaximumTLSVersion
 _SSLCiphersuiteMinimumTLSVersion
-
-#if __OBJC2__ && (TARGET_OS_IPHONE || (TARGET_OS_OSX && __x86_64__))
-_OBJC_CLASS_$_SFSignInAnalytics
-#endif //__OBJC2__ && IPHONE || OSX
index b054999d3eb47d545b791e2baaaaf674311fc76c..909ec7f9dba5b5eea7cc20be011c62c6d1553e49 100644 (file)
 #endif
 
 #include "SecFramework.h"
-#include <dispatch/dispatch.h>
 #include <CoreFoundation/CFBundle.h>
-#include <CoreFoundation/CFURLAccess.h>
-#include <Security/SecRandom.h>
-#include <CommonCrypto/CommonRandomSPI.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <utilities/debugging.h>
 #include <utilities/SecCFWrappers.h>
-#include <Security/SecBase.h>
-#include <inttypes.h>
 
 /* Security.framework's bundle id. */
 #if TARGET_OS_IPHONE
@@ -64,19 +54,3 @@ CFStringRef SecFrameworkCopyLocalizedString(CFStringRef key,
 
     return CFRetainSafe(key);
 }
-
-CFURLRef SecFrameworkCopyResourceURL(CFStringRef resourceName,
-       CFStringRef resourceType, CFStringRef subDirName) {
-    CFURLRef url = NULL;
-    CFBundleRef bundle = SecFrameworkGetBundle();
-    if (bundle) {
-        url = CFBundleCopyResourceURL(bundle, resourceName,
-                       resourceType, subDirName);
-               if (!url) {
-            secwarning("resource: %@.%@ in %@ not found", resourceName,
-                resourceType, subDirName);
-               }
-    }
-
-       return url;
-}
index 29c74c60f0c6e584207b4c866c36de1a14fcfb76..a1c35effe2249b07066718c88abfa50466c360c7 100644 (file)
@@ -43,9 +43,6 @@ __BEGIN_DECLS
 CFStringRef SecFrameworkCopyLocalizedString(CFStringRef key,
     CFStringRef tableName);
 
-CFURLRef SecFrameworkCopyResourceURL(CFStringRef resourceName,
-       CFStringRef resourceType, CFStringRef subDirName);
-
 /* Return the SHA1 digest of a chunk of data as newly allocated CFDataRef. */
 CFDataRef SecSHA1DigestCreate(CFAllocatorRef allocator,
        const UInt8 *data, CFIndex length);
index 9404603c25129fc3412917dd8c6c37f93646157f..0d6db54a8a6f7ea35a49819ce96141329f03bf4b 100644 (file)
@@ -284,17 +284,19 @@ __BEGIN_DECLS
 #define SEC_TRUST_ERROR_LeafMarkersProdAndQA        SecStringWithDefaultValue("Missing project-specific extension OID", "Trust", 0, "Missing project-specific extension OID", "Error for leaf marker OID allowing prod or QA")
 #define SEC_TRUST_ERROR_BlackListedLeaf             SecStringWithDefaultValue("Certificate is blocked", "Trust", 0, "Certificate is blocked", "Error for blocklisted certificates")
 #define SEC_TRUST_ERROR_GrayListedLeaf              SecStringWithDefaultValue("Certificate is listed as untrusted", "Trust", 0, "Certificate is listed as untrusted", "Error for graylisted certificates")
+#define SEC_TRUST_ERROR_LeafSPKISHA256              SecStringWithDefaultValue("Public key does not match pinned value", "Trust", 0, "Public key does not match pinned value", "Error for leaf public key pin")
+#define SEC_TRUST_ERROR_NotCA                      SecStringWithDefaultValue("Leaf certificate is a CA", "Trust", 0, "Leaf certificate is a CA", "Error for leaf CA")
 #define SEC_TRUST_ERROR_IssuerCommonName            SecStringWithDefaultValue("Common Name does not match expected name", "Trust", 0, "Common Name does not match expected name", "Error for issuer common name mismatch")
 #define SEC_TRUST_ERROR_BasicConstraints            SecStringWithDefaultValue("Basic constraints are required but missing", "Trust", 0, "Basic constraints are required but missing", "Error for missing basic constraints")
 #define SEC_TRUST_ERROR_BasicConstraintsCA          SecStringWithDefaultValue("Non-CA certificate used as a CA", "Trust", 0, "Non-CA certificate used as a CA", "Error for CA basic constraints")
 #define SEC_TRUST_ERROR_BasicConstraintsPathLen     SecStringWithDefaultValue("Chain exceeded constrained path length", "Trust", 0, "Chain exceeded constrained path length", "Error for path length basic constraints")
 #define SEC_TRUST_ERROR_IntermediateSPKISHA256      SecStringWithDefaultValue("Public key does not match pinned value", "Trust", 0, "Public key does not match pinned value", "Error for intermediate public key pin")
+#define SEC_TRUST_ERROR_CAspkiSHA256                SecStringWithDefaultValue("Public key does not match pinned value", "Trust", 0, "Public key does not match pinned value", "Error for CA public key pin")
 #define SEC_TRUST_ERROR_IntermediateEKU             SecStringWithDefaultValue("Extended key usage does not match pinned value", "Trust", 0, "Extended key usage does not match pinned value", "Error for intermediate extended key usage pin")
 #define SEC_TRUST_ERROR_IntermediateMarkerOid       SecStringWithDefaultValue("Missing issuer-specific extension OID", "Trust", 0, "Missing issuer-specific extension OID", "Error for intermediate marker OID")
 #define SEC_TRUST_ERROR_IntermediateMarkerOidWithoutValueCheck SecStringWithDefaultValue("Missing issuer-specific extension OID", "Trust", 0, "Missing issuer-specific extension OID", "Error for intermediate marker OID")
 #define SEC_TRUST_ERROR_IntermediateOrganization    SecStringWithDefaultValue("Organization does not match expected name", "Trust", 0, "Organization does not match expected name", "Error for issuer organization mismatch")
 #define SEC_TRUST_ERROR_IntermediateCountry         SecStringWithDefaultValue("Country or Region does not match expected name", "Trust", 0, "Country or Region does not match expected name", "Error for issuer country mismatch")
-#define SEC_TRUST_ERROR_AnchorSHA1                  SecStringWithDefaultValue("Anchor does not match pinned fingerprint", "Trust", 0, "Anchor does not match pinned fingerprint", "Error for anchor SHA-1 fingerprint pin")
 #define SEC_TRUST_ERROR_AnchorSHA256                SecStringWithDefaultValue("Anchor does not match pinned fingerprint", "Trust", 0, "Anchor does not match pinned fingerprint", "Error for anchor SHA-256 fingerprint pin")
 #define SEC_TRUST_ERROR_AnchorTrusted               SecStringWithDefaultValue("Root is not trusted", "Trust", 0, "Root is not trusted", "Error for untrusted root")
 #define SEC_TRUST_ERROR_MissingIntermediate         SecStringWithDefaultValue("Unable to build chain to root (possible missing intermediate)", "Trust", 0, "Unable to build chain to root (possible missing intermediate)", "Error for missing intermediates")
index 22a1cdfe3340d5a75cf9195c8f7b645d3e659eb3..4f325ec90850b59d29bdf61967cc5e66263a5464 100644 (file)
 #include <utilities/SecXPCError.h>
 #include <utilities/der_plist.h>
 #include <utilities/der_plist_internal.h>
-#include <assert.h>
-#include <dlfcn.h>
+#include <utilities/simulatecrash_assert.h>
 #include <libaks_acl_cf_keys.h>
 #include <os/activity.h>
 #include <pthread.h>
 #include <os/lock.h>
+#include <os/feature_private.h>
 
 #include <Security/SecInternal.h>
 #include "keychain/SecureObjectSync/SOSInternal.h"
 
 #include <coreauthd_spi.h>
 #include <LocalAuthentication/LAPrivateDefines.h>
-#include <LocalAuthentication/LACFSupport.h>
 
 #include <ctkclient/ctkclient.h>
 
+#include "SecItemRateLimit.h"
+
 /*
  * See corresponding definition in SecDbKeychainItemV7. This is the unserialized
  * maximum, so the daemon's limit is not exactly the same.
@@ -461,15 +462,6 @@ SecItemCreateFromAttributeDictionary(CFDictionaryRef refAttributes) {
        return ref;
 }
 
-#if !TARGET_OS_OSX
-OSStatus
-SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames)
-{
-    // @@@ TBI
-    return -1 /* errSecUnimplemented */;
-}
-#endif // TARGET_OS_OSX
-
 typedef OSStatus (*secitem_operation)(CFDictionaryRef attributes, CFTypeRef *result);
 
 static bool explode_identity(CFDictionaryRef attributes, secitem_operation operation, 
@@ -543,7 +535,7 @@ static bool explode_identity(CFDictionaryRef attributes, secitem_operation opera
                     if (result) {
                         if (!status) {
                             /* result is a persistent ref to a cert */
-                            sqlite_int64 rowid;
+                            sqlite_int64 rowid = -1;
                             CFDictionaryRef tokenAttrs = NULL;
                             if (_SecItemParsePersistentRef(result, NULL, &rowid, &tokenAttrs)) {
                                 *return_result = _SecItemCreatePersistentRef(kSecClassIdentity, rowid, tokenAttrs);
@@ -674,21 +666,31 @@ static void infer_cert_label(SecCFDictionaryCOW *attributes)
     }
 }
 
-static CFDataRef CreateTokenPersistentRefData(CFTypeRef class, CFDictionaryRef attributes)
-{
+static CFDataRef CreateTokenPersistentRefData(CFTypeRef class, CFDictionaryRef attributes) {
     CFDataRef tokenPersistentRef = NULL;
-    CFStringRef tokenId;
+    CFStringRef tokenID = NULL;
+    CFDataRef tokenData = NULL;
+    CFDataRef oid = NULL;
     CFDictionaryRef itemValue = NULL;
-    require_quiet(tokenId = CFCast(CFString, CFDictionaryGetValue(attributes, kSecAttrTokenID)), out);
-    if (CFEqual(class, kSecClassIdentity)) {
-        itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateData), NULL);
+
+    oid = CFDictionaryGetValue(attributes, kSecAttrTokenOID);
+    if (oid != NULL) {
+        require_quiet(tokenID = CFCast(CFString, CFDictionaryGetValue(attributes, kSecAttrTokenID)), out);
     } else {
-        itemValue = SecTokenItemValueCopy(CFDictionaryGetValue(attributes, kSecValueData), NULL);
+        // Identities are identified by their contained certificate, so we need to get tokenID and OID from certificate,
+        // not from the key.
+        if (CFEqual(class, kSecClassIdentity) && oid == NULL) {
+            require_quiet(tokenID = CFCast(CFString, CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateTokenID)), out);
+            require_quiet(tokenData = CFCast(CFData, CFDictionaryGetValue(attributes, kSecAttrIdentityCertificateData)), out);
+        } else {
+            require_quiet(tokenID = CFCast(CFString, CFDictionaryGetValue(attributes, kSecAttrTokenID)), out);
+            require_quiet(tokenData = CFCast(CFData, CFDictionaryGetValue(attributes, kSecValueData)), out);
+        }
+        require_quiet(itemValue = SecTokenItemValueCopy(tokenData, NULL), out);
+        require_quiet(oid = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey), out);
+        require_quiet(CFCast(CFData, oid) != NULL, out);
     }
-    require_quiet(itemValue, out);
-    CFDataRef oid = CFDictionaryGetValue(itemValue, kSecTokenValueObjectIDKey);
-    require_quiet(oid, out);
-    CFArrayRef array = CFArrayCreateForCFTypes(kCFAllocatorDefault, class, tokenId, oid, NULL);
+    CFArrayRef array = CFArrayCreateForCFTypes(kCFAllocatorDefault, class, tokenID, oid, NULL);
     tokenPersistentRef = CFPropertyListCreateDERData(kCFAllocatorDefault, array, NULL);
     CFRelease(array);
 out:
@@ -702,9 +704,12 @@ static const uint8_t tk_persistent_ref_id[] = {'t', 'k', 'p', 'r'};
 CFDataRef _SecItemCreatePersistentRef(CFTypeRef class, sqlite_int64 rowid, CFDictionaryRef attributes)
 {
     CFDataRef result = NULL;
-    if (attributes && CFDictionaryContainsKey(attributes, CFEqual(class, kSecClassIdentity) ? kSecAttrIdentityCertificateTokenID : kSecAttrTokenID)) {
-        CFDataRef tokenPersistentRef = CreateTokenPersistentRefData(class, attributes);
-        require(tokenPersistentRef, out);
+    CFDataRef tokenPersistentRef = NULL;
+    if (attributes != NULL) {
+        tokenPersistentRef = CreateTokenPersistentRefData(class, attributes);
+    }
+
+    if (tokenPersistentRef != NULL) {
         CFMutableDataRef tmpData = CFDataCreateMutable(kCFAllocatorDefault, sizeof(tk_persistent_ref_id) + CFDataGetLength(tokenPersistentRef));
         CFDataAppendBytes(tmpData, tk_persistent_ref_id, sizeof(tk_persistent_ref_id));
         CFDataAppend(tmpData, tokenPersistentRef);
@@ -748,7 +753,7 @@ static bool ParseTokenPersistentRefData(CFDataRef persistent_ref, CFStringRef *r
     CFPropertyListRef pl = NULL;
     const uint8_t *der = CFDataGetBytePtr(persistent_ref) + sizeof(tk_persistent_ref_id);
     const uint8_t *der_end = der + (CFDataGetLength(persistent_ref) - sizeof(tk_persistent_ref_id));
-    require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &pl, NULL, der, der_end), out);
+    require_quiet(der = der_decode_plist(0, &pl, NULL, der, der_end), out);
     require_quiet(der == der_end, out);
     require_quiet(CFGetTypeID(pl) == CFArrayGetTypeID(), out);
     require_quiet(CFArrayGetCount(pl) == 3, out);
@@ -828,11 +833,11 @@ static CFDataRef SecTokenItemValueCreate(CFDataRef oid, CFDataRef access_control
 }
 
 CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) {
-    CFPropertyListRef plist = NULL;
+    CFPropertyListRef plist = NULL, result = NULL;
     require_quiet(CFCastWithError(CFData, db_value, error), out);
     const uint8_t *der = CFDataGetBytePtr(db_value);
     const uint8_t *der_end = der + CFDataGetLength(db_value);
-    require_quiet(der = der_decode_plist(0, kCFPropertyListImmutable, &plist, error, der, der_end), out);
+    require_quiet(der = der_decode_plist(0, &plist, error, der, der_end), out);
     require_action_quiet(der == der_end, out, SecError(errSecDecode, error, CFSTR("trailing garbage at end of token data field")));
     CFTypeRef value = CFDictionaryGetValue(plist, kSecTokenValueObjectIDKey);
     require_action_quiet(CFCast(CFData, value) != NULL, out,
@@ -841,9 +846,10 @@ CFDictionaryRef SecTokenItemValueCopy(CFDataRef db_value, CFErrorRef *error) {
     require_quiet(value == NULL || CFCastWithError(CFData, value, error), out);
     value = CFDictionaryGetValue(plist, kSecTokenValueDataKey);
     require_quiet(value == NULL || CFCastWithError(CFData, value, error), out);
-
+    result = CFRetainSafe(plist);
 out:
-    return plist;
+    CFReleaseNull(plist);
+    return result;
 }
 
 TKTokenRef SecTokenCreate(CFStringRef token_id, SecCFDictionaryCOW *auth_params, CFErrorRef *error) {
@@ -988,8 +994,11 @@ static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token,
             CFDictionaryRef parsed_value = NULL;
             require_quiet(parsed_value = SecTokenItemValueCopy(value, error), out);
             object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
+            require_quiet(object_id == NULL || CFCastWithError(CFData, object_id, error) != NULL, out);
             ac_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueAccessControlKey));
+            require_quiet(ac_data == NULL || CFCastWithError(CFData, ac_data, error) != NULL, out);
             object_value = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
+            require_quiet(object_value == NULL || CFCastWithError(CFData, object_value, error) != NULL, out);
             CFRelease(parsed_value);
             if ((wants_data || wants_ref) && object_value == NULL) {
                 // Retrieve value directly from the token.
@@ -1057,7 +1066,9 @@ static bool SecItemResultCopyPrepared(CFTypeRef raw_result, TKTokenRef token,
             CFDictionaryRef parsed_value;
             require_quiet(parsed_value = SecTokenItemValueCopy(data, error), out);
             cert_data = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueDataKey));
+            require_quiet(cert_data == NULL || CFCastWithError(CFData, cert_data, error) != NULL, out);
             cert_object_id = CFRetainSafe(CFDictionaryGetValue(parsed_value, kSecTokenValueObjectIDKey));
+            require_quiet(cert_object_id == NULL || CFCastWithError(CFData, cert_object_id, error) != NULL, out);
             CFRelease(parsed_value);
             if (cert_data == NULL) {
                 // Retrieve value directly from the token.
@@ -1123,7 +1134,7 @@ out:
 }
 
 bool SecItemResultProcess(CFDictionaryRef query, CFDictionaryRef auth_params, TKTokenRef token,
-                                 CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error) {
+                          CFTypeRef raw_result, CFTypeRef *result, CFErrorRef *error) {
     bool ok = false;
     require_action_quiet(raw_result != NULL, out, ok = true);
     require_action_quiet(result != NULL, out, ok = true);
@@ -1160,7 +1171,6 @@ out:
 static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, CFErrorRef *error) {
     bool ok = false;
     CFDataRef ac_data = NULL, acm_context = NULL;
-    void *la_lib = NULL;
 
     // If a ref was specified we get its attribute dictionary and parse it.
     CFTypeRef value = CFDictionaryGetValue(attrs->dictionary, kSecValueRef);
@@ -1251,9 +1261,6 @@ static bool SecItemAttributesPrepare(SecCFDictionaryCOW *attrs, bool forQuery, C
     ok = true;
 
 out:
-    if (la_lib != NULL) {
-        dlclose(la_lib);
-    }
     CFReleaseSafe(ac_data);
     CFReleaseSafe(acm_context);
     return ok;
@@ -1496,12 +1503,17 @@ bool SecItemAuthDoQuery(SecCFDictionaryCOW *query, SecCFDictionaryCOW *attribute
         }
 
         CFDictionaryRef attrs = (attributes != NULL) ? attributes->dictionary : NULL;
-        if(!perform(token, query->dictionary, attrs, auth_params.dictionary, error)) {
-            require_quiet((result = SecItemCreatePairsFromError(error, ac_pairs)) == kSecItemAuthResultOK, out);
+        if(perform(token, query->dictionary, attrs, auth_params.dictionary, error)) {
+            result = kSecItemAuthResultOK;
+            if(error && *error) {
+                // <rdar://problem/60642633> SecItemAuthDoQuery perform() sometimes returns success and fills in error parameter
+                secdebug("SecItemAuthDoQuery", "perform() succeded but returned an error: %@", *error);
+                CFReleaseNull(*error);
+            }
+        } else {
+            result = SecItemCreatePairsFromError(error, ac_pairs);
         }
 
-        result = kSecItemAuthResultOK;
-
     out:
         return result;
     }, NULL);
@@ -1549,16 +1561,21 @@ static bool dict_to_error_request(enum SecXPCOperation op, CFDictionaryRef query
     }, NULL);
 }
 
-static bool cfstring_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef attributes, __unused SecurityClient *client, CFErrorRef *error)
+static bool cfstring_array_array_to_error_request(enum SecXPCOperation op, CFStringRef string, CFArrayRef groups, CFArrayRef items, __unused SecurityClient *client, CFErrorRef *error)
 {
     return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
         if (string) {
             if (!SecXPCDictionarySetString(message, kSecXPCKeyString, string, error))
                 return false;
         }
+
+        if (groups) {
+            if (!SecXPCDictionarySetPList(message, kSecXPCKeyArray, groups, error))
+                return false;
+        }
         
-        if (attributes) {
-            if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, attributes, error))
+        if (items) {
+            if (!SecXPCDictionarySetPList(message, kSecXPCKeyQuery, items, error))
                 return false;
         }
         
@@ -1698,6 +1715,16 @@ out:
     return ok;
 }
 
+static void countReadOnlyAPICall() {
+    if (!isReadOnlyAPIRateWithinLimits()) {
+    }
+}
+
+static void countModifyingAPICall() {
+    if (!isModifyingAPIRateWithinLimits()) {
+    }
+}
+
 OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
     __block SecCFDictionaryCOW attrs = { attributes };
     OSStatus status;
@@ -1714,8 +1741,10 @@ OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result) {
             if (token == NULL) {
                 CFTypeRef raw_result = NULL;
                 logUnreasonableDataLength(attributes);
-                if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error))
+                countModifyingAPICall();
+                if (!SECURITYD_XPC(sec_item_add, cftype_client_to_bool_cftype_error_request, attributes, SecSecurityClientGet(), &raw_result, error)) {
                     return false;
+                }
 
                 bool ok = SecItemResultProcess(attributes, auth_params, token, raw_result, result, error);
                 CFReleaseSafe(raw_result);
@@ -1756,8 +1785,10 @@ OSStatus SecItemCopyMatching(CFDictionaryRef inQuery, CFTypeRef *result) {
     status = SecOSStatusWith(^bool(CFErrorRef *error) {
         return SecItemAuthDoQuery(&query, NULL, SecItemCopyMatching, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
             CFTypeRef raw_result = NULL;
-            if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error))
+            countReadOnlyAPICall();
+            if (!SECURITYD_XPC(sec_item_copy_matching, cftype_client_to_bool_cftype_error_request, query, SecSecurityClientGet(), &raw_result, error)) {
                 return false;
+            }
 
             // We intentionally pass NULL as token argument, because we want to be able to decide about token on which the item lives
             // on per-record basis, not wholesale.  Logic inside SecItemResultCopyPrepared will open proper token according
@@ -1899,6 +1930,7 @@ SecItemUpdateWithError(CFDictionaryRef inQuery,
         goto errOut;
 
     result = SecItemAuthDoQuery(&query, &attributesToUpdate, SecItemUpdate, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
+        countModifyingAPICall();
         if (token == NULL) {
                 return SecItemRawUpdate(query, attributes, error);
         } else {
@@ -1953,6 +1985,7 @@ OSStatus SecItemDelete(CFDictionaryRef inQuery) {
 
     status = SecOSStatusWith(^bool(CFErrorRef *error) {
         return SecItemAuthDoQuery(&query, NULL, SecItemDelete, error, ^bool(TKTokenRef token, CFDictionaryRef query, CFDictionaryRef attributes, CFDictionaryRef auth_params, CFErrorRef *error) {
+            countModifyingAPICall();
             if (token == NULL) {
                 return SECURITYD_XPC(sec_item_delete, dict_client_to_error_request, query, SecSecurityClientGet(), error);
             } else {
@@ -2004,75 +2037,50 @@ SecItemDeleteAll(void)
     });
 }
 
-#if 0
-static bool
-agrps_client_to_error_request(enum SecXPCOperation op, CFArrayRef agrps, __unused SecurityClient *client, CFErrorRef *error)
-{
-    return securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
-        return SecXPCDictionarySetPList(message, kSecXPCKeyAccessGroups, agrps, error);
-    }, NULL);
-}
-#endif
-
 bool SecItemDeleteAllWithAccessGroups(CFArrayRef accessGroups, CFErrorRef *error) {
-#if 0
-    os_activity_t activity = os_activity_create("SecItemDeleteAllWithAccessGroups", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
-    os_activity_scope(activity);
-    os_release(activity);
-
-    return SECURITYD_XPC(sec_delete_items_with_access_groups, agrps_client_to_error_request, accessGroups,
-                        SecSecurityClientGet(), error);
-#else
     return true;
-#endif
 }
 
 OSStatus
-#if SECITEM_SHIM_OSX
-SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
-#else
-SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes)
-#endif
+SecItemUpdateTokenItemsForAccessGroups(CFTypeRef tokenID, CFArrayRef accessGroups, CFArrayRef tokenItemsAttributes)
 {
     OSStatus status;
 
-    os_activity_t activity = os_activity_create("SecItemUpdateTokenItems_ios", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_t activity = os_activity_create("SecItemUpdateTokenItemsForAccessGroups", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
     os_activity_scope(activity);
     os_release(activity);
 
     status = SecOSStatusWith(^bool(CFErrorRef *error) {
-        CFArrayRef tmpArrayRef = tokenItemsAttributes;
+        bool ok = false;
+        CFMutableArrayRef tokenItemsForServer = NULL;
         if (tokenItemsAttributes) {
-            CFMutableArrayRef tokenItems = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+            tokenItemsForServer = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
             for (CFIndex i = 0; i < CFArrayGetCount(tokenItemsAttributes); ++i) {
                 CFDictionaryRef itemAttributes = CFArrayGetValueAtIndex(tokenItemsAttributes, i);
                 CFTypeRef accessControl = CFDictionaryGetValue(itemAttributes, kSecAttrAccessControl);
                 CFTypeRef tokenOID = CFDictionaryGetValue(itemAttributes, kSecAttrTokenOID);
                 CFTypeRef valueData = CFDictionaryGetValue(itemAttributes, kSecValueData);
                 if (tokenOID != NULL && accessControl != NULL && CFDataGetTypeID() == CFGetTypeID(accessControl)) {
-                    CFDataRef data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error);
-                    if (!data) {
-                        CFRelease(tokenItems);
-                        return false;
-                    }
-                    
+                    CFDataRef data;
+                    require_quiet(data = SecTokenItemValueCreate(tokenOID, accessControl, valueData, error), out);
                     CFMutableDictionaryRef attributes = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, itemAttributes);
                     CFDictionarySetValue(attributes, kSecValueData, data);
                     CFDictionarySetValue(attributes, kSecAttrTokenID, tokenID);
                     CFDictionaryRemoveValue(attributes, kSecAttrAccessControl);
                     CFDictionaryRemoveValue(attributes, kSecAttrTokenOID);
-                    CFArrayAppendValue(tokenItems, attributes);
-                    CFRelease(attributes);
-                    CFRelease(data);
+                    CFArrayAppendValue(tokenItemsForServer, attributes);
+                    CFReleaseNull(attributes);
+                    CFReleaseNull(data);
+                } else {
+                    CFArrayAppendValue(tokenItemsForServer, itemAttributes);
                 }
-                else
-                    CFArrayAppendValue(tokenItems, itemAttributes);
             }
-            
-            tmpArrayRef = tokenItems;
         }
 
-        return SECURITYD_XPC(sec_item_update_token_items, cfstring_array_to_error_request, tokenID, tmpArrayRef, SecSecurityClientGet(), error);
+        ok = SECURITYD_XPC(sec_item_update_token_items_for_access_groups, cfstring_array_array_to_error_request, tokenID, accessGroups, tokenItemsForServer, SecSecurityClientGet(), error);
+    out:
+        CFReleaseNull(tokenItemsForServer);
+        return ok;
     });
 
     return status;
index faa47c8811ef3801f523d0d8ee65f5d33cfc6f39..a9af1e2230ec43367306c7f19768bac661058215 100644 (file)
@@ -30,6 +30,7 @@
 #include <Security/SecItemPriv.h>
 #include <Security/SecItemInternal.h>
 #include <utilities/SecCFRelease.h>
+#import <utilities/debugging.h>
 
 #include <os/activity.h>
 
@@ -52,7 +53,7 @@ OSStatus _SecItemAddAndNotifyOnSync(CFDictionaryRef attributes, CFTypeRef * CF_R
             __block CFTypeRef raw_result = NULL;
             __block CFErrorRef raw_error = NULL;
 
-            id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+            id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(false, ^(NSError *error) {
                 syncCallback(false, (__bridge CFErrorRef)error);
             });
             if (rpc == NULL) {
@@ -103,7 +104,7 @@ void SecItemSetCurrentItemAcrossAllDevices(CFStringRef accessGroup,
     os_activity_scope(activity);
 
     @autoreleasepool {
-        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(false, ^(NSError *error) {
             complete((__bridge CFErrorRef) error);
         });
         [rpc secItemSetCurrentItemAcrossAllDevices:(__bridge NSData*)newCurrentItemReference
@@ -129,7 +130,7 @@ void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup,
     os_activity_scope(activity);
 
     @autoreleasepool {
-        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(false, ^(NSError *error) {
             complete(NULL, (__bridge CFErrorRef) error);
         });
         [rpc secItemFetchCurrentItemAcrossAllDevices:(__bridge NSString*)accessGroup
@@ -147,7 +148,7 @@ void _SecItemFetchDigests(NSString *itemClass, NSString *accessGroup, void (^com
     os_activity_t activity = os_activity_create("_SecItemFetchDigests", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
     os_activity_scope(activity);
 
-    id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+    id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(false, ^(NSError *error) {
         complete(NULL, error);
     });
     [rpc secItemDigest:itemClass accessGroup:accessGroup complete:complete];
@@ -167,7 +168,7 @@ void _SecKeychainDeleteMultiUser(NSString *musr, void (^complete)(bool, NSError
     uuid_t musrUUID;
     [uuid getUUIDBytes:musrUUID];
 
-    id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+    id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(false, ^(NSError *error) {
         complete(false, error);
     });
     [rpc secKeychainDeleteMultiuser:[NSData dataWithBytes:musrUUID length:sizeof(uuid_t)] complete:^(bool status, NSError *error) {
@@ -179,9 +180,28 @@ void SecItemVerifyBackupIntegrity(BOOL lightweight,
                                   void(^completion)(NSDictionary<NSString*, NSString*>* results, NSError* error))
 {
     @autoreleasepool {
-        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(^(NSError *error) {
+        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(true, ^(NSError *error) {
             completion(@{@"summary" : @"XPC Error"}, error);
         });
         [rpc secItemVerifyBackupIntegrity:lightweight completion:completion];
     }
 }
+
+OSStatus SecItemDeleteKeychainItemsForAppClip(CFStringRef applicationIdentifier)
+{
+    __block OSStatus status = errSecInternal;
+    @autoreleasepool {
+        id<SecuritydXPCProtocol> rpc = SecuritydXPCProxyObject(true, ^(NSError *error) {
+            secerror("xpc: failure to obtain XPC proxy object for app clip deletion, %@", error);
+        });
+        [rpc secItemDeleteForAppClipApplicationIdentifier:(__bridge NSString*)applicationIdentifier
+                                               completion:^(OSStatus xpcStatus) {
+            // Other errors turn into errSecInternal for caller
+            secnotice("xpc", "app clip deletion result: %i", (int)xpcStatus);
+            if (xpcStatus == errSecMissingEntitlement || xpcStatus == errSecSuccess) {
+                status = xpcStatus;
+            }
+        }];
+    }
+    return status;
+}
index 614e40d8801adf39d54efa3e4b6467ffa663a196..9581cb8b2d865cbb7bcf120c27c8d336c8fd25d9 100644 (file)
@@ -124,6 +124,17 @@ static bool string_string_data_data_data_to_bool_error_request(enum SecXPCOperat
     });
 }
 
+static CFStringRef string_to_string_error_request(enum SecXPCOperation op, CFStringRef viewName, CFErrorRef *error)
+{
+    __block CFStringRef result = NULL;
+    securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
+        return SecXPCDictionarySetString(message, kSecXPCKeyString, viewName, error);
+    }, ^bool(xpc_object_t response, CFErrorRef *error) {
+        return result = SecXPCDictionaryCopyString(response, kSecXPCKeyResult, error);
+    });
+    return result;
+}
+
 static CFArrayRef to_array_error_request(enum SecXPCOperation op, CFErrorRef *error)
 {
     __block CFArrayRef result = NULL;
@@ -346,6 +357,25 @@ bool SecItemBackupWithRegisteredBackups(CFErrorRef *error, void(^backup)(CFStrin
     return true;
 }
 
+static CFStringRef SecItemBackupViewAndCopyBackupPeerID(CFStringRef viewName, CFErrorRef *error)
+{
+    __block CFStringRef result;
+    os_activity_initiate("SecItemBackupViewAndCopyBackupPeerID", OS_ACTIVITY_FLAG_DEFAULT, ^{
+        result = SECURITYD_XPC(sec_item_backup_ensure_copy_view, string_to_string_error_request, viewName, error);
+    });
+    return result;
+}
+
+bool SecItemBackupWithRegisteredViewBackup(CFStringRef viewName, CFErrorRef *error) {
+    CFStringRef backupName = SecItemBackupViewAndCopyBackupPeerID(viewName, error);
+    if(backupName == NULL) {
+        return false;
+    }
+    CFReleaseNull(backupName);
+    return true;
+}
+
+
 static bool SecItemBackupDoResetEventBody(const uint8_t *der, const uint8_t *der_end, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item)) {
     size_t sequence_len;
     const uint8_t *sequence_body = ccder_decode_len(&sequence_len, der, der_end);
@@ -377,7 +407,7 @@ static bool SecItemBackupDoResetEventBody(const uint8_t *der, const uint8_t *der
 
 static bool SecItemBackupDoAddEvent(const uint8_t *der, const uint8_t *der_end, CFErrorRef *error, void (^handleEvent)(SecBackupEventType et, CFTypeRef key, CFTypeRef item)) {
     CFDictionaryRef eventDict = NULL;
-    const uint8_t *der_end_of_dict = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &eventDict, error, der, der_end);
+    const uint8_t *der_end_of_dict = der_decode_dictionary(kCFAllocatorDefault, &eventDict, error, der, der_end);
     if (der_end_of_dict && der_end_of_dict != der_end) {
         // Can't ever happen!
         SecError(errSecDecode, error, CFSTR("trailing junk after add"));
@@ -589,11 +619,6 @@ void SecItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef
     CFReleaseSafe(localError);
 }
 
-CFDictionaryRef SecItemBackupCopyMatching(CFDataRef keybag, CFDataRef secret, CFDictionaryRef backup, CFDictionaryRef query, CFErrorRef *error) {
-    SecError(errSecUnimplemented, error, CFSTR("SecItemBackupCopyMatching unimplemented"));
-    return NULL;
-}
-
 bool SecBackupKeybagAdd(CFDataRef passcode, CFDataRef *identifier, CFURLRef *pathinfo, CFErrorRef *error) {
     __block bool result = false;
     os_activity_initiate("_SecServerBackupKeybagAdd", OS_ACTIVITY_FLAG_DEFAULT, ^{
index b6b73679efea618a0816e0a266af302270e17b84..c6047c6d574802eccc003a794ba6b73fc1323a9c 100644 (file)
@@ -54,6 +54,8 @@ typedef enum SecBackupEventType {
 
 bool SecItemBackupWithRegisteredBackups(CFErrorRef *error, void(^backup)(CFStringRef backupName));
 
+bool SecItemBackupWithRegisteredViewBackup(CFStringRef viewName, CFErrorRef *error);
+
 /*!
  @function SecItemBackupWithChanges
  @abstract Tell securityd which keybag (via a persistent ref) to use to backup
@@ -85,24 +87,6 @@ bool SecItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagD
  @discussion CloudServices iterates over all the backups, calling this for each backup with peer infos matching the chosen device. */
 void SecItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFTypeRef backup, void (^completion)(CFErrorRef error));
 
-/*!
- @function SecItemBackupCopyMatching
- @abstract Query the contents of a backup dictionary.
- @param keybag The bag protecting the backup data.
- @param secret Credential to unlock keybag.
- @param backup Dictionary returned from SecItemBackupDataSource.
- @param query A dictionary containing an item class specification and
- optional attributes for controlling the search. See the "Keychain
- Search Attributes" section of SecItemCopyMatching for a description of
- currently defined search attributes.
- @result CFTypeRef reference to the found item(s). The
- exact type of the result is based on the search attributes supplied
- in the query.  Returns NULL and sets *error if there is a failure.
- @discussion This allows clients to "restore" a backup and fetch an item from
- it without restoring the backup to the keychain, and in particular without
- even having a writable keychain around, such as when running in the restore OS. */
-CFDictionaryRef SecItemBackupCopyMatching(CFDataRef keybag, CFDataRef secret, CFDictionaryRef backup, CFDictionaryRef query, CFErrorRef *error);
-
 // Utility function to compute a confirmed manifest from a v0 backup dictionary.
 CFDataRef SecItemBackupCreateManifest(CFDictionaryRef backup, CFErrorRef *error);
 
index 38904fe63f55aa53ddf9ebd3980e834395e8af75..a5fd1aa8ecd9d9405e5a8451d511900bdb97a135 100644 (file)
@@ -120,6 +120,13 @@ SEC_CONST_DECL (kSecAttrPCSPlaintextServiceIdentifier, "pcss");
 SEC_CONST_DECL (kSecAttrPCSPlaintextPublicKey, "pcsk");
 SEC_CONST_DECL (kSecAttrPCSPlaintextPublicIdentity, "pcsi");
 
+SEC_CONST_DECL (kSecDataInetExtraNotes, "binn");
+SEC_CONST_DECL (kSecDataInetExtraHistory, "bini");
+SEC_CONST_DECL (kSecDataInetExtraClientDefined0, "bin0");
+SEC_CONST_DECL (kSecDataInetExtraClientDefined1, "bin1");
+SEC_CONST_DECL (kSecDataInetExtraClientDefined2, "bin2");
+SEC_CONST_DECL (kSecDataInetExtraClientDefined3, "bin3");
+
 /* Predefined access groups constants */
 SEC_CONST_DECL (kSecAttrAccessGroupToken, "com.apple.token");
 
index 50cc4c6aeac94b9568d1f005bf6f3fca2140903f..33b184f144b007b206b9eb5de8945dae6085a232 100644 (file)
@@ -105,6 +105,11 @@ CFArrayRef SecItemCopyParentCertificates_ios(CFDataRef normalizedIssuer, CFArray
 
 bool SecItemCertificateExists(CFDataRef normalizedIssuer, CFDataRef serialNumber, CFArrayRef accessGroups, CFErrorRef *error);
 
+/*!
+    @constant kSecAttrAppClipItem Boolean attribute indicating whether the origin of this item is an App Clip client
+*/
+static const CFStringRef kSecAttrAppClipItem = CFSTR("clip");
+
 __END_DECLS
 
 #endif /* !_SECURITY_SECITEMINTERNAL_H_ */
diff --git a/OSX/sec/Security/SecItemRateLimit.h b/OSX/sec/Security/SecItemRateLimit.h
new file mode 100644 (file)
index 0000000..b5503a8
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef SECITEMRATELIMIT_H_
+#define SECITEMRATELIMIT_H_
+
+#include <stdbool.h>
+
+bool isReadOnlyAPIRateWithinLimits(void);
+bool isModifyingAPIRateWithinLimits(void);
+
+#endif // SECITEMRATELIMIT_H_
diff --git a/OSX/sec/Security/SecItemRateLimit.m b/OSX/sec/Security/SecItemRateLimit.m
new file mode 100644 (file)
index 0000000..c18f9ed
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2020 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 "SecItemRateLimit.h"
+#import "SecItemRateLimit_tests.h"
+
+#import <utilities/debugging.h>
+#import <utilities/SecInternalReleasePriv.h>
+#import "ipc/securityd_client.h"
+
+#import <sys/codesign.h>
+#import <os/feature_private.h>
+
+// Dressed-down version of RateLimiter which directly computes the rate of one bucket and resets when it runs out of tokens
+
+// Broken out so the test-only reset method can reinit this
+static SecItemRateLimit* ratelimit;
+
+@implementation SecItemRateLimit {
+    bool _forceEnabled;
+    dispatch_queue_t _dataQueue;
+}
+
++ (instancetype)instance {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        ratelimit = [SecItemRateLimit new];
+    });
+    return ratelimit;
+}
+
+- (instancetype)init {
+    if (self = [super init]) {
+        _roCapacity = 25;      // allow burst of this size
+        _roRate = 3.0;      // allow sustained rate of this many per second
+        _rwCapacity = 25;
+        _rwRate = 1.0;
+        _roBucket = nil;
+        _rwBucket = nil;
+        _forceEnabled = false;
+        _limitMultiplier = 5.0;     // Multiply capacity and rate by this much after exceeding limit
+        _dataQueue = dispatch_queue_create("com.apple.keychain.secitemratelimit.dataqueue", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+    }
+
+    return self;
+}
+
+- (bool)isEnabled {
+    return _forceEnabled || [self shouldCountAPICalls];
+}
+
+- (void)forceEnabled:(bool)force {
+    _forceEnabled = force;
+    secnotice("secitemratelimit", "%sorcing SIRL to be enabled (effective: %i)", force ? "F" : "Not f", [self isEnabled]);
+}
+
+- (bool)isReadOnlyAPICallWithinLimits {
+    if (![self consumeTokenFromBucket:false]) {
+        secnotice("secitemratelimit", "Readonly API rate exceeded");
+        return false;
+    } else {
+        return true;
+    }
+}
+
+- (bool)isModifyingAPICallWithinLimits {
+    if (![self consumeTokenFromBucket:true]) {
+        secnotice("secitemratelimit", "Modifying API rate exceeded");
+        return false;
+    } else {
+        return true;
+    }
+}
+
+- (bool)consumeTokenFromBucket:(bool)readwrite {
+    if (![self shouldCountAPICalls] && !_forceEnabled) {
+        return true;
+    }
+
+    __block bool ok = false;
+    dispatch_sync(_dataQueue, ^{
+        int* capacity = readwrite ? &_rwCapacity : &_roCapacity;
+        double* rate = readwrite ? &_rwRate : &_roRate;
+        NSDate* __strong* bucket = readwrite ? &_rwBucket : &_roBucket;
+
+        NSDate* now = [NSDate now];
+        NSDate* fullBucket = [now dateByAddingTimeInterval:-(*capacity * (1.0 / *rate))];
+        // bucket has more tokens than a 'full' bucket? This prevents occasional-but-bursty activity slipping through
+        if (!*bucket || [*bucket timeIntervalSinceDate: fullBucket] < 0) {
+            *bucket = fullBucket;
+        }
+
+        *bucket = [*bucket dateByAddingTimeInterval:1.0 / *rate];
+        ok = [*bucket timeIntervalSinceDate:now] <= 0;
+
+        // Get a new bucket next time so we only complain every now and then
+        if (!ok) {
+            *bucket = nil;
+            *capacity *= _limitMultiplier;
+            *rate *= _limitMultiplier;
+        }
+    });
+
+    return ok;
+}
+
+- (bool)shouldCountAPICalls {
+    static bool shouldCount = false;
+    static dispatch_once_t shouldCountToken;
+    dispatch_once(&shouldCountToken, ^{
+        if (!SecIsInternalRelease()) {
+            secnotice("secitemratelimit", "Not internal release, disabling SIRL");
+            return;
+        }
+
+        // gSecurityd is the XPC elision mechanism for testing; don't want simcrashes during tests
+        if (gSecurityd != nil) {
+            secnotice("secitemratelimit", "gSecurityd non-nil, disabling SIRL for testing");
+            return;
+        }
+
+        if (!os_feature_enabled(Security, SecItemRateLimiting)) {
+            secnotice("secitemratelimit", "SIRL disabled via feature flag");
+            return;
+        }
+
+        SecTaskRef task = SecTaskCreateFromSelf(NULL);
+        NSMutableArray* exempt = [NSMutableArray arrayWithArray:@[@"com.apple.pcsstatus", @"com.apple.protectedcloudstorage.protectedcloudkeysyncing", @"com.apple.cloudd", @"com.apple.pcsctl"]];
+        CFStringRef identifier = NULL;
+        require_action_quiet(task, cleanup, secerror("secitemratelimit: unable to get task from self, disabling SIRL"));
+
+        // If not a valid or debugged platform binary, don't count
+        uint32_t flags = SecTaskGetCodeSignStatus(task);
+        require_action_quiet((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) == (CS_VALID | CS_PLATFORM_BINARY) ||
+                             (flags & (CS_DEBUGGED | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) == (CS_DEBUGGED | CS_PLATFORM_BINARY),
+                             cleanup, secnotice("secitemratelimit", "Not valid/debugged platform binary, disabling SIRL"));
+
+        // Some processes have legitimate need to query or modify a large number of items
+        identifier = SecTaskCopySigningIdentifier(task, NULL);
+        require_action_quiet(identifier, cleanup, secerror("secitemratelimit: unable to get signing identifier, disabling SIRL"));
+#if TARGET_OS_OSX
+        [exempt addObjectsFromArray:@[@"com.apple.keychainaccess", @"com.apple.Safari"]];
+#elif TARGET_OS_IOS
+        [exempt addObjectsFromArray:@[@"com.apple.mobilesafari", @"com.apple.Preferences"]];
+#endif
+        if ([exempt containsObject:(__bridge NSString*)identifier]) {
+            secnotice("secitemratelimit", "%@ exempt from SIRL", identifier);
+            goto cleanup;
+        }
+
+        secnotice("secitemratelimit", "valid/debugged platform binary %@ on internal release, enabling SIRL", identifier);
+        shouldCount = true;
+
+cleanup:
+        CFReleaseNull(task);
+        CFReleaseNull(identifier);
+    });
+    return shouldCount;
+}
+
+// Testing
++ (instancetype)getStaticRateLimit {
+    return [SecItemRateLimit instance];
+}
+
+// Testing and super thread-UNsafe. Caveat emptor.
++ (void)resetStaticRateLimit {
+       ratelimit = [SecItemRateLimit new];
+}
+
+@end
+
+bool isReadOnlyAPIRateWithinLimits(void) {
+    return [[SecItemRateLimit instance] isReadOnlyAPICallWithinLimits];
+}
+
+bool isModifyingAPIRateWithinLimits(void) {
+    return [[SecItemRateLimit instance] isModifyingAPICallWithinLimits];
+}
diff --git a/OSX/sec/Security/SecItemRateLimit_tests.h b/OSX/sec/Security/SecItemRateLimit_tests.h
new file mode 100644 (file)
index 0000000..c79c947
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 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 SecItemRateLimit_tests_h
+#define SecItemRateLimit_tests_h
+
+#import "SecItemRateLimit.h"
+#import <Foundation/Foundation.h>
+
+// Broken out into header for testing convenience.
+// If you need this, why?
+@interface SecItemRateLimit : NSObject
+
+@property (nonatomic, readonly) int roCapacity;
+@property (nonatomic, readonly) double roRate;
+@property (nonatomic, readonly) int rwCapacity;
+@property (nonatomic, readonly) double rwRate;
+@property (nonatomic, readonly) double limitMultiplier;
+
+@property (nonatomic, readonly) NSDate* roBucket;
+@property (nonatomic, readonly) NSDate* rwBucket;
+
+- (bool)shouldCountAPICalls;
+- (bool)isEnabled;
+- (void)forceEnabled:(bool)force;
+
++ (instancetype)getStaticRateLimit;
++ (void)resetStaticRateLimit;
+
+@end
+
+#endif /* SecItemRateLimit_tests_h */
index 02b89f36db00365b27a6a4431e4c8bb0ea35a80f..862dd996a4c2a4d7b76124c4500187dbfa078416 100644 (file)
@@ -47,7 +47,6 @@ OSStatus SecItemAdd_ios(CFDictionaryRef attributes, CFTypeRef *result);
 OSStatus SecItemCopyMatching_ios(CFDictionaryRef query, CFTypeRef *result);
 OSStatus SecItemUpdate_ios(CFDictionaryRef query, CFDictionaryRef attributesToUpdate);
 OSStatus SecItemDelete_ios(CFDictionaryRef query);
-OSStatus SecItemUpdateTokenItems_ios(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes);
 
 OSStatus SecKeyGeneratePair_ios(CFDictionaryRef parameters, SecKeyRef *publicKey, SecKeyRef *privateKey);
 SecKeyRef SecKeyCreateRandomKey_ios(CFDictionaryRef parameters, CFErrorRef *error);
@@ -58,7 +57,6 @@ SecKeyRef SecKeyCreateRandomKey_ios(CFDictionaryRef parameters, CFErrorRef *erro
 #define SecItemCopyMatching SecItemCopyMatching_ios
 #define SecItemUpdate SecItemUpdate_ios
 #define SecItemDelete SecItemDelete_ios
-#define SecItemUpdateTokenItems SecItemUpdateTokenItems_ios
 
 #define SecKeyGeneratePair SecKeyGeneratePair_ios
 #define SecKeyCreateRandomKey SecKeyCreateRandomKey_ios
index 218f1a9b1252199c5307575bd26d88d776173020..35c0afab9e4d911b58fea442804c02667590a2f1 100644 (file)
@@ -1199,7 +1199,7 @@ OSStatus SecKeyCopyPersistentRef(SecKeyRef key, CFDataRef* persistentRef)
     if (!persistentRef) {
         secerror("SecKeyCopyPersistentRef: Need a persistentRef pointer for this to work");
         return errSecParam;
-    }
+    }    
 
     CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                                          kSecReturnPersistentRef,   kCFBooleanTrue,
index 07a8b98bb9a293ae6cd9e811d4bc18f51ea47df6..3e0868cfaf0cc018e33f812e5f263536c556ca10 100644 (file)
@@ -716,12 +716,12 @@ static CFTypeRef SecKeyECDHCopyX963Result(SecKeyOperationContext *context, const
         CFMutableDataRef kdfResult = CFDataCreateMutableWithScratch(kCFAllocatorDefault, requestedSize);
         int err = ccansikdf_x963(di, CFDataGetLength(sharedSecret), CFDataGetBytePtr(sharedSecret), sharedInfoLength, sharedInfo,
                                  requestedSize, CFDataGetMutableBytePtr(kdfResult));
-        require_noerr_action_quiet(err, out, (CFReleaseNull(result),
+        require_noerr_action_quiet(err, out, (CFReleaseNull(kdfResult),
                                               SecError(errSecParam, error, CFSTR("ECDHKeyExchange wrong input (%d)"), err)));
         CFAssignRetained(result, kdfResult);
     } else {
         // In test-only mode, propagate result (YES/NO) of underlying operation.
-        result = CFRetainAssign(result, sharedSecret);
+        CFRetainAssign(result, sharedSecret);
     }
 out:
     CFReleaseNull(sharedSecret);
@@ -949,8 +949,11 @@ out:
 static CFDataRef SecKeyECIESDecryptAESGCMCopyResult(CFDataRef keyExchangeResult, CFDataRef inData, CFDictionaryRef inParams,
                                                     CFErrorRef *error) {
     CFDataRef result = NULL;
-    CFMutableDataRef plaintext = CFDataCreateMutableWithScratch(kCFAllocatorDefault, CFDataGetLength(inData) - kSecKeyIESTagLength);
-    CFMutableDataRef tag = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), kSecKeyIESTagLength);
+    CFMutableDataRef plaintext = NULL;
+    CFMutableDataRef tag = NULL;
+    require_action_quiet(CFDataGetLength(inData) >= kSecKeyIESTagLength, out, SecError(errSecParam, error, CFSTR("ECIES: Input data too short")));
+    plaintext = CFDataCreateMutableWithScratch(kCFAllocatorDefault, CFDataGetLength(inData) - kSecKeyIESTagLength);
+    tag = CFDataCreateMutableWithScratch(SecCFAllocatorZeroize(), kSecKeyIESTagLength);
     CFDataGetBytes(inData, CFRangeMake(CFDataGetLength(inData) - kSecKeyIESTagLength, kSecKeyIESTagLength),
                    CFDataGetMutableBytePtr(tag));
     CFIndex aesKeySize = CFDataGetLength(keyExchangeResult) - sizeof(kSecKeyIESIV);
index 948559481722d98a45099685b6e0d023d7e4ba5a..b5a0e9807a8cbc020bb11c682f0e833ef20a3dd2 100644 (file)
 @implementation SecKeyProxy
 - (instancetype)initWithKey:(SecKeyRef)key certificate:(nullable NSData *)certificate {
     if (self = [super init]) {
-        _key = CFBridgingRelease(CFRetain(key));
+        if (key != nil) {
+            _key = CFBridgingRelease(CFRetainSafe(key));
+        } else {
+            _key = nil;
+        }
         _certificate = certificate;
         _listener = [NSXPCListener anonymousListener];
         _listener.delegate = self;
index 743320a28aea71871787538258b97c9679f900a0..d79b0ebe8581c5b1a4fdfa34e538f60e8d410f0b 100644 (file)
@@ -56,8 +56,13 @@ typedef struct _SecOTRPublicIdentity* SecOTRPublicIdentityRef;
  * Full identity functions
  */
 SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error);
-    
+
+// This variant is used by MessageProtection that doesn't use persistent references anymore.
 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
+                                                            CFErrorRef *error);
+
+// This variant is used by SOS, and still relies on privateKey having a persistent reference.
+SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRefSOS(CFAllocatorRef allocator, SecKeyRef privateKey,
                                                                 CFErrorRef *error);
 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromData(CFAllocatorRef allocator, CFDataRef serializedData, CFErrorRef *error);
     
index 221274d7d11c59839c660cd640d510bfc299963f..492eef0e1ccd774e2d9bf947dd7f4a0f4586290e 100644 (file)
@@ -31,8 +31,7 @@
 #include <corecrypto/ccsha1.h>
 #include <corecrypto/ccec_priv.h>
 #include <corecrypto/ccec.h>
-
-#include <CommonCrypto/CommonRandomSPI.h>
+#include <corecrypto/ccrng.h>
 
 #define kECKeySize 256
 
@@ -177,7 +176,7 @@ fail:
 
 OSStatus SecFDHKNewKey(SecOTRFullDHKeyRef fullKey)
 {
-    struct ccrng_state *rng=ccDRBGGetRngState();
+    struct ccrng_state *rng=ccrng(NULL);
 
     // We need compact keys, maybe we should be using
     // ccecdh_generate_key or ccechd_generate_compact_key, but for now ecdh are fine for compact use IFF we don't
index 877863eba0139c97b1936e951263400e764bfcb6..c38b51ca5185e775cac682a637e13487b19c30dd 100644 (file)
@@ -186,7 +186,7 @@ errOut:
 SecOTRFullIdentityRef SecOTRFullIdentityCreate(CFAllocatorRef allocator, CFErrorRef *error)
 {
     SecKeyRef signingKey = SecOTRCreateSigningKey(allocator);
-    SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRef(allocator, signingKey, error);
+    SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator, signingKey, error);
     CFReleaseNull(signingKey);
 
     return newID;
@@ -298,7 +298,8 @@ OSStatus SecOTRFIInitFromV2Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef all
     --*size;
 
     require_noerr_quiet(status = SecOTRFICreateKeysFromReadPersistentRefAndPublicKey(bytes, size, &newID->publicSigningKey, &newID->privateSigningKey, &newID->privateKeyPersistentRef, &CreateECPublicKeyFrom), fail);
-
+    newID->isMessageProtectionKey = false;
+    
     return status;
 
 fail:
@@ -309,6 +310,49 @@ fail:
     return status;
 }
 
+static
+OSStatus SecOTRFIInitFromV3Bytes(SecOTRFullIdentityRef newID, CFAllocatorRef allocator,
+                                const uint8_t **bytes,size_t *size) {
+    OSStatus status = errSecInvalidData;
+    require_action(**bytes == 3, fail, status = errSecParam);
+    ++*bytes;
+    --*size;
+    
+    uint16_t dataSize;
+    require_noerr_quiet(readSize(bytes, size, &dataSize), fail);
+    
+    int32_t keysz32 = 256;
+    CFNumberRef ksizeNumber = CFNumberCreate(NULL, kCFNumberSInt32Type, &keysz32);
+    CFDataRef keyBytes = CFDataCreate(allocator, *bytes, dataSize);
+    
+    CFDictionaryRef dict = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                       kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom,
+                                                       kSecAttrKeyClass, kSecAttrKeyClassPrivate,
+                                                       kSecAttrKeySizeInBits, ksizeNumber,
+                                                       kSecAttrIsPermanent, kCFBooleanFalse, NULL);
+    
+    CFErrorRef error;
+    SecKeyRef key = SecKeyCreateWithData(keyBytes, dict, &error);
+    
+    CFReleaseSafe(dict);
+    CFReleaseSafe(keyBytes);
+    CFReleaseSafe(ksizeNumber);
+    
+    if (key == NULL) {
+        CFRelease(error);
+        return errSecInvalidData;
+    }
+    
+    newID->privateKeyPersistentRef = NULL;
+    newID->isMessageProtectionKey = true;
+    newID->privateSigningKey = key;
+    newID->publicSigningKey = SecKeyCopyPublicKey(newID->privateSigningKey);
+    status = errSecSuccess;
+    
+fail:
+    return status;
+}
+
 // TODO: Probably move to SecKey
 static CFDataRef SecKeyCreatePersistentRef(SecKeyRef theKey, CFErrorRef *error) {
     CFDataRef persistentRef = NULL;
@@ -320,13 +364,27 @@ static CFDataRef SecKeyCreatePersistentRef(SecKeyRef theKey, CFErrorRef *error)
 
 SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRef(CFAllocatorRef allocator, SecKeyRef privateKey,
                                                             CFErrorRef *error) {
-    // TODO - make sure this is an appropriate key type
-    SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
-    CFRetainAssign(newID->privateSigningKey, privateKey);
-    require_action(newID->publicSigningKey = SecKeyCreatePublicFromPrivate(privateKey), fail,
-                   SecError(errSecInternalComponent, error, CFSTR("Failed to extract public key from private key")));
+      // TODO - make sure this is an appropriate key type
+      SecOTRFullIdentityRef newID = CFTypeAllocate(SecOTRFullIdentity, struct _SecOTRFullIdentity, allocator);
+      CFRetainAssign(newID->privateSigningKey, privateKey);
+      require_action(newID->publicSigningKey = SecKeyCreatePublicFromPrivate(privateKey), fail,
+                     SecError(errSecInternalComponent, error, CFSTR("Failed to extract public key from private key")));
+      // MessageProtection keys are no longer having persistent references.
+      newID->privateKeyPersistentRef = NULL;
+      newID->isMessageProtectionKey = true;
+      
+      require(SecOTRFICachePublicHash(newID, error), fail);
+      return newID;
+  fail:
+      CFReleaseNull(newID);
+      return NULL;
+}
+
+SecOTRFullIdentityRef SecOTRFullIdentityCreateFromSecKeyRefSOS(CFAllocatorRef allocator, SecKeyRef privateKey,
+                                                            CFErrorRef *error) {
+    SecOTRFullIdentityRef newID = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, error);
     require(newID->privateKeyPersistentRef = SecKeyCreatePersistentRef(privateKey, error), fail);
-    require(SecOTRFICachePublicHash(newID, error), fail);
+    newID->isMessageProtectionKey = false;
     return newID;
 fail:
     CFReleaseNull(newID);
@@ -347,6 +405,9 @@ SecOTRFullIdentityRef SecOTRFullIdentityCreateFromBytes(CFAllocatorRef allocator
         case 2:
             require_noerr_action_quiet(status = SecOTRFIInitFromV2Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v2 otr session: %d"), (int)status));
             break;
+        case 3:
+            require_noerr_action_quiet(status = SecOTRFIInitFromV3Bytes(newID, allocator, bytes, size), fail, SecError(status, error, CFSTR("failed to decode v3 otr session: %d"), (int)status));
+            break;
         case 0: // Version 0 was used in seeds of 5.0, transition from those seeds unsupported - keys were in exported data.
         default:
             SecError(errSecParam, error, CFSTR("unknown otr session version %hhu"), **bytes);
@@ -432,6 +493,23 @@ bool SecOTRFIPurgeAllFromKeychain(CFErrorRef *error)
     }
 }
 
+static OSStatus SecOTRFIAppendV3Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
+{
+    const uint8_t version = 3;
+    CFIndex start = CFDataGetLength(serializeInto);
+    CFDataAppendBytes(serializeInto, &version, sizeof(version));
+    CFErrorRef error = nil;
+    CFDataRef privKeyBytes = SecKeyCopyExternalRepresentation(fullID->privateSigningKey, &error);
+    require(privKeyBytes != nil, fail);
+    appendSizeAndData(privKeyBytes, serializeInto);
+    CFReleaseSafe(privKeyBytes);
+    return errSecSuccess;
+
+fail:
+    CFDataSetLength(serializeInto, start);
+
+    return errSecParam;
+}
 
 static OSStatus SecOTRFIAppendV2Serialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto)
 {
@@ -452,7 +530,13 @@ fail:
 
 bool SecOTRFIAppendSerialization(SecOTRFullIdentityRef fullID, CFMutableDataRef serializeInto, CFErrorRef *error)
 {
-    OSStatus status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
+    OSStatus status = errSecParam;
+    if (fullID->isMessageProtectionKey) {
+        status = SecOTRFIAppendV3Serialization(fullID, serializeInto);
+    } else {
+        status = SecOTRFIAppendV2Serialization(fullID, serializeInto);
+    }
+    
     if (errSecSuccess == status) {
         return true;
     } else {
index 8ce081c9d258d7944fc3d8c9e86de6e1d91bd7f8..61b288ea8ccf79369c75c8f31d6240fbadc8099c 100644 (file)
@@ -52,7 +52,8 @@ struct _SecOTRFullIdentity {
     SecKeyRef   publicSigningKey;
     SecKeyRef   privateSigningKey;
     CFDataRef   privateKeyPersistentRef;
-    
+
+    bool        isMessageProtectionKey;
     uint8_t     publicIDHash[kMPIDHashSize];
 };
 
index 3fe809942e1b7c33661350486b4430d7b0ed8db4..fc84f8c4ed1d4ffa055e9cda125edea35a09004f 100644 (file)
 
 #include <AssertMacros.h>
 
+#include <security_utilities/simulatecrash_assert.h>
+
 __BEGIN_DECLS
 
-static CC_NONNULL((1,2))
-OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected);
+CF_ASSUME_NONNULL_BEGIN
+
+static
+OSStatus ReadAndVerifyByte(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint8_t expected);
 
-static CC_NONNULL((1,2))
-OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected);
+static
+OSStatus ReadAndVerifyShort(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint16_t expected);
 
-static CC_NONNULL((1,2))
-OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected);
+static
+OSStatus ReadAndVerifyMessageType(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected);
 
-static CC_NONNULL((1,2,3,4))
-OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size,
-                         const uint8_t **dataBytes, size_t *dataSize);
-static CC_NONNULL((1,2,3,4))
-OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size,
-                        const uint8_t **mpiBytes, size_t *mpiSize);
+static
+OSStatus SizeAndSkipDATA(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size,
+                         const uint8_t *_Nonnull *_Nonnull dataBytes, size_t *dataSize);
+static
+OSStatus SizeAndSkipMPI(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size,
+                        const uint8_t *_Nonnull *_Nonnull mpiBytes, size_t *mpiSize);
 
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadLongLongCompact(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
+static
+OSStatus ReadLongLongCompact(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value);
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value);
+static
+OSStatus ReadLongLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value);
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value);
+static
+OSStatus ReadLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint32_t* value);
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value);
+static
+OSStatus ReadShort(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint16_t* value);
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value);
+static
+OSStatus ReadByte(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint8_t* value);
 
-static CC_NONNULL((1,2,3))
-OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type);
+static
+OSStatus ReadMessageType(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, OTRMessageType* type);
 
-static CC_NONNULL((1,2,4))
-OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x);
+static
+OSStatus ReadMPI(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x);
 
-static CC_NONNULL((1,2,3,4))
-OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data);
+static
+OSStatus ReadDATA(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data);
 
-static CC_NONNULL((1,2,3))
-OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId);
+static
+OSStatus CreatePublicKey(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, _Nonnull SecOTRPublicIdentityRef *_Nonnull publicId);
 
-static CC_NONNULL((2,3))
-CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr);
+static
+CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef _Nullable allocator, const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr);
 
-static CC_NONNULL((1))
+static
 void AppendLongLongCompact(CFMutableDataRef appendTo, uint64_t value);
 
-static CC_NONNULL((1))
+static
 void AppendLongLong(CFMutableDataRef appendTo, uint64_t value);
 
-static CC_NONNULL((1))
+static
 void AppendLong(CFMutableDataRef appendTo, uint32_t value);
 
-static CC_NONNULL((1))
+static
 void AppendShort(CFMutableDataRef appendTo, uint16_t value);
 
-static CC_NONNULL((1))
+static
 void AppendByte(CFMutableDataRef appendTo, uint8_t type);
 
-static CC_NONNULL((1))
+static
 void AppendMessageType(CFMutableDataRef appendTo, OTRMessageType type);
 
-static CC_NONNULL((1,3))
+static
 void AppendMPI(CFMutableDataRef appendTo, cc_size n, const cc_unit *x);
 
-static CC_NONNULL((1,3))
+static
 void AppendDATA(CFMutableDataRef appendTo, size_t size, const uint8_t*data);
 
-static CC_NONNULL((1,2))
+static
 void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId);
 
     
@@ -122,7 +126,7 @@ void AppendPublicKey(CFMutableDataRef appendTo, SecOTRPublicIdentityRef publicId
 
 static uint16_t kCurrentOTRVersion = 0x2;
     
-static inline OSStatus ReadLongLong(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value)
+static inline OSStatus ReadLongLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -146,7 +150,7 @@ fail:
     return errSecParam;
 }
 
-static inline OSStatus ReadLongLongCompact(const uint8_t**bytesPtr, size_t*sizePtr, uint64_t* value)
+static inline OSStatus ReadLongLongCompact(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint64_t* value)
 {
     bool moreBytes = true;
 
@@ -172,7 +176,7 @@ fail:
     return !moreBytes ? errSecSuccess : errSecDecode;
 }
 
-static inline OSStatus ReadLong(const uint8_t**bytesPtr, size_t*sizePtr, uint32_t* value)
+static inline OSStatus ReadLong(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint32_t* value)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -192,7 +196,7 @@ fail:
     return errSecParam;
 }
     
-static inline OSStatus ReadShort(const uint8_t**bytesPtr, size_t*sizePtr, uint16_t* value)
+static inline OSStatus ReadShort(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint16_t* value)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -210,7 +214,7 @@ fail:
     return errSecParam;
 }
 
-static inline OSStatus ReadByte(const uint8_t**bytesPtr, size_t*sizePtr, uint8_t* value)
+static inline OSStatus ReadByte(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, uint8_t* value)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -227,7 +231,7 @@ fail:
     return errSecParam;
 }
 
-static inline OSStatus ReadByteAsBool(const uint8_t**bytesPtr, size_t*sizePtr, bool* value)
+static inline OSStatus ReadByteAsBool(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, bool* value)
 {
     uint8_t byte = 0;
 
@@ -239,7 +243,7 @@ static inline OSStatus ReadByteAsBool(const uint8_t**bytesPtr, size_t*sizePtr, b
     return result;
 }
     
-static inline OSStatus ReadMessageType(const uint8_t**bytesPtr, size_t*sizePtr, OTRMessageType* type)
+static inline OSStatus ReadMessageType(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, OTRMessageType* type)
 {
     OSStatus result = errSecParam;
     uint8_t value;
@@ -252,7 +256,7 @@ fail:
     return result;
 }
 
-static inline OSStatus ReadMPI(const uint8_t**bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x)
+static inline OSStatus ReadMPI(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, cc_size n, cc_unit *x)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -276,7 +280,7 @@ fail:
     
 }
     
-static inline OSStatus ReadDATA(const uint8_t**bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data)
+static inline OSStatus ReadDATA(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, size_t* dataSize, uint8_t* data)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -301,7 +305,7 @@ fail:
     
 }
     
-static inline OSStatus CreatePublicKey(const uint8_t**bytesPtr, size_t*sizePtr, SecOTRPublicIdentityRef* publicId)
+static inline OSStatus CreatePublicKey(const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr, _Nonnull SecOTRPublicIdentityRef *_Nonnull publicId)
 {
     require(bytesPtr != NULL, fail);
     require(sizePtr != NULL, fail);
@@ -336,7 +340,7 @@ fail:
     
 }
     
-static inline CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef allocator, const uint8_t**bytesPtr, size_t*sizePtr)
+static inline CFMutableDataRef CFDataCreateMutableFromOTRDATA(CFAllocatorRef _Nullable allocator, const uint8_t *_Nonnull *_Nonnull bytesPtr, size_t*sizePtr)
 {
     CFMutableDataRef result = NULL;
     uint32_t sizeInStream;
@@ -359,7 +363,7 @@ exit:
 //
 // Parse and verify functions
 //
-static inline OSStatus ReadAndVerifyByte(const uint8_t**bytes, size_t*size, uint8_t expected)
+static inline OSStatus ReadAndVerifyByte(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint8_t expected)
 {
     uint8_t found;
     OSStatus result = ReadByte(bytes, size, &found);
@@ -369,7 +373,7 @@ exit:
     return result;
 }
 
-static inline OSStatus ReadAndVerifyShort(const uint8_t**bytes, size_t*size, uint16_t expected)
+static inline OSStatus ReadAndVerifyShort(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, uint16_t expected)
 {
     uint16_t found;
     OSStatus result = ReadShort(bytes, size, &found);
@@ -379,7 +383,7 @@ exit:
     return result;
 }
 
-static inline OSStatus ReadAndVerifyMessageType(const uint8_t**bytes, size_t*size, OTRMessageType expected)
+static inline OSStatus ReadAndVerifyMessageType(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected)
 {
     OTRMessageType found;
     OSStatus result = ReadMessageType(bytes, size, &found);
@@ -389,12 +393,12 @@ exit:
     return result;
 }
 
-static inline OSStatus ReadAndVerifyVersion(const uint8_t**bytes, size_t*size)
+static inline OSStatus ReadAndVerifyVersion(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size)
 {
     return ReadAndVerifyShort(bytes, size, kCurrentOTRVersion);
 }
 
-static inline OSStatus ReadAndVerifyHeader(const uint8_t**bytes, size_t*size, OTRMessageType expected)
+static inline OSStatus ReadAndVerifyHeader(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType expected)
 {
     OSStatus result = ReadAndVerifyVersion(bytes, size);
     require_noerr_quiet(result, exit);
@@ -406,7 +410,7 @@ exit:
     return result;
 }
 
-static inline OSStatus ReadHeader(const uint8_t**bytes, size_t*size, OTRMessageType *messageType)
+static inline OSStatus ReadHeader(const uint8_t *_Nonnull *_Nonnull bytes, size_t*size, OTRMessageType *messageType)
 {
     OSStatus result = ReadAndVerifyVersion(bytes, size);
     require_noerr_quiet(result, exit);
@@ -418,8 +422,8 @@ exit:
     return result;
 }
 
-static inline OSStatus SizeAndSkipDATA(const uint8_t **bytes, size_t *size,
-                                const uint8_t **dataBytes, size_t *dataSize)
+static inline OSStatus SizeAndSkipDATA(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size,
+                                const uint8_t *_Nonnull *_Nonnull dataBytes, size_t *dataSize)
 {
     OSStatus result;
     uint32_t sizeRead;
@@ -436,8 +440,8 @@ exit:
     return result;
 }
 
-static inline OSStatus SizeAndSkipMPI(const uint8_t **bytes, size_t *size,
-                               const uint8_t **mpiBytes, size_t *mpiSize)
+static inline OSStatus SizeAndSkipMPI(const uint8_t *_Nonnull *_Nonnull bytes, size_t *size,
+                               const uint8_t *_Nonnull *_Nonnull mpiBytes, size_t *mpiSize)
 {
     // MPIs looke like data for skipping.
     return SizeAndSkipDATA(bytes, size, mpiBytes, mpiSize);
@@ -550,6 +554,8 @@ static inline void AppendHeader(CFMutableDataRef appendTo, OTRMessageType type)
     AppendMessageType(appendTo, type);
 }
 
+CF_ASSUME_NONNULL_END
+
 __END_DECLS
 
 #endif
index b0f666db27aa921f89d1c29cd5f03177fb9b4f2e..37cc0faa61069268552fb81ae8fc2cf339a5e9fe 100644 (file)
@@ -186,6 +186,7 @@ SecOTRPublicIdentityRef SecOTRPublicIdentityCreateFromBytes(CFAllocatorRef alloc
     const uint8_t* fullSequenceEnd = *bytes + *size;
 
     const uint8_t* keyData = ccder_decode_sequence_tl(&fullSequenceEnd, *bytes, fullSequenceEnd);
+    require(keyData != NULL, fail);
     size_t fullSize = (size_t)(fullSequenceEnd - *bytes);
     
     size_t   keyDataSize;
index 7e4ec3477fda3656c4288f5a4433be836ff59167..de5ad666a879f2070ed405543d4a1e97bfc6a7de 100644 (file)
@@ -1359,12 +1359,6 @@ abort:
 }
 
 
-OSStatus SecOTRSEndSession(SecOTRSessionRef session,
-                           CFMutableDataRef messageToSend)
-{
-    return errSecUnimplemented;
-}
-
 static CFDataRef data_to_data_error_request(enum SecXPCOperation op, CFDataRef publicPeerId, CFErrorRef *error) {
     __block CFDataRef result = NULL;
     securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
index 652a80004ebf045a8252b5ccf32d672a430ac8cf..05ac05d798c0db8593927513000fcdd97bd316ce 100644 (file)
@@ -80,10 +80,6 @@ OSStatus SecOTRSProcessPacket(SecOTRSessionRef session,
                               CFDataRef incomingPacket,
                               CFMutableDataRef negotiationResponse);
     
-OSStatus SecOTRSEndSession(SecOTRSessionRef session,
-                           CFMutableDataRef messageToSend);
-
-
 bool SecOTRSIsForKeys(SecOTRSessionRef session, SecKeyRef myPublic, SecKeyRef theirPublic);
 bool SecOTRSGetIsReadyForMessages(SecOTRSessionRef session);
 bool SecOTRSGetIsIdle(SecOTRSessionRef session);
index 2e15999cb14995f68d23011272c39d9b9789183f..5e32b6eb1fb337d3573572ca96daeca2376bed35 100644 (file)
 #include <utilities/array_size.h>
 #include <ipc/securityd_client.h>
 #include <os/variant_private.h>
+#include <MobileGestalt.h>
 
 #include <utilities/SecInternalReleasePriv.h>
 
+#include <Security/SecBase64.h>
+
 #undef POLICYCHECKMACRO
 #define POLICYCHECKMACRO(NAME, TRUSTRESULT, SUBTYPE, LEAFCHECK, PATHCHECK, LEAFONLY, CSSMERR, OSSTATUS) \
     const CFStringRef kSecPolicyCheck##NAME = CFSTR(#NAME);
@@ -76,7 +79,6 @@ const CFStringRef kSecPolicyApple##NAME = CFSTR("1.2.840.113635.100.1."#OID);
 #include "SecPolicy.list"
 //Some naming exceptions
 SEC_CONST_DECL(kSecPolicyMacAppStoreReceipt, "1.2.840.113635.100.1.19")
-SEC_CONST_DECL(kSecPolicyAppleIDValidationRecordSigningPolicy, "1.2.840.113635.100.1.30");
 
 SEC_CONST_DECL (kSecPolicyOid, "SecPolicyOid");
 SEC_CONST_DECL (kSecPolicyName, "SecPolicyName");
@@ -134,48 +136,9 @@ SEC_CONST_DECL (kSecPolicyNameAppleAMPService, "AMP");
 SEC_CONST_DECL (kSecPolicyNameAppleSiriService, "Siri");
 SEC_CONST_DECL (kSecPolicyNameAppleHomeAppClipUploadService, "HomeAppClipUploadService");
 SEC_CONST_DECL (kSecPolicyNameAppleUpdatesService, "Updates");
+SEC_CONST_DECL (kSecPolicyNameApplePushCertPortal, "PushCertPortal");
 
-#define kSecPolicySHA1Size 20
-#define kSecPolicySHA256Size 32
-__unused const UInt8 kAppleCASHA1[kSecPolicySHA1Size] = {
-    0x61, 0x1E, 0x5B, 0x66, 0x2C, 0x59, 0x3A, 0x08, 0xFF, 0x58,
-    0xD1, 0x4A, 0xE2, 0x24, 0x52, 0xD1, 0x98, 0xDF, 0x6C, 0x60
-};
-
-__unused static const UInt8 kAppleTESTCASHA1[kSecPolicySHA1Size] = {
-    0xbc, 0x30, 0x55, 0xc8, 0xc8, 0xd3, 0x48, 0x3f, 0xf4, 0x8d,
-    0xfe, 0x3d, 0x51, 0x75, 0x31, 0xc9, 0xf4, 0xd7, 0x4a, 0xf7
-};
-
-static const UInt8 kITMSCASHA1[kSecPolicySHA1Size] = {
-    0x1D, 0x33, 0x42, 0x46, 0x8B, 0x10, 0xBD, 0xE6, 0x45, 0xCE,
-    0x44, 0x6E, 0xBB, 0xE8, 0xF5, 0x03, 0x5D, 0xF8, 0x32, 0x22
-};
-
-static const UInt8 kFactoryDeviceCASHA1[kSecPolicySHA1Size] = {
-       0xef, 0x68, 0x73, 0x17, 0xa4, 0xf8, 0xf9, 0x4b, 0x7b, 0x21,
-       0xe2, 0x2f, 0x09, 0x8f, 0xfd, 0x6a, 0xae, 0xc0, 0x0d, 0x63
-};
-
-static const UInt8 kApplePKISettingsAuthority[kSecPolicySHA1Size] = {
-       0x1D, 0x0C, 0xBA, 0xAD, 0x17, 0xFD, 0x7E, 0x9E, 0x9F, 0xF1,
-       0xC9, 0xA2, 0x66, 0x79, 0x60, 0x00, 0x8B, 0xAE, 0x70, 0xB8
-};
-
-static const UInt8 kAppleTestPKISettingsAuthority[kSecPolicySHA1Size] = {
-       0xDB, 0xBA, 0x25, 0x0B, 0xD8, 0x62, 0x71, 0x87, 0x54, 0x7E,
-       0xD7, 0xEF, 0x11, 0x94, 0x7E, 0x82, 0xE6, 0xD8, 0x1C, 0x9A
-};
-
-static const UInt8 kTestAppleRootCA_ECC_SHA1[kSecPolicySHA1Size] = {
-       0x62, 0x0A, 0xED, 0x83, 0xD2, 0x97, 0x4A, 0x77, 0x56, 0x33,
-       0x83, 0xBE, 0xDB, 0xF9, 0xA1, 0xBD, 0x5F, 0xFE, 0x55, 0x7B
-};
-
-__unused static const UInt8 kAppleRootCA_ECC_SHA1[kSecPolicySHA1Size] = {
-    0xB5, 0x2C, 0xB0, 0x2F, 0xD5, 0x67, 0xE0, 0x35, 0x9F, 0xE8,
-    0xFA, 0x4D, 0x4C, 0x41, 0x03, 0x79, 0x70, 0xFE, 0x01, 0xB0
-};
+#define kSecPolicySHA256Size CC_SHA256_DIGEST_LENGTH
 
 // MARK: -
 // MARK: SecPolicy
@@ -390,6 +353,8 @@ SecPolicyRef SecPolicyCreateWithProperties(CFTypeRef policyIdentifier,
         policy = SecPolicyCreateAppleBasicAttestationUser(rootDigest);
     } else if (CFEqual(policyIdentifier, kSecPolicyAppleComponentCertificate)) {
         policy = SecPolicyCreateAppleComponentCertificate(rootDigest);
+    } else if (CFEqual(policyIdentifier, kSecPolicyAppleAggregateMetricTransparency)) {
+        policy = SecPolicyCreateAggregateMetricTransparency(!client);
     }
     /* For a couple of common patterns we use the macro, but some of the
      * policies are deprecated (or not yet available), so we need to ignore the warning. */
@@ -1227,29 +1192,13 @@ errOut:
     return result;
 }
 
-static bool SecPolicyAddAnchorSHA1Options(CFMutableDictionaryRef options,
-                                          const UInt8 anchorSha1[kSecPolicySHA1Size])
-{
-    bool success = false;
-    CFDataRef anchorData = NULL;
-
-    require(anchorData = CFDataCreate(kCFAllocatorDefault, anchorSha1, kSecPolicySHA1Size), errOut);
-    add_element(options, kSecPolicyCheckAnchorSHA1, anchorData);
-
-    success = true;
-
-errOut:
-    CFReleaseSafe(anchorData);
-    return success;
-}
-
 static bool SecPolicyAddAnchorSHA256Options(CFMutableDictionaryRef options,
-                                            const UInt8 anchorSha1[kSecPolicySHA256Size])
+                                            const UInt8 anchorSha256[kSecPolicySHA256Size])
 {
     bool success = false;
     CFDataRef anchorData = NULL;
 
-    require(anchorData = CFDataCreate(kCFAllocatorDefault, anchorSha1, kSecPolicySHA256Size), errOut);
+    require(anchorData = CFDataCreate(kCFAllocatorDefault, anchorSha256, kSecPolicySHA256Size), errOut);
     add_element(options, kSecPolicyCheckAnchorSHA256, anchorData);
 
     success = true;
@@ -1325,18 +1274,223 @@ static bool SecPolicyAddAppleAnchorOptions(CFMutableDictionaryRef options, CFStr
     return true;
 }
 
+CFDataRef CreateCFDataFromBase64CFString(CFStringRef base64string)
+{
+    __block CFDataRef cfData = NULL;
+
+    require_quiet(base64string, errOut);
+
+    CFStringPerformWithCStringAndLength(base64string, ^(const char *base64string_buf, size_t base64string_buf_length) {
+        void *data = NULL;
+
+        require_quiet(base64string_buf != NULL, errOut);
+        require_quiet(base64string_buf_length != 0, errOut);
+
+        size_t expected_data_length = SecBase64Decode(base64string_buf, base64string_buf_length, NULL, 0);
+        require_quiet(expected_data_length != 0, errOut);
+
+        data = malloc(expected_data_length);
+        require(data != NULL, errOut);
+
+        size_t actual_data_length = SecBase64Decode(base64string_buf, base64string_buf_length, data, expected_data_length);
+        require_quiet(actual_data_length != 0, errOut);
+
+        cfData = CFDataCreate(kCFAllocatorDefault, (const uint8_t *)data, actual_data_length);
+
+    errOut:
+        free(data);
+        return;
+    });
+
+errOut:
+    return cfData;
+}
+
+static CFStringRef CopyParentDomainNameFromHostName(CFStringRef hostName)
+{
+    CFStringRef parentDomainName = NULL;
+
+    require_quiet(hostName, errOut);
+
+    CFIndex hostNameLength = CFStringGetLength(hostName);
+    require_quiet(hostNameLength != 0, errOut);
+
+    CFRange nextLabel = CFStringFind(hostName, CFSTR("."), 0);
+    require_quiet(nextLabel.location != kCFNotFound && nextLabel.location < (hostNameLength - 1), errOut);
+
+    CFRange parentDomainNameRange = CFRangeMake(nextLabel.location + 1, hostNameLength - nextLabel.location - 1);
+    parentDomainName =  CFStringCreateWithSubstring(NULL, hostName, parentDomainNameRange);
+
+errOut:
+    return parentDomainName;
+}
+
+CFArrayRef parseNSPinnedDomains(CFDictionaryRef nsPinnedDomainsDict, CFStringRef hostName, CFStringRef nsPinnedIdentityType)
+{
+    CFMutableArrayRef targetSPKISHA256 = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+    __block bool hostNamePinned = false;
+
+    // Strip the trailing dot if any.
+    CFIndex hostNameLength = CFStringGetLength(hostName);
+    if (hostNameLength > 0 && '.' == CFStringGetCharacterAtIndex(hostName, hostNameLength - 1)) {
+        hostName = CFStringCreateWithSubstring(NULL, hostName, CFRangeMake(0, hostNameLength - 1));
+        require_quiet(hostName, errOut);
+    } else {
+        CFRetainSafe(hostName);
+    }
+
+    CFDictionaryForEach(nsPinnedDomainsDict, ^(const void *key, const void *value) {
+        CFStringRef parentDomainName = NULL;
+
+        require_quiet(isString(key), errOutNSPinnedDomainsDict);
+        require_quiet(isDictionary(value), errOutNSPinnedDomainsDict);
+
+        // Match one of the pinned domains to the current endpoint's hostname.
+        CFStringRef domainName = (CFStringRef)key;
+        bool hostNameMatched = (CFStringCompare(domainName, hostName, kCFCompareCaseInsensitive) == kCFCompareEqualTo);
+
+        // Match one of the pinned domains to the current endpoint's parent domain if allowed.
+        if (hostNameMatched == false) {
+            CFTypeRef nsIncludesSubdomains = CFDictionaryGetValue(value, CFSTR("NSIncludesSubdomains"));
+            require_quiet(nsIncludesSubdomains == kCFBooleanTrue, errOutNSPinnedDomainsDict);
+
+            parentDomainName = CopyParentDomainNameFromHostName(hostName);
+            require_quiet(parentDomainName != NULL, errOutNSPinnedDomainsDict);
+
+            hostNameMatched = (CFStringCompare(domainName, parentDomainName, kCFCompareCaseInsensitive) == kCFCompareEqualTo);
+        }
+        require_quiet(hostNameMatched, errOutNSPinnedDomainsDict);
+
+        CFTypeRef nsPinnedIdentities = CFDictionaryGetValue(value, nsPinnedIdentityType);
+        require_quiet(nsPinnedIdentities, errOutNSPinnedDomainsDict);
+        hostNamePinned = true;
+
+        require_quiet(isArray(nsPinnedIdentities), errOutNSPinnedDomainsDict);
+        CFArrayForEach(nsPinnedIdentities, ^(const void *v) {
+            CFDataRef spkiSHA256 = NULL;
+
+            require_quiet(isDictionary(v), errOutNSPinnedIdentities);
+
+            CFTypeRef spkiSHA256base64 = CFDictionaryGetValue(v, CFSTR("SPKI-SHA256-BASE64"));
+            require_quiet(isString(spkiSHA256base64), errOutNSPinnedIdentities);
+
+            spkiSHA256 = CreateCFDataFromBase64CFString(spkiSHA256base64);
+            require_quiet(spkiSHA256, errOutNSPinnedIdentities);
+
+            CFArrayAppendValue(targetSPKISHA256, spkiSHA256);
+
+        errOutNSPinnedIdentities:
+            CFReleaseSafe(spkiSHA256);
+        });
+
+    errOutNSPinnedDomainsDict:
+        CFReleaseSafe(parentDomainName);
+        return;
+    });
+
+errOut:
+    CFReleaseSafe(hostName);
+    if (hostNamePinned == false) {
+        CFReleaseNull(targetSPKISHA256);
+    }
+    return targetSPKISHA256;
+}
+
+static CFArrayRef getNSPinnedIdentitiesForHostName(CFStringRef hostName, CFStringRef nsPinnedIdentityType)
+{
+    CFMutableArrayRef targetSPKISHA256 = NULL;
+
+    static CFDictionaryRef nsPinnedDomainsDict = NULL;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        CFBundleRef bundle = CFBundleGetMainBundle();
+        require(bundle, initializationIncomplete);
+
+        CFTypeRef nsAppTransportSecurityDict = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("NSAppTransportSecurity"));
+        require_quiet(isDictionary(nsAppTransportSecurityDict), initializationIncomplete);
+
+        nsPinnedDomainsDict = CFDictionaryGetValue(nsAppTransportSecurityDict, CFSTR("NSPinnedDomains"));
+        require(isDictionary(nsPinnedDomainsDict), initializationIncomplete);
+        return;
+
+    initializationIncomplete:
+        nsPinnedDomainsDict = NULL;
+    });
+    // To proceed, this or a previous call must have found NSPinnedDomains in the info dictionary.
+    require_quiet(nsPinnedDomainsDict, errOut);
+
+    targetSPKISHA256 = (CFMutableArrayRef)parseNSPinnedDomains(nsPinnedDomainsDict, hostName, nsPinnedIdentityType);
+
+    // Return NULL if the hostname (or its parent domain name) is not among the pinned domains.
+    // Otherwise return an array of zero or more SPKI SHA256 identities.
+errOut:
+    return targetSPKISHA256;
+}
+
+static void SecPolicyAddATSpinningIfInfoSpecified(CFMutableDictionaryRef options)
+{
+    CFStringRef hostname = CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname);
+    require_quiet(isString(hostname), errOut);
+
+    CFArrayRef leafSPKISHA256 = getNSPinnedIdentitiesForHostName(hostname, CFSTR("NSPinnedLeafIdentities"));
+    if (leafSPKISHA256) {
+        add_element(options, kSecPolicyCheckLeafSPKISHA256, leafSPKISHA256);
+    }
+
+    CFArrayRef caSPKISHA256 = getNSPinnedIdentitiesForHostName(hostname, CFSTR("NSPinnedCAIdentities"));
+    if (caSPKISHA256) {
+        add_element(options, kSecPolicyCheckCAspkiSHA256, caSPKISHA256);
+    }
+
+errOut:
+    return;
+}
+
+void SecPolicyReconcilePinningRequiredIfInfoSpecified(CFMutableDictionaryRef options)
+{
+    bool hasPinningRequiredKey = false;
+    CFArrayRef leafSPKISHA256 = NULL;
+    CFArrayRef caSPKISHA256 = NULL;
+
+    hasPinningRequiredKey = CFDictionaryContainsKey(options, kSecPolicyCheckPinningRequired);
+    require_quiet(hasPinningRequiredKey, errOut);
+
+    // A non-NULL, empty, leafSPKISHA256 array allows all leaves and thus excludes this hostname from pinning.
+    leafSPKISHA256 = CFDictionaryGetValue(options, kSecPolicyCheckLeafSPKISHA256);
+    caSPKISHA256 = CFDictionaryGetValue(options, kSecPolicyCheckCAspkiSHA256);
+    if (isArray(leafSPKISHA256) && CFArrayGetCount(leafSPKISHA256) == 0 &&
+        isArray(caSPKISHA256) && CFArrayGetCount(caSPKISHA256) == 0) {
+        CFDictionaryRemoveValue(options, kSecPolicyCheckPinningRequired);
+    }
+
+    // kSecPolicyCheckPinningRequired and (kSecPolicyCheckLeafSPKISHA256, kSecPolicyCheckCAspkiSHA256) are mutually exclusive.
+    CFDictionaryRemoveValue(options, kSecPolicyCheckLeafSPKISHA256);
+    CFDictionaryRemoveValue(options, kSecPolicyCheckCAspkiSHA256);
+
+errOut:
+    return;
+}
+
 static bool SecPolicyAddPinningRequiredIfInfoSpecified(CFMutableDictionaryRef options)
 {
-    CFBundleRef bundle = CFBundleGetMainBundle();
-    if (bundle) {
-        CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("SecTrustPinningRequired"));
-        if (isBoolean(value) && CFBooleanGetValue(value)) {
-            add_element(options, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
+    static bool result = false;
+    static bool hasPinningRequiredKey = false;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        CFBundleRef bundle = CFBundleGetMainBundle();
+        if (bundle) {
+            CFTypeRef value = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR("SecTrustPinningRequired"));
+            if (isBoolean(value) && CFBooleanGetValue(value)) {
+                hasPinningRequiredKey = true;
+            }
+            result = true;
         }
-    } else {
-        return false;
+    });
+    if (result && hasPinningRequiredKey) {
+        add_element(options, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
     }
-    return true;
+    return result;
 }
 
 //
@@ -1380,6 +1534,8 @@ SecPolicyRef SecPolicyCreateSSL(Boolean server, CFStringRef hostname) {
         require_quiet(SecPolicyRemoveWeakHashOptions(options), errOut);
         require_quiet(SecPolicyAddStrongKeySizeOptions(options), errOut);
         require_quiet(SecPolicyAddPinningRequiredIfInfoSpecified(options), errOut);
+        SecPolicyAddATSpinningIfInfoSpecified(options);
+        SecPolicyReconcilePinningRequiredIfInfoSpecified(options);
         CFDictionaryAddValue(options, kSecPolicyCheckValidityPeriodMaximums, kCFBooleanTrue);
         CFDictionaryAddValue(options, kSecPolicyCheckServerAuthEKU, kCFBooleanTrue); // enforces stricter EKU rules than set_ssl_ekus below for certain anchor types
 #if !TARGET_OS_BRIDGE
@@ -1417,6 +1573,8 @@ SecPolicyRef SecPolicyCreateLegacySSL(Boolean server, CFStringRef hostname) {
     if (server) {
         // fewer requirements than the standard SSL policy
         require_quiet(SecPolicyAddPinningRequiredIfInfoSpecified(options), errOut);
+        SecPolicyAddATSpinningIfInfoSpecified(options);
+        SecPolicyReconcilePinningRequiredIfInfoSpecified(options);
         CFDictionaryAddValue(options, kSecPolicyCheckValidityPeriodMaximums, kCFBooleanTrue);
 #if !TARGET_OS_BRIDGE
         CFDictionaryAddValue(options, kSecPolicyCheckSystemTrustedCTRequired, kCFBooleanTrue);
@@ -1513,7 +1671,7 @@ fail:
 
 SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef hostname,
                                           CFStringRef intermediateMarkerOID, CFStringRef leafMarkerOID) {
-    CFMutableDictionaryRef options = NULL, appleAnchorOptions = NULL;
+    CFMutableDictionaryRef options = NULL;
     SecPolicyRef result = NULL;
 
     if (!policyName || !hostname || !leafMarkerOID) {
@@ -1578,7 +1736,6 @@ SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef h
 
 errOut:
     CFReleaseSafe(options);
-    CFReleaseSafe(appleAnchorOptions);
     return result;
 }
 
@@ -1653,6 +1810,13 @@ errOut:
        return result;
 }
 
+/* subject:/C=US/O=Apple Inc./OU=Apple iPhone/CN=[TEST] Apple iPhone Device CA */
+/* issuer :/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=[TEST] Apple iPhone Certification Authority */
+const uint8_t kFactoryDeviceCASHA256[CC_SHA256_DIGEST_LENGTH] = {
+    0x7b, 0x8e, 0xc8, 0x78, 0xff, 0x3a, 0xcf, 0x61, 0xdd, 0xe6, 0x53, 0x77, 0x2b, 0xe7, 0x32, 0xc5,
+    0x97, 0xf4, 0x6b, 0x9c, 0xa6, 0x00, 0xc5, 0x2c, 0xc1, 0x25, 0x85, 0x02, 0x03, 0x06, 0x97, 0x96
+};
+
 SecPolicyRef SecPolicyCreateFactoryDeviceCertificate(void) {
        CFMutableDictionaryRef options = NULL;
        SecPolicyRef result = NULL;
@@ -1662,16 +1826,9 @@ SecPolicyRef SecPolicyCreateFactoryDeviceCertificate(void) {
 
     SecPolicyAddBasicCertOptions(options);
 
-#if 0
-       CFDictionaryAddValue(options, kSecPolicyCheckKeyUsage,
-               kCFBooleanTrue);
-       CFDictionaryAddValue(options, kSecPolicyCheckExtendedKeyUsage,
-               kCFBooleanTrue);
-#endif
-
     /* Basic X.509 policy with the additional requirements that the chain
        is anchored at the factory device certificate issuer. */
-    require(SecPolicyAddAnchorSHA1Options(options, kFactoryDeviceCASHA1), errOut);
+    require(SecPolicyAddAnchorSHA256Options(options, kFactoryDeviceCASHA256), errOut);
 
        require(result = SecPolicyCreate(kSecPolicyAppleFactoryDeviceCertificate,
                                      kSecPolicyNameFactoryDeviceCertificate, options),
@@ -1710,6 +1867,13 @@ errOut:
        return result;
 }
 
+/* subject:/O=Apple Inc./OU=iTunes Store/CN=iTunes Store Root/C=US/ST=California/L=Cupertino */
+/* issuer :/O=Apple Inc./OU=iTunes Store/CN=iTunes Store Root/C=US/ST=California/L=Cupertino */
+const uint8_t kITMS_CA_SHA256[CC_SHA256_DIGEST_LENGTH] = {
+    0xa1, 0xdc, 0x36, 0x23, 0x84, 0xb4, 0xba, 0x0f, 0xaf, 0xea, 0x2a, 0xd4, 0xac, 0xc4, 0x86, 0x8f,
+    0xfb, 0xae, 0x57, 0x21, 0x4d, 0x20, 0x88, 0xc8, 0x82, 0xe7, 0x65, 0x13, 0x47, 0xab, 0x81, 0xd7
+};
+
 SecPolicyRef SecPolicyCreateiTunesStoreURLBag(void) {
        CFMutableDictionaryRef options = NULL;
        SecPolicyRef result = NULL;
@@ -1726,7 +1890,7 @@ SecPolicyRef SecPolicyCreateiTunesStoreURLBag(void) {
                CFSTR("iTunes Store URL Bag"));
 
     require(SecPolicyAddChainLengthOptions(options, 2), errOut);
-    require(SecPolicyAddAnchorSHA1Options(options, kITMSCASHA1), errOut);
+    require(SecPolicyAddAnchorSHA256Options(options, kITMS_CA_SHA256), errOut);
 
        require(result = SecPolicyCreate(kSecPolicyAppleiTunesStoreURLBag,
                                      kSecPolicyNameiTunesStoreURLBag, options), errOut);
@@ -2093,6 +2257,10 @@ SecPolicyRef SecPolicyCreateOCSPSigner(void) {
     /* Require id-kp-OCSPSigning extendedKeyUsage to be present, not optional. */
     add_eku(options, &oidExtendedKeyUsageOCSPSigning);
 
+    /* Check for digitalSignature KU and CA:FALSE. See <rdar://problem/65354714> */
+    add_ku(options, kSecKeyUsageDigitalSignature);
+    CFDictionarySetValue(options, kSecPolicyCheckNotCA, kCFBooleanTrue);
+
     require(result = SecPolicyCreate(kSecPolicyAppleOCSPSigner,
                                      kSecPolicyNameOCSPSigner, options), errOut);
 
@@ -2175,7 +2343,6 @@ SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef email) {
     if (smimeUsage & kSecSignSMIMEUsage) {
         add_ku(options, kSecKeyUsageUnspecified);
         add_ku(options, kSecKeyUsageDigitalSignature);
-        add_ku(options, kSecKeyUsageNonRepudiation);
     }
     if (smimeUsage & kSecKeyEncryptSMIMEUsage) {
         add_ku(options, kSecKeyUsageKeyEncipherment);
@@ -2183,31 +2350,18 @@ SecPolicyRef SecPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef email) {
     if (smimeUsage & kSecDataEncryptSMIMEUsage) {
         add_ku(options, kSecKeyUsageDataEncipherment);
     }
-    if (smimeUsage & kSecKeyExchangeDecryptSMIMEUsage) {
-        add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageDecipherOnly);
-    }
-    if (smimeUsage & kSecKeyExchangeEncryptSMIMEUsage) {
-        add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageEncipherOnly);
-    }
-    if (smimeUsage & kSecKeyExchangeBothSMIMEUsage) {
-        add_ku(options, kSecKeyUsageKeyAgreement | kSecKeyUsageEncipherOnly | kSecKeyUsageDecipherOnly);
+    if (smimeUsage & kSecKeyExchangeDecryptSMIMEUsage ||
+        smimeUsage & kSecKeyExchangeEncryptSMIMEUsage ||
+        smimeUsage & kSecKeyExchangeBothSMIMEUsage) {
+        /* <rdar://57130017> */
+        add_ku(options, kSecKeyUsageKeyAgreement);
     }
 
        if (email) {
                CFDictionaryAddValue(options, kSecPolicyCheckEmail, email);
        }
 
-    /* RFC 3850 paragraph 4.4.4
-
-       If the extended key usage extension is present in the certificate
-       then interpersonal message S/MIME receiving agents MUST check that it
-       contains either the emailProtection or the anyExtendedKeyUsage OID as
-       defined in [KEYM].  S/MIME uses other than interpersonal messaging
-       MAY require the explicit presence of the extended key usage extension
-       or other OIDs to be present in the extension or both.
-     */
     add_eku(options, NULL); /* eku extension is optional */
-    add_eku(options, &oidAnyExtendedKeyUsage);
     add_eku(options, &oidExtendedKeyUsageEmailProtection);
 
 #if !TARGET_OS_IPHONE
@@ -2691,21 +2845,19 @@ SecPolicyRef SecPolicyCreateConfigurationProfileSigner(void)
     return CreateConfigurationProfileSigner(false);
 }
 
-
 SecPolicyRef SecPolicyCreateQAConfigurationProfileSigner(void)
 {
-#if RC_SEED_BUILD
-    // Seed builds permit the QA signer
-    return CreateConfigurationProfileSigner(true);
-#else // !RC_SEED_BUILD
-    if (os_variant_has_internal_diagnostics("com.apple.security")) {
-        // Internal builds permit the QA signer
-        return CreateConfigurationProfileSigner(true);
+    CFStringRef releaseType = MGCopyAnswer(kMGQReleaseType, NULL);
+    SecPolicyRef result = NULL;
+    if (releaseType == NULL) {
+        // customer variants do not trust the QA signer
+        result = CreateConfigurationProfileSigner(false);
     } else {
-        // GM builds do not trust the QA signer
-        return CreateConfigurationProfileSigner(false);
+        // all other variants (beta, carrier, internal, etc) allow the QA signer
+        result = CreateConfigurationProfileSigner(true);
     }
-#endif // !RC_SEED_BUILD
+    CFReleaseNull(releaseType);
+    return result;
 }
 
 SecPolicyRef SecPolicyCreateOSXProvisioningProfileSigning(void)
@@ -2739,54 +2891,6 @@ errOut:
     return result;
 }
 
-
-SecPolicyRef SecPolicyCreateOTAPKISigner(void)
-{
-       SecPolicyRef result = NULL;
-       CFMutableDictionaryRef options = NULL;
-       require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                                     &kCFTypeDictionaryKeyCallBacks,
-                                                     &kCFTypeDictionaryValueCallBacks), errOut);
-       SecPolicyAddBasicX509Options(options);
-
-       SecPolicyAddAnchorSHA1Options(options, kApplePKISettingsAuthority);
-    require(SecPolicyAddChainLengthOptions(options, 2), errOut);
-
-       require(result = SecPolicyCreate(kSecPolicyAppleOTAPKISigner,
-                                     kSecPolicyNameOTAPKISigner, options), errOut);
-
-errOut:
-  CFReleaseSafe(options);
-  return result;
-
-}
-
-
-SecPolicyRef SecPolicyCreateTestOTAPKISigner(void)
-{
-    /* Guard against use on production devices */
-    if (!SecIsInternalRelease()) {
-        return SecPolicyCreateOTAPKISigner();
-    }
-
-       SecPolicyRef result = NULL;
-       CFMutableDictionaryRef options = NULL;
-       require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                                     &kCFTypeDictionaryKeyCallBacks,
-                                                     &kCFTypeDictionaryValueCallBacks), errOut);
-       SecPolicyAddBasicX509Options(options);
-
-       SecPolicyAddAnchorSHA1Options(options, kAppleTestPKISettingsAuthority);
-    require(SecPolicyAddChainLengthOptions(options, 2), errOut);
-
-       require(result = SecPolicyCreate(kSecPolicyAppleTestOTAPKISigner,
-                                     kSecPolicyNameTestOTAPKISigner, options), errOut);
-
-errOut:
-  CFReleaseSafe(options);
-  return result;
-}
-
 /*!
  @function SecPolicyCreateAppleSMPEncryption
  @abstract Check for intermediate certificate 'Apple System Integration CA - G3' by name,
@@ -2830,6 +2934,13 @@ errOut:
        return result;
 }
 
+/* subject:/CN=Test Apple Root CA - ECC/OU=Certification Authority/O=Apple Inc./C=US */
+/* issuer :/CN=Test Apple Root CA - ECC/OU=Certification Authority/O=Apple Inc./C=US */
+const uint8_t kTestAppleRootCA_ECC_SHA256[CC_SHA256_DIGEST_LENGTH] = {
+    0xe8, 0x6a, 0xd6, 0x5c, 0x74, 0x60, 0x21, 0x14, 0x47, 0xc6, 0x6a, 0xd7, 0x5f, 0xf8, 0x06, 0x7b,
+    0xec, 0xb5, 0x52, 0x7e, 0x4e, 0xa1, 0xac, 0x48, 0xcf, 0x3c, 0x53, 0x8f, 0x4d, 0x2b, 0x20, 0xa9
+};
+
 /*!
  @function SecPolicyCreateTestAppleSMPEncryption
  @abstract Check for intermediate certificate 'Test Apple System Integration CA - ECC' by name,
@@ -2845,7 +2956,7 @@ SecPolicyRef SecPolicyCreateTestAppleSMPEncryption(void)
                                                      &kCFTypeDictionaryValueCallBacks), errOut);
        SecPolicyAddBasicCertOptions(options);
 
-       SecPolicyAddAnchorSHA1Options(options, kTestAppleRootCA_ECC_SHA1);
+       SecPolicyAddAnchorSHA256Options(options, kTestAppleRootCA_ECC_SHA256);
        require(SecPolicyAddChainLengthOptions(options, 3), errOut);
 
        CFDictionaryAddValue(options, kSecPolicyCheckIssuerCommonName,
@@ -2923,7 +3034,6 @@ SecPolicyCreateAppleServerAuthCommon(CFStringRef hostname,
                                      const DERItem *leafMarkerOID,
                                      const DERItem *UATLeafMarkerOID)
 {
-    CFMutableDictionaryRef appleAnchorOptions = NULL;
     CFMutableDictionaryRef options = NULL;
     SecPolicyRef result = NULL;
     CFDataRef oid = NULL, uatoid = NULL;
@@ -2986,7 +3096,6 @@ SecPolicyCreateAppleServerAuthCommon(CFStringRef hostname,
     require(result, errOut);
 
 errOut:
-    CFReleaseSafe(appleAnchorOptions);
     CFReleaseSafe(options);
     CFReleaseSafe(oid);
     CFReleaseSafe(uatoid);
@@ -2999,12 +3108,10 @@ errOut:
  */
 SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef hostname)
 {
-    SecPolicyRef result = SecPolicyCreateSSL(true, hostname);
-
-    SecPolicySetOid(result, kSecPolicyAppleIDSService);
-    SecPolicySetName(result, kSecPolicyNameAppleIDSBag);
-
-    return result;
+    return SecPolicyCreateAppleServerAuthCommon(hostname, NULL, kSecPolicyAppleIDSService,
+                                                kSecPolicyNameAppleIDSBag,
+                                                &oidAppleCertExtAppleServerAuthenticationIDSProd,
+                                                &oidAppleCertExtAppleServerAuthenticationIDSProdQA);
 }
 
 /*!
@@ -3483,7 +3590,6 @@ errOut:
 }
 
 SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) {
-    CFMutableDictionaryRef appleAnchorOptions = NULL;
     CFMutableDictionaryRef options = NULL;
     SecPolicyRef result = NULL;
     CFDataRef oid = NULL;
@@ -3521,7 +3627,6 @@ SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname) {
     require(result, errOut);
 
 errOut:
-    CFReleaseSafe(appleAnchorOptions);
     CFReleaseSafe(options);
     CFReleaseSafe(oid);
     return result;
@@ -3668,9 +3773,6 @@ errOut:
 SecPolicyRef SecPolicyCreateAppleWarsaw(void) {
     CFMutableDictionaryRef options = NULL;
     SecPolicyRef result = NULL;
-#if TARGET_OS_BRIDGE
-    CFMutableDictionaryRef appleAnchorOptions = NULL;
-#endif
 
     require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                                 &kCFTypeDictionaryKeyCallBacks,
@@ -3785,9 +3887,6 @@ errOut:
 SecPolicyRef SecPolicyCreateMobileSoftwareUpdate(void) {
     CFMutableDictionaryRef options = NULL;
     SecPolicyRef result = NULL;
-#if TARGET_OS_BRIDGE
-    CFMutableDictionaryRef appleAnchorOptions = NULL;
-#endif
 
     require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                                                 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks), errOut);
@@ -4184,6 +4283,140 @@ errOut:
     return result;
 }
 
+/* subject:/CN=Apple External EC Root/O=Apple Inc./C=US */
+/* SKID: 3F:A4:C0:94:20:70:CB:3B:DD:A8:54:E6:14:1E:29:CC:4D:14:38:53 */
+/* Not Before: Jan 23 00:46:48 2020 GMT, Not After : Jan 18 00:00:00 2045 GMT */
+/* Signature Algorithm: ecdsa-with-SHA384 */
+const uint8_t AppleExternalECRoot_SHA256[kSecPolicySHA256Size] = {
+    0x72, 0x56, 0x6e, 0x6f, 0x66, 0x30, 0x0c, 0xfd, 0x24, 0xe5, 0xe6, 0x85, 0xa2, 0xf1, 0x5a, 0x74,
+    0x9d, 0xe0, 0x4b, 0xb0, 0x38, 0x50, 0x77, 0x91, 0x96, 0x63, 0x6e, 0x07, 0x23, 0x0f, 0x91, 0x1e
+};
+/* subject:/CN=Test Apple External EC Root/O=Apple Inc./C=US */
+/* SKID: 07:6B:07:47:33:E4:96:B4:FC:6F:FA:32:2C:8E:BE:70:C2:8F:80:3C */
+/* Not Before: Nov  5 18:00:46 2019 GMT, Not After : Oct 29 18:00:46 2044 GMT */
+/* Signature Algorithm: ecdsa-with-SHA384 */
+const uint8_t TestAppleExternalECRoot_SHA256[kSecPolicySHA256Size] = {
+    0xf3, 0x98, 0x39, 0xdc, 0x6a, 0x64, 0xf6, 0xe3, 0xa0, 0xdc, 0x97, 0xd7, 0x83, 0x61, 0x6b, 0x84,
+    0x9f, 0xdf, 0xa1, 0x70, 0x54, 0x59, 0xae, 0x96, 0x0f, 0x41, 0xe1, 0x16, 0xa3, 0xb4, 0x8b, 0xb5
+};
+SecPolicyRef SecPolicyCreateApplePayQRCodeEncryption(void) {
+    CFMutableDictionaryRef options = NULL;
+    SecPolicyRef result = NULL;
+
+    require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                &kCFTypeDictionaryKeyCallBacks,
+                                                &kCFTypeDictionaryValueCallBacks), errOut);
+
+    /* Check expiration */
+    SecPolicyAddBasicX509Options(options);
+
+    /* Exactly 3 certs in the chain */
+    require(SecPolicyAddChainLengthOptions(options, 3), errOut);
+
+    /* Apple External EC CA 1 - G1 */
+    add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.22"));
+
+    /* ApplePay QR Code Encryption */
+    add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.13.3"));
+
+    /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */
+    require(SecPolicyAddStrongKeySizeOptions(options), errOut);
+
+    require(SecPolicyAddAnchorSHA256Options(options, AppleExternalECRoot_SHA256),errOut);
+    if (SecIsInternalRelease()) {
+        require(SecPolicyAddAnchorSHA256Options(options, TestAppleExternalECRoot_SHA256),errOut);
+    }
+
+    /* Check revocation using any available method */
+    add_element(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny);
+
+    require(result = SecPolicyCreate(kSecPolicyApplePayQRCodeEncryption,
+                                     kSecPolicyNamePayQRCodeEncryption, options), errOut);
+
+errOut:
+    CFReleaseSafe(options);
+    return result;
+}
+
+SecPolicyRef SecPolicyCreateApplePayQRCodeSigning(void) {
+    CFMutableDictionaryRef options = NULL;
+    SecPolicyRef result = NULL;
+
+    require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                &kCFTypeDictionaryKeyCallBacks,
+                                                &kCFTypeDictionaryValueCallBacks), errOut);
+
+    /* Check expiration */
+    SecPolicyAddBasicX509Options(options);
+
+    /* Exactly 3 certs in the chain */
+    require(SecPolicyAddChainLengthOptions(options, 3), errOut);
+
+    /* Apple External EC CA 1 - G1 */
+    add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.22"));
+
+    /* ApplePay QR Code Signing */
+    add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.12.12"));
+
+    /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */
+    require(SecPolicyAddStrongKeySizeOptions(options), errOut);
+
+    require(SecPolicyAddAnchorSHA256Options(options, AppleExternalECRoot_SHA256),errOut);
+    if (SecIsInternalRelease()) {
+        require(SecPolicyAddAnchorSHA256Options(options, TestAppleExternalECRoot_SHA256),errOut);
+    }
+
+    /* Check revocation using any available method */
+    add_element(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny);
+
+    require(result = SecPolicyCreate(kSecPolicyApplePayQRCodeSigning,
+                                     kSecPolicyNamePayQRCodeSigning, options), errOut);
+
+errOut:
+    CFReleaseSafe(options);
+    return result;
+}
+
+SecPolicyRef SecPolicyCreateAppleAccessoryUpdateSigning(void) {
+    CFMutableDictionaryRef options = NULL;
+    SecPolicyRef result = NULL;
+
+    require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                &kCFTypeDictionaryKeyCallBacks,
+                                                &kCFTypeDictionaryValueCallBacks), errOut);
+
+    /* No expiration check */
+    SecPolicyAddBasicCertOptions(options);
+
+    /* Exactly 3 certs in the chain */
+    require(SecPolicyAddChainLengthOptions(options, 3), errOut);
+
+    /* Apple Anchor */
+    require_quiet(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAccessoryUpdateSigning), errOut);
+
+    /* Apple External EC CA 1 - G1 */
+    add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.17"));
+
+    /* Accessory Manufacturer Firmware Signing Prod */
+    add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.12.9"));
+    if (isCFPreferenceInSecurityDomain(CFSTR("AllowAccessoryUpdateSigningBeta"))) {
+        add_leaf_marker_string(options, CFSTR("1.2.840.113635.100.12.10")); // ProdQA
+    }
+
+    /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */
+    require(SecPolicyAddStrongKeySizeOptions(options), errOut);
+
+    /* Check revocation using any available method */
+    add_element(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny);
+
+    require(result = SecPolicyCreate(kSecPolicyAppleAccessoryUpdateSigning,
+                                     kSecPolicyNameAccessoryUpdateSigning, options), errOut);
+
+errOut:
+    CFReleaseSafe(options);
+    return result;
+}
+
 CF_RETURNS_RETAINED SecPolicyRef SecPolicyCreateEscrowServiceIdKeySigning(void)
 {
     SecPolicyRef result = NULL;
@@ -4235,3 +4468,51 @@ errOut:
     CFReleaseSafe(options);
     return result;
 }
+
+SecPolicyRef SecPolicyCreateAggregateMetricTransparency(bool facilitator)
+{
+    CFMutableDictionaryRef options = NULL;
+    SecPolicyRef result = NULL;
+
+    require(options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                                &kCFTypeDictionaryKeyCallBacks,
+                                                &kCFTypeDictionaryValueCallBacks), errOut);
+
+    SecPolicyAddBasicX509Options(options);
+
+    /* Anchored to the Apple Roots */
+    require(SecPolicyAddAppleAnchorOptions(options, kSecPolicyNameAggregateMetricTransparency), errOut);
+
+    /* Exactly 3 certs in the chain */
+    require(SecPolicyAddChainLengthOptions(options, 3), errOut);
+
+    /* Intermediate marker OID matches AAICA 6 */
+    add_element(options, kSecPolicyCheckIntermediateMarkerOid, CFSTR("1.2.840.113635.100.6.2.26"));
+
+    /* Leaf marker OID matches expected OID for either Facilitator or Partner */
+    if (facilitator) {
+        add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.12.17"));
+    } else {
+        add_element(options, kSecPolicyCheckLeafMarkerOidWithoutValueCheck, CFSTR("1.2.840.113635.100.12.18"));
+    }
+
+    /* Check revocation using any available method */
+    add_element(options, kSecPolicyCheckRevocation, kSecPolicyCheckRevocationAny);
+
+    /* RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger. */
+    require(SecPolicyAddStrongKeySizeOptions(options), errOut);
+
+    /* Require CT */
+    if (!SecIsInternalRelease() || !isCFPreferenceInSecurityDomain(CFSTR("disableAggregateMetricsCTCheck"))) {
+        add_element(options, kSecPolicyCheckCTRequired, kCFBooleanTrue);
+    }
+
+    /* Check for weak hashes */
+    // require(SecPolicyRemoveWeakHashOptions(options), errOut); // the current WWDR CA cert is signed with SHA1
+    require(result = SecPolicyCreate(kSecPolicyAppleAggregateMetricTransparency,
+                                     kSecPolicyNameAggregateMetricTransparency, options), errOut);
+
+errOut:
+    CFReleaseSafe(options);
+    return result;
+}
index 621b185596ded6b2d1db5ed397de7b1ec912cfd0..bd0ddbc41ff3cfddd96063ce22fabb02afd1a51f 100644 (file)
@@ -35,8 +35,6 @@ POLICYMACRO(EscrowService,                          24, E, AppleEscrowService,
 POLICYMACRO(ProfileSigner,                          25, E, AppleProfileSigner,                    , Y, ConfigurationProfileSigner)
 POLICYMACRO(QAProfileSigner,                        26, E, AppleQAProfileSigner,                  , Y, QAConfigurationProfileSigner)
 POLICYMACRO(TestMobileStore,                        27, E, AppleTestMobileStore,                  , Y, TestMobileStoreSigner)
-POLICYMACRO(OTAPKISigner,                           28, E, AppleOTAPKIAssetSigner,                , Y, OTAPKISigner)
-POLICYMACRO(TestOTAPKISigner,                       29, E, AppleTestOTAPKIAssetSigner,            , Y, TestOTAPKISigner)
 POLICYMACRO(IDValidationRecordSigning,              30, E, AppleIDValidationRecordSigningPolicy,  , Y, AppleIDValidationRecordSigningPolicy)
 POLICYMACRO(SMPEncryption,                          31, E, AppleSMPEncryption,                    , Y, AppleSMPEncryption)
 POLICYMACRO(TestSMPEncryption,                      32, E, AppleTestSMPEncryption,                , Y, TestAppleSMPEncryption)
@@ -101,6 +99,9 @@ POLICYMACRO(KeyTransparency,                        93, E, KT,
 POLICYMACRO(LegacySSL,                              94, E, legacySSL,                             ,  , LegacySSL)
 POLICYMACRO(Alisha,                                 95, E, Alisha,                                , Y, Alisha)
 POLICYMACRO(MeasuredBootPolicySigning,              96, E, MeasuredBootPolicySigning,             , Y, MeasuredBootPolicySigning)
-// 97-99 used on master
+POLICYMACRO(PayQRCodeEncryption,                    97, E, ApplePayQRCodeEncryption,              , Y, ApplePayQRCodeEncryption)
+POLICYMACRO(PayQRCodeSigning,                       98, E, ApplePayQRCodeSigning,                 , Y, ApplePayQRCodeSigning)
+POLICYMACRO(AccessoryUpdateSigning,                 99, E, AccessoryUpdateSigning,                , Y, AppleAccessoryUpdateSigning)
 POLICYMACRO(EscrowServiceIdKeySigning,             100, E, AppleEscrowServiceIdKeySigning,        , Y, EscrowServiceIdKeySigning)
 POLICYMACRO(PCSEscrowServiceIdKeySigning,          101, E, ApplePCSEscrowServiceIdKeySigning,     , Y, PCSEscrowServiceIdKeySigning)
+POLICYMACRO(AggregateMetricTransparency,           102, E, AggregateMetricTransparency,           ,  , AggregateMetricTransparency)
index 18072c46028352c919c6171a9927784eb46be26f..91f55d0f1fa8a37bf10a173a844124685c716e8b 100644 (file)
@@ -23,7 +23,7 @@ POLICYCHECKMACRO(TemporalValidity,               R, E, L, A, O, 0x8001210A, errS
 POLICYCHECKMACRO(WeakKeySize,                    F, S, L, A, O, 0x80012115, errSecUnsupportedKeySize) //CSSMERR_TP_INVALID_CERTIFICATE
 POLICYCHECKMACRO(WeakSignature,                  F, H, L, A, O, 0x80010955, errSecInvalidDigestAlgorithm) //CSSMERR_CSP_INVALID_DIGEST_ALGORITHM
 POLICYCHECKMACRO(KeyUsage,                       R, U, L,  , O, 0x80012406, errSecInvalidKeyUsageForPolicy) //CSSMERR_APPLETP_INVALID_KEY_USAGE
-POLICYCHECKMACRO(ExtendedKeyUsage,               R, U, L,  , O, 0x80012407, errSecInvalidExtendedKeyUsage) //CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
+POLICYCHECKMACRO(ExtendedKeyUsage,               R, U, L, A, O, 0x80012407, errSecInvalidExtendedKeyUsage) //CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
 POLICYCHECKMACRO(SubjectCommonName,              R, P, L,  , O, 0x8001243B, errSecInvalidSubjectName) //CSSMERR_APPLETP_IDENTIFIER_MISSING
 POLICYCHECKMACRO(SubjectCommonNamePrefix,        R, P, L,  , O, 0x8001243B, errSecInvalidSubjectName) //CSSMERR_APPLETP_IDENTIFIER_MISSING
 POLICYCHECKMACRO(SubjectCommonNameTEST,          R, P, L,  , O, 0x8001243B, errSecInvalidSubjectName) //CSSMERR_APPLETP_IDENTIFIER_MISSING
@@ -36,6 +36,8 @@ POLICYCHECKMACRO(LeafMarkerOidWithoutValueCheck, R, P, L,  , O, 0x80012439, errS
 POLICYCHECKMACRO(LeafMarkersProdAndQA,           R, P, L,  , O, 0x80012439, errSecMissingRequiredExtension) //CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
 POLICYCHECKMACRO(BlackListedLeaf,                F, B, L,  ,  , 0x8001210C, errSecCertificateRevoked) //CSSMERR_TP_CERT_REVOKED
 POLICYCHECKMACRO(GrayListedLeaf,                 R, T, L,  ,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
+POLICYCHECKMACRO(LeafSPKISHA256,                 R, P, L,  ,  , 0x8001243D, errSSLATSCertificateTrustViolation) //CSSMERR_APPLETP_LEAF_PIN_MISMATCH
+POLICYCHECKMACRO(NotCA,                          R, C, L,  , O, 0x80012116, errSecCertificateIsCA) // CSSMERR_TP_INVALID_CERT_AUTHORITY
 
 /********************************************************
 *********** Unverified Intermediate Checks *************
@@ -54,11 +56,11 @@ POLICYCHECKMACRO(IntermediateCountry,                    R, P,  , A,  , 0x800124
 /********************************************************
 ************** Unverified Anchor Checks ****************
 ********************************************************/
-POLICYCHECKMACRO(AnchorSHA1,                     R, P,  , A,  , 0x8001243C, errSecInvalidRoot) //CSSMERR_APPLETP_CA_PIN_MISMATCH
 POLICYCHECKMACRO(AnchorSHA256,                   R, P,  , A,  , 0x8001243C, errSecInvalidRoot) //CSSMERR_APPLETP_CA_PIN_MISMATCH
 POLICYCHECKMACRO(AnchorTrusted,                  R, T,  ,  ,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
 POLICYCHECKMACRO(MissingIntermediate,            R, T,  ,  ,  , 0x8001212A, errSecCreateChainFailed) //CSSMERR_TP_NOT_TRUSTED
 POLICYCHECKMACRO(AnchorApple,                    R, P,  , A,  , 0x8001243C, errSecInvalidRoot) //CSSMERR_APPLETP_CA_PIN_MISMATCH
+POLICYCHECKMACRO(CAspkiSHA256,                   R, P,  , A,  , 0x8001243C, errSSLATSCertificateTrustViolation) //CSSMERR_APPLETP_CA_PIN_MISMATCH
 
 /********************************************************
 *********** Unverified Certificate Checks **************
@@ -66,7 +68,7 @@ POLICYCHECKMACRO(AnchorApple,                    R, P,  , A,  , 0x8001243C, errS
 POLICYCHECKMACRO(NonEmptySubject,                R, C,  , A, O, 0x80012437, errSecInvalidSubjectName) //CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
 POLICYCHECKMACRO(IdLinkage,                      R, C,  , A,  , 0x80012404, errSecInvalidIDLinkage) //CSSMERR_APPLETP_INVALID_AUTHORITY_ID
 POLICYCHECKMACRO(KeySize,                        R, P,  , A, O, 0x80010918, errSecUnsupportedKeySize) //CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
-POLICYCHECKMACRO(SignatureHashAlgorithms,        R, P,  , A, O, 0x80010913, errSecInvalidDigestAlgorithm) //CSSMERR_CSP_ALGID_MISMATCH
+POLICYCHECKMACRO(SignatureHashAlgorithms,        R, H,  , A, O, 0x80010913, errSecInvalidDigestAlgorithm) //CSSMERR_CSP_ALGID_MISMATCH
 POLICYCHECKMACRO(CertificatePolicy,              R, P,  , A, O, 0x80012439, errSecInvalidPolicyIdentifiers) //CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
 POLICYCHECKMACRO(ValidRoot,                      R, E,  ,  ,  , 0x8001210A, errSecCertificateExpired) //CSSMERR_TP_CERT_EXPIRED
 
@@ -81,12 +83,12 @@ POLICYCHECKMACRO(PolicyConstraints,              R, C,  ,  ,  , 0x80012115, errS
 POLICYCHECKMACRO(GrayListedKey,                  R, T,  ,  ,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
 POLICYCHECKMACRO(BlackListedKey,                 F, B,  ,  ,  , 0x8001210C, errSecCertificateRevoked) //CSSMERR_TP_CERT_REVOKED
 POLICYCHECKMACRO(UsageConstraints,               D, D,  ,  ,  , 0x80012436, errSecTrustSettingDeny) //CSSMERR_APPLETP_TRUST_SETTING_DENY
-POLICYCHECKMACRO(SystemTrustedWeakHash,          R, C,  , A,  , 0x80010955, errSecInvalidDigestAlgorithm) //CSSMERR_CSP_INVALID_DIGEST_ALGORITHM
-POLICYCHECKMACRO(SystemTrustedWeakKey,           R, C,  , A,  , 0x80010918, errSecUnsupportedKeySize) //CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
+POLICYCHECKMACRO(SystemTrustedWeakHash,          R, H,  , A,  , 0x80010955, errSecInvalidDigestAlgorithm) //CSSMERR_CSP_INVALID_DIGEST_ALGORITHM
+POLICYCHECKMACRO(SystemTrustedWeakKey,           R, S,  , A,  , 0x80010918, errSecUnsupportedKeySize) //CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
 POLICYCHECKMACRO(PinningRequired,                R, P, L,  ,  , 0x8001243C, errSecInvalidRoot) //CSSMERR_APPLETP_CA_PIN_MISMATCH
 POLICYCHECKMACRO(Revocation,                     F, V, L,  ,  , 0x8001210C, errSecCertificateRevoked) //CSSMERR_TP_CERT_REVOKED
 POLICYCHECKMACRO(RevocationResponseRequired,     R, P, L,  ,  , 0x80012423, errSecIncompleteCertRevocationCheck) //CSSMERR_APPLETP_INCOMPLETE_REVOCATION_CHECK
-POLICYCHECKMACRO(CTRequired,                     R, T,  ,  ,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
+POLICYCHECKMACRO(CTRequired,                     R, T,  , A,  , 0x8001212A, errSecNotTrusted) //CSSMERR_TP_NOT_TRUSTED
 POLICYCHECKMACRO(SystemTrustedCTRequired,        R, C,  , A,  , 0x80012114, errSecVerifyActionFailed) //CSSMERR_TP_VERIFY_ACTION_FAILED
 POLICYCHECKMACRO(IssuerPolicyConstraints,        F, B,  ,  ,  , 0x80012120, errSecCertificatePolicyNotAllowed) //CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
 POLICYCHECKMACRO(IssuerNameConstraints,          F, B,  ,  ,  , 0x8001211F, errSecCertificateNameNotAllowed) //CSSMERR_TP_INVALID_NAME
index d7562db8e0a014b4e4f02b8c74c32f494993bb7e..36d614e4c6a94115260347df3a86a7ac4f195c0f 100644 (file)
@@ -62,6 +62,10 @@ static bool keyusage_allows(SecKeyUsage keyUsage, CFTypeRef xku) {
     SInt32 dku;
     CFNumberGetValue((CFNumberRef)xku, kCFNumberSInt32Type, &dku);
     SecKeyUsage ku = (SecKeyUsage)dku;
+    /* kSecKeyUsageUnspecified is a special sentinel for allowing a missing KU extension */
+    if (ku == kSecKeyUsageUnspecified) {
+        return (keyUsage == ku);
+    }
     return (keyUsage & ku) == ku;
 }
 
@@ -303,15 +307,13 @@ bool SecPolicyCheckCertSSLHostname(SecCertificateRef cert, CFTypeRef pvcValue) {
                obtained by SecCertificateCopyIPAddresses. Comparisons
                must always use the canonical data representation of the
                address, since string notation may omit zeros, etc. */
-            CFArrayRef ipAddresses = SecCertificateCopyIPAddresses(cert);
+            CFArrayRef ipAddresses = SecCertificateCopyIPAddressDatas(cert);
             CFIndex ix, count = (ipAddresses) ? CFArrayGetCount(ipAddresses) : 0;
             for (ix = 0; ix < count && !dnsMatch; ++ix) {
-                CFStringRef ipAddress = (CFStringRef)CFArrayGetValueAtIndex(ipAddresses, ix);
-                CFDataRef addrData = SecFrameworkCopyIPAddressData(ipAddress);
-                if (CFEqualSafe(hostIPData, addrData)) {
+                CFDataRef ipAddress = (CFDataRef)CFArrayGetValueAtIndex(ipAddresses, ix);
+                if (CFEqualSafe(hostIPData, ipAddress)) {
                     dnsMatch = true;
                 }
-                CFReleaseSafe(addrData);
             }
             CFReleaseSafe(ipAddresses);
             CFReleaseSafe(hostIPData);
@@ -693,6 +695,13 @@ bool SecPolicyCheckCertUnparseableExtension(SecCertificateRef cert, CFTypeRef pv
     return true;
 }
 
+bool SecPolicyCheckCertNotCA(SecCertificateRef cert, CFTypeRef pvcValue) {
+    if (SecCertificateIsCA(cert)) {
+        return false;
+    }
+    return true;
+}
+
 /*
  * MARK: SecLeafPVC functions
  */
index fb8f2c5123cce0a6e86e670182f816333ee84201..66f9f2393efc413b619190fce310d05cf12f6f7d 100644 (file)
@@ -607,12 +607,13 @@ static CFDataRef SecRSAPrivateKeyCreatePKCS1(CFAllocatorRef allocator, ccrsa_ful
 {
     const size_t result_size = ccrsa_export_priv_size(fullkey);
 
-       CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size);
+    CFMutableDataRef pkcs1 = CFDataCreateMutable(allocator, result_size);
 
-    if (pkcs1 == NULL)
+    if (pkcs1 == NULL) {
         return NULL;
+    }
 
-       CFDataSetLength(pkcs1, result_size);
+    CFDataSetLength(pkcs1, result_size);
 
     uint8_t *bytes = CFDataGetMutableBytePtr(pkcs1);
 
index a59b922a500510a6d8f28a1a7fc78f5db33d2e49..5f400e0201f05e8a396da298b7a0e555c8b8f39d 100644 (file)
@@ -9,9 +9,9 @@
 #import <corecrypto/cchkdf.h>
 #import <corecrypto/ccsha2.h>
 #import <corecrypto/ccec.h>
+#import <corecrypto/ccrng.h>
 
 #import <utilities/SecCFWrappers.h>
-#import <CommonCrypto/CommonRandomSPI.h>
 #import <AssertMacros.h>
 
 
@@ -301,7 +301,7 @@ RKBackupCreateECKey(SecRecoveryKey *rk, bool returnFullkey)
 
     status = ccec_generate_key_deterministic(cp,
                                              CFDataGetLength(derivedSecret), CFDataGetBytePtr(derivedSecret),
-                                             ccDRBGGetRngState(),
+                                             ccrng(NULL),
                                              CCEC_GENKEY_DETERMINISTIC_COMPACT,
                                              fullKey);
     require_noerr(status, fail);
index 507a181b8f9e3f1a4fae96afd1c2e1e840d341cb..e43f0f6b7756dd0828fe7fbb51245b220dab60d1 100644 (file)
@@ -327,11 +327,7 @@ CFDataRef SecCopyDecryptedForServer(SecKeyRef serverFullKey, CFDataRef blob, CFE
 CFDataRef SecCopyEncryptedToServer(SecTrustRef trustedEvaluation, CFDataRef dataToEncrypt, CFErrorRef *error)
 {
     CFDataRef result = NULL;
-#if TARGET_OS_OSX
-    SecKeyRef trustKey = SecTrustCopyPublicKey_ios(trustedEvaluation);
-#else
-    SecKeyRef trustKey = SecTrustCopyPublicKey(trustedEvaluation);
-#endif
+    SecKeyRef trustKey = SecTrustCopyKey(trustedEvaluation);
 
     require_action_quiet(trustKey, fail,
                          SecError(errSecInteractionNotAllowed, error, CFSTR("Failed to get key out of trust ref, was it evaluated?")));
index b9ec9bf600371e31ecbca8c3a91b51e93b317d56..f77c9af2fb63c5c70cf89ee21bf96221f0a2c03c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2014-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 /* forward declarations */
 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFStringRef password, CFErrorRef *error);
 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+OSStatus SecCopySharedWebCredentialSyncUsingAuthSvcs(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
+#endif
 
 #if SHAREDWEBCREDENTIALS
 
+// OSX now has SWC enabled, but cannot link SharedWebCredentials framework: rdar://59958701
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+
+OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
+    CFStringRef account,
+    CFStringRef password,
+    CFErrorRef *error)
+{
+    OSStatus status = errSecUnimplemented;
+    if (error) {
+        SecError(status, error, CFSTR("SecAddSharedWebCredentialSync not supported on this platform"));
+    }
+    return status;
+}
+
+#else
+
 OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
     CFStringRef account,
     CFStringRef password,
@@ -59,7 +79,7 @@ OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
     }
     status = SecOSStatusWith(^bool (CFErrorRef *error) {
         CFTypeRef raw_result = NULL;
-        bool xpc_result;
+        bool xpc_result = false;
         bool internal_spi = false; // TODO: support this for SecurityDevTests
         if(internal_spi && gSecurityd && gSecurityd->sec_add_shared_web_credential) {
             xpc_result = gSecurityd->sec_add_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
@@ -84,6 +104,7 @@ OSStatus SecAddSharedWebCredentialSync(CFStringRef fqdn,
 
     return status;
 }
+#endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
 #endif /* SHAREDWEBCREDENTIALS */
 
 void SecAddSharedWebCredential(CFStringRef fqdn,
@@ -147,6 +168,23 @@ void SecAddSharedWebCredential(CFStringRef fqdn,
 }
 
 #if SHAREDWEBCREDENTIALS
+
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+
+OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
+    CFStringRef account,
+    CFArrayRef *credentials,
+    CFErrorRef *error)
+{
+    OSStatus status = errSecUnimplemented;
+    if (error) {
+        SecError(status, error, CFSTR("SecCopySharedWebCredentialSync not supported on this platform"));
+    }
+    return status;
+}
+
+#else
+
 OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
     CFStringRef account,
     CFArrayRef *credentials,
@@ -164,7 +202,7 @@ OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
     }
     status = SecOSStatusWith(^bool (CFErrorRef *error) {
         CFTypeRef raw_result = NULL;
-        bool xpc_result;
+        bool xpc_result = false;
         bool internal_spi = false; // TODO: support this for SecurityDevTests
         if(internal_spi && gSecurityd && gSecurityd->sec_copy_shared_web_credential) {
             xpc_result = gSecurityd->sec_copy_shared_web_credential(args, NULL, NULL, NULL, SecAccessGroupsGetCurrent(), &raw_result, error);
@@ -192,6 +230,7 @@ OSStatus SecCopySharedWebCredentialSync(CFStringRef fqdn,
 
     return status;
 }
+#endif /* !TARGET_OS_OSX || !TARGET_OS_MACCATALYST */
 #endif /* SHAREDWEBCREDENTIALS */
 
 void SecRequestSharedWebCredential(CFStringRef fqdn,
@@ -227,7 +266,11 @@ void SecRequestSharedWebCredential(CFStringRef fqdn,
        __block CFStringRef accountStr = CFRetainSafe(account);
 
     dispatch_async(dst_queue, ^{
+#if TARGET_OS_OSX || TARGET_OS_MACCATALYST
+               OSStatus status = SecCopySharedWebCredentialSyncUsingAuthSvcs(serverStr, accountStr, &result, &error);
+#else
                OSStatus status = SecCopySharedWebCredentialSync(serverStr, accountStr, &result, &error);
+#endif
                CFReleaseSafe(serverStr);
                CFReleaseSafe(accountStr);
 
@@ -250,7 +293,7 @@ void SecRequestSharedWebCredential(CFStringRef fqdn,
         }
         CFReleaseSafe(error);
     });
-#endif
+#endif /* SHAREDWEBCREDENTIALS */
 
 }
 
diff --git a/OSX/sec/Security/SecSharedCredential.m b/OSX/sec/Security/SecSharedCredential.m
new file mode 100644 (file)
index 0000000..4fd5f18
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2020 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@
+ *
+ * SecSharedCredential.m - Retrieve shared credentials with AuthenticationServices.
+ *
+ */
+
+#include <Security/SecSharedCredential.h>
+#include <Security/SecBasePriv.h>
+#include <utilities/SecCFError.h>
+#include <utilities/SecCFWrappers.h>
+#include "SecItemInternal.h"
+#include <dlfcn.h>
+
+#import <Foundation/Foundation.h>
+#import <AuthenticationServices/AuthenticationServices.h>
+
+// Forward declaration of the primary function implemented in this file
+OSStatus SecCopySharedWebCredentialSyncUsingAuthSvcs(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error);
+
+// Classes we will load dynamically
+static Class kASAuthorizationClass = NULL;
+static Class kASAuthorizationControllerClass = NULL;
+static Class kASAuthorizationPasswordProviderClass = NULL;
+static Class kASPasswordCredentialClass = NULL;
+static Class kUIApplicationClass = NULL;
+static Class kNSApplicationClass = NULL;
+
+static void loadAuthenticationServices(void) {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        const char *path = "/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices";
+        if ( [NSProcessInfo processInfo].macCatalystApp == YES ) {
+            path = "/System/iOSSupport/System/Library/Frameworks/AuthenticationServices.framework/AuthenticationServices";
+        }
+        void* lib_handle = dlopen(path, RTLD_LAZY);
+        if (lib_handle != NULL) {
+            kASAuthorizationClass = NSClassFromString(@"ASAuthorization");
+            kASAuthorizationControllerClass = NSClassFromString(@"ASAuthorizationController");
+            kASAuthorizationPasswordProviderClass = NSClassFromString(@"ASAuthorizationPasswordProvider");
+            kASPasswordCredentialClass = NSClassFromString(@"ASPasswordCredential");
+        }
+    });
+}
+
+static void loadUIKit(void) {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        const char *path = "/System/Library/Frameworks/UIKit.framework/UIKit";
+        if ( [NSProcessInfo processInfo].macCatalystApp == YES ) {
+            path = "/System/Library/iOSSupport/System/Library/Frameworks/UIKit.framework/UIKit";
+        }
+        void* lib_handle = dlopen(path, RTLD_LAZY);
+        if (lib_handle != NULL) {
+            kUIApplicationClass = NSClassFromString(@"UIApplication");
+        }
+    });
+}
+
+static void loadAppKit(void) {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        const char *path = "/System/Library/Frameworks/AppKit.framework/AppKit";
+        void* lib_handle = dlopen(path, RTLD_LAZY);
+        if (lib_handle != NULL) {
+            kNSApplicationClass = NSClassFromString(@"NSApplication");
+        }
+    });
+}
+
+static Class ASAuthorizationClass() {
+    loadAuthenticationServices();
+    return kASAuthorizationClass;
+}
+
+static Class ASAuthorizationControllerClass() {
+    loadAuthenticationServices();
+    return kASAuthorizationControllerClass;
+}
+
+static Class ASAuthorizationPasswordProviderClass() {
+    loadAuthenticationServices();
+    return kASAuthorizationPasswordProviderClass;
+}
+
+static Class ASPasswordCredentialClass() {
+    loadAuthenticationServices();
+    return kASPasswordCredentialClass;
+}
+
+static Class UIApplicationClass() {
+    loadUIKit();
+    return kUIApplicationClass;
+}
+
+static Class NSApplicationClass() {
+    loadAppKit();
+    return kNSApplicationClass;
+}
+
+@interface SharedCredentialController : NSObject
+    <ASAuthorizationControllerDelegate,
+     ASAuthorizationControllerPresentationContextProviding>
+
+-(ASPasswordCredential *)passwordCredential;
+
+@end
+
+@implementation SharedCredentialController {
+    ASAuthorizationPasswordProvider *_provider;
+    ASAuthorizationController *_controller;
+    ASPasswordCredential *_passwordCredential;
+    dispatch_semaphore_t _semaphore;
+    NSError *_error;
+    OSStatus _result;
+}
+
+- (void)dealloc {
+    // Don't want any further callbacks since we are going away
+    _controller.delegate = nil;
+    _controller.presentationContextProvider = nil;
+}
+
+- (void)_requestCredential {
+    if (!_provider) {
+        _provider = [[ASAuthorizationPasswordProviderClass() alloc] init];
+    }
+    if (!_controller) {
+        _controller = [[ASAuthorizationControllerClass() alloc] initWithAuthorizationRequests:@[ [_provider createRequest] ]];
+    }
+    _controller.delegate = self;
+    _controller.presentationContextProvider = self;
+    _semaphore = dispatch_semaphore_create(0);
+    _result = errSecItemNotFound;
+    _error = nil;
+
+    [_controller performRequests];
+}
+
+- (ASPasswordCredential *)passwordCredential {
+    if (_passwordCredential) {
+        return _passwordCredential;
+    }
+    BOOL shouldRequest = YES; // ( [NSProcessInfo processInfo].macCatalystApp == YES );
+    if (shouldRequest) {
+        [self _requestCredential];
+        // wait synchronously until user picks a credential or cancels
+        dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
+    } else {
+        // unable to return a shared credential: <rdar://problem/59958701>
+        _result = errSecItemNotFound;
+        _error = [[NSError alloc] initWithDomain:NSOSStatusErrorDomain code:_result userInfo:NULL];
+    }
+    return _passwordCredential;
+}
+
+- (NSError *)error {
+    return _error;
+}
+
+- (OSStatus)result {
+    return _result;
+}
+
+- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithAuthorization:(ASAuthorization *)authorization {
+    secinfo("swcagent", "SWC received didCompleteWithAuthorization");
+    ASPasswordCredential *passwordCredential = authorization.credential;
+    if (![passwordCredential isKindOfClass:[ASPasswordCredentialClass() class]]) {
+        _passwordCredential = nil;
+        _result = errSecItemNotFound;
+    } else {
+        _passwordCredential = passwordCredential;
+        _result = errSecSuccess;
+    }
+    dispatch_semaphore_signal(_semaphore);
+}
+
+- (void)authorizationController:(ASAuthorizationController *)controller didCompleteWithError:(NSError *)error {
+    secinfo("swcagent", "SWC received didCompleteWithError");
+    _passwordCredential = nil;
+    _error = error;
+    _result = errSecItemNotFound;
+    dispatch_semaphore_signal(_semaphore);
+}
+
+- (ASPresentationAnchor)presentationAnchorForAuthorizationController:(ASAuthorizationController *)controller
+{
+    ASPresentationAnchor anchorWindow = nil;
+#if TARGET_OS_OSX
+    if ( [NSProcessInfo processInfo].macCatalystApp == NO ) {
+        anchorWindow = [[NSApplicationClass() sharedApplication] keyWindow];
+    }
+#endif
+    if (!anchorWindow) {
+        anchorWindow = [[UIApplicationClass() sharedApplication] keyWindow];
+    }
+    return anchorWindow;
+}
+
+@end
+
+OSStatus SecCopySharedWebCredentialSyncUsingAuthSvcs(CFStringRef fqdn, CFStringRef account, CFArrayRef *credentials, CFErrorRef *error) {
+    SharedCredentialController *controller = [[SharedCredentialController alloc] init];
+    ASPasswordCredential *passwordCredential = [controller passwordCredential];
+    OSStatus status = [controller result];
+    NSArray *returnedCredentials = @[];
+    if (status != errSecSuccess) {
+        secinfo("swcagent", "SecCopySharedWebCredentialSyncUsingAuthSvcs received result %d", (int)status);
+        if (error) {
+            *error = (CFErrorRef)CFBridgingRetain([controller error]);
+        }
+    } else if (passwordCredential) {
+        // Use the .user and .password of the passwordCredential to satisfy the SWC interface.
+        NSDictionary *credential = @{
+            (id)kSecAttrServer : (__bridge NSString*)fqdn,
+            (id)kSecAttrAccount : passwordCredential.user,
+            (id)kSecSharedPassword : passwordCredential.password,
+        };
+        returnedCredentials = @[ credential ];
+    } else {
+        secinfo("swcagent", "SecCopySharedWebCredentialSyncUsingAuthSvcs found no credential");
+        status = errSecItemNotFound;
+    }
+    if (credentials) {
+        *credentials = (CFArrayRef)CFBridgingRetain(returnedCredentials);
+    }
+    return status;
+}
index d64de6dd4b7923bce1416c602c0f5cee9d43fcd9..ba6a8f66c0af95aae06dd467a9a613cf9e2b50d4 100644 (file)
@@ -1834,15 +1834,7 @@ CFStringRef SecTrustCopyFailureDescription(SecTrustRef trust) {
     return reason;
 }
 
-#if TARGET_OS_OSX
-/* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
-   so we will refer to this one internally as SecTrustCopyPublicKey_ios,
-   and call it from SecTrustCopyPublicKey.
- */
-SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
-#else
-SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
-#endif
+SecKeyRef SecTrustCopyKey(SecTrustRef trust)
 {
     if (!trust) {
         return NULL;
@@ -1870,7 +1862,20 @@ SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
             }
         });
     }
-       return publicKey;
+    return publicKey;
+}
+
+#if TARGET_OS_OSX
+/* On OS X we need SecTrustCopyPublicKey to give us a CDSA-based SecKeyRef,
+   so we will refer to this one internally as SecTrustCopyPublicKey_ios,
+   and call it from SecTrustCopyPublicKey.
+ */
+SecKeyRef SecTrustCopyPublicKey_ios(SecTrustRef trust)
+#else
+SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
+#endif
+{
+    return SecTrustCopyKey(trust);
 }
 
 CFIndex SecTrustGetCertificateCount(SecTrustRef trust) {
@@ -2222,7 +2227,6 @@ static void applyDetailProperty(const void *_key, const void *_value,
     } else if (CFEqual(key, kSecPolicyCheckCriticalExtensions)) {
         tf->unknownCritExtn = true;
     } else if (CFEqual(key, kSecPolicyCheckAnchorTrusted)
-        || CFEqual(key, kSecPolicyCheckAnchorSHA1)
         || CFEqual(key, kSecPolicyCheckAnchorSHA256)
         || CFEqual(key, kSecPolicyCheckAnchorApple)) {
         tf->untrustedAnchor = true;
@@ -2576,6 +2580,18 @@ CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef *error) {
     return result;
 }
 
+bool SecTrustTriggerValidUpdate(CFErrorRef *error) {
+    do_if_registered(sec_valid_update, error);
+
+    os_activity_t activity = os_activity_create("SecTrustTriggerValidUpdate", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    uint64_t num = do_ota_pki_op(kSecXPCOpValidUpdate, error);
+
+    os_release(activity);
+    return num;
+}
+
 bool SecTrustReportTLSAnalytics(CFStringRef eventName, xpc_object_t eventAttributes, CFErrorRef *error) {
     if (!eventName || !eventAttributes) {
         return false;
index 4921bdd9ec5ae979d1d7d009fb07ae010ea8d132..8d11e5fc00f2c7e941e6f5ab678bddac596d5261 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2015-2016 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2015-2020 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,
@@ -17,7 +17,7 @@
  * 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@
  */
 
@@ -44,6 +44,7 @@ __BEGIN_DECLS
 #define kSecTrustTrustedLogsKey "trustedLogs"
 #define kSecTrustVerifyDateKey "verifyDate"
 #define kSecTrustExceptionsKey "exceptions"
+#define kSecTrustRevocationAdditionsKey "revocationCheck"
 
 /* args_out keys. */
 #define kSecTrustDetailsKey "details"
index 32f84c3b5aec34782d5e89d7f431091067a780d1..c6a51c86be05ad2e46905e053b359f96faf57c3b 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2007-2018 Apple Inc. All Rights Reserved.
- * 
+ * Copyright (c) 2007-2020 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,
  * 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@
  */
 
-/* 
+/*
  * SecTrustStore.c - CertificateSource API to a system root certificate store
  */
 #include <Security/SecTrustStore.h>
@@ -95,12 +95,12 @@ Boolean SecTrustStoreContains(SecTrustStoreRef ts,
 
        require(ts, errOut);
        require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
-    
+
 
     ok = (SecOSStatusWith(^bool (CFErrorRef *error) {
         return TRUSTD_XPC(sec_trust_store_contains, string_data_to_bool_bool_error, ts, digest, &contains, error);
     }) == errSecSuccess);
-    
+
 errOut:
        return ok && contains;
 }
@@ -206,7 +206,7 @@ OSStatus SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
     Boolean isSelfSigned = false;
     require_noerr_quiet(result = SecCertificateIsSelfSigned(certificate, &isSelfSigned), out);
     require_noerr_quiet(result = validateTrustSettings(isSelfSigned, trustSettingsDictOrArray, &validatedTrustSettings), out);
-    
+
     os_activity_initiate("SecTrustStoreSetTrustSettings", OS_ACTIVITY_FLAG_DEFAULT, ^{
         result = SecOSStatusWith(^bool (CFErrorRef *error) {
             return TRUSTD_XPC(sec_trust_store_set_trust_settings, string_cert_cftype_to_error, ts, certificate, validatedTrustSettings, error);
@@ -229,7 +229,7 @@ OSStatus SecTrustStoreRemoveCertificate(SecTrustStoreRef ts,
     require(ts, errOut);
     require(digest = SecCertificateGetSHA1Digest(certificate), errOut);
     require(gTrustd || ts == (SecTrustStoreRef)kSecTrustStoreUserName, errOut);
-    
+
     status = SecOSStatusWith(^bool (CFErrorRef *error) {
         return TRUSTD_XPC(sec_trust_store_remove_certificate, string_data_to_bool_error, ts, digest, error);
     });
@@ -262,12 +262,12 @@ OSStatus SecTrustStoreGetSettingsAssetVersionNumber(SecTrustSettingsAssetVersion
     if (NULL == p_settings_asset_version_number) {
         return errSecParam;
     }
-    
+
     OSStatus status = errSecSuccess;
     CFErrorRef error = nil;
     uint64_t versionNumber = SecTrustGetAssetVersionNumber(&error);
     *p_settings_asset_version_number = (SecTrustSettingsAssetVersionNumber)versionNumber;
-    
+
     if (error) {
         status = (OSStatus)CFErrorGetCode(error);
     }
@@ -404,3 +404,73 @@ CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier,
     return NULL;
 #endif // TARGET_OS_BRIDGE
 }
+
+/* MARK: CA Revocation Additions */
+
+/* Specify explicit additions to the list of known CAs for which revocation will be checked.
+ * Input: dictionary with following key and value:
+ *   Key = kSecCARevocationAdditionsKey; Value = Array of dictionaries
+ * For revocation checking to be enabled for certificates issued by a CA, the CA must be specified as a
+ * dictionary entry containing the hash of the subjectPublicKeyInfo that appears in the CA certificate:
+ *   Key = kSecCARevocationHashAlgorithmKey; Value = String. Currently, must be ”sha256”.
+ *   Key = kSecCARevocationSPKIHashKey; Value = Data. Created by applying the specified hash algorithm
+ *   to the DER encoding of the certificate's subjectPublicKeyInfo.
+*/
+
+const CFStringRef kSecCARevocationAdditionsKey = CFSTR("EnabledForCAs");
+const CFStringRef kSecCARevocationHashAlgorithmKey = CFSTR("HashAlgorithm");
+const CFStringRef kSecCARevocationSPKIHashKey = CFSTR("SubjectPublicKeyInfoHash");
+
+bool SecTrustStoreSetCARevocationAdditions(CFStringRef applicationIdentifier, CFDictionaryRef additions, CFErrorRef *error) {
+#if !TARGET_OS_BRIDGE
+    if (applicationIdentifier && gTrustd && gTrustd->sec_trust_store_set_ca_revocation_additions) {
+        return gTrustd->sec_trust_store_set_ca_revocation_additions(applicationIdentifier, additions, error);
+    } else if (gTrustd && gTrustd->sec_trust_store_set_ca_revocation_additions) {
+        /* When calling from the TrustTests, we need to pass the appID for the tests. Ordinarily,
+         * this is done by trustd using the client's entitlements. */
+        return gTrustd->sec_trust_store_set_ca_revocation_additions(CFSTR("com.apple.trusttests"), additions, error);
+    }
+
+    os_activity_t activity = os_activity_create("SecTrustStoreSetCARevocationAdditions", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    __block bool result = false;
+    securityd_send_sync_and_do(kSecXPCOpSetCARevocationAdditions, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+        SecXPCDictionarySetPListOptional(message, kSecTrustRevocationAdditionsKey, additions, block_error);
+        SecXPCDictionarySetStringOptional(message, kSecTrustEventApplicationID, applicationIdentifier, block_error);
+        return true;
+    }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
+        result = SecXPCDictionaryGetBool(response, kSecXPCKeyResult, block_error);
+        return true;
+    });
+
+    os_release(activity);
+    return result;
+#else // TARGET_OS_BRIDGE
+    return SecError(errSecReadOnly, error, CFSTR("SecTrustStoreSetCARevocationAdditions not supported on bridgeOS"));
+#endif // TARGET_OS_BRIDGE
+}
+
+CFDictionaryRef SecTrustStoreCopyCARevocationAdditions(CFStringRef applicationIdentifier, CFErrorRef *error) {
+#if !TARGET_OS_BRIDGE
+    do_if_registered(sec_trust_store_copy_ca_revocation_additions, applicationIdentifier, error);
+
+    os_activity_t activity = os_activity_create("SecTrustStoreCopyCARevocationAdditions", OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT);
+    os_activity_scope(activity);
+
+    __block CFDictionaryRef result = NULL;
+    securityd_send_sync_and_do(kSecXPCOpCopyCARevocationAdditions, error, ^bool(xpc_object_t message, CFErrorRef *block_error) {
+        SecXPCDictionarySetStringOptional(message, kSecTrustEventApplicationID, applicationIdentifier, block_error);
+        return true;
+    }, ^bool(xpc_object_t response, CFErrorRef *block_error) {
+        (void)SecXPCDictionaryCopyDictionaryOptional(response, kSecTrustRevocationAdditionsKey, &result, block_error);
+        return true;
+    });
+
+    os_release(activity);
+    return result;
+#else // TARGET_OS_BRIDGE
+    SecError(errSecReadOnly, error, CFSTR("SecTrustStoreCopyCARevocationAdditions not supported on bridgeOS"));
+    return NULL;
+#endif // TARGET_OS_BRIDGE
+}
index 698ae145def6ccec094cbe6ed2ef2c26a7cc5eee..085760038fc07dcfea6a5d4b46ea65d975d31632 100644 (file)
@@ -143,24 +143,14 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("RejectApplicants");
         case kSecXPCOpRemoveThisDeviceFromCircle:
             return CFSTR("RemoveThisDeviceFromCircle");
-        case kSecXPCOpRemoveThisDeviceFromCircleWithAnalytics:
-            return CFSTR("RemoveThisDeviceFromCircleWithAnalytics");
         case kSecXPCOpRemovePeersFromCircle:
             return CFSTR("RemovePeersFromCircle");
-        case kSecXPCOpRemovePeersFromCircleWithAnalytics:
-            return CFSTR("RemovePeersFromCircleWithAnalytics");
         case kSecXPCOpRequestToJoin:
             return CFSTR("RequestToJoin");
-        case kSecXPCOpRequestToJoinWithAnalytics:
-            return CFSTR("RequestToJoinWithAnalytics");
         case kSecXPCOpRequestToJoinAfterRestore:
             return CFSTR("RequestToJoinAfterRestore");
-        case kSecXPCOpRequestToJoinAfterRestoreWithAnalytics:
-            return CFSTR("RequestToJoinAfterRestoreWithAnalytics");
         case kSecXPCOpResetToEmpty:
             return CFSTR("ResetToEmpty");
-        case kSecXPCOpResetToEmptyWithAnalytics:
-            return CFSTR("ResetToEmptyWithAnalytics");
         case kSecXPCOpResetToOffering:
             return CFSTR("ResetToOffering");
         case kSecXPCOpRollKeys:
@@ -175,8 +165,6 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("SetUserCredentials");
         case kSecXPCOpSetUserCredentialsAndDSID:
             return CFSTR("SetUserCredentialsAndDSID");
-        case kSecXPCOpSetUserCredentialsAndDSIDWithAnalytics:
-            return CFSTR("SetUserCredentialsAndDSIDWithAnalytics");
         case kSecXPCOpTryUserCredentials:
             return CFSTR("TryUserCredentials");
         case kSecXPCOpValidateUserPublic:
@@ -195,6 +183,8 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("add");
         case sec_item_backup_copy_names_id:
             return CFSTR("backup_copy_names");
+        case sec_item_backup_ensure_copy_view_id:
+            return CFSTR("backup_register_view");
         case sec_item_backup_handoff_fd_id:
             return CFSTR("backup_handoff_fd");
         case sec_item_backup_restore_id:
@@ -249,7 +239,7 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("WhoAmI");
         case kSecXPCOpTransmogrifyToSyncBubble:
             return CFSTR("TransmogrifyToSyncBubble");
-        case sec_item_update_token_items_id:
+        case sec_item_update_token_items_for_access_groups_id:
             return CFSTR("UpdateTokenItems");
         case sec_delete_items_with_access_groups_id:
             return CFSTR("sec_delete_items_with_access_groups_id");
@@ -283,22 +273,34 @@ CFStringRef SOSCCGetOperationDescription(enum SecXPCOperation op)
             return CFSTR("GetExceptionResetCount");
         case sec_trust_increment_exception_reset_count_id:
             return CFSTR("IncrementExceptionResetCount");
+        case kSecXPCOpSetCARevocationAdditions:
+            return CFSTR("SetCARevocationAdditions");
+        case kSecXPCOpCopyCARevocationAdditions:
+            return CFSTR("CopyCARevocationAdditions");
+        case kSecXPCOpValidUpdate:
+            return CFSTR("ValidUpdate");
         default:
             return CFSTR("Unknown xpc operation");
     }
 }
 
 bool SecXPCDictionarySetPList(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error)
+{
+    return SecXPCDictionarySetPListWithRepair(message, key, object, false, error);
+}
+
+bool SecXPCDictionarySetPListWithRepair(xpc_object_t message, const char *key, CFTypeRef object, bool repair, CFErrorRef *error)
 {
     if (!object)
         return SecError(errSecParam, error, CFSTR("object for key %s is NULL"), key);
 
     size_t size = der_sizeof_plist(object, error);
-    if (!size)
+    if (!size) {
         return false;
+    }
     uint8_t *der = malloc(size);
     uint8_t *der_end = der + size;
-    uint8_t *der_start = der_encode_plist(object, error, der, der_end);
+    uint8_t *der_start = der_encode_plist_repair(object, error, repair, der, der_end);
     if (!der_start) {
         free(der);
         return false;
@@ -492,10 +494,16 @@ CFTypeRef SecXPCDictionaryCopyPList(xpc_object_t message, const char *key, CFErr
 
     const uint8_t *der_end = der + size;
     /* use the sensitive allocator so that the dictionary is zeroized upon deallocation */
-    const uint8_t *decode_end = der_decode_plist(SecCFAllocatorZeroize(), kCFPropertyListImmutable,
+    const uint8_t *decode_end = der_decode_plist(SecCFAllocatorZeroize(),
                                           &cfobject, error, der, der_end);
     if (decode_end != der_end) {
-        SecError(errSecParam, error, CFSTR("trailing garbage after der decoded object for key %s"), key);
+        CFStringRef description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("trailing garbage after der decoded object for key %s"), key);
+        SecError(errSecParam, error, CFSTR("%@"), description);
+        if (error) {    // The no-error case is handled in SecError directly
+            secerror("xpc: %@", *error);
+        }
+        __security_simulatecrash(description, __sec_exception_code_CorruptItem);
+        CFReleaseNull(description);
         CFReleaseNull(cfobject);
     }
 
index da93c9fa4e37392135b53f5711ff149f3a8d1970..92d6df73cc7156cb897b809cedaba19f08dc6c72 100644 (file)
@@ -35,6 +35,7 @@ bool SecXPCDictionarySetDataOptional(xpc_object_t message, const char *key, CFDa
 bool SecXPCDictionarySetBool(xpc_object_t message, const char *key, bool value, CFErrorRef *error);
 
 bool SecXPCDictionarySetPList(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error);
+bool SecXPCDictionarySetPListWithRepair(xpc_object_t message, const char *key, CFTypeRef object, bool repair, CFErrorRef *error);
 bool SecXPCDictionarySetPListOptional(xpc_object_t message, const char *key, CFTypeRef object, CFErrorRef *error);
 
 bool SecXPCDictionarySetString(xpc_object_t message, const char *key, CFStringRef string, CFErrorRef *error);
index 92e3c930921c8763ee12c0948edfd72980d9c7ae..e068beebef4e1bc658231061f9c8b695b057a16d 100644 (file)
@@ -76,6 +76,9 @@ bool securityd_message_no_error(xpc_object_t message, CFErrorRef *error);
 
 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups);
 CFArrayRef SecAccessGroupsGetCurrent(void);
+void SecSecurityClientRegularToAppClip(void);
+void SecSecurityClientAppClipToRegular(void);
+void SecSecurityClientSetApplicationIdentifier(CFStringRef identifier);
 
 #include <os/log_private.h>
 extern os_log_t secLogObjForScope(const char *scope);
index 17abc062f9617ae54c7cf377eb1a1efe4f4d07d9..3f33e88843b91ee74c3d0ee49cc1dce2236a06ea 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "p12pbegen.h"
 
+#include <security_utilities/simulatecrash_assert.h>
+
 static uint8_t *concatenate_to_blocksize(const uint8_t *data, size_t data_length, 
     size_t blocksize, size_t *blocklength)
 {
index 6c873d227754952dbc440052d877ef3b27536437..bdf13306c97ad2014d9f8672c2b7577d18439215 100644 (file)
@@ -47,7 +47,7 @@
 #include <MobileCoreServices/LSApplicationProxy.h>
 #endif
 
-#if TARGET_OS_IPHONE && !TARGET_OS_WATCH
+#if TARGET_OS_IPHONE && !TARGET_OS_WATCH && !TARGET_OS_TV
 #include <dlfcn.h>
 #include <WebUI/WBUAutoFillData.h>
 
@@ -85,7 +85,7 @@ typedef WBSAutoFillDataClasses (*WBUAutoFillGetEnabledDataClasses_f)(void);
 #import <LocalAuthentication/LocalAuthentication.h>
 #import <LocalAuthentication/LAContext+Private.h>
 #import <MobileGestalt.h>
-#import <ManagedConfiguration/MCProfileConnection.h>
+#import <ManagedConfiguration/ManagedConfiguration.h>
 #endif
 
 static NSString *swca_string_table = @"SharedWebCredentials";
index 5dd78112c412c4b503fb2a070d81dec0ba847f31..274a87672b98812f7e4db6d690fed61bfc638441 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2009,2012-2015 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009,2012-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -40,6 +40,7 @@
 #include <vproc_priv.h>
 #include <xpc/xpc.h>
 #include <xpc/private.h>
+#include <os/feature_private.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <Security/SecItem.h>
@@ -69,27 +70,33 @@ struct trustd *gTrustd;
 
 /* Hardcoded Access Groups for the server itself */
 static CFArrayRef SecServerCopyAccessGroups(void) {
-    return CFArrayCreateForCFTypes(kCFAllocatorDefault,
+    CFArrayRef accessGroups = CFArrayCreateForCFTypes(kCFAllocatorDefault,
 #if NO_SERVER
-                                   CFSTR("test"),
-                                   CFSTR("apple"),
-                                   CFSTR("lockdown-identities"),
-                                   CFSTR("123456.test.group"),
-                                   CFSTR("123456.test.group2"),
-                                   CFSTR("com.apple.cfnetwork"),
-                                   CFSTR("com.apple.bluetooth"),
+                                                      CFSTR("test"),
+                                                      CFSTR("apple"),
+                                                      CFSTR("lockdown-identities"),
+                                                      CFSTR("123456.test.group"),
+                                                      CFSTR("123456.test.group2"),
+                                                      CFSTR("com.apple.cfnetwork"),
+                                                      CFSTR("com.apple.bluetooth"),
 #endif
-                                   CFSTR("sync"),
-                                   CFSTR("com.apple.security.sos"),
-                                   CFSTR("com.apple.security.ckks"),
-                                   CFSTR("com.apple.security.octagon"),
-                                   CFSTR("com.apple.security.egoIdentities"),
-                                   CFSTR("com.apple.security.sos-usercredential"),
-                                   CFSTR("com.apple.sbd"),
-                                   CFSTR("com.apple.lakitu"),
-                                   CFSTR("com.apple.security.securityd"),
-                                   kSecAttrAccessGroupToken,
-                                   NULL);
+                                                      CFSTR("sync"),
+                                                      CFSTR("com.apple.security.sos"),
+                                                      CFSTR("com.apple.security.ckks"),
+                                                      CFSTR("com.apple.security.octagon"),
+                                                      CFSTR("com.apple.security.egoIdentities"),
+                                                      CFSTR("com.apple.security.sos-usercredential"),
+                                                      CFSTR("com.apple.sbd"),
+                                                      CFSTR("com.apple.lakitu"),
+                                                      CFSTR("com.apple.security.securityd"),
+                                                      NULL);
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        CFMutableArrayRef mutableGroups = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, accessGroups);
+        CFArrayAppendValue(mutableGroups, kSecAttrAccessGroupToken);
+        CFAssignRetained(accessGroups, mutableGroups);
+    }
+
+    return accessGroups;
 }
 
 static SecurityClient gClient;
@@ -137,6 +144,8 @@ SecSecurityClientGet(void)
         gClient.activeUser = 501;
         gClient.musr = NULL;
 #endif
+        gClient.applicationIdentifier = NULL;
+        gClient.isAppClip = false;
     });
     return &gClient;
 }
@@ -150,8 +159,30 @@ CFArrayRef SecAccessGroupsGetCurrent(void) {
 // Only for testing.
 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups) {
     // Not thread safe at all, but OK because it is meant to be used only by tests.
-    CFReleaseNull(gClient.accessGroups);
-    gClient.accessGroups = CFRetainSafe(accessGroups);
+    SecurityClient* client = SecSecurityClientGet();
+    CFReleaseNull(client->accessGroups);
+    client->accessGroups = CFRetainSafe(accessGroups);
+}
+
+// Testing
+void SecSecurityClientRegularToAppClip(void) {
+    SecurityClient* client = SecSecurityClientGet();
+    client->isAppClip = true;
+}
+
+// Testing
+void SecSecurityClientAppClipToRegular(void) {
+    SecurityClient* client = SecSecurityClientGet();
+    client->isAppClip = false;
+}
+
+// Testing
+void SecSecurityClientSetApplicationIdentifier(CFStringRef identifier) {
+    SecurityClient* client = SecSecurityClientGet();
+    CFReleaseNull(client->applicationIdentifier);
+    if (identifier) {
+        client->applicationIdentifier = CFRetain(identifier);
+    }
 }
 
 #if !TARGET_OS_IPHONE
@@ -227,6 +258,9 @@ static bool is_trust_operation(enum SecXPCOperation op) {
         case kSecXPCOpCopyCTExceptions:
         case sec_trust_get_exception_reset_count_id:
         case sec_trust_increment_exception_reset_count_id:
+        case kSecXPCOpSetCARevocationAdditions:
+        case kSecXPCOpCopyCARevocationAdditions:
+        case kSecXPCOpValidUpdate:
             return true;
         default:
             break;
index b9957cc7ec7b880e9d9e50dca4e8ce877ffdd4a7..e9d8975c60e98675f8f0c5c2592edf10ca601dbd 100644 (file)
@@ -26,6 +26,7 @@
 #import <Foundation/NSXPCConnection_Private.h>
 #import <objc/runtime.h>
 #import <utilities/debugging.h>
+#import <Security/SecXPCHelper.h>
 
 #include <ipc/securityd_client.h>
 
                     ofReply:0];
 
 #if OCTAGON
-    static NSMutableSet *errClasses;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        // By finding classes by strings at runtime, we'll only get the CloudKit helpers if you link CloudKit
-        // Plus, we don't have to weak-link cloudkit from Security.framework
-
-        errClasses = [[NSMutableSet alloc] init];
-        char *classes[] = {
-            "NSError",
-            "NSArray",
-            "NSString",
-            "NSNumber",
-            "NSData",
-            "NSDate",
-            "CKReference",
-            "CKAsset",
-            "CLLocation",
-            "CKPackage",
-            "CKArchivedAnchoredPackage",
-            "CKPrettyError",
-            "CKRecordID",
-            "NSURL",
-        };
-
-        for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
-            Class cls = objc_getClass(classes[n]);
-            if (cls) {
-                [errClasses addObject:cls];
-            }
-        }
-    });
+    NSSet<Class> *errClasses = [SecXPCHelper safeErrorClasses];
 
     @try {
         [rpcCallbackInterface setClasses:errClasses forSelector:@selector(callCallback:error:) argumentIndex:1 ofReply:NO];
         [interface setClasses:errClasses forSelector:@selector(SecItemAddAndNotifyOnSync:
                                                                syncCallback:
                                                                complete:) argumentIndex:2 ofReply:YES];
-        [interface setClasses:errClasses forSelector:@selector(secItemFetchCurrentItemAcrossAllDevices:
-                                                               identifier:
-                                                               viewHint:
-                                                               fetchCloudValue:
-                                                               complete:) argumentIndex:1 ofReply:YES];
-        [interface setClasses:errClasses forSelector:@selector(secItemDigest:
-                                                               accessGroup:
-                                                               complete:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(secItemSetCurrentItemAcrossAllDevices:
                                                                newCurrentItemHash:
                                                                accessGroup:
                                                                oldCurrentItemReference:
                                                                oldCurrentItemHash:
                                                                complete:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(secItemFetchCurrentItemAcrossAllDevices:
+                                                               identifier:
+                                                               viewHint:
+                                                               fetchCloudValue:
+                                                               complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(secItemDigest:
+                                                               accessGroup:
+                                                               complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(secKeychainDeleteMultiuser:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(secItemVerifyBackupIntegrity:completion:) argumentIndex:1 ofReply:YES];
+
     }
     @catch(NSException* e) {
         secerror("Could not configure SecuritydXPCProtocol: %@", e);
-#if DEBUG
         @throw e;
-#endif // DEBUG
     }
 #endif // OCTAGON
 }
 }
 @end
 
-id<SecuritydXPCProtocol> SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError *))
+id<SecuritydXPCProtocol> SecuritydXPCProxyObject(bool synchronous, void (^rpcErrorHandler)(NSError *))
 {
     if (gSecurityd && gSecurityd->secd_xpc_server) {
         return (__bridge id<SecuritydXPCProtocol>)gSecurityd->secd_xpc_server;
@@ -156,7 +128,11 @@ id<SecuritydXPCProtocol> SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError
         rpcErrorHandler([NSError errorWithDomain:@"securityd" code:-1 userInfo:@{ NSLocalizedDescriptionKey : @"Could not create SecuritydXPCClient" }]);
         return NULL;
     } else {
-        return [rpc.connection remoteObjectProxyWithErrorHandler: rpcErrorHandler];
+        if (synchronous) {
+            return [rpc.connection synchronousRemoteObjectProxyWithErrorHandler:rpcErrorHandler];
+        } else {
+            return [rpc.connection remoteObjectProxyWithErrorHandler:rpcErrorHandler];
+        }
     }
 }
 
index 59392e17692ddb39a694932f86821b3066eb76b0..f9484f12893a46fe1b149231a80b98017016d1da 100644 (file)
                                <key>Interval</key>
                                <real>86400</real>
                        </dict>
+                       <key>com.apple.securityd.prng</key>
+                       <dict>
+                               <key>Priority</key>
+                               <string>Maintenance</string>
+                               <key>Interval</key>
+                               <real>3600</real>
+                <key>RequiresClassC</key>
+                <false/>
+                       </dict>
                </dict>
        </dict>
 </dict>
index e75b5e1b301c68670f95a3521785899b20bc8078..6be938f59e4d3e8a07d57e9ae207c530d17e0e35 100644 (file)
                                <key>NetworkTransferDirection</key>
                                <string>Bidirectional</string>
                        </dict>
+                       <key>com.apple.securityd.prng</key>
+                       <dict>
+                               <key>Priority</key>
+                               <string>Maintenance</string>
+                               <key>Interval</key>
+                               <real>3600</real>
+                <key>RequiresClassC</key>
+                <false/>
+                       </dict>
                </dict>
                <key>com.apple.notifyd.matching</key>
                <dict>
index ed945f01c12e189e372072f26c6bb864a7dfbcdd..289b0ff14e11cc17eec496f62a9b5b087c00391f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2018 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2007-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -182,6 +182,7 @@ enum SecXPCOperation {
     sec_keychain_backup_syncable_id,
     sec_keychain_restore_syncable_id,
     sec_item_backup_copy_names_id,
+    sec_item_backup_ensure_copy_view_id,
     sec_item_backup_handoff_fd_id,
     sec_item_backup_set_confirmed_manifest_id,
     sec_item_backup_restore_id,
@@ -216,24 +217,18 @@ enum SecXPCOperation {
     kSecXPCOpTryUserCredentials,
     kSecXPCOpSetUserCredentials,
     kSecXPCOpSetUserCredentialsAndDSID,
-    kSecXPCOpSetUserCredentialsAndDSIDWithAnalytics,
     kSecXPCOpCanAuthenticate,
     kSecXPCOpPurgeUserCredentials,
     kSecXPCOpDeviceInCircle,
     kSecXPCOpRequestToJoin,
-    kSecXPCOpRequestToJoinWithAnalytics,
     kSecXPCOpRequestToJoinAfterRestore,
-    kSecXPCOpRequestToJoinAfterRestoreWithAnalytics,
     kSecXPCOpResetToOffering,
     kSecXPCOpResetToEmpty,
-    kSecXPCOpResetToEmptyWithAnalytics,
     kSecXPCOpView,
     kSecXPCOpViewSet,
-    kSecXPCOpViewSetWithAnalytics,
     kSecXPCOpRemoveThisDeviceFromCircle,
-    kSecXPCOpRemoveThisDeviceFromCircleWithAnalytics,
     kSecXPCOpRemovePeersFromCircle,
-    kSecXPCOpRemovePeersFromCircleWithAnalytics,
+    kSecXPCOpLoggedIntoAccount,
     kSecXPCOpLoggedOutOfAccount,
     kSecXPCOpBailFromCircle,
     kSecXPCOpAcceptApplicants,
@@ -255,7 +250,6 @@ enum SecXPCOperation {
     kSecXPCOpSetNewPublicBackupKey,
     kSecXPCOpSetBagForAllSlices,
     kSecXPCOpWaitForInitialSync,
-    kSecXPCOpWaitForInitialSyncWithAnalytics,
     kSecXPCOpCheckPeerAvailability,
     kSecXPCOpCopyApplication,
     kSecXPCOpCopyCircleJoiningBlob,
@@ -270,7 +264,7 @@ enum SecXPCOperation {
     kSecXPCOpWhoAmI,
     kSecXPCOpTransmogrifyToSyncBubble,
     kSecXPCOpTransmogrifyToSystemKeychain,
-    sec_item_update_token_items_id,
+    sec_item_update_token_items_for_access_groups_id,
     kSecXPCOpDeleteUserView,
     sec_trust_store_copy_all_id,
     sec_trust_store_copy_usage_constraints_id,
@@ -294,6 +288,9 @@ enum SecXPCOperation {
     kSecXPCOpOTASecExperimentGetNewAsset,
     sec_trust_get_exception_reset_count_id,
     sec_trust_increment_exception_reset_count_id,
+    kSecXPCOpSetCARevocationAdditions,
+    kSecXPCOpCopyCARevocationAdditions,
+    kSecXPCOpValidUpdate,
 };
 
 
@@ -313,6 +310,8 @@ typedef struct SecurityClient {
     bool inMultiUser;
     int activeUser;
 #endif
+    bool isAppClip;
+    CFStringRef applicationIdentifier;
 } SecurityClient;
 
 
@@ -334,7 +333,7 @@ struct securityd {
     CFDataRef (*sec_keychain_backup)(SecurityClient *client, CFDataRef keybag, CFDataRef passcode, bool emcs, CFErrorRef* error);
     bool (*sec_keychain_restore)(CFDataRef backup, SecurityClient *client, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error);
     bool (*sec_roll_keys)(bool force, CFErrorRef* error);
-    bool (*sec_item_update_token_items)(CFStringRef tokenID, CFArrayRef query, SecurityClient *client, CFErrorRef* error);
+    bool (*sec_item_update_token_items_for_access_groups)(CFStringRef tokenID, CFArrayRef accessGroups, CFArrayRef tokenItems, SecurityClient *client, CFErrorRef* error);
     bool (*sec_delete_items_with_access_groups)(CFArrayRef bundleIDs, SecurityClient *client, CFErrorRef *error);
     /* SHAREDWEBCREDENTIALS */
     bool (*sec_add_shared_web_credential)(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef accessGroups, CFTypeRef *result, CFErrorRef *error);
@@ -343,6 +342,7 @@ struct securityd {
     CFDictionaryRef (*sec_keychain_backup_syncable)(CFDictionaryRef backup_in, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error);
     bool (*sec_keychain_restore_syncable)(CFDictionaryRef backup, CFDataRef keybag, CFDataRef passcode, CFErrorRef* error);
     CFArrayRef (*sec_item_backup_copy_names)(CFErrorRef *error);
+    CFStringRef (*sec_item_backup_ensure_copy_view)(CFStringRef viewName, CFErrorRef *error);
     int (*sec_item_backup_handoff_fd)(CFStringRef backupName, CFErrorRef *error);
     bool (*sec_item_backup_set_confirmed_manifest)(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifest, CFErrorRef *error);
     bool (*sec_item_backup_restore)(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error);
@@ -351,28 +351,22 @@ struct securityd {
     bool (*soscc_TryUserCredentials)(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error);
     bool (*soscc_SetUserCredentials)(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error);
     bool (*soscc_SetUserCredentialsAndDSID)(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error);
-    bool (*soscc_SetUserCredentialsAndDSIDWithAnalytics)(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error);
     bool (*soscc_CanAuthenticate)(CFErrorRef *error);
     bool (*soscc_PurgeUserCredentials)(CFErrorRef *error);
     SOSCCStatus (*soscc_ThisDeviceIsInCircle)(CFErrorRef* error);
     bool (*soscc_RequestToJoinCircle)(CFErrorRef* error);
-    bool (*soscc_RequestToJoinCircleWithAnalytics)(CFDataRef parentEvent, CFErrorRef* error);
     bool (*soscc_RequestToJoinCircleAfterRestore)(CFErrorRef* error);
-    bool (*soscc_RequestToJoinCircleAfterRestoreWithAnalytics)(CFDataRef parentEvent, CFErrorRef* error);
     bool (*soscc_SetToNew)(CFErrorRef *error);
     bool (*soscc_ResetToOffering)(CFErrorRef* error);
     bool (*soscc_ResetToEmpty)(CFErrorRef* error);
-    bool (*soscc_ResetToEmptyWithAnalytics)(CFDataRef parentEvent, CFErrorRef* error);
     SOSViewResultCode (*soscc_View)(CFStringRef view, SOSViewActionCode action, CFErrorRef *error);
     bool (*soscc_ViewSet)(CFSetRef enabledViews, CFSetRef disabledViews);
-    bool (*soscc_ViewSetWithAnalytics)(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent);
     bool (*soscc_RegisterSingleRecoverySecret)(CFDataRef backupSlice, bool forV0Only, CFErrorRef *error);
     bool (*soscc_RegisterRecoveryPublicKey)(CFDataRef recovery_key, CFErrorRef *error);
     CFDataRef (*soscc_CopyRecoveryPublicKey)(CFErrorRef *error);
     bool (*soscc_RemoveThisDeviceFromCircle)(CFErrorRef* error);
-    bool (*soscc_RemoveThisDeviceFromCircleWithAnalytics)(CFDataRef parentEvent, CFErrorRef* error);
     bool (*soscc_RemovePeersFromCircle)(CFArrayRef peers, CFErrorRef* error);
-    bool (*soscc_RemovePeersFromCircleWithAnalytics)(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error);
+    bool (*soscc_LoggedIntoAccount)(CFErrorRef* error);
     bool (*soscc_LoggedOutOfAccount)(CFErrorRef* error);
     bool (*soscc_BailFromCircle)(uint64_t limit_in_seconds, CFErrorRef* error);
     bool (*soscc_AcceptApplicants)(CFArrayRef applicants, CFErrorRef* error);
@@ -400,7 +394,6 @@ struct securityd {
     bool   (*sec_set_circle_log_settings)(CFTypeRef type, CFErrorRef* error);
     SOSPeerInfoRef (*soscc_CopyMyPeerInfo)(CFErrorRef*);
     bool (*soscc_WaitForInitialSync)(CFErrorRef*);
-    bool (*soscc_WaitForInitialSyncWithAnalytics)(CFDataRef parentEvent, CFErrorRef *error);
     bool (*soscc_PeerAvailability)(CFErrorRef *error);
     SOSPeerInfoRef (*soscc_CopyApplicant)(CFErrorRef *error);
     CFDataRef (*soscc_CopyCircleJoiningBlob)(SOSPeerInfoRef applicant, CFErrorRef *error);
@@ -445,6 +438,9 @@ struct trustd {
     bool (*sec_trust_increment_exception_reset_count)(CFErrorRef *error);
     uint64_t (*sec_trust_get_exception_reset_count)(CFErrorRef *error);
 #endif
+    bool (*sec_trust_store_set_ca_revocation_additions)(CFStringRef appID, CFDictionaryRef additions, CFErrorRef *error);
+    CFDictionaryRef (*sec_trust_store_copy_ca_revocation_additions)(CFStringRef appID, CFErrorRef *error);
+    bool (*sec_valid_update)(CFErrorRef *error);
 };
 
 extern struct trustd *gTrustd;
@@ -534,11 +530,14 @@ typedef void (^SecBoolNSErrorCallback) (bool, NSError*);
 - (void)secItemVerifyBackupIntegrity:(BOOL)lightweight
                           completion:(void (^)(NSDictionary<NSString*, NSString*>* resultsPerKeyclass, NSError* error))completion;
 
+// Delete all items from the keychain where agrp==identifier and clip==1. Requires App Clip deletion entitlement.
+- (void)secItemDeleteForAppClipApplicationIdentifier:(NSString*)identifier
+                                          completion:(void (^)(OSStatus status))completion;
 @end
 
 // Call this to receive a proxy object conforming to SecuritydXPCProtocol that you can call methods on.
 // It's probably a remote object for securityd/secd, but it might be in-process if you've configured it that way.
-id<SecuritydXPCProtocol> SecuritydXPCProxyObject(void (^rpcErrorHandler)(NSError *));
+id<SecuritydXPCProtocol> SecuritydXPCProxyObject(bool synchronous, void (^rpcErrorHandler)(NSError *));
 
 // Set up a local securityxpcserver: after this call, all securitydxpc calls will be handled in-process instead of actually transferring to securityd
 id<SecuritydXPCProtocol> SecCreateLocalSecuritydXPCServer(void) NS_RETURNS_RETAINED;
index 1a8eb59e0098a2d27d3bc3e3a454d25f0ae159b0..86935cfec588fd319a10d32e02dd2229fe49dd87 100644 (file)
@@ -30,6 +30,7 @@
 #include <os/transaction_private.h>
 #include <os/variant_private.h>
 
+#include <corecrypto/ccec.h>
 #include "keychain/SecureObjectSync/SOSPeerInfoDER.h"
 #include <Security/SecureObjectSync/SOSCloudCircle.h>
 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
@@ -58,6 +59,7 @@
 #include "trust/trustd/SecTrustStoreServer.h"
 #include "keychain/securityd/iCloudTrace.h"
 #include "keychain/securityd/spi.h"
+#include <utilities/SecAKSWrappers.h>
 #include <utilities/SecCFError.h>
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecDb.h>
 
 #include "util.h"
 
+static void refresh_prng(void)
+{
+    aks_ref_key_t ref = NULL;
+
+    int fd = open("/dev/random", O_WRONLY);
+    if (fd == -1) {
+        secerror("failed to open /dev/random (%d)", errno);
+        goto out;
+    }
+
+    /* create class F ref-key, and use its public key as an entropy source */
+    int err = aks_ref_key_create(bad_keybag_handle, key_class_f, key_type_asym_ec_p256, NULL, 0, &ref);
+    if (err != kAKSReturnSuccess) {
+        secerror("failed to create refkey (%d)", err);
+        goto out;
+    }
+
+    size_t pub_key_len = 0;
+    const uint8_t *pub_key = aks_ref_key_get_public_key(ref, &pub_key_len);
+    if (pub_key_len > ccec_export_pub_size_cp(ccec_cp_256())) {
+        secerror("invalid pub key (%zu)", pub_key_len);
+        goto out;
+    }
+
+    while (pub_key_len > 0) {
+        ssize_t n = write(fd, pub_key, pub_key_len);
+        if (n == -1) {
+            secerror("failed to write /dev/random (%d)", errno);
+            goto out;
+        }
+
+        pub_key += n;
+        pub_key_len -= n;
+    }
+
+ out:
+    if (ref) {
+        aks_ref_key_free(&ref);
+    }
+
+    if (fd >= 0) {
+        close(fd);
+    }
+}
+
 #if SECUREOBJECTSYNC
 
 CF_RETURNS_RETAINED
@@ -191,7 +238,7 @@ static CFDataRef SecXPCDictionaryCopyCFDataRef(xpc_object_t message, const char
     CFDataRef retval = NULL;
     const uint8_t *bytes = NULL;
     size_t len = 0;
-    
+
     bytes = xpc_dictionary_get_data(message, key, &len);
     require_action_quiet(bytes, errOut, SOSCreateError(kSOSErrorBadKey, CFSTR("missing CFDataRef info"), NULL, error));
     retval = CFDataCreate(NULL, bytes, len);
@@ -208,7 +255,7 @@ static CFSetRef CreateCFSetRefFromXPCObject(xpc_object_t xpcSetDER, CFErrorRef*
 
     const uint8_t* der = xpc_data_get_bytes_ptr(xpcSetDER);
     const uint8_t* der_end = der + xpc_data_get_length(xpcSetDER);
-    der = der_decode_set(kCFAllocatorDefault, kCFPropertyListMutableContainersAndLeaves, &retval, error, der, der_end);
+    der = der_decode_set(kCFAllocatorDefault, &retval, error, der, der_end);
     if (der != der_end) {
         SecError(errSecDecode, error, CFSTR("trailing garbage at end of SecAccessControl data"));
         goto errOut;
@@ -341,6 +388,8 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
         .allowSyncBubbleKeychain = false,
         .isNetworkExtension = false,
         .canAccessNetworkExtensionAccessGroups = false,
+        .applicationIdentifier = NULL,
+        .isAppClip = false,
     };
 
     secdebug("serverxpc", "entering");
@@ -383,6 +432,16 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                            CFDictionaryGetValue(query, kSecAttrPCSPlaintextPublicIdentity)) {
                             entitlementsCorrect = EntitlementPresentAndTrue(sec_item_add_id, client.task, kSecEntitlementPrivateCKKSPlaintextFields, &error);
                         }
+                        if(entitlementsCorrect &&
+                           (CFDictionaryGetValue(query, kSecDataInetExtraNotes) ||
+                            CFDictionaryGetValue(query, kSecDataInetExtraHistory) ||
+                            CFDictionaryGetValue(query, kSecDataInetExtraClientDefined0) ||
+                            CFDictionaryGetValue(query, kSecDataInetExtraClientDefined1) ||
+                            CFDictionaryGetValue(query, kSecDataInetExtraClientDefined2) ||
+                            CFDictionaryGetValue(query, kSecDataInetExtraClientDefined3))) {
+                            entitlementsCorrect = EntitlementPresentAndTrue(sec_item_add_id, client.task, kSecEntitlementPrivateInetExpansionFields, &error);
+                        }
+
                         if (entitlementsCorrect && CFDictionaryGetValue(query, kSecAttrSysBound)) {
                             entitlementsCorrect = EntitlementPresentAndTrue(sec_item_add_id, client.task, kSecEntitlementPrivateSysBound, &error);
                         }
@@ -406,7 +465,7 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                     if (query) {
                         CFTypeRef result = NULL;
                         if (_SecItemCopyMatching(query, &client, &result, &error) && result) {
-                            SecXPCDictionarySetPList(replyMessage, kSecXPCKeyResult, result, &error);
+                            SecXPCDictionarySetPListWithRepair(replyMessage, kSecXPCKeyResult, result, true, &error);
                             CFReleaseNull(result);
                         }
                         CFReleaseNull(query);
@@ -429,6 +488,15 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                CFDictionaryGetValue(attributesToUpdate, kSecAttrPCSPlaintextPublicIdentity)) {
                                 entitlementsCorrect = EntitlementPresentAndTrue(sec_item_update_id, client.task, kSecEntitlementPrivateCKKSPlaintextFields, &error);
                             }
+                            if(entitlementsCorrect &&
+                               (CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraNotes) ||
+                                CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraHistory) ||
+                                CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraClientDefined0) ||
+                                CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraClientDefined1) ||
+                                CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraClientDefined2) ||
+                                CFDictionaryGetValue(attributesToUpdate, kSecDataInetExtraClientDefined3))) {
+                                entitlementsCorrect = EntitlementPresentAndTrue(sec_item_update_id, client.task, kSecEntitlementPrivateInetExpansionFields, &error);
+                            }
                             if (entitlementsCorrect && CFDictionaryGetValue(query, kSecAttrSysBound)) {
                                 entitlementsCorrect = EntitlementPresentAndTrue(sec_item_update_id, client.task, kSecEntitlementPrivateSysBound, &error);
                             }
@@ -456,17 +524,20 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                 }
                 break;
             }
-            case sec_item_update_token_items_id:
+            case sec_item_update_token_items_for_access_groups_id:
             {
-                if (EntitlementAbsentOrFalse(sec_item_add_id, client.task, kSecEntitlementKeychainDeny, &error)) {
+                if (EntitlementAbsentOrFalse(sec_item_update_token_items_for_access_groups_id, client.task, kSecEntitlementKeychainDeny, &error) &&
+                    EntitlementPresentAndTrue(sec_item_update_token_items_for_access_groups_id, client.task, kSecEntitlementUpdateTokenItems, &error)) {
                     CFStringRef tokenID =  SecXPCDictionaryCopyString(event, kSecXPCKeyString, &error);
-                    CFArrayRef attributes = SecXPCDictionaryCopyArray(event, kSecXPCKeyQuery, &error);
+                    CFArrayRef accessGroups = SecXPCDictionaryCopyArray(event, kSecXPCKeyArray, &error);
+                    CFArrayRef tokenItems = SecXPCDictionaryCopyArray(event, kSecXPCKeyQuery, &error);
                     if (tokenID) {
-                        bool result = _SecItemUpdateTokenItems(tokenID, attributes, &client, &error);
+                        bool result = _SecItemUpdateTokenItemsForAccessGroups(tokenID, accessGroups, tokenItems, &client, &error);
                         xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, result);
                     }
                     CFReleaseNull(tokenID);
-                    CFReleaseNull(attributes);
+                    CFReleaseNull(accessGroups);
+                    CFReleaseNull(tokenItems);
                 }
                 break;
             }
@@ -642,6 +713,18 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                 }
                 break;
             }
+            case sec_item_backup_ensure_copy_view_id:
+            {
+                if(EntitlementPresentAndTrue(operation, client.task, kSecEntitlementRestoreKeychain, &error)) {
+                    CFStringRef viewName = NULL;
+                    if (SecXPCDictionaryCopyStringOptional(event, kSecXPCKeyString, &viewName, &error)) {
+                        CFStringRef name = SecServerItemBackupEnsureCopyView(viewName, &error);
+                        SecXPCDictionarySetString(replyMessage, kSecXPCKeyResult, name, &error);
+                        CFReleaseNull(name);
+                    }
+                }
+                break;
+            }
             case sec_item_backup_handoff_fd_id:
             {
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementRestoreKeychain, &error)) {
@@ -833,19 +916,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                     });
                 }
                 break;
-            case kSecXPCOpSetUserCredentialsAndDSIDWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    with_label_and_password_and_dsid(event, ^(CFStringRef label, CFDataRef password, CFStringRef dsid) {
-                        CFDataRef parentEvent = NULL;
-                        if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){
-                            xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(label, password, dsid, parentEvent, &error));
-                        }else{
-                            xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCSetUserCredentialsAndDSID_Server(label, password, dsid, &error));
-                        }
-                        CFReleaseNull(parentEvent);
-                        });
-                    }
-                break;
             case kSecXPCOpView:
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                     with_view_and_action(event, ^(CFStringRef view, uint64_t actionCode) {
@@ -854,18 +924,13 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                     });
                 }
                 break;
-            case kSecXPCOpViewSet: // FALLTHROUGH
-            case kSecXPCOpViewSetWithAnalytics:
+            case kSecXPCOpViewSet:
                     if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                         CFSetRef enabledViews = SecXPCSetCreateFromXPCDictionaryElement(event, kSecXPCKeyEnabledViewsKey);
                         CFSetRef disabledViews = SecXPCSetCreateFromXPCDictionaryElement(event, kSecXPCKeyDisabledViewsKey);
-                        CFDataRef parentEvent = NULL;
-                        if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error)){
-                            xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, parentEvent));
-                        }
+                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCViewSet_Server(enabledViews, disabledViews));
                         CFReleaseNull(enabledViews);
                         CFReleaseNull(disabledViews);
-                        CFReleaseNull(parentEvent);
                     }
                 break;
             case kSecXPCOpCanAuthenticate:
@@ -892,14 +957,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                             SOSCCRequestToJoinCircle_Server(&error));
                 }
                 break;
-            case kSecXPCOpRequestToJoinWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFDataRef parentEvent = NULL;
-                    SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error);
-                    xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircleWithAnalytics_Server(parentEvent, &error));
-                    CFReleaseNull(parentEvent);
-                }
-                break;
             case kSecXPCOpAccountHasPublicKey:
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                     xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
@@ -913,17 +970,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                             SOSCCRequestToJoinCircleAfterRestore_Server(&error));
                 }
                 break;
-            case kSecXPCOpRequestToJoinAfterRestoreWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFDataRef parentEvent = NULL;
-                    if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error)  && parentEvent != NULL){
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(parentEvent, &error));
-                    }else{
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRequestToJoinCircleAfterRestore_Server(&error));
-                    }
-                    CFReleaseNull(parentEvent);
-                }
-                break;
             case kSecXPCOpRequestDeviceID:
             case kSecXPCOpSetDeviceID:
             case kSecXPCOpHandleIDSMessage:
@@ -952,33 +998,12 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                             SOSCCResetToEmpty_Server(&error));
                 }
                 break;
-            case kSecXPCOpResetToEmptyWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFDataRef parentEvent = NULL;
-                    if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCResetToEmptyWithAnalytics_Server(parentEvent, &error));
-                    }else{
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCResetToEmpty_Server(&error));
-                    }
-                }
-                break;
             case kSecXPCOpRemoveThisDeviceFromCircle:
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                     xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
                                             SOSCCRemoveThisDeviceFromCircle_Server(&error));
                 }
                 break;
-            case kSecXPCOpRemoveThisDeviceFromCircleWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFDataRef parentEvent = NULL;
-                    if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(parentEvent, &error));
-                    }else{
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRemoveThisDeviceFromCircle_Server(&error));
-                    }
-                    CFReleaseNull(parentEvent);
-                }
-                break;
             case kSecXPCOpRemovePeersFromCircle:
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                     CFArrayRef applicants = SecXPCDictionaryCopyPeerInfoArray(event, kSecXPCKeyPeerInfoArray, &error);
@@ -987,19 +1012,13 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                     CFReleaseNull(applicants);
                 }
                 break;
-            case kSecXPCOpRemovePeersFromCircleWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFArrayRef applicants = SecXPCDictionaryCopyPeerInfoArray(event, kSecXPCKeyPeerInfoArray, &error);
-                    CFDataRef parentEvent = NULL;
-                    if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRemovePeersFromCircleWithAnalytics_Server(applicants, parentEvent, &error));
-                    }else{
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCRemovePeersFromCircle_Server(applicants, &error));
+                case kSecXPCOpLoggedIntoAccount:
+                    if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
+                        SOSCCNotifyLoggedIntoAccount_Server();
+                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
+                                                true);
                     }
-                    CFReleaseNull(parentEvent);
-                    CFReleaseNull(applicants);
-                }
-                break;
+                    break;
             case kSecXPCOpLoggedOutOfAccount:
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                     xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult,
@@ -1131,7 +1150,7 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                                                  SOSCCCopyViewUnawarePeerInfo_Server(&error),
                                                                  &error);
                 }
-                    break;
+                break;
             case kSecXPCOpCopyEngineState:
                 {
                 if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
@@ -1149,7 +1168,7 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                     }
                 }
                 break;
-                case kSecXPCOpCopyPeerPeerInfo:
+            case kSecXPCOpCopyPeerPeerInfo:
                     if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                         xpc_dictionary_set_and_consume_PeerInfoArray(replyMessage, kSecXPCKeyResult,
                                                                      SOSCCCopyPeerPeerInfo_Server(&error),
@@ -1231,18 +1250,6 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                                             SOSCCWaitForInitialSync_Server(&error));
                 }
                 break;
-
-            case kSecXPCOpWaitForInitialSyncWithAnalytics:
-                if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
-                    CFDataRef parentEvent = NULL;
-                    if(SecXPCDictionaryCopyDataOptional(event, kSecXPCKeySignInAnalytics, &parentEvent, &error) && parentEvent != NULL){
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCWaitForInitialSyncWithAnalytics_Server(parentEvent, &error));
-                    }else{
-                        xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, SOSCCWaitForInitialSync_Server(&error));
-                    }
-                    CFReleaseNull(parentEvent);
-                }
-                break;
             case kSecXPCOpPeersHaveViewsEnabled:
                 {
                     CFArrayRef viewSet = SecXPCDictionaryCopyArray(event, kSecXPCKeyArray, &error);
@@ -1367,14 +1374,12 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
                         }
                     }
                     break;
-                    
             case kSecXPCOpKVSKeyCleanup:
-                    if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {                        
+                    if (EntitlementPresentAndTrue(operation, client.task, kSecEntitlementKeychainCloudCircle, &error)) {
                         bool retval = SOSCCCleanupKVSKeys_Server(&error);
                         xpc_dictionary_set_bool(replyMessage, kSecXPCKeyResult, retval);
                     }
                     break;
-        
             case kSecXPCOpMessageFromPeerIsPending:
                 {
                     SOSPeerInfoRef peer = SecXPCDictionaryCopyPeerInfo(event, kSecXPCKeyPeerInfo, &error);
@@ -1499,12 +1504,14 @@ static void securityd_xpc_dictionary_handler(const xpc_connection_t connection,
         xpc_connection_send_message(connection, replyMessage);
         xpc_release(replyMessage);
     }
-    if (xpcError)
+    if (xpcError) {
         xpc_release(xpcError);
+    }
     CFReleaseSafe(error);
     CFReleaseSafe(client.accessGroups);
     CFReleaseSafe(client.musr);
     CFReleaseSafe(client.task);
+    CFReleaseNull(client.applicationIdentifier);
     CFReleaseSafe(domains);
     CFReleaseSafe(clientAuditToken);
 }
@@ -1541,6 +1548,13 @@ static void securityd_xpc_init(const char *service_name)
     });
 #endif
 
+    xpc_activity_register("com.apple.securityd.prng", XPC_ACTIVITY_CHECK_IN, ^(xpc_activity_t activity) {
+        xpc_activity_state_t state = xpc_activity_get_state(activity);
+        if (state == XPC_ACTIVITY_STATE_RUN) {
+            refresh_prng();
+        }
+    });
+
 #if OCTAGON && !TARGET_OS_BRIDGE
     // Kick off reporting tasks.
     if (os_variant_has_internal_diagnostics("com.apple.security") && !os_variant_is_recovery("securityd")) {
@@ -1552,7 +1566,7 @@ static void securityd_xpc_init(const char *service_name)
 
 // <rdar://problem/22425706> 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp
 
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_BRIDGE
 static void securityd_soscc_lock_hack() {
        dispatch_queue_t                soscc_lock_queue = dispatch_queue_create("soscc_lock_queue", DISPATCH_QUEUE_PRIORITY_DEFAULT);
        int                                     soscc_tok;
@@ -1642,22 +1656,29 @@ int main(int argc, char *argv[])
     });
 #endif
 
+    signal(SIGTERM, SIG_IGN);
+    static dispatch_source_t termSource;
+    termSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0));
+    dispatch_source_set_event_handler(termSource, ^{
+        secnotice("signal", "SIGTERM, exiting when clean ✌️");
+        xpc_transaction_exit_clean();
+    });
+    dispatch_activate(termSource);
+
 #if TARGET_OS_OSX
 #define SECD_PROFILE_NAME "com.apple.secd"
     const char *homedir = homedirPath();
-    if (homedir == NULL)
+    if (homedir == NULL) {
         errx(1, "failed to get home directory for secd");
+    }
 
     char *errorbuf = NULL;
-    const char *sandbox_params[] = {
-        "_HOME", homedir,
-        NULL
-    };
-    int32_t            rc;
-
-    rc = sandbox_init_with_parameters(SECD_PROFILE_NAME, SANDBOX_NAMED, sandbox_params, &errorbuf);
-    if (rc)
-        err(1, "Failed to process in a sandbox: %d %s", rc, errorbuf);
+    const char *sandbox_params[] = {"_HOME", homedir, NULL};
+    int32_t rc = sandbox_init_with_parameters(SECD_PROFILE_NAME, SANDBOX_NAMED, sandbox_params, &errorbuf);
+    if (rc) {
+        errx(1, "Failed to instantiate sandbox: %d %s", rc, errorbuf);
+        /* errx will quit the process */
+    }
 #endif /* TARGET_OS_OSX */
 
     const char *serviceName = kSecuritydXPCServiceName;
@@ -1674,11 +1695,12 @@ int main(int argc, char *argv[])
 
     securityd_init_server();
     securityd_xpc_init(serviceName);
-
     SecCreateSecuritydXPCServer();
+
 #if SECUREOBJECTSYNC
     SOSControlServerInitialize();
 #endif
+
 #if OCTAGON
     CKKSControlServerInitialize();
     OctagonControlServerInitialize();
@@ -1686,7 +1708,7 @@ int main(int argc, char *argv[])
 #endif
 
        // <rdar://problem/22425706> 13B104+Roots:Device never moved past spinner after using approval to ENABLE icdp
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR && !TARGET_OS_BRIDGE
        securityd_soscc_lock_hack();
 #endif
 
index 8db291ac708080b0456b886fa614b3395aba0207..50607d9e86602988088e28cf7807299706dedd03 100644 (file)
@@ -75,6 +75,8 @@
         self->_client.inMultiUser                            = existingClient->inMultiUser;
         self->_client.activeUser                             = existingClient->activeUser;
 #endif
+        self->_client.applicationIdentifier                  = CFRetainSafe(existingClient->applicationIdentifier);
+        self->_client.isAppClip                              = existingClient->isAppClip;
     }
     return self;
 }
@@ -88,6 +90,7 @@
     CFReleaseNull(self->_client.task);
     CFReleaseNull(self->_client.accessGroups);
     CFReleaseNull(self->_client.musr);
+    CFReleaseNull(self->_client.applicationIdentifier);
 }
 @end
 
index 3dd4c5843b61a29f4eac28c97095fd0207634e60..f5fbfa983e4c6c690501badc3331ad9c9fb34f07 100644 (file)
 #include <Security/SecTaskPriv.h>
 #include "ipc/securityd_client.h"
 #include <Security/SecEntitlements.h>
+#include "sectask/SystemEntitlements.h"
 #include <Security/SecItem.h>
 #include "utilities/SecCFRelease.h"
 #include "utilities/SecCFWrappers.h"
 #include "utilities/debugging.h"
+#include <os/feature_private.h>
 
 CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
                                             CFStringRef entitlement)
@@ -70,8 +72,14 @@ CFArrayRef SecTaskCopyArrayOfStringsForEntitlement(SecTaskRef task,
 }
 
 CFStringRef SecTaskCopyApplicationIdentifier(SecTaskRef task) {
-    return SecTaskCopyStringForEntitlement(task,
-                                           kSecEntitlementApplicationIdentifier);
+    // Catalyst apps may have the iOS style application identifier.
+    CFStringRef result = SecTaskCopyStringForEntitlement(task,
+                                                         kSecEntitlementBasicApplicationIdentifier);
+    if (!result) {
+        result = SecTaskCopyStringForEntitlement(task,
+                                                 kSecEntitlementAppleApplicationIdentifier);
+    }
+    return result;
 }
 
 #if TARGET_OS_IOS
@@ -85,6 +93,8 @@ CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
 {
     CFMutableArrayRef groups = NULL;
 
+    bool onDemandInstallable = SecTaskGetBooleanValueForEntitlement(task, kSystemEntitlementOnDemandInstallCapable);
+
     CFArrayRef keychainAccessGroups, appleSecurityApplicationGroups;
     CFStringRef appID;
     CFArrayRef associatedAppIDs;
@@ -92,7 +102,7 @@ CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
     keychainAccessGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementKeychainAccessGroups);
     appleSecurityApplicationGroups = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAppleSecurityApplicationGroups);
     appID = SecTaskCopyApplicationIdentifier(task);
-    // Marzipan apps (may?) have this entitlement.
+    // Catalyst apps (may?) have this entitlement.
     associatedAppIDs = SecTaskCopyArrayOfStringsForEntitlement(task, kSecEntitlementAssociatedApplicationIdentifier);
 
     groups = CFArrayCreateMutableForCFTypes(NULL);
@@ -118,14 +128,19 @@ CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
             CFArrayAppendValue(groups, appID);
         }
         if (appleSecurityApplicationGroups) {
-            CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, CFArrayGetCount(appleSecurityApplicationGroups)));
+            if (onDemandInstallable) {
+                // This is perfectly legal for other functionality but not for keychain use
+                secnotice("entitlements", "Ignoring \"%@\" because client is API-restricted", kSecEntitlementAppleSecurityApplicationGroups);
+            } else {
+                CFArrayAppendArray(groups, appleSecurityApplicationGroups, CFRangeMake(0, CFArrayGetCount(appleSecurityApplicationGroups)));
+            }
         }
     } else {
         // Try to provide some hopefully helpful diagnostics for common failure cases.
         if (CFArrayGetCount(groups) == 0) {
             if (appID) {
                 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
-                       kSecEntitlementApplicationIdentifier, appID);
+                           kSecEntitlementApplicationIdentifier, appID);
             }
             if (appleSecurityApplicationGroups) {
                 secwarning("Entitlement %@=%@ is ignored because of invalid application signature or incorrect provisioning profile",
@@ -134,6 +149,21 @@ CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
         }
     }
 
+    // Do not allow to explicitly specify com.apple.token if token support is not allowed by feature flags.
+    CFIndex index = CFArrayGetFirstIndexOfValue(groups, CFRangeMake(0, CFArrayGetCount(groups)), kSecAttrAccessGroupToken);
+    if (index != kCFNotFound) {
+        if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+            // Make sure that com.apple.token is last one. This is because it is always read-only group and therefore updating keychain
+            // operations without explicitly set kSecAttrAccessGroup attribute would always fail.
+            CFArrayRemoveValueAtIndex(groups, index);
+            CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
+        } else {
+            secwarning("Keychain access group com.apple.token ignored, feature not available");
+            CFArrayRemoveValueAtIndex(groups, index);
+        }
+    }
+
+#if TARGET_OS_OSX
     /*
      * We would like to add implicit token access group always, but we avoid doing that in case that application
      * clearly intended to use non-smartcard functionality of keychain but messed up signing or provisioning. In this case,
@@ -142,8 +172,12 @@ CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task)
      */
     bool entitlementsFailure = (CFArrayGetCount(groups) == 0 && appID != NULL);
     if (!entitlementsFailure) {
-        CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
+        bool addTokenGroup = os_feature_enabled(CryptoTokenKit, UseTokens);
+        if (addTokenGroup && !CFArrayContainsValue(groups, CFRangeMake(0, CFArrayGetCount(groups)), kSecAttrAccessGroupToken)) {
+            CFArrayAppendValue(groups, kSecAttrAccessGroupToken);
+        }
     }
+#endif
 
     CFReleaseNull(associatedAppIDs);
     CFReleaseNull(appID);
index 216018f93d2865419decda179a08bc3a3dff2532..8d878b21c1c1ddfe77522da4ce44e4660536a6b5 100644 (file)
@@ -46,5 +46,8 @@ bool SecTaskIsEligiblePlatformBinary(SecTaskRef task, CFArrayRef identifiers);
 
 // Testing support
 void SecAccessGroupsSetCurrent(CFArrayRef accessGroups);
+void SecSecurityClientRegularToAppClip(void);
+void SecSecurityClientAppClipToRegular(void);
+void SecSecurityClientSetApplicationIdentifier(CFStringRef identifier);
 
 #endif /* server_security_helpers_h */
index b360fc43c789c0b18e3ebbfce459da0277db0137..b6351c6b165d91334fd959299189354b0bc81f47 100644 (file)
@@ -30,6 +30,7 @@
 #include <Security/SecTaskPriv.h>
 #include "ipc/securityd_client.h"
 #include <Security/SecEntitlements.h>
+#include "sectask/SystemEntitlements.h"
 #include <utilities/SecInternalReleasePriv.h>
 #include <sys/codesign.h>
 #include <Security/SecItem.h>
@@ -108,8 +109,7 @@ fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t aud
         client->uid = uid;
         client->musr = NULL;
 
-#if TARGET_OS_IOS
-#if HAVE_MOBILE_KEYBAG_SUPPORT
+#if TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT
         if (device_is_multiuser()) {
             CFErrorRef error = NULL;
 
@@ -139,15 +139,23 @@ fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t aud
                 client->keybag = KEYBAG_DEVICE;
             }
         } else
-#endif
+#endif /* TARGET_OS_IOS && HAVE_MOBILE_KEYBAG_SUPPORT */
+#if TARGET_OS_IOS || TARGET_OS_TV
         /*
-         * If the client application is a enterprise app according to usermanager, switch
-         * to the per enterprise slice of keychain.
+         * iOS supports Enterprise Data Separation.
+         * tvOS supports guest users.
+         * Use the appropriate musr values for either.
          */
         {
             UMUserPersona * persona = [[UMUserManager sharedManager] currentPersona];
-            if (persona && persona.userPersonaType == UMUserPersonaTypeEnterprise) {
-                secinfo("serverxpc", "securityd client: enterprise user");
+            if (persona &&
+#if TARGET_OS_IOS
+                persona.userPersonaType == UMUserPersonaTypeEnterprise
+#elif TARGET_OS_TV
+                persona.userPersonaType == UMUserPersonaTypeGuest
+#endif
+                ) {
+                secinfo("serverxpc", "securityd client: persona user %@", persona.userPersonaNickName);
                 uuid_t uuid;
 
                 if (uuid_parse([persona.userPersonaUniqueString UTF8String], uuid) != 0) {
@@ -156,11 +164,15 @@ fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t aud
                 client->musr = CFDataCreate(NULL, uuid, sizeof(uuid_t));
             }
         }
-#endif /* TARGET_OS_IOS */
+#endif /* TARGET_OS_IOS || TARGET_OS_TV */
 
         client->task = SecTaskCreateWithAuditToken(kCFAllocatorDefault, auditToken);
-
         client->accessGroups = SecTaskCopyAccessGroups(client->task);
+        client->applicationIdentifier = SecTaskCopyApplicationIdentifier(client->task);
+        client->isAppClip = SecTaskGetBooleanValueForEntitlement(client->task, kSystemEntitlementOnDemandInstallCapable);
+        if (client->isAppClip) {
+            secinfo("serverxpc", "securityd client: app clip (API restricted)");
+        }
 
 #if TARGET_OS_IPHONE
         client->allowSystemKeychain = SecTaskGetBooleanValueForEntitlement(client->task, kSecEntitlementPrivateSystemKeychain);
@@ -173,6 +185,10 @@ fill_security_client(SecurityClient * client, const uid_t uid, audit_token_t aud
         }
 #endif
         if (!sanityCheckClientAccessGroups(client)) {
+            CFReleaseNull(client->task);
+            CFReleaseNull(client->accessGroups);
+            CFReleaseNull(client->musr);
+            CFReleaseNull(client->applicationIdentifier);
             return false;
         }
     }
index 274133055eb9b43eff0a71f2733a910fa3c109db..6372a4590d8c05676fdf1fd959673e9ac48b6989 100644 (file)
         }
     }
 
+    if(attributes[(id)kSecDataInetExtraNotes] ||
+       attributes[(id)kSecDataInetExtraHistory] ||
+       attributes[(id)kSecDataInetExtraClientDefined0] ||
+       attributes[(id)kSecDataInetExtraClientDefined1] ||
+       attributes[(id)kSecDataInetExtraClientDefined2] ||
+       attributes[(id)kSecDataInetExtraClientDefined3]) {
+        if(![self clientHasBooleanEntitlement:(__bridge NSString*)kSecEntitlementPrivateInetExpansionFields]) {
+              SecError(errSecMissingEntitlement, &cferror, CFSTR("SecItemAddAndNotifyOnSync: %@ does not have entitlement %@"), _client.task, kSecEntitlementPrivateInetExpansionFields);
+              complete(NULL, NULL, (__bridge NSError*) cferror);
+              CFReleaseNull(cferror);
+              return;
+          }
+    }
+
     CFTypeRef cfresult = NULL;
 
     NSMutableDictionary* callbackQuery = [attributes mutableCopy];
                                   (__bridge NSString *)kSecAttrSynchronizable : (__bridge NSString *)kSecAttrSynchronizableAny,
                                   };
 
-    Query *q = query_create_with_limit((__bridge CFDictionaryRef)attributes, _client.musr, 0, &cferror);
+    Query *q = query_create_with_limit((__bridge CFDictionaryRef)attributes, _client.musr, 0, &(_client), &cferror);
     if (q == NULL) {
         SecError(errSecParam, &cferror, CFSTR("failed to build query: %@"), _client.task);
         complete(NULL, (__bridge NSError*) cferror);
     [[SecDbBackupManager manager] verifyBackupIntegrity:lightweight completion:completion];
 }
 
+
+- (void)secItemDeleteForAppClipApplicationIdentifier:(NSString*)identifier
+                                              completion:(void (^)(OSStatus))completion
+{
+    if (![self clientHasBooleanEntitlement:(__bridge NSString*)kSecEntitlementPrivateAppClipDeletion]) {
+        completion(errSecMissingEntitlement);
+        return;
+    }
+
+    completion(SecServerDeleteForAppClipApplicationIdentifier((__bridge CFStringRef)identifier));
+}
+
 @end
diff --git a/OSX/sec/os_log/com.apple.security.ckks.plist b/OSX/sec/os_log/com.apple.security.ckks.plist
new file mode 100644 (file)
index 0000000..b164d1b
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>DEFAULT-OPTIONS</key>
+       <dict>
+               <key>Default-Privacy-Setting</key>
+               <string>Public</string>
+               <key>Enabled</key>
+               <string>True</string>
+               <key>Persist</key>
+               <string>Default</string>
+               <key>Enable-Oversize-Messages</key>
+               <true/>
+               <key>TTL</key>
+               <string>Default</string>
+               <key>Development</key>
+               <dict>
+                       <key>Enabled</key>
+                       <string>True</string>
+                       <key>Persist</key>
+                       <string>Default</string>
+                       <key>TTL</key>
+                       <string>Default</string>
+               </dict>
+               <key>Debug</key>
+               <dict>
+                       <key>Enabled</key>
+                       <string>True</string>
+                       <key>Persist</key>
+                       <string>True</string>
+                       <key>TTL</key>
+                       <string>2</string>
+               </dict>
+       </dict>
+</dict>
+</plist>
index 87da5a3ddbebb31f116502e29a5c4a63b4b32cb5..a293e2d73ae819b5b2afb36f528fb9aa99a4cbd9 100644 (file)
                        <string>30</string>
                </dict>
        </dict>
+       <key>itemDelete</key>
+       <dict>
+               <key>Default-Privacy-Setting</key>
+               <string>Public</string>
+               <key>Enabled</key>
+               <string>True</string>
+               <key>Persist</key>
+               <string>True</string>
+               <key>TTL</key>
+               <string>10d</string>
+               <key>Development</key>
+               <dict>
+                       <key>Enabled</key>
+                       <string>True</string>
+                       <key>Persist</key>
+                       <string>True</string>
+                       <key>TTL</key>
+                       <string>10d</string>
+               </dict>
+       </dict>
 </dict>
 </plist>
index 35eb83390cfccaa92a12af4672a21a2ec142dcba..9dc36dce5d09eb6ccfe55a9187410f7fba5e54b0 100644 (file)
                <string>123456.test.group</string>
                <string>123456.test.group2</string>
        </array>
+       <key>com.apple.private.AuthorizationServices</key>
+       <array>
+               <string>com.apple.trust-settings.admin</string>
+       </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
index 44ebadc5d65846bdca453e7859fdc5618cbb63b1..e637efee6f1c84635ef8217c85b7de3ee540510e 100644 (file)
@@ -5,6 +5,5 @@
 /* Don't prevent multiple inclusion of this file. */
 #include <libsecurity_ssl/regressions/ssl_regressions.h>
 #include <libsecurity_keychain/regressions/keychain_regressions.h>
-#include <Breadcrumb/breadcrumb_regressions.h>
 #include <libsecurity_cms/regressions/cms_regressions.h>
 
index 8378610461289e718f91f80c4c94a0722b322bf9..f599fe70f93fa830b574a8421f7ff731c5d840a8 100644 (file)
 
 ONE_TEST(si_21_sectrust_asr)
 ONE_TEST(si_22_sectrust_iap)
-#if !TARGET_OS_WATCH
-ONE_TEST(si_23_sectrust_ocsp)
-#else
-DISABLED_ONE_TEST(si_23_sectrust_ocsp)
-#endif
 ONE_TEST(si_24_sectrust_itms)
 ONE_TEST(si_24_sectrust_diginotar)
 ONE_TEST(si_24_sectrust_digicert_malaysia)
 ONE_TEST(si_24_sectrust_passbook)
 ONE_TEST(si_25_cms_skid)
 ONE_TEST(si_26_sectrust_copyproperties)
-ONE_TEST(si_28_sectrustsettings)
 ONE_TEST(si_29_cms_chain_mode)
 ONE_TEST(si_32_sectrust_pinning_required)
 ONE_TEST(si_34_cms_timestamp)
@@ -41,19 +35,10 @@ ONE_TEST(si_62_csr)
 ONE_TEST(si_64_ossl_cms)
 ONE_TEST(si_65_cms_cert_policy)
 ONE_TEST(si_66_smime)
-#if !TARGET_OS_WATCH
-ONE_TEST(si_67_sectrust_blocklist)
-ONE_TEST(si_84_sectrust_allowlist)
-#else
-DISABLED_ONE_TEST(si_67_sectrust_blocklist)
-DISABLED_ONE_TEST(si_84_sectrust_allowlist)
-#endif
 ONE_TEST(si_68_secmatchissuer)
 ONE_TEST(si_70_sectrust_unified)
 ONE_TEST(si_71_mobile_store_policy)
-ONE_TEST(si_74_OTA_PKI_Signer)
 ONE_TEST(si_83_seccertificate_sighashalg)
-ONE_TEST(si_88_sectrust_valid)
 ONE_TEST(si_89_cms_hash_agility)
 ONE_TEST(rk_01_recoverykey)
 
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_SAN_seq_length.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_SAN_seq_length.cer
new file mode 100644 (file)
index 0000000..787be23
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_SAN_seq_length.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_general_name_type.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_general_name_type.cer
new file mode 100644 (file)
index 0000000..8805ba1
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/bad_general_name_type.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/san_zero_length_sequence.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/san_zero_length_sequence.cer
new file mode 100644 (file)
index 0000000..b6249ec
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/san_zero_length_sequence.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_aia.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_aia.cer
new file mode 100644 (file)
index 0000000..a83546f
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_aia.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_certificate_policies.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_certificate_policies.cer
new file mode 100644 (file)
index 0000000..9cb2c1f
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_certificate_policies.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_crldps.cer b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_crldps.cer
new file mode 100644 (file)
index 0000000..ed0b660
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ExtensionFailureCerts/zero_length_crldps.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_explicit_paramaters.cer b/OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_explicit_paramaters.cer
new file mode 100644 (file)
index 0000000..f9c5304
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/KeyFailureCerts/parse_fail_explicit_paramaters.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/rdn_short_length.cer b/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/rdn_short_length.cer
new file mode 100644 (file)
index 0000000..9c0f93b
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/rdn_short_length.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/zero_length_rdn.cer b/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/zero_length_rdn.cer
new file mode 100644 (file)
index 0000000..e4194b7
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/NameFailureCerts/zero_length_rdn.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_critical_policy_mappings.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_critical_policy_mappings.cer
new file mode 100644 (file)
index 0000000..a696bd7
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_critical_policy_mappings.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_ekus.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_ekus.cer
new file mode 100644 (file)
index 0000000..7b839ce
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_ekus.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_extensions.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_extensions.cer
new file mode 100644 (file)
index 0000000..96ed5c6
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_extensions.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_general_subtrees.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_general_subtrees.cer
new file mode 100644 (file)
index 0000000..5d76d03
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseFailureCerts/zero_length_general_subtrees.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_constructed_uri_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_constructed_uri_name.cer
new file mode 100644 (file)
index 0000000..bab809e
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_constructed_uri_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_directory_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_directory_name.cer
new file mode 100644 (file)
index 0000000..e755cec
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_directory_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_dns_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_dns_name.cer
new file mode 100644 (file)
index 0000000..3e60bc9
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_dns_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_edi_party_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_edi_party_name.cer
new file mode 100644 (file)
index 0000000..0020d4c
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_edi_party_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_ip_address.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_ip_address.cer
new file mode 100644 (file)
index 0000000..64eff2a
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_ip_address.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_other_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_other_name.cer
new file mode 100644 (file)
index 0000000..124c48e
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_other_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_registered_id.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_registered_id.cer
new file mode 100644 (file)
index 0000000..44163a7
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_registered_id.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_rfc822_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_rfc822_name.cer
new file mode 100644 (file)
index 0000000..6eaaa8e
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_rfc822_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_uri_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_uri_name.cer
new file mode 100644 (file)
index 0000000..77a69f7
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_uri_name.cer differ
diff --git a/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_x400_name.cer b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_x400_name.cer
new file mode 100644 (file)
index 0000000..c84a8d9
Binary files /dev/null and b/OSX/shared_regressions/si-18-certificate-parse/ParseSuccessCerts/general_name_type_x400_name.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/AAACertificateServices.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/AAACertificateServices.cer
new file mode 100644 (file)
index 0000000..5c715fa
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/AAACertificateServices.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ApplePublicServerRSA12-G1.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ApplePublicServerRSA12-G1.cer
new file mode 100644 (file)
index 0000000..3b7788b
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ApplePublicServerRSA12-G1.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomainsParsingTest.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomainsParsingTest.plist
new file mode 100644 (file)
index 0000000..8dd2219
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_ca</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <false/>
+                       <key>NSPinnedCAIdentities</key>
+                       <true/>
+                       <key>NSPinnedCAIdentitiesCount</key>
+                       <integer>1</integer>
+                       <key>NSIncludesSubdomains</key>
+                       <true/>
+               </dict>
+       </dict>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_leaf</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <true/>
+                       <key>NSPinnedLeafIdentitiesCount</key>
+                       <integer>2</integer>
+                       <key>NSPinnedCAIdentities</key>
+                       <false/>
+               </dict>
+       </dict>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_leaf_and_ca</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <true/>
+                       <key>NSPinnedLeafIdentitiesCount</key>
+                       <integer>1</integer>
+                       <key>NSPinnedCAIdentities</key>
+                       <true/>
+                       <key>NSPinnedCAIdentitiesCount</key>
+                       <integer>2</integer>
+               </dict>
+       </dict>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_without_spki</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <false/>
+                       <key>NSPinnedCAIdentities</key>
+                       <false/>
+               </dict>
+       </dict>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_with_empty_spki</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <true/>
+                       <key>NSPinnedLeafIdentitiesCount</key>
+                       <integer>0</integer>
+                       <key>NSPinnedCAIdentities</key>
+                       <false/>
+               </dict>
+       </dict>
+       <dict>
+               <key>PlistDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>PlistFileName</key>
+               <string>NSPinnedDomains_with_invalid_spki</string>
+               <key>ExpectedProperties</key>
+               <dict>
+                       <key>NSPinnedLeafIdentities</key>
+                       <true/>
+                       <key>NSPinnedLeafIdentitiesCount</key>
+                       <integer>0</integer>
+                       <key>NSPinnedCAIdentities</key>
+                       <true/>
+                       <key>NSPinnedCAIdentitiesCount</key>
+                       <integer>0</integer>
+               </dict>
+       </dict>
+</array>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_ca.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_ca.plist
new file mode 100644 (file)
index 0000000..edac4c7
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                               <key>NSIncludesSubdomains</key>
+                               <true/>
+                               <key>NSPinnedCAIdentities</key>
+                               <array>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=</string> <!-- DigiCert Root -->
+                                       </dict>
+                               </array>
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf.plist
new file mode 100644 (file)
index 0000000..4cab23a
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                               <key>NSPinnedLeafIdentities</key>
+                               <array>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>i9HalScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=</string> <!-- example.org (Serial Number 0f:d0:78:dd:48:f1:a2:bd:4d:0f:2b:a9:6b:60:38:fe) -->
+                                       </dict>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>i9HalScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=</string>
+                                       </dict>
+                               </array>
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf_and_ca.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_leaf_and_ca.plist
new file mode 100644 (file)
index 0000000..9a8c555
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                               <key>NSPinnedCAIdentities</key>
+                               <array>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>5kJvNEMw0KjrCAu7eXY5HZdvyCS13BbA0VJG1RSP91w=</string> <!-- DigiCert Intermediate -->
+                                       </dict>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=</string> <!-- DigiCert Root -->
+                                       </dict>
+                               </array>
+                               <key>NSPinnedLeafIdentities</key>
+                               <array>
+                                       <dict>
+                                               <key>SPKI-SHA256-BASE64</key>
+                                               <string>i9HalScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=</string> <!-- example.org (Serial Number 0f:d0:78:dd:48:f1:a2:bd:4d:0f:2b:a9:6b:60:38:fe) -->
+                                       </dict>
+                               </array>
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_empty_spki.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_empty_spki.plist
new file mode 100644 (file)
index 0000000..a974f8b
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                               <key>NSPinnedLeafIdentities</key>
+                               <array>
+                               </array>
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_invalid_spki.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_with_invalid_spki.plist
new file mode 100644 (file)
index 0000000..187c60d
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                               <key>NSPinnedCAIdentities</key>
+                               <array>
+                                       <string>r/mIkG3eEpVdm+u/ko/cwxzOMo1bk4TyHIlByibiA5E=</string> <!-- DigiCert Root (Bad syntax) -->
+                               </array>
+                               <key>NSPinnedLeafIdentities</key>
+                               <string>i9HalScvf6T/skE3/A7QOq5n5cTYs8UHNOEFCnkguSI=</string> <!-- example.org (Bad syntax) (Serial Number 0f:d0:78:dd:48:f1:a2:bd:4d:0f:2b:a9:6b:60:38:fe) -->
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_without_spki.plist b/OSX/shared_regressions/si-20-sectrust-policies-data/NSPinnedDomains_without_spki.plist
new file mode 100644 (file)
index 0000000..81657f6
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSPinnedDomains</key>
+               <dict>
+                       <key>example.org</key>
+                       <dict>
+                       </dict> <!-- example.org -->
+               </dict> <!-- NSPinnedDomains -->
+       </dict> <!-- NSAppTransportSecurity -->
+</dict>
+</plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/OCSP_TestCA.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/OCSP_TestCA.cer
new file mode 100644 (file)
index 0000000..9df4ea9
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/OCSP_TestCA.cer differ
index 8f960ce7dd92a1c28d7d21a2d572015e72529e22..eb3fde79db712c9870caa2250fcc266ee9d2ca68 100644 (file)
                <key>CertDirectory</key>
                <string>si-20-sectrust-policies-data</string>
                <key>MajorTestName</key>
-               <string>iPhoneProfileSigning</string>
+               <string>iPhoneProfileApplicationSigning</string>
                <key>MinorTestName</key>
                <string>PositiveTest</string>
                <key>Policies</key>
                        <key>Properties</key>
                        <dict>
                                <key>SecPolicyName</key>
-                               <string>openmarket.ess.apple.com</string>
+                               <string>init.ess.apple.com</string>
                        </dict>
                </dict>
                <key>Leaf</key>
                <key>ChainLength</key>
                <integer>3</integer>
                <key>VerifyDate</key>
-               <date>2019-02-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                <key>MajorTestName</key>
                <string>Systemwide-Baseline</string>
                <key>MinorTestName</key>
-               <string>IDS-IST</string>
+               <string>IDS-PublicTrust</string>
                <key>Policies</key>
                <dict>
                        <key>PolicyIdentifier</key>
                        <key>Properties</key>
                        <dict>
                                <key>SecPolicyName</key>
-                               <string>static.ess.apple.com</string>
+                               <string>pds-init.ess.apple.com</string>
                        </dict>
                </dict>
                <key>Leaf</key>
-               <string>ids_ist_static</string>
+               <string>ids_init_public</string>
                <key>Intermediates</key>
-               <string>AppleISTCA2G1</string>
+               <string>ApplePublicServerRSA12-G1</string>
                <key>Anchors</key>
-               <string>GeoTrustGlobalCA</string>
+               <string>AAACertificateServices</string>
                <key>ExpectedResult</key>
                <integer>4</integer>
                <key>ChainLength</key>
                <integer>3</integer>
                <key>VerifyDate</key>
-               <date>2017-12-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                <key>ChainLength</key>
                <integer>3</integer>
                <key>VerifyDate</key>
-               <date>2019-02-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                        <key>Properties</key>
                        <dict>
                                <key>SecPolicyName</key>
-                               <string>openmarket.ess.apple.com</string>
+                               <string>init.ess.apple.com</string>
                                <key>SecPolicyPolicyName</key>
                                <string>IDS</string>
                        </dict>
                <key>ChainLength</key>
                <integer>3</integer>
                <key>VerifyDate</key>
-               <date>2019-02-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                <string>si-20-sectrust-policies-data</string>
+               <key>BridgeOSDisable</key>
+               <true/>
                <key>MajorTestName</key>
                <string>Systemwide-PolicyName</string>
                <key>MinorTestName</key>
                        <key>Properties</key>
                        <dict>
                                <key>SecPolicyName</key>
-                               <string>static.ess.apple.com</string>
+                               <string>pds-init.ess.apple.com</string>
                                <key>SecPolicyPolicyName</key>
                                <string>IDS</string>
                        </dict>
                </dict>
                <key>Leaf</key>
-               <string>ids_ist_static</string>
+               <string>ids_init_public</string>
                <key>Intermediates</key>
-               <string>AppleISTCA2G1</string>
+               <string>ApplePublicServerRSA12-G1</string>
                <key>Anchors</key>
-               <string>GeoTrustGlobalCA</string>
+               <string>AAACertificateServices</string>
                <key>ExpectedResult</key>
                <integer>5</integer>
                <key>VerifyDate</key>
-               <date>2017-02-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                <key>ChainLength</key>
                <integer>3</integer>
                <key>VerifyDate</key>
-               <date>2019-02-08T21:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                        <key>Properties</key>
                        <dict>
                                <key>SecPolicyName</key>
-                               <string>static.ess.apple.com</string>
+                               <string>init.ess.apple.com</string>
                        </dict>
                </dict>
                <key>Leaf</key>
-               <string>ids_ist_static</string>
+               <string>ids_test</string>
                <key>Intermediates</key>
-               <string>AppleISTCA2G1</string>
+               <string>TestAppleServerAuthentication</string>
                <key>Anchors</key>
-               <string>GeoTrustGlobalCA</string>
+               <string>TestAppleRootCA</string>
                <key>ExpectedResult</key>
                <integer>4</integer>
                <key>VerifyDate</key>
-               <date>2017-04-08T20:00:00Z</date>
+               <date>2020-09-15T00:00:00Z</date>
        </dict>
        <dict>
                <key>CertDirectory</key>
                <key>VerifyDate</key>
                <date>2017-02-20T21:00:00Z</date>
        </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>BridgeOSDisable</key>
+               <true/>
+               <key>MajorTestName</key>
+               <string>Systemwide-Both</string>
+               <key>MinorTestName</key>
+               <string>Precedence</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>identity.ess.apple.com</string>
+                               <key>SecPolicyPolicyName</key>
+                               <string>APN</string>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
        <dict>
                <key>CertDirectory</key>
                <string>si-20-sectrust-policies-data</string>
                <key>ChainLength</key>
                <integer>3</integer>
        </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>iPhoneProfileApplicationSigning</string>
+               <key>MinorTestName</key>
+               <string>PositiveTest</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.55</string>
+               </dict>
+               <key>Leaf</key>
+               <string>test_iphone_distribution</string>
+               <key>Intermediates</key>
+               <string>TestAppleWWDR-G3</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>VerifyDate</key>
+               <date>2020-03-01T20:00:00Z</date>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>OCSP</string>
+               <key>MinorTestName</key>
+               <string>PositiveTest</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.66</string>
+               </dict>
+               <key>Leaf</key>
+               <string>ocsp_responder</string>
+               <key>Anchors</key>
+               <string>OCSP_TestCA</string>
+               <key>VerifyDate</key>
+               <date>2020-08-01T20:00:00Z</date>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>2</integer>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>OCSP</string>
+               <key>MinorTestName</key>
+               <string>NegativeTest-SubCA</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.66</string>
+               </dict>
+               <key>Leaf</key>
+               <string>ocsp_subca</string>
+               <key>Anchors</key>
+               <string>OCSP_TestCA</string>
+               <key>VerifyDate</key>
+               <date>2020-08-01T20:00:00Z</date>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>2</integer>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>OCSP</string>
+               <key>MinorTestName</key>
+               <string>NegativeTest-MissingEKU</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.66</string>
+               </dict>
+               <key>Leaf</key>
+               <string>ocsp_missing_eku</string>
+               <key>Anchors</key>
+               <string>OCSP_TestCA</string>
+               <key>VerifyDate</key>
+               <date>2020-08-01T20:00:00Z</date>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>2</integer>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>OCSP</string>
+               <key>MinorTestName</key>
+               <string>NegativeTest-MissingKU</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.66</string>
+               </dict>
+               <key>Leaf</key>
+               <string>ocsp_missing_ku</string>
+               <key>Anchors</key>
+               <string>OCSP_TestCA</string>
+               <key>VerifyDate</key>
+               <date>2020-08-01T20:00:00Z</date>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>2</integer>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckLeafSPKISHA256</string>
+               <key>MinorTestName</key>
+               <string>leaf-good</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>LeafSPKISHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>+GxzfmXKLWfWePjBrbCey6zjhsMU/KtGFQExWAnFJeQ=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckLeafSPKISHA256</string>
+               <key>MinorTestName</key>
+               <string>leaf-empty</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>LeafSPKISHA256</key>
+                               <array/>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckLeafSPKISHA256</string>
+               <key>MinorTestName</key>
+               <string>leaf-bad</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>LeafSPKISHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>intermediate-good</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>CAspkiSHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>Yc/8PBtv5TPVDELtY0SUFd5zObsSVVzm7WbLz5eIpQM=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>intermediate-empty</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>CAspkiSHA256</key>
+                               <array/>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>intermediate-bad</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>CAspkiSHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>root-good</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>CAspkiSHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>pmuYhKz98VG4gaGpUvi3y7CEl5+yJNGQ8/ARWg4FVnw=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>leaf-good-intermediate-good-root-good</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>LeafSPKISHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>+GxzfmXKLWfWePjBrbCey6zjhsMU/KtGFQExWAnFJeQ=</string>
+                               </array>
+                               <key>CAspkiSHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>Yc/8PBtv5TPVDELtY0SUFd5zObsSVVzm7WbLz5eIpQM=</string>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>pmuYhKz98VG4gaGpUvi3y7CEl5+yJNGQ8/ARWg4FVnw=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>4</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
+       <dict>
+               <key>CertDirectory</key>
+               <string>si-20-sectrust-policies-data</string>
+               <key>MajorTestName</key>
+               <string>kSecPolicyCheckCAspkiSHA256</string>
+               <key>MinorTestName</key>
+               <string>leaf-bad-intermediate-good-root-good</string>
+               <key>Policies</key>
+               <dict>
+                       <key>PolicyIdentifier</key>
+                       <string>1.2.840.113635.100.1.3</string>
+                       <key>Properties</key>
+                       <dict>
+                               <key>SecPolicyName</key>
+                               <string>init.ess.apple.com</string>
+                               <key>SecPolicyClient</key>
+                               <false/>
+                               <key>LeafSPKISHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                               </array>
+                               <key>CAspkiSHA256</key>
+                               <array>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>Yc/8PBtv5TPVDELtY0SUFd5zObsSVVzm7WbLz5eIpQM=</string>
+                                       <string>QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE=</string>
+                                       <string>pmuYhKz98VG4gaGpUvi3y7CEl5+yJNGQ8/ARWg4FVnw=</string>
+                               </array>
+                       </dict>
+               </dict>
+               <key>Leaf</key>
+               <string>ids_test</string>
+               <key>Intermediates</key>
+               <string>TestAppleServerAuthentication</string>
+               <key>Anchors</key>
+               <string>TestAppleRootCA</string>
+               <key>ExpectedResult</key>
+               <integer>5</integer>
+               <key>ChainLength</key>
+               <integer>3</integer>
+               <key>VerifyDate</key>
+               <date>2020-09-15T00:00:00Z</date>
+       </dict>
 </array>
 </plist>
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/TestAppleWWDR-G3.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/TestAppleWWDR-G3.cer
new file mode 100644 (file)
index 0000000..212690f
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/TestAppleWWDR-G3.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ids_init_public.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ids_init_public.cer
new file mode 100644 (file)
index 0000000..5cc09d6
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ids_init_public.cer differ
index c489eff14903509b3effeb59dda5ad22ca400f72..d2fed0a4638c4ddc0d10187b7db37d8380703249 100644 (file)
Binary files a/OSX/shared_regressions/si-20-sectrust-policies-data/ids_test.cer and b/OSX/shared_regressions/si-20-sectrust-policies-data/ids_test.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_eku.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_eku.cer
new file mode 100644 (file)
index 0000000..e60f5cb
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_eku.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_ku.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_ku.cer
new file mode 100644 (file)
index 0000000..edadfed
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_missing_ku.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_responder.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_responder.cer
new file mode 100644 (file)
index 0000000..582b1a0
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_responder.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_subca.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_subca.cer
new file mode 100644 (file)
index 0000000..60b13d8
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/ocsp_subca.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/test_iPh0ne_distribution.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/test_iPh0ne_distribution.cer
new file mode 100644 (file)
index 0000000..1196715
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/test_iPh0ne_distribution.cer differ
diff --git a/OSX/shared_regressions/si-20-sectrust-policies-data/test_iphone_distribution.cer b/OSX/shared_regressions/si-20-sectrust-policies-data/test_iphone_distribution.cer
new file mode 100644 (file)
index 0000000..1196715
Binary files /dev/null and b/OSX/shared_regressions/si-20-sectrust-policies-data/test_iphone_distribution.cer differ
index e276aeb779d35f25f020881b321e192423a0f254..cd8a2a465ea84266972a00457045f0e06106279d 100644 (file)
@@ -8,17 +8,13 @@
 #import <Security/SecKeyPriv.h>
 #import <Security/SecAccessControlPriv.h>
 #import <libaks_acl_cf_keys.h>
-#if !TARGET_OS_OSX
 #import "MobileGestalt.h"
-#else
-#import <RemoteServiceDiscovery/RemoteServiceDiscovery.h>
-#endif
 
 #import "shared_regressions.h"
 
-static id generateKey(id keyType, CFStringRef protection, BOOL noACL) {
+static id generateKey(id keyType, CFStringRef protection, BOOL withACL) {
     id accessControl;
-    if (noACL) {
+    if (!withACL) {
         accessControl = CFBridgingRelease(SecAccessControlCreate(kCFAllocatorDefault, NULL));
         SecAccessControlSetProtection((__bridge SecAccessControlRef)accessControl, protection, NULL);
     } else {
@@ -41,9 +37,9 @@ static void secKeySepTest(BOOL testPKA) {
     } else {
         keyTypes = @[(id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyTypeSecureEnclaveAttestation];
     }
-    BOOL noACL = YES;
+    BOOL withACL = NO;
     for (id keyType in keyTypes) {
-        id privateKey = generateKey((id)keyType, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, (noACL = !noACL));
+        id privateKey = generateKey((id)keyType, kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, (withACL = !withACL));
         ok(privateKey, "failed to create key '%@'", keyType);
         id publicKey = (__bridge_transfer id)SecKeyCopyPublicKey((SecKeyRef)privateKey);
 
@@ -92,16 +88,13 @@ static void secKeySepTest(BOOL testPKA) {
     }
 }
 
-static void attestationTest(CFStringRef protection, BOOL noACL) {
+static void attestationTest(CFStringRef protection, BOOL withACL) {
     NSError *error;
-    id privKey = generateKey((id)kSecAttrKeyTypeECSECPrimeRandom, protection, noACL);
-    id uik = generateKey((id)kSecAttrKeyTypeSecureEnclaveAttestation, protection, noACL);
+    id privKey = generateKey((id)kSecAttrKeyTypeECSECPrimeRandom, protection, withACL);
+    id uik = generateKey((id)kSecAttrKeyTypeSecureEnclaveAttestation, protection, withACL);
     id sik = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeSIK, (void *)&error));
     ok(sik != nil, "get SIK key: %@", error);
 
-    id pubSIK = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sik));
-    ok(pubSIK != nil, "get SIK pubkey");
-
     error = nil;
     NSData *attSIKPlain = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)uik, (void *)&error));
     ok(attSIKPlain != nil, "SIK attesting UIK, no nonce: %@", error);
@@ -120,70 +113,82 @@ static void attestationTest(CFStringRef protection, BOOL noACL) {
     ok(SecKeySetParameter((__bridge SecKeyRef)uik, kSecKeyParameterSETokenAttestationNonce, (__bridge CFPropertyListRef)nonce, (void *)&error), "Set nonce to UIK: %@", error);
     NSData *attUIKNonce = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)uik, (__bridge SecKeyRef)privKey, (void *)&error));
     ok(attUIKNonce != nil, "SIK attesting UIK, with nonce: %@", error);
+}
+
+static void sysKeyAttestationTest(CFStringRef protection, BOOL withACL, const char *name, SecKeyAttestationKeyType committed, SecKeyAttestationKeyType proposed, BOOL canAttest) {
+    NSError *error;
+    id privKey = generateKey((id)kSecAttrKeyTypeECSECPrimeRandom, protection, withACL);
+    id sik = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeSIK, (void *)&error));
+    ok(sik != nil, "get SIK key: %@", error);
+
+    id pubSIK = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sik));
+    ok(pubSIK != nil, "get SIK pubkey");
+
+    id sysKeyC = CFBridgingRelease(SecKeyCopyAttestationKey(committed, (void *)&error));
+    if (sysKeyC == nil) {
+        diag("skipping attestation test, platform does not support key %s-committed", name);
+        return;
+    }
 
     error = nil;
-    id sysUikC = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeUIKCommitted, (void *)&error));
-    if (sysUikC == nil) {
-        // Platform does not support system UIK, so just fake test rounds to avoid testplan counting failures.
-        for (int i = 0; i < 19; i++) {
-            ok(true);
-        }
-    } else {
-        ok(sysUikC != nil, "get UIK-committed key, error: %@", error);
-        error = nil;
-        id sysUikP = CFBridgingRelease(SecKeyCopyAttestationKey(kSecKeyAttestationKeyTypeUIKProposed, (void *)&error));
-        ok(sysUikP != nil, "get UIK-proposed key: %@", error);
+    id sysKeyP = CFBridgingRelease(SecKeyCopyAttestationKey(proposed, (void *)&error));
+    ok(sysKeyP != nil, "unable to get proposed key, but successfully got committed key");
 
+    if (canAttest) {
         error = nil;
-        NSData *attUIKC = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikC, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKC != nil, "Sys-UIK-committed attesting privKey: %@", error);
+        NSData *attSysKeyC = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyC, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyC != nil, "%s-committed attesting privKey: %@", name, error);
 
         error = nil;
-        NSData *attUIKP = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikP, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKP != nil, "Sys-UIK-proposed attesting privKey: %@", error);
+        NSData *attSysKeyP = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyP, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyP != nil, "%s-proposed attesting privKey: %@", name, error);
+    }
 
-        id pubUIKP = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysUikP));
-        ok(pubUIKP != nil, "Sys-UIK-proposed copy public key");
-        id pubUIKC = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysUikC));
-        ok(pubUIKC != nil, "Sys-UIK-proposed copy public key");
+    id pubSysKeyP = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysKeyP));
+    ok(pubSysKeyP != nil, "%s-proposed copy public key", name);
+    id pubSysKeyC = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysKeyC));
+    ok(pubSysKeyC != nil, "%s-committed copy public key", name);
 
-        BOOL res = SecKeyControlLifetime((__bridge SecKeyRef)sysUikC, kSecKeyControlLifetimeTypeBump, (void *)&error);
-        ok(res, "bumping sys-uik: %@", error);
+    BOOL res = SecKeyControlLifetime((__bridge SecKeyRef)sysKeyC, kSecKeyControlLifetimeTypeBump, (void *)&error);
+    ok(res, "bumping %s: %@", name, error);
 
+    if (canAttest) {
         error = nil;
-        NSData *attUIKCN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikC, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKCN != nil, "Sys-UIK-committed attesting privKey: %@", error);
+        NSData *attSysKeyCN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyC, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyCN != nil, "%s-committed attesting privKey: %@", name, error);
 
         error = nil;
-        NSData *attUIKPN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikP, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKPN != nil, "Sys-UIK-proposed attesting privKey: %@", error);
+        NSData *attSysKeyPN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyP, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyPN != nil, "%s-proposed attesting privKey: %@", name, error);
+    }
 
-        id pubUIKPN = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysUikP));
-        ok(pubUIKPN != nil, "Sys-UIK-proposed copy public key");
-        ok(![pubUIKPN isEqual:pubUIKC], "Sys-UIK proposed and committed differ after bump");
+    id pubSysKeyPN = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysKeyP));
+    ok(pubSysKeyPN != nil, "%s-proposed copy public key", name);
+    ok(![pubSysKeyPN isEqual:pubSysKeyC], "%s proposed and committed differ after bump", name);
 
-        res = SecKeyControlLifetime((__bridge SecKeyRef)sysUikP, kSecKeyControlLifetimeTypeCommit, (void *)&error);
-        ok(res, "committing sys-uik: %@", error);
+    res = SecKeyControlLifetime((__bridge SecKeyRef)sysKeyP, kSecKeyControlLifetimeTypeCommit, (void *)&error);
+    ok(res, "committing %s: %@", name, error);
 
+    if (canAttest) {
         error = nil;
-        NSData *attUIKCNN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikC, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKCNN != nil, "Sys-UIK-committed attesting privKey: %@", error);
+        NSData *attSysKeyCNN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyC, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyCNN != nil, "%s-committed attesting privKey: %@", name, error);
 
         error = nil;
-        NSData *attUIKPNN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysUikP, (__bridge SecKeyRef)privKey, (void *)&error));
-        ok(attUIKPNN != nil, "Sys-UIK-proposed attesting privKey: %@", error);
+        NSData *attSysKeyPNN = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sysKeyP, (__bridge SecKeyRef)privKey, (void *)&error));
+        ok(attSysKeyPNN != nil, "%s-proposed attesting privKey: %@", name, error);
+    }
 
-        id pubUIKCN = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysUikC));
-        ok(pubUIKCN != nil, "Sys-UIK-committed copy public key");
-        ok([pubUIKPN isEqual:pubUIKCN], "Sys-UIK proposed and committed same after commit");
+    id pubSysKeyCN = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)sysKeyC));
+    ok(pubSysKeyCN != nil, "%s-committed copy public key", name);
+    ok([pubSysKeyPN isEqual:pubSysKeyCN], "%s proposed and committed same after commit", name);
 
-        // Attest system-UIK with SIK
-        NSData *attSIKUIKP = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)sysUikP, (void *)&error));
-        ok(attSIKUIKP != nil, "SIK attesting Sys-UIK-proposed, error: %@", error);
+    // Attest system key with SIK
+    NSData *attSIKSysKeyP = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)sysKeyP, (void *)&error));
+    ok(attSIKSysKeyP != nil, "SIK attesting %s-proposed, error: %@", name, error);
 
-        NSData *attSIKUIKC = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)sysUikC, (void *)&error));
-        ok(attSIKUIKC != nil, "SIK attesting Sys-UIK-committed, error: %@", error);
-    }
+    NSData *attSIKSysKeyC = CFBridgingRelease(SecKeyCreateAttestation((__bridge SecKeyRef)sik, (__bridge SecKeyRef)sysKeyC, (void *)&error));
+    ok(attSIKSysKeyC != nil, "SIK attesting %s-committed, error: %@", name, error);
 }
 
 static void keyFromBlobTest(void) {
@@ -494,35 +499,44 @@ static void secAccessControlDescriptionTest(void) {
 
 int si_44_seckey_aks(int argc, char *const *argv) {
     @autoreleasepool {
-        BOOL testPKA = YES;
-#if !TARGET_OS_OSX
-        NSNumber *hasPKA = (__bridge_transfer id)MGCopyAnswer(kMGQHasPKA, NULL);
-        if(![hasPKA isKindOfClass:NSNumber.class] || ![hasPKA boolValue]) {
-            testPKA = NO;
-        }
-#else
-        if (remote_device_copy_unique_of_type(REMOTE_DEVICE_TYPE_EOS) == nil && remote_device_copy_unique_of_type(REMOTE_DEVICE_TYPE_BRIDGE_COPROC) == nil) {
+        NSNumber *hasSEP = CFBridgingRelease(MGCopyAnswer(kMGQHasSEP, NULL));
+        if (!hasSEP.boolValue) {
             // macOS without SEP cannot run attestations at all.
             plan_tests(1);
             ok(true);
             return 0;
         }
 
-        testPKA = NO;
-#endif
-        plan_tests(testPKA ? 119 : 104);
+        NSNumber *hasPKA = CFBridgingRelease(MGCopyAnswer(kMGQHasPKA, NULL));
+        plan_tests(hasPKA.boolValue ? 207 : 113);
 
         secAccessControlDescriptionTest();
-        secKeySepTest(testPKA);
-        attestationTest(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, NO);
-        attestationTest(kSecAttrAccessibleUntilReboot, YES);
+        secKeySepTest(hasPKA.boolValue);
+
+        attestationTest(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, YES);
+        attestationTest(kSecAttrAccessibleUntilReboot, NO);
+
+        sysKeyAttestationTest(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, YES, "SysUIK", kSecKeyAttestationKeyTypeUIKCommitted, kSecKeyAttestationKeyTypeUIKProposed, YES);
+        sysKeyAttestationTest(kSecAttrAccessibleUntilReboot, NO, "SysUIK", kSecKeyAttestationKeyTypeUIKCommitted, kSecKeyAttestationKeyTypeUIKProposed, YES);
+
+        // OIK is too weird to be usable directly, just skip is testing for now.
+#if 0
+        sysKeyAttestationTest(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, YES, "OIK", kSecKeyAttestationKeyTypeOIKCommitted, kSecKeyAttestationKeyTypeOIKProposed, NO);
+        sysKeyAttestationTest(kSecAttrAccessibleUntilReboot, NO, "OIK", kSecKeyAttestationKeyTypeOIKCommitted, kSecKeyAttestationKeyTypeOIKProposed, NO);
+#endif
+
+        sysKeyAttestationTest(kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, YES, "DAK", kSecKeyAttestationKeyTypeDAKCommitted, kSecKeyAttestationKeyTypeDAKProposed, YES);
+        sysKeyAttestationTest(kSecAttrAccessibleUntilReboot, NO, "DAK", kSecKeyAttestationKeyTypeDAKCommitted, kSecKeyAttestationKeyTypeDAKProposed, YES);
+
         keyFromBlobTest();
         keychainTest();
 
-        // Put SEP keys into test-keybag mode. Available only when running in direct-mode, not with extension.
-        SecKeySetParameter(NULL, kSecAttrTokenIDAppleKeyStore, kCFBooleanTrue, NULL);
-        rewrapTest();
-        SecKeySetParameter(NULL, kSecAttrTokenIDAppleKeyStore, kCFBooleanFalse, NULL);
+        if (hasPKA.boolValue) {
+            // Put SEP keys into test-keybag mode. Available only when running in direct-mode, not with extension.
+            SecKeySetParameter(NULL, kSecAttrTokenIDAppleKeyStore, kCFBooleanTrue, NULL);
+            rewrapTest();
+            SecKeySetParameter(NULL, kSecAttrTokenIDAppleKeyStore, kCFBooleanFalse, NULL);
+        }
 
         return 0;
     }
index c0aa33aa7c80a4cfbac7c82e4825aef464ea6882..648dfeae00f6bbae92264a95c6c1c31988e65073 100644 (file)
@@ -54,11 +54,12 @@ static void test_key_proxy_connect() {
 
     // Create new proxy and invalidate it (idempotent, so we try invalidate multiple times).
     keyProxy = [[SecKeyProxy alloc] initWithKey:(SecKeyRef)serverKey];
+    endpoint = keyProxy.endpoint;
     [keyProxy invalidate];
     [keyProxy invalidate];
-    secondKey = [SecKeyProxy createKeyFromEndpoint:keyProxy.endpoint error:&error];
+    secondKey = [SecKeyProxy createKeyFromEndpoint:endpoint error:&error];
     is(secondKey, NULL, "connection to invalidated proxy should be refused.");
-    
+
     // Invalidate connected proxy, make sure that remote key does not work as expected.
     keyProxy = [[SecKeyProxy alloc] initWithKey:(SecKeyRef)serverKey];
     secondKey = [SecKeyProxy createKeyFromEndpoint:keyProxy.endpoint error:&error];
diff --git a/OSX/shared_regressions/si-88-sectrust-valid.m b/OSX/shared_regressions/si-88-sectrust-valid.m
deleted file mode 100644 (file)
index 28b593a..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- *  si-88-sectrust-valid.m
- *  Security
- *
- *  Copyright (c) 2017-2019 Apple Inc. All Rights Reserved.
- *
- */
-
-#include <CoreFoundation/CoreFoundation.h>
-#include <Security/Security.h>
-#include <Security/SecTrust.h>
-#include <Security/SecPolicy.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <utilities/SecCFWrappers.h>
-
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include "shared_regressions.h"
-
-enum {
-    kBasicPolicy = 0,
-    kSSLServerPolicy = 1,
-};
-
-/* number of tests in the test_valid_trust function */
-#define TVT_COUNT 8
-
-static void test_valid_trust(SecCertificateRef leaf, SecCertificateRef ca, SecCertificateRef subca,
-                             CFArrayRef anchors, CFDateRef date, CFIndex policyID,
-                             SecTrustResultType expected, const char *test_name)
-{
-    CFArrayRef policies=NULL;
-    SecPolicyRef policy=NULL;
-    SecTrustRef trust=NULL;
-    SecTrustResultType trustResult;
-    CFMutableArrayRef certs=NULL;
-
-    printf("Starting %s\n", test_name);
-    isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array");
-    if (certs) {
-        if (leaf) {
-            CFArrayAppendValue(certs, leaf);
-        }
-        if (ca) {
-            CFArrayAppendValue(certs, ca);
-        }
-        if (subca) {
-            CFArrayAppendValue(certs, subca);
-        }
-    }
-
-    if (policyID == kSSLServerPolicy) {
-        isnt(policy = SecPolicyCreateSSL(true, NULL), NULL, "create ssl policy");
-    } else {
-        isnt(policy = SecPolicyCreateBasicX509(), NULL, "create basic policy");
-    }
-    isnt(policies = CFArrayCreate(kCFAllocatorDefault, (const void **)&policy, 1, &kCFTypeArrayCallBacks), NULL, "create policies");
-    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust), "create trust");
-
-    assert(trust); // silence analyzer
-    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors");
-    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
-    ok_status(SecTrustEvaluate(trust, &trustResult), "evaluate trust");
-    ok(trustResult == expected, "trustResult %d expected (got %d)",
-       (int)expected, (int)trustResult);
-
-    CFReleaseSafe(certs);
-    CFReleaseSafe(policy);
-    CFReleaseSafe(policies);
-    CFReleaseSafe(trust);
-}
-
-#import <Foundation/Foundation.h>
-SecCertificateRef SecCertificateCreateWithPEM(CFAllocatorRef allocator, CFDataRef pem_certificate);
-
-static SecCertificateRef SecCertificateCreateFromResource(NSString *name)
-{
-    NSString *resources = @"si-88-sectrust-valid-data";
-    NSString *extension = @"pem";
-
-    NSURL *url = [[NSBundle mainBundle] URLForResource:name withExtension:extension subdirectory:resources];
-    if (!url) {
-        printf("No URL for resource \"%s.pem\"\n", [name UTF8String]);
-        return NULL;
-    }
-
-    NSData *certData = [NSData dataWithContentsOfURL:url];
-    if (!certData) {
-        printf("No cert data for resource \"%s.pem\"\n", [name UTF8String]);
-        return NULL;
-    }
-
-    return SecCertificateCreateWithPEM(kCFAllocatorDefault, (__bridge CFDataRef)certData);
-}
-
-/* number of tests in date_constraints_tests function, plus calls to test_valid_trust */
-#define DC_COUNT (12+(TVT_COUNT*6))
-
-static void date_constraints_tests()
-{
-    SecCertificateRef ca_na=NULL, ca_nb=NULL, root=NULL;
-    SecCertificateRef leaf_na_ok1=NULL, leaf_na_ok2=NULL;
-    SecCertificateRef leaf_nb_ok1=NULL, leaf_nb_ok2=NULL, leaf_nb_revoked1=NULL;
-
-    isnt(ca_na = SecCertificateCreateFromResource(@"ca-na"), NULL, "create ca-na cert");
-    isnt(ca_nb = SecCertificateCreateFromResource(@"ca-nb"), NULL, "create ca-nb cert");
-    isnt(root = SecCertificateCreateFromResource(@"root"), NULL, "create root cert");
-    isnt(leaf_na_ok1 = SecCertificateCreateFromResource(@"leaf-na-ok1"), NULL, "create leaf-na-ok1 cert");
-    isnt(leaf_na_ok2 = SecCertificateCreateFromResource(@"leaf-na-ok2"), NULL, "create leaf-na-ok2 cert");
-    isnt(leaf_nb_ok1 = SecCertificateCreateFromResource(@"leaf-nb-ok1"), NULL, "create leaf-nb-ok1 cert");
-    isnt(leaf_nb_ok2 = SecCertificateCreateFromResource(@"leaf-nb-ok2"), NULL, "create leaf-nb-ok2 cert");
-    isnt(leaf_nb_revoked1 = SecCertificateCreateFromResource(@"leaf-nb-revoked1"), NULL, "create leaf-nb-revoked1 cert");
-
-    CFMutableArrayRef anchors=NULL;
-    isnt(anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create anchors array");
-    if (anchors && root) {
-        CFArrayAppendValue(anchors, root);
-    }
-    CFCalendarRef cal = NULL;
-    CFAbsoluteTime at;
-    CFDateRef date_20180102 = NULL; // a date when our test certs would all be valid, in the absence of Valid db info
-
-    isnt(cal = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar), NULL, "create calendar");
-    ok(CFCalendarComposeAbsoluteTime(cal, &at, "yMd", 2018, 1, 2), "create verify absolute time 20180102");
-    isnt(date_20180102 = CFDateCreate(kCFAllocatorDefault, at), NULL, "create verify date 20180102");
-
-    /* Case 0: leaf_na_ok1 (not revoked) */
-    /* -- OK: cert issued 2017-10-20, before the CA not-after date of 2017-10-21 */
-    /*        test cert has no SCT, but is expected to be OK since we now only apply the CT restriction for SSL. */
-    test_valid_trust(leaf_na_ok1, ca_na, NULL, anchors, date_20180102,
-                     kBasicPolicy, kSecTrustResultUnspecified,
-                     "leaf_na_ok1 basic");
-
-    /* Case 1: leaf_na_ok1 (not revoked) */
-    /* -- BAD: since a not-after date now requires CT (for SSL) and the test cert has no SCT, this is fatal. */
-    test_valid_trust(leaf_na_ok1, ca_na, NULL, anchors, date_20180102,
-                     kSSLServerPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_na_ok1 ssl");
-
-    /* Case 2: leaf_na_ok2 (revoked) */
-    /* -- BAD: cert issued 2017-10-26, after the CA not-after date of 2017-10-21 */
-    test_valid_trust(leaf_na_ok2, ca_na, NULL, anchors, date_20180102,
-                     kBasicPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_na_ok2 basic");
-
-    /* Case 3: leaf_nb_ok1 (revoked) */
-    /* -- BAD: cert issued 2017-10-20, before the CA not-before date of 2017-10-22 */
-    test_valid_trust(leaf_nb_ok1, ca_nb, NULL, anchors, date_20180102,
-                     kBasicPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_nb_ok1 basic");
-
-    /* Case 4: leaf_nb_ok2 (not revoked) */
-    /* -- OK: cert issued 2017-10-26, after the CA not-before date of 2017-10-22 */
-    test_valid_trust(leaf_nb_ok2, ca_nb, NULL, anchors, date_20180102,
-                     kBasicPolicy, kSecTrustResultUnspecified,
-                     "leaf_nb_ok2 basic");
-
-    /* Case 5: leaf_nb_revoked1 (revoked) */
-    /* -- BAD: cert issued 2017-10-20, before the CA not-before date of 2017-10-22 */
-    test_valid_trust(leaf_nb_revoked1, ca_nb, NULL, anchors, date_20180102,
-                     kBasicPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_nb_revoked1 basic");
-
-    CFReleaseSafe(ca_na);
-    CFReleaseSafe(ca_nb);
-    CFReleaseSafe(leaf_na_ok1);
-    CFReleaseSafe(leaf_na_ok2);
-    CFReleaseSafe(leaf_nb_ok1);
-    CFReleaseSafe(leaf_nb_ok2);
-    CFReleaseSafe(leaf_nb_revoked1);
-    CFReleaseSafe(root);
-    CFReleaseSafe(anchors);
-    CFReleaseSafe(cal);
-    CFReleaseSafe(date_20180102);
-}
-
-/* number of tests in known_intermediate_tests function, plus calls to test_valid_trust */
-#define KI_COUNT (10+(TVT_COUNT*3))
-
-static void known_intermediate_tests()
-{
-    SecCertificateRef ca_ki=NULL, root=NULL;
-    SecCertificateRef leaf_ki_ok1=NULL, leaf_ki_revoked1=NULL;
-    SecCertificateRef leaf_unknown=NULL, ca_unknown=NULL;
-
-    isnt(ca_ki = SecCertificateCreateFromResource(@"ca-ki"), NULL, "create ca-ki cert");
-    isnt(root = SecCertificateCreateFromResource(@"root"), NULL, "create root cert");
-    isnt(leaf_ki_ok1 = SecCertificateCreateFromResource(@"leaf-ki-ok1"), NULL, "create leaf-ki-ok1 cert");
-    isnt(leaf_ki_revoked1 = SecCertificateCreateFromResource(@"leaf-ki-revoked1"), NULL, "create leaf-ki-revoked1 cert");
-    isnt(ca_unknown = SecCertificateCreateFromResource(@"ca-unknown"), NULL, "create ca-unknown cert");
-    isnt(leaf_unknown = SecCertificateCreateFromResource(@"leaf-unknown"), NULL, "create leaf-unknown cert");
-
-    CFMutableArrayRef anchors=NULL;
-    isnt(anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create anchors array");
-    if (anchors && root) {
-        CFArrayAppendValue(anchors, root);
-    }
-    CFCalendarRef cal = NULL;
-    CFAbsoluteTime at;
-    CFDateRef date_20180310 = NULL; // a date when our test certs would all be valid, in the absence of Valid db info
-
-    isnt(cal = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar), NULL, "create calendar");
-    ok(CFCalendarComposeAbsoluteTime(cal, &at, "yMd", 2018, 3, 10), "create verify absolute time 20180310");
-    isnt(date_20180310 = CFDateCreate(kCFAllocatorDefault, at), NULL, "create verify date 20180310");
-
-    /* Case 1: leaf_ki_ok1 */
-    /* -- OK: cert issued by a known intermediate */
-    test_valid_trust(leaf_ki_ok1, ca_ki, NULL, anchors, date_20180310,
-                     kBasicPolicy, kSecTrustResultUnspecified,
-                     "leaf_ki_ok1");
-
-    /* Case 2: leaf_ki_revoked1 */
-    /* -- BAD: CA specifies known-only+complete serial blocklist; this cert is on the blocklist. */
-    test_valid_trust(leaf_ki_revoked1, ca_ki, NULL, anchors, date_20180310,
-                     kBasicPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_ki_revoked1");
-
-    /* Case 3: leaf_unknown */
-    /* -- BAD: ca_unknown issued from ca_ki, but is not a known intermediate.
-     * ca_ki has a path len of 0 which would normally result in kSecTrustResultRecoverableTrustFailure;
-     * however, since known-intermediates is asserted for ca_ki (non-overridable), we expect a fatal failure. */
-    test_valid_trust(leaf_unknown, ca_unknown, ca_ki, anchors, date_20180310,
-                     kBasicPolicy, kSecTrustResultFatalTrustFailure,
-                     "leaf_unknown test");
-
-    CFReleaseSafe(ca_ki);
-    CFReleaseSafe(leaf_ki_ok1);
-    CFReleaseSafe(leaf_ki_revoked1);
-    CFReleaseSafe(ca_unknown);
-    CFReleaseSafe(leaf_unknown);
-    CFReleaseSafe(root);
-    CFReleaseSafe(anchors);
-    CFReleaseSafe(cal);
-    CFReleaseSafe(date_20180310);
-}
-
-static int ping_host(char *host_name)
-{
-    struct sockaddr_in pin;
-    struct hostent *nlp_host;
-    int sd = 0;
-    int port = 80;
-    int retries = 5; // we try 5 times, then give up
-
-    while ((nlp_host=gethostbyname(host_name))==0 && retries--) {
-        printf("Resolve Error! (%s) %d\n", host_name, h_errno);
-        sleep(1);
-    }
-    if (nlp_host==0) {
-        return 0;
-    }
-
-    bzero(&pin,sizeof(pin));
-    pin.sin_family=AF_INET;
-    pin.sin_addr.s_addr=htonl(INADDR_ANY);
-    pin.sin_addr.s_addr=((struct in_addr *)(nlp_host->h_addr))->s_addr;
-    pin.sin_port=htons(port);
-
-    sd=socket(AF_INET,SOCK_STREAM,0);
-
-    if (connect(sd,(struct sockaddr*)&pin,sizeof(pin))==-1) {
-        printf("connect error! (%s) %d\n", host_name, errno);
-        close(sd);
-        return 0;
-    }
-    close(sd);
-    return 1;
-}
-
-static int preflight_network()
-{
-    char *hosts[] = {
-        "EVSecure-ocsp.verisign.com",
-        "EVIntl-ocsp.verisign.com",
-        "EVIntl-aia.verisign.com",
-        "ocsp.comodoca.com",
-        "crt.comodoca.com",
-        "ocsp.entrust.net",
-        "ocsp.digicert.com",
-    };
-
-    for (unsigned host_cnt = 0; host_cnt < sizeof(hosts)/sizeof(hosts[0]); host_cnt ++) {
-        if (!ping_host(hosts[host_cnt])) {
-            printf("Accessing specific server (%s) failed, check the network!\n", hosts[host_cnt]);
-            return 0;
-        }
-    }
-    return 1;
-}
-
-int si_88_sectrust_valid(int argc, char *const *argv)
-{
-    plan_tests(DC_COUNT+KI_COUNT);
-
-    if (!preflight_network()) {
-        return 0;
-    }
-
-    date_constraints_tests();
-    known_intermediate_tests();
-
-    return 0;
-}
index 9817610115f3b05c35f45419b8e451dcbe52220c..3a9031e1f497173d3b6e6d8edd65d3dbf36c9c05 100644 (file)
@@ -63,7 +63,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFStringRef decoded = NULL;
 
-    const uint8_t* decode_end = der_decode_string(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_string(NULL,
                                                   &decoded, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
@@ -77,7 +77,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFTypeRef decoded_type = NULL;
 
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
index ceeeddf9f1da4844932295c10b2da0e9354efd60..fb50b629691f74ab9a24be2d874535e7ddc1263c 100644 (file)
@@ -120,14 +120,14 @@ static void one_test(const struct test_case * thisCase)
 #endif
 
     CFDataRef decoded = NULL;
-    const uint8_t* decode_end = der_decode_data(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_data(NULL,
                                                 &decoded, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
     ok((decoded != NULL) && CFEqual(decoded, start));
 
     CFTypeRef decoded_type = NULL;
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
index ed6fe783382b2f48b00d462569952cc056a43603..5a4ae67a9fc4f0b3f11dd14ab4723d997c579540 100644 (file)
@@ -61,14 +61,14 @@ static void one_test(CFBooleanRef value, size_t der_size, const uint8_t *expecte
 #endif
 
     CFBooleanRef decoded = NULL;
-    const uint8_t* decode_end = der_decode_boolean(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_boolean(NULL,
                                                    &decoded, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
     ok((decoded != NULL) && CFEqual(decoded, value));
 
     CFPropertyListRef decoded_type = NULL;
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end);
index 8eb5d0388f2a8c091e764a65f46c2dfe9e2a8398..6b6b17385c9ff52eb118e80e8ddb9fe7a9315f11 100644 (file)
@@ -82,7 +82,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFNumberRef decoded = NULL;
     
-    const uint8_t* decode_end = der_decode_number(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_number(NULL,
                                                   &decoded, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
@@ -90,7 +90,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFPropertyListRef decoded_type = NULL;
 
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end, "didn't decode whole buffer");
index 5627a9dbf07505d131a9035eca1053ad4760bc30..1407628299485da6153c6be6d0d14521d95903af 100644 (file)
@@ -83,7 +83,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFArrayRef decoded = NULL;
     
-    const uint8_t* decode_end = der_decode_array(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_array(NULL,
                                                  &decoded, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
@@ -91,7 +91,7 @@ static void one_test(const struct test_case * thisCase)
 
     CFTypeRef decoded_type = NULL;
 
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
 
     ok(decode_end == buffer_end, "didn't decode whole buffer");
index 945bf3fe4941cfa4ab007dfb4d22cafbb9e14173..9f9c3515932ecaa139de6ae1b9e027494187f04e 100644 (file)
@@ -83,7 +83,7 @@ static void test_dictionary(CFDictionaryRef testValue, size_t expected_size, con
     
     CFDictionaryRef decoded = NULL;
     
-    const uint8_t* decode_end = der_decode_dictionary(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_dictionary(NULL,
                                                       &decoded, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
@@ -91,7 +91,7 @@ static void test_dictionary(CFDictionaryRef testValue, size_t expected_size, con
     
     CFPropertyListRef decoded_type = NULL;
     
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
index df3d05fcb9912c3159ab7d732e419ef2ec81bb0f..8b781a7303752c1abdc7b1ad6b328b209459bf3c 100644 (file)
@@ -114,6 +114,7 @@ static bool ok_date_equals(int testnumber, CFDateRef decoded, CFDateRef expected
     }
 }
 
+#if 0
 static CFCalendarRef sZuluCalendar = NULL;
 
 static CFCalendarRef SecCFCalendarGetZulu() {
@@ -170,10 +171,12 @@ static bool parallelizeZulu(bool useSharedZuluCalendar, void(^action)(CFCalendar
     dispatch_release(dgroup);
     return !stop;
 }
+#endif
 
 // We expect this to fail until this is fixed:
 //  <rdar://problem/16372688> CFCalendarDecomposeAbsoluteTime is not thread safe
 //
+#if 0
 static void testWithUnguardedZuluCalendar() {
     const bool useSharedZuluCalendar = true;
     __block bool success = true;
@@ -217,6 +220,7 @@ static void testDoWithZulu() {
 
     ok(success,"unexpected result from CFCalendarDecomposeAbsoluteTime");
 }
+#endif
 
 #define kTestsPerTestCase 12
 static void one_test(const struct test_case * thisCase, int testnumber)
@@ -246,7 +250,7 @@ static void one_test(const struct test_case * thisCase, int testnumber)
     CFReleaseNull(error);
 
     CFDateRef decoded = NULL;
-    const uint8_t* decode_end = der_decode_date(NULL, kCFPropertyListMutableContainers,
+    const uint8_t* decode_end = der_decode_date(NULL,
                                                   &decoded, &error, encoded, buffer_end);
     ok(error == NULL, "[%d] der_decode_date failed: %@", testnumber, error);
     CFReleaseNull(error);
@@ -256,7 +260,7 @@ static void one_test(const struct test_case * thisCase, int testnumber)
 
     CFPropertyListRef decoded_type = NULL;
 
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainers,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, &error, encoded, buffer_end);
     ok(error == NULL, "[%d] der_decode_plist failed: %@", testnumber, error);
     CFReleaseNull(error);
index eff6f58842ac8c64c88d0784f719a5c60ee3ad85..845b5b15ab56e5c81e1e4d659e3da6e11a797053 100644 (file)
@@ -86,7 +86,7 @@ static void test_set(CFSetRef testValue, size_t expected_size, const uint8_t* ex
     
     CFSetRef decoded = NULL;
     
-    const uint8_t* decode_end = der_decode_set(NULL, kCFPropertyListMutableContainersAndLeaves,
+    const uint8_t* decode_end = der_decode_set(NULL,
                                                       &decoded, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
@@ -94,7 +94,7 @@ static void test_set(CFSetRef testValue, size_t expected_size, const uint8_t* ex
     
     CFPropertyListRef decoded_type = NULL;
     
-    decode_end = der_decode_plist(NULL, kCFPropertyListMutableContainersAndLeaves,
+    decode_end = der_decode_plist(NULL,
                                   &decoded_type, NULL, encoded, buffer_end);
     
     ok(decode_end == buffer_end, "didn't decode whole buffer");
index 5c3c4d13c2033c8d816a855b047404ff4d5d55a6..90d2c0c9262d6edae6bf0e95b3f08835856d5657 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <utilities/SecCFRelease.h>
 #include <utilities/SecDb.h>
+#include <utilities/SecDbInternal.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 
@@ -71,25 +72,25 @@ static void count_connections(SecDbRef db) {
     dispatch_group_t group = dispatch_group_create();
     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     dispatch_group_async(group, queue, ^{
-        cmp_ok(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), <=, kSecDbMaxWriters, "max writers is %d", kSecDbMaxWriters);
+        cmp_ok(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), <=, kSecDbMaxWriters, "max writers is %zu", kSecDbMaxWriters);
     TODO: {
         todo("can't guarantee all threads used");
-        is(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), kSecDbMaxWriters, "max writers is %d", kSecDbMaxWriters);
+        is(count_func(db, "writers", &max_conn_count, SecDbPerformWrite), kSecDbMaxWriters, "max writers is %zu", kSecDbMaxWriters);
         }
     });
     dispatch_group_async(group, queue, ^{
-        cmp_ok(count_func(db, "readers",  &max_conn_count, SecDbPerformRead), <=, kSecDbMaxReaders, "max readers is %d", kSecDbMaxReaders);
+        cmp_ok(count_func(db, "readers",  &max_conn_count, SecDbPerformRead), <=, kSecDbMaxReaders, "max readers is %zu", kSecDbMaxReaders);
     TODO: {
         todo("can't guarantee all threads used");
-        is(count_func(db, "readers",  &max_conn_count, SecDbPerformRead), kSecDbMaxReaders, "max readers is %d", kSecDbMaxReaders);
+        is(count_func(db, "readers",  &max_conn_count, SecDbPerformRead), kSecDbMaxReaders, "max readers is %zu", kSecDbMaxReaders);
         }
     });
     dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
     dispatch_release(group);
-    cmp_ok(max_conn_count, <=, kSecDbMaxIdleHandles, "max idle connection count is %d", kSecDbMaxIdleHandles);
+    cmp_ok(max_conn_count, <=, kSecDbMaxIdleHandles, "max idle connection count is %zu", kSecDbMaxIdleHandles);
     TODO: {
         todo("can't guarantee all threads idle");
-        is(max_conn_count, kSecDbMaxIdleHandles, "max idle connection count is %d", kSecDbMaxIdleHandles);
+        is(max_conn_count, kSecDbMaxIdleHandles, "max idle connection count is %zu", kSecDbMaxIdleHandles);
     }
 
 }
index b7f9c5bfe2b93c8e0c4253aac25207264393ff70..52c8b838104710956dfa96d2ca67969a55847580 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecDb.h>
+#include <utilities/SecDbInternal.h>
 #include <utilities/SecDispatchRelease.h>
 
 #include <CoreFoundation/CoreFoundation.h>
@@ -31,7 +32,7 @@
 #include "utilities_regressions.h"
 #include <time.h>
 
-#define kTestCount 3418
+#define kTestCount 3422     // God I love magic numbers
 
 // Queue to protect counters and test_ok invocations
 static dispatch_queue_t count_queue;
@@ -187,7 +188,7 @@ static void tests(void)
     CFReleaseNull(tid);
 
     const char *home_var = getenv("HOME");
-    CFStringRef dbName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/Library/Keychains/su-41-sqldb-stress.db"), home_var ? home_var : "");
+    CFStringRef dbName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s/Library/Keychains/su-41-secdb-stress.db"), home_var ? home_var : "/var/tmp");
     CFStringPerformWithCString(dbName, ^(const char *path) { unlink(path); });
 
     SecDbRef db = SecDbCreate(dbName, 0600, true, true, true, true, kSecDbMaxIdleHandles,
@@ -244,14 +245,18 @@ static void tests(void)
 
     dispatch_release_null(count_queue);
 
-    cmp_ok(max_idle, >=, kSecDbMaxIdleHandles - 1, "max idle at least %d", kSecDbMaxIdleHandles - 1);
-    cmp_ok(max_writers, >=, kSecDbMaxWriters - 1, "max writers at least %d", kSecDbMaxWriters - 1);
-    cmp_ok(max_readers, >=, kSecDbMaxReaders - 1, "max readers at least %d", kSecDbMaxReaders - 1);
+    cmp_ok(SecDbIdleConnectionCount(db), >=, kSecDbMaxIdleHandles - 1, "cur idle at least %lu", kSecDbMaxIdleHandles - 1);
+    cmp_ok(SecDbIdleConnectionCount(db), <=, kSecDbMaxIdleHandles, "cur idle at most %lu", kSecDbMaxIdleHandles);
+    cmp_ok(max_idle, <=, kSecDbMaxIdleHandles, "max idle at most %lu", kSecDbMaxIdleHandles - 1);
+    cmp_ok(max_writers, >=, kSecDbMaxWriters - 1, "max writers at least %lu", kSecDbMaxWriters - 1);
+    cmp_ok(max_readers, >=, kSecDbMaxReaders - 1, "max readers at least %lu", kSecDbMaxReaders - 1);
+    cmp_ok(max_writers, <=, kSecDbMaxWriters, "max writers at most %lu", kSecDbMaxWriters);
+    cmp_ok(max_readers, <=, kSecDbMaxReaders, "max readers at most %lu", kSecDbMaxReaders);
     TODO: {
         todo("race conditions make us not always hit the limits reliably.");
-        is(max_idle, kSecDbMaxIdleHandles, "max idle connection count is %d", kSecDbMaxIdleHandles);
-        is(max_writers, kSecDbMaxWriters, "max writers is %d", kSecDbMaxWriters);
-        is(max_readers, kSecDbMaxReaders, "max readers is %d", kSecDbMaxReaders);
+        is(max_idle, kSecDbMaxIdleHandles, "max idle connection count is %zu", kSecDbMaxIdleHandles);
+        is(max_writers, kSecDbMaxWriters, "max writers is %zu", kSecDbMaxWriters);
+        is(max_readers, kSecDbMaxReaders, "max readers is %zu", kSecDbMaxReaders);
     }
 
     CFReleaseSafe(dbName);
diff --git a/OSX/utilities/SecADWrapper.c b/OSX/utilities/SecADWrapper.c
deleted file mode 100644 (file)
index 7d6aba8..0000000
+++ /dev/null
@@ -1,102 +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 "SecADWrapper.h"
-
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-#include <AggregateDictionary/ADClient.h>
-
-static typeof(ADClientAddValueForScalarKey) *soft_ADClientAddValueForScalarKey = NULL;
-static typeof(ADClientClearScalarKey) *soft_ADClientClearScalarKey = NULL;
-static typeof(ADClientSetValueForScalarKey) *soft_ADClientSetValueForScalarKey = NULL;
-static typeof(ADClientPushValueForDistributionKey) *soft_ADClientPushValueForDistributionKey = NULL;
-
-static bool
-setup(void)
-{
-    static dispatch_once_t onceToken;
-    static CFBundleRef bundle = NULL;
-    dispatch_once(&onceToken, ^{
-
-        CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework"), kCFURLPOSIXPathStyle, true);
-        if (url == NULL)
-            return;
-
-        bundle = CFBundleCreate(kCFAllocatorDefault, url);
-        CFRelease(url);
-        if (bundle == NULL)
-            return;
-
-        soft_ADClientClearScalarKey = CFBundleGetFunctionPointerForName(bundle, CFSTR("ADClientClearScalarKey"));
-        soft_ADClientSetValueForScalarKey = CFBundleGetFunctionPointerForName(bundle, CFSTR("ADClientSetValueForScalarKey"));
-        soft_ADClientAddValueForScalarKey = CFBundleGetFunctionPointerForName(bundle, CFSTR("ADClientAddValueForScalarKey"));
-        soft_ADClientPushValueForDistributionKey = CFBundleGetFunctionPointerForName(bundle, CFSTR("ADClientPushValueForDistributionKey"));
-
-        if (soft_ADClientClearScalarKey == NULL ||
-            soft_ADClientSetValueForScalarKey == NULL ||
-            soft_ADClientAddValueForScalarKey == NULL ||
-            soft_ADClientPushValueForDistributionKey == NULL)
-        {
-            CFRelease(bundle);
-            bundle = NULL;
-        }
-    });
-    return bundle != NULL;
-}
-#endif
-
-void
-SecADClearScalarKey(CFStringRef key)
-{
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-    if (setup())
-        soft_ADClientClearScalarKey(key);
-#endif
-}
-
-void
-SecADSetValueForScalarKey(CFStringRef key, int64_t value)
-{
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-    if (setup())
-        soft_ADClientSetValueForScalarKey(key, value);
-#endif
-}
-void
-SecADAddValueForScalarKey(CFStringRef key, int64_t value)
-{
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-    if (setup())
-        soft_ADClientAddValueForScalarKey(key, value);
-#endif
-}
-
-void
-SecADClientPushValueForDistributionKey(CFStringRef key, int64_t value)
-{
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-    if (setup())
-        soft_ADClientPushValueForDistributionKey(key, value);
-#endif
-}
-
diff --git a/OSX/utilities/SecADWrapper.h b/OSX/utilities/SecADWrapper.h
deleted file mode 100644 (file)
index 3ea457f..0000000
+++ /dev/null
@@ -1,35 +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 SecADWrapper_h
-#define SecADWrapper_h
-
-#include <TargetConditionals.h>
-#include <CoreFoundation/CoreFoundation.h>
-
-extern void SecADClearScalarKey(CFStringRef key);
-extern void SecADSetValueForScalarKey(CFStringRef key, int64_t value);
-extern void SecADAddValueForScalarKey(CFStringRef key, int64_t value);
-extern void SecADClientPushValueForDistributionKey(CFStringRef key, int64_t value);
-
-#endif /* SecADWrapper_h */
index 588b9de2a5a2e5821c028c13727602fb607ef371..dc815dfde7a6b4810fcb1ebdfb785a98c82c3050 100644 (file)
@@ -24,6 +24,8 @@
 
 #include <utilities/SecCFCCWrappers.h>
 
+#include <utilities/simulatecrash_assert.h>
+
 CFDataRef CFDataCreateDigestWithBytes(CFAllocatorRef allocator, const struct ccdigest_info *di, size_t len,
                                 const void *data, CFErrorRef *error) {
     CFMutableDataRef digest = CFDataCreateMutable(allocator, di->output_size);
index 39caa712e34c81d2ca24aa38891d01d0a40c1423..fd428b297ca7f96db6d25550f92cb39d08f6a397 100644 (file)
@@ -26,7 +26,8 @@
 #include <utilities/SecCFRelease.h>
 #include <utilities/debugging.h>
 #include <notify.h>
-
+#include "keychain/SecureObjectSync/SOSInternal.h"
+#include <Security/OTConstants.h>
 
 //
 // OSStatus values we magically know
@@ -69,66 +70,26 @@ bool SecCheckErrno(int result, CFErrorRef *error, CFStringRef format, ...) {
     return false;
 }
 
-bool SecPOSIXError(int error, CFErrorRef *cferror, CFStringRef format, ...)
-{
-       if (error == 0) return true;
-       if (error) {
-               va_list args;
-               CFIndex code = error;
-               CFErrorRef previousError = *cferror;
-
-               *cferror = NULL;
-               va_start(args, format);
-               SecCFCreateErrorWithFormatAndArguments(code, kSecErrnoDomain, previousError, cferror, NULL, format, args);
-               va_end(args);
-       }
-       return false;
-}
-
-bool SecCoreCryptoError(int error, CFErrorRef *cferror, CFStringRef format, ...)
-{
-       if (error == 0) return true;
-       if (error) {
-               va_list args;
-               CFIndex code = error;
-               CFErrorRef previousError = *cferror;
-
-               *cferror = NULL;
-               va_start(args, format);
-               SecCFCreateErrorWithFormatAndArguments(code, kSecCoreCryptoDomain, previousError, cferror, NULL, format, args);
-               va_end(args);
-       }
-       return false;
-}
+bool SecError(OSStatus status, CFErrorRef *error, CFStringRef format, ...) {
+    if (status == 0) {
+        return true;
+    }
 
+    CFErrorRef localError = NULL;
+    va_list args;
+    CFIndex code = status;
+    va_start(args, format);
+    SecCFCreateErrorWithFormatAndArguments(code, kSecErrorDomain, error ? *error : NULL, &localError, NULL, format, args);
+    va_end(args);
 
-bool SecNotifyError(uint32_t result, CFErrorRef *error, CFStringRef format, ...) {
-    if (result == NOTIFY_STATUS_OK) return true;
     if (error) {
-        va_list args;
-        CFIndex code = result;
-        CFErrorRef previousError = *error;
-
-        *error = NULL;
-        va_start(args, format);
-        SecCFCreateErrorWithFormatAndArguments(code, kSecNotifyDomain, previousError, error, NULL, format, args);
-        va_end(args);
+        *error = localError; // Existing *error is consumed by SecCFCreateErrorWithFormatAndArguments
+    } else {
+        // This happens a bunch in our codebase, so this log can only really exist in debug builds
+        secdebug("secerror", "Error, but no out-parameter for error: %@", localError);
+        CFReleaseNull(localError);
     }
-    return false;
-}
-
-bool SecError(OSStatus status, CFErrorRef *error, CFStringRef format, ...) {
-    if (status == 0) return true;
-    if (error) {
-        va_list args;
-        CFIndex code = status;
-        CFErrorRef previousError = *error;
 
-        *error = NULL;
-        va_start(args, format);
-        SecCFCreateErrorWithFormatAndArguments(code, kSecErrorDomain, previousError, error, NULL, format, args);
-        va_end(args);
-    }
     return false;
 }
 
@@ -175,6 +136,57 @@ bool SecCFCreateErrorWithFormat(CFIndex errorCode, CFStringRef domain, CFErrorRe
     return result;
 }
 
+static bool SecCFErrorIsEqual(CFIndex errorCode, CFStringRef domain, CFStringRef description, CFErrorRef previousError)
+{
+    bool isEqual = false;
+    bool equalDescriptions = false;
+
+    if (previousError == NULL) {
+        return false;
+    }
+
+    CFDictionaryRef previousUserInfo = CFErrorCopyUserInfo(previousError);
+    CFStringRef previousDescription = CFDictionaryGetValue(previousUserInfo, kCFErrorDescriptionKey);
+    if (previousDescription) {
+        equalDescriptions = CFStringCompare(description, previousDescription, 0) == kCFCompareEqualTo ? true : false;
+    }
+
+    CFReleaseNull(previousUserInfo);
+    bool equalCodes = errorCode == CFErrorGetCode(previousError);
+
+    CFErrorDomain previousDomain = CFErrorGetDomain(previousError);
+    bool equalDomains = CFStringCompare(domain, previousDomain, 0) == kCFCompareEqualTo ? true : false;
+
+    isEqual = equalCodes && equalDomains && equalDescriptions;
+    return isEqual;
+}
+
+#define CAP_LIMIT   200
+static bool SecCFErrorShouldCapNestedError(CFErrorRef previousError, long *newCount)
+{
+    bool shouldCap = false;
+
+    if (previousError) {
+        CFDictionaryRef userInfo = CFErrorCopyUserInfo(previousError);
+        if (userInfo && CFDictionaryContainsKey(userInfo, kSOSCountKey) == true) {
+            CFNumberRef previousCount = CFDictionaryGetValue(userInfo, kSOSCountKey);
+            if (previousCount) {
+                long previousLong = 0;
+                CFNumberGetValue(previousCount, kCFNumberLongType, &previousLong);
+                if (SecErrorIsNestedErrorCappingEnabled() && previousLong >= CAP_LIMIT) {
+                    shouldCap = true;
+                } else {
+                    *newCount = previousLong+1;
+                }
+            }
+        }
+        CFReleaseNull(userInfo);
+    } else {
+        *newCount = 0;
+    }
+    return shouldCap;
+}
+
 // Also consumes whatever newError points to
 bool SecCFCreateErrorWithFormatAndArguments(CFIndex errorCode, CFStringRef domain,
                                             CF_CONSUMED CFErrorRef previousError, CFErrorRef *newError,
@@ -182,35 +194,57 @@ bool SecCFCreateErrorWithFormatAndArguments(CFIndex errorCode, CFStringRef domai
 {
     if (newError && !(*newError)) {
         CFStringRef formattedString = CFStringCreateWithFormatAndArguments(NULL, formatoptions, format, args);
-        
-        const void* keys[2] =   { kCFErrorDescriptionKey,   kCFErrorUnderlyingErrorKey};
-        const void* values[2] = { formattedString,          previousError };
-        const CFIndex numEntriesToUse = (previousError != NULL) ? 2 : 1;
 
-        // Prepare to release whatever we replaced, as long as they didn't tell us to do so via previousError
-        // In a sane world, this function wouldn't have a previousError argument, since it should always release what it's replacing,
-        // but changing all callsites is a huge change
-        CFErrorRef replacing = ((*newError) == previousError) ? NULL : *newError;
+        long newDepthCount = 0;
+        CFNumberRef newCount = NULL;
+
+        if (SecCFErrorIsEqual(errorCode, domain, formattedString, previousError) == true) {
+            secdebug("error_thee_well", "SecCFCreateErrorWithFormatAndArguments previous Error: %@ is equal to the new incoming error: domain: %@, error code: %ld, description: %@", previousError, domain, (long)errorCode, formattedString);
+            *newError = CFRetainSafe(previousError);
+            CFReleaseNull(previousError);
+            CFReleaseNull(formattedString);
+            return false;
+        } else if (SecCFErrorShouldCapNestedError(previousError, &newDepthCount) == true) {
+            secdebug("error_thee_well", "SecCFCreateErrorWithFormatAndArguments reached nested error limit, returning previous error: %@", previousError);
+            *newError = CFRetainSafe(previousError);
+            CFReleaseNull(previousError);
+            CFReleaseNull(formattedString);
+            return false;
+        } else {
+            newCount = CFNumberCreate(kCFAllocatorDefault, kCFNumberLongType, &newDepthCount);
+        }
 
-        *newError = CFErrorCreateWithUserInfoKeysAndValues(kCFAllocatorDefault, domain, errorCode,
-                                                           keys, values, numEntriesToUse);
+        CFMutableDictionaryRef newUserInfo = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
 
-        CFReleaseNull(formattedString);
-        if (previousError)
-            secdebug("error_thee_well", "encapsulated %@ with new error: %@", previousError, *newError);
+        if (previousError) {
+            CFDictionaryAddValue(newUserInfo, kCFErrorUnderlyingErrorKey, previousError);
+        }
+        if (newCount) {
+            CFDictionaryAddValue(newUserInfo, kSOSCountKey, newCount);
+        }
+        if (formattedString) {
+            CFDictionaryAddValue(newUserInfo, kCFErrorDescriptionKey, formattedString);
+        }
+
+        *newError = CFErrorCreate(kCFAllocatorDefault, domain, errorCode, newUserInfo);
 
-        CFReleaseNull(replacing);
+        if (previousError) {
+            secdebug("error_thee_well", "encapsulated %@ with new error: %@", previousError, *newError);
+        }
+        CFReleaseNull(newCount);
+        CFReleaseNull(formattedString);
+        CFReleaseNull(newUserInfo);
         CFReleaseNull(previousError);
     } else {
         if (previousError && newError && (previousError != *newError)) {
             secdebug("error_thee_well", "dropping %@", previousError);
-            CFRelease(previousError);
+            CFReleaseNull(previousError);
         }
     }
 
-    if (newError)
+    if (newError) {
         secdebug("error_thee_well", "SecError: %@", *newError);
-
+    }
 
     return false;
 }
index 3d6121ee59d31f38ca8836a54e112d9b0f669b8e..853e150a58ae469bf0b903aa4485298f778e8ce6 100644 (file)
@@ -47,21 +47,6 @@ bool SecCheckErrno(int result, CFErrorRef *error, CFStringRef format, ...)
 bool SecError(OSStatus status, CFErrorRef *error, CFStringRef format, ...)
    CF_FORMAT_FUNCTION(3, 4);
 
-// Direct checking of POSIX errors.
-bool SecPOSIXError(int error, CFErrorRef *cferror, CFStringRef format, ...)
-    CF_FORMAT_FUNCTION(3, 4);
-
-// CoreCrypto error
-#define kSecCoreCryptoDomain CFSTR("kSecCoreCryptoDomain")
-bool SecCoreCryptoError(int error, CFErrorRef *cferror, CFStringRef format, ...)
-    CF_FORMAT_FUNCTION(3, 4);
-
-// Notification
-#define kSecNotifyDomain CFSTR("kSecNotifyDomain")
-bool SecNotifyError(uint32_t result, CFErrorRef *error, CFStringRef format, ...)
-    CF_FORMAT_FUNCTION(3, 4);
-
-
 // requirement error, typically parameters
 bool SecRequirementError(bool requirement, CFErrorRef *error, CFStringRef format, ...)
     CF_FORMAT_FUNCTION(3, 4);
@@ -95,7 +80,9 @@ static inline bool asArrayOptional(CFTypeRef cfType, CFArrayRef *array, CFErrorR
         if (array) *array = (CFArrayRef)cfType;
         return true;
     }
-    SecError(-50, error, CFSTR("object %@ is not an array"), cfType);
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not an array"), cfType);
+    }
     return false;
 }
 
@@ -104,16 +91,9 @@ static inline bool asDataOptional(CFTypeRef cfType, CFDataRef *data, CFErrorRef
         if (data) *data = (CFDataRef)cfType;
         return true;
     }
-    SecError(-50, error, CFSTR("object %@ is not an data"), cfType);
-    return false;
-}
-
-static inline bool asSetOptional(CFTypeRef cfType, CFSetRef *set, CFErrorRef *error) {
-    if (!cfType || CFGetTypeID(cfType) == CFSetGetTypeID()) {
-        if (set) *set = (CFSetRef)cfType;
-        return true;
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not an data"), cfType);
     }
-    SecError(-50, error, CFSTR("object %@ is not a set"), cfType);
     return false;
 }
 
@@ -121,63 +101,23 @@ static inline bool asSetOptional(CFTypeRef cfType, CFSetRef *set, CFErrorRef *er
 // MARK: Required value type casting
 //
 
-//
-// MARK: Required value type casting
-//
-
-static inline CFArrayRef copyIfArray(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFArrayGetTypeID())
-        return (CFArrayRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not an array"), cfType);
-    return NULL;
-}
-
-static inline CFBooleanRef copyIfBoolean(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID())
-        return (CFBooleanRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not an boolean"), cfType);
-    return NULL;
-}
-
 static inline CFDataRef copyIfData(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDataGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFDataGetTypeID()) {
         return (CFDataRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a data"), cfType);
-    return NULL;
-}
-
-static inline CFDateRef copyIfDate(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDateGetTypeID())
-        return (CFDateRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a date"), cfType);
-    return NULL;
-}
-
-static inline CFDictionaryRef copyIfDictionary(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID())
-        return (CFDictionaryRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a dictionary"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a data"), cfType);
+    }
     return NULL;
 }
 
 static inline CFSetRef copyIfSet(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFSetGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFSetGetTypeID()) {
         return (CFSetRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a set"), cfType);
-    return NULL;
-}
-
-static inline CFStringRef copyIfString(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFStringGetTypeID())
-        return (CFStringRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a string"), cfType);
-    return NULL;
-}
-
-static inline CFUUIDRef copyIfUUID(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFUUIDGetTypeID())
-        return (CFUUIDRef)CFRetainSafe(cfType);
-    SecError(-50, error, CFSTR("object %@ is not a UUID"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a set"), cfType);
+    }
     return NULL;
 }
 
@@ -185,58 +125,72 @@ static inline CFUUIDRef copyIfUUID(CFTypeRef cfType, CFErrorRef *error) {
 // MARK: Analyzer confusing asXxx casting
 //
 static inline CFArrayRef asArray(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFArrayGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFArrayGetTypeID()) {
         return (CFArrayRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not an array"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not an array"), cfType);
+    }
     return NULL;
 }
 
 static inline CFBooleanRef asBoolean(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFBooleanGetTypeID()) {
         return (CFBooleanRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not an boolean"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not an boolean"), cfType);
+    }
     return NULL;
 }
 
 static inline CFDataRef asData(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDataGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFDataGetTypeID()) {
         return (CFDataRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a data"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a data"), cfType);
+    }
     return NULL;
 }
 
 static inline CFDateRef asDate(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDateGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFDateGetTypeID()) {
         return (CFDateRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a date"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a date"), cfType);
+    }
     return NULL;
 }
 
 static inline CFDictionaryRef asDictionary(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFDictionaryGetTypeID()) {
         return (CFDictionaryRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a dictionary"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a dictionary"), cfType);
+    }
     return NULL;
 }
 
 static inline CFSetRef asSet(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFSetGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFSetGetTypeID()) {
         return (CFSetRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a set"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a set"), cfType);
+    }
     return NULL;
 }
 
 static inline CFStringRef asString(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFStringGetTypeID())
+    if (cfType && CFGetTypeID(cfType) == CFStringGetTypeID()) {
         return (CFStringRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a string"), cfType);
-    return NULL;
-}
-
-static inline CFUUIDRef asUUID(CFTypeRef cfType, CFErrorRef *error) {
-    if (cfType && CFGetTypeID(cfType) == CFUUIDGetTypeID())
-        return (CFUUIDRef)cfType;
-    SecError(-50, error, CFSTR("object %@ is not a UUID"), cfType);
+    }
+    if(error) {
+        SecError(-50, error, CFSTR("object %@ is not a string"), cfType);
+    }
     return NULL;
 }
 
index 1cfb109bccf3bcb6761d7085cbc2c2211feb2dd8..979adda6ec5b0a5b850679ecb180356af05623b5 100644 (file)
@@ -34,7 +34,7 @@
 
 #include <IOKit/IOReturn.h>
 
-#include <assert.h>
+#include "utilities/simulatecrash_assert.h"
 #include <dispatch/dispatch.h>
 #include <stdlib.h>
 #include <string.h>
@@ -225,12 +225,12 @@ static inline bool isNull(CFTypeRef cfType) {
 
 // Usage: void foo(CFTypeRef value) { CFDataRef data = CFCast(CFData, value); }
 #define CFCast(type, value)                                               \
-    ((value != NULL) && CFGetTypeID(value) == type ## GetTypeID() ? (type ## Ref)(value) : NULL)
+    ({ __typeof__(value) _v = (value); (_v != NULL) && CFGetTypeID(_v) == type ## GetTypeID() ? (type ## Ref)_v : NULL; })
 
-#define CFCastWithError(type, value, error)                               \
-    ((value != NULL) && CFGetTypeID(value) == type ## GetTypeID() ?       \
-        (type ## Ref)(value) :                                            \
-        (SecError(errSecParam, error, CFSTR("Unexpected type")), NULL))
+#define CFCastWithError(type, value, error)                                                      \
+    ({ __typeof__(value) _v = (value); (_v != NULL) && CFGetTypeID(_v) == type ## GetTypeID() ?  \
+        (type ## Ref)_v :                                                                        \
+        (SecError(errSecParam, error, CFSTR("Unexpected type")), NULL); })
 
 //
 // MARK CFEqual Helpers
@@ -369,7 +369,9 @@ static inline const uint8_t* CFDataGetPastEndPtr(CFDataRef theData) {
     return CFDataGetBytePtr(theData) + CFDataGetLength(theData);
 }
 
-static inline CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right)
+// This function compare DER data object, which take into account the length
+// of the data objects when doing the comparsion which item is "before" or "after"
+static inline CFComparisonResult CFDataCompareDERData(CFDataRef left, CFDataRef right)
 {
     const size_t left_size = CFDataGetLength(left);
     const size_t right_size = CFDataGetLength(right);
@@ -385,6 +387,10 @@ static inline CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right)
         return kCFCompareEqualTo;
 }
 
+static inline __deprecated_msg("please use CFEqual or CFDataCompareDERData") CFComparisonResult CFDataCompare(CFDataRef left, CFDataRef right) {
+    return CFDataCompareDERData(left, right);
+}
+
 static inline CFDataRef CFDataCreateWithHash(CFAllocatorRef allocator, const struct ccdigest_info *di, const uint8_t *buffer, const uint8_t length) {
     CFMutableDataRef result = CFDataCreateMutableWithScratch(allocator, di->output_size);
 
@@ -530,13 +536,13 @@ static inline CFStringRef CFStringCreateTruncatedCopy(CFStringRef s, CFIndex len
 //
 
 static inline
-const void *SecCFRetainForCollection(CFAllocatorRef allocator, const void *value)
+const void *SecCFRetainForCollection(CFAllocatorRef __unused allocator, const void *value)
 {
     return CFRetain(value);
 }
 
 static inline
-void SecCFReleaseForCollection(CFAllocatorRef allocator, const void *value)
+void SecCFReleaseForCollection(CFAllocatorRef __unused allocator, const void *value)
 {
     CFRelease(value);
 }
@@ -1015,7 +1021,8 @@ static inline CFDateRef CFDateCreateForGregorianMoment(CFAllocatorRef allocator,
     return CFDateCreate(allocator, CFAbsoluteTimeForGregorianMoment(tz, year, month, day, hour, minute, second));
 }
 
-static inline CFDateRef CFDateCreateForGregorianDay(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day, int hour, int minute, int second)
+static inline CFDateRef CFDateCreateForGregorianDay(CFAllocatorRef allocator, CFTimeZoneRef tz, int year, int month, int day,
+                                                    int __unused hour, int __unused minute, int __unused second)
 {
     return CFDateCreate(allocator, CFAbsoluteTimeForGregorianDay(tz, year, month, day));
 }
index 244ffd282d77c251e99f7bf1707d50f28a2f686d..2f8dc662b5be6a86be3dc20d0be91594cfd57702 100644 (file)
 * @APPLE_LICENSE_HEADER_END@
 */
 
-#import <Foundation/Foundation.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+void SecCoreAnalyticsSendValue(CFStringRef _Nonnull eventName, int64_t value);
 
 #if __OBJC__
 
+#import <Foundation/Foundation.h>
+
 NS_ASSUME_NONNULL_BEGIN
 
+extern NSString* const SecCoreAnalyticsValue;
+
 @interface SecCoreAnalytics : NSObject
 
 + (void)sendEvent:(NSString*) eventName event:(NSDictionary<NSString*,NSObject*> *)event;
index 3e41cf17d1976459987384fa85cd88479b23dcee..e58cea450fe65a963e31e0146dd5c9390505ffcb 100644 (file)
 #import <SoftLinking/SoftLinking.h>
 #import <Availability.h>
 
+NSString* const SecCoreAnalyticsValue = @"value";
+
+
+void SecCoreAnalyticsSendValue(CFStringRef _Nonnull eventName, int64_t value)
+{
+    [SecCoreAnalytics sendEvent:(__bridge NSString*)eventName
+                          event:@{
+                              SecCoreAnalyticsValue: [NSNumber numberWithLong:value],
+                          }];
+}
+
 @implementation SecCoreAnalytics
 
-SOFT_LINK_FRAMEWORK_SAFE(PrivateFrameworks, CoreAnalytics);
+SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CoreAnalytics);
 
 SOFT_LINK_FUNCTION(CoreAnalytics, AnalyticsSendEvent, soft_AnalyticsSendEvent, \
     void, (NSString* eventName, NSDictionary<NSString*,NSObject*>* eventPayload),(eventName, eventPayload));
index f09ef95f7031915a577446cbe06f8574a049b558..422b871bce829a0d48cc91cd4a25f56e1ae397b9 100644 (file)
@@ -23,6 +23,7 @@
 
 
 #include "SecDb.h"
+#include "SecDbInternal.h"
 #include "debugging.h"
 
 #include <sqlite3.h>
@@ -87,9 +88,13 @@ struct __OpaqueSecDb {
     CFStringRef db_path;
     dispatch_queue_t queue;
     dispatch_queue_t commitQueue;
-    CFMutableArrayRef connections;
-    dispatch_semaphore_t write_semaphore;
-    dispatch_semaphore_t read_semaphore;
+
+    CFMutableArrayRef idleWriteConnections;     // up to kSecDbMaxWriters of them (currently 1, requires locking change for >1)
+    CFMutableArrayRef idleReadConnections;      // up to kSecDbMaxReaders of them
+    pthread_mutex_t writeMutex;
+    // TODO: Replace after we have rdar://problem/60961964
+    dispatch_semaphore_t readSemaphore;
+
     bool didFirstOpen;
     bool (^opened)(SecDbRef db, SecDbConnectionRef dbconn, bool didCreate, bool *callMeAgainForNextConnection, CFErrorRef *error);
     bool callOpenedHandlerForNextConnection;
@@ -200,7 +205,7 @@ static CFStringRef
 SecDbCopyFormatDescription(CFTypeRef value, CFDictionaryRef formatOptions)
 {
     SecDbRef db = (SecDbRef)value;
-    return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDb path:%@ connections: %@>"), db->db_path, db->connections);
+    return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<SecDb path:%@ connections: %@>"), db->db_path, db->idleReadConnections);
 }
 
 
@@ -208,8 +213,13 @@ static void
 SecDbDestroy(CFTypeRef value)
 {
     SecDbRef db = (SecDbRef)value;
-    CFReleaseNull(db->connections);
+
     CFReleaseNull(db->db_path);
+    dispatch_sync(db->queue, ^{
+        CFReleaseNull(db->idleWriteConnections);
+        CFReleaseNull(db->idleReadConnections);
+    });
+
     if (db->queue) {
         dispatch_release(db->queue);
         db->queue = NULL;
@@ -218,14 +228,14 @@ SecDbDestroy(CFTypeRef value)
         dispatch_release(db->commitQueue);
         db->commitQueue = NULL;
     }
-    if (db->read_semaphore) {
-        dispatch_release(db->read_semaphore);
-        db->read_semaphore = NULL;
-    }
-    if (db->write_semaphore) {
-        dispatch_release(db->write_semaphore);
-        db->write_semaphore = NULL;
+
+    pthread_mutex_destroy(&(db->writeMutex));
+
+    if (db->readSemaphore) {
+        dispatch_release(db->readSemaphore);
+        db->readSemaphore = NULL;
     }
+
     if (db->opened) {
         Block_release(db->opened);
         db->opened = NULL;
@@ -252,9 +262,12 @@ SecDbCreate(CFStringRef dbName, mode_t mode, bool readWrite, bool allowRepair, b
         db->commitQueue = dispatch_queue_create(cqNameStr, DISPATCH_QUEUE_CONCURRENT);
     });
     CFReleaseNull(commitQueueStr);
-    db->read_semaphore = dispatch_semaphore_create(kSecDbMaxReaders);
-    db->write_semaphore = dispatch_semaphore_create(kSecDbMaxWriters);
-    db->connections = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
+    db->readSemaphore = dispatch_semaphore_create(kSecDbMaxReaders);
+    if (pthread_mutex_init(&(db->writeMutex), NULL) != 0) {
+        seccritical("SecDb: SecDbCreate failed to init the write mutex, this will end badly");
+    }
+    db->idleWriteConnections = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
+    db->idleReadConnections = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
     db->opened = opened ? Block_copy(opened) : NULL;
     if (getenv("__OSINSTALL_ENVIRONMENT") != NULL) {
         // TODO: Move this code out of this layer
@@ -280,13 +293,15 @@ CFIndex
 SecDbIdleConnectionCount(SecDbRef db) {
     __block CFIndex count = 0;
     dispatch_sync(db->queue, ^{
-        count = CFArrayGetCount(db->connections);
+        count = CFArrayGetCount(db->idleReadConnections);
+        count += CFArrayGetCount(db->idleWriteConnections);
     });
     return count;
 }
 
 void SecDbAddNotifyPhaseBlock(SecDbRef db, SecDBNotifyBlock notifyPhase)
 {
+#if !TARGET_OS_BRIDGE
     // SecDbNotifyPhase seems to mostly be called on the db's commitQueue, and not the db's queue. Therefore, protect the array with that queue.
     dispatch_sync(db->commitQueue, ^{
         SecDBNotifyBlock block = Block_copy(notifyPhase); /* Force the block off the stack */
@@ -296,9 +311,11 @@ void SecDbAddNotifyPhaseBlock(SecDbRef db, SecDBNotifyBlock notifyPhase)
         CFArrayAppendValue(db->notifyPhase, block);
         Block_release(block);
     });
+#endif
 }
 
 static void SecDbNotifyPhase(SecDbConnectionRef dbconn, SecDbTransactionPhase phase) {
+#if !TARGET_OS_BRIDGE
     if (CFArrayGetCount(dbconn->changes)) {
         CFArrayRef changes = dbconn->changes;
         dbconn->changes = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
@@ -310,6 +327,7 @@ static void SecDbNotifyPhase(SecDbConnectionRef dbconn, SecDbTransactionPhase ph
         }
         CFReleaseSafe(changes);
     }
+#endif
 }
 
 static void SecDbOnNotify(SecDbConnectionRef dbconn, void (^perform)(void)) {
@@ -784,10 +802,6 @@ bool SecDbCheckpoint(SecDbConnectionRef dbconn, CFErrorRef *error)
     return SecDbConnectionCheckCode(dbconn, sqlite3_wal_checkpoint(dbconn->handle, NULL), error, CFSTR("wal_checkpoint"));
 }
 
-static bool SecDbFileControl(SecDbConnectionRef dbconn, int op, void *arg, CFErrorRef *error) {
-    return SecDbConnectionCheckCode(dbconn, sqlite3_file_control(dbconn->handle, NULL, op, arg), error, CFSTR("file_control"));
-}
-
 static sqlite3 *_SecDbOpenV2(const char *path,
                              int flags,
                              int useWAL,
@@ -986,19 +1000,24 @@ SecDbProfileMask(void)
 static int
 SecDbTraceV2(unsigned mask, void *ctx, void *p, void *x) {
     SecDbConnectionRef dbconn __unused = ctx;
+
+#if SECDB_DEBUGGING
     const char *trace = "unknown";
+    char *tofree = NULL;
 
     if (mask == SQLITE_TRACE_PROFILE)
         trace = sqlite3_sql(p);
     else if (mask == SQLITE_TRACE_STMT) {
         trace = sqlite3_sql(p);
     } else if (mask == SQLITE_TRACE_ROW) {
-        trace = sqlite3_expanded_sql(p);
+        trace = tofree = sqlite3_expanded_sql(p);
     }
 
-#if SECDB_DEBUGGING
     secinfo("#SecDB", "#SecDB %{public}s", trace);
+
+    sqlite3_free(tofree);
 #endif
+
     return 0;
 }
 
@@ -1089,21 +1108,36 @@ static void SecDbConectionSetReadOnly(SecDbConnectionRef dbconn, bool readOnly)
     dbconn->readOnly = readOnly;
 }
 
-/* Read only connections go to the end of the queue, writeable connections
- go to the start of the queue. */
 SecDbConnectionRef SecDbConnectionAcquire(SecDbRef db, bool readOnly, CFErrorRef *error) {
     SecDbConnectionRef dbconn = NULL;
     SecDbConnectionAcquireRefMigrationSafe(db, readOnly, &dbconn, error);
     return dbconn;
 }
 
+static void SecDbConnectionConsumeResource(SecDbRef db, bool readOnly) {
+    if (readOnly) {
+        dispatch_semaphore_wait(db->readSemaphore, DISPATCH_TIME_FOREVER);
+    } else {
+        pthread_mutex_lock(&(db->writeMutex));
+    }
+}
+
+static void SecDbConnectionMakeResourceAvailable(SecDbRef db, bool readOnly) {
+    if (readOnly) {
+        dispatch_semaphore_signal(db->readSemaphore);
+    } else {
+        pthread_mutex_unlock(&(db->writeMutex));
+    }
+}
+
 bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbConnectionRef* dbconnRef, CFErrorRef *error)
 {
     CFRetain(db);
 #if SECDB_DEBUGGING
     secinfo("dbconn", "acquire %s connection", readOnly ? "ro" : "rw");
 #endif
-    dispatch_semaphore_wait(readOnly ? db->read_semaphore : db->write_semaphore, DISPATCH_TIME_FOREVER);
+    SecDbConnectionConsumeResource(db, readOnly);
+
     __block SecDbConnectionRef dbconn = NULL;
     __block bool ok = true;
     __block bool ranOpenedHandler = false;
@@ -1140,29 +1174,23 @@ bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbCon
             if (ok) {
                 db->didFirstOpen = ok = SecDbDidCreateFirstConnection(dbconn, didCreate, error);
                 ranOpenedHandler = true;
-            }
-            if (!ok)
+                SecDbConectionSetReadOnly(dbconn, readOnly);    // first connection always created "rw", so set to real value
+            } else {
                 CFReleaseNull(dbconn);
+            }
         } else {
             /* Try to get one from the cache */
-            CFIndex count = CFArrayGetCount(db->connections);
-            while (count && !dbconn) {
-                CFIndex ix = readOnly ? count - 1 : 0;
-                if (assignDbConn((SecDbConnectionRef)CFArrayGetValueAtIndex(db->connections, ix)))
+            CFMutableArrayRef cache = readOnly ? db->idleReadConnections : db->idleWriteConnections;
+            if (CFArrayGetCount(cache) && !dbconn) {
+                if (assignDbConn((SecDbConnectionRef)CFArrayGetValueAtIndex(cache, 0))) {
                     CFRetainSafe(dbconn);
-                else
-                    secerror("got NULL dbconn at index: %" PRIdCFIndex " skipping", ix);
-                CFArrayRemoveValueAtIndex(db->connections, ix);
+                }
+                CFArrayRemoveValueAtIndex(cache, 0);
             }
         }
     });
 
-    if (dbconn) {
-        /* Make sure the connection we found has the right access */
-        if (SecDbConnectionIsReadOnly(dbconn) != readOnly) {
-            SecDbConectionSetReadOnly(dbconn, readOnly);
-        }
-    } else if (ok) {
+    if (ok && !dbconn) {
         /* Nothing found in cache, create a new connection */
         bool created = false;
         if (assignDbConn(SecDbConnectionCreate(db, readOnly, error)) && !SecDbOpenHandle(dbconn, &created, error)) {
@@ -1170,7 +1198,6 @@ bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbCon
         }
     }
 
-
     if (dbconn && !ranOpenedHandler && dbconn->db->opened) {
         dispatch_sync(db->queue, ^{
             if (dbconn->db->callOpenedHandlerForNextConnection) {
@@ -1189,8 +1216,8 @@ bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbCon
     }
 
     if (!dbconn) {
-        // If acquire fails we need to signal the semaphore again.
-        dispatch_semaphore_signal(readOnly ? db->read_semaphore : db->write_semaphore);
+        // Caller doesn't get (to use) a connection so the backing synchronization primitive is available again
+        SecDbConnectionMakeResourceAvailable(db, readOnly);
         CFRelease(db);
     }
 
@@ -1199,33 +1226,38 @@ bool SecDbConnectionAcquireRefMigrationSafe(SecDbRef db, bool readOnly, SecDbCon
 
 void SecDbConnectionRelease(SecDbConnectionRef dbconn) {
     if (!dbconn) {
-        secerror("called with NULL dbconn");
+        secerror("SecDbConnectionRelease called with NULL dbconn");
         return;
     }
     SecDbRef db = dbconn->db;
 #if SECDB_DEBUGGING
     secinfo("dbconn", "release %@", dbconn);
 #endif
+
+    bool readOnly = SecDbConnectionIsReadOnly(dbconn);
     dispatch_sync(db->queue, ^{
-        bool readOnly = SecDbConnectionIsReadOnly(dbconn);
         if (dbconn->hasIOFailure) {
             // Something wrong on the file layer (e.g. revoked file descriptor for networked home)
-            // so we don't trust our existing connections anymore.
-            CFArrayRemoveAllValues(db->connections);
+            secwarning("SecDbConnectionRelease: IO failure reported in connection, throwing away currently idle caches");
+            // Any other checked-out connections are beyond our grasp. If they did not have IO failures they'll come back,
+            // otherwise this branch gets taken more than once and gradually those connections die off
+            CFArrayRemoveAllValues(db->idleWriteConnections);
+            CFArrayRemoveAllValues(db->idleReadConnections);
         } else {
-            CFIndex count = CFArrayGetCount(db->connections);
-            // Add back possible writable dbconn to the pool.
-            CFArrayInsertValueAtIndex(db->connections, readOnly ? count : 0, dbconn);
-            // Remove the last (probably read-only) dbconn from the pool.
-            if (count >= db->maxIdleHandles) {
-                CFArrayRemoveValueAtIndex(db->connections, count);
+            CFMutableArrayRef cache = readOnly ? db->idleReadConnections : db->idleWriteConnections;
+            CFIndex count = CFArrayGetCount(cache);
+            if ((unsigned long)count < (readOnly ? kSecDbMaxReaders : kSecDbMaxWriters)) {
+                CFArrayAppendValue(cache, dbconn);
+            } else {
+                secerror("dbconn: did not expect to run out of room in the %s cache when releasing connection", readOnly ? "ro" : "rw");
             }
         }
-        // Signal after we have put the connection back in the pool of connections
-        dispatch_semaphore_signal(readOnly ? db->read_semaphore : db->write_semaphore);
-        CFRelease(dbconn);
-        CFRelease(db);
     });
+
+    // Signal after we have put the connection back in the pool of connections
+    SecDbConnectionMakeResourceAvailable(db, readOnly);
+    CFRelease(dbconn);
+    CFRelease(db);
 }
 
 void SecDbReleaseAllConnections(SecDbRef db) {
@@ -1235,29 +1267,31 @@ void SecDbReleaseAllConnections(SecDbRef db) {
         return;
     }
     dispatch_sync(db->queue, ^{
-        CFArrayRemoveAllValues(db->connections);
-        dispatch_semaphore_signal(db->write_semaphore);
-        dispatch_semaphore_signal(db->read_semaphore);
+        CFArrayRemoveAllValues(db->idleReadConnections);
+        CFArrayRemoveAllValues(db->idleWriteConnections);
+    });
+}
+
+static void onQueueSecDbForceCloseForCache(CFMutableArrayRef cache) {
+    CFArrayForEach(cache, ^(const void* ptr) {
+        SecDbConnectionRef connection = (SecDbConnectionRef)ptr;
+
+        // this pointer is claimed to be nonretained
+        connection->db = NULL;
+
+        if(connection->handle) {
+            sqlite3_close(connection->handle);
+            connection->handle = NULL;
+        }
     });
+    CFArrayRemoveAllValues(cache);
 }
 
 // Please make sure you want to do this. Any use of the outstanding connections to this DB will cause a crash.
 void SecDbForceClose(SecDbRef db) {
     dispatch_sync(db->queue, ^{
-        CFArrayForEach(db->connections, ^(const void* p) {
-            SecDbConnectionRef connection = (SecDbConnectionRef)p;
-
-            // this pointer is claimed to be nonretained
-            connection->db = NULL;
-
-            if(connection->handle) {
-                sqlite3_close(connection->handle);
-                connection->handle = NULL;
-            }
-        });
-        CFArrayRemoveAllValues(db->connections);
-        dispatch_semaphore_signal(db->write_semaphore);
-        dispatch_semaphore_signal(db->read_semaphore);
+        onQueueSecDbForceCloseForCache(db->idleReadConnections);
+        onQueueSecDbForceCloseForCache(db->idleWriteConnections);
     });
 }
 
index 06ea04e4fea3ae8a5a0fe1edbab82c29483c4802..9316e3e889f6977c9358b1fbc091796303ed71ad 100644 (file)
@@ -36,14 +36,6 @@ typedef struct __OpaqueSecDbConnection *SecDbConnectionRef;
 typedef struct __OpaqueSecDbStatement *SecDbStatementRef;
 struct SOSDigestVector;
 
-// MARK: Configuration values, not used by clients directly.
-// TODO: Move this section to a private header
-enum {
-    kSecDbMaxReaders = 4,
-    kSecDbMaxWriters = 1,
-    kSecDbMaxIdleHandles = 3,
-};
-
 // MARK: SecDbTransactionType
 enum {
     kSecDbNoneTransactionType = 0,
diff --git a/OSX/utilities/SecDbInternal.h b/OSX/utilities/SecDbInternal.h
new file mode 100644 (file)
index 0000000..15a5ef2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SecDbInternal_h
+#define SecDbInternal_h
+
+#include "SecDb.h"
+
+static const size_t kSecDbMaxReaders = 5;
+
+// Do not increase this without changing lock types in SecDb
+static const size_t kSecDbMaxWriters = 1;
+
+// maxreaders + maxwriters
+static const size_t kSecDbMaxIdleHandles = 6;
+
+#endif /* SecDbInternal_h */
index ffe3923b7bed28abe8f75ad0a95059fe3cc7c580..3606eef82652bd3c135b8d203feb571340c30a02 100644 (file)
@@ -262,7 +262,16 @@ CFURLRef SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName)
 
 CFURLRef SecCopyURLForFileInRevocationInfoDirectory(CFStringRef fileName)
 {
+#if TARGET_OS_OSX
+    return SecCopyURLForFileInBaseDirectory(true, CFSTR("private/var/protected/trustd/"), fileName);
+#else
     return SecCopyURLForFileInBaseDirectory(true, CFSTR("Library/Keychains/crls/"), fileName);
+#endif
+}
+
+CFURLRef SecCopyURLForFileInProtectedDirectory(CFStringRef fileName)
+{
+    return SecCopyURLForFileInBaseDirectory(true, CFSTR("private/var/protected/"), fileName);
 }
 
 static void WithPathInDirectory(CFURLRef fileURL, void(^operation)(const char *utf8String))
@@ -292,6 +301,11 @@ void WithPathInUserCacheDirectory(CFStringRef fileName, void(^operation)(const c
     WithPathInDirectory(SecCopyURLForFileInUserCacheDirectory(fileName), operation);
 }
 
+void WithPathInProtectedDirectory(CFStringRef fileName, void(^operation)(const char *utf8String))
+{
+    WithPathInDirectory(SecCopyURLForFileInProtectedDirectory(fileName), operation);
+}
+
 void SetCustomHomeURL(CFURLRef url)
 {
     sCustomHomeURL = CFRetainSafe(url);
index 09dcd233747e9e480d585e4306e28eb330f26c47..dc59d9f2136b8011029d452720c2e0eca1668eca 100644 (file)
@@ -40,10 +40,12 @@ CFURLRef SecCopyURLForFileInUserCacheDirectory(CFStringRef fileName) CF_RETURNS_
 CFURLRef SecCopyURLForFileInPreferencesDirectory(CFStringRef fileName) CF_RETURNS_RETAINED;
 CFURLRef SecCopyURLForFileInManagedPreferencesDirectory(CFStringRef fileName) CF_RETURNS_RETAINED;
 CFURLRef SecCopyURLForFileInRevocationInfoDirectory(CFStringRef fileName) CF_RETURNS_RETAINED;
+CFURLRef SecCopyURLForFileInProtectedDirectory(CFStringRef fileName) CF_RETURNS_RETAINED;
 
 void WithPathInKeychainDirectory(CFStringRef fileName, void(^operation)(const char *utf8String));
 void WithPathInRevocationInfoDirectory(CFStringRef fileName, void(^operation)(const char *utf8String));
 void WithPathInUserCacheDirectory(CFStringRef fileName, void(^operation)(const char *utf8String));
+void WithPathInProtectedDirectory(CFStringRef fileName, void(^operation)(const char *utf8String));
 
 void SetCustomHomePath(const char* path);
 void SetCustomHomeURLString(CFStringRef path);
index 47e9266f562976e869af9fdb09c5eadc9af268d5..83b6f6b8984e8be542eeadb18102a3aac7a61eaf 100644 (file)
@@ -56,7 +56,7 @@ CFErrorRef SecCreateCFErrorWithXPCObject(xpc_object_t xpc_error)
         const uint8_t *der = xpc_dictionary_get_data(xpc_error, kUserInfoKey, &size);
         if (der) {
             const uint8_t *der_end = der + size;
-            der = der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable,
+            der = der_decode_plist(kCFAllocatorDefault,
                                    &user_info, NULL, der, der_end);
             if (der != der_end)
                 CFReleaseNull(user_info);
index 4b926795a624cf347bf11f72ae11af1fbf769598..019b49a1915a6f38668cb2743431a6f893b88bd6 100644 (file)
@@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN
  * Some NSError objects contain non-NSSecureCoding-compliant userInfo.
  * When in doubt, use cleanseErrorForXPC: before encodedDataFromError:
  */
-+ (NSError *)errorFromEncodedData:(NSData *)data;
++ (NSError * _Nullable)errorFromEncodedData:(NSData *)data;
 + (NSData *)encodedDataFromError:(NSError *)error;
 @end
 
index 5980d1822292de9948dc21c7d0ae52e176da2d5e..73e3cf329427f68be450e2b1bd49f9a043443128 100644 (file)
     return errorClasses;
 }
 
++ (NSSet<Class> *)safeCKErrorPrimitiveClasses
+{
+    static NSMutableSet<Class> *errorClasses = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        errorClasses = [NSMutableSet set];
+        char *classes[] = {
+            "CKArchivedAnchoredPackage",
+            "CKAsset",
+            "CKPackage",
+            "CKRecordID",
+            "CKReference",
+            "CLLocation",
+        };
+
+        for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
+            Class class = objc_getClass(classes[n]);
+            if (class) {
+                [errorClasses addObject:class];
+            }
+        }
+    });
+
+    return errorClasses;
+}
+
 + (NSSet<Class> *)safeErrorCollectionClasses
 {
     static NSMutableSet<Class> *errorClasses = nil;
@@ -47,6 +73,7 @@
             "NSError",
             "NSOrderedSet",
             "NSSet",
+            "NSURLError",
         };
 
         for (unsigned n = 0; n < sizeof(classes) / sizeof(classes[0]); n++) {
@@ -69,6 +96,9 @@
         for (Class class in [SecXPCHelper safeErrorPrimitiveClasses]) {
             [errorClasses addObject:class];
         }
+        for (Class class in [SecXPCHelper safeCKErrorPrimitiveClasses]) {
+            [errorClasses addObject:class];
+        }
         for (Class class in [SecXPCHelper safeErrorCollectionClasses]) {
             [errorClasses addObject:class];
         }
 
 static NSString *kArchiveKeyError = @"error";
 
-+ (NSError *)errorFromEncodedData:(NSData *)data
++ (NSError * _Nullable)errorFromEncodedData:(NSData *)data
 {
     NSKeyedUnarchiver *unarchiver = nil;
     NSError *error = nil;
index 14695726caae41d80f63d60ed316f2f6321e366d..b0bd2ce1299159ef7cbdfb1e2005d5543461c2fd 100644 (file)
@@ -215,13 +215,6 @@ static int string_to_log_level(CFStringRef string) {
         return -1;
 }
 
-static void CFSetAppendValues(CFSetRef set, CFMutableArrayRef appendTo)
-{
-    CFSetForEach(set, ^(const void *value) {
-        CFArrayAppendValue(appendTo, value);
-    });
-}
-
 static CFMutableArrayRef CFSetOfCFObjectsCopyValues(CFSetRef setOfCFs)
 {
     CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
@@ -401,18 +394,6 @@ void __security_debug_init(void) {
 }
 
 
-
-
-static char *copyScopeStr(CFStringRef scope, char *alternative) {
-    char *scopeStr = NULL;
-    if(scope) {
-        scopeStr = CFStringToCString(scope);
-    } else {
-        scopeStr = strdup("noScope");
-    }
-    return scopeStr;
-}
-
 os_log_t
 secLogObjForCFScope(CFStringRef scope)
 {
index 52769f1909b6018a0a2791849e5b764c32fcf7eb..caa2b9c22dea5cda406491783977b7dda435a0cb 100644 (file)
@@ -144,6 +144,9 @@ void __security_stackshotreport(CFStringRef reason, uint32_t code);
 #define __sec_exception_code_SQLiteBusy             __sec_exception_code(10)
 #define __sec_exception_code_CorruptDb(rc)          __sec_exception_code(11|((rc)<<8))
 #define __sec_exception_code_Watchdog               __sec_exception_code(12)
+#define __sec_exception_code_BadStash               __sec_exception_code(13)
+#define __sec_exception_code_UnexpectedState        __sec_exception_code(14)
+#define __sec_exception_code_RateLimit              __sec_exception_code(15)
 
 /* For testing only, turns off/on simulated crashes, when turning on, returns number of
    simulated crashes which were not reported since last turned off. */
index 95eaf95e5c40ab0271a51f15e81438e7fc9a6d43..77885476f6b3d90b346dbfdbea5cd516f7f205aa 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_array(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_array(CFAllocatorRef allocator,
                                 CFArrayRef* array, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     CFMutableArrayRef result = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
 
     const uint8_t *elements_end;
     const uint8_t *current_element = ccder_decode_sequence_tl(&elements_end, der, der_end);
+    if (!current_element) {
+        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("tag/length decode failed"), NULL, error);
+    }
     
     while (current_element != NULL && current_element < elements_end) {
         CFPropertyListRef element = NULL;
-        current_element = der_decode_plist(allocator, mutability, &element, error, current_element, elements_end);
+        current_element = der_decode_plist(allocator, &element, error, current_element, elements_end);
         if (current_element) {
             CFArrayAppendValue(result, element);
             CFReleaseNull(element);
@@ -86,6 +91,7 @@ uint8_t* der_encode_array(CFArrayRef array, CFErrorRef *error,
     {
         der_end = der_encode_plist(CFArrayGetValueAtIndex(array, position), error, der, der_end);
     }
-    
-    return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, der_end);
+
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, original_der_end, der, der_end),
+                                      error);
 }
index 986c3132931c930e1405dfd5bd67956e9473f83d..0ab42b49ebc715d0bb6264275264da3c754a4046 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_boolean(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_boolean(CFAllocatorRef allocator,
                                   CFBooleanRef* boolean, CFErrorRef *error,
                                   const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     size_t payload_size = 0;
     const uint8_t *payload = ccder_decode_tl(CCDER_BOOLEAN, &payload_size, der, der_end);
@@ -64,7 +66,8 @@ uint8_t* der_encode_boolean(CFBooleanRef boolean, CFErrorRef *error,
 {
     uint8_t value = CFBooleanGetValue(boolean);
 
-    return ccder_encode_tl(CCDER_BOOLEAN, 1, der,
-           ccder_encode_body(1, &value, der, der_end));
+    return SecCCDEREncodeHandleResult(ccder_encode_tl(CCDER_BOOLEAN, 1, der,
+                                                      ccder_encode_body(1, &value, der, der_end)),
+                                      error);
 
 }
index b29ddfe0ba23881e13425cf0afb8057f275340b5..83bdcec6c0919bfbf7e784312f803cb7c7cf65ee 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_data_mutable(CFAllocatorRef allocator, CFOptionFlags mutability,
-                                       CFMutableDataRef* data, CFErrorRef *error,
-                                       const uint8_t* der, const uint8_t *der_end)
-{
-    if (NULL == der)
-        return NULL;
-
-    size_t payload_size = 0;
-    const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end);
-
-    if (NULL == payload || (ssize_t) (der_end - payload) < (ssize_t) payload_size) {
-        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Unknown data encoding"), NULL, error);
-        return NULL;
-    }
-
-    *data = CFDataCreateMutable(allocator, 0);
-
-    if (NULL == *data) {
-        SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Failed to create data"), NULL, error);
-        return NULL;
-    }
-
-    CFDataAppendBytes(*data, payload, payload_size);
-
-    return payload + payload_size;
-}
-
-
-const uint8_t* der_decode_data(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_data(CFAllocatorRef allocator,
                                CFDataRef* data, CFErrorRef *error,
                                const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     size_t payload_size = 0;
     const uint8_t *payload = ccder_decode_tl(CCDER_OCTET_STRING, &payload_size, der, der_end);
@@ -97,7 +71,8 @@ uint8_t* der_encode_data(CFDataRef data, CFErrorRef *error,
 {
     const CFIndex data_length = CFDataGetLength(data);
 
-    return ccder_encode_tl(CCDER_OCTET_STRING, data_length, der,
-           ccder_encode_body(data_length, CFDataGetBytePtr(data), der, der_end));
+    return SecCCDEREncodeHandleResult(ccder_encode_tl(CCDER_OCTET_STRING, data_length, der,
+                                                      ccder_encode_body(data_length, CFDataGetBytePtr(data), der, der_end)),
+                                      error);
 
 }
index 0bdde9cca2efc685b79fd2e9824c9f74bb2577cc..d930f660ad26e2dcfd622cd563f913943c79909c 100644 (file)
 /* Cumulative number of days in the year for months up to month i.  */
 static int mdays[13] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
 
+static bool validateDateComponents(int year, int month, int day, int hour, int minute, int second, int *is_leap_year, CFErrorRef* error)
+{
+    int leapyear = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) ? 1 : 0;
+    if (is_leap_year) {
+        *is_leap_year = leapyear;
+    }
+    if (month < 1 || month > 12 || day < 1 || day > 31 || hour >= 24 || minute >= 60 || second > 61
+        || (month == 2 && day > mdays[month] - mdays[month - 1] + leapyear)
+        || (month != 2 && day > mdays[month] - mdays[month - 1]))
+    {
+        SecError(kSecDERErrorUnknownEncoding, error, CFSTR("Invalid date: %i, %i, %i, %i, %i, %i, %i"), year, month, day, hour, minute, second, leapyear);
+        return false;
+    }
+
+    return true;
+}
+
 static CFAbsoluteTime SecGregorianDateGetAbsoluteTime(int year, int month, int day, int hour, int minute, int second, CFTimeInterval timeZoneOffset, CFErrorRef *error) {
-    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 >= 24 || minute >= 60 || second >= 60.0
-        || (month == 2 && day > mdays[month] - mdays[month - 1] + is_leap_year)
-        || (month != 2 && day > mdays[month] - mdays[month - 1])) {
-        /* Invalid date. */
-        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Invalid date."), 0, error);
+    int is_leap_year = 0;
+    if (!validateDateComponents(year, month, day, hour, minute, second, &is_leap_year, error)) {
         return NULL_TIME;
     }
 
@@ -72,8 +85,10 @@ static bool SecAbsoluteTimeGetGregorianDate(CFTimeInterval at, int *year, int *m
     SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar) {
         result = CFCalendarDecomposeAbsoluteTime(zuluCalendar, at, "yMdHms", year, month, day, hour, minute, second);
     });
-    if (!result)
+    if (!result) {
         SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("Failed to encode date."), 0, error);
+    }
+
     return result;
 }
 
@@ -144,9 +159,11 @@ static const uint8_t *der_decode_decimal_fraction(double *fraction, CFErrorRef *
                 value += (ch - '0');
             }
         }
-        if (der >= der_end)
+        if (der >= der_end) {
+            SecCFDERCreateError(kSecDERErrorOverflow,
+                                CFSTR("overflow"), 0, error);
             der = NULL;
-        else if (last == '0') {
+        else if (last == '0') {
             SecCFDERCreateError(kSecDERErrorUnknownEncoding,
                                 CFSTR("fraction ends in 0"), 0, error);
             der = NULL;
@@ -205,14 +222,6 @@ static const uint8_t* der_decode_commontime_body(CFAbsoluteTime *at, CFErrorRef
 
        CFTimeInterval timeZoneOffset = der_decode_timezone_offset(&der, der_end, error);
 
-#if 0
-    secinfo("dateparse",
-             "date %.*s year: %04d%02d%02d%02d%02d%02d%+05g",
-             length, bytes, g.year, g.month,
-             g.day, g.hour, g.minute, g.second,
-             timeZoneOffset / 60);
-#endif
-
     if (der) {
         if (der != der_end) {
             SecCFDERCreateError(kSecDERErrorUnknownEncoding,
@@ -257,12 +266,14 @@ const uint8_t* der_decode_universaltime_body(CFAbsoluteTime *at, CFErrorRef *err
     return der_decode_commontime_body(at, error, year, der, der_end);
 }
 
-const uint8_t* der_decode_date(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_date(CFAllocatorRef allocator,
                                CFDateRef* date, CFErrorRef *error,
                                const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     der = ccder_decode_constructed_tl(CCDER_GENERALIZED_TIME, &der_end, der, der_end);
     CFAbsoluteTime at = 0;
@@ -373,13 +384,38 @@ static uint8_t *ccder_encode_nanoseconds(CFAbsoluteTime at, const uint8_t *der,
     return der_end;
 }
 
-/* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
 uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
                                          const uint8_t *der, uint8_t *der_end)
+{
+    return der_encode_generalizedtime_body_repair(at, error, false, der, der_end);
+}
+
+/* Encode generalized zulu time YYYYMMDDhhmmss[.ssss]Z */
+uint8_t* der_encode_generalizedtime_body_repair(CFAbsoluteTime at, CFErrorRef *error, bool repair,
+                                         const uint8_t *der, uint8_t *der_end)
 {
     int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
-    if (!SecAbsoluteTimeGetGregorianDate(at, &year, &month, &day, &hour, &minute, &second, error))
+    if (!SecAbsoluteTimeGetGregorianDate(at, &year, &month, &day, &hour, &minute, &second, error)) {
+        secerror("der: unable to encode date: %@", error ? *error : NULL);
         return NULL;
+    }
+
+    // Without repair flag, do not let validation change result so we do not change existing behavior
+    CFErrorRef localError = NULL;
+    if (!validateDateComponents(year, month, day, hour, minute, second, 0, &localError)) {
+        CFStringRef desc = CFErrorCopyDescription(localError);
+        __security_simulatecrash(desc, __sec_exception_code_CorruptItem);
+        CFReleaseNull(desc);
+        secerror("der: invalid date: %@; %s", localError, repair ? "setting default value" : "continuing");
+        CFReleaseNull(localError);
+        if (repair) {
+            year = 2001;
+            month = 1;
+            day = 1;
+            // I don't think this is required but I don't want any funny business with exactly midnight in any timezone
+            minute = 1;
+        }
+    }
 
     uint8_t * result = ccder_encode_decimal_quad(year, der,
            ccder_encode_decimal_pair(month, der,
@@ -387,17 +423,18 @@ uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
            ccder_encode_decimal_pair(hour, der,
            ccder_encode_decimal_pair(minute, der,
            ccder_encode_decimal_pair(second, der,
-           ccder_encode_nanoseconds(at, der,
+           ccder_encode_nanoseconds(at, der,    // Uses original "at" even after repair because DER length calculations depend on its exact value
            ccder_encode_byte('Z', der, der_end))))))));
 
-    return result;
+    return SecCCDEREncodeHandleResult(result, error);
 }
 
 uint8_t* der_encode_generalizedtime(CFAbsoluteTime at, CFErrorRef *error,
                                     const uint8_t *der, uint8_t *der_end)
 {
-    return ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME, der_end, der,
-           der_encode_generalizedtime_body(at, error, der, der_end));
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME, der_end, der,
+                                                                  der_encode_generalizedtime_body(at, error, der, der_end)),
+                                      error);
 }
 
 
@@ -407,3 +444,11 @@ uint8_t* der_encode_date(CFDateRef date, CFErrorRef *error,
     return der_encode_generalizedtime(CFDateGetAbsoluteTime(date), error,
                                       der, der_end);
 }
+
+uint8_t* der_encode_date_repair(CFDateRef date, CFErrorRef *error,
+                                bool repair, const uint8_t *der, uint8_t *der_end)
+{
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_GENERALIZED_TIME, der_end, der,
+                                                                  der_encode_generalizedtime_body_repair(CFDateGetAbsoluteTime(date), error, repair, der, der_end)),
+                                      error);
+}
index 327ea7de993dfc5bf598e5e84fa674f0ba84321f..a92871b626e4cfd2911ba474d30efede785ececf 100644 (file)
@@ -39,5 +39,7 @@ uint8_t* der_encode_generalizedtime(CFAbsoluteTime at, CFErrorRef *error,
 size_t der_sizeof_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error);
 uint8_t* der_encode_generalizedtime_body(CFAbsoluteTime at, CFErrorRef *error,
                                          const uint8_t *der, uint8_t *der_end);
+uint8_t* der_encode_generalizedtime_body_repair(CFAbsoluteTime at, CFErrorRef *error, bool repair,
+                                                const uint8_t *der, uint8_t *der_end);
 
 #endif /* _UTILITIES_DER_DATE_H_ */
index bb00295380e7c52460509735f47ccfc5254661fb..6c080d0390920d0e81376124cff30cfc2e7f9d9c 100644 (file)
@@ -32,7 +32,7 @@
 #include <corecrypto/ccder.h>
 #include <CoreFoundation/CoreFoundation.h>
 
-static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_key_value(CFAllocatorRef allocator,
                                            CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
                                            const uint8_t* der, const uint8_t *der_end)
 {
@@ -48,8 +48,8 @@ static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, CFOptionFla
     CFTypeRef valueObject = NULL;
     
     
-    payload = der_decode_plist(allocator, mutability, &keyObject, error, payload, payload_end);
-    payload = der_decode_plist(allocator, mutability, &valueObject, error, payload, payload_end);
+    payload = der_decode_plist(allocator, &keyObject, error, payload, payload_end);
+    payload = der_decode_plist(allocator, &valueObject, error, payload, payload_end);
 
     if (payload != NULL) {
         *key = keyObject;
@@ -61,12 +61,14 @@ static const uint8_t* der_decode_key_value(CFAllocatorRef allocator, CFOptionFla
     return payload;
 }
 
-const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_dictionary(CFAllocatorRef allocator,
                                      CFDictionaryRef* dictionary, CFErrorRef *error,
                                      const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     const uint8_t *payload_end = 0;
     const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SET, &payload_end, der, der_end);
@@ -89,7 +91,7 @@ const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, CFOptionFlags mut
         CFTypeRef key = NULL;
         CFTypeRef value = NULL;
         
-        payload = der_decode_key_value(allocator, mutability, &key, &value, error, payload, payload_end);
+        payload = der_decode_key_value(allocator, &key, &value, error, payload, payload_end);
         
         if (payload) {
             CFDictionaryAddValue(dict, key, value);
@@ -120,10 +122,12 @@ struct size_context {
 static size_t der_sizeof_key_value(CFTypeRef key, CFTypeRef value, CFErrorRef *error) {
     size_t key_size = der_sizeof_plist(key, error);
     if (key_size == 0) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return 0;
     }
     size_t value_size = der_sizeof_plist(value, error);
     if (value_size == 0) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return 0;
     }
     return ccder_sizeof(CCDER_CONSTRUCTED_SEQUENCE, key_size + value_size);
@@ -163,9 +167,10 @@ size_t der_sizeof_dictionary(CFDictionaryRef dict, CFErrorRef *error)
 static uint8_t* der_encode_key_value(CFPropertyListRef key, CFPropertyListRef value, CFErrorRef *error,
                                      const uint8_t* der, uint8_t *der_end)
 {
-    return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
-           der_encode_plist(key, error, der,
-           der_encode_plist(value, error, der, der_end)));
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, der_end, der,
+                                                                  der_encode_plist(key, error, der,
+                                                                                   der_encode_plist(value, error, der, der_end))),
+                                      error);
 }
 
 struct encode_context {
@@ -206,9 +211,9 @@ static void add_sequence_to_array(const void *key_void, const void *value_void,
     }
 }
 
-static CFComparisonResult cfdata_compare_contents(const void *val1, const void *val2, void *context __unused)
+static CFComparisonResult cfdata_compare_der_contents(const void *val1, const void *val2, void *context __unused)
 {
-    return CFDataCompare((CFDataRef) val1, (CFDataRef) val2);
+    return CFDataCompareDERData((CFDataRef) val1, (CFDataRef) val2);
 }
 
 
@@ -227,7 +232,7 @@ uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error,
     
     CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements));
 
-    CFArraySortValues(elements, allOfThem, cfdata_compare_contents, NULL);
+    CFArraySortValues(elements, allOfThem, cfdata_compare_der_contents, NULL);
 
     uint8_t* original_der_end = der_end;
 
@@ -239,6 +244,7 @@ uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error,
 
     CFReleaseNull(elements);
 
-    return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end);
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_SET, original_der_end, der, der_end),
+                                      error);
 
 }
index b462a031f7792a8cdb0263b6a61d010c294fdd81..de3c0bf6c0b96e8f2c966e10f1e13c605c66b869 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_null(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_null(CFAllocatorRef allocator,
                                   CFNullRef* nul, CFErrorRef *error,
                                   const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
        
     size_t payload_size = 0;
     const uint8_t *payload = ccder_decode_tl(CCDER_NULL, &payload_size, der, der_end);
@@ -62,5 +64,6 @@ size_t der_sizeof_null(CFNullRef data __unused, CFErrorRef *error)
 uint8_t* der_encode_null(CFNullRef boolean __unused, CFErrorRef *error,
                             const uint8_t *der, uint8_t *der_end)
 {
-       return ccder_encode_tl(CCDER_NULL, 0, der, der_end);
+       return SecCCDEREncodeHandleResult(ccder_encode_tl(CCDER_NULL, 0, der, der_end),
+                                      error);
 }
index 29560a71472df6053293abcbfe92bd0db4822b9e..c47ce8a2c70616be5ab6a16a166c860a41ccc697 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_number(CFAllocatorRef allocator,
                                  CFNumberRef* number, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     size_t payload_size = 0;
     const uint8_t *payload = ccder_decode_tl(CCDER_INTEGER, &payload_size, der, der_end);
@@ -50,7 +52,6 @@ const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutabil
     if (payload_size > sizeof(long long)) {
         SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Number too large"), NULL, error);
         return NULL;
-
     }
 
     long long value = 0;
@@ -107,8 +108,10 @@ static inline size_t bytes_when_encoded(long long value)
 size_t der_sizeof_number(CFNumberRef data, CFErrorRef *error)
 {
     long long value;
-    if (!CFNumberGetValue(data, kCFNumberLongLongType, &value))
+    if (!CFNumberGetValue(data, kCFNumberLongLongType, &value)) {
+        SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Unable to get number from data"), NULL, error);
         return 0;
+    }
     
     return ccder_sizeof(CCDER_INTEGER, bytes_when_encoded(value));
 }
@@ -117,13 +120,17 @@ uint8_t* der_encode_number(CFNumberRef number, CFErrorRef *error,
                            const uint8_t *der, uint8_t *der_end)
 {
     long long value;
-    if (!CFNumberGetValue(number, kCFNumberLongLongType, &value))
+    if (!CFNumberGetValue(number, kCFNumberLongLongType, &value)) {
+        SecCFDERCreateError(kSecDERErrorUnsupportedNumberType, CFSTR("Unable to get number from data"), NULL, error);
         return NULL;
+    }
     
     size_t first_byte_to_include = bytes_when_encoded(value);
     
-    if (!der_end || (ssize_t) (der_end - der) < (ssize_t) first_byte_to_include)
+    if (!der_end || (ssize_t) (der_end - der) < (ssize_t) first_byte_to_include) {
+        SecCFDERCreateError(kSecDERErrorAllocationFailure, CFSTR("Unknown size"), NULL, error);
         return NULL;
+    }
 
     // Put the bytes we should include on the end.
     for(size_t bytes_included = 0; bytes_included < first_byte_to_include; ++bytes_included)
@@ -133,6 +140,7 @@ uint8_t* der_encode_number(CFNumberRef number, CFErrorRef *error,
         value >>= 8;
     }
 
-    return ccder_encode_tl(CCDER_INTEGER, first_byte_to_include, der, der_end);
+    return SecCCDEREncodeHandleResult(ccder_encode_tl(CCDER_INTEGER, first_byte_to_include, der, der_end),
+                                      error);
 
 }
index e053c3f432236ea2e6559b05d2ae237a2e8409ab..0a0f347630207f3f3d79e17d2643ae4dda4b367f 100644 (file)
@@ -31,6 +31,8 @@
 #include <corecrypto/ccder.h>
 #include <CoreFoundation/CoreFoundation.h>
 
+#include "utilities/simulatecrash_assert.h"
+
 //
 // der..CFPropertyList
 //
 //
 //
 
-const uint8_t* der_decode_plist(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_plist(CFAllocatorRef allocator,
                                 CFPropertyListRef* pl, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end)
-{    if (NULL == der)
-    return NULL;
+{
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
+        return NULL;
+    }
 
     ccder_tag tag;
-    if (NULL == ccder_decode_tag(&tag, der, der_end))
+    if (NULL == ccder_decode_tag(&tag, der, der_end)) {
+        SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("invalid tag"), NULL, error);
         return NULL;
+    }
 
     switch (tag) {
                case CCDER_NULL:
-                       return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end);
+                       return der_decode_null(allocator, (CFNullRef*)pl, error, der, der_end);
         case CCDER_BOOLEAN:
-            return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end);
+            return der_decode_boolean(allocator, (CFBooleanRef*)pl, error, der, der_end);
         case CCDER_OCTET_STRING:
-            return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end);
+            return der_decode_data(allocator, (CFDataRef*)pl, error, der, der_end);
         case CCDER_GENERALIZED_TIME:
-            return der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end);
+            return der_decode_date(allocator, (CFDateRef*)pl, error, der, der_end);
         case CCDER_CONSTRUCTED_SEQUENCE:
-            return der_decode_array(allocator, mutability, (CFArrayRef*)pl, error, der, der_end);
+            return der_decode_array(allocator, (CFArrayRef*)pl, error, der, der_end);
         case CCDER_UTF8_STRING:
-            return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end);
+            return der_decode_string(allocator, (CFStringRef*)pl, error, der, der_end);
         case CCDER_INTEGER:
-            return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end);
+            return der_decode_number(allocator, (CFNumberRef*)pl, error, der, der_end);
         case CCDER_CONSTRUCTED_SET:
-            return der_decode_dictionary(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end);
+            return der_decode_dictionary(allocator, (CFDictionaryRef*)pl, error, der, der_end);
         case CCDER_CONSTRUCTED_CFSET:
-            return der_decode_set(allocator, mutability, (CFSetRef*)pl, error, der, der_end);
+            return der_decode_set(allocator, (CFSetRef*)pl, error, der, der_end);
         default:
             SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error);
             return NULL;
@@ -109,17 +116,22 @@ size_t der_sizeof_plist(CFPropertyListRef pl, CFErrorRef *error)
         return der_sizeof_string((CFStringRef) pl, error);
     else if (CFNumberGetTypeID() == dataType)
         return der_sizeof_number((CFNumberRef) pl, error);
-       if (CFNullGetTypeID() == dataType)
-               return der_sizeof_null((CFNullRef) pl, error);
-       else {
+    else if (CFNullGetTypeID() == dataType)
+        return der_sizeof_null((CFNullRef) pl, error);
+    else {
         SecCFDERCreateError(kSecDERErrorUnsupportedCFObject, CFSTR("Unsupported CFType"), NULL, error);
         return 0;
     }
 }
 
-
 uint8_t* der_encode_plist(CFPropertyListRef pl, CFErrorRef *error,
                           const uint8_t *der, uint8_t *der_end)
+{
+    return der_encode_plist_repair(pl, error, false, der, der_end);
+}
+
+uint8_t* der_encode_plist_repair(CFPropertyListRef pl, CFErrorRef *error,
+                                 bool repair, const uint8_t *der, uint8_t *der_end)
 {
     if (!pl) {
         SecCFDERCreateError(kSecDERErrorUnsupportedCFObject, CFSTR("Null CFType"), NULL, error);
@@ -135,7 +147,7 @@ uint8_t* der_encode_plist(CFPropertyListRef pl, CFErrorRef *error,
     else if (CFDataGetTypeID() == dataType)
         return der_encode_data((CFDataRef) pl, error, der, der_end);
     else if (CFDateGetTypeID() == dataType)
-        return der_encode_date((CFDateRef) pl, error, der, der_end);
+        return der_encode_date_repair((CFDateRef) pl, error, repair, der, der_end);
     else if (CFDictionaryGetTypeID() == dataType)
         return der_encode_dictionary((CFDictionaryRef) pl, error, der, der_end);
     else if (CFSetGetTypeID() == dataType)
@@ -144,8 +156,8 @@ uint8_t* der_encode_plist(CFPropertyListRef pl, CFErrorRef *error,
         return der_encode_string((CFStringRef) pl, error, der, der_end);
     else if (CFNumberGetTypeID() == dataType)
         return der_encode_number((CFNumberRef) pl, error, der, der_end);
-       else if (CFNullGetTypeID() == dataType)
-               return der_encode_null((CFNullRef) pl, error, der, der_end);
+    else if (CFNullGetTypeID() == dataType)
+        return der_encode_null((CFNullRef) pl, error, der, der_end);
     else {
         SecCFDERCreateError(kSecDERErrorUnsupportedCFObject, CFSTR("Unsupported CFType"), NULL, error);
         return NULL;
@@ -174,7 +186,7 @@ CFPropertyListRef CFPropertyListCreateWithDERData(CFAllocatorRef allocator, CFDa
     CFPropertyListRef plist = NULL;
     const uint8_t *der = CFDataGetBytePtr(data);
     const uint8_t *der_end = der + CFDataGetLength(data);
-    der = der_decode_plist(0, kCFPropertyListMutableContainers, &plist, error, der, der_end);
+    der = der_decode_plist(0, &plist, error, der, der_end);
     if (der && der != der_end) {
         SecCFDERCreateError(kSecDERErrorUnknownEncoding, CFSTR("trailing garbage after plist item"), NULL, error);
         CFReleaseNull(plist);
index 36629478c2df3e9e8f0399db8eedff63260c2125..109e082f455ebd7d973091a97b3ba97dea275324 100644 (file)
@@ -40,6 +40,9 @@ static const CFIndex kSecDERErrorUnsupportedDERType = -2;
 static const CFIndex kSecDERErrorAllocationFailure = -3;
 static const CFIndex kSecDERErrorUnsupportedNumberType = -4;
 static const CFIndex kSecDERErrorUnsupportedCFObject = -5;
+static const CFIndex kSecDERErrorNullInput = -6;
+static const CFIndex kSecDERErrorCCDEREncode = -7;
+static const CFIndex kSecDERErrorOverflow = -8;
 
 extern CFStringRef sSecDERErrorDomain;
 
@@ -55,7 +58,11 @@ size_t der_sizeof_plist(CFPropertyListRef pl, CFErrorRef *error);
 uint8_t* der_encode_plist(CFPropertyListRef pl, CFErrorRef *error,
                            const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_plist(CFAllocatorRef pl, CFOptionFlags mutability,
+// When allowed to repair, if certain objects (right now only Dates) do not validate, set them to recognizable defaults
+uint8_t* der_encode_plist_repair(CFPropertyListRef pl, CFErrorRef *error,
+                                 bool repair, const uint8_t *der, uint8_t *der_end);
+
+const uint8_t* der_decode_plist(CFAllocatorRef pl,
                                 CFPropertyListRef* cf, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end);
 
index 017834f1aef50f198c1ec0ea7c10fa6ddee82658..5b1041b40f5beb9a50e50b526c46c6769636de28 100644 (file)
 #include "utilities/der_plist_internal.h"
 #include "utilities/SecCFError.h"
 #include "utilities/SecCFRelease.h"
+#include "utilities/der_plist.h"
 #include <CoreFoundation/CoreFoundation.h>
 
 CFStringRef sSecDERErrorDomain = CFSTR("com.apple.security.cfder.error");
+
+uint8_t * SecCCDEREncodeHandleResult(uint8_t *der, CFErrorRef *newError)
+{
+    if (!der) {
+        SecCFDERCreateError(kSecDERErrorCCDEREncode, CFSTR("ccder failed to encode"), NULL, newError);
+    }
+    return der;
+}
index 6b334d8ef9b90b9917a0543b754f676e88084a6c..e604f089a1bfc6d7ca9d7e4fcb5a82ffbe3d0fb4 100644 (file)
@@ -32,6 +32,8 @@
 #define SecCFDERCreateError(errorCode, descriptionString, previousError, newError) \
     SecCFCreateErrorWithFormat(errorCode, sSecDERErrorDomain, previousError, newError, NULL, descriptionString)
 
+uint8_t * SecCCDEREncodeHandleResult(uint8_t *der, CFErrorRef *newError);
+
 
 // CFArray <-> DER
 size_t der_sizeof_array(CFArrayRef array, CFErrorRef *error);
@@ -39,7 +41,7 @@ size_t der_sizeof_array(CFArrayRef array, CFErrorRef *error);
 uint8_t* der_encode_array(CFArrayRef array, CFErrorRef *error,
                           const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_array(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_array(CFAllocatorRef allocator,
                                 CFArrayRef* array, CFErrorRef *error,
                                 const uint8_t* der, const uint8_t *der_end);
 
@@ -49,7 +51,7 @@ size_t der_sizeof_null(CFNullRef      nul, CFErrorRef *error);
 uint8_t* der_encode_null(CFNullRef     nul, CFErrorRef *error,
                             const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_null(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_null(CFAllocatorRef allocator,
                                   CFNullRef    *nul, CFErrorRef *error,
                                   const uint8_t* der, const uint8_t *der_end);
 
@@ -60,7 +62,7 @@ size_t der_sizeof_boolean(CFBooleanRef boolean, CFErrorRef *error);
 uint8_t* der_encode_boolean(CFBooleanRef boolean, CFErrorRef *error,
                             const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_boolean(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_boolean(CFAllocatorRef allocator,
                                   CFBooleanRef* boolean, CFErrorRef *error,
                                   const uint8_t* der, const uint8_t *der_end);
 
@@ -70,22 +72,20 @@ size_t der_sizeof_data(CFDataRef data, CFErrorRef *error);
 uint8_t* der_encode_data(CFDataRef data, CFErrorRef *error,
                          const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_data(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_data(CFAllocatorRef allocator,
                                CFDataRef* data, CFErrorRef *error,
                                const uint8_t* der, const uint8_t *der_end);
 
-const uint8_t* der_decode_data_mutable(CFAllocatorRef allocator, CFOptionFlags mutability,
-                                       CFMutableDataRef* data, CFErrorRef *error,
-                                       const uint8_t* der, const uint8_t *der_end);
-
-
 // CFDate <-> DER
 size_t der_sizeof_date(CFDateRef date, CFErrorRef *error);
 
 uint8_t* der_encode_date(CFDateRef date, CFErrorRef *error,
                          const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_date(CFAllocatorRef allocator, CFOptionFlags mutability,
+uint8_t* der_encode_date_repair(CFDateRef date, CFErrorRef *error,
+                                bool repair, const uint8_t *der, uint8_t *der_end);
+
+const uint8_t* der_decode_date(CFAllocatorRef allocator,
                                CFDateRef* date, CFErrorRef *error,
                                const uint8_t* der, const uint8_t *der_end);
 
@@ -96,7 +96,7 @@ size_t der_sizeof_dictionary(CFDictionaryRef dictionary, CFErrorRef *error);
 uint8_t* der_encode_dictionary(CFDictionaryRef dictionary, CFErrorRef *error,
                                const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_dictionary(CFAllocatorRef allocator,
                                      CFDictionaryRef* dictionary, CFErrorRef *error,
                                      const uint8_t* der, const uint8_t *der_end);
 
@@ -107,7 +107,7 @@ size_t der_sizeof_number(CFNumberRef number, CFErrorRef *error);
 uint8_t* der_encode_number(CFNumberRef number, CFErrorRef *error,
                            const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_number(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_number(CFAllocatorRef allocator,
                                  CFNumberRef* number, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end);
 
@@ -117,7 +117,7 @@ size_t der_sizeof_string(CFStringRef string, CFErrorRef *error);
 uint8_t* der_encode_string(CFStringRef string, CFErrorRef *error,
                            const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_string(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_string(CFAllocatorRef allocator,
                                  CFStringRef* string, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end);
 
@@ -127,7 +127,7 @@ size_t der_sizeof_set(CFSetRef dict, CFErrorRef *error);
 uint8_t* der_encode_set(CFSetRef set, CFErrorRef *error,
                         const uint8_t *der, uint8_t *der_end);
 
-const uint8_t* der_decode_set(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_set(CFAllocatorRef allocator,
                               CFSetRef* set, CFErrorRef *error,
                               const uint8_t* der, const uint8_t *der_end);
 
index 8bf2a8957a0932c5d2c87ae9a7ba995b38bcd73f..4a3377f83cff29159a39a51f06bb842f09c2f656 100644 (file)
 #include <corecrypto/ccder.h>
 #include <CoreFoundation/CoreFoundation.h>
 
-const uint8_t* der_decode_set(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_set(CFAllocatorRef allocator,
                                      CFSetRef* set, CFErrorRef *error,
                                      const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
     
     const uint8_t *payload_end = 0;
     const uint8_t *payload = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_CFSET, &payload_end, der, der_end);
@@ -60,7 +62,7 @@ const uint8_t* der_decode_set(CFAllocatorRef allocator, CFOptionFlags mutability
     while (payload != NULL && payload < payload_end) {
         CFTypeRef value = NULL;
         
-        payload = der_decode_plist(allocator, mutability, &value, error, payload, payload_end);
+        payload = der_decode_plist(allocator, &value, error, payload, payload_end);
         
         if (payload) {
             CFSetAddValue(theSet, value);
@@ -148,9 +150,9 @@ static void add_sequence_to_array(const void *value_void, void *context_void)
     }
 }
 
-static CFComparisonResult cfdata_compare_contents(const void *val1, const void *val2, void *context __unused)
+static CFComparisonResult cfdata_compare_der_contents(const void *val1, const void *val2, void *context __unused)
 {
-    return CFDataCompare((CFDataRef) val1, (CFDataRef) val2);
+    return CFDataCompareDERData((CFDataRef) val1, (CFDataRef) val2);
 }
 
 
@@ -169,7 +171,7 @@ uint8_t* der_encode_set(CFSetRef set, CFErrorRef *error,
     
     CFRange allOfThem = CFRangeMake(0, CFArrayGetCount(elements));
     
-    CFArraySortValues(elements, allOfThem, cfdata_compare_contents, NULL);
+    CFArraySortValues(elements, allOfThem, cfdata_compare_der_contents, NULL);
 
     uint8_t* original_der_end = der_end;
     
@@ -181,6 +183,7 @@ uint8_t* der_encode_set(CFSetRef set, CFErrorRef *error,
     
     CFReleaseNull(elements);
     
-    return ccder_encode_constructed_tl(CCDER_CONSTRUCTED_CFSET, original_der_end, der, der_end);
+    return SecCCDEREncodeHandleResult(ccder_encode_constructed_tl(CCDER_CONSTRUCTED_CFSET, original_der_end, der, der_end),
+                                      error);
     
 }
index d02dfd01e8930fda3fb43a2567927fd84222bcbb..bd8329bb16ca4f3a75ee1bd036b3d494c2ba1642 100644 (file)
@@ -14,7 +14,7 @@
 #include <corecrypto/ccder.h>
 
 // If you provide a set in *set, we will add elements to it and return the union.
-const uint8_t* der_decode_set(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_set(CFAllocatorRef allocator,
                               CFSetRef* set, CFErrorRef *error,
                               const uint8_t* der, const uint8_t *der_end);
 
index 2f0c5dc07c3fd9690cc72dd3001845da3f953c7b..972a1206566d38027e04da77e655848c39c7bb1b 100644 (file)
 #include <CoreFoundation/CoreFoundation.h>
 
 
-const uint8_t* der_decode_string(CFAllocatorRef allocator, CFOptionFlags mutability,
+const uint8_t* der_decode_string(CFAllocatorRef allocator,
                                  CFStringRef* string, CFErrorRef *error,
                                  const uint8_t* der, const uint8_t *der_end)
 {
-    if (NULL == der)
+    if (NULL == der) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     size_t payload_size = 0;
     const uint8_t *payload = ccder_decode_tl(CCDER_UTF8_STRING, &payload_size, der, der_end);
@@ -73,9 +75,10 @@ size_t der_sizeof_string(CFStringRef str, CFErrorRef *error)
 uint8_t* der_encode_string(CFStringRef string, CFErrorRef *error,
                            const uint8_t *der, uint8_t *der_end)
 {
-    // Obey the NULL allowed rules.
-    if (!der_end)
+    if (NULL == der_end) {
+        SecCFDERCreateError(kSecDERErrorNullInput, CFSTR("null input"), NULL, error);
         return NULL;
+    }
 
     const CFIndex str_length = CFStringGetLength(string);
 
@@ -88,7 +91,8 @@ uint8_t* der_encode_string(CFStringRef string, CFErrorRef *error,
         return NULL;
     }
 
-    return ccder_encode_tl(CCDER_UTF8_STRING, bytes_used, der,
-           ccder_encode_body(bytes_used, buffer, der, der_end));
+    return SecCCDEREncodeHandleResult(ccder_encode_tl(CCDER_UTF8_STRING, bytes_used, der,
+                                                      ccder_encode_body(bytes_used, buffer, der, der_end)),
+                                      error);
 
 }
diff --git a/OSX/utilities/entitlements.c b/OSX/utilities/entitlements.c
new file mode 100644 (file)
index 0000000..bffbe6f
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+* Copyright (c) 2020 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 "entitlements.h"
+
+/// Moves the entitlement value from the original entitlement into the target entitlement.
+static void transferEntitlement(CFMutableDictionaryRef entitlements, CFStringRef originalEntitlement, CFStringRef targetEntitlement)
+{
+    CFTypeRef value = (CFStringRef)CFDictionaryGetValue(entitlements, originalEntitlement);
+    CFDictionaryAddValue(entitlements, targetEntitlement, value);
+}
+
+/// Determines if an entitlement needs fixup, which means it has a value for the original entitlement and no value for the
+/// target entitlement.
+static bool entitlementNeedsFixup(CFDictionaryRef entitlements, CFStringRef originalEntitlement, CFStringRef targetEntitlement)
+{
+    // Entitlements only need fixup on macOS running on Apple Silicon, so just always fall through to the default case otherwise.
+#if TARGET_OS_OSX && TARGET_CPU_ARM64
+    CFTypeRef originalValue = (CFStringRef)CFDictionaryGetValue(entitlements, originalEntitlement);
+    CFTypeRef newValue = (CFStringRef)CFDictionaryGetValue(entitlements, targetEntitlement);
+    if (originalValue != NULL && newValue == NULL) {
+        return true;
+    }
+#endif
+    return false;
+}
+
+bool needsCatalystEntitlementFixup(CFDictionaryRef entitlements)
+{
+    return entitlementNeedsFixup(entitlements, CFSTR("application-identifier"), CFSTR("com.apple.application-identifier")) ||
+           entitlementNeedsFixup(entitlements, CFSTR("aps-environment"), CFSTR("com.apple.developer.aps-environment"));
+}
+
+bool updateCatalystEntitlements(CFMutableDictionaryRef entitlements)
+{
+    bool updated = false;
+    if (entitlementNeedsFixup(entitlements, CFSTR("application-identifier"), CFSTR("com.apple.application-identifier"))) {
+        transferEntitlement(entitlements, CFSTR("application-identifier"), CFSTR("com.apple.application-identifier"));
+        updated = true;
+    }
+    if (entitlementNeedsFixup(entitlements, CFSTR("aps-environment"), CFSTR("com.apple.developer.aps-environment"))) {
+        transferEntitlement(entitlements, CFSTR("aps-environment"), CFSTR("com.apple.developer.aps-environment"));
+        updated = true;
+    }
+    return updated;
+}
diff --git a/OSX/utilities/entitlements.h b/OSX/utilities/entitlements.h
new file mode 100644 (file)
index 0000000..427f0bc
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+* Copyright (c) 2020 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 _utilities_entitlements_h
+#define _utilities_entitlements_h
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/// Checks an entitlement dictionary to determine if any Catalyst-related entitlements need to be updated.
+bool needsCatalystEntitlementFixup(CFDictionaryRef entitlements);
+
+/// Modifies an entitlements dictionary to add the necessary Catalyst-related entitlements based on pre-existing entitlements.
+/// Returns whether the entitlements were modified.
+bool updateCatalystEntitlements(CFMutableDictionaryRef entitlements);
+
+__END_DECLS
+
+#endif /* _utilities_entitlements_h */
index 197dfe35d189e4802931e48629f4472c02b18121..0a41470c531be8be576ce2af7347070c4fbf18ea 100644 (file)
@@ -11,7 +11,7 @@
 #import <SoftLinking/SoftLinking.h>
 #import <Foundation/Foundation.h>
 
-SOFT_LINK_FRAMEWORK_SAFE(PrivateFrameworks, CrashReporterSupport);
+SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CrashReporterSupport);
 
 SOFT_LINK_FUNCTION(CrashReporterSupport, SimulateCrash, soft_SimulateCrash, \
                    BOOL, (pid_t pid, mach_exception_data_type_t exceptionCode, NSString *description),
diff --git a/OSX/utilities/simulatecrash_assert.h b/OSX/utilities/simulatecrash_assert.h
new file mode 100644 (file)
index 0000000..33d13b3
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2020 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 _SECURITY_UTILITIES_SIMULATECRASH_ASSERT_H_
+#define _SECURITY_UTILITIES_SIMULATECRASH_ASSERT_H_
+
+#if !defined(NDEBUG) || !defined(__OBJC__)
+    #include <assert.h>
+#else // NDEBUG && __OBJC__
+    #include "debugging.h"
+    #undef assert
+    #define assert(expr) { \
+        if (!(expr)) { \
+            __security_simulatecrash(CFSTR("Execution has encountered an unexpected state"), __sec_exception_code_UnexpectedState); \
+        } \
+    }
+#endif // NDEBUG && __OBJC__
+
+#endif /* _SECURITY_UTILITIES_SIMULATECRASH_ASSERT_H_ */
index e08137ea059066f4d44d731a7480520cdd18d223..4bcfade31e6f4c11b1f2eae4c6fc6dc46b994202 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
        <key>Project</key>
@@ -46,6 +46,8 @@
                        </array>
                        <key>Disabled</key>
                        <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_1</string>
+                       <key>MayRunConcurrently</key>
+                       <false/>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -56,6 +58,8 @@
                        </array>
                        <key>Disabled</key>
                        <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_2</string>
+                       <key>MayRunConcurrently</key>
+                       <false/>
                </dict>
                <dict>
                        <key>TestName</key>
@@ -66,6 +70,8 @@
                        </array>
                        <key>Disabled</key>
                        <string>BATS_UTD_Disabled_keychainnetworkextensionsharing_3</string>
+                       <key>MayRunConcurrently</key>
+                       <false/>
                </dict>
                <dict>
                        <key>TestName</key>
                </dict>
                <dict>
                        <key>TestName</key>
-                       <string>KeychainSecd_macOS</string>
+                       <string>KeychainSecd</string>
                        <key>ShowSubtestResults</key>
                        <true/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD</string>
-                               <string>/AppleInternal/XCTests/com.apple.security/secdxctests_mac.xctest</string>
+                               <string>/AppleInternal/CoreOS/tests/Security/KeychainEntitledTestRunner</string>
+                               <string>-t</string>
+                               <string>secdxctests</string>
                        </array>
                        <key>Disabled</key>
-                       <string>BATS_UTD_Disabled_KeychainSecd_macOS</string>
+                       <string>BATS_UTD_Disabled_KeychainSecdXCTests</string>
                </dict>
                <dict>
                        <key>TestName</key>
-                       <string>KeychainSecd_iOS</string>
+                       <string>SecDbBackupTests</string>
+                       <key>WorkingDirectory</key>
+                       <string>/AppleInternal/XCTests/com.apple.security/</string>
                        <key>ShowSubtestResults</key>
                        <true/>
                        <key>Command</key>
                        <array>
-                               <string>BATS_XCTEST_CMD</string>
-                               <string>/AppleInternal/XCTests/com.apple.security/secdxctests_ios.xctest</string>
+                               <string>/AppleInternal/CoreOS/tests/Security/KeychainEntitledTestRunner</string>
+                               <string>-t</string>
+                               <string>SecDbBackupTests</string>
                        </array>
                        <key>Disabled</key>
-                       <string>BATS_UTD_Disabled_KeychainSecd_iOS</string>
+                       <string>BATS_UTD_Disabled_KeychainSecDbBackupTests</string>
                </dict>
                <dict>
                        <key>TestName</key>
                        <key>Disabled</key>
                        <string>BATS_UTD_Disabled_SecurityUtiltitesTests</string>
                </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>SecCodeAPITest</string>
+                       <key>Command</key>
+                       <array>
+                               <string>/AppleInternal/CoreOS/tests/Security/secseccodeapitest</string>
+                       </array>
+                       <key>Disabled</key>
+                       <string>BATS_UTD_Disabled_SecCodeAPITest</string>
+                       <key>ShowSubtestResults</key>
+                       <true/>
+               </dict>
        </array>
 </dict>
 </plist>
index e8549e96ad1226293a7311600b1404d97a5e1115..78aa0fef3fe8b227ff8c9bc703ccf911eacd1d4f 100644 (file)
@@ -45,6 +45,9 @@
 #define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _TRUE_
 #define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_
 #define BATS_UTD_Disabled_security_sysdiagnose _TRUE_
+#define BATS_UTD_Disabled_KeychainSecdXCTests _TRUE_
+#define BATS_UTD_Disabled_KeychainSecDbBackupTests _TRUE_
+#define BATS_UTD_Disabled_SecCodeAPITest _TRUE_
 
 #elif TARGET_OS_OSX
 /* For MacOS, we disable the iOS only tests. */
 #define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_
 #define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_
 #define BATS_UTD_Disabled_security_sysdiagnose _FALSE_
+#define BATS_UTD_Disabled_KeychainSecdXCTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecDbBackupTests _FALSE_
+#define BATS_UTD_Disabled_SecCodeAPITest _FALSE_
+
+#elif TARGET_OS_WATCH
+#define BATS_UTD_Disabled_AuthorizationTest _TRUE_
+#define BATS_UTD_Disabled_EduModeTest _FALSE_
+#define BATS_UTD_Disabled_KCPairingTest _FALSE_
+#define BATS_UTD_Disabled_KeychainAnalyticsTests _FALSE_
+#define BATS_UTD_Disabled_KeychainMockAKSTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecd_iOS _FALSE_
+#define BATS_UTD_Disabled_KeychainSecd_macOS _TRUE_
+#define BATS_UTD_Disabled_SecurityUtiltitesTests _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_1 _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_2 _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_
+#define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_
+#define BATS_UTD_Disabled_security_sysdiagnose _FALSE_
+#define BATS_UTD_Disabled_KeychainSecdXCTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecDbBackupTests _TRUE_
+#define BATS_UTD_Disabled_SecCodeAPITest _TRUE_
+
+#elif TARGET_OS_TV
+#define BATS_UTD_Disabled_AuthorizationTest _TRUE_
+#define BATS_UTD_Disabled_EduModeTest _FALSE_
+#define BATS_UTD_Disabled_KCPairingTest _FALSE_
+#define BATS_UTD_Disabled_KeychainAnalyticsTests _FALSE_
+#define BATS_UTD_Disabled_KeychainMockAKSTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecd_iOS _FALSE_
+#define BATS_UTD_Disabled_KeychainSecd_macOS _TRUE_
+#define BATS_UTD_Disabled_SecurityUtiltitesTests _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_1 _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_2 _FALSE_
+#define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_
+#define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_
+#define BATS_UTD_Disabled_security_sysdiagnose _FALSE_
+#define BATS_UTD_Disabled_KeychainSecdXCTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecDbBackupTests _TRUE_
+#define BATS_UTD_Disabled_SecCodeAPITest _TRUE_
 
 #else
 /* By default, assume iOS platforms. We disable the MacOS only tests. */
 #define BATS_UTD_Disabled_keychainnetworkextensionsharing_3 _FALSE_
 #define BATS_UTD_Disabled_keystorectl_get_lock_state _FALSE_
 #define BATS_UTD_Disabled_security_sysdiagnose _FALSE_
+#define BATS_UTD_Disabled_KeychainSecdXCTests _FALSE_
+#define BATS_UTD_Disabled_KeychainSecDbBackupTests _FALSE_
+#define BATS_UTD_Disabled_SecCodeAPITest _TRUE_
 
 #endif
index 14986bd6df1a531b1a9e4a8f5f2288daeef50298..94e961a3a615727a4e9e33fe8b07a0fdc832eb47 100644 (file)
@@ -1,6 +1,25 @@
-//
-//  Copyright 2016 Apple. All rights reserved.
-//
+/*
+ * Copyright (c) 2016,2020 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@
+ */
 
 /*
  * This is to fool os services to not provide the Keychain manager
@@ -14,6 +33,7 @@
 #include <Security/SecItemPriv.h>
 #include <notify.h>
 #include <err.h>
+#import <TargetConditionals.h>
 
 int
 main(int argc, const char ** argv)
@@ -32,8 +52,9 @@ main(int argc, const char ** argv)
         (id)kSecAttrAccessible : (id)kSecAttrAccessibleAfterFirstUnlock,
     };
     status = SecItemDelete((__bridge CFDictionaryRef)query);
-    if (status != errSecSuccess && status != errSecItemNotFound)
+    if (status != errSecSuccess && status != errSecItemNotFound) {
         errx(1, "cleanup item: %d", (int)status);
+    }
 
     notify_register_dispatch("com.apple.security.view-change.PCS", &token, queue, ^(int __unused token2) {
         printf("got notification\n");
@@ -45,13 +66,22 @@ main(int argc, const char ** argv)
      */
 
     status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
-    if (status != errSecSuccess)
+    if (status != errSecSuccess) {
         errx(1, "add item: %d", (int)status);
+    }
 
     sleep(3);
 
-    if (!got_notification)
+// Bridge explicitly disables notify phase, no PCS, octagon or sos on this platform
+#if !TARGET_OS_BRIDGE
+    if (!got_notification) {
         errx(1, "failed to get notification on add");
+    }
+#else
+    if (got_notification) {
+        errx(1, "received unexpected notification on add");
+    }
+#endif
     got_notification = false;
 
     /*
@@ -59,13 +89,21 @@ main(int argc, const char ** argv)
      */
 
     status = SecItemDelete((__bridge CFDictionaryRef)query);
-    if (status != errSecSuccess)
+    if (status != errSecSuccess) {
         errx(1, "cleanup2 item: %d", (int)status);
+    }
 
     sleep(3);
 
-    if (!got_notification)
+#if !TARGET_OS_BRIDGE
+    if (!got_notification) {
         errx(1, "failed to get notification on delete");
+    }
+#else
+    if (got_notification) {
+        errx(1, "received unexpected notification on delete");
+    }
+#endif
 
     return 0;
 }
index 122a78bd59ba2168e55a9010d54183328de20b09..dea0cee5f5ec6e7a10b20b93734a72cd9b1ce6fe 100644 (file)
@@ -43,8 +43,9 @@ Cleanup(void)
         (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
     };
     status = SecItemDelete((__bridge CFDictionaryRef)query);
-    if (status != errSecSuccess || status == errSecItemNotFound)
+    if (status != errSecSuccess) {
         printf("cleanup ag1: %d\n", (int)status);
+    }
 
     query = @{
         (id)kSecClass : (id)kSecClassGenericPassword,
@@ -52,8 +53,9 @@ Cleanup(void)
         (id)kSecUseDataProtectionKeychain : (id)kCFBooleanTrue,
     };
     status = SecItemDelete((__bridge CFDictionaryRef)query);
-    if (status != errSecSuccess || status != errSecItemNotFound)
+    if (status != errSecSuccess) {
         printf("cleanup ag2: %d\n", (int)status);
+    }
 }
 
 static void
diff --git a/RegressionTests/secseccodeapitest.c b/RegressionTests/secseccodeapitest.c
new file mode 100644 (file)
index 0000000..660abf7
--- /dev/null
@@ -0,0 +1,253 @@
+//
+//  secseccodeapitest.c
+//  secseccodeapitest
+//
+
+#include "authd_private.h"
+
+#include <stdio.h>
+#include <xpc/xpc.h>
+#include <Security/SecCode.h>
+#include <libkern/OSAtomic.h>
+#include <AssertMacros.h>
+
+#define BEGIN()                                             \
+({                                                          \
+    fprintf(stdout, "[BEGIN] %s\n", __FUNCTION__);          \
+})
+
+#define INFO(fmt, ...)                                      \
+({                                                          \
+    fprintf(stdout, fmt "\n", ##__VA_ARGS__);               \
+})
+
+#define PASS(fmt, ...)                                                      \
+({                                                                          \
+    fprintf(stdout, "[PASS] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__);    \
+})
+
+#define FAIL(fmt, ...)                                                      \
+({                                                                          \
+    fprintf(stdout, "[FAIL] %s " fmt "\n", __FUNCTION__, ##__VA_ARGS__);    \
+})
+
+#define SAFE_RELEASE(x)                                     \
+({                                                          \
+    if (x) {                                                \
+        CFRelease(x);                                       \
+        x = NULL;                                           \
+    }                                                       \
+})
+
+enum xpcConnectionStates {
+    kXPCConnectionStateNotCancelled = 0,
+    kXPCConnectionStateCancelled,
+    kXPCConnectionStateOkayToExit,
+    kXPCConnectionStateServerNotAvailable,
+};
+
+static int
+_validatePathFromSecCode(SecCodeRef processRef, const char *path)
+{
+    int ret = -1;
+    OSStatus status;
+    SecStaticCodeRef staticProcessRef = NULL;
+    CFURLRef pathURL = NULL;
+    CFStringRef pathString = NULL;
+
+    /* Get the StaticCodeRef for this SecCodeRef */
+    status = SecCodeCopyStaticCode(processRef, kSecCSDefaultFlags, &staticProcessRef);
+    require_noerr_action(status, exit, ret = -1);
+
+    INFO("Successfully created a SecStaticCodeRef");
+
+    /* Copy the path of requested service */
+    status = SecCodeCopyPath(staticProcessRef, kSecCSDefaultFlags, &pathURL);
+    require_noerr_action(status, exit, ret = -1);
+
+    INFO("Successfully created a CFURLRef");
+
+    /* Get the CFStringRef from the CFURLRef */
+    pathString = CFURLGetString(pathURL);
+    require_action(pathString, exit, ret = -1);
+
+    INFO("Successfully created a CFStingRef");
+
+    if (!strncmp(path, CFStringGetCStringPtr(pathString, kCFStringEncodingUTF8), strlen(path))) {
+        INFO("Successfully confirmed the location of requested service");
+        ret = 0;
+    } else {
+        INFO("Location of service incorrect: %s", CFStringGetCStringPtr(pathString, kCFStringEncodingUTF8));
+        ret = -1;
+    }
+
+exit:
+    SAFE_RELEASE(pathURL);
+    SAFE_RELEASE(staticProcessRef);
+
+    return ret;
+}
+
+static int
+CheckCreateWithXPCMessage(void)
+{
+    BEGIN();
+
+    int ret;
+    OSStatus status;
+    xpc_connection_t connection = NULL;
+    xpc_object_t message = NULL, reply = NULL;
+    SecCodeRef processRef = NULL;
+    volatile static int xpcState = kXPCConnectionStateNotCancelled;
+
+    connection = xpc_connection_create(SECURITY_AUTH_NAME, NULL);
+    if (NULL == connection) {
+        FAIL("Unable to create an XPC connection with %s", SECURITY_AUTH_NAME);
+        return -1;
+    }
+
+    INFO("XPC Connection with %s created", SECURITY_AUTH_NAME);
+
+    xpc_connection_set_event_handler(connection, ^(xpc_object_t event) {
+        if (xpc_get_type(event) == XPC_TYPE_ERROR && event == XPC_ERROR_CONNECTION_INVALID) {
+            if (OSAtomicCompareAndSwapInt(kXPCConnectionStateCancelled, kXPCConnectionStateOkayToExit, &xpcState)) {
+                INFO("XPC Connection Cancelled");
+            } else {
+                xpcState = kXPCConnectionStateServerNotAvailable;
+                FAIL("Authorization server not available");
+            }
+        }
+    });
+
+    xpc_connection_resume(connection);
+
+    INFO("XPC Connection resumed");
+
+    /* Create an empty dictionary */
+    message = xpc_dictionary_create(NULL, NULL, 0);
+
+    /*
+     * Set _type to something invalid. This is done because authd will simply
+     * return an "invalid type" for this case, which means no state changes in
+     * the authd daemon.
+     */
+    xpc_dictionary_set_uint64(message, AUTH_XPC_TYPE, AUTHORIZATION_COPY_RIGHT_PROPERTIES+512);
+
+    /* Send object and wait for response */
+    reply = xpc_connection_send_message_with_reply_sync(connection, message);
+    xpc_release(message);
+
+    INFO("XPC Message received");
+
+    /* Create a SecCode using the XPC Message */
+    status = SecCodeCreateWithXPCMessage(reply, kSecCSDefaultFlags, &processRef);
+    if (status) {
+        FAIL("Unable to create a SecCodeRef from message reply [%d]", status);
+        xpc_release(reply);
+        return -1;
+    }
+    xpc_release(reply);
+
+    INFO("Successfully created a SecCodeRef");
+
+    const char *authdLocation = "file:///System/Library/Frameworks/Security.framework/Versions/A/XPCServices/authd.xpc/";
+    if (_validatePathFromSecCode(processRef, authdLocation)) {
+        FAIL("Unable to verify authd location");
+        ret = -1;
+    } else {
+        PASS("authd location successfully verified");
+        ret = 0;
+    }
+
+    SAFE_RELEASE(processRef);
+
+    // Potential race condition in getting an actual XPC_TYPE_ERROR vs getting
+    // a connection cancelled. We are okay with this since this is extremely unlikely...
+    if (OSAtomicCompareAndSwapInt(kXPCConnectionStateNotCancelled, kXPCConnectionStateCancelled, &xpcState)) {
+        xpc_connection_cancel(connection);
+    }
+
+    while (xpcState != kXPCConnectionStateOkayToExit) {
+        if (xpcState == kXPCConnectionStateServerNotAvailable) {
+            break;
+        }
+        usleep(1000 * 1);
+    }
+
+    return ret;
+}
+
+static int
+CheckCreateWithXPCMessage_invalidXPCObject(void)
+{
+    BEGIN();
+
+    OSStatus status;
+    xpc_object_t invalidObject = NULL;
+    SecCodeRef processRef = NULL;
+
+    /* Create an NULL object */
+    invalidObject = xpc_null_create();
+
+    INFO("Created a NULL object");
+
+    /* Try and acquire a SecCodeRef through the NULL object -- should fail with errSecCSInvalidObjectRef */
+    status = SecCodeCreateWithXPCMessage(invalidObject, kSecCSDefaultFlags, &processRef);
+    if (status != errSecCSInvalidObjectRef) {
+        FAIL("Return code unexpected [%d]", status);
+        return -1;
+    }
+
+    PASS("Got expected return code");
+    return 0;
+}
+
+static int
+CheckCreateWithXPCMessage_NULLConnectionInObject(void)
+{
+    BEGIN();
+
+    OSStatus status;
+    xpc_object_t emptyDictionary = NULL;
+    SecCodeRef processRef = NULL;
+
+    /* Create an empty dictionary object */
+    emptyDictionary = xpc_dictionary_create_empty();
+
+    INFO("Created an empty dictionary object");
+
+    /* Try and acquire a SecCodeRef through the empty dictionary -- should fail with errSecCSInvalidObjectRef */
+    status = SecCodeCreateWithXPCMessage(emptyDictionary, kSecCSDefaultFlags, &processRef);
+    if (status != errSecCSInvalidObjectRef) {
+        FAIL("Return code unexpected [%d]", status);
+        return -1;
+    }
+
+    PASS("Got expected return code");
+    return 0;
+}
+
+int main(void)
+{
+    fprintf(stdout, "[TEST] secseccodeapitest\n");
+
+    int i;
+    int (*testList[])(void) = {
+        CheckCreateWithXPCMessage,
+        CheckCreateWithXPCMessage_invalidXPCObject,
+        CheckCreateWithXPCMessage_NULLConnectionInObject
+    };
+    const int numberOfTests = sizeof(testList) / sizeof(*testList);
+    int testResults[numberOfTests] = {0};
+
+    for (i = 0; i < numberOfTests; i++) {
+        testResults[i] = testList[i]();
+    }
+
+    fprintf(stdout, "[SUMMARY]\n");
+    for (i = 0; i < numberOfTests; i++) {
+        fprintf(stdout, "%d. %s\n", i+1, testResults[i] == 0 ? "Passed" : "Failed");
+    }
+
+    return 0;
+}
index a3efacd01c583602fe021a28a8bb7bb5541ec757..241e9740f5b338535c5b7a98425de39828e9af33 100644 (file)
@@ -332,7 +332,6 @@ SEC_EXP_CLASS(CKKSControl)
 SEC_EXP_CLASS(SecuritydXPCClient)
 
 #if __OBJC2__
-SEC_EXP_CLASS(SFSignInAnalytics)
 SEC_EXP_CLASS(SecXPCHelper)
 SEC_EXP_CLASS(OTClique)
 SEC_EXP_CLASS(OTConfigurationContext)
@@ -365,19 +364,13 @@ _OTProtocolPiggybacking
 _OTDefaultsDomain
 _OTDefaultsOctagonEnable
 _OTTrustStatusChangeNotification
-
-_OctagonEventAttributeZoneName
-_OctagonEventAttributeFailureReason
-_OctagonEventAttributeTimeSinceLastPostedFollowUp
+_OTEscrowRecordPrefix
 
 _SecEscrowRequestHavePrecord
 _SecEscrowRequestPendingPasscode
 _SecEscrowRequestPendingCertificate
 
-_OTCKContainerName
-_CuttlefishTrustZone
 _CuttlefishErrorDomain
-_TrustedPeersHelperErrorDomain
 _CuttlefishErrorRetryAfterKey
 
 _OctagonPlatformSupportsSOS
@@ -392,6 +385,14 @@ _OctagonAuthoritativeTrustIsEnabled
 _OctagonAuthoritativeTrustSetIsEnabled
 _OctagonIsSOSFeatureEnabled
 _OctagonSetSOSFeatureEnabled
+_OctagonIsOptimizationEnabled
+_OctagonSetOptimizationEnabled
+_OctagonSetEscrowRecordFetchEnabled
+_OctagonIsEscrowRecordFetchEnabled
+_SecKVSOnCloudKitIsEnabled
+_SecKVSOnCloudKitSetOverrideIsEnabled
+_SecErrorIsNestedErrorCappingEnabled
+_SecErrorSetOverrideNestedErrorCappingIsEnabled
 
 SEC_EXP_CLASS(OTJoiningConfiguration)
 SEC_EXP_CLASS(OTControl)
@@ -400,6 +401,9 @@ SEC_EXP_CLASS(SecuritydXPCClient)
 _SecAccessGroupsGetCurrent
 _SecAccessGroupsSetCurrent
 _SecSecurityClientGet
+_SecSecurityClientRegularToAppClip
+_SecSecurityClientAppClipToRegular
+_SecSecurityClientSetApplicationIdentifier
 _securityd_create_message
 _securityd_message_with_reply_sync
 _securityd_message_no_error
@@ -415,7 +419,6 @@ __SecSetSecuritydTargetUID
 
 _SecDERItemCopyOIDDecimalRepresentation
 _SecDigestCreate
-_SecFrameworkCopyResourceURL
 _SecCopyErrorMessageString
 
 _SecFrameworkCopyIPAddressData
@@ -536,11 +539,12 @@ _AuthorizationExecuteWithPrivilegesExternalFormInternal
 _AuthorizationFree
 _AuthorizationFreeItemSet
 _AuthorizationMakeExternalForm
-_AuthorizationPreauthorizeCredentials
 _AuthorizationRightGet
 _AuthorizationRightRemove
 _AuthorizationRightSet
 _AuthorizationEnableSmartCard
+_AuthorizationCopyPreloginUserDatabase
+_AuthorizationCopyRightProperties
 _SessionCreate
 _SessionGetInfo
 _SessionSetDistinguishedUser
@@ -913,14 +917,10 @@ _SecDigestGetData
 _SecFDERecoveryUnwrapCRSKWithPrivKey
 _SecFDERecoveryWrapCRSKWithPubKey
 _SecGenericPasswordCreate
-_SecIdentityAddPreferenceItem
-_SecIdentityCompare
-_SecIdentityCopyFromPreferenceItem
 _SecIdentityCopyPreference
 _SecIdentityCopyPreferred
 _SecIdentityCopySystemIdentity
 _SecIdentityCreateWithCertificate
-_SecIdentityFindPreferenceItem
 _SecIdentitySearchCopyNext
 _SecIdentitySearchCreate
 _SecIdentitySearchCreateWithAttributes
@@ -929,11 +929,10 @@ _SecIdentitySearchGetTypeID
 _SecIdentitySetPreference
 _SecIdentitySetPreferred
 _SecIdentitySetSystemIdentity
-_SecIdentityUpdatePreferenceItem
 _SecInferLabelFromX509Name
 _SecItemAdd_ios
 _SecItemCopyMatching_ios
-_SecItemUpdateTokenItems_ios
+_SecItemUpdateTokenItemsForAccessGroups
 
 _SecKeyGeneratePair_ios
 
@@ -950,7 +949,6 @@ _SecItemUpdate_ios
 _SecKeychainAddCallback
 _SecKeychainAddDBToKeychainList
 _SecKeychainAddGenericPassword
-_SecKeychainAddIToolsPassword
 _SecKeychainAddInternetPassword
 _SecKeychainAttemptMigrationWithMasterKey
 _SecKeychainAttributeInfoForItemID
@@ -1034,7 +1032,6 @@ _SecKeychainLogout
 _SecKeychainMDSInstall
 _SecKeychainMakeFromFullPath
 _SecKeychainOpen
-_SecKeychainOpenWithGuid
 _SecKeychainRecodeKeychain
 _SecKeychainRemoveCallback
 _SecKeychainRemoveDBFromKeychainList
@@ -1589,6 +1586,7 @@ _SecCodeCopyHost
 _SecCodeCopyGuestWithAttributes
 _SecCodeCreateWithAuditToken
 _SecCodeCreateWithPID
+_SecCodeCreateWithXPCMessage
 _SecCodeCheckValidity
 _SecCodeCheckValidityWithErrors
 _SecCodeCopyPath
@@ -1699,6 +1697,7 @@ _kSecCodeInfoDiskRepVersionMin
 _kSecCodeInfoDiskRepVersionSDK
 _kSecCodeInfoResourceDirectory
 _kSecCodeInfoNotarizationDate
+_kSecCodeInfoSignatureVersion
 _kSecGuestAttributeCanonical
 _kSecGuestAttributeDynamicCode
 _kSecGuestAttributeDynamicCodeInfoPlist
@@ -1819,6 +1818,9 @@ _SecRequirementGetTypeID
 _SecStaticCodeCheckValidity
 _SecStaticCodeCreateWithPath
 _SecStaticCodeGetTypeID
+_SecStaticCodeSetCallback
+_SecStaticCodeSetValidationConditions
+_SecStaticCodeCancelValidation
 _kSecCFErrorArchitecture
 _kSecCFErrorGuestAttributes
 _kSecCFErrorInfoPlist
@@ -1830,6 +1832,7 @@ _kSecCFErrorResourceSideband
 _kSecCodeAttributeArchitecture
 _kSecCodeAttributeBundleVersion
 _kSecCodeAttributeSubarchitecture
+_kSecCodeDirectoryFlagTable
 _kSecCodeInfoCMS
 _kSecCodeInfoCMSDigest
 _kSecCodeInfoCMSDigestHashType
@@ -1856,6 +1859,7 @@ _kSecCodeInfoPlatformIdentifier
 _kSecCodeInfoRequirementData
 _kSecCodeInfoRequirements
 _kSecCodeInfoResourceDirectory
+_kSecCodeInfoSignatureVersion
 _kSecCodeInfoSource
 _kSecCodeInfoStatus
 _kSecCodeInfoTimestamp
@@ -1872,13 +1876,6 @@ _kSecGuestAttributeSubarchitecture
 
 #endif // TARGET_OS_IPHONE
 
-#if TARGET_OS_OSX
-//breadcrumb
-_SecBreadcrumbCreateFromPassword
-_SecBreadcrumbCopyPassword
-_SecBreadcrumbCreateNewEncryptedKey
-#endif // TARGET_OS_OSX
-
 //
 // libDER OIDs
 //
@@ -2009,6 +2006,7 @@ _SecTranslocateAppLaunchCheckin
 _SecTranslocateURLShouldRunTranslocated
 _SecTranslocateIsTranslocatedURL
 _SecTranslocateCreateOriginalPathForURL
+_SecTranslocateCreateGeneric
 #endif // TARGET_OS_OSX
 
 #if TARGET_OS_OSX
@@ -2087,7 +2085,8 @@ _OBJC_CLASS_$_SFAnalyticsMultiSampler
 _OBJC_CLASS_$_SFAnalyticsSampler
 _OBJC_CLASS_$_SFAnalyticsSQLiteStore
 _OBJC_CLASS_$_SecCoreAnalytics
-_OBJC_METACLASS_$_SFSignInAnalytics
+_SecCoreAnalyticsValue
+_SecCoreAnalyticsSendValue
 _SFAnalyticsMaxEventsToReport
 _SFSQLiteJournalSuffixes
 _SFAnalyticsSamplerIntervalOncePerReport
@@ -2116,6 +2115,7 @@ _SFAnalyticsAttributeErrorUnderlyingChain
 _SFAnalyticsAttributeLastUploadTime
 _SFAnalyticsTopicCloudServices
 _SFAnalyticsTopicKeySync
+_SFAnalyticsTopicNetworking
 _SFAnalyticsTopicTransparency
 _SFAnalyticsTopicTrust
 _SFAnalyticsErrorDomain
@@ -2132,6 +2132,8 @@ _CKDKVSPerfCounterSynchronizeFailures
 
 _OBJC_CLASS_$_LocalKeychainAnalytics
 _LKAEventUpgrade
+_LKAEventStash
+_LKAEventStashLoad
 #endif // __OBJC2__
 
 _LKAReportKeychainUpgradeOutcome
@@ -2167,3 +2169,5 @@ _SecCreateCFErrorWithXPCObject
 _SecCreateXPCObjectWithCFError
 
 _SecItemVerifyBackupIntegrity
+
+_SecItemDeleteKeychainItemsForAppClip
index d469fbf5f1a05a23ebe341bc7d128e7f310c6750..6ccf9ee997df6aa4be37477d805a5fe41de29e57 100644 (file)
@@ -13,7 +13,9 @@
                        buildPhases = (
                        );
                        dependencies = (
+                               6C2045F82424BC4400F9461D /* PBXTargetDependency */,
                                47C2F1902059CBFC0062DE30 /* PBXTargetDependency */,
+                               DCE27861245B81BD00381FE8 /* PBXTargetDependency */,
                                D469C4E5218BECCE008AC1FC /* PBXTargetDependency */,
                                0C78CCE51FCC97E7008B4B24 /* PBXTargetDependency */,
                                EB27FF261E40716D00EC9E3A /* PBXTargetDependency */,
@@ -52,6 +54,7 @@
                                EB6A6FBD1B90F9170045DC68 /* PBXTargetDependency */,
                                DC647C46208A85C900D0F9F8 /* PBXTargetDependency */,
                                D4F56BAB217FCAF600FCA6B7 /* PBXTargetDependency */,
+                               0C65BB4F23C3F3270063D2B7 /* PBXTargetDependency */,
                        );
                        name = Security_frameworks_ios;
                        productName = kernel;
@@ -73,6 +76,7 @@
                        buildPhases = (
                        );
                        dependencies = (
+                               5AAE383623D261CF0025CF9E /* PBXTargetDependency */,
                                EB74CC232207E99700F1BBAD /* PBXTargetDependency */,
                                47C2F18C2059CBEA0062DE30 /* PBXTargetDependency */,
                                4771D982209A76B100BA9772 /* PBXTargetDependency */,
                        buildPhases = (
                        );
                        dependencies = (
+                               0CCC22D223F39A7500E1FCD0 /* PBXTargetDependency */,
+                               6CF33CA62387156600D1E75D /* PBXTargetDependency */,
                                EB694E87223AB79400F02C1C /* PBXTargetDependency */,
-                               D4E0E9762224DE9100A802E0 /* PBXTargetDependency */,
                                D4E0E9702224DE8200A802E0 /* PBXTargetDependency */,
                                D4E0E9722224DE8200A802E0 /* PBXTargetDependency */,
                                D4E0E9742224DE8200A802E0 /* PBXTargetDependency */,
                        buildPhases = (
                        );
                        dependencies = (
+                               0CCC22D423F39A7C00E1FCD0 /* PBXTargetDependency */,
+                               6CF33CA82387157200D1E75D /* PBXTargetDependency */,
                                EB694E72223AB78E00F02C1C /* PBXTargetDependency */,
-                               D4E0E9AC2224DFEB00A802E0 /* PBXTargetDependency */,
                                D4E0E9A62224DFDD00A802E0 /* PBXTargetDependency */,
                                D4E0E9A82224DFDD00A802E0 /* PBXTargetDependency */,
                                D4E0E9AA2224DFDD00A802E0 /* PBXTargetDependency */,
                                D4F56B9D217FCA7E00FCA6B7 /* PBXTargetDependency */,
                                D4F56B9F217FCA8600FCA6B7 /* PBXTargetDependency */,
                                D4F56BB72181380600FCA6B7 /* PBXTargetDependency */,
+                               0C2B36C523C42EC800000718 /* PBXTargetDependency */,
                        );
                        name = Security_frameworks_tvos;
                        productName = Security_frameworks_tvos;
                                D4F56BA7217FCAB000FCA6B7 /* PBXTargetDependency */,
                                D4F56BA5217FCAAA00FCA6B7 /* PBXTargetDependency */,
                                D4F56BBB2181387600FCA6B7 /* PBXTargetDependency */,
+                               0C2B36C323C42EBC00000718 /* PBXTargetDependency */,
                        );
                        name = Security_frameworks_watchos;
                        productName = Security_frameworks_watchos;
                        buildPhases = (
                        );
                        dependencies = (
+                               0CCC22D023F39A6A00E1FCD0 /* PBXTargetDependency */,
+                               6CC638FE2266AE0A00E5DB0B /* PBXTargetDependency */,
+                               6CC639002266AE0A00E5DB0B /* PBXTargetDependency */,
                                EB694E8B223AB7A200F02C1C /* PBXTargetDependency */,
                                EB694DD0223A087700F02C1C /* PBXTargetDependency */,
                                EB694DC82239E5F200F02C1C /* PBXTargetDependency */,
                                D4A763E32224BDF90063B2B9 /* PBXTargetDependency */,
                                D4A763E12224BDED0063B2B9 /* PBXTargetDependency */,
                                D4A763DF2224BDDC0063B2B9 /* PBXTargetDependency */,
-                               D4A763DD2224BDCC0063B2B9 /* PBXTargetDependency */,
-                               D4A763DB2224BDAB0063B2B9 /* PBXTargetDependency */,
                                D4A763D92224BD990063B2B9 /* PBXTargetDependency */,
                                D4A763D52224BD6F0063B2B9 /* PBXTargetDependency */,
                                D4A763D32224BD640063B2B9 /* PBXTargetDependency */,
                                D477EE7B21ED48C000C9AAFF /* PBXTargetDependency */,
                                D477EE7D21ED48CB00C9AAFF /* PBXTargetDependency */,
                                D477EE7F21ED48D500C9AAFF /* PBXTargetDependency */,
-                               D477EE8321ED48E800C9AAFF /* PBXTargetDependency */,
                                D477EE8121ED48DF00C9AAFF /* PBXTargetDependency */,
                                EBB8521022F793A200424FD0 /* PBXTargetDependency */,
+                               6C61D3E8242A29BA008AB9BB /* PBXTargetDependency */,
+                               3E88361D24F08F5400E9F4D6 /* PBXTargetDependency */,
                        );
                        name = Security_tests_osx;
                        productName = Security_test_macos;
                        buildPhases = (
                        );
                        dependencies = (
+                               0CCC22CE23F39A6300E1FCD0 /* PBXTargetDependency */,
+                               6C2D797522C06CEF00C3CE32 /* PBXTargetDependency */,
+                               6C2D797322C06CEB00C3CE32 /* PBXTargetDependency */,
                                EB694E89223AB79B00F02C1C /* PBXTargetDependency */,
                                EB694DCE223A086C00F02C1C /* PBXTargetDependency */,
                                EB694DC42239E5A200F02C1C /* PBXTargetDependency */,
-                               D4E0E97A2224DEE600A802E0 /* PBXTargetDependency */,
                                D45D8F882224DC3F00D6C124 /* PBXTargetDependency */,
                                D45D8F862224DBF800D6C124 /* PBXTargetDependency */,
-                               D45D8F842224DBEF00D6C124 /* PBXTargetDependency */,
                                D45D8F822224DBE300D6C124 /* PBXTargetDependency */,
                                D45D8F7E2224DBD900D6C124 /* PBXTargetDependency */,
                                D45D8F7C2224DBC600D6C124 /* PBXTargetDependency */,
                                EB58A0621E74C8E4009C10D7 /* PBXTargetDependency */,
                                EB10557D1E14DFB60003C309 /* PBXTargetDependency */,
                                BE9C38D31EB11605007E2AE1 /* PBXTargetDependency */,
-                               47D991D020407F7E0078CAE2 /* PBXTargetDependency */,
                                EBB8521222F793AC00424FD0 /* PBXTargetDependency */,
                        );
                        name = Security_tests_ios;
                                DC647C44208A85BE00D0F9F8 /* PBXTargetDependency */,
                                DC58C4431D77C1F8003C25A4 /* PBXTargetDependency */,
                                D4F56BB32181306900FCA6B7 /* PBXTargetDependency */,
+                               0C65BB4D23C3F31B0063D2B7 /* PBXTargetDependency */,
                        );
                        name = Security_frameworks_osx;
                        productName = Security_frameworks_macos;
                        buildPhases = (
                        );
                        dependencies = (
+                               6C7BE2EA23C3DD9C003BB2CA /* PBXTargetDependency */,
                                47455B24205B3E2F008FE980 /* PBXTargetDependency */,
                                D41257F71E941E9600781F23 /* PBXTargetDependency */,
                        );
                091B39732063B67700ECAB6F /* RemoteServiceDiscovery.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 091B396D2063B64A00ECAB6F /* RemoteServiceDiscovery.framework */; };
                0940F6F82151316500C06F18 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; };
                0940F6F92151316600C06F18 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; };
-               096C647020AB1BC700D7B7D5 /* KeychainEntitlementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */; };
-               09BFE35C20A32E0E008511E9 /* KeychainEntitlementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */; };
+               097CE59F246966A100958AF8 /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D690911652E06A0079537A /* libMobileGestalt.dylib */; };
                09CB49701F2F64E300C8E4DE /* si-44-seckey-fv.m in Sources */ = {isa = PBXBuildFile; fileRef = 09CB496A1F2F64AF00C8E4DE /* si-44-seckey-fv.m */; };
                09EF431B21A5A8CC0066CF20 /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; };
                0C00FC86217A980100C8BF00 /* OTLocalCuttlefishReset.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C00FC81217A971800C8BF00 /* OTLocalCuttlefishReset.m */; };
+               0C0203E623A857C1005D0A68 /* OTEscrowRecord.proto in Sources */ = {isa = PBXBuildFile; fileRef = 0C0203E023A8564E005D0A68 /* OTEscrowRecord.proto */; };
                0C0582C620D9CA4800D7BD7A /* OTClique.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CDBCD8620AD03FB007F8EA7 /* OTClique.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0C0582CC20D9CA4900D7BD7A /* OTClique.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CDBCD8620AD03FB007F8EA7 /* OTClique.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0C0BDB32175685B000BC1A7E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0BDB31175685B000BC1A7E /* main.m */; };
                0C0BDB931756A8C900BC1A7E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
                0C0C4F86216FB73C00C14C61 /* EscrowKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0C4F83216FB55600C14C61 /* EscrowKeys.swift */; };
                0C0C4F87216FB73F00C14C61 /* BottledPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0C4F84216FB56B00C14C61 /* BottledPeer.swift */; };
+               0C0CB73923AD714D0020C6BF /* Container_EscrowRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0CB73723AD71400020C6BF /* Container_EscrowRecords.swift */; };
+               0C0CB73A23AD715A0020C6BF /* Container_EscrowRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0CB73723AD71400020C6BF /* Container_EscrowRecords.swift */; };
+               0C0CB73B23AD71650020C6BF /* Container_EscrowRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0CB73723AD71400020C6BF /* Container_EscrowRecords.swift */; };
                0C0CECA41DA45ED700C22FBC /* recovery_key.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0CEC9E1DA45EA200C22FBC /* recovery_key.m */; };
+               0C0D920C23BFEAB30070A68C /* OTCDPRecoveryInformation.proto in Sources */ = {isa = PBXBuildFile; fileRef = 0C0D920523BFEA740070A68C /* OTCDPRecoveryInformation.proto */; };
                0C0DA5CE1FE1EAB9003BD3BB /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
                0C0DA5CF1FE1F1C5003BD3BB /* OTControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0D1FCB452300580909 /* OTControlProtocol.m */; };
                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 */; };
                0C12B1F12138D31600BE0A98 /* OTClientStateMachine.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */; };
+               0C147A2823F39CD10034F08B /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
                0C16371C1FD116B300210823 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; };
                0C1637271FD2065400210823 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
                0C1637291FD2066A00210823 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                0C1B8BB72233244F0094D5DA /* OTVouchWithRecoveryKeyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */; };
                0C29BF222323288C003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; };
                0C29BF2523232897003C807E /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; };
+               0C2B32A423C4000F00A97B18 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               0C2B32A523C4001900A97B18 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
                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 */; };
                0C2BCBCF1D0648EF00ED7A2F /* dtlsEchoServer.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C2BCBA61D063F7D00ED7A2F /* dtlsEchoServer.c */; };
                0C2F337220DD64930031A92D /* OTRamping.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337120DD647D0031A92D /* OTRamping.m */; };
                0C2F337320DD64940031A92D /* OTRamping.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F337120DD647D0031A92D /* OTRamping.m */; };
+               0C3810F123EF6FC4002D7E19 /* OctagonTrust.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CD743A623C3EC8000FA0EC5 /* OctagonTrust.framework */; };
                0C38AA92212B2D1900C90A1D /* OTEpochOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C4F4DE121153659007F7E20 /* OTEpochOperation.h */; };
                0C38AA96212B2D1E00C90A1D /* OTClientVoucherOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC8A9002123AA3B005D7F6A /* OTClientVoucherOperation.h */; };
                0C38AA98212B2D2300C90A1D /* OTJoinWithVoucherOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC8A9052123AF16005D7F6A /* OTJoinWithVoucherOperation.h */; };
                0C3BB3582188E18C0018FC14 /* OTPrivateKey+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3522188E18A0018FC14 /* OTPrivateKey+SF.m */; };
                0C3BB35A2188E18C0018FC14 /* OTAuthenticatedCiphertext+SF.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3BB3542188E18B0018FC14 /* OTAuthenticatedCiphertext+SF.m */; };
                0C3C00731EF3636500AB19FE /* secd-155-otr-negotiation-monitor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C00721EF3636300AB19FE /* secd-155-otr-negotiation-monitor.m */; };
+               0C3C47C624902D960084B951 /* OTSupportOctagonMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C47C024902D450084B951 /* OTSupportOctagonMessage.m */; };
+               0C3C47C724902D960084B951 /* OTSupportSOSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C47C324902D460084B951 /* OTSupportSOSMessage.m */; };
+               0C3C47C824902DA50084B951 /* OTSupportSOSMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C47C324902D460084B951 /* OTSupportSOSMessage.m */; };
+               0C3C47C924902DA50084B951 /* OTSupportOctagonMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C3C47C024902D450084B951 /* OTSupportOctagonMessage.m */; };
+               0C3DF8C824789C3C009CF03A /* Container_Peers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3DF8C524789C04009CF03A /* Container_Peers.swift */; };
+               0C3DF8C924789D06009CF03A /* Container_Peers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3DF8C524789C04009CF03A /* Container_Peers.swift */; };
+               0C3DF8CA24789D0A009CF03A /* Container_Peers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C3DF8C524789C04009CF03A /* Container_Peers.swift */; };
                0C3E316B21372FA50093C04B /* OctagonPairingTests+ProximitySetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604812134DD5D00BFBBB8 /* OctagonPairingTests+ProximitySetup.swift */; };
+               0C468FE123C7D487006F4582 /* OTEscrowRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FDE23C7D471006F4582 /* OTEscrowRecord.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FE223C7D487006F4582 /* OTEscrowRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */; };
+               0C468FE323C7D487006F4582 /* OTEscrowRecordMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FDA23C7D41D006F4582 /* OTEscrowRecordMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FE423C7D487006F4582 /* OTEscrowRecordMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */; };
+               0C468FE523C7D487006F4582 /* OTEscrowRecordMetadataClientMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FDB23C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FE623C7D487006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */; };
+               0C468FEF23C7D4D5006F4582 /* OTCDPRecoveryInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FEA23C7D4C8006F4582 /* OTCDPRecoveryInformation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FF023C7D4D5006F4582 /* OTCDPRecoveryInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FEE23C7D4CA006F4582 /* OTCDPRecoveryInformation.m */; };
+               0C468FF123C7D4D5006F4582 /* OTEscrowAuthenticationInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FE823C7D4C8006F4582 /* OTEscrowAuthenticationInformation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FF223C7D4D5006F4582 /* OTEscrowAuthenticationInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FEC23C7D4C9006F4582 /* OTEscrowAuthenticationInformation.m */; };
+               0C468FF323C7D4D5006F4582 /* OTICDPRecordContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FE723C7D4C7006F4582 /* OTICDPRecordContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FF423C7D4D5006F4582 /* OTICDPRecordContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FED23C7D4C9006F4582 /* OTICDPRecordContext.m */; };
+               0C468FF523C7D4D5006F4582 /* OTICDPRecordSilentContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C468FE923C7D4C8006F4582 /* OTICDPRecordSilentContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C468FF623C7D4D5006F4582 /* OTICDPRecordSilentContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FEB23C7D4C9006F4582 /* OTICDPRecordSilentContext.m */; };
+               0C468FF723C7D4E3006F4582 /* OTEscrowRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */; };
+               0C468FF823C7D4E3006F4582 /* OTEscrowRecordMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */; };
+               0C468FF923C7D4E3006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */; };
+               0C468FFA23C7D4EF006F4582 /* OTEscrowRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */; };
+               0C468FFB23C7D4EF006F4582 /* OTEscrowRecordMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */; };
+               0C468FFC23C7D4EF006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */; };
+               0C468FFD23C7D4F9006F4582 /* OTEscrowRecord.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */; };
+               0C468FFE23C7D4F9006F4582 /* OTEscrowRecordMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */; };
+               0C468FFF23C7D4F9006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */; };
                0C46A5712034C6BA00F17112 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.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 */; };
                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 */; };
                0C4CDE6F22922E550050C499 /* OctagonTests+RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C4CDE6D22922E360050C499 /* OctagonTests+RecoveryKey.swift */; };
-               0C4D96A621F24E5700617E60 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               0C4D96A721F25F2C00617E60 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
                0C4F4DE221153E9E007F7E20 /* OTEpochOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C4F4DDA211535E8007F7E20 /* OTEpochOperation.m */; };
                0C5258BA21BB062F00B32C96 /* FakeSOSControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C5258B821BB05C100B32C96 /* FakeSOSControl.m */; };
                0C5258BB21BB128000B32C96 /* FakeSOSControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C5258B821BB05C100B32C96 /* FakeSOSControl.m */; };
                0C5258BD21BB137900B32C96 /* FakeSOSControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C5258BC21BB137800B32C96 /* FakeSOSControl.h */; };
-               0C5663EC20BE2DF30035F362 /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; };
-               0C5663EF20BE2E220035F362 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
+               0C570B7923F3A015001FEB3B /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
+               0C570B7B23F3A09A001FEB3B /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
+               0C570B7C23F3A0E3001FEB3B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; };
+               0C570B8123F3A1EC001FEB3B /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
                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 */; };
                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 */; };
+               0C64C0802485B2EF00D84A5D /* OTPreloadOctagonKeysOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C64C07C2485A53000D84A5D /* OTPreloadOctagonKeysOperation.m */; };
                0C66046A2134983900BFBBB8 /* OTEstablishOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C6604692134983900BFBBB8 /* OTEstablishOperation.m */; };
                0C66047E2134CA5600BFBBB8 /* OTDeviceInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C66047B2134C88C00BFBBB8 /* OTDeviceInformation.m */; };
-               0C6C0FCB21F1415B00CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               0C6C0FCF21F1457600CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               0C6C0FD021F145F600CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               0C6C0FD121F1465500CD5B9E /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               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 */; };
-               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 */; };
                0C78F1CD16A5E1BF00654E08 /* sectask-10-sectask.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C78F1CA16A5E1BF00654E08 /* sectask-10-sectask.c */; };
                0C78F1CE16A5E1BF00654E08 /* sectask_ipc.defs in Sources */ = {isa = PBXBuildFile; fileRef = 0C78F1CB16A5E1BF00654E08 /* sectask_ipc.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                0C78F1CF16A5E1BF00654E08 /* sectask_ipc.defs in Sources */ = {isa = PBXBuildFile; fileRef = 0C78F1CB16A5E1BF00654E08 /* sectask_ipc.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
                0C78F1D016A5E3EB00654E08 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; };
+               0C79213D23C3F6E100193389 /* OctagonTrust.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD743B723C3ED7E00FA0EC5 /* OctagonTrust.m */; };
                0C7A8BBF21714CDC00F4C480 /* OTJoiningConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */; };
                0C7A8BC021714D0E00F4C480 /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                0C84D8341FCF43AF00B822E3 /* OTControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0D1FCB452300580909 /* OTControlProtocol.m */; };
                0C8FD52521483EF20098E3FB /* OT.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCCC7C820261D310024405E /* OT.m */; };
                0C97867D235A77230040A867 /* com.apple.security.signposts.plist in Copy System logging profile */ = {isa = PBXBuildFile; fileRef = 0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */; };
                0C98122821ACCC9300784441 /* OTClique.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F336A20DD643B0031A92D /* OTClique.m */; };
-               0C9AEEAF20783FBB00BF6237 /* SFSignInAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */; };
-               0C9AEEBB20783FF900BF6237 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
-               0C9AEEBE207843D000BF6237 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; };
-               0C9FB40720D872A600864612 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
-               0C9FB40920D8735500864612 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
+               0C9A54B6250C286100FF007B /* OctagonTrustTests+Errors.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C9A54B4250C27F100FF007B /* OctagonTrustTests+Errors.m */; };
+               0C9F65AD23E3AD2E00B1A2C5 /* OTEscrowTranslation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C9F65AC23E3ACF700B1A2C5 /* OTEscrowTranslation.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0C9F65AE23E3AD3200B1A2C5 /* OTEscrowTranslation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C9F65AA23E3ACF700B1A2C5 /* OTEscrowTranslation.m */; };
+               0CA1D0B923E9034600021038 /* OctagonTests+EscrowTestVectors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CA1D0B223E9023100021038 /* OctagonTests+EscrowTestVectors.swift */; };
                0CA2282F2187A5CA00A1C56C /* BottledPeer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0C4F84216FB56B00C14C61 /* BottledPeer.swift */; };
                0CA378E723876DFC00090B7E /* reset_ick_account in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0C7382F023863AD5004F98CB /* reset_ick_account */; };
                0CA4B4722171410200B17169 /* EscrowKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C0C4F83216FB55600C14C61 /* EscrowKeys.swift */; };
                0CB8DC9A2194B14C0021A7C8 /* OTVouchWithBottleOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */; };
                0CB9754F2023A8F5008D6B48 /* CloudKitMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.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 */; };
                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 */; };
-               0CBFEACC200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               0CBFEACD200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0CBF883D23AAD9F100652EDD /* OctagonTests+EscrowRecords.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CBF883A23AAD9DC00652EDD /* OctagonTests+EscrowRecords.swift */; };
                0CC319241DA46FBF005D42EA /* ProtectedCloudStorage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43DB542E1BB1F85B0083C3F1 /* ProtectedCloudStorage.framework */; };
-               0CC3771320A222BC00B58D2D /* SFSignInAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */; };
                0CC593F02299B9AA006C34B5 /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; };
                0CC593F62299EC3D006C34B5 /* OTDeviceInformationAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DC19484B21812EC5007C2260 /* OTDeviceInformationAdapter.m */; };
                0CC593F92299EE06006C34B5 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
                0CC8A8FE2123A9F6005D7F6A /* OTClientVoucherOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CC8A8FA2123A9EB005D7F6A /* OTClientVoucherOperation.m */; };
                0CC8A9032123AF06005D7F6A /* OTJoinWithVoucherOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CC8A9012123AEF7005D7F6A /* OTJoinWithVoucherOperation.m */; };
+               0CC9403023F39E84004B71AA /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
+               0CCC21FC23F33DA900E1FCD0 /* OTICDPRecordContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FED23C7D4C9006F4582 /* OTICDPRecordContext.m */; };
+               0CCC21FD23F33DCE00E1FCD0 /* OTCDPRecoveryInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FEE23C7D4CA006F4582 /* OTCDPRecoveryInformation.m */; };
+               0CCC21FE23F33DD400E1FCD0 /* OTEscrowAuthenticationInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C468FEC23C7D4C9006F4582 /* OTEscrowAuthenticationInformation.m */; };
+               0CCC21FF23F3577A00E1FCD0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; };
+               0CCC22A023F367D100E1FCD0 /* OctagonTrustTests-EscrowRecords.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCC229F23F367D100E1FCD0 /* OctagonTrustTests-EscrowRecords.m */; };
+               0CCC22A423F374EB00E1FCD0 /* OctagonTrust.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CD743A623C3EC8000FA0EC5 /* OctagonTrust.framework */; };
+               0CCC22A523F3763C00E1FCD0 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
+               0CCC22A623F3868400E1FCD0 /* OTControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C8BBF0E1FCB452400580909 /* OTControl.m */; };
+               0CCC22A823F38AD600E1FCD0 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
+               0CCC22A923F38AFD00E1FCD0 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
+               0CCC22AE23F38B2D00E1FCD0 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
+               0CCC22B223F38B5B00E1FCD0 /* libsqlite3.0.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22B123F38B5B00E1FCD0 /* libsqlite3.0.tbd */; };
+               0CCC22B323F38B6D00E1FCD0 /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
+               0CCC22B623F38BCD00E1FCD0 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4911167209558900066A1E4 /* CoreData.framework */; };
+               0CCC22B723F38BF500E1FCD0 /* CloudKitMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */; };
+               0CCC22B823F38C0E00E1FCD0 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; };
+               0CCC22B923F38C3000E1FCD0 /* CKKSMockSOSPresentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA9BC06221B7AFB00B4EB26 /* CKKSMockSOSPresentAdapter.m */; };
+               0CCC22BB23F38C8800E1FCD0 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
+               0CCC22BC23F38D3500E1FCD0 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
+               0CCC22BD23F38D4B00E1FCD0 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EB49B2DC202DF251003F34A0 /* libbsm.tbd */; };
+               0CCC22BE23F38D7C00E1FCD0 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
+               0CCC22BF23F38D8E00E1FCD0 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
+               0CCC22C023F38DA100E1FCD0 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
+               0CCC22C123F38DC100E1FCD0 /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; };
+               0CCC22C723F3904D00E1FCD0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
+               0CCC22C823F390E400E1FCD0 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D1838B1FB3827700CFCD89 /* OCMock.framework */; };
+               0CCC22C923F3932600E1FCD0 /* CloudKitKeychainSyncingTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CA4EBF2202B8D1D002B1D96 /* CloudKitKeychainSyncingTestsBase.m */; };
+               0CCC22CA23F3933000E1FCD0 /* CloudKitKeychainSyncingMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */; };
+               0CCC22D623F39B2E00E1FCD0 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
+               0CCC22D723F39B7200E1FCD0 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
+               0CCC22D823F39BCA00E1FCD0 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
                0CCDE7171EEB08220021A946 /* secd-156-timers.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CCDE7161EEB08220021A946 /* secd-156-timers.m */; };
                0CD3D519224048A800024755 /* OTSetRecoveryKeyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD3D5152240479600024755 /* OTSetRecoveryKeyOperation.m */; };
+               0CD5040523F39DEA0036C279 /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */; };
                0CD5797A21498F8200C43496 /* OctagonPairingTests+Piggybacking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CD5797721498F7700C43496 /* OctagonPairingTests+Piggybacking.swift */; };
+               0CD743AA23C3EC8000FA0EC5 /* OctagonTrust.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD743A823C3EC8000FA0EC5 /* OctagonTrust.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               0CD743AF23C3ECEB00FA0EC5 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; };
+               0CD743BB23C3EF1D00FA0EC5 /* OTClique+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD743BA23C3EF0D00FA0EC5 /* OTClique+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0CD743BC23C3EF1E00FA0EC5 /* OTClique+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD743BA23C3EF0D00FA0EC5 /* OTClique+Private.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0CD8CB051ECA50780076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; };
                0CD8CB0B1ECA50920076F37F /* SOSPeerOTRTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */; };
                0CD9E34323592DD7002995DE /* OctagonSignPosts.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CD9E33E235928D1002995DE /* OctagonSignPosts.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0CD9E34523592EA6002995DE /* OctagonSignPosts.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E340235928E9002995DE /* OctagonSignPosts.m */; };
                0CD9E34623592EA7002995DE /* OctagonSignPosts.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CD9E340235928E9002995DE /* OctagonSignPosts.m */; };
                0CDD6F79226E83F6009094C2 /* OTTriggerEscrowUpdateOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */; };
-               0CE079F41FEA15B20040A3F1 /* SFBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */; };
                0CE15E2C222DF63600B7EAA4 /* RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA4 /* RecoveryKey.swift */; };
                0CE15E2D222DF63600B7EAA4 /* RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA4 /* RecoveryKey.swift */; };
                0CE15E2F222DF63600B7EAA4 /* RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CE15E2A222DF63500B7EAA4 /* RecoveryKey.swift */; };
                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 */; };
-               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 */; };
                0CE760541E13155100B4381E /* SOSAccountTrustClassic+Circle.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CE760531E13155100B4381E /* SOSAccountTrustClassic+Circle.h */; };
                0CE887D32299A9090082D120 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                0CE887D52299A9C70082D120 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
                0CE902352395D0A3005E3F8C /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
-               0CF406522072E422003D6A7F /* SFSignInAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */; };
                0CF70BD9218BED1000EC3515 /* CuttlefishExtensionWorkaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF70BD6218BECF500EC3515 /* CuttlefishExtensionWorkaround.swift */; };
                0CF70BDA218BEFAE00EC3515 /* CuttlefishExtensionWorkaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF70BD6218BECF500EC3515 /* CuttlefishExtensionWorkaround.swift */; };
                0CF70BDB218BEFF000EC3515 /* CuttlefishExtensionWorkaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF70BD6218BECF500EC3515 /* CuttlefishExtensionWorkaround.swift */; };
                3DD1FF9F201FC5410086D049 /* STLegacyTests+sslciphers.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE81201AA5100086D049 /* STLegacyTests+sslciphers.m */; };
                3DD1FFA0201FC5450086D049 /* STLegacyTests+tls12.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE7D201AA50E0086D049 /* STLegacyTests+tls12.m */; };
                3DD1FFA1201FC5660086D049 /* ssl-utils.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCA451D8B82CD00070CB0 /* ssl-utils.c */; };
-               3DD1FFA2201FC5800086D049 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
                3DD1FFA3201FC5870086D049 /* libDiagnosticMessagesClient.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */; };
                3DD1FFA4201FC58F0086D049 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                3DD1FFA5201FC59D0086D049 /* libsecurity_ssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BC9CF1D8B824700070CB0 /* libsecurity_ssl.a */; };
                3DD1FFC6201FDB1D0086D049 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
                3DD1FFC8201FDB1D0086D049 /* libsecurity_ssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BC9CF1D8B824700070CB0 /* libsecurity_ssl.a */; };
                3DD1FFC9201FDB1D0086D049 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
-               3DD1FFCB201FDB1D0086D049 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
                3DD1FFD1201FDC460086D049 /* STLegacyTests+clientauth41.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE78201AA50C0086D049 /* STLegacyTests+clientauth41.m */; };
                3DD1FFD5201FF7860086D049 /* SecureTransport_iosTests.plist in Copy Plist */ = {isa = PBXBuildFile; fileRef = 3DD1FE86201AA5120086D049 /* SecureTransport_iosTests.plist */; };
                3DD1FFD7201FF7B10086D049 /* SecureTransport_macosTests.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3DD1FE79201AA50D0086D049 /* SecureTransport_macosTests.plist */; };
                3DD2589F20478CF900F5DA78 /* STLegacyTests+session.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */; };
                3DD258A020478CFA00F5DA78 /* STLegacyTests+session.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */; };
                3DD258AC2051F10300F5DA78 /* STLegacyTests+sni.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DD1FE7F201AA50F0086D049 /* STLegacyTests+sni.m */; };
+               3E88360D24F068EF00E9F4D6 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
+               3E88361424F0699F00E9F4D6 /* secseccodeapitest.c in Sources */ = {isa = PBXBuildFile; fileRef = 3E88361324F0699F00E9F4D6 /* secseccodeapitest.c */; };
+               3E88361B24F08DA100E9F4D6 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                433E519E1B66D5F600482618 /* AppSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 433E519D1B66D5F600482618 /* AppSupport.framework */; };
                4381603A1B4DCE8F00C54D58 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
                4381603B1B4DCEFF00C54D58 /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; };
                4718AE92205B39C40068EC3F /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.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 */; };
                4718AE99205B39C40068EC3F /* SFKeychainServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 47FF17251FD60ACA00875565 /* SFKeychainServer.m */; };
                4718AE9B205B39C40068EC3F /* swcagent_client.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78EA01D80860C00865A7C /* swcagent_client.c */; };
                4718AE9E205B39C40068EC3F /* SecDbKeychainSerializedAKSWrappedKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 47922D371FAA7C040008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.h */; };
                4727FBC91F991E5A0003AE36 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                4727FBCD1F991F660003AE36 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBCC1F991F660003AE36 /* libsqlite3.dylib */; };
                4727FBCE1F991F820003AE36 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBCF1F991F820003AE36 /* SecurityFoundation.framework */; };
-               4727FBD11F991F990003AE36 /* libMobileGestalt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD01F991F990003AE36 /* libMobileGestalt.dylib */; };
                4727FBD31F9920290003AE36 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD21F9920290003AE36 /* CloudKit.framework */; };
                4727FBD51F9920510003AE36 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD41F9920510003AE36 /* ProtocolBuffer.framework */; };
                4727FBD61F9920960003AE36 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
                475F37201EE8F23900248FB5 /* SFAnalytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = 475F371F1EE8F23900248FB5 /* SFAnalytics.plist */; };
                475F37211EE8F23900248FB5 /* SFAnalytics.plist in Resources */ = {isa = PBXBuildFile; fileRef = 475F371F1EE8F23900248FB5 /* SFAnalytics.plist */; };
                4764E9272059D866005497C9 /* KeychainModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 470D966B1FCDE4BA0065FE90 /* KeychainModel.xcdatamodeld */; };
-               4764E92D2059D8BF005497C9 /* KeychainModel.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 470D966B1FCDE4BA0065FE90 /* KeychainModel.xcdatamodeld */; };
                476541651F339F6300413F65 /* SecdWatchdog.h in Headers */ = {isa = PBXBuildFile; fileRef = 476541631F339F6300413F65 /* SecdWatchdog.h */; };
                476541701F33B59300413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541711F33B59500413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541A11F33EDA500413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541A21F33EDAD00413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541A31F33EDCC00413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
-               476541A41F33EDED00413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
-               476541A51F33EE1E00413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541A61F33EE2700413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                476541A71F33EE3F00413F65 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                47702B181E5E58E600B29577 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; };
                4771D9A0209B7C2700BA9772 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4771D99F209B7C2600BA9772 /* Security.framework */; };
                4771D9A2209B7C3900BA9772 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4771D9A1209B7C3900BA9772 /* Accounts.framework */; };
                477A1F5220320E4A00ACD81D /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 477A1F4C20320E4900ACD81D /* Accounts.framework */; };
-               477A1F5320320E5100ACD81D /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; };
                477A1FE4203763A500ACD81D /* KeychainAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 477A1FE1203763A500ACD81D /* KeychainAPITests.m */; };
-               477A1FE5203763A500ACD81D /* KeychainAPITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 477A1FE1203763A500ACD81D /* KeychainAPITests.m */; };
                477A1FED2037A0E000ACD81D /* KeychainXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 477A1FEC2037A0E000ACD81D /* KeychainXCTest.m */; };
-               477A1FEE2037A0E000ACD81D /* KeychainXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 477A1FEC2037A0E000ACD81D /* KeychainXCTest.m */; };
                478014541FBF577000C4043D /* si-44-seckey-proxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 09A3B9DF1F8271A200C5C324 /* si-44-seckey-proxy.m */; };
                4780146A1FBF5BD600C4043D /* SecKeyProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 09E9991F1F7D76550018DF67 /* SecKeyProxy.m */; };
                478014701FBF5BD800C4043D /* SecKeyProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 09E9991F1F7D76550018DF67 /* SecKeyProxy.m */; };
                478014791FBF5D2000C4043D /* SecKeyProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
                4780147F1FBF5D2100C4043D /* SecKeyProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 09A3B9D71F8267BB00C5C324 /* SecKeyProxy.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               478D42761FD72A8100CAB645 /* server_xpc.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB2214A1E8B0861001598BC /* server_xpc.m */; };
-               478D42771FD72A8100CAB645 /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; };
-               478D42781FD72A8100CAB645 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
-               478D42791FD72A8100CAB645 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
-               478D427A1FD72A8100CAB645 /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
-               478D427B1FD72A8100CAB645 /* KeychainCryptoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4727FBB91F9918590003AE36 /* KeychainCryptoTests.m */; };
-               478D427C1FD72A8100CAB645 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
-               478D427F1FD72A8100CAB645 /* libprequelite.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 472339611FD7155C00CB6A72 /* libprequelite.dylib */; };
-               478D42801FD72A8100CAB645 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D1838B1FB3827700CFCD89 /* OCMock.framework */; };
-               478D42811FD72A8100CAB645 /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; };
-               478D42821FD72A8100CAB645 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBE81F9921D00003AE36 /* libACM.a */; };
-               478D42831FD72A8100CAB645 /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBE61F9921890003AE36 /* ApplePushService.framework */; };
-               478D42841FD72A8100CAB645 /* SharedWebCredentials.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBE41F99217A0003AE36 /* SharedWebCredentials.framework */; };
-               478D42851FD72A8100CAB645 /* MobileKeyBag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBE21F9921660003AE36 /* MobileKeyBag.framework */; };
-               478D42861FD72A8100CAB645 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBE01F99212F0003AE36 /* IOKit.framework */; };
-               478D42871FD72A8100CAB645 /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBDE1F99211D0003AE36 /* libaks.a */; };
-               478D42881FD72A8100CAB645 /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBDC1F9920F10003AE36 /* libaks_acl.a */; };
-               478D42891FD72A8100CAB645 /* WirelessDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBDA1F9920CB0003AE36 /* WirelessDiagnostics.framework */; };
-               478D428A1FD72A8100CAB645 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD81F9920BB0003AE36 /* SystemConfiguration.framework */; };
-               478D428B1FD72A8100CAB645 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
-               478D428C1FD72A8100CAB645 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
-               478D428D1FD72A8100CAB645 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD41F9920510003AE36 /* ProtocolBuffer.framework */; };
-               478D428E1FD72A8100CAB645 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBD21F9920290003AE36 /* CloudKit.framework */; };
-               478D42901FD72A8100CAB645 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBCF1F991F820003AE36 /* SecurityFoundation.framework */; };
-               478D42911FD72A8100CAB645 /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBCC1F991F660003AE36 /* libsqlite3.dylib */; };
-               478D42931FD72A8100CAB645 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
-               478D42951FD72A8100CAB645 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; };
-               478D42961FD72A8100CAB645 /* libsecdRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EDB11D80D58400B0A59C /* libsecdRegressions.a */; };
-               478D42971FD72A8100CAB645 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBC41F991C460003AE36 /* Foundation.framework */; };
-               478D429E1FD72C4800CAB645 /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9391D7F3DF200AFB96E /* CrashReporterSupport.framework */; };
-               478D429F1FD72C8400CAB645 /* AppleSystemInfo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3F1D78F2FF002223DE /* AppleSystemInfo.framework */; };
                479108B71EE879F9008CEFA0 /* CKKSAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 479108B51EE879F9008CEFA0 /* CKKSAnalytics.h */; };
                4791B4652118BBFF00977C3F /* OTControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBF0C1FCB452200580909 /* OTControlProtocol.h */; settings = {ATTRIBUTES = (Private, ); }; };
                4791B46B2118BC0000977C3F /* OTControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBF0C1FCB452200580909 /* OTControlProtocol.h */; settings = {ATTRIBUTES = (Private, ); }; };
                47922D541FAA7E060008F7E0 /* SecDbKeychainSerializedItemV7.h in Headers */ = {isa = PBXBuildFile; fileRef = 47922D501FAA7DF60008F7E0 /* SecDbKeychainSerializedItemV7.h */; };
                47922D561FAA7E0D0008F7E0 /* SecDbKeychainSerializedItemV7.m in Sources */ = {isa = PBXBuildFile; fileRef = 47922D511FAA7DF70008F7E0 /* SecDbKeychainSerializedItemV7.m */; };
                479231E82065B31300B2718C /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
-               479231EE2065B32200B2718C /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
                479231EF2065C52200B2718C /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; };
                479231F02065C52D00B2718C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; };
                479DA1721EBBA8D10065C98F /* CKKSManifest.m in Sources */ = {isa = PBXBuildFile; fileRef = 47CEED1F1E60DE900044EAB4 /* CKKSManifest.m */; };
                47A05B181FDB5DBC00D0816E /* SFKeychainControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 47A05B101FDB5A8B00D0816E /* SFKeychainControl.h */; };
                47A0ABA81E6F7B24001B388C /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */; };
                47A91562201A43BA00FF8F46 /* SecSharedCredential.h in Headers */ = {isa = PBXBuildFile; fileRef = BE061FE01899ECEE00C739F6 /* SecSharedCredential.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               47B011991F17D78D0030B49F /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; };
                47B90C901F350966006500BC /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E9391D7F3DF200AFB96E /* CrashReporterSupport.framework */; };
                47C2F1762059A2300062DE30 /* libprequelite.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CE98B5B1FA9360700CF1D54 /* libprequelite.tbd */; };
                47C2F1842059CB680062DE30 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4727FBC41F991C460003AE36 /* Foundation.framework */; };
                482FE5642177C6850031C11E /* libprequelite.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CE98B5B1FA9360700CF1D54 /* libprequelite.tbd */; };
                482FE5652177C6D90031C11E /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; };
                482FE5662177C6E40031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
-               482FE5672177C7260031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
-               482FE5682177C73C0031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
                482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
-               482FE56A2177C7980031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
                482FE56C2177CEEF0031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
                482FE56D2177CF150031C11E /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
                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 */; };
+               487A65F4245B65F1005F51D6 /* secd-68-fullPeerInfoIntegrity.m in Sources */ = {isa = PBXBuildFile; fileRef = 487A65F3245B65F1005F51D6 /* secd-68-fullPeerInfoIntegrity.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 */; };
                48FE669620E6E69D00FAEF17 /* SOSAuthKitHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 48FE668F20E6E69B00FAEF17 /* SOSAuthKitHelpers.m */; };
                5A04BB1A22986717001848A0 /* SecXPCHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A04BB182298670C001848A0 /* SecXPCHelper.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5A06118E229ED5EB006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
                5A061191229ED6DB006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
-               5A061192229ED6E5006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
-               5A061193229ED6E6006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
                5A061194229ED6E7006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
                5A061196229ED6E8006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
                5A061197229ED6EB006AF14A /* NSDate+SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A06118D229ED5EB006AF14A /* NSDate+SFAnalytics.m */; };
-               5A061198229ED8F3006AF14A /* NSDate+SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               5A061199229ED8F4006AF14A /* NSDate+SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 5A061190229ED60C006AF14A /* NSDate+SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5A0F84A522AEAF5B0097AEEA /* NSDate+SFAnalyticsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A1A1C2122A71D2A00CB8D1D /* NSDate+SFAnalyticsTests.m */; };
                5A43A083225FA39C005450E4 /* SecProtocolHelperTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 5A43A07F225FA38D005450E4 /* SecProtocolHelperTest.m */; };
                5A43A084225FA3A5005450E4 /* SecProtocolTest.m in Sources */ = {isa = PBXBuildFile; fileRef = AA44E0B3202E3451001EA371 /* SecProtocolTest.m */; };
                5F00F9592306147A00B832E0 /* SecImportExport.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E551D8085FC00865A7C /* SecImportExport.c */; };
                5F00F95B230614AC00B832E0 /* SecImportExportPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                5F00F95C230614AD00B832E0 /* SecImportExportPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F00F95A230614A200B832E0 /* SecImportExportPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               5F4C22002489C6AB00F0C425 /* simulatecrash_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F4C21FE2489C68900F0C425 /* simulatecrash_assert.h */; };
+               5F4C22012489C6AC00F0C425 /* simulatecrash_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F4C21FE2489C68900F0C425 /* simulatecrash_assert.h */; settings = {ATTRIBUTES = (Public, ); }; };
                5F84950222DFB505008B3EFB /* SecTrustExceptionResetCount.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */; };
                6C02134E21F7ED25009D5C80 /* SecDbBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C02134D21F7ED16009D5C80 /* SecDbBackupTests.m */; };
-               6C02135021F7EF07009D5C80 /* SecDbBackupTests.plist in Copy BATS Test Discovery Plist */ = {isa = PBXBuildFile; fileRef = 6C02134C21F7ED16009D5C80 /* SecDbBackupTests.plist */; };
+               6C06CB902408602900025303 /* SecItemInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CEDF7370F3A6CFB0027C4FE /* SecItemInternal.h */; };
+               6C06CB912408602A00025303 /* SecItemInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CEDF7370F3A6CFB0027C4FE /* SecItemInternal.h */; };
                6C1260FD1F7DA42D001B2EEC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
                6C13AE471F8E9F5F00F047E3 /* supd.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69517E1F758E1000F68F91 /* supd.m */; };
                6C13AE481F8E9FC800F047E3 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                6C1520D41DCCF71400C85C6D /* secd.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = 6C1520CD1DCCF57A00C85C6D /* secd.8 */; };
+               6C16258723C4FFEC0086A0FF /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
+               6C16258823C5001C0086A0FF /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
                6C1F93111DD5E41A00585608 /* libDiagnosticMessagesClient.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3C1D78F25C002223DE /* libDiagnosticMessagesClient.dylib */; };
+               6C2045F12424BAC900F9461D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C99786D242362EC008C498D /* main.m */; };
+               6C2045F22424BACE00F9461D /* KeychainStasher.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C99786B242362EC008C498D /* KeychainStasher.m */; };
+               6C2045F42424BBCD00F9461D /* com.apple.security.KeychainStasher.sb in Install Sandbox Profile */ = {isa = PBXBuildFile; fileRef = 6C48D10F2423A3C0004AF950 /* com.apple.security.KeychainStasher.sb */; };
+               6C2045F52424BBDD00F9461D /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C997879242364E5008C498D /* Foundation.framework */; };
+               6C2045FB2424BCD600F9461D /* com.apple.security.KeychainStasher.plist in Install LaunchAgent plist */ = {isa = PBXBuildFile; fileRef = 6C2045F92424BCB800F9461D /* com.apple.security.KeychainStasher.plist */; };
+               6C2138C4225183FE007DEDD3 /* SecDbKeychainSerializedMetadataKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */; };
+               6C220088244F075E000A4557 /* SecItemRateLimit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C513A38244F007B00207D5E /* SecItemRateLimit.m */; };
+               6C22008A244F0760000A4557 /* SecItemRateLimit.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C513A38244F007B00207D5E /* SecItemRateLimit.m */; };
                6C23F02F227A3A28009F6756 /* com.apple.securityd.sb in Install Sandbox Profile */ = {isa = PBXBuildFile; fileRef = 6C23F02C227A39E9009F6756 /* com.apple.securityd.sb */; };
+               6C2D463D24C88AA10015C3C9 /* LegacyAPICounts.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C2D463B24C88A870015C3C9 /* LegacyAPICounts.m */; };
+               6C2D463E24C88AA60015C3C9 /* LegacyAPICounts.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C2D463924C88A700015C3C9 /* LegacyAPICounts.h */; };
                6C32BB9920EAE6B00042DF59 /* LocalKeychainAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C814A4B2050B4B600CB391B /* LocalKeychainAnalytics.m */; };
                6C32D36420F2C23100ACAB2C /* TPPBPolicyRedaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C70D8DE20EBDFD700AB6FAF /* TPPBPolicyRedaction.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6C32D36520F2C23D00ACAB2C /* TPPBPolicyDocument.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C0C807420EAF81900334E33 /* TPPBPolicyDocument.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6C588D801EAA20AB00D7E322 /* RateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC7F5B31E9F99EE0014AE63 /* RateLimiter.m */; };
                6C5B36BA1E2F9B95008AD443 /* WirelessDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C3D1E2537C6007F95E5 /* WirelessDiagnostics.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                6C5B36C01E2F9BEA008AD443 /* WirelessDiagnostics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C3D1E2537C6007F95E5 /* WirelessDiagnostics.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+               6C5D62A6221B6E3F00AF79DC /* secdxctests-entitlements.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6C5D62A5221B6E3F00AF79DC /* secdxctests-entitlements.plist */; };
+               6C61D3E9242A2C14008AB9BB /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
+               6C6AF17A221A06790091CE0A /* SecDbKeychainSerializedMetadataKey.proto in Sources */ = {isa = PBXBuildFile; fileRef = 6C6AF178221A03930091CE0A /* SecDbKeychainSerializedMetadataKey.proto */; };
+               6C6AF17F221A07090091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */; };
+               6C6AF180221A070A0091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */; };
+               6C6AF181221A070C0091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */; };
+               6C6AF182221A07230091CE0A /* SecDbKeychainSerializedMetadataKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C6AF17D221A06F70091CE0A /* SecDbKeychainSerializedMetadataKey.h */; };
+               6C6AF183221A07240091CE0A /* SecDbKeychainSerializedMetadataKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C6AF17D221A06F70091CE0A /* SecDbKeychainSerializedMetadataKey.h */; };
+               6C6B3AC623F1A820002827C2 /* KeychainEntitlementsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */; };
+               6C6B3ADF23F1B3E0002827C2 /* KeychainAppClipTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C84E3C723ECBC84003C9710 /* KeychainAppClipTests.m */; };
                6C7094CC2239D21E00C5DAC6 /* SecDbBackupManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C4AEF8B218A0A400012C5DA /* SecDbBackupManager.m */; };
                6C73F48A2006B839003D5D63 /* SOSAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C7BB0032006B4EE004D1B6B /* SOSAnalytics.m */; };
                6C73F48B2006B83A003D5D63 /* SOSAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C7BB0032006B4EE004D1B6B /* SOSAnalytics.m */; };
                6C73F48D2006B83E003D5D63 /* SOSAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C7BB0032006B4EE004D1B6B /* SOSAnalytics.m */; };
                6C73F48F2006B910003D5D63 /* SOSAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C7BB0042006B4EF004D1B6B /* SOSAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6C73F4902006B911003D5D63 /* SOSAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C7BB0042006B4EF004D1B6B /* SOSAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               6C75560624212B4400025D78 /* keychainstasherinterface.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C755603242121F000025D78 /* keychainstasherinterface.m */; };
+               6C7BE2B823C3DD64003BB2CA /* SecurityTool.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA981D80CC2A00B0A59C /* SecurityTool.c */; };
+               6C7BE2B923C3DD64003BB2CA /* scep.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E231D8085FC00865A7C /* scep.c */; };
+               6C7BE2BA23C3DD64003BB2CA /* trust_update.m in Sources */ = {isa = PBXBuildFile; fileRef = D453C38A1FEC669300DE349B /* trust_update.m */; };
+               6C7BE2BB23C3DD64003BB2CA /* keychain_backup.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E211D8085FC00865A7C /* keychain_backup.c */; };
+               6C7BE2BC23C3DD64003BB2CA /* whoami.m in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA911D80CC2A00B0A59C /* whoami.m */; };
+               6C7BE2BE23C3DD64003BB2CA /* KeychainCheck.m in Sources */ = {isa = PBXBuildFile; fileRef = 473337831FDB29A200E19F30 /* KeychainCheck.m */; };
+               6C7BE2BF23C3DD64003BB2CA /* log_control.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1D1D8085FC00865A7C /* log_control.c */; };
+               6C7BE2C023C3DD64003BB2CA /* not_on_this_platorm.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCDB41D8C6A5B00070CB0 /* not_on_this_platorm.c */; };
+               6C7BE2C123C3DD64003BB2CA /* keychain_util.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1A1D8085FC00865A7C /* keychain_util.c */; };
+               6C7BE2C223C3DD64003BB2CA /* security_tool_commands.c in Sources */ = {isa = PBXBuildFile; fileRef = E7104A0B169E171900DB0045 /* security_tool_commands.c */; };
+               6C7BE2C323C3DD64003BB2CA /* codesign.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1E1D8085FC00865A7C /* codesign.c */; };
+               6C7BE2C523C3DD64003BB2CA /* NSFileHandle+Formatting.m in Sources */ = {isa = PBXBuildFile; fileRef = E78A9AD91D34959200006B5B /* NSFileHandle+Formatting.m */; };
+               6C7BE2C623C3DD64003BB2CA /* keychain_find.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E201D8085FC00865A7C /* keychain_find.m */; };
+               6C7BE2C723C3DD64003BB2CA /* readline.c in Sources */ = {isa = PBXBuildFile; fileRef = DC65E7BE1D8CBB1500152EF0 /* readline.c */; };
+               6C7BE2C823C3DD64003BB2CA /* add_internet_password.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1C1D8085FC00865A7C /* add_internet_password.c */; };
+               6C7BE2C923C3DD64003BB2CA /* digest_calc.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */; };
+               6C7BE2CA23C3DD64003BB2CA /* leaks.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA931D80CC2A00B0A59C /* leaks.c */; };
+               6C7BE2CB23C3DD64003BB2CA /* show_certificates.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E251D8085FC00865A7C /* show_certificates.c */; };
+               6C7BE2CC23C3DD64003BB2CA /* spc.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E261D8085FC00865A7C /* spc.c */; };
+               6C7BE2CD23C3DD64003BB2CA /* verify_cert.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E191D8085FC00865A7C /* verify_cert.c */; };
+               6C7BE2CE23C3DD64003BB2CA /* ct_exceptions.m in Sources */ = {isa = PBXBuildFile; fileRef = D4A3A596217A85CB00F0A8DA /* ct_exceptions.m */; };
+               6C7BE2CF23C3DD64003BB2CA /* keychain_add.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E1F1D8085FC00865A7C /* keychain_add.c */; };
+               6C7BE2D023C3DD64003BB2CA /* pkcs12_util.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E221D8085FC00865A7C /* pkcs12_util.c */; };
+               6C7BE2D123C3DD64003BB2CA /* print_cert.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA951D80CC2A00B0A59C /* print_cert.c */; };
+               6C7BE2D423C3DD64003BB2CA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
+               6C7BE2D723C3DD64003BB2CA /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
+               6C7BE2D823C3DD64003BB2CA /* AggregateDictionary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72B368BD179891FC004C37CE /* AggregateDictionary.framework */; };
+               6C7BE2D923C3DD64003BB2CA /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E43C48C1B00D07000E5ECB2 /* CoreFoundation.framework */; };
+               6C7BE2DC23C3DD64003BB2CA /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; };
+               6C7BE2DD23C3DD64003BB2CA /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
+               6C7BE2E023C3DD64003BB2CA /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; };
+               6C7BE2E323C3DD64003BB2CA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
+               6C7BE2EB23C3DDC3003BB2CA /* libsecurityd_bridge.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4718AEE2205B39C40068EC3F /* libsecurityd_bridge.a */; };
                6C7FD5DF1F87FA42002C2285 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; };
                6C814A4C2050B4B600CB391B /* LocalKeychainAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C814A4A2050B4B600CB391B /* LocalKeychainAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6C814A4D2050B4B600CB391B /* LocalKeychainAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C814A4B2050B4B600CB391B /* LocalKeychainAnalytics.m */; };
                6C8CC3B61E2F98C2009025C5 /* ProtocolBuffer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6C0B0C441E2537CC007F95E5 /* ProtocolBuffer.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                6C8CE6C11FA248DA0032ADF0 /* SFAnalyticsActivityTracker+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C8CE6BB1FA248B50032ADF0 /* SFAnalyticsActivityTracker+Internal.h */; };
                6C8CE6C21FA248DB0032ADF0 /* SFAnalyticsActivityTracker+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C8CE6BB1FA248B50032ADF0 /* SFAnalyticsActivityTracker+Internal.h */; };
-               6C8FF4B3224C1A8D00E5C812 /* TrustedPeers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */; };
+               6C912AA0227A3E9600671FC6 /* CheckV12DevEnabled.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C4AEF83218A09210012C5DA /* CheckV12DevEnabled.m */; };
+               6C912AA1227A3E9700671FC6 /* CheckV12DevEnabled.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C4AEF83218A09210012C5DA /* CheckV12DevEnabled.m */; };
+               6C963284242A279B00C53CE2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C963283242A279B00C53CE2 /* main.m */; };
+               6C96328A242A284C00C53CE2 /* MobileKeyBag.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FC30AB1332DE9000802946 /* MobileKeyBag.framework */; };
+               6C97434824D1C8CB00A2025C /* LegacyAPICounts.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C2D463924C88A700015C3C9 /* LegacyAPICounts.h */; };
+               6C97434A24D1C8DE00A2025C /* LegacyAPICounts.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C2D463B24C88A870015C3C9 /* LegacyAPICounts.m */; };
                6C9791C821C20CFF0074C609 /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; };
                6C9791C921C2EAB60074C609 /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; };
-               6C9791CA21C2EAB70074C609 /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; };
                6C9791CB21C325C30074C609 /* SecDbBackupRecoverySet.proto in Sources */ = {isa = PBXBuildFile; fileRef = 6CB6CC022198D4BC0080AD6F /* SecDbBackupRecoverySet.proto */; };
-               6C98083E1E788AEB00E70590 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
-               6C98084A1E788AEB00E70590 /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; };
-               6C98084D1E788AEB00E70590 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
-               6C98084E1E788AEB00E70590 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
-               6C98084F1E788AEB00E70590 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; };
-               6C9808501E788AEB00E70590 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
-               6C9808511E788AEB00E70590 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; };
-               6C9808521E788AEB00E70590 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
-               6C9808531E788AEB00E70590 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; };
-               6C9808541E788AEB00E70590 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; };
-               6C9808551E788AEB00E70590 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
-               6C9808561E788AEB00E70590 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; };
-               6C9808571E788AEB00E70590 /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; };
-               6C9808581E788AEB00E70590 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; };
-               6C9808591E788AEB00E70590 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; };
-               6C98085A1E788AEB00E70590 /* libctkclient_sep.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient_sep.a */; };
-               6C98085B1E788AEB00E70590 /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC27B57D1DDFC24500599261 /* libsqlite3.0.dylib */; };
-               6C98085C1E788AEB00E70590 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; };
-               6C98087A1E788AFD00E70590 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
-               6C9808861E788AFD00E70590 /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; };
-               6C9808891E788AFD00E70590 /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
-               6C98088A1E788AFD00E70590 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
-               6C98088B1E788AFD00E70590 /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; };
-               6C98088C1E788AFD00E70590 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
-               6C98088D1E788AFD00E70590 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; };
-               6C98088E1E788AFD00E70590 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
-               6C98088F1E788AFD00E70590 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; };
-               6C9808901E788AFD00E70590 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; };
-               6C9808911E788AFD00E70590 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E71F3E3016EA69A900FAF9B4 /* SystemConfiguration.framework */; };
-               6C9808921E788AFD00E70590 /* libACM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC610A3A1D78F228002223DE /* libACM.a */; };
-               6C9808931E788AFD00E70590 /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; };
-               6C9808941E788AFD00E70590 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; };
-               6C9808951E788AFD00E70590 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; };
-               6C9808961E788AFD00E70590 /* libctkclient_sep.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient_sep.a */; };
-               6C9808971E788AFD00E70590 /* libsqlite3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC27B57D1DDFC24500599261 /* libsqlite3.0.dylib */; };
-               6C9808981E788AFD00E70590 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; };
-               6C9808A51E788CD100E70590 /* CKKSCloudKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDF7911E3C2D69003F2555 /* CKKSCloudKitTests.m */; };
-               6C9808A61E788CD200E70590 /* CKKSCloudKitTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CCDF7911E3C2D69003F2555 /* CKKSCloudKitTests.m */; };
                6C9AA7A11F7C1D9000D08296 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C9AA7A01F7C1D9000D08296 /* main.m */; };
                6C9AA7A51F7C6F7F00D08296 /* SecArgParse.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5BCC461E5380EA00649140 /* SecArgParse.c */; };
                6CA837642210CA8A002770F1 /* kc-45-change-password.c in Sources */ = {isa = PBXBuildFile; fileRef = 6CA837612210C5E7002770F1 /* kc-45-change-password.c */; };
-               6CAA8CDD1F82EDEF007B6E03 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
-               6CAA8CEE1F83E417007B6E03 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C32C0AF0A4975F6002891BD /* Security.framework */; };
-               6CAA8CEF1F83E65D007B6E03 /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; };
-               6CAA8CF01F83E65E007B6E03 /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; };
-               6CAA8CF61F83E79D007B6E03 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; };
-               6CAA8CF71F83E79E007B6E03 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; };
-               6CAA8CF81F83E7A9007B6E03 /* SFAnalyticsSQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69518D1F75A7DB00F68F91 /* SFAnalyticsSQLiteStore.m */; };
-               6CAA8CF91F83E7AA007B6E03 /* SFAnalyticsSQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69518D1F75A7DB00F68F91 /* SFAnalyticsSQLiteStore.m */; };
+               6CA9690A24ACC2D100C08B5E /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                6CAA8CFC1F83E7EA007B6E03 /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; };
                6CAA8CFD1F83E7EB007B6E03 /* SFObjCType.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BE1F152EB10082882F /* SFObjCType.m */; };
                6CAA8CFE1F83E800007B6E03 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; };
                6CAA8CFF1F83E800007B6E03 /* SFSQLite.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BC1F152EB10082882F /* SFSQLite.m */; };
-               6CAA8D0D1F83EC57007B6E03 /* SFSQLiteStatement.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9BF1F152EB10082882F /* SFSQLiteStatement.m */; };
-               6CAA8D131F83ECD4007B6E03 /* SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalytics.m */; };
-               6CAA8D141F83ECD5007B6E03 /* SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalytics.m */; };
                6CAA8D271F843002007B6E03 /* supd.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69517E1F758E1000F68F91 /* supd.m */; };
                6CAA8D351F84306C007B6E03 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6951801F758E1000F68F91 /* main.m */; };
                6CAA8D371F843196007B6E03 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                6CAA8D3A1F8431A7007B6E03 /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                6CAA8D3B1F8431AE007B6E03 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; };
                6CAB39C71E521BEA00566A79 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
+               6CB0C5F824ACDB5300479FB4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                6CB420A52051FDD500FF2D44 /* LocalKeychainAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C814A4B2050B4B600CB391B /* LocalKeychainAnalytics.m */; };
                6CB420AB2051FDE000FF2D44 /* LocalKeychainAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C814A4A2050B4B600CB391B /* LocalKeychainAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CB5F47B1E402E6700DBF3F0 /* KeychainEntitledTestRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */; };
                6CBF65401FA1480C00A68667 /* SFAnalyticsActivityTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CBF65371FA147E500A68667 /* SFAnalyticsActivityTracker.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CBF65411FA1481100A68667 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; };
                6CBF65421FA2255800A68667 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; };
-               6CBF65431FA2257100A68667 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; };
-               6CBF65441FA2257200A68667 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; };
                6CC1859E1E24E8EB009657D8 /* CKKSRateLimiter.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC185971E24E87D009657D8 /* CKKSRateLimiter.h */; };
                6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CC185981E24E87D009657D8 /* CKKSRateLimiter.m */; };
                6CC952481FB4CB2C0051A823 /* SFAnalytics+Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CC952421FB4C5CA0051A823 /* SFAnalytics+Internal.h */; };
                6CCDF78C1E3C26BC003F2555 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CCDF78B1E3C26BC003F2555 /* XCTest.framework */; };
                6CCDF78D1E3C26C2003F2555 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D40B6A881E2B5F9900CD6EE5 /* Foundation.framework */; };
                6CD1DBED21F9281D00D158FB /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
+               6CD224E623949132001B70FD /* SecDbBackupTestsBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C6579FC2394878700701C8B /* SecDbBackupTestsBase.m */; };
+               6CD8412C23F5D871003DDF34 /* KeychainBackupTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CD8412B23F5D871003DDF34 /* KeychainBackupTests.m */; };
                6CDB5FF51FA78D1A00410924 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
                6CDB5FF61FA78D1B00410924 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
-               6CDB5FF81FA78D2300410924 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
-               6CDB5FF91FA78D2400410924 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
                6CDB5FFA1FA78D2500410924 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
                6CDB5FFB1FA78D2C00410924 /* SFAnalyticsMultiSampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CDB5FF41FA78CB500410924 /* SFAnalyticsMultiSampler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CDB5FFC1FA78D2D00410924 /* SFAnalyticsMultiSampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CDB5FF41FA78CB500410924 /* SFAnalyticsMultiSampler.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CDB60111FA9386200410924 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                6CDB601A1FA93A1800410924 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CB96BB41F966E0C00E11457 /* libsqlite3.tbd */; };
                6CDB601B1FA93A2000410924 /* libprequelite.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CFDC4561F907E1D00646DBB /* libprequelite.tbd */; };
-               6CDF8DEF1F96495600140B54 /* SFAnalyticsSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDF8DE61F95562B00140B54 /* SFAnalyticsSampler.m */; };
-               6CDF8DF01F96495700140B54 /* SFAnalyticsSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDF8DE61F95562B00140B54 /* SFAnalyticsSampler.m */; };
                6CDF8DF21F9649AB00140B54 /* SFAnalyticsSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDF8DE61F95562B00140B54 /* SFAnalyticsSampler.m */; };
                6CDF8DF31F9649C000140B54 /* SFAnalyticsSQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C69518D1F75A7DB00F68F91 /* SFAnalyticsSQLiteStore.m */; };
                6CDF8DF41F9649C000140B54 /* SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalytics.m */; };
-               6CE22D701E49206600974785 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6CE22D6F1E49206600974785 /* UIKit.framework */; };
                6CE3654B1FA100D00012F6AB /* SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9DA1F1540CE0082882F /* SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CE3654C1FA100D10012F6AB /* SFAnalytics.h in Headers */ = {isa = PBXBuildFile; fileRef = 4723C9DA1F1540CE0082882F /* SFAnalytics.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6CE3654D1FA100E50012F6AB /* SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalytics.m */; };
                6CF4A0B81E45488B00ECD7B5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0B71E45488B00ECD7B5 /* AppDelegate.m */; };
                6CF4A0BB1E45488B00ECD7B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0BA1E45488B00ECD7B5 /* main.m */; };
                6CF4A0BE1E45488B00ECD7B5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0BD1E45488B00ECD7B5 /* ViewController.m */; };
-               6CF4A0E41E4549F200ECD7B5 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0E31E4549F200ECD7B5 /* main.m */; };
-               6CF4A0E71E4549F300ECD7B5 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0E61E4549F300ECD7B5 /* AppDelegate.m */; };
-               6CF4A0EA1E4549F300ECD7B5 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CF4A0E91E4549F300ECD7B5 /* ViewController.m */; };
                7200D76F177B9999009BB396 /* ManagedConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72C3EC2D1705F24E0040C87C /* ManagedConfiguration.framework */; };
                7281E0871DFD01800021E1B7 /* SOSAccountGetSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 7281E0861DFD015A0021E1B7 /* SOSAccountGetSet.m */; };
                7281E08D1DFD0B520021E1B7 /* XPCNotificationDispatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = E7C787331DD0FED50087FC34 /* XPCNotificationDispatcher.m */; };
                A690B033208A75D1002FB775 /* notarization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A6B1BA78207BD9D400F1E099 /* notarization.cpp */; };
                A6B1BA81207BD9EC00F1E099 /* notarization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A6B1BA78207BD9D400F1E099 /* notarization.cpp */; };
                A6B1BA82207BDCB200F1E099 /* notarization.h in Headers */ = {isa = PBXBuildFile; fileRef = A6B1BA79207BD9D400F1E099 /* notarization.h */; };
+               A6BC648824897C5E00A21CD7 /* CSCommonPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787441D7790A500B50D50 /* CSCommonPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A6BC6491248B0AB400A21CD7 /* SecStaticCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17874C1D7790A500B50D50 /* SecStaticCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               A6BF3B3623EB95F0009AF079 /* entitlements.h in Headers */ = {isa = PBXBuildFile; fileRef = A6BF3B3123EB94A7009AF079 /* entitlements.h */; };
+               A6C737B923F37A480009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
+               A6C737BA23F37A4B0009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
+               A6C737BB23F37AB00009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
+               A6C737BD23F37AB20009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
+               A6C737C023F37AB90009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
+               A6C737C123F37AC00009C930 /* entitlements.c in Sources */ = {isa = PBXBuildFile; fileRef = A6BF3B3223EB94A7009AF079 /* entitlements.c */; };
                AA0DA47A21E818AB009F1C74 /* builtins.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = AA0DA47921E8189E009F1C74 /* builtins.json */; };
                AA0DA47B21E818AB009F1C74 /* example1.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = AA0DA47821E8189D009F1C74 /* example1.json */; };
                AA0DA47D21E818D2009F1C74 /* builtins.json in CopyFiles */ = {isa = PBXBuildFile; fileRef = AA0DA47921E8189E009F1C74 /* builtins.json */; };
                BE197F5B1911723E00BA91D1 /* SpringBoardUIServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE197F5A1911723E00BA91D1 /* SpringBoardUIServices.framework */; };
                BE197F5C1911724900BA91D1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE411314471B000DE34E /* UIKit.framework */; };
                BE197F5E191173A800BA91D1 /* SWCViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BE197F5D191173A800BA91D1 /* SWCViewController.m */; };
-               BE197F61191173F200BA91D1 /* entitlements.plist in Resources */ = {isa = PBXBuildFile; fileRef = BE197F60191173F200BA91D1 /* entitlements.plist */; };
                BE22FBC61EE0E8AB00893431 /* Monkey.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBC51EE0E8AB00893431 /* Monkey.m */; };
                BE22FBCE1EE1E26600893431 /* Keychain.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBCD1EE1E26600893431 /* Keychain.m */; };
                BE22FBD11EE2084100893431 /* Config.m in Sources */ = {isa = PBXBuildFile; fileRef = BE22FBD01EE2084100893431 /* Config.m */; };
                BE536019209BB76B0027E25A /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA311DEE768000D0F733 /* CloudKit.framework */; };
                BE53601A209BB7F80027E25A /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                BE53601B209BB8390027E25A /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
-               BE53601C209BB8970027E25A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
                BE53602D209BBF630027E25A /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
                BE536030209BC1FD0027E25A /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
                BE536031209BC2F90027E25A /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                BE536034209BC3C40027E25A /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; };
                BE55C77C2044D0C90045863D /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE55C77B2044D0C90045863D /* Client.swift */; };
                BE55C77E2044D7E60045863D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE55C77D2044D7E60045863D /* main.swift */; };
+               BE57B1182509E1000045B7FD /* ca_revocation_additions.m in Sources */ = {isa = PBXBuildFile; fileRef = BE57B1162509E0FF0045B7FD /* ca_revocation_additions.m */; };
+               BE57B1192509E1000045B7FD /* ca_revocation_additions.m in Sources */ = {isa = PBXBuildFile; fileRef = BE57B1162509E0FF0045B7FD /* ca_revocation_additions.m */; };
+               BE57B11A2509E1000045B7FD /* ca_revocation_additions.m in Sources */ = {isa = PBXBuildFile; fileRef = BE57B1162509E0FF0045B7FD /* ca_revocation_additions.m */; };
                BE61F5AF1EB0060C00556CCF /* TrustedPeers.h in Headers */ = {isa = PBXBuildFile; fileRef = BEF88C641EB0005F00357577 /* TrustedPeers.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               BE6215BE1DB6E69100961E15 /* si-84-sectrust-allowlist.m in Sources */ = {isa = PBXBuildFile; fileRef = BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */; };
                BE64A7FA22AF006F001209F3 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 474B5FBF1E662E21007546F8 /* SecurityFoundation.framework */; };
                BE64A7FC22AF008D001209F3 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D848541C6C1D9C0025BB44 /* Foundation.framework */; };
                BE64A80022AF010B001209F3 /* trusted_cert_ssl.m in Sources */ = {isa = PBXBuildFile; fileRef = BE64A7FE22AF010A001209F3 /* trusted_cert_ssl.m */; };
                BE72782B209D27C800F0DA77 /* TPKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BE72782A209D27C800F0DA77 /* TPKeyTests.m */; };
                BE72782C209D2C1400F0DA77 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
                BE759DCB1917E38D00801E02 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE451314471B000DE34E /* CoreGraphics.framework */; };
+               BE7B8E132415579900E1CF4F /* SecSharedCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7B8E112415579800E1CF4F /* SecSharedCredential.m */; };
+               BE7B8E142415579900E1CF4F /* SecSharedCredential.m in Sources */ = {isa = PBXBuildFile; fileRef = BE7B8E112415579800E1CF4F /* SecSharedCredential.m */; };
+               BE7B8E152415580D00E1CF4F /* SecSharedCredential.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E8C1D8085FC00865A7C /* SecSharedCredential.c */; };
                BE8ABDD81DC2DD9100EC2D58 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; };
                BE92249E204F203C0052E828 /* TrustedPeersHelper.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BE92249C204F203C0052E828 /* TrustedPeersHelper.xcdatamodeld */; };
-               BE9B8B4A202BB4A20081EF87 /* si-88-sectrust-valid.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9B8B49202BB4A10081EF87 /* si-88-sectrust-valid.m */; };
-               BE9B8B4B202BB4D10081EF87 /* si-88-sectrust-valid-data in Resources */ = {isa = PBXBuildFile; fileRef = BE9B8B43202BB42C0081EF87 /* si-88-sectrust-valid-data */; };
-               BE9B8B4C202BB4E30081EF87 /* si-88-sectrust-valid-data in Resources */ = {isa = PBXBuildFile; fileRef = BE9B8B43202BB42C0081EF87 /* si-88-sectrust-valid-data */; };
-               BE9B8B4D202BB4F30081EF87 /* si-88-sectrust-valid-data in Resources */ = {isa = PBXBuildFile; fileRef = BE9B8B43202BB42C0081EF87 /* si-88-sectrust-valid-data */; };
                BE9F4F8C2072D881004A52C2 /* Cuttlefish.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F4F8B2072D881004A52C2 /* Cuttlefish.pb.swift */; };
                BE9F8D10206C099800B53D16 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D0F206C099800B53D16 /* Container.swift */; };
                BE9F8D12206C121400B53D16 /* Decrypter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D11206C121400B53D16 /* Decrypter.swift */; };
                BEAA0046202B785000E51F45 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7FCBE431314471B000DE34E /* Foundation.framework */; };
                BEB0B06E1FE9E81D007E6A83 /* TPPBPeerDynamicInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BE7089CF1FA3BA01001ACC20 /* TPPBPeerDynamicInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BEB0B06F1FE9E850007E6A83 /* TPPBPeerPermanentInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BE7089DD1FA40B93001ACC20 /* TPPBPeerPermanentInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               BEB0B0701FE9E8F6007E6A83 /* TPPBPeerStableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BE7089D41FA3BA04001ACC20 /* TPPBPeerStableInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               BEB0B0701FE9E8F6007E6A83 /* TPPBPeerStableInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BE7089D41FA3BA04001ACC20 /* TPPBPeerStableInfo.h */; settings = {ATTRIBUTES = (Public, ); }; };
                BEB0B0711FE9E936007E6A83 /* TPPBPolicySecret.h in Headers */ = {isa = PBXBuildFile; fileRef = BE7089D31FA3BA03001ACC20 /* TPPBPolicySecret.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BEB49F30206E98D0008DA7F4 /* TPECPublicKeyFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = BEB49F29206E98CD008DA7F4 /* TPECPublicKeyFactory.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BEB49F31206E98D0008DA7F4 /* TPECPublicKeyFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = BEB49F2F206E98CE008DA7F4 /* TPECPublicKeyFactory.m */; };
                D40B6A991E2B68A400CD6EE5 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */; };
                D40B6A9A1E2B68E800CD6EE5 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; };
                D40B6A9B1E2B690E00CD6EE5 /* SecuritydXPC.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E9A1D8085FC00865A7C /* SecuritydXPC.c */; };
-               D40B6A9D1E2B6A2700CD6EE5 /* login.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E8271D7A4F0E00AFB96E /* login.framework */; };
                D40B6A9E1E2B6A6F00CD6EE5 /* libtrustd.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D4ADA3191E2B41670031CEA3 /* libtrustd.a */; };
                D40B7CA021605BF800AC9A75 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; settings = {ATTRIBUTES = (Required, ); }; };
                D4119E78202BDF490048587B /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
                D418CC701E690CAD00330A44 /* MobileAsset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7273402816CAFB3C0096622A /* MobileAsset.framework */; };
                D418CC711E690CBC00330A44 /* MobileAsset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7273402816CAFB3C0096622A /* MobileAsset.framework */; };
                D41D36711EB14D87007FA978 /* libDiagnosticMessagesClient.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */; };
+               D423114323725F9F000E470A /* SMIMEPolicyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D423114223725F9F000E470A /* SMIMEPolicyTests.m */; };
+               D423114423725F9F000E470A /* SMIMEPolicyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D423114223725F9F000E470A /* SMIMEPolicyTests.m */; };
+               D4231148237261F8000E470A /* SMIMEPolicyTests-data in Resources */ = {isa = PBXBuildFile; fileRef = D4231147237261F7000E470A /* SMIMEPolicyTests-data */; };
+               D4231149237261F8000E470A /* SMIMEPolicyTests-data in Resources */ = {isa = PBXBuildFile; fileRef = D4231147237261F7000E470A /* SMIMEPolicyTests-data */; };
                D425EC1D1DD3C3CF00DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; };
                D425EC231DD3FFF200DE5DEC /* SecInternalRelease.c in Sources */ = {isa = PBXBuildFile; fileRef = DC0BCC761D8C68CF00070CB0 /* SecInternalRelease.c */; };
                D4267BD123440F8900B54678 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF730310EF9CDE300E17471 /* CFNetwork.framework */; };
                D458C517214E2C690043D982 /* si-20-sectrust-policies-data in Resources */ = {isa = PBXBuildFile; fileRef = D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */; };
                D458C51A214E2CC80043D982 /* si-20-sectrust-policies-data in Resources */ = {isa = PBXBuildFile; fileRef = D4EC94FA1CEA482D0083E753 /* si-20-sectrust-policies-data */; };
                D458C51C214E2DEB0043D982 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D458C4C5214E1A400043D982 /* Assets.xcassets */; };
-               D458C51D214E2DEB0043D982 /* Base.lproj in Resources */ = {isa = PBXBuildFile; fileRef = D458C4C7214E1A400043D982 /* Base.lproj */; };
                D458C51F214E2E0C0043D982 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D458C51E214E2E0C0043D982 /* Main.storyboard */; };
                D458C520214E33260043D982 /* ECTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AC5766214E195300A32C01 /* ECTests.m */; };
                D458C521214E33260043D982 /* ECTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AC5766214E195300A32C01 /* ECTests.m */; };
                D458C523214E33380043D982 /* KeySizeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AC5768214E195400A32C01 /* KeySizeTests.m */; };
                D458C524214E33430043D982 /* VerifyDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AC5764214E195200A32C01 /* VerifyDateTests.m */; };
                D458C525214E33440043D982 /* VerifyDateTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4AC5764214E195200A32C01 /* VerifyDateTests.m */; };
+               D458DAC32375FEA300E5890E /* TrustSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D458DAC22375FEA300E5890E /* TrustSettingsTests.m */; };
+               D458DAC42375FEA300E5890E /* TrustSettingsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D458DAC22375FEA300E5890E /* TrustSettingsTests.m */; };
                D45917E41DC13E6700752D25 /* SecCertificateRequest.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E3E1D8085FC00865A7C /* SecCertificateRequest.c */; };
+               D4593EFF24C131180069F577 /* SecTrustStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C1B442C0BB9CAF900461B82 /* SecTrustStore.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D46246971F9AE2E400D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246911F9AE2E400D63882 /* libDER.a */; };
                D46246A31F9AE59E00D63882 /* oids.h in Headers */ = {isa = PBXBuildFile; fileRef = D46246A21F9AE49E00D63882 /* oids.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D46246A81F9AE64000D63882 /* oids.h in Headers */ = {isa = PBXBuildFile; fileRef = D46246A21F9AE49E00D63882 /* oids.h */; settings = {ATTRIBUTES = (Public, ); }; };
                D46246B91F9AE79000D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
                D46246BA1F9AE7A000D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
                D46246BB1F9AE7B300D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
-               D46246BC1F9AE82B00D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
-               D46246BD1F9AE83600D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
                D46246BE1F9AE86400D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246AF1F9AE73F00D63882 /* libDER.a */; };
                D46246C91F9AEA5300D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246C31F9AEA5200D63882 /* libDER.a */; };
                D46246D41F9AEAE300D63882 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246CE1F9AEAE300D63882 /* libDER.a */; };
                D4707A2D2114C1E8005BCFDA /* SecCmsContentInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = D4707A2B2114B31A005BCFDA /* SecCmsContentInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D4707A2F2114C315005BCFDA /* SecCmsDigestContext.h in Headers */ = {isa = PBXBuildFile; fileRef = D4707A2E2114C30A005BCFDA /* SecCmsDigestContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
                D4707A302114C316005BCFDA /* SecCmsDigestContext.h in Headers */ = {isa = PBXBuildFile; fileRef = D4707A2E2114C30A005BCFDA /* SecCmsDigestContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               D477CB5C237B6E0E00C02355 /* PersonalizationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB5B237B6E0E00C02355 /* PersonalizationTests.m */; };
+               D477CB5D237B6E0E00C02355 /* PersonalizationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB5B237B6E0E00C02355 /* PersonalizationTests.m */; };
+               D477CB6A237CBA2C00C02355 /* TrustDaemonTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB69237CBA2C00C02355 /* TrustDaemonTestCase.m */; };
+               D477CB6B237CBA2C00C02355 /* TrustDaemonTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB69237CBA2C00C02355 /* TrustDaemonTestCase.m */; };
                D477CB78237E482800C02355 /* si-88-sectrust-valid-data in Resources */ = {isa = PBXBuildFile; fileRef = D477CB76237E453C00C02355 /* si-88-sectrust-valid-data */; };
                D477CB79237E484300C02355 /* si-88-sectrust-valid-data in Resources */ = {isa = PBXBuildFile; fileRef = D477CB76237E453C00C02355 /* si-88-sectrust-valid-data */; };
                D477CB7B237E4BD700C02355 /* ExceptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB7A237E4BD700C02355 /* ExceptionTests.m */; };
                D477CB7C237E4BD700C02355 /* ExceptionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB7A237E4BD700C02355 /* ExceptionTests.m */; };
+               D477CB82237F692400C02355 /* RevocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB81237F692400C02355 /* RevocationTests.m */; };
+               D477CB83237F692400C02355 /* RevocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB81237F692400C02355 /* RevocationTests.m */; };
+               D477CB87237F8B2F00C02355 /* CAIssuerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB86237F8B2F00C02355 /* CAIssuerTests.m */; };
+               D477CB88237F8B2F00C02355 /* CAIssuerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB86237F8B2F00C02355 /* CAIssuerTests.m */; };
+               D477CB8B237F8DBC00C02355 /* AllowlistBlocklistTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB8A237F8DBB00C02355 /* AllowlistBlocklistTests.m */; };
+               D477CB8C237F8DBC00C02355 /* AllowlistBlocklistTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB8A237F8DBB00C02355 /* AllowlistBlocklistTests.m */; };
+               D477CB8F237F975500C02355 /* ValidTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB8E237F975500C02355 /* ValidTests.m */; };
+               D477CB90237F975500C02355 /* ValidTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D477CB8E237F975500C02355 /* ValidTests.m */; };
                D479F6E21F980FAB00388D28 /* Trust.strings in Resources */ = {isa = PBXBuildFile; fileRef = D479F6DF1F980F8F00388D28 /* Trust.strings */; };
                D479F6E31F981FD600388D28 /* OID.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C198F1F0ACDB4BF00AAB142 /* OID.strings */; };
                D479F6E41F981FD600388D28 /* Certificate.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C198F1D0ACDB4BF00AAB142 /* Certificate.strings */; };
                D491116F209559510066A1E4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4911167209558900066A1E4 /* CoreData.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                D49111702095595B0066A1E4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4911167209558900066A1E4 /* CoreData.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                D4911172209559630066A1E4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4911167209558900066A1E4 /* CoreData.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
-               D4911173209559630066A1E4 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4911167209558900066A1E4 /* CoreData.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                D4961BC42079424200F16DA7 /* TrustURLSessionDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D4961BBD2079423300F16DA7 /* TrustURLSessionDelegate.m */; };
-               D49A370323873A580065719F /* RevocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370023873A570065719F /* RevocationTests.m */; };
-               D49A370423873A580065719F /* RevocationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370023873A570065719F /* RevocationTests.m */; };
-               D49A370623873BD30065719F /* TrustDaemonTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370523873BD30065719F /* TrustDaemonTestCase.m */; };
-               D49A370723873BD30065719F /* TrustDaemonTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370523873BD30065719F /* TrustDaemonTestCase.m */; };
+               D4981B8F24F723EA004B033B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; };
                D49A370C23877ECC0065719F /* OCSPCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370B23877ECC0065719F /* OCSPCacheTests.m */; };
                D49A370D23877ECC0065719F /* OCSPCacheTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D49A370B23877ECC0065719F /* OCSPCacheTests.m */; };
+               D49BD0742476F67700FC7E1C /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
+               D49BD0762476F74B00FC7E1C /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
+               D49BD0772476F7C000FC7E1C /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
+               D49BD07824770E2D00FC7E1C /* libMobileGestalt.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE53602C209BBF2F0027E25A /* libMobileGestalt.tbd */; };
                D4A0F8C2211E6A2F00443CA1 /* si-82-sectrust-ct-data in Resources */ = {isa = PBXBuildFile; fileRef = D4A0F8C1211E6A2F00443CA1 /* si-82-sectrust-ct-data */; };
                D4A0F8C7211E6A5800443CA1 /* TrustFrameworkTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = D4A0F8C4211E6A5700443CA1 /* TrustFrameworkTestCase.m */; };
                D4A0F8C8211E6A5800443CA1 /* CertificateInterfaceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4A0F8C6211E6A5700443CA1 /* CertificateInterfaceTests.m */; };
                D4D92DA622788FEB0009A7CF /* NISTTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4D92DA422788FEB0009A7CF /* NISTTests.m */; };
                D4D92DA8227890500009A7CF /* nist-certs in Resources */ = {isa = PBXBuildFile; fileRef = D4D92DA72278904F0009A7CF /* nist-certs */; };
                D4D92DA9227890500009A7CF /* nist-certs in Resources */ = {isa = PBXBuildFile; fileRef = D4D92DA72278904F0009A7CF /* nist-certs */; };
+               D4E6D8592404EAD40074CB26 /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246911F9AE2E400D63882 /* libDER.a */; };
                D4EA5CF822B225D100883439 /* LoggingServerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EA5CF622B225C000883439 /* LoggingServerTests.m */; };
                D4EA5CF922B225D100883439 /* LoggingServerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D4EA5CF622B225C000883439 /* LoggingServerTests.m */; };
                D4EF32172156B025000A31A5 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                D4FD4227217D7C4F002B7EE2 /* si-87-sectrust-name-constraints in Resources */ = {isa = PBXBuildFile; fileRef = D4C6C5C71FB2AD3F007EA57E /* si-87-sectrust-name-constraints */; };
                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, ); }; };
+               DA2F591823A32BC100C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F591E23A986A300C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F592123A9874800C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F592523A99E8400C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F592623A99EC900C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F592723A99F2900C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA2F592823A99F6300C30285 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
                DA30D6851DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m in Sources */ = {isa = PBXBuildFile; fileRef = DA30D6841DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.m */; };
                DA31CB212319DC8F0039F1CC /* TPStringTable.m in Sources */ = {isa = PBXBuildFile; fileRef = DA700FC82310C0E00051A7DE /* TPStringTable.m */; };
+               DA3862A723A9CD2E001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA3862A923AAD1FD001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA3862AA23AAD959001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA3862AB23AAE3A8001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA3862AC23AAE3D3001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA3862AE23AAE65E001E21F1 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
                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 */; };
+               DA53FC3923A9BA68002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC3C23A9BDD5002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC3D23A9BF28002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC3E23A9C180002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC3F23A9C26F002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4023A9C351002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4123A9C3CE002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4223A9C442002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4423A9C779002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4523A9C801002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4623A9CB13002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4723A9CBAA002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4823A9CC16002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
+               DA53FC4923A9CC8D002D5EA9 /* SoftLinking.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA2F591523A32BB400C30285 /* SoftLinking.framework */; };
                DA5B871C2065A8440093F083 /* SecAutorelease.h in Headers */ = {isa = PBXBuildFile; fileRef = DA5B871A2065A8410093F083 /* SecAutorelease.h */; };
                DA5B871D2065A8440093F083 /* SecAutorelease.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5B871B2065A8430093F083 /* SecAutorelease.m */; };
                DA6AA1651FE88AFB004565B0 /* CKKSControlServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6AA15E1FE88AF9004565B0 /* CKKSControlServer.m */; };
                DC00ABF11D821FC400513D74 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
                DC00ABF21D821FC800513D74 /* libSOSRegressions.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC681D80D0C400B0A59C /* libSOSRegressions.a */; };
                DC00ABF31D821FCD00513D74 /* libSecureObjectSyncServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E8C61D80C25800B0A59C /* libSecureObjectSyncServer.a */; };
-               DC00C91D20B3B79600628BEB /* libsecurity.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCC78EA91D8088E200865A7C /* libsecurity.a */; };
                DC00C92020B3B7CC00628BEB /* libDER.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D46246911F9AE2E400D63882 /* libDER.a */; };
                DC00C92320B3B80500628BEB /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EB49B2DC202DF251003F34A0 /* libbsm.tbd */; };
                DC00C92420B3B82600628BEB /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
                DC05037A21409A4100A8EDB7 /* OCMockUmbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = DC05037821409A4100A8EDB7 /* OCMockUmbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
                DC05038121409A6100A8EDB7 /* OCMock.framework in Embed OCMock */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
                DC05038221409B3400A8EDB7 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC3502E81E02172C00BC0587 /* OCMock.framework */; };
-               DC066DF02102563300694EAF /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
+               DC061A71246213660026ADB3 /* CKKSLocalResetOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC061A70246211DE0026ADB3 /* CKKSLocalResetOperation.m */; };
+               DC061A722462136F0026ADB3 /* CKKSOperationDependencies.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3412E6245780BA008ABD0A /* CKKSOperationDependencies.m */; };
                DC07090422936DB2002711B9 /* OctagonTests+ErrorHandling.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC07090222936BCC002711B9 /* OctagonTests+ErrorHandling.swift */; };
                DC08D1C41E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */; };
                DC08D1CC1E64FCC5006237DA /* CKKSSOSTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC08D1CB1E64FCC5006237DA /* CKKSSOSTests.m */; };
                DC1787261D778FDE00B50D50 /* SecManifest.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787241D778FDE00B50D50 /* SecManifest.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787271D778FDE00B50D50 /* SecureDownloadInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787251D778FDE00B50D50 /* SecureDownloadInternal.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787351D77903700B50D50 /* SecAccessPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787281D77903700B50D50 /* SecAccessPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               DC1787361D77903700B50D50 /* SecCertificateBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787291D77903700B50D50 /* SecCertificateBundle.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787371D77903700B50D50 /* SecFDERecoveryAsymmetricCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17872A1D77903700B50D50 /* SecFDERecoveryAsymmetricCrypto.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787381D77903700B50D50 /* SecIdentitySearchPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17872B1D77903700B50D50 /* SecIdentitySearchPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787391D77903700B50D50 /* SecKeychainItemExtendedAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = DC17872C1D77903700B50D50 /* SecKeychainItemExtendedAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787701D77911D00B50D50 /* osKeyTemplates.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787671D77911D00B50D50 /* osKeyTemplates.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787711D77911D00B50D50 /* secasn1t.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787681D77911D00B50D50 /* secasn1t.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787721D77911D00B50D50 /* X509Templates.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787691D77911D00B50D50 /* X509Templates.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               DC1787741D77915500B50D50 /* SecBreadcrumb.h in Headers */ = {isa = PBXBuildFile; fileRef = DC1787731D77915500B50D50 /* SecBreadcrumb.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787751D77916000B50D50 /* SecAccessControlPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 443381DA18A3D81400215606 /* SecAccessControlPriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787761D77916600B50D50 /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1787771D77916A00B50D50 /* SecDH.h in Headers */ = {isa = PBXBuildFile; fileRef = 7940D4110C3ACF9000FDB5D8 /* SecDH.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC1789281D779A0F00B50D50 /* libaks_acl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF8C1A01472C000958DC /* libaks_acl.a */; };
                DC1789291D779A2800B50D50 /* libctkclient_sep.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDD1AA0A45C0021AA26 /* libctkclient_sep.a */; };
                DC17892A1D779A3200B50D50 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; };
-               DC1789A21D779DF400B50D50 /* SecBreadcrumb.c in Sources */ = {isa = PBXBuildFile; fileRef = DC1789A01D779DEE00B50D50 /* SecBreadcrumb.c */; };
                DC1789A51D779E3B00B50D50 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC1789A41D779E3B00B50D50 /* dummy.cpp */; };
                DC1789E91D77A0F300B50D50 /* CloudKeychain.strings in Resources */ = {isa = PBXBuildFile; fileRef = 53C0E1F1177FAC2C00F8A018 /* CloudKeychain.strings */; };
                DC178A1F1D77A1E700B50D50 /* cssm.mdsinfo in Resources */ = {isa = PBXBuildFile; fileRef = DC178A0E1D77A1E700B50D50 /* cssm.mdsinfo */; };
                DC178A421D77A1F600B50D50 /* FDEPrefs.plist in Resources */ = {isa = PBXBuildFile; fileRef = DC178A311D77A1F500B50D50 /* FDEPrefs.plist */; };
                DC178A431D77A1F600B50D50 /* SecDebugErrorMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A321D77A1F500B50D50 /* SecDebugErrorMessages.strings */; };
                DC178A441D77A1F600B50D50 /* SecErrorMessages.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A331D77A1F500B50D50 /* SecErrorMessages.strings */; };
-               DC178A451D77A1F600B50D50 /* framework.sb in Resources */ = {isa = PBXBuildFile; fileRef = DC178A351D77A1F500B50D50 /* framework.sb */; };
                DC178A471D77A1F600B50D50 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A381D77A1F500B50D50 /* InfoPlist.strings */; };
                DC178A481D77A1F600B50D50 /* TimeStampingPrefs.plist in Resources */ = {isa = PBXBuildFile; fileRef = DC178A3A1D77A1F500B50D50 /* TimeStampingPrefs.plist */; };
                DC178A491D77A1F600B50D50 /* authorization.dfr.prompts.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC178A3B1D77A1F500B50D50 /* authorization.dfr.prompts.strings */; };
                DC222C361E02419B00B09171 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 107227350D91FE89003CF14F /* libbsm.dylib */; };
                DC222C8A1E089BAE00B09171 /* CKKSSQLTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222C891E089BAE00B09171 /* CKKSSQLTests.m */; };
                DC222CA81E08A7D900B09171 /* CloudKitMockXCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = DC222CA71E08A7D900B09171 /* CloudKitMockXCTest.m */; };
-               DC2353291ECA658300D7C1BE /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
-               DC23532F1ECA658400D7C1BE /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
-               DC2353301ECA658900D7C1BE /* server_security_helpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4269061E82FBDF002B7110 /* server_security_helpers.m */; };
-               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 */; };
                DC2C5F511F0D935300FEBDA7 /* CKKSControlProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DC2C5F5D1F0EB97E00FEBDA7 /* CKKSNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = DC2C5F5A1F0EB97E00FEBDA7 /* CKKSNotifier.h */; };
                DC2C5F601F0EB97E00FEBDA7 /* CKKSNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = DC2C5F5B1F0EB97E00FEBDA7 /* CKKSNotifier.m */; };
-               DC2D438F1F0EEC2A0005D382 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; };
-               DC2D43951F0EEC300005D382 /* MockCloudKit.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3502E61E0214C800BC0587 /* MockCloudKit.m */; };
                DC2FA71120E5770400DB7518 /* OTClique.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C2F336A20DD643B0031A92D /* OTClique.m */; };
                DC2FA72520E57AB500DB7518 /* SOSPeerInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D631D8085F200865A7C /* SOSPeerInfo.m */; };
                DC2FA72A20E57BFD00DB7518 /* SOSAccountTrust.m in Sources */ = {isa = PBXBuildFile; fileRef = CD31F8601DCD4C1400414B46 /* SOSAccountTrust.m */; };
                DC3D748C1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC3D748A1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.h */; };
                DC3D748E1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC3D748B1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m */; };
                DC3E18C82125015300073D80 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
-               DC3E18EB2125FB8700073D80 /* libaks_mock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC36895E21235F42003A3735 /* libaks_mock.a */; };
                DC4268F61E82036F002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
                DC4268FC1E820370002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
                DC4268FE1E820371002B7110 /* server_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6ACC401E81DF9400125DC5 /* server_endpoint.m */; };
                DC4A76A3221267D4006F2D8F /* EscrowRequestServerHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = DC4A76A2221267D4006F2D8F /* EscrowRequestServerHelpers.m */; };
                DC4A76A5221268A6006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
                DC4A76A62212691F006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
-               DC4A76A72212694F006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
-               DC4A76A822126959006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
-               DC4A76AA22126993006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
                DC4A76AB221269B8006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC4A76A92212698B006F2D8F /* CloudServices.framework */; };
                DC4A76AC221269E4006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
                DC4A76AD22126A17006F2D8F /* CloudServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C8A38C817B93DF10001B4C0 /* CloudServices.framework */; };
                DC52EDFA1D80D66600B0A59C /* SOSRegressionUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D0A1D8085F200865A7C /* SOSRegressionUtilities.m */; };
                DC52EE441D80D71900B0A59C /* si-21-sectrust-asr.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DBD1D8085FC00865A7C /* si-21-sectrust-asr.c */; };
                DC52EE451D80D71900B0A59C /* si-22-sectrust-iap.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DBE1D8085FC00865A7C /* si-22-sectrust-iap.c */; };
-               DC52EE471D80D71900B0A59C /* si-23-sectrust-ocsp.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC01D8085FC00865A7C /* si-23-sectrust-ocsp.c */; };
                DC52EE481D80D71900B0A59C /* si-24-sectrust-digicert-malaysia.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC11D8085FC00865A7C /* si-24-sectrust-digicert-malaysia.c */; };
                DC52EE491D80D71900B0A59C /* si-24-sectrust-diginotar.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC21D8085FC00865A7C /* si-24-sectrust-diginotar.c */; };
                DC52EE4A1D80D71900B0A59C /* si-24-sectrust-itms.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC31D8085FC00865A7C /* si-24-sectrust-itms.c */; };
                DC52EE4C1D80D71900B0A59C /* si-24-sectrust-passbook.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC51D8085FC00865A7C /* si-24-sectrust-passbook.c */; };
                DC52EE4D1D80D71900B0A59C /* si-26-sectrust-copyproperties.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC61D8085FC00865A7C /* si-26-sectrust-copyproperties.c */; };
-               DC52EE4F1D80D71900B0A59C /* si-28-sectrustsettings.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DC81D8085FC00865A7C /* si-28-sectrustsettings.m */; };
                DC52EE531D80D73800B0A59C /* si-44-seckey-gen.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD31D8085FC00865A7C /* si-44-seckey-gen.m */; };
                DC52EE541D80D73800B0A59C /* si-44-seckey-rsa.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD41D8085FC00865A7C /* si-44-seckey-rsa.m */; };
                DC52EE551D80D73800B0A59C /* si-44-seckey-ec.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD51D8085FC00865A7C /* si-44-seckey-ec.m */; };
                DC52EE561D80D73800B0A59C /* si-44-seckey-ies.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DD61D8085FC00865A7C /* si-44-seckey-ies.m */; };
-               DC52EE571D80D73800B0A59C /* si-67-sectrust-blocklist.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DF71D8085FC00865A7C /* si-67-sectrust-blocklist.c */; };
                DC52EE581D80D73800B0A59C /* si-70-sectrust-unified.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFA1D8085FC00865A7C /* si-70-sectrust-unified.c */; };
                DC52EE5A1D80D73800B0A59C /* si-83-seccertificate-sighashalg.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */; };
-               DC52EE601D80D79900B0A59C /* si-74-OTAPKISigner.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFE1D8085FC00865A7C /* si-74-OTAPKISigner.c */; };
                DC52EE611D80D79E00B0A59C /* si-71-mobile-store-policy.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78DFB1D8085FC00865A7C /* si-71-mobile-store-policy.c */; };
                DC52EE6F1D80D83F00B0A59C /* SecPasswordGenerate.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E7A1D8085FC00865A7C /* SecPasswordGenerate.c */; };
                DC52EE701D80D84700B0A59C /* SecItemConstants.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E5C1D8085FC00865A7C /* SecItemConstants.c */; };
                DC5AC0C21D83538D00CF422C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789241D7799CD00B50D50 /* CoreFoundation.framework */; };
                DC5AC0C41D8353BB00CF422C /* System.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC5AC0C31D8353B900CF422C /* System.framework */; };
                DC5AC0C51D8353C200CF422C /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
-               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 */; };
                DC5AC0D31D83544D00CF422C /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = DC17891E1D77999D00B50D50 /* libsqlite3.dylib */; };
                DC5AC0E61D8354CA00CF422C /* tokendatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABF9B1D83511A00CF422C /* tokendatabase.cpp */; };
                DC5AC0E71D8354CA00CF422C /* tokenkey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABF9D1D83511A00CF422C /* tokenkey.cpp */; };
                DC5AC0E81D8354CA00CF422C /* tokenaccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABF9F1D83511A00CF422C /* tokenaccess.cpp */; };
-               DC5AC0E91D8354CA00CF422C /* pcscmonitor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABFA31D83511A00CF422C /* pcscmonitor.cpp */; };
                DC5AC0EA1D8354CA00CF422C /* reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABFA51D83511A00CF422C /* reader.cpp */; };
                DC5AC0EB1D8354CA00CF422C /* token.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABFA71D83511A00CF422C /* token.cpp */; };
                DC5AC0EC1D8354CA00CF422C /* tokend.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC5ABFA91D83511A00CF422C /* tokend.cpp */; };
                DC5F35AE1EE0F27C00900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
                DC5F35AF1EE0F27C00900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
                DC5F35B01EE0F27C00900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
-               DC5F35B11EE0F28B00900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
-               DC5F35B21EE0F28C00900966 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
                DC5F65AE2225C22C0051E9FA /* CKKSProvideKeySetOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC5F65AC2225C22C0051E9FA /* CKKSProvideKeySetOperation.h */; };
                DC5F65AF2225C22C0051E9FA /* CKKSProvideKeySetOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5F65AD2225C22C0051E9FA /* CKKSProvideKeySetOperation.m */; };
                DC5F65B12225CD720051E9FA /* CKKSProvideKeySetOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC5F65AD2225C22C0051E9FA /* CKKSProvideKeySetOperation.m */; };
                DC60132E2147220600863C1A /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
-               DC6013312147220F00863C1A /* libaks_mock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC36895E21235F42003A3735 /* libaks_mock.a */; };
                DC6013392147227800863C1A /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
                DC6063B221B09AB200069B82 /* KCJoiningRequestCircleSession.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6063B121B09AB200069B82 /* KCJoiningRequestCircleSession.m */; };
                DC610A181D78F129002223DE /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0C0BDB31175685B000BC1A7E /* main.m */; };
                DC6D2C931DD2836500BE372D /* CKKSOutgoingQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = DC9B7AE61DCBF651004E9385 /* CKKSOutgoingQueueEntry.h */; };
                DC6DE899213076C000C6B56D /* OTSOSUpgradeOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC6DE897213076C000C6B56D /* OTSOSUpgradeOperation.h */; };
                DC6DE89C213076C000C6B56D /* OTSOSUpgradeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6DE898213076C000C6B56D /* OTSOSUpgradeOperation.m */; };
+               DC6E02162405DE3900C61335 /* OTModifyUserControllableViewStatusOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC6E02132405DDC400C61335 /* OTModifyUserControllableViewStatusOperation.m */; };
                DC71D85C1D94CCD40065FB93 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                DC71D8F51D959F150065FB93 /* com.apple.securityd.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */; };
                DC725030229600C000493D88 /* OctagonTests+Reset.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC72502D229600A800493D88 /* OctagonTests+Reset.swift */; };
                DC8506B52097F1FD00C712EC /* whoami.m in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA911D80CC2A00B0A59C /* whoami.m */; };
                DC8506B62097F39100C712EC /* libSOSCommands.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52EC341D80CFB200B0A59C /* libSOSCommands.a */; };
                DC85687E2284E7860088D3EF /* OctagonTestMocks.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC85687C2284E7850088D3EF /* OctagonTestMocks.swift */; };
+               DC86122C2408AC190092E93B /* CKKSTests+ItemSyncChoice.m in Sources */ = {isa = PBXBuildFile; fileRef = DC86122B2408AC190092E93B /* CKKSTests+ItemSyncChoice.m */; };
                DC8757F4218D2003000E65F1 /* OTRemovePeersOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC8757F2218D2003000E65F1 /* OTRemovePeersOperation.h */; };
                DC8757F5218D2003000E65F1 /* OTRemovePeersOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC8757F3218D2003000E65F1 /* OTRemovePeersOperation.m */; };
+               DC880F68243D4CC00059806D /* CKKSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DC880F67243D4CC00059806D /* CKKSLogging.m */; };
+               DC880F69243D4CE50059806D /* CKKSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DC880F67243D4CC00059806D /* CKKSLogging.m */; };
+               DC880F6A243D4D640059806D /* CKKSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DC880F67243D4CC00059806D /* CKKSLogging.m */; };
+               DC880F6B243D4D730059806D /* CKKSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DC880F67243D4CC00059806D /* CKKSLogging.m */; };
+               DC880F6C243D4DC00059806D /* CKKSLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = DC880F67243D4CC00059806D /* CKKSLogging.m */; };
                DC8834521D8A21AA00CE0ACA /* SecAsn1Coder.c in Sources */ = {isa = PBXBuildFile; fileRef = DC88340A1D8A21AA00CE0ACA /* SecAsn1Coder.c */; };
                DC8834541D8A21AA00CE0ACA /* SecAsn1Templates.c in Sources */ = {isa = PBXBuildFile; fileRef = DC88340C1D8A21AA00CE0ACA /* SecAsn1Templates.c */; };
                DC8834571D8A21AA00CE0ACA /* certExtensionTemplates.c in Sources */ = {isa = PBXBuildFile; fileRef = DC88340F1D8A21AA00CE0ACA /* certExtensionTemplates.c */; };
                DC926F081F33F7D30012A315 /* SecCodeHost.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD067981D8CDF7E007602F1 /* SecCodeHost.h */; settings = {ATTRIBUTES = (Public, ); }; };
                DC926F091F33FA8D0012A315 /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; };
                DC926F0A1F33FA8E0012A315 /* CKKSControlProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */; };
-               DC93C4C5214713C5008F8362 /* libaks_mock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC36895E21235F42003A3735 /* libaks_mock.a */; };
-               DC93C4CA214713E5008F8362 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
-               DC93C4CB214713ED008F8362 /* libaks_mock.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC36895E21235F42003A3735 /* libaks_mock.a */; };
-               DC93C4D021471FD8008F8362 /* libsecurityd_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC52E7C21D80BC8000B0A59C /* libsecurityd_ios.a */; };
                DC93F02922387A010072720A /* OTSOSUpdatePreapprovalsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DC93F02722387A010072720A /* OTSOSUpdatePreapprovalsOperation.h */; };
                DC93F02A22387A010072720A /* OTSOSUpdatePreapprovalsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC93F02822387A010072720A /* OTSOSUpdatePreapprovalsOperation.m */; };
+               DC947E8524638320005B8669 /* CKKSCheckKeyHierarchyOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DC947E832463831F005B8669 /* CKKSCheckKeyHierarchyOperation.m */; };
                DC94BCCA1F10448600E07CEB /* CloudKitCategories.h in Headers */ = {isa = PBXBuildFile; fileRef = DC94BCC81F10448600E07CEB /* CloudKitCategories.h */; };
                DC94BCCC1F10448600E07CEB /* CloudKitCategories.m in Sources */ = {isa = PBXBuildFile; fileRef = DC94BCC91F10448600E07CEB /* CloudKitCategories.m */; };
                DC96053F1ECA2D6400AF9BDA /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; };
                DC963E821D95EC1C008A153E /* libsecurity_codesigning.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCD068CB1D8CDFFE007602F1 /* libsecurity_codesigning.plist */; };
                DC963E841D95EC31008A153E /* libsecurity_codesigning.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = DCD068CC1D8CDFFE007602F1 /* libsecurity_codesigning.txt */; };
                DC963EC61D95F646008A153E /* der_plist.h in Headers */ = {isa = PBXBuildFile; fileRef = 524492931AFD6D480043695A /* der_plist.h */; };
+               DC9978B82404AA3200A5EE2F /* Container_UserSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9978B72404AA3200A5EE2F /* Container_UserSync.swift */; };
+               DC9978B92404AA3200A5EE2F /* Container_UserSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9978B72404AA3200A5EE2F /* Container_UserSync.swift */; };
+               DC9978BB2404B26900A5EE2F /* Container_UserSync.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9978B72404AA3200A5EE2F /* Container_UserSync.swift */; };
                DC99B86B20EACA470065B73B /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
                DC99B86C20EACA470065B73B /* FakeCuttlefish.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEA8557F20B5DC7D00D5AD11 /* FakeCuttlefish.swift */; };
                DC99B86D20EACA470065B73B /* SecdWatchdog.m in Sources */ = {isa = PBXBuildFile; fileRef = 476541641F339F6300413F65 /* SecdWatchdog.m */; };
                DCA4D1FF1E552DD50056214F /* CKKSCurrentKeyPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */; };
                DCA4D2151E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */; };
                DCA4D2171E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */; };
+               DCA7F7EF23A44AA200927989 /* OctagonPolicyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCA7F7EE23A44AA200927989 /* OctagonPolicyTests.swift */; };
                DCA85B931E8D97E400BA7241 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; };
                DCA85B941E8D97E400BA7241 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; };
                DCA85B971E8D980200BA7241 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; };
                DCA85B981E8D980A00BA7241 /* client_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC844AEC1E81F315007AAB71 /* client_endpoint.m */; };
                DCA85B991E8D980B00BA7241 /* client_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC844AEC1E81F315007AAB71 /* client_endpoint.m */; };
                DCA85B9B1E8D981200BA7241 /* client_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC844AEC1E81F315007AAB71 /* client_endpoint.m */; };
+               DCA992AD2400BB99007959AF /* TPPBAncientEpoch.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC373A820D810DA00DBDF5B /* TPPBAncientEpoch.proto */; };
                DCA9BC02221B721E00B4EB26 /* CKKSCloudKitClassDependencies.h in Headers */ = {isa = PBXBuildFile; fileRef = DCA9BC00221B721D00B4EB26 /* CKKSCloudKitClassDependencies.h */; };
                DCA9BC03221B721E00B4EB26 /* CKKSCloudKitClassDependencies.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA9BC01221B721E00B4EB26 /* CKKSCloudKitClassDependencies.m */; };
                DCA9BC07221B7AFB00B4EB26 /* CKKSMockSOSPresentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DCA9BC06221B7AFB00B4EB26 /* CKKSMockSOSPresentAdapter.m */; };
                DCAA209A23AAF8F600DCB594 /* Container_RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAA209823AAF8BD00DCB594 /* Container_RecoveryKey.swift */; };
                DCAA209B23AAF8FD00DCB594 /* Container_RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAA209823AAF8BD00DCB594 /* Container_RecoveryKey.swift */; };
                DCAA209C23AAF93700DCB594 /* Container_RecoveryKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAA209823AAF8BD00DCB594 /* Container_RecoveryKey.swift */; };
+               DCAAF3362493F9C600D4EB55 /* LocalAuthentication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EAFA4CD1EF16059002DC188 /* LocalAuthentication.framework */; };
                DCAB14271E40039600C81511 /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; };
                DCAB17CE21FFF75B00E1DFCF /* MockSynchronousEscrowServer.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAB17CC21FFF6C400E1DFCF /* MockSynchronousEscrowServer.m */; };
                DCAB17D12200D26900E1DFCF /* SecEscrowPendingRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = DCAB17CF2200D26700E1DFCF /* SecEscrowPendingRecord.h */; };
                DCB342FB1D8A32A20054D16E /* SecBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342441D8A32A20054D16E /* SecBase.cpp */; };
                DCB342FC1D8A32A20054D16E /* SecBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342451D8A32A20054D16E /* SecBridge.h */; };
                DCB342FD1D8A32A20054D16E /* SecCertificate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342461D8A32A20054D16E /* SecCertificate.cpp */; };
-               DCB342FE1D8A32A20054D16E /* SecCertificateBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342471D8A32A20054D16E /* SecCertificateBundle.cpp */; };
                DCB343001D8A32A20054D16E /* SecIdentity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342491D8A32A20054D16E /* SecIdentity.cpp */; };
                DCB343011D8A32A20054D16E /* SecIdentitySearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB3424A1D8A32A20054D16E /* SecIdentitySearch.cpp */; };
                DCB343021D8A32A20054D16E /* SecItemConstants.c in Sources */ = {isa = PBXBuildFile; fileRef = DCB3424B1D8A32A20054D16E /* SecItemConstants.c */; };
                DCB3435A1D8A32A20054D16E /* PolicyCursor.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342A51D8A32A20054D16E /* PolicyCursor.h */; };
                DCB3435B1D8A32A20054D16E /* SecCFTypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342A61D8A32A20054D16E /* SecCFTypes.cpp */; };
                DCB3435C1D8A32A20054D16E /* SecCFTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342A71D8A32A20054D16E /* SecCFTypes.h */; };
-               DCB3435D1D8A32A20054D16E /* SecKeychainAddIToolsPassword.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342A81D8A32A20054D16E /* SecKeychainAddIToolsPassword.cpp */; };
                DCB3435E1D8A32A20054D16E /* StorageManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342AA1D8A32A20054D16E /* StorageManager.cpp */; };
                DCB3435F1D8A32A20054D16E /* Trust.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DCB342AB1D8A32A20054D16E /* Trust.cpp */; };
                DCB343601D8A32A20054D16E /* Trust.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB342AC1D8A32A20054D16E /* Trust.h */; };
                DCB4584C2240396E00115F8C /* NSError+UsefulConstructors.m in Sources */ = {isa = PBXBuildFile; fileRef = DCAE1DD62073FCDE00B4F687 /* NSError+UsefulConstructors.m */; };
                DCB468DF20EC25FF00BA7E5B /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE55C77B2044D0C90045863D /* Client.swift */; };
                DCB468E520EC262C00BA7E5B /* ContainerMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE9F8D18206C4AD300B53D16 /* ContainerMap.swift */; };
-               DCB515DE1ED3CF86001F1152 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
-               DCB515DF1ED3CF95001F1152 /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
-               DCB515E01ED3D111001F1152 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; };
-               DCB515E11ED3D11A001F1152 /* client.c in Sources */ = {isa = PBXBuildFile; fileRef = 7908507F0CA87CF00083CC4D /* client.c */; };
-               DCB515E21ED3D134001F1152 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; };
-               DCB515E31ED3D135001F1152 /* SecTask.c in Sources */ = {isa = PBXBuildFile; fileRef = 107226D00D91DB32003CF14F /* SecTask.c */; };
-               DCB515E41ED3D15A001F1152 /* client_endpoint.m in Sources */ = {isa = PBXBuildFile; fileRef = DC844AEC1E81F315007AAB71 /* client_endpoint.m */; };
+               DCB55175247F48290009A859 /* CKKSDeleteCKZoneOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB55173247F48290009A859 /* CKKSDeleteCKZoneOperation.h */; };
+               DCB55176247F48290009A859 /* CKKSDeleteCKZoneOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB55174247F48290009A859 /* CKKSDeleteCKZoneOperation.m */; };
+               DCB55177247F483D0009A859 /* CKKSCreateCKZoneOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB5516B247F3DB50009A859 /* CKKSCreateCKZoneOperation.m */; };
                DCB5D93B1E4A9A3400BE22AB /* CKKSSynchronizeOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */; };
                DCB5D93D1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */; };
                DCB7D8C31D8E181B00867385 /* libsecurity_utilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD06AB01D8E0D53007602F1 /* libsecurity_utilities.a */; };
                DCB9475621274A1900ED9272 /* TPHObjcTranslation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB9475421274A1900ED9272 /* TPHObjcTranslation.m */; };
                DCB9475821274F9D00ED9272 /* TPHObjcTranslation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCB9475421274A1900ED9272 /* TPHObjcTranslation.m */; };
                DCB9475A2127534C00ED9272 /* OctagonTests+SOSUpgrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCB947592127534C00ED9272 /* OctagonTests+SOSUpgrade.swift */; };
+               DCBA6F2924105399009A5187 /* CKKSTests+ForwardCompatibility.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBA6F2824105399009A5187 /* CKKSTests+ForwardCompatibility.m */; };
                DCBB8AC41D80DD95007ED154 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */; };
                DCBDB3BB1E57CA7A00B61300 /* CKKSViewManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */; };
                DCBF4ABA21FFC82100539F0A /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
                DCBF4ABB21FFC82100539F0A /* SecFramework.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E4F1D8085FC00865A7C /* SecFramework.c */; };
                DCBF4ABE21FFC82100539F0A /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
-               DCBF4AC121FFC82100539F0A /* CoreCDP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C9FB40120D8729A00864612 /* CoreCDP.framework */; };
                DCBF4AC221FFC82100539F0A /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                DCBF4AC321FFC82100539F0A /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CF4C19C171E0EA600877419 /* Accounts.framework */; };
                DCBF4AC421FFC82100539F0A /* AppleAccount.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C84DA541720698900AEE225 /* AppleAccount.framework */; };
                DCBF4AE521FFC9B300539F0A /* SecEscrowRequestTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBF4AE321FFC9A800539F0A /* SecEscrowRequestTests.m */; };
                DCBFF832222611A200C5C044 /* OTFetchCKKSKeysOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCBFF830222611A200C5C044 /* OTFetchCKKSKeysOperation.h */; };
                DCBFF833222611A200C5C044 /* OTFetchCKKSKeysOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCBFF831222611A200C5C044 /* OTFetchCKKSKeysOperation.m */; };
+               DCC03FA423FF521100A4DA3F /* TPSyncingPolicy.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC03FA223FF521100A4DA3F /* TPSyncingPolicy.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               DCC03FA523FF521100A4DA3F /* TPSyncingPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC03FA323FF521100A4DA3F /* TPSyncingPolicy.m */; };
                DCC093791D80B02100F984E4 /* SecOnOSX.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78E671D8085FC00865A7C /* SecOnOSX.h */; };
                DCC0937A1D80B07200F984E4 /* SecOTRSessionPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFFC15AFB73800B9D400 /* SecOTRSessionPriv.h */; };
                DCC0937B1D80B07B00F984E4 /* SecOTRSession.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFFB15AFB73800B9D400 /* SecOTRSession.h */; };
                DCC093801D80B0B700F984E4 /* SecCFAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = D47F514B1C3B812500A7CEFE /* SecCFAllocator.h */; };
                DCC19518214C53FD00C9E0B6 /* AuthKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D4A7DD7320A26CF900F51F3F /* AuthKit.framework */; };
                DCC1951C214C668A00C9E0B6 /* AppleAccount.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C84DA541720698900AEE225 /* AppleAccount.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
+               DCC40B112383786D00402CB9 /* CKKSStates.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC40B0F2383786D00402CB9 /* CKKSStates.h */; };
+               DCC40B122383786D00402CB9 /* CKKSStates.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC40B102383786D00402CB9 /* CKKSStates.m */; };
                DCC51C99209B7C1500A40387 /* print_cert.c in Sources */ = {isa = PBXBuildFile; fileRef = DC52EA951D80CC2A00B0A59C /* print_cert.c */; };
                DCC54181225C05180095D926 /* OTUploadNewCKKSTLKsOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC5417F225C05170095D926 /* OTUploadNewCKKSTLKsOperation.h */; };
                DCC54182225C05180095D926 /* OTUploadNewCKKSTLKsOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC54180225C05180095D926 /* OTUploadNewCKKSTLKsOperation.m */; };
                DCC78EE51D808B2100865A7C /* SecBase64.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E351D8085FC00865A7C /* SecBase64.c */; };
                DCC78EE61D808B2A00865A7C /* SecAccessControl.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78E301D8085FC00865A7C /* SecAccessControl.m */; };
                DCC78EE71D808B2F00865A7C /* secViewDisplay.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D9E1D8085F200865A7C /* secViewDisplay.c */; };
-               DCCA5E841E539EE7009EE93D /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCCA5E831E539EE7009EE93D /* AppKit.framework */; };
                DCCBFA1E1DBA95CD001DD54D /* kc-20-item-delete-stress.c in Sources */ = {isa = PBXBuildFile; fileRef = DCCBFA1D1DBA95CD001DD54D /* kc-20-item-delete-stress.c */; };
                DCCBFA391DBAE445001DD54D /* SecInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C6416F00BB357D5001C83FD /* SecInternal.h */; settings = {ATTRIBUTES = (Private, ); }; };
                DCCD33C91E3FE95900AA4AD1 /* spi.c in Sources */ = {isa = PBXBuildFile; fileRef = DCC78CB01D8085D800865A7C /* spi.c */; };
                DCD8A20A1E09FB5900E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; settings = {ATTRIBUTES = (Weak, ); }; };
                DCD8A20B1E09FB5A00E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
                DCD8A20C1E09FB6600E4FA0A /* libSecureObjectSyncFramework.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */; };
+               DCDACB5924A3F38E0054080C /* com.apple.security.ckks.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = DCDACB5724A3F1AA0054080C /* com.apple.security.ckks.plist */; };
+               DCDACB5A24A3F39A0054080C /* com.apple.security.ckks.plist in Copy Logging Files */ = {isa = PBXBuildFile; fileRef = DCDACB5724A3F1AA0054080C /* com.apple.security.ckks.plist */; };
                DCDB296C1FD8820400B5D242 /* SFAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = 4723C9DB1F1540CE0082882F /* SFAnalytics.m */; };
                DCDB296E1FD8821400B5D242 /* SFAnalyticsActivityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBF65381FA147E500A68667 /* SFAnalyticsActivityTracker.m */; };
                DCDB29701FD8821800B5D242 /* SFAnalyticsMultiSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */; };
                DCDCCB391DF25D18006E840E /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA311DEE768000D0F733 /* CloudKit.framework */; };
                DCDCCB3A1DF25D1D006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; };
                DCDCCB3B1DF25D69006E840E /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA311DEE768000D0F733 /* CloudKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
-               DCDCCB3C1DF25D74006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; };
+               DCDCCB3C1DF25D74006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
                DCDCCB3E1DF25DA0006E840E /* ApplePushService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC9EBA231DEE36FE00D0F733 /* ApplePushService.framework */; };
                DCDCCB8F1DF7B8D4006E840E /* CKKSItem.h in Headers */ = {isa = PBXBuildFile; fileRef = DCDCCB8D1DF7B8D4006E840E /* CKKSItem.h */; };
                DCDCCB901DF7B8D4006E840E /* CKKSItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDCCB8E1DF7B8D4006E840E /* CKKSItem.m */; };
                DCE0774321ADD635002662FD /* TPPBPeerDynamicInfo.proto in Sources */ = {isa = PBXBuildFile; fileRef = BE7089CB1FA3B19A001ACC20 /* TPPBPeerDynamicInfo.proto */; };
                DCE0774621ADD638002662FD /* TPPBDisposition.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC3739B20CF2AA200DBDF5B /* TPPBDisposition.proto */; };
                DCE0774721ADD63A002662FD /* TPPBDispositionEntry.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC373C120D8224A00DBDF5B /* TPPBDispositionEntry.proto */; };
-               DCE0774821ADD63C002662FD /* TPPBAncientEpoch.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC373A820D810DA00DBDF5B /* TPPBAncientEpoch.proto */; };
                DCE0774921ADD63E002662FD /* TPPBPolicyProhibits.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC373A620D810D800DBDF5B /* TPPBPolicyProhibits.proto */; };
                DCE0774A21ADD640002662FD /* TPPBUnknownMachineID.proto in Sources */ = {isa = PBXBuildFile; fileRef = BEC373A720D810D900DBDF5B /* TPPBUnknownMachineID.proto */; };
                DCE0774B21ADD642002662FD /* TPPBPeerStableInfo.proto in Sources */ = {isa = PBXBuildFile; fileRef = BE7089CC1FA3B332001ACC20 /* TPPBPeerStableInfo.proto */; };
                DCE4E7AB1D7A43B500AFB96E /* Invalid-webmail.jaring.my.crt in Copy DigiCertMalaysia Resources */ = {isa = PBXBuildFile; fileRef = 79679E261462028800CF997F /* Invalid-webmail.jaring.my.crt */; };
                DCE4E7AC1D7A43B500AFB96E /* Invalid-www.cybersecurity.my.crt in Copy DigiCertMalaysia Resources */ = {isa = PBXBuildFile; fileRef = 794743191462137C00D638A3 /* Invalid-www.cybersecurity.my.crt */; };
                DCE4E7B51D7A43FF00AFB96E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E6D71D7A420D00AFB96E /* main.m */; };
-               DCE4E7B61D7A440A00AFB96E /* bc-10-knife-on-bread.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E6D41D7A41E400AFB96E /* bc-10-knife-on-bread.m */; };
                DCE4E7BF1D7A463400AFB96E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789041D77980500B50D50 /* Security.framework */; };
                DCE4E7C11D7A463E00AFB96E /* SecurityFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCE4E7C01D7A463E00AFB96E /* SecurityFoundation.framework */; };
                DCE4E7C61D7A468300AFB96E /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB2CA4D81D2C28C800AB770F /* libaks.a */; };
-               DCE4E7DF1D7A4B4C00AFB96E /* bc-10-knife-on-bread.m in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E6D41D7A41E400AFB96E /* bc-10-knife-on-bread.m */; };
                DCE4E7E21D7A4B7F00AFB96E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = DCE4E7E11D7A4B7F00AFB96E /* main.c */; };
                DCE4E7E41D7A4B8F00AFB96E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E7D848541C6C1D9C0025BB44 /* Foundation.framework */; };
                DCE4E7E71D7A4B9C00AFB96E /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC1789261D7799D300B50D50 /* IOKit.framework */; };
                DCEA5D571E2826DB0089CF55 /* CKKSSIV.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */; };
                DCEA5D851E2F14810089CF55 /* OctagonAPSReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = DCEA5D831E2F14810089CF55 /* OctagonAPSReceiver.h */; };
                DCEA5D871E2F14810089CF55 /* OctagonAPSReceiver.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D841E2F14810089CF55 /* OctagonAPSReceiver.m */; };
-               DCEA5D971E3015830089CF55 /* CKKSZone.m in Sources */ = {isa = PBXBuildFile; fileRef = DCEA5D961E3014250089CF55 /* CKKSZone.m */; };
                DCEDE3511D80B0FA00C3826E /* secd-71-engine-save-sample1.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78C651D8085D800865A7C /* secd-71-engine-save-sample1.h */; };
                DCEDE3901D80B10100C3826E /* SecOTRIdentityPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AF7FFF615AFB73800B9D400 /* SecOTRIdentityPriv.h */; };
                DCEDE3911D80B10800C3826E /* SecCTKKeyPriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCC78E451D8085FC00865A7C /* SecCTKKeyPriv.h */; };
                DCF94A7C222D9F2400C01744 /* OctagonCKKSPeerAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = DCF94A7A222D9F2400C01744 /* OctagonCKKSPeerAdapter.m */; };
                DCFABF8E20081E2F001128B5 /* CKKSDeviceStateUploadTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFABF8D20081E2F001128B5 /* CKKSDeviceStateUploadTests.m */; };
                DCFAEDCF1D999859005187E4 /* SOSAccountGhost.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEDC81D999851005187E4 /* SOSAccountGhost.m */; };
-               DCFAEDD21D99991F005187E4 /* secd-668-ghosts.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.m */; };
                DCFAEDD61D99A47A005187E4 /* secd-36-ks-encrypt.m in Sources */ = {isa = PBXBuildFile; fileRef = DCFAEDD51D99A464005187E4 /* secd-36-ks-encrypt.m */; };
                DCFAEDD71D99A4AB005187E4 /* secd-154-engine-backoff.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78C771D8085D800865A7C /* secd-154-engine-backoff.m */; };
                DCFB12C51E95A4C000510F5F /* CKKSAccountStateTracker.h in Headers */ = {isa = PBXBuildFile; fileRef = DCFB12C31E95A4C000510F5F /* CKKSAccountStateTracker.h */; };
                E7F482961C74FDF800390FDB /* KCJoiningSession.h in Headers */ = {isa = PBXBuildFile; fileRef = E7F480131C7397CE00390FDB /* KCJoiningSession.h */; settings = {ATTRIBUTES = (Public, ); }; };
                E7F482A11C7543E500390FDB /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; };
                E7F482A31C7544E600390FDB /* libctkclient_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7F482A21C7544E600390FDB /* libctkclient_test.a */; };
-               E7F482A61C75453900390FDB /* libcoreauthd_test_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */; };
                E7F482AA1C7554FB00390FDB /* NSError+KCCreationHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = E7F482A91C7554F500390FDB /* NSError+KCCreationHelpers.m */; };
                E7F482AC1C7558F700390FDB /* KCJoiningAcceptSession.m in Sources */ = {isa = PBXBuildFile; fileRef = E7F482AB1C7558F700390FDB /* KCJoiningAcceptSession.m */; };
                E7F482E61C7640D300390FDB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CBCE5A90BE7F69100FF81F5 /* IOKit.framework */; };
                EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = EB49B2DC202DF251003F34A0 /* libbsm.tbd */; };
                EB49B2E0202DF5D7003F34A0 /* server_entitlement_helpers.c in Sources */ = {isa = PBXBuildFile; fileRef = DC5F35A41EE0F1A900900966 /* server_entitlement_helpers.c */; };
                EB49B308202FF421003F34A0 /* OCMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 47D1838B1FB3827700CFCD89 /* OCMock.framework */; };
-               EB4B6E201DC0682A00AFC494 /* SecADWrapper.c in Sources */ = {isa = PBXBuildFile; fileRef = EBF3749A1DC064200065D840 /* SecADWrapper.c */; };
-               EB4B6E261DC0683600AFC494 /* SecADWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = EBF3749B1DC064200065D840 /* SecADWrapper.h */; };
                EB4E0CDB1FF36A9700CDCACC /* CKKSReachabilityTracker.m in Sources */ = {isa = PBXBuildFile; fileRef = EB4E0CD51FF36A1900CDCACC /* CKKSReachabilityTracker.m */; };
                EB58A0511E74BF07009C10D7 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D82BD316A5EADA0078DFE5 /* Security.framework */; };
                EB59D6731E95F01600997EAC /* libcompression.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB59D66B1E95EF2900997EAC /* libcompression.dylib */; };
                EB75B48C1E75407C00E469CC /* libutilities.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCC361D8C684F00070CB0 /* libutilities.a */; };
                EB75B48D1E75408900E469CC /* libASN1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC8834081D8A218F00CE0ACA /* libASN1.a */; };
                EB75B48F1E75409A00E469CC /* libsqlite3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CB740680A4749C800D641BB /* libsqlite3.dylib */; };
-               EB75B4901E7540AA00E469CC /* libctkclient_test.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4469FBDC1AA0A45C0021AA26 /* libctkclient_test.a */; };
-               EB75B4911E7540BF00E469CC /* libcoreauthd_test_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E8B53A41AA0B8A600345E7B /* libcoreauthd_test_client.a */; };
                EB75B4951E75A44100E469CC /* SOSPiggyback.h in Headers */ = {isa = PBXBuildFile; fileRef = EB75B4931E75A44100E469CC /* SOSPiggyback.h */; };
                EB76B7591DCB0CA200C43FBC /* CloudKeychainProxy.8 in Install man8 page */ = {isa = PBXBuildFile; fileRef = DC24B5851DA432E900330B48 /* CloudKeychainProxy.8 */; };
                EB7732C221963B0500FCF513 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
                EB7732D921963BA500FCF513 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EB80DE57219600CF005B10FA /* libz.dylib */; };
-               EB7732DB21963BC100FCF513 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D4119E72202BDF2B0048587B /* libz.tbd */; };
                EB78D3F91E600E93009AFE05 /* SOSCloudCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = DCC78D891D8085F200865A7C /* SOSCloudCircle.m */; };
                EB7AE6F81E86DACC00B80B15 /* SecPLWrappers.m in Sources */ = {isa = PBXBuildFile; fileRef = EB7AE6F61E86D55400B80B15 /* SecPLWrappers.m */; };
                EB7AE6F91E86DAD200B80B15 /* SecPLWrappers.h in Headers */ = {isa = PBXBuildFile; fileRef = EB7AE6F71E86D55400B80B15 /* SecPLWrappers.h */; };
                EB973651234E8F4B00518B2B /* CKKSPBFileStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = EB97364F234E8F4A00518B2B /* CKKSPBFileStorage.h */; };
                EB973652234E8F4B00518B2B /* CKKSPBFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = EB973650234E8F4B00518B2B /* CKKSPBFileStorage.m */; };
                EB9795B522FE9256002BDBFB /* SecItemTests.m in Sources */ = {isa = PBXBuildFile; fileRef = EB6D1D5322FE8D3000205E83 /* SecItemTests.m */; };
-               EB9B283321C7755700173DC2 /* OTDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE971FC9DA5A00580909 /* OTDefines.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               EB9B283421C7755800173DC2 /* OTDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C8BBE971FC9DA5A00580909 /* OTDefines.h */; settings = {ATTRIBUTES = (Private, ); }; };
                EB9B285721C77C8D00173DC2 /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; };
                EB9B285821C77C8D00173DC2 /* OTDefines.m in Sources */ = {isa = PBXBuildFile; fileRef = EBCE06E521C6E26000FB1493 /* OTDefines.m */; };
                EB9C02481E8A15B40040D3C6 /* secd-37-pairing-initial-sync.m in Sources */ = {isa = PBXBuildFile; fileRef = EB9C02421E8A112A0040D3C6 /* secd-37-pairing-initial-sync.m */; };
                F667EC611E96E9E700203D5C /* authdtests.m in Sources */ = {isa = PBXBuildFile; fileRef = F6A0971F1E953ABD00B1E7D6 /* authdtests.m */; };
                F667EC621E96EAD200203D5C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F667EC551E96E94800203D5C /* main.m */; };
                F667EC631E96EDC500203D5C /* libregressionBase.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DC0BCBFD1D8C648C00070CB0 /* libregressionBase.a */; };
+               F681C3AB2386B8C30083F22C /* PreloginUserDb.m in Sources */ = {isa = PBXBuildFile; fileRef = F681C3A82386B8B40083F22C /* PreloginUserDb.m */; };
                F682C1D41F4486F700F1B029 /* libctkloginhelper.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F682C1CE1F4486F600F1B029 /* libctkloginhelper.a */; };
                F6AF96681E646CAF00917214 /* libcoreauthd_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4432AF6A1A01458F000958DC /* libcoreauthd_client.a */; };
+               F6B1B48B24144B5F00CB3E3F /* libctkloginhelperlite.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F6B1B48924144B5E00CB3E3F /* libctkloginhelperlite.a */; };
                F6EEF76F21675E8000FB7F79 /* AuthorizationTrampolinePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = F6D600702166551800F9F7C9 /* AuthorizationTrampolinePriv.h */; };
                F6EEF77521675EF000FB7F79 /* AuthorizationTrampolinePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = F6D600702166551800F9F7C9 /* AuthorizationTrampolinePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               F6F4105324AC622F00369037 /* libaks.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EB2CA4D81D2C28C800AB770F /* libaks.a */; };
                F964772C1E5832540019E4EB /* SecCodePriv.h in Headers */ = {isa = PBXBuildFile; fileRef = DCD0678E1D8CDF7E007602F1 /* SecCodePriv.h */; settings = {ATTRIBUTES = (Private, ); }; };
                F9F77E98223C2F9A00E5CBF6 /* requirement.c in Sources */ = {isa = PBXBuildFile; fileRef = F9F77E96223C2F7B00E5CBF6 /* requirement.c */; };
                F9F77E99223C2F9A00E5CBF6 /* requirement.h in Headers */ = {isa = PBXBuildFile; fileRef = F9F77E97223C2F7C00E5CBF6 /* requirement.h */; };
+               FC63722F237B5D1C00973738 /* SecItemServer+SWC.m in Sources */ = {isa = PBXBuildFile; fileRef = FC63722A237B5CF900973738 /* SecItemServer+SWC.m */; };
+               FC637231237B5D2200973738 /* SecItemServer+SWC.m in Sources */ = {isa = PBXBuildFile; fileRef = FC63722A237B5CF900973738 /* SecItemServer+SWC.m */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXBuildRule section */
                        );
                        isEditable = 1;
                        outputFiles = (
-                               "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).exp",
+                               "$(BUILT_PRODUCTS_DIR)/$(PRODUCT_NAME).$(CURRENT_ARCH).exp",
                        );
-                       runOncePerArchitecture = 0;
-                       script = "#!/bin/sh\n\nfor file in ${HEADER_SEARCH_PATHS[@]} ; do\nHEADER_SEARCH_OPTIONS=\"${HEADER_SEARCH_OPTIONS} -I${file}\"\ndone\n\nfor prep in ${GCC_PREPROCESSOR_DEFINITIONS[@]} ; do\nPREPROCESSOR=\"${PREPROCESSOR} -D${prep}\"\ndone\n\nxcrun clang -E -Xpreprocessor -P -x objective-c ${HEADER_SEARCH_OPTIONS} ${OTHER_INPUT_FILE_FLAGS} ${PREPROCESSOR} ${INPUT_FILE_PATH} -o \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.exp\"\n";
+                       script = "#!/bin/sh\n\nfor file in ${HEADER_SEARCH_PATHS[@]} ; do\nHEADER_SEARCH_OPTIONS=\"${HEADER_SEARCH_OPTIONS} -I${file}\"\ndone\n\nfor prep in ${GCC_PREPROCESSOR_DEFINITIONS[@]} ; do\nPREPROCESSOR=\"${PREPROCESSOR} -D${prep}\"\ndone\n\nxcrun clang -E -Xpreprocessor -P -x objective-c -arch ${CURRENT_ARCH} ${HEADER_SEARCH_OPTIONS} ${OTHER_INPUT_FILE_FLAGS} ${PREPROCESSOR} ${INPUT_FILE_PATH} -o \"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.${CURRENT_ARCH}.exp\"\n";
                };
                DCF216DD21ADD5D10029CCC1 /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
                        remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
                        remoteInfo = utilities;
                };
+               0C2B36C223C42EBC00000718 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CD743A523C3EC8000FA0EC5;
+                       remoteInfo = Clique;
+               };
+               0C2B36C423C42EC800000718 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CD743A523C3EC8000FA0EC5;
+                       remoteInfo = Clique;
+               };
                0C2BCBBB1D0640B200ED7A2F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 0C2BCBBD1D0648D100ED7A2F;
                        remoteInfo = dtlsEchoServer;
                };
-               0C3E2EA82073F5C400F5B95B /* PBXContainerItemProxy */ = {
+               0C65BB4C23C3F31B0063D2B7 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 4C32C0AE0A4975F6002891BD;
-                       remoteInfo = Security_ios;
+                       remoteGlobalIDString = 0CD743A523C3EC8000FA0EC5;
+                       remoteInfo = Clique;
                };
-               0C5663ED20BE2E1A0035F362 /* PBXContainerItemProxy */ = {
+               0C65BB4E23C3F3270063D2B7 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
-                       remoteInfo = utilities;
+                       remoteGlobalIDString = 0CD743A523C3EC8000FA0EC5;
+                       remoteInfo = Clique;
                };
                0C78CCE41FCC97E7008B4B24 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        remoteGlobalIDString = 0C8BBEFD1FCB446400580909;
                        remoteInfo = otctl;
                };
+               0C7EB14C23F3D13C0089097B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
+                       remoteInfo = aks_support;
+               };
+               0C7EB14E23F3D1480089097B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
+                       remoteInfo = utilities;
+               };
                0C85DFD91FB38BB6000343A7 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DCC78EA81D8088E200865A7C;
                        remoteInfo = security;
                };
-               0C9AEEB920783FE000BF6237 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC1789031D77980500B50D50;
-                       remoteInfo = Security_osx;
-               };
                0CA378E823876E0900090B7E /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
                        remoteInfo = libsecurityd_ios;
                };
+               0CCC22AA23F38B0600E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
+                       remoteInfo = SecureObjectSyncServer;
+               };
+               0CCC22AC23F38B0E00E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
+                       remoteInfo = libsecurityd_ios;
+               };
+               0CCC22CD23F39A6300E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CCC220023F357EE00E1FCD0;
+                       remoteInfo = OctagonTrustTests;
+               };
+               0CCC22CF23F39A6A00E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CCC220023F357EE00E1FCD0;
+                       remoteInfo = OctagonTrustTests;
+               };
+               0CCC22D123F39A7500E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CCC220023F357EE00E1FCD0;
+                       remoteInfo = OctagonTrustTests;
+               };
+               0CCC22D323F39A7C00E1FCD0 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 0CCC220023F357EE00E1FCD0;
+                       remoteInfo = OctagonTrustTests;
+               };
                0CF0920F219649DB002B0AEE /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
                        remoteInfo = utilities;
                };
+               3E88361C24F08F5400E9F4D6 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 3E88360824F068EF00E9F4D6;
+                       remoteInfo = secseccodeapitest;
+               };
                438169E61B4EE4B300C54D58 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 4771D971209A755800BA9772;
                        remoteInfo = KeychainDataclassOwner;
                };
-               478D426E1FD72A8100CAB645 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52EDA61D80D58400B0A59C;
-                       remoteInfo = secdRegressions;
-               };
-               478D42701FD72A8100CAB645 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC0BCBD91D8C648C00070CB0;
-                       remoteInfo = regressionBase;
-               };
-               478D42741FD72A8100CAB645 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCC78EA81D8088E200865A7C;
-                       remoteInfo = security;
-               };
                47A6FC69206B461700BD6C54 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
                        remoteInfo = libsecurityd_ios;
                };
-               47A6FC6B206B462400BD6C54 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
-                       remoteInfo = libsecurityd_ios;
-               };
                47C2F18B2059CBEA0062DE30 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC1789031D77980500B50D50;
                        remoteInfo = Security_osx;
                };
-               47D991CF20407F7E0078CAE2 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
-                       remoteInfo = secdxctests_ios;
-               };
                47DE88CD1FA7AD6200DD3254 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 5346480017331E1100FE9172;
                        remoteInfo = KeychainSyncAccountNotification;
                };
-               6C4AA1A92228B640006FA945 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = EB9C1DAE1BDFD4DE00F89272;
-                       remoteInfo = SecurityBatsTests;
-               };
-               6C8FF4B5224C1A9800E5C812 /* PBXContainerItemProxy */ = {
+               5AAE383523D261CF0025CF9E /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = BEF88C271EAFFC3F00357577;
-                       remoteInfo = TrustedPeers;
+                       remoteGlobalIDString = 5A442F81233C330F00918373;
+                       remoteInfo = experimentTool;
                };
-               6C9808301E788AEB00E70590 /* PBXContainerItemProxy */ = {
+               6C14CA0323C4F6830097B572 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC8834011D8A218F00CE0ACA;
-                       remoteInfo = ASN1_not_installed;
+                       remoteGlobalIDString = 4718AE2E205B39C40068EC3F;
+                       remoteInfo = libsecurityd_bridge;
                };
-               6C9808321E788AEB00E70590 /* PBXContainerItemProxy */ = {
+               6C16258023C4FFC40086A0FF /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
-                       remoteInfo = utilities;
+                       remoteGlobalIDString = D4ADA3181E2B41670031CEA3;
+                       remoteInfo = libtrustd;
                };
-               6C9808361E788AEB00E70590 /* PBXContainerItemProxy */ = {
+               6C16258323C4FFD40086A0FF /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
                        remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
                        remoteInfo = SecureObjectSyncFramework;
                };
-               6C9808381E788AEB00E70590 /* PBXContainerItemProxy */ = {
+               6C16258523C4FFD40086A0FF /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
                        remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
                        remoteInfo = SecureObjectSyncServer;
                };
-               6C98083A1E788AEB00E70590 /* PBXContainerItemProxy */ = {
+               6C2045F72424BC4400F9461D /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DCC78EA81D8088E200865A7C;
-                       remoteInfo = security;
+                       remoteGlobalIDString = 6C2045E92424BA7E00F9461D;
+                       remoteInfo = KeychainStasher;
                };
-               6C98086C1E788AFD00E70590 /* PBXContainerItemProxy */ = {
+               6C2D797222C06CEB00C3CE32 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC8834011D8A218F00CE0ACA;
-                       remoteInfo = ASN1_not_installed;
+                       remoteGlobalIDString = 6C39234421F13E4D00D018AD;
+                       remoteInfo = SecDbBackupTests;
                };
-               6C98086E1E788AFD00E70590 /* PBXContainerItemProxy */ = {
+               6C2D797422C06CEF00C3CE32 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
-                       remoteInfo = utilities;
+                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
+                       remoteInfo = secdxctests;
                };
-               6C9808721E788AFD00E70590 /* PBXContainerItemProxy */ = {
+               6C4AA1A92228B640006FA945 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
-                       remoteInfo = SecureObjectSyncFramework;
+                       remoteGlobalIDString = EB9C1DAE1BDFD4DE00F89272;
+                       remoteInfo = SecurityBatsTests;
                };
-               6C9808741E788AFD00E70590 /* PBXContainerItemProxy */ = {
+               6C61D3E7242A29BA008AB9BB /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
-                       remoteInfo = SecureObjectSyncServer;
+                       remoteGlobalIDString = 6C963280242A279B00C53CE2;
+                       remoteInfo = stashtester;
                };
-               6C9808761E788AFD00E70590 /* PBXContainerItemProxy */ = {
+               6C7BE2AB23C3DD64003BB2CA /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = DCC78EA81D8088E200865A7C;
-                       remoteInfo = security;
+                       remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
+                       remoteInfo = aks_support;
                };
-               6C98089F1E788B9400E70590 /* PBXContainerItemProxy */ = {
+               6C7BE2AD23C3DD64003BB2CA /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5;
-                       remoteInfo = KeychainEntitledTestApp_mac;
+                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
+                       remoteInfo = utilities;
                };
-               6C9808A31E788CB100E70590 /* PBXContainerItemProxy */ = {
+               6C7BE2E923C3DD9C003BB2CA /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 6CF4A0DF1E4549F200ECD7B5;
-                       remoteInfo = KeychainEntitledTestApp_ios;
+                       remoteGlobalIDString = 6C7BE2A923C3DD64003BB2CA;
+                       remoteInfo = securitytool_bridge;
                };
                6C9A49B11FAB647D00239D58 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
                        remoteInfo = utilities;
                };
+               6CA9690C24ACC5C100C08B5E /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
+                       remoteInfo = utilities;
+               };
                6CAA8D3C1F8431BC007B6E03 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 6CAA8D1F1F842FB3007B6E03;
                        remoteInfo = supd;
                };
+               6CC638E6226695B900E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
+                       remoteInfo = SecureObjectSyncServer;
+               };
+               6CC638E8226695B900E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
+                       remoteInfo = SecureObjectSyncFramework;
+               };
+               6CC638EA226695C300E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
+                       remoteInfo = SecureObjectSyncServer;
+               };
+               6CC638EC226695C300E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
+                       remoteInfo = SecureObjectSyncFramework;
+               };
+               6CC638FD2266AE0A00E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
+                       remoteInfo = secdxctests;
+               };
+               6CC638FF2266AE0A00E5DB0B /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 6C39234421F13E4D00D018AD;
+                       remoteInfo = SecDbBackupTests;
+               };
+               6CE2AEAA22B2C1BE00C96AE7 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5;
+                       remoteInfo = "KeychainEntitledTestApp-mac";
+               };
+               6CE2AEAC22B2C1C300C96AE7 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5;
+                       remoteInfo = "KeychainEntitledTestApp-mac";
+               };
+               6CF33CA52387156600D1E75D /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
+                       remoteInfo = secdxctests;
+               };
+               6CF33CA72387157200D1E75D /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
+                       remoteInfo = secdxctests;
+               };
                873C14B121540FED003C9C00 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 6CCDF7831E3C25FA003F2555;
                        remoteInfo = KeychainEntitledTestRunner;
                };
-               D45D8F832224DBEF00D6C124 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 6C9808681E788AFD00E70590;
-                       remoteInfo = CKKSCloudKitTests_ios;
-               };
                D45D8F852224DBF800D6C124 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = BEF88C2F1EAFFC3F00357577;
                        remoteInfo = TrustedPeersTests;
                };
-               D477EE8221ED48E800C9AAFF /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 478D426C1FD72A8100CAB645;
-                       remoteInfo = secdxctests_mac;
-               };
                D4794E6A21222E72007C6725 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC3502B41E0208BE00BC0587;
                        remoteInfo = CKKSTests;
                };
-               D4A763DA2224BDAB0063B2B9 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 6C98082C1E788AEB00E70590;
-                       remoteInfo = CKKSCloudKitTests_mac;
-               };
-               D4A763DC2224BDCC0063B2B9 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 6CF4A0B31E45488B00ECD7B5;
-                       remoteInfo = KeychainEntitledTestApp_mac;
-               };
                D4A763DE2224BDDC0063B2B9 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 47702B2D1E5F492C00B29577;
                        remoteInfo = seckeychainnetworkextensionunauthorizedaccesstest;
                };
-               D4E0E9752224DE9100A802E0 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
-                       remoteInfo = secdxctests_ios;
-               };
-               D4E0E9792224DEE600A802E0 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 6CF4A0DF1E4549F200ECD7B5;
-                       remoteInfo = KeychainEntitledTestApp_ios;
-               };
                D4E0E97B2224DF0300A802E0 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = 47702B2D1E5F492C00B29577;
                        remoteInfo = seckeychainnetworkextensionunauthorizedaccesstest;
                };
-               D4E0E9AB2224DFEB00A802E0 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 4727FBB61F9918580003AE36;
-                       remoteInfo = secdxctests_ios;
-               };
                D4E0E9AD2224E00600A802E0 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
                        remoteInfo = libsecurityd_ios;
                };
-               DC34CD2C20326C2C00302481 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
-                       remoteInfo = SecureObjectSyncServer;
-               };
-               DC34CD3320326C3100302481 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
-                       remoteInfo = SecureObjectSyncFramework;
-               };
-               DC34CD3520326C3B00302481 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC0BCC211D8C684F00070CB0;
-                       remoteInfo = utilities;
-               };
                DC3502C31E020D4D00BC0587 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
                        remoteInfo = aks_support;
                };
-               DC69A5862165298500512BD6 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
-                       remoteInfo = aks_support;
-               };
                DC6BC2731D90D07800DD57B3 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC8834011D8A218F00CE0ACA;
                        remoteInfo = ASN1_not_installed;
                };
-               DC93C4C8214713DC008F8362 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
-                       remoteInfo = libsecurityd_ios;
-               };
-               DC93C4CC21471401008F8362 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52E7731D80BC8000B0A59C;
-                       remoteInfo = libsecurityd_ios;
-               };
                DC99B85D20EACA470065B73B /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DCD66DC41D8205C400DB1393;
                        remoteInfo = libSecOtrOSX;
                };
-               DCD6BF5321E919610015F7A8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
-                       remoteInfo = aks_support;
-               };
-               DCD6BF5521E9196E0015F7A8 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
-                       remoteInfo = aks_support;
-               };
                DCD6BF5721E919820015F7A8 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DCDA5E4F2124B9C5009B11B2;
                        remoteInfo = aks_support;
                };
+               DCE27860245B81BD00381FE8 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 4771D971209A755800BA9772;
+                       remoteInfo = KeychainDataclassOwner;
+               };
                DCE4E8D71D7F37F200AFB96E /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        remoteGlobalIDString = DC0BC5501D8B6D2D00070CB0;
                        remoteInfo = XPCKeychainSandboxCheck;
                };
-               EBD7DF8021FF475B0089F2DF /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DC52E8BE1D80C25800B0A59C;
-                       remoteInfo = SecureObjectSyncServer;
-               };
-               EBD7DF8221FF475B0089F2DF /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = DCD8A1061E09EE0F00E4FA0A;
-                       remoteInfo = SecureObjectSyncFramework;
-               };
                EBF374811DC058B60065D840 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 4C35DB69094F906D002917C4 /* Project object */;
                        name = "Copy System logging profile";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               0C9AEEB320783FBB00BF6237 /* Embed OCMock */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "";
-                       dstSubfolderSpec = 10;
-                       files = (
-                       );
-                       name = "Embed OCMock";
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                0CA378E623876DEC00090B7E /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               0CF4064A2072E3E3003D6A7F /* Embed OCMock */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 2147483647;
-                       dstPath = "";
-                       dstSubfolderSpec = 10;
-                       files = (
-                       );
-                       name = "Embed OCMock";
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                3D58394821890FFB000ACA44 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        dstPath = /System/Library/Preferences/Logging/Subsystems;
                        dstSubfolderSpec = 0;
                        files = (
+                               DCDACB5A24A3F39A0054080C /* com.apple.security.ckks.plist in Copy Logging Files */,
                                DC71D8F51D959F150065FB93 /* com.apple.securityd.plist in Copy Logging Files */,
                        );
                        name = "Copy Logging Files";
                        name = "Install man8 page";
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               6C2045F32424BBB900F9461D /* Install Sandbox Profile */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /System/Library/Sandbox/Profiles;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               6C2045F42424BBCD00F9461D /* com.apple.security.KeychainStasher.sb in Install Sandbox Profile */,
+                       );
+                       name = "Install Sandbox Profile";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
+               6C2045FA2424BCC300F9461D /* Install LaunchAgent plist */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /System/Library/LaunchAgents;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               6C2045FB2424BCD600F9461D /* com.apple.security.KeychainStasher.plist in Install LaunchAgent plist */,
+                       );
+                       name = "Install LaunchAgent plist";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                6C23F02E227A39FD009F6756 /* Install Sandbox Profile */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6C7E8F1F21F7BE64008A2D56 /* Copy BATS Test Discovery Plist */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
-                       dstSubfolderSpec = 0;
-                       files = (
-                               6C02135021F7EF07009D5C80 /* SecDbBackupTests.plist in Copy BATS Test Discovery Plist */,
-                       );
-                       name = "Copy BATS Test Discovery Plist";
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
                6C9AA79C1F7C1D8F00D08296 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        dstPath = /System/Library/Preferences/Logging/Subsystems;
                        dstSubfolderSpec = 0;
                        files = (
+                               DCDACB5924A3F38E0054080C /* com.apple.security.ckks.plist in Copy Logging Files */,
                                DCE4E80E1D7A4E3B00AFB96E /* com.apple.securityd.plist in Copy Logging Files */,
                        );
                        name = "Copy Logging Files";
                09E9991F1F7D76550018DF67 /* SecKeyProxy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecKeyProxy.m; sourceTree = "<group>"; };
                0C00FC81217A971800C8BF00 /* OTLocalCuttlefishReset.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLocalCuttlefishReset.m; sourceTree = "<group>"; };
                0C00FC85217A972E00C8BF00 /* OTLocalCuttlefishReset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTLocalCuttlefishReset.h; sourceTree = "<group>"; };
+               0C0203E023A8564E005D0A68 /* OTEscrowRecord.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; name = OTEscrowRecord.proto; path = proto/OTEscrowRecord.proto; sourceTree = "<group>"; };
                0C0BDB2F175685B000BC1A7E /* secdtests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secdtests; sourceTree = BUILT_PRODUCTS_DIR; };
                0C0BDB31175685B000BC1A7E /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
                0C0BDB441756868B00BC1A7E /* testlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = testlist.h; sourceTree = "<group>"; };
                0C0C4F83216FB55600C14C61 /* EscrowKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EscrowKeys.swift; sourceTree = "<group>"; };
                0C0C4F84216FB56B00C14C61 /* BottledPeer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottledPeer.swift; sourceTree = "<group>"; };
                0C0C88771CCEC5BD00617D1B /* 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 = "<group>"; };
+               0C0CB73723AD71400020C6BF /* Container_EscrowRecords.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container_EscrowRecords.swift; sourceTree = "<group>"; };
                0C0CEC9D1DA45EA200C22FBC /* recovery_key.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = recovery_key.h; sourceTree = "<group>"; };
                0C0CEC9E1DA45EA200C22FBC /* recovery_key.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = recovery_key.m; sourceTree = "<group>"; };
+               0C0D920523BFEA740070A68C /* OTCDPRecoveryInformation.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; name = OTCDPRecoveryInformation.proto; path = proto/OTCDPRecoveryInformation.proto; sourceTree = "<group>"; };
                0C0F76DD21399AF40074EDDF /* OTPairingMessage.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = OTPairingMessage.proto; sourceTree = "<group>"; };
-               0C108C4B208A677100E8CF70 /* SFSignInAnalytics+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFSignInAnalytics+Internal.h"; sourceTree = "<group>"; };
                0C12B1F02138D31600BE0A98 /* OTClientStateMachine.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientStateMachine.m; sourceTree = "<group>"; };
                0C12B1F52138D32F00BE0A98 /* OTClientStateMachine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClientStateMachine.h; sourceTree = "<group>"; };
                0C1B8BB3223323710094D5DA /* OTVouchWithRecoveryKeyOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTVouchWithRecoveryKeyOperation.h; sourceTree = "<group>"; };
                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 = "<group>"; };
+               0C3C47C024902D450084B951 /* OTSupportOctagonMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSupportOctagonMessage.m; sourceTree = "<group>"; };
+               0C3C47C224902D460084B951 /* OTSupportSOSMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSupportSOSMessage.h; sourceTree = "<group>"; };
+               0C3C47C324902D460084B951 /* OTSupportSOSMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSupportSOSMessage.m; sourceTree = "<group>"; };
+               0C3C47C424902D470084B951 /* OTSupportOctagonMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSupportOctagonMessage.h; sourceTree = "<group>"; };
+               0C3C47C524902D470084B951 /* OTGlobalEnums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTGlobalEnums.h; sourceTree = "<group>"; };
+               0C3DF8C524789C04009CF03A /* Container_Peers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container_Peers.swift; sourceTree = "<group>"; };
+               0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTEscrowRecordMetadata.m; path = proto/generated_source/OTEscrowRecordMetadata.m; sourceTree = "<group>"; };
+               0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTEscrowRecordMetadataClientMetadata.m; path = proto/generated_source/OTEscrowRecordMetadataClientMetadata.m; sourceTree = "<group>"; };
+               0C468FDA23C7D41D006F4582 /* OTEscrowRecordMetadata.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTEscrowRecordMetadata.h; path = proto/generated_source/OTEscrowRecordMetadata.h; sourceTree = "<group>"; };
+               0C468FDB23C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTEscrowRecordMetadataClientMetadata.h; path = proto/generated_source/OTEscrowRecordMetadataClientMetadata.h; sourceTree = "<group>"; };
+               0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTEscrowRecord.m; path = proto/generated_source/OTEscrowRecord.m; sourceTree = "<group>"; };
+               0C468FDE23C7D471006F4582 /* OTEscrowRecord.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTEscrowRecord.h; path = proto/generated_source/OTEscrowRecord.h; sourceTree = "<group>"; };
+               0C468FE723C7D4C7006F4582 /* OTICDPRecordContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTICDPRecordContext.h; path = proto/generated_source/OTICDPRecordContext.h; sourceTree = "<group>"; };
+               0C468FE823C7D4C8006F4582 /* OTEscrowAuthenticationInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTEscrowAuthenticationInformation.h; path = proto/generated_source/OTEscrowAuthenticationInformation.h; sourceTree = "<group>"; };
+               0C468FE923C7D4C8006F4582 /* OTICDPRecordSilentContext.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTICDPRecordSilentContext.h; path = proto/generated_source/OTICDPRecordSilentContext.h; sourceTree = "<group>"; };
+               0C468FEA23C7D4C8006F4582 /* OTCDPRecoveryInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = OTCDPRecoveryInformation.h; path = proto/generated_source/OTCDPRecoveryInformation.h; sourceTree = "<group>"; };
+               0C468FEB23C7D4C9006F4582 /* OTICDPRecordSilentContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTICDPRecordSilentContext.m; path = proto/generated_source/OTICDPRecordSilentContext.m; sourceTree = "<group>"; };
+               0C468FEC23C7D4C9006F4582 /* OTEscrowAuthenticationInformation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTEscrowAuthenticationInformation.m; path = proto/generated_source/OTEscrowAuthenticationInformation.m; sourceTree = "<group>"; };
+               0C468FED23C7D4C9006F4582 /* OTICDPRecordContext.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTICDPRecordContext.m; path = proto/generated_source/OTICDPRecordContext.m; sourceTree = "<group>"; };
+               0C468FEE23C7D4CA006F4582 /* OTCDPRecoveryInformation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OTCDPRecoveryInformation.m; path = proto/generated_source/OTCDPRecoveryInformation.m; sourceTree = "<group>"; };
                0C48990A1E0E0FF300C6CF70 /* SOSTransportCircleCK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSTransportCircleCK.h; sourceTree = "<group>"; };
                0C4899111E0E105D00C6CF70 /* SOSTransportCircleCK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSTransportCircleCK.m; sourceTree = "<group>"; };
                0C48991B1E0F384700C6CF70 /* SOSAccountTrustClassic.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAccountTrustClassic.m; path = SecureObjectSync/SOSAccountTrustClassic.m; sourceTree = "<group>"; };
                0C5258B821BB05C100B32C96 /* FakeSOSControl.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = FakeSOSControl.m; path = Tests/FakeSOSControl.m; sourceTree = "<group>"; };
                0C5258BC21BB137800B32C96 /* FakeSOSControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FakeSOSControl.h; path = Tests/FakeSOSControl.h; sourceTree = "<group>"; };
                0C5824A322860001009E8C15 /* OctagonTests+HealthCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+HealthCheck.swift"; sourceTree = "<group>"; };
+               0C64C07C2485A53000D84A5D /* OTPreloadOctagonKeysOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTPreloadOctagonKeysOperation.m; sourceTree = "<group>"; };
+               0C64C07F2485A54100D84A5D /* OTPreloadOctagonKeysOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPreloadOctagonKeysOperation.h; sourceTree = "<group>"; };
                0C6604692134983900BFBBB8 /* OTEstablishOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTEstablishOperation.m; sourceTree = "<group>"; };
                0C66046E2134985100BFBBB8 /* OTEstablishOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTEstablishOperation.h; sourceTree = "<group>"; };
                0C6604782134C86500BFBBB8 /* OTDeviceInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTDeviceInformation.h; sourceTree = "<group>"; };
                0C8FD546214AEC650098E3FB /* OTJoiningConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTJoiningConfiguration.h; sourceTree = "<group>"; };
                0C8FD549214AECD70098E3FB /* OTJoiningConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTJoiningConfiguration.m; sourceTree = "<group>"; };
                0C97867C235A76E70040A867 /* com.apple.security.signposts.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.signposts.plist; sourceTree = "<group>"; };
+               0C9A54B4250C27F100FF007B /* OctagonTrustTests+Errors.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OctagonTrustTests+Errors.m"; sourceTree = "<group>"; };
+               0C9A54B7250C290800FF007B /* OctagonTrustTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTrustTests.h; sourceTree = "<group>"; };
                0C9AE289214054F4003BFDB5 /* OTSponsorToApplicantRound1M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound1M2.h; sourceTree = "<group>"; };
                0C9AE28A214054F5003BFDB5 /* OTSponsorToApplicantRound2M2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSponsorToApplicantRound2M2.h; sourceTree = "<group>"; };
                0C9AE28B214054F5003BFDB5 /* OTApplicantToSponsorRound2M1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTApplicantToSponsorRound2M1.h; sourceTree = "<group>"; };
                0C9AE290214054F7003BFDB5 /* OTSponsorToApplicantRound2M2.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSponsorToApplicantRound2M2.m; sourceTree = "<group>"; };
                0C9AE2A1214055CE003BFDB5 /* OTPairingMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTPairingMessage.h; sourceTree = "<group>"; };
                0C9AE2A2214055CF003BFDB5 /* OTPairingMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTPairingMessage.m; sourceTree = "<group>"; };
-               0C9AEEB720783FBB00BF6237 /* SignInAnalyticsTests_osx.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SignInAnalyticsTests_osx.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               0C9FB40120D8729A00864612 /* CoreCDP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreCDP.framework; path = System/Library/PrivateFrameworks/CoreCDP.framework; sourceTree = SDKROOT; };
+               0C9F65AA23E3ACF700B1A2C5 /* OTEscrowTranslation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTEscrowTranslation.m; sourceTree = "<group>"; };
+               0C9F65AC23E3ACF700B1A2C5 /* OTEscrowTranslation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTEscrowTranslation.h; sourceTree = "<group>"; };
+               0CA1D0B223E9023100021038 /* OctagonTests+EscrowTestVectors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+EscrowTestVectors.swift"; sourceTree = "<group>"; };
                0CA4EBF1202B8D1C002B1D96 /* CloudKitKeychainSyncingTestsBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CloudKitKeychainSyncingTestsBase.h; sourceTree = "<group>"; };
                0CA4EBF2202B8D1D002B1D96 /* CloudKitKeychainSyncingTestsBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudKitKeychainSyncingTestsBase.m; sourceTree = "<group>"; };
                0CA702082280D5600085AC54 /* OTCheckHealthOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTCheckHealthOperation.m; sourceTree = "<group>"; };
                0CBA047C214C4E4D005B3A2F /* OctagonPairingTests+ProxMultiClients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonPairingTests+ProxMultiClients.swift"; sourceTree = "<group>"; };
                0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TestsObjcTranslation.m; sourceTree = "<group>"; };
                0CBEF3422242C9BE00015691 /* TestsObjcTranslation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestsObjcTranslation.h; sourceTree = "<group>"; };
+               0CBF883A23AAD9DC00652EDD /* OctagonTests+EscrowRecords.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+EscrowRecords.swift"; sourceTree = "<group>"; };
                0CC8A8FA2123A9EB005D7F6A /* OTClientVoucherOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTClientVoucherOperation.m; sourceTree = "<group>"; };
                0CC8A9002123AA3B005D7F6A /* OTClientVoucherOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTClientVoucherOperation.h; sourceTree = "<group>"; };
                0CC8A9012123AEF7005D7F6A /* OTJoinWithVoucherOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTJoinWithVoucherOperation.m; sourceTree = "<group>"; };
                0CC8A9052123AF16005D7F6A /* OTJoinWithVoucherOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTJoinWithVoucherOperation.h; sourceTree = "<group>"; };
+               0CCC227923F357EE00E1FCD0 /* OctagonTrustTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OctagonTrustTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               0CCC229223F35D4300E1FCD0 /* OctagonTrustTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "OctagonTrustTests-Info.plist"; sourceTree = "<group>"; };
+               0CCC229F23F367D100E1FCD0 /* OctagonTrustTests-EscrowRecords.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "OctagonTrustTests-EscrowRecords.m"; sourceTree = "<group>"; };
+               0CCC22A323F36DD300E1FCD0 /* OctagonTrustTests-EscrowTestVectors.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OctagonTrustTests-EscrowTestVectors.h"; sourceTree = "<group>"; };
+               0CCC22B123F38B5B00E1FCD0 /* libsqlite3.0.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.0.tbd; path = usr/lib/libsqlite3.0.tbd; sourceTree = SDKROOT; };
+               0CCC22CC23F395A100E1FCD0 /* OctagonTrustEscrowRecoverer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTrustEscrowRecoverer.h; sourceTree = "<group>"; };
+               0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreCDP.framework; path = System/Library/PrivateFrameworks/CoreCDP.framework; sourceTree = SDKROOT; };
                0CCCC7C720261D050024405E /* OT.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OT.h; sourceTree = "<group>"; };
                0CCCC7C820261D310024405E /* OT.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OT.m; sourceTree = "<group>"; };
                0CCDE7161EEB08220021A946 /* secd-156-timers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-156-timers.m"; sourceTree = "<group>"; };
                0CD3D5152240479600024755 /* OTSetRecoveryKeyOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSetRecoveryKeyOperation.m; sourceTree = "<group>"; };
                0CD3D518224047B400024755 /* OTSetRecoveryKeyOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSetRecoveryKeyOperation.h; sourceTree = "<group>"; };
                0CD5797721498F7700C43496 /* OctagonPairingTests+Piggybacking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonPairingTests+Piggybacking.swift"; sourceTree = "<group>"; };
+               0CD743A623C3EC8000FA0EC5 /* OctagonTrust.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OctagonTrust.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+               0CD743A823C3EC8000FA0EC5 /* OctagonTrust.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OctagonTrust.h; sourceTree = "<group>"; };
+               0CD743A923C3EC8000FA0EC5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               0CD743B723C3ED7E00FA0EC5 /* OctagonTrust.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OctagonTrust.m; sourceTree = "<group>"; };
+               0CD743BA23C3EF0D00FA0EC5 /* OTClique+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OTClique+Private.h"; sourceTree = "<group>"; };
                0CD8CB041ECA50780076F37F /* SOSPeerOTRTimer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSPeerOTRTimer.m; sourceTree = "<group>"; };
                0CD8CB0C1ECA50D10076F37F /* SOSPeerOTRTimer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSPeerOTRTimer.h; sourceTree = "<group>"; };
                0CD8D654207D6E65005CDBE8 /* SFAnalytics+Signin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Signin.h"; sourceTree = "<group>"; };
                0CE760531E13155100B4381E /* SOSAccountTrustClassic+Circle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Circle.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Circle.h"; sourceTree = "<group>"; };
                0CE760551E1316E900B4381E /* SOSAccountTrustClassic+Retirement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "SOSAccountTrustClassic+Retirement.h"; path = "SecureObjectSync/SOSAccountTrustClassic+Retirement.h"; sourceTree = "<group>"; };
                0CE98B5B1FA9360700CF1D54 /* libprequelite.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libprequelite.tbd; path = usr/lib/libprequelite.tbd; sourceTree = SDKROOT; };
-               0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSignInAnalytics.m; sourceTree = "<group>"; };
-               0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFSignInAnalytics.h; sourceTree = "<group>"; };
-               0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFSignInAnalyticsTests.m; sourceTree = "<group>"; };
                0CF405FC2072E352003D6A7F /* SFTMTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SFTMTests-Info.plist"; sourceTree = "<group>"; };
-               0CF406502072E3E3003D6A7F /* SignInAnalyticsTests_ios.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SignInAnalyticsTests_ios.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                0CF70BD6218BECF500EC3515 /* CuttlefishExtensionWorkaround.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CuttlefishExtensionWorkaround.swift; sourceTree = "<group>"; };
+               0CF7613D23F24B5D00A3C3AD /* KeychainCircle.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = KeychainCircle.modulemap; path = Modules/KeychainCircle.modulemap; sourceTree = "<group>"; };
+               0CF7613F23F24B5E00A3C3AD /* OctagonTrust.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = OctagonTrust.modulemap; path = Modules/OctagonTrust.modulemap; sourceTree = "<group>"; };
                0CFC029B1D41650700E6283B /* libcoretls.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcoretls.dylib; path = usr/lib/libcoretls.dylib; sourceTree = SDKROOT; };
                107226D00D91DB32003CF14F /* SecTask.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecTask.c; sourceTree = "<group>"; };
                107226D10D91DB32003CF14F /* SecTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecTask.h; path = sectask/SecTask.h; sourceTree = "<group>"; };
                2281820D17B4686C0067C9C9 /* BackgroundTaskAgent.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BackgroundTaskAgent.framework; path = System/Library/PrivateFrameworks/BackgroundTaskAgent.framework; sourceTree = SDKROOT; };
                24CBF8731E9D4E4500F09F0E /* kc-44-secrecoverypassword.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "kc-44-secrecoverypassword.c"; path = "regressions/kc-44-secrecoverypassword.c"; sourceTree = "<group>"; };
                3D58394D21890FFB000ACA44 /* SecExperimentTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecExperimentTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               3DC5BD58241830D50039ABF4 /* SecureTransportTests_macos.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = SecureTransportTests_macos.xctestplan; path = OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_macos.xctestplan; sourceTree = "<group>"; };
+               3DC5BD59241845100039ABF4 /* SecureTransportTests_ios.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; name = SecureTransportTests_ios.xctestplan; path = OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_ios.xctestplan; sourceTree = "<group>"; };
                3DD1FE78201AA50C0086D049 /* STLegacyTests+clientauth41.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STLegacyTests+clientauth41.m"; sourceTree = "<group>"; };
                3DD1FE79201AA50D0086D049 /* SecureTransport_macosTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = SecureTransport_macosTests.plist; sourceTree = "<group>"; };
                3DD1FE7A201AA50D0086D049 /* STLegacyTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "STLegacyTests-Entitlements.plist"; sourceTree = "<group>"; };
                3DD1FFA9201FC5C30086D049 /* libcoretls_cfhelpers.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcoretls_cfhelpers.tbd; path = usr/lib/libcoretls_cfhelpers.tbd; sourceTree = SDKROOT; };
                3DD1FFD0201FDB1D0086D049 /* SecureTransport_ios_tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecureTransport_ios_tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                3DD2589820478CCE00F5DA78 /* STLegacyTests+session.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "STLegacyTests+session.m"; sourceTree = "<group>"; };
+               3E88361124F068EF00E9F4D6 /* secseccodeapitest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secseccodeapitest; sourceTree = BUILT_PRODUCTS_DIR; };
+               3E88361324F0699F00E9F4D6 /* secseccodeapitest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = secseccodeapitest.c; sourceTree = "<group>"; };
                433E519D1B66D5F600482618 /* AppSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppSupport.framework; path = System/Library/PrivateFrameworks/AppSupport.framework; sourceTree = SDKROOT; };
                4381690C1B4EDCBD00C54D58 /* SOSCCAuthPlugin.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SOSCCAuthPlugin.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                4381690F1B4EDCBD00C54D58 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                4723C9D11F1531970082882F /* CKKSLoggerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSLoggerTests.m; sourceTree = "<group>"; };
                4723C9DA1F1540CE0082882F /* SFAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFAnalytics.h; sourceTree = "<group>"; };
                4723C9DB1F1540CE0082882F /* SFAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFAnalytics.m; sourceTree = "<group>"; };
-               4727FBB71F9918580003AE36 /* secdxctests_ios.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = secdxctests_ios.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               4727FBB71F9918580003AE36 /* secdxctests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = secdxctests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                4727FBB91F9918590003AE36 /* KeychainCryptoTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainCryptoTests.m; sourceTree = "<group>"; };
                4727FBBB1F9918590003AE36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                4727FBC41F991C460003AE36 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
                4727FBE41F99217A0003AE36 /* SharedWebCredentials.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SharedWebCredentials.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.Internal.sdk/System/Library/PrivateFrameworks/SharedWebCredentials.framework; sourceTree = DEVELOPER_DIR; };
                4727FBE61F9921890003AE36 /* ApplePushService.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplePushService.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.Internal.sdk/System/Library/PrivateFrameworks/ApplePushService.framework; sourceTree = DEVELOPER_DIR; };
                4727FBE81F9921D00003AE36 /* libACM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libACM.a; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.Internal.sdk/usr/local/lib/libACM.a; sourceTree = DEVELOPER_DIR; };
-               472E184F20D9A20D00ECE7C9 /* libcoreauthd_client.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoreauthd_client.a; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/local/lib/libcoreauthd_client.a; sourceTree = DEVELOPER_DIR; };
                473337771FDAFBCC00E19F30 /* SFKeychainControlManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFKeychainControlManager.h; sourceTree = "<group>"; };
                473337781FDAFBCC00E19F30 /* SFKeychainControlManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFKeychainControlManager.m; sourceTree = "<group>"; };
                473337821FDB29A200E19F30 /* KeychainCheck.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainCheck.h; sourceTree = "<group>"; };
                475EDCF520D98BCF009D2409 /* libACM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libACM.a; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/local/lib/libACM.a; sourceTree = DEVELOPER_DIR; };
                475EDCF720D98BF6009D2409 /* CoreCDP.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreCDP.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/CoreCDP.framework; sourceTree = DEVELOPER_DIR; };
                475EDCF920D98C0D009D2409 /* CryptoTokenKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CryptoTokenKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/CryptoTokenKit.framework; sourceTree = DEVELOPER_DIR; };
-               475EDCFB20D98C3C009D2409 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/libDER.a; sourceTree = SDKROOT; };
                475EDCFD20D98C53009D2409 /* libaks.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libaks.a; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/local/lib/libaks.a; sourceTree = DEVELOPER_DIR; };
                475EDCFF20D98C64009D2409 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
                475EDD0120D98C81009D2409 /* libaks_acl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libaks_acl.a; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/local/lib/libaks_acl.a; sourceTree = DEVELOPER_DIR; };
                477A1FE1203763A500ACD81D /* KeychainAPITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainAPITests.m; sourceTree = "<group>"; };
                477A1FEB2037A0E000ACD81D /* KeychainXCTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainXCTest.h; sourceTree = "<group>"; };
                477A1FEC2037A0E000ACD81D /* KeychainXCTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainXCTest.m; sourceTree = "<group>"; };
-               478D429C1FD72A8100CAB645 /* secdxctests_mac.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = secdxctests_mac.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                479108B51EE879F9008CEFA0 /* CKKSAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSAnalytics.h; sourceTree = "<group>"; };
                479108B61EE879F9008CEFA0 /* CKKSAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSAnalytics.m; sourceTree = "<group>"; };
                47922D171FAA65120008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SecDbKeychainSerializedAKSWrappedKey.proto; sourceTree = "<group>"; };
                48776C7C1DA5BB5F00CC09B9 /* SOSRingRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSRingRecovery.m; sourceTree = "<group>"; };
                48776C7D1DA5BB5F00CC09B9 /* SOSRingRecovery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSRingRecovery.h; sourceTree = "<group>"; };
                48776C801DA5BC0E00CC09B9 /* SOSAccountRecovery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountRecovery.m; sourceTree = "<group>"; };
+               487A65F3245B65F1005F51D6 /* secd-68-fullPeerInfoIntegrity.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "secd-68-fullPeerInfoIntegrity.m"; sourceTree = "<group>"; };
                48AC7B5C232B1A1700F02B6F /* SOSIntervalEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSIntervalEvent.h; sourceTree = "<group>"; };
                48AC7B71232B1A7000F02B6F /* SOSIntervalEvent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSIntervalEvent.m; sourceTree = "<group>"; };
                48C2F9321E4BCFC30093D70C /* accountCirclesViewsPrint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = accountCirclesViewsPrint.m; sourceTree = "<group>"; };
                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 = "<group>"; };
                5F00F95A230614A200B832E0 /* SecImportExportPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecImportExportPriv.h; path = keychain/headers/SecImportExportPriv.h; sourceTree = "<group>"; };
+               5F4C21FE2489C68900F0C425 /* simulatecrash_assert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = simulatecrash_assert.h; sourceTree = "<group>"; };
                5F8494FF22DFB502008B3EFB /* SecTrustExceptionResetCount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecTrustExceptionResetCount.m; sourceTree = "<group>"; };
                617570BA22C2D19E00EFBA37 /* Security.macOS.private.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; name = Security.macOS.private.modulemap; path = Modules/Security.macOS.private.modulemap; sourceTree = "<group>"; };
-               6C02134C21F7ED16009D5C80 /* SecDbBackupTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = SecDbBackupTests.plist; path = tests/SecDbBackupTests/SecDbBackupTests.plist; sourceTree = SOURCE_ROOT; };
+               61BDC97E242932A100A2ABD8 /* SecTranslocateEnumUtils.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SecTranslocateEnumUtils.hpp; sourceTree = "<group>"; };
                6C02134D21F7ED16009D5C80 /* SecDbBackupTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SecDbBackupTests.m; path = tests/SecDbBackupTests/SecDbBackupTests.m; sourceTree = SOURCE_ROOT; };
                6C02134F21F7ED45009D5C80 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; name = Info.plist; path = tests/SecDbBackupTests/Info.plist; sourceTree = SOURCE_ROOT; };
                6C0B0C3D1E2537C6007F95E5 /* WirelessDiagnostics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WirelessDiagnostics.framework; path = System/Library/PrivateFrameworks/WirelessDiagnostics.framework; sourceTree = SDKROOT; };
                6C1260FA1F7D631D001B2EEC /* securityuploadd-ios.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "securityuploadd-ios.plist"; sourceTree = "<group>"; };
                6C1520CD1DCCF57A00C85C6D /* secd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = secd.8; sourceTree = "<group>"; };
                6C1A29FC1F882788002312D8 /* SFAnalyticsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFAnalyticsTests.m; sourceTree = "<group>"; };
-               6C2008EF220BB4B500674B3A /* Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Entitlements.plist; sourceTree = "<group>"; };
+               6C2008EF220BB4B500674B3A /* SecDbBackupTests-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "SecDbBackupTests-Entitlements.plist"; sourceTree = "<group>"; };
+               6C2045EA2424BA7E00F9461D /* KeychainStasher */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KeychainStasher; sourceTree = BUILT_PRODUCTS_DIR; };
+               6C2045F92424BCB800F9461D /* com.apple.security.KeychainStasher.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.KeychainStasher.plist; sourceTree = "<group>"; };
                6C23F02C227A39E9009F6756 /* com.apple.securityd.sb */ = {isa = PBXFileReference; lastKnownFileType = text; name = com.apple.securityd.sb; path = securityd/etc/com.apple.securityd.sb; sourceTree = SOURCE_ROOT; };
+               6C2D463924C88A700015C3C9 /* LegacyAPICounts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LegacyAPICounts.h; sourceTree = "<group>"; };
+               6C2D463B24C88A870015C3C9 /* LegacyAPICounts.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LegacyAPICounts.m; sourceTree = "<group>"; };
                6C34462F1E24F6BE00F9522B /* CKKSRateLimiterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSRateLimiterTests.m; sourceTree = "<group>"; };
                6C39237921F13E4D00D018AD /* SecDbBackupTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SecDbBackupTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                6C4605B81F882B9B001421B6 /* KeychainAnalyticsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainAnalyticsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               6C48D10D2423A2F3004AF950 /* KeychainStasher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = KeychainStasher.entitlements; sourceTree = "<group>"; };
+               6C48D10F2423A3C0004AF950 /* com.apple.security.KeychainStasher.sb */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.security.KeychainStasher.sb; sourceTree = "<group>"; };
                6C4AEF82218A09210012C5DA /* CheckV12DevEnabled.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CheckV12DevEnabled.h; sourceTree = "<group>"; };
                6C4AEF83218A09210012C5DA /* CheckV12DevEnabled.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckV12DevEnabled.m; sourceTree = "<group>"; };
                6C4AEF8A218A0A400012C5DA /* SecDbBackupManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecDbBackupManager.h; sourceTree = "<group>"; };
                6C4AEF93218A124B0012C5DA /* SecDbKeychainMetadataKeyStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecDbKeychainMetadataKeyStore.m; sourceTree = "<group>"; };
                6C4AEF9C218A16F80012C5DA /* SecAKSObjCWrappers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecAKSObjCWrappers.h; sourceTree = "<group>"; };
                6C4AEF9D218A16F80012C5DA /* SecAKSObjCWrappers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecAKSObjCWrappers.m; sourceTree = "<group>"; };
+               6C513A37244F007B00207D5E /* SecItemRateLimit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecItemRateLimit.h; sourceTree = "<group>"; };
+               6C513A38244F007B00207D5E /* SecItemRateLimit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecItemRateLimit.m; sourceTree = "<group>"; };
                6C5232D41E3C183F00330DB1 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/System/Library/Frameworks/CloudKit.framework; sourceTree = DEVELOPER_DIR; };
+               6C54BE0C23F41497004716CB /* SystemEntitlements.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemEntitlements.h; sourceTree = "<group>"; };
                6C588D791EAA149F00D7E322 /* RateLimiterTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RateLimiterTests.m; sourceTree = "<group>"; };
                6C5B101B1F91613E009B091E /* supdctl-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "supdctl-Entitlements.plist"; sourceTree = "<group>"; };
                6C5B10211F9164F5009B091E /* securityuploadd.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = securityuploadd.8; sourceTree = "<group>"; };
+               6C5D62A5221B6E3F00AF79DC /* secdxctests-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = "secdxctests-entitlements.plist"; sourceTree = "<group>"; };
+               6C6579FC2394878700701C8B /* SecDbBackupTestsBase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecDbBackupTestsBase.m; sourceTree = "<group>"; };
                6C69517C1F758E1000F68F91 /* supdProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = supdProtocol.h; sourceTree = "<group>"; };
                6C69517D1F758E1000F68F91 /* supd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = supd.h; sourceTree = "<group>"; };
                6C69517E1F758E1000F68F91 /* supd.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = supd.m; sourceTree = "<group>"; };
                6C69518D1F75A7DB00F68F91 /* SFAnalyticsSQLiteStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFAnalyticsSQLiteStore.m; sourceTree = "<group>"; };
                6C69518E1F75A7DC00F68F91 /* SFAnalyticsSQLiteStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFAnalyticsSQLiteStore.h; sourceTree = "<group>"; };
                6C69518F1F75A8C100F68F91 /* SFAnalyticsDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFAnalyticsDefines.h; sourceTree = "<group>"; };
+               6C6AF178221A03930091CE0A /* SecDbKeychainSerializedMetadataKey.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SecDbKeychainSerializedMetadataKey.proto; sourceTree = "<group>"; };
+               6C6AF17D221A06F70091CE0A /* SecDbKeychainSerializedMetadataKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecDbKeychainSerializedMetadataKey.h; sourceTree = "<group>"; };
+               6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecDbKeychainSerializedMetadataKey.m; sourceTree = "<group>"; };
                6C70D8D420EB02B700AB6FAF /* TPPBPolicyCategoriesByView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPPBPolicyCategoriesByView.m; sourceTree = "<group>"; };
                6C70D8D520EBDE4500AB6FAF /* TPPBPolicyRedaction.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = TPPBPolicyRedaction.proto; sourceTree = "<group>"; };
                6C70D8DD20EBDFD600AB6FAF /* TPPBPolicyRedaction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPPBPolicyRedaction.m; sourceTree = "<group>"; };
                6C70D8DE20EBDFD700AB6FAF /* TPPBPolicyRedaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPPBPolicyRedaction.h; sourceTree = "<group>"; };
+               6C755603242121F000025D78 /* keychainstasherinterface.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = keychainstasherinterface.m; sourceTree = "<group>"; };
+               6C755604242121F000025D78 /* keychainstasherinterface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = keychainstasherinterface.h; sourceTree = "<group>"; };
                6C758CB01F8826100075BD78 /* SupdTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SupdTests.m; sourceTree = "<group>"; };
                6C758CB21F8826100075BD78 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                6C7BB0032006B4EE004D1B6B /* SOSAnalytics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SOSAnalytics.m; path = Analytics/Clients/SOSAnalytics.m; sourceTree = SOURCE_ROOT; };
                6C7BB0042006B4EF004D1B6B /* SOSAnalytics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SOSAnalytics.h; path = Analytics/Clients/SOSAnalytics.h; sourceTree = SOURCE_ROOT; };
+               6C7BE2E723C3DD64003BB2CA /* securitytool_bridge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = securitytool_bridge; sourceTree = BUILT_PRODUCTS_DIR; };
                6C814A4A2050B4B600CB391B /* LocalKeychainAnalytics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalKeychainAnalytics.h; sourceTree = "<group>"; };
                6C814A4B2050B4B600CB391B /* LocalKeychainAnalytics.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalKeychainAnalytics.m; sourceTree = "<group>"; };
+               6C84E3C723ECBC84003C9710 /* KeychainAppClipTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainAppClipTests.m; sourceTree = "<group>"; };
                6C860C741F4F63AD004100A1 /* SOSEnsureBackup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SOSEnsureBackup.h; sourceTree = "<group>"; };
                6C860C7A1F4F63DB004100A1 /* SOSEnsureBackup.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SOSEnsureBackup.m; sourceTree = "<group>"; };
                6C880FBE21C334FB00D38D66 /* SecDbBackupBagIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecDbBackupBagIdentity.h; sourceTree = "<group>"; };
                6C880FC721C334FE00D38D66 /* SecDbBackupRecoverySet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecDbBackupRecoverySet.h; sourceTree = "<group>"; };
                6C8CE6BB1FA248B50032ADF0 /* SFAnalyticsActivityTracker+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalyticsActivityTracker+Internal.h"; sourceTree = "<group>"; };
                6C8CE6C31FA24A670032ADF0 /* SFAnalyticsSampler+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SFAnalyticsSampler+Internal.h"; sourceTree = "<group>"; };
+               6C915BE3242E14BC00DBDAFB /* SecDbInternal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecDbInternal.h; sourceTree = "<group>"; };
+               6C963281242A279B00C53CE2 /* stashtester */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stashtester; sourceTree = BUILT_PRODUCTS_DIR; };
+               6C963283242A279B00C53CE2 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+               6C963289242A27F300C53CE2 /* stashtester.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = stashtester.entitlements; sourceTree = "<group>"; };
                6C9791C421C17D060074C609 /* SecDbBackupManager_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecDbBackupManager_Internal.h; sourceTree = "<group>"; };
-               6C9808611E788AEB00E70590 /* CKKSCloudKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CKKSCloudKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-               6C98089D1E788AFD00E70590 /* CKKSCloudKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CKKSCloudKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               6C997869242362EC008C498D /* KeychainStasherProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainStasherProtocol.h; sourceTree = "<group>"; };
+               6C99786A242362EC008C498D /* KeychainStasher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainStasher.h; sourceTree = "<group>"; };
+               6C99786B242362EC008C498D /* KeychainStasher.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainStasher.m; sourceTree = "<group>"; };
+               6C99786D242362EC008C498D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+               6C99786F242362EC008C498D /* KeychainStasher-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "KeychainStasher-Info.plist"; sourceTree = "<group>"; };
+               6C997879242364E5008C498D /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.16.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
+               6C99787C242364FB008C498D /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.16.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
                6C9AA79E1F7C1D8F00D08296 /* supdctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = supdctl; sourceTree = BUILT_PRODUCTS_DIR; };
                6C9AA7A01F7C1D9000D08296 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
                6CA2B9431E9F9F5700C43444 /* RateLimiter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RateLimiter.h; sourceTree = "<group>"; };
                6CA837612210C5E7002770F1 /* kc-45-change-password.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "kc-45-change-password.c"; path = "regressions/kc-45-change-password.c"; sourceTree = "<group>"; };
                6CAA8D201F842FB3007B6E03 /* securityuploadd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = securityuploadd; sourceTree = BUILT_PRODUCTS_DIR; };
-               6CB5F4751E4025AB00DBF3F0 /* CKKSCloudKitTestsInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = CKKSCloudKitTestsInfo.plist; sourceTree = "<group>"; };
-               6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner-Entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "KeychainEntitledTestRunner-Entitlements.plist"; sourceTree = "<group>"; };
+               6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = KeychainEntitledTestRunner.entitlements; sourceTree = "<group>"; };
                6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeychainEntitledTestRunner.m; sourceTree = "<group>"; };
                6CB6CC022198D4BC0080AD6F /* SecDbBackupRecoverySet.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SecDbBackupRecoverySet.proto; sourceTree = "<group>"; };
                6CB96BB41F966E0C00E11457 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
                6CC952421FB4C5CA0051A823 /* SFAnalytics+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFAnalytics+Internal.h"; sourceTree = "<group>"; };
                6CCDF7841E3C25FA003F2555 /* KeychainEntitledTestRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = KeychainEntitledTestRunner; sourceTree = BUILT_PRODUCTS_DIR; };
                6CCDF78B1E3C26BC003F2555 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Platforms/MacOSX.platform/Developer/Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
-               6CCDF7911E3C2D69003F2555 /* CKKSCloudKitTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSCloudKitTests.m; sourceTree = "<group>"; };
+               6CD224E7239493E8001B70FD /* SecDbBackupTestsBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecDbBackupTestsBase.h; sourceTree = "<group>"; };
+               6CD8412B23F5D871003DDF34 /* KeychainBackupTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainBackupTests.m; sourceTree = "<group>"; };
                6CDB5FED1FA78CB400410924 /* SFAnalyticsMultiSampler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SFAnalyticsMultiSampler.m; sourceTree = "<group>"; };
                6CDB5FF31FA78CB500410924 /* SFAnalyticsMultiSampler+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SFAnalyticsMultiSampler+Internal.h"; sourceTree = "<group>"; };
                6CDB5FF41FA78CB500410924 /* SFAnalyticsMultiSampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SFAnalyticsMultiSampler.h; sourceTree = "<group>"; };
                6CDF8DE51F95562B00140B54 /* SFAnalyticsSampler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFAnalyticsSampler.h; sourceTree = "<group>"; };
                6CDF8DE61F95562B00140B54 /* SFAnalyticsSampler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFAnalyticsSampler.m; sourceTree = "<group>"; };
                6CE22D6F1E49206600974785 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
+               6CF1B5C5245077E400FD8CC4 /* SecItemRateLimit_tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecItemRateLimit_tests.h; sourceTree = "<group>"; };
+               6CF33CA2238714C900D1E75D /* bats_utd_plist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bats_utd_plist.h; sourceTree = "<group>"; };
+               6CF33CA4238714C900D1E75D /* PreprocessPlist.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = PreprocessPlist.sh; sourceTree = "<group>"; };
                6CF4A0B41E45488B00ECD7B5 /* KeychainEntitledTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeychainEntitledTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
                6CF4A0B61E45488B00ECD7B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
                6CF4A0B71E45488B00ECD7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
                6CF4A0BC1E45488B00ECD7B5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
                6CF4A0BD1E45488B00ECD7B5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
                6CF4A0BF1E45488B00ECD7B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
-               6CF4A0C41E45488B00ECD7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
-               6CF4A0E01E4549F200ECD7B5 /* KeychainEntitledTestApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = KeychainEntitledTestApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
-               6CF4A0E31E4549F200ECD7B5 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
-               6CF4A0E51E4549F200ECD7B5 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
-               6CF4A0E61E4549F300ECD7B5 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-               6CF4A0E81E4549F300ECD7B5 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
-               6CF4A0E91E4549F300ECD7B5 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
-               6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
-               6CF4A0F31E4549F300ECD7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               6CF4A0C41E45488B00ECD7B5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
                6CFDC4561F907E1D00646DBB /* libprequelite.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libprequelite.tbd; path = usr/lib/libprequelite.tbd; sourceTree = SDKROOT; };
                7221843E1EC6782A004C7BED /* sec_action.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sec_action.c; sourceTree = "<group>"; };
                7221843F1EC6782A004C7BED /* sec_action.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sec_action.h; sourceTree = "<group>"; };
                8ED6F6C8110904E300D2B368 /* SecPBKDF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecPBKDF.h; sourceTree = "<group>"; };
                A6B1BA78207BD9D400F1E099 /* notarization.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = notarization.cpp; sourceTree = "<group>"; };
                A6B1BA79207BD9D400F1E099 /* notarization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = notarization.h; sourceTree = "<group>"; };
+               A6BF3B3123EB94A7009AF079 /* entitlements.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = entitlements.h; sourceTree = "<group>"; };
+               A6BF3B3223EB94A7009AF079 /* entitlements.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = entitlements.c; sourceTree = "<group>"; };
                AA0DA47821E8189D009F1C74 /* example1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = example1.json; path = protocol/test_data/example1.json; sourceTree = "<group>"; };
                AA0DA47921E8189E009F1C74 /* builtins.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = builtins.json; path = protocol/test_data/builtins.json; sourceTree = "<group>"; };
                AA44E0B3202E3451001EA371 /* SecProtocolTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SecProtocolTest.m; path = protocol/SecProtocolTest.m; sourceTree = "<group>"; };
                BE55C77A2044D0C80045863D /* TrustedPeersHelper-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "TrustedPeersHelper-Bridging-Header.h"; sourceTree = "<group>"; };
                BE55C77B2044D0C90045863D /* Client.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Client.swift; sourceTree = "<group>"; };
                BE55C77D2044D7E60045863D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
-               BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-84-sectrust-allowlist.m"; sourceTree = "<group>"; };
+               BE57B1162509E0FF0045B7FD /* ca_revocation_additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ca_revocation_additions.m; sourceTree = "<group>"; };
                BE64A7FD22AF0109001209F3 /* trusted_cert_ssl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trusted_cert_ssl.h; sourceTree = "<group>"; };
                BE64A7FE22AF010A001209F3 /* trusted_cert_ssl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = trusted_cert_ssl.m; sourceTree = "<group>"; };
                BE7089911F9AA027001ACC20 /* TPPBVoucher.proto */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.protobuf; path = TPPBVoucher.proto; sourceTree = "<group>"; };
                BE7089DD1FA40B93001ACC20 /* TPPBPeerPermanentInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPPBPeerPermanentInfo.h; sourceTree = "<group>"; };
                BE7089DE1FA40B95001ACC20 /* TPPBPeerPermanentInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TPPBPeerPermanentInfo.m; sourceTree = "<group>"; };
                BE72782A209D27C800F0DA77 /* TPKeyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPKeyTests.m; sourceTree = "<group>"; };
-               BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = framework_requiring_modern_objc_runtime.xcconfig; path = xcconfig/framework_requiring_modern_objc_runtime.xcconfig; sourceTree = "<group>"; };
+               BE7B8E112415579800E1CF4F /* SecSharedCredential.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecSharedCredential.m; sourceTree = "<group>"; };
                BE8ABDD71DC2DD9100EC2D58 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
                BE92249D204F203C0052E828 /* TrustedPeersHelper.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TrustedPeersHelper.xcdatamodel; sourceTree = "<group>"; };
-               BE9B8B43202BB42C0081EF87 /* si-88-sectrust-valid-data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "si-88-sectrust-valid-data"; sourceTree = "<group>"; };
-               BE9B8B49202BB4A10081EF87 /* si-88-sectrust-valid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "si-88-sectrust-valid.m"; path = "OSX/shared_regressions/si-88-sectrust-valid.m"; sourceTree = SOURCE_ROOT; };
                BE9F4F8B2072D881004A52C2 /* Cuttlefish.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Cuttlefish.pb.swift; sourceTree = "<group>"; };
                BE9F8D0F206C099800B53D16 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = "<group>"; };
                BE9F8D11206C121400B53D16 /* Decrypter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decrypter.swift; sourceTree = "<group>"; };
                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 = "<group>"; };
                D41D36701EB14D87007FA978 /* libDiagnosticMessagesClient.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libDiagnosticMessagesClient.tbd; path = usr/lib/libDiagnosticMessagesClient.tbd; sourceTree = SDKROOT; };
+               D423114223725F9F000E470A /* SMIMEPolicyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = SMIMEPolicyTests.m; path = tests/TrustTests/EvaluationTests/SMIMEPolicyTests.m; sourceTree = "<group>"; };
+               D4231147237261F7000E470A /* SMIMEPolicyTests-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "SMIMEPolicyTests-data"; path = "tests/TrustTests/TestData/SMIMEPolicyTests-data"; sourceTree = "<group>"; };
                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; };
                D42C8390211590BC008D3D83 /* CMSDecoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CMSDecoder.cpp; path = OSX/libsecurity_cms/lib/CMSDecoder.cpp; sourceTree = "<group>"; };
                D42C83A221159569008D3D83 /* cms-trust-settings-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cms-trust-settings-test.c"; path = "OSX/libsecurity_cms/regressions/cms-trust-settings-test.c"; sourceTree = "<group>"; };
                D42C83A321159569008D3D83 /* cms-trust-settings-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cms-trust-settings-test.h"; path = "OSX/libsecurity_cms/regressions/cms-trust-settings-test.h"; sourceTree = "<group>"; };
                D42C83A621163866008D3D83 /* cert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cert.h; path = libsecurity_smime/lib/cert.h; sourceTree = SOURCE_ROOT; };
+               D42D044124733BEA004E7AA2 /* com.apple.securityuploadd.sb */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.securityuploadd.sb; sourceTree = "<group>"; };
                D437185C211671A300EA350A /* cms-01-basic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "cms-01-basic.c"; path = "OSX/libsecurity_smime/regressions/cms-01-basic.c"; sourceTree = "<group>"; };
                D437185D211671A400EA350A /* smime-cms-test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "smime-cms-test.c"; path = "OSX/libsecurity_smime/regressions/smime-cms-test.c"; sourceTree = "<group>"; };
                D437185E211671A400EA350A /* cms-01-basic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "cms-01-basic.h"; path = "OSX/libsecurity_smime/regressions/cms-01-basic.h"; sourceTree = "<group>"; };
                D458C4C0214E19FB0043D982 /* TrustInterfaceTests_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrustInterfaceTests_data.h; path = tests/TrustTests/FrameworkTests/TrustInterfaceTests_data.h; sourceTree = "<group>"; };
                D458C4C5214E1A400043D982 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = tests/TrustTests/TestRunners/Assets.xcassets; sourceTree = "<group>"; };
                D458C4C6214E1A400043D982 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = tests/TrustTests/TestRunners/main.m; sourceTree = "<group>"; };
-               D458C4C7214E1A400043D982 /* Base.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Base.lproj; path = tests/TrustTests/TestRunners/Base.lproj; sourceTree = "<group>"; };
                D458C4C8214E1A410043D982 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = tests/TrustTests/TestRunners/AppDelegate.h; sourceTree = "<group>"; };
                D458C4C9214E1A410043D982 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewController.h; path = tests/TrustTests/TestRunners/ViewController.h; sourceTree = "<group>"; };
                D458C4CA214E1A420043D982 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = tests/TrustTests/TestRunners/AppDelegate.m; sourceTree = "<group>"; };
                D458C513214E27620043D982 /* PolicyTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PolicyTests.m; path = tests/TrustTests/EvaluationTests/PolicyTests.m; sourceTree = "<group>"; };
                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 = "<group>"; };
                D458C51E214E2E0C0043D982 /* Main.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Main.storyboard; path = tests/TrustTests/TestRunners/Main.storyboard; sourceTree = "<group>"; };
+               D458DAC22375FEA300E5890E /* TrustSettingsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustSettingsTests.m; path = tests/TrustTests/EvaluationTests/TrustSettingsTests.m; sourceTree = "<group>"; };
+               D458DAC52375FEE900E5890E /* TrustSettingsTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TrustSettingsTests_data.h; path = tests/TrustTests/EvaluationTests/TrustSettingsTests_data.h; sourceTree = "<group>"; };
                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/headers/oids.h; sourceTree = "<group>"; };
                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; };
                D46246CE1F9AEAE300D63882 /* libDER.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libDER.a; path = usr/local/lib/security_libDER/libDER.a; sourceTree = SDKROOT; };
-               D46513072097954B005D93FE /* si-23-sectrust-ocsp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "si-23-sectrust-ocsp.h"; sourceTree = "<group>"; };
                D47079F221128C46005BCFDA /* SecCMS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SecCMS.h; path = CMS/SecCMS.h; sourceTree = "<group>"; };
                D47079F9211355B3005BCFDA /* CMSEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CMSEncoder.h; path = CMS/CMSEncoder.h; sourceTree = "<group>"; };
                D4707A0521136E69005BCFDA /* TrustTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TrustTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                D4707A282113ECA0005BCFDA /* SecCmsMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsMessage.h; path = CMS/SecCmsMessage.h; sourceTree = "<group>"; };
                D4707A2B2114B31A005BCFDA /* SecCmsContentInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsContentInfo.h; path = CMS/SecCmsContentInfo.h; sourceTree = "<group>"; };
                D4707A2E2114C30A005BCFDA /* SecCmsDigestContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCmsDigestContext.h; path = CMS/SecCmsDigestContext.h; sourceTree = "<group>"; };
+               D477CB5B237B6E0E00C02355 /* PersonalizationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = PersonalizationTests.m; path = tests/TrustTests/DaemonTests/PersonalizationTests.m; sourceTree = "<group>"; };
+               D477CB69237CBA2C00C02355 /* TrustDaemonTestCase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustDaemonTestCase.m; path = tests/TrustTests/DaemonTests/TrustDaemonTestCase.m; sourceTree = "<group>"; };
+               D477CB6D237CBACD00C02355 /* TrustDaemonTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TrustDaemonTestCase.h; path = tests/TrustTests/DaemonTests/TrustDaemonTestCase.h; sourceTree = "<group>"; };
                D477CB76237E453C00C02355 /* si-88-sectrust-valid-data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "si-88-sectrust-valid-data"; path = "SecurityTests/si-88-sectrust-valid-data"; sourceTree = "<group>"; };
                D477CB7A237E4BD700C02355 /* ExceptionTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ExceptionTests.m; path = tests/TrustTests/EvaluationTests/ExceptionTests.m; sourceTree = "<group>"; };
                D477CB7D237F321400C02355 /* ExceptionTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ExceptionTests_data.h; path = tests/TrustTests/EvaluationTests/ExceptionTests_data.h; sourceTree = "<group>"; };
+               D477CB81237F692400C02355 /* RevocationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RevocationTests.m; path = tests/TrustTests/EvaluationTests/RevocationTests.m; sourceTree = "<group>"; };
+               D477CB85237F6A0700C02355 /* RevocationTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RevocationTests_data.h; path = tests/TrustTests/EvaluationTests/RevocationTests_data.h; sourceTree = "<group>"; };
+               D477CB86237F8B2F00C02355 /* CAIssuerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = CAIssuerTests.m; path = tests/TrustTests/EvaluationTests/CAIssuerTests.m; sourceTree = "<group>"; };
+               D477CB89237F8CB300C02355 /* CAIssuerTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CAIssuerTests_data.h; path = tests/TrustTests/EvaluationTests/CAIssuerTests_data.h; sourceTree = "<group>"; };
+               D477CB8A237F8DBB00C02355 /* AllowlistBlocklistTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AllowlistBlocklistTests.m; path = tests/TrustTests/EvaluationTests/AllowlistBlocklistTests.m; sourceTree = "<group>"; };
+               D477CB8D237F8EB200C02355 /* AllowlistBlocklistTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AllowlistBlocklistTests_data.h; path = tests/TrustTests/EvaluationTests/AllowlistBlocklistTests_data.h; sourceTree = "<group>"; };
+               D477CB8E237F975500C02355 /* ValidTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = ValidTests.m; path = tests/TrustTests/EvaluationTests/ValidTests.m; sourceTree = "<group>"; };
                D479F6E01F980F8F00388D28 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = en.lproj/Trust.strings; sourceTree = "<group>"; };
+               D47A085B2486EC1A000F2C49 /* AppleExternalRootCertificates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppleExternalRootCertificates.h; sourceTree = "<group>"; };
+               D47A55892466100A0039285D /* MSUDataAccessor.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MSUDataAccessor.framework; path = System/Library/PrivateFrameworks/MSUDataAccessor.framework; sourceTree = SDKROOT; };
                D47AB2CA2356AD72005A3801 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
                D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64.xcconfig; path = xcconfig/lib_ios_x64.xcconfig; sourceTree = "<group>"; };
                D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = lib_ios_x64_shim.xcconfig; path = xcconfig/lib_ios_x64_shim.xcconfig; sourceTree = "<group>"; };
-               D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = all_arches.xcconfig; path = xcconfig/all_arches.xcconfig; sourceTree = "<group>"; };
                D47CA65C1EB036450038E2BB /* libMobileGestalt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libMobileGestalt.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.0.Internal.sdk/usr/lib/libMobileGestalt.dylib; sourceTree = DEVELOPER_DIR; };
                D47DCCB423427C7D00B80E37 /* md.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = md.m; sourceTree = "<group>"; };
                D47DCCB723427C8D00B80E37 /* md.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = md.h; sourceTree = "<group>"; };
                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; path = TrustURLSessionDelegate.m; sourceTree = "<group>"; };
                D4961BC52079426000F16DA7 /* TrustURLSessionDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TrustURLSessionDelegate.h; sourceTree = "<group>"; };
-               D49A370023873A570065719F /* RevocationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RevocationTests.m; path = tests/TrustTests/EvaluationTests/RevocationTests.m; sourceTree = "<group>"; };
-               D49A370223873A570065719F /* RevocationTests_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RevocationTests_data.h; path = tests/TrustTests/EvaluationTests/RevocationTests_data.h; sourceTree = "<group>"; };
-               D49A370523873BD30065719F /* TrustDaemonTestCase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = TrustDaemonTestCase.m; path = tests/TrustTests/DaemonTests/TrustDaemonTestCase.m; sourceTree = "<group>"; };
-               D49A370823873BF10065719F /* TrustDaemonTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TrustDaemonTestCase.h; path = tests/TrustTests/DaemonTests/TrustDaemonTestCase.h; sourceTree = "<group>"; };
                D49A370B23877ECC0065719F /* OCSPCacheTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = OCSPCacheTests.m; path = tests/TrustTests/DaemonTests/OCSPCacheTests.m; sourceTree = "<group>"; };
                D4A0F8BA211E69CB00443CA1 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = tests/TrustTests/Info.plist; sourceTree = "<group>"; };
                D4A0F8BB211E69CB00443CA1 /* TestMacroConversions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TestMacroConversions.h; path = tests/TrustTests/TestMacroConversions.h; sourceTree = "<group>"; };
                D4FD4222217D7B48002B7EE2 /* PathScoringTests_data.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PathScoringTests_data.h; path = tests/TrustTests/EvaluationTests/PathScoringTests_data.h; sourceTree = "<group>"; };
                D4FD4223217D7BE3002B7EE2 /* libarchive.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.2.tbd; path = usr/lib/libarchive.2.tbd; sourceTree = SDKROOT; };
                DA2C402D2189302E005F1CC3 /* mach_notify.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = mach_notify.defs; sourceTree = "<group>"; };
+               DA2F591523A32BB400C30285 /* SoftLinking.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SoftLinking.framework; path = System/Library/PrivateFrameworks/SoftLinking.framework; sourceTree = SDKROOT; };
                DA30D6761DF8C8FB00EC6B43 /* KeychainSyncAccountUpdater.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KeychainSyncAccountUpdater.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                DA30D6781DF8C8FB00EC6B43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                DA30D6831DF8CA4100EC6B43 /* KeychainSyncAccountUpdater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeychainSyncAccountUpdater.h; sourceTree = "<group>"; };
                DC05037621409A4000A8EDB7 /* OCMockUmbrella.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OCMockUmbrella.framework; sourceTree = BUILT_PRODUCTS_DIR; };
                DC05037821409A4100A8EDB7 /* OCMockUmbrella.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OCMockUmbrella.h; sourceTree = "<group>"; };
                DC05037921409A4100A8EDB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               DC061A6E246211DD0026ADB3 /* CKKSLocalResetOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSLocalResetOperation.h; sourceTree = "<group>"; };
+               DC061A70246211DE0026ADB3 /* CKKSLocalResetOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSLocalResetOperation.m; sourceTree = "<group>"; };
                DC07090222936BCC002711B9 /* OctagonTests+ErrorHandling.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+ErrorHandling.swift"; sourceTree = "<group>"; };
                DC08D1C21E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CloudKitKeychainSyncingMockXCTest.h; sourceTree = "<group>"; };
                DC08D1C31E64FA8C006237DA /* CloudKitKeychainSyncingMockXCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CloudKitKeychainSyncingMockXCTest.m; sourceTree = "<group>"; };
                DC1787241D778FDE00B50D50 /* SecManifest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecManifest.h; path = OSX/libsecurity_manifest/lib/SecManifest.h; sourceTree = "<group>"; };
                DC1787251D778FDE00B50D50 /* SecureDownloadInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecureDownloadInternal.h; path = OSX/libsecurity_manifest/lib/SecureDownloadInternal.h; sourceTree = "<group>"; };
                DC1787281D77903700B50D50 /* SecAccessPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecAccessPriv.h; path = OSX/libsecurity_keychain/lib/SecAccessPriv.h; sourceTree = "<group>"; };
-               DC1787291D77903700B50D50 /* SecCertificateBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecCertificateBundle.h; path = OSX/libsecurity_keychain/lib/SecCertificateBundle.h; sourceTree = "<group>"; };
                DC17872A1D77903700B50D50 /* SecFDERecoveryAsymmetricCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecFDERecoveryAsymmetricCrypto.h; path = OSX/libsecurity_keychain/lib/SecFDERecoveryAsymmetricCrypto.h; sourceTree = "<group>"; };
                DC17872B1D77903700B50D50 /* SecIdentitySearchPriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecIdentitySearchPriv.h; path = OSX/libsecurity_keychain/lib/SecIdentitySearchPriv.h; sourceTree = "<group>"; };
                DC17872C1D77903700B50D50 /* SecKeychainItemExtendedAttributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecKeychainItemExtendedAttributes.h; path = OSX/libsecurity_keychain/lib/SecKeychainItemExtendedAttributes.h; sourceTree = "<group>"; };
                DC1787671D77911D00B50D50 /* osKeyTemplates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = osKeyTemplates.h; path = OSX/libsecurity_asn1/lib/osKeyTemplates.h; sourceTree = "<group>"; };
                DC1787681D77911D00B50D50 /* secasn1t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = secasn1t.h; path = OSX/libsecurity_asn1/lib/secasn1t.h; sourceTree = "<group>"; };
                DC1787691D77911D00B50D50 /* X509Templates.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = X509Templates.h; path = OSX/libsecurity_asn1/lib/X509Templates.h; sourceTree = "<group>"; };
-               DC1787731D77915500B50D50 /* SecBreadcrumb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SecBreadcrumb.h; path = OSX/Breadcrumb/SecBreadcrumb.h; sourceTree = SOURCE_ROOT; };
                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; };
                DC1789221D7799A600B50D50 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
                DC1789241D7799CD00B50D50 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
                DC1789261D7799D300B50D50 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
-               DC1789A01D779DEE00B50D50 /* SecBreadcrumb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SecBreadcrumb.c; path = OSX/Breadcrumb/SecBreadcrumb.c; sourceTree = "<group>"; };
                DC1789A41D779E3B00B50D50 /* dummy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dummy.cpp; path = OSX/lib/dummy.cpp; sourceTree = "<group>"; };
                DC178A0E1D77A1E700B50D50 /* cssm.mdsinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = cssm.mdsinfo; path = OSX/libsecurity_cssm/mds/cssm.mdsinfo; sourceTree = "<group>"; };
                DC178A0F1D77A1E700B50D50 /* csp_capabilities.mdsinfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = csp_capabilities.mdsinfo; path = OSX/libsecurity_apple_csp/mds/csp_capabilities.mdsinfo; sourceTree = "<group>"; };
                DC178A311D77A1F500B50D50 /* FDEPrefs.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = FDEPrefs.plist; path = OSX/lib/FDEPrefs.plist; sourceTree = "<group>"; };
                DC178A321D77A1F500B50D50 /* SecDebugErrorMessages.strings */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; fileEncoding = 10; name = SecDebugErrorMessages.strings; path = derived_src/SecDebugErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; };
                DC178A341D77A1F500B50D50 /* SecErrorMessages.strings */ = {isa = PBXFileReference; explicitFileType = text.plist.strings; fileEncoding = 10; name = SecErrorMessages.strings; path = derived_src/en.lproj/SecErrorMessages.strings; sourceTree = BUILT_PRODUCTS_DIR; };
-               DC178A351D77A1F500B50D50 /* framework.sb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = framework.sb; path = OSX/lib/framework.sb; sourceTree = "<group>"; };
                DC178A391D77A1F500B50D50 /* en */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = en; path = OSX/lib/en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
                DC178A3A1D77A1F500B50D50 /* TimeStampingPrefs.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = TimeStampingPrefs.plist; path = OSX/lib/TimeStampingPrefs.plist; sourceTree = "<group>"; };
                DC178A3C1D77A1F500B50D50 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = OSX/lib/en.lproj/authorization.dfr.prompts.strings; sourceTree = "<group>"; };
                DC24B5681DA326B900330B48 /* rule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rule.h; path = OSX/authd/rule.h; sourceTree = "<group>"; };
                DC24B5691DA326B900330B48 /* server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = server.h; path = OSX/authd/server.h; sourceTree = "<group>"; };
                DC24B56A1DA326B900330B48 /* session.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = session.h; path = OSX/authd/session.h; sourceTree = "<group>"; };
-               DC24B5701DA3274000330B48 /* breadcrumb_regressions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = breadcrumb_regressions.h; path = OSX/Breadcrumb/breadcrumb_regressions.h; sourceTree = "<group>"; };
                DC24B5711DA327A800330B48 /* KDAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KDAppDelegate.h; path = OSX/Keychain/KDAppDelegate.h; sourceTree = SOURCE_ROOT; };
                DC24B5721DA327A800330B48 /* KDCirclePeer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KDCirclePeer.h; path = OSX/Keychain/KDCirclePeer.h; sourceTree = SOURCE_ROOT; };
                DC24B5731DA327A800330B48 /* KDSecCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KDSecCircle.h; path = OSX/Keychain/KDSecCircle.h; sourceTree = SOURCE_ROOT; };
                DC311E782124B8EF002F5EAE /* aks_real_witness.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = aks_real_witness.h; sourceTree = "<group>"; };
                DC311E792124B8EF002F5EAE /* aks_real_witness.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = aks_real_witness.c; sourceTree = "<group>"; };
                DC340C53208E7BAE004D7EEC /* swift_binary.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = swift_binary.xcconfig; path = xcconfig/swift_binary.xcconfig; sourceTree = "<group>"; };
+               DC3412E5245780B9008ABD0A /* CKKSOperationDependencies.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSOperationDependencies.h; sourceTree = "<group>"; };
+               DC3412E6245780BA008ABD0A /* CKKSOperationDependencies.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSOperationDependencies.m; sourceTree = "<group>"; };
                DC3502B51E0208BE00BC0587 /* CKKSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CKKSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                DC3502B71E0208BE00BC0587 /* CKKSTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSTests.m; sourceTree = "<group>"; };
                DC3502B91E0208BE00BC0587 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                DC6ACC401E81DF9400125DC5 /* server_endpoint.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = server_endpoint.m; sourceTree = "<group>"; };
                DC6DE897213076C000C6B56D /* OTSOSUpgradeOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSOSUpgradeOperation.h; sourceTree = "<group>"; };
                DC6DE898213076C000C6B56D /* OTSOSUpgradeOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSOSUpgradeOperation.m; sourceTree = "<group>"; };
+               DC6E02122405DDC300C61335 /* OTModifyUserControllableViewStatusOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTModifyUserControllableViewStatusOperation.h; sourceTree = "<group>"; };
+               DC6E02132405DDC400C61335 /* OTModifyUserControllableViewStatusOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTModifyUserControllableViewStatusOperation.m; sourceTree = "<group>"; };
                DC7181062089172F00B2CB13 /* TrustedPeersHelper-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TrustedPeersHelper-entitlements.plist"; sourceTree = "<group>"; };
                DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = lib_ios_shim.xcconfig; path = xcconfig/lib_ios_shim.xcconfig; sourceTree = "<group>"; };
                DC72502D229600A800493D88 /* OctagonTests+Reset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+Reset.swift"; sourceTree = "<group>"; };
                DC844AEC1E81F315007AAB71 /* client_endpoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = client_endpoint.m; sourceTree = "<group>"; };
                DC85687C2284E7850088D3EF /* OctagonTestMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OctagonTestMocks.swift; sourceTree = "<group>"; };
                DC85687F2284E79C0088D3EF /* OctagonEscrowRecoverer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OctagonEscrowRecoverer.h; sourceTree = "<group>"; };
+               DC86122B2408AC190092E93B /* CKKSTests+ItemSyncChoice.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+ItemSyncChoice.m"; sourceTree = "<group>"; };
                DC8757F2218D2003000E65F1 /* OTRemovePeersOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTRemovePeersOperation.h; sourceTree = "<group>"; };
                DC8757F3218D2003000E65F1 /* OTRemovePeersOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTRemovePeersOperation.m; sourceTree = "<group>"; };
+               DC880F67243D4CC00059806D /* CKKSLogging.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSLogging.m; sourceTree = "<group>"; };
                DC8834081D8A218F00CE0ACA /* libASN1.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libASN1.a; sourceTree = BUILT_PRODUCTS_DIR; };
                DC88340A1D8A21AA00CE0ACA /* SecAsn1Coder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAsn1Coder.c; sourceTree = "<group>"; };
                DC88340C1D8A21AA00CE0ACA /* SecAsn1Templates.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecAsn1Templates.c; sourceTree = "<group>"; };
                DC90A4C621F279D4001300EB /* SecEscrowPendingRecord.proto */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.protobuf; path = SecEscrowPendingRecord.proto; sourceTree = "<group>"; };
                DC93F02722387A010072720A /* OTSOSUpdatePreapprovalsOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSOSUpdatePreapprovalsOperation.h; sourceTree = "<group>"; };
                DC93F02822387A010072720A /* OTSOSUpdatePreapprovalsOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSOSUpdatePreapprovalsOperation.m; sourceTree = "<group>"; };
+               DC947E812463831E005B8669 /* CKKSCheckKeyHierarchyOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSCheckKeyHierarchyOperation.h; sourceTree = "<group>"; };
+               DC947E832463831F005B8669 /* CKKSCheckKeyHierarchyOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSCheckKeyHierarchyOperation.m; sourceTree = "<group>"; };
                DC94BCC81F10448600E07CEB /* CloudKitCategories.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CloudKitCategories.h; sourceTree = "<group>"; };
                DC94BCC91F10448600E07CEB /* CloudKitCategories.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CloudKitCategories.m; sourceTree = "<group>"; };
                DC976C581E3AC5E50012A6DD /* PlatformFeatures.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = PlatformFeatures.xcconfig; path = xcconfig/PlatformFeatures.xcconfig; sourceTree = "<group>"; };
+               DC9978B72404AA3200A5EE2F /* Container_UserSync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container_UserSync.swift; sourceTree = "<group>"; };
                DC99B89220EACA470065B73B /* OctagonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OctagonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                DC99B89320EACA480065B73B /* OctagonTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "OctagonTests-Info.plist"; sourceTree = "<group>"; };
                DC9A2C5E1EB3F556008FAC27 /* CKKSTests+Coalesce.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+Coalesce.m"; sourceTree = "<group>"; };
                DCA4D1F41E5520550056214F /* CKKSCurrentKeyPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSCurrentKeyPointer.m; sourceTree = "<group>"; };
                DCA4D2131E5684220056214F /* CKKSReencryptOutgoingItemsOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSReencryptOutgoingItemsOperation.h; sourceTree = "<group>"; };
                DCA4D2141E5684220056214F /* CKKSReencryptOutgoingItemsOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSReencryptOutgoingItemsOperation.m; sourceTree = "<group>"; };
+               DCA7F7EE23A44AA200927989 /* OctagonPolicyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OctagonPolicyTests.swift; sourceTree = "<group>"; };
                DCA9BC00221B721D00B4EB26 /* CKKSCloudKitClassDependencies.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSCloudKitClassDependencies.h; sourceTree = "<group>"; };
                DCA9BC01221B721E00B4EB26 /* CKKSCloudKitClassDependencies.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSCloudKitClassDependencies.m; sourceTree = "<group>"; };
                DCA9BC05221B7AFB00B4EB26 /* CKKSMockSOSPresentAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSMockSOSPresentAdapter.h; sourceTree = "<group>"; };
                DCB342441D8A32A20054D16E /* SecBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecBase.cpp; sourceTree = "<group>"; };
                DCB342451D8A32A20054D16E /* SecBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecBridge.h; sourceTree = "<group>"; };
                DCB342461D8A32A20054D16E /* SecCertificate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCertificate.cpp; sourceTree = "<group>"; };
-               DCB342471D8A32A20054D16E /* SecCertificateBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCertificateBundle.cpp; sourceTree = "<group>"; };
                DCB342491D8A32A20054D16E /* SecIdentity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecIdentity.cpp; sourceTree = "<group>"; };
                DCB3424A1D8A32A20054D16E /* SecIdentitySearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecIdentitySearch.cpp; sourceTree = "<group>"; };
                DCB3424B1D8A32A20054D16E /* SecItemConstants.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SecItemConstants.c; sourceTree = "<group>"; };
                DCB342A51D8A32A20054D16E /* PolicyCursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PolicyCursor.h; sourceTree = "<group>"; };
                DCB342A61D8A32A20054D16E /* SecCFTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecCFTypes.cpp; sourceTree = "<group>"; };
                DCB342A71D8A32A20054D16E /* SecCFTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecCFTypes.h; sourceTree = "<group>"; };
-               DCB342A81D8A32A20054D16E /* SecKeychainAddIToolsPassword.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecKeychainAddIToolsPassword.cpp; sourceTree = "<group>"; };
                DCB342AA1D8A32A20054D16E /* StorageManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = StorageManager.cpp; sourceTree = "<group>"; };
                DCB342AB1D8A32A20054D16E /* Trust.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Trust.cpp; sourceTree = "<group>"; };
                DCB342AC1D8A32A20054D16E /* Trust.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Trust.h; sourceTree = "<group>"; };
                DCB344711D8A35270054D16E /* si-33-keychain-backup.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "si-33-keychain-backup.c"; path = "regressions/si-33-keychain-backup.c"; sourceTree = "<group>"; };
                DCB344721D8A35270054D16E /* si-34-one-true-keychain.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "si-34-one-true-keychain.c"; path = "regressions/si-34-one-true-keychain.c"; sourceTree = "<group>"; };
                DCB41DF9216C3F8A00F219E0 /* tpctl-entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "tpctl-entitlements.plist"; sourceTree = "<group>"; };
+               DCB5516A247F3DB50009A859 /* CKKSCreateCKZoneOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSCreateCKZoneOperation.h; sourceTree = "<group>"; };
+               DCB5516B247F3DB50009A859 /* CKKSCreateCKZoneOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSCreateCKZoneOperation.m; sourceTree = "<group>"; };
+               DCB55173247F48290009A859 /* CKKSDeleteCKZoneOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSDeleteCKZoneOperation.h; sourceTree = "<group>"; };
+               DCB55174247F48290009A859 /* CKKSDeleteCKZoneOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSDeleteCKZoneOperation.m; sourceTree = "<group>"; };
                DCB5D9391E4A9A3400BE22AB /* CKKSSynchronizeOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSSynchronizeOperation.h; sourceTree = "<group>"; };
                DCB5D93A1E4A9A3400BE22AB /* CKKSSynchronizeOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSynchronizeOperation.m; sourceTree = "<group>"; };
                DCB946AD22FCB88400BE4490 /* OTDetermineHSA2AccountStatusOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTDetermineHSA2AccountStatusOperation.h; sourceTree = "<group>"; };
                DCB947592127534C00ED9272 /* OctagonTests+SOSUpgrade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+SOSUpgrade.swift"; sourceTree = "<group>"; };
                DCB9475B2127562100ED9272 /* OTSOSAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTSOSAdapter.h; sourceTree = "<group>"; };
                DCB9475C2127562100ED9272 /* OTSOSAdapter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTSOSAdapter.m; sourceTree = "<group>"; };
+               DCBA6F2824105399009A5187 /* CKKSTests+ForwardCompatibility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "CKKSTests+ForwardCompatibility.m"; sourceTree = "<group>"; };
+               DCBDA460245A39A300B0938B /* com.apple.TrustedPeersHelper.sb */ = {isa = PBXFileReference; lastKnownFileType = text; path = com.apple.TrustedPeersHelper.sb; sourceTree = "<group>"; };
                DCBDB3B01E57C67500B61300 /* CKKSKeychainView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSKeychainView.h; sourceTree = "<group>"; };
                DCBDB3B11E57C67500B61300 /* CKKSKeychainView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSKeychainView.m; sourceTree = "<group>"; };
                DCBDB3B91E57CA7A00B61300 /* CKKSViewManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSViewManager.h; sourceTree = "<group>"; };
                DCBF4AE321FFC9A800539F0A /* SecEscrowRequestTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecEscrowRequestTests.m; sourceTree = "<group>"; };
                DCBFF830222611A200C5C044 /* OTFetchCKKSKeysOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTFetchCKKSKeysOperation.h; sourceTree = "<group>"; };
                DCBFF831222611A200C5C044 /* OTFetchCKKSKeysOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTFetchCKKSKeysOperation.m; sourceTree = "<group>"; };
+               DCC03FA223FF521100A4DA3F /* TPSyncingPolicy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TPSyncingPolicy.h; sourceTree = "<group>"; };
+               DCC03FA323FF521100A4DA3F /* TPSyncingPolicy.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TPSyncingPolicy.m; sourceTree = "<group>"; };
                DCC0800D1CFF7903005C35C8 /* CSSMOID.exp-in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "CSSMOID.exp-in"; sourceTree = "<group>"; };
                DCC1849220EEEC4400F3B26C /* security_framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = security_framework.xcconfig; path = xcconfig/security_framework.xcconfig; sourceTree = "<group>"; };
+               DCC40B0F2383786D00402CB9 /* CKKSStates.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CKKSStates.h; sourceTree = "<group>"; };
+               DCC40B102383786D00402CB9 /* CKKSStates.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSStates.m; sourceTree = "<group>"; };
                DCC5417F225C05170095D926 /* OTUploadNewCKKSTLKsOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTUploadNewCKKSTLKsOperation.h; sourceTree = "<group>"; };
                DCC54180225C05180095D926 /* OTUploadNewCKKSTLKsOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTUploadNewCKKSTLKsOperation.m; sourceTree = "<group>"; };
                DCC5860220BF8A98005C7269 /* SecBase.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecBase.c; sourceTree = "<group>"; };
                DCC78DBD1D8085FC00865A7C /* si-21-sectrust-asr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-21-sectrust-asr.c"; sourceTree = "<group>"; };
                DCC78DBE1D8085FC00865A7C /* si-22-sectrust-iap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-22-sectrust-iap.c"; sourceTree = "<group>"; };
                DCC78DBF1D8085FC00865A7C /* si-22-sectrust-iap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-22-sectrust-iap.h"; sourceTree = "<group>"; };
-               DCC78DC01D8085FC00865A7C /* si-23-sectrust-ocsp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-23-sectrust-ocsp.c"; sourceTree = "<group>"; };
                DCC78DC11D8085FC00865A7C /* si-24-sectrust-digicert-malaysia.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-24-sectrust-digicert-malaysia.c"; sourceTree = "<group>"; };
                DCC78DC21D8085FC00865A7C /* si-24-sectrust-diginotar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-24-sectrust-diginotar.c"; sourceTree = "<group>"; };
                DCC78DC31D8085FC00865A7C /* si-24-sectrust-itms.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-24-sectrust-itms.c"; sourceTree = "<group>"; };
                DCC78DC51D8085FC00865A7C /* si-24-sectrust-passbook.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-24-sectrust-passbook.c"; sourceTree = "<group>"; };
                DCC78DC61D8085FC00865A7C /* si-26-sectrust-copyproperties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-26-sectrust-copyproperties.c"; sourceTree = "<group>"; };
-               DCC78DC81D8085FC00865A7C /* si-28-sectrustsettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "si-28-sectrustsettings.m"; sourceTree = "<group>"; };
-               DCC78DC91D8085FC00865A7C /* si-28-sectrustsettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "si-28-sectrustsettings.h"; sourceTree = "<group>"; };
                DCC78DCA1D8085FC00865A7C /* si-30-keychain-upgrade.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-30-keychain-upgrade.c"; sourceTree = "<group>"; };
                DCC78DCB1D8085FC00865A7C /* si-31-keychain-bad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-31-keychain-bad.c"; sourceTree = "<group>"; };
                DCC78DCC1D8085FC00865A7C /* si-31-keychain-unreadable.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-31-keychain-unreadable.c"; sourceTree = "<group>"; };
                DCC78DE81D8085FC00865A7C /* si-65-cms-cert-policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-65-cms-cert-policy.c"; sourceTree = "<group>"; };
                DCC78DE91D8085FC00865A7C /* signed-receipt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "signed-receipt.h"; sourceTree = "<group>"; };
                DCC78DEB1D8085FC00865A7C /* si-66-smime.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-66-smime.c"; sourceTree = "<group>"; };
-               DCC78DEC1D8085FC00865A7C /* Global Trustee.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Global Trustee.cer.h"; sourceTree = "<group>"; };
-               DCC78DED1D8085FC00865A7C /* UTN-USERFirst-Hardware.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UTN-USERFirst-Hardware.cer.h"; sourceTree = "<group>"; };
-               DCC78DEE1D8085FC00865A7C /* addons.mozilla.org.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = addons.mozilla.org.cer.h; sourceTree = "<group>"; };
-               DCC78DEF1D8085FC00865A7C /* login.live.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.live.com.cer.h; sourceTree = "<group>"; };
-               DCC78DF01D8085FC00865A7C /* login.skype.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.skype.com.cer.h; sourceTree = "<group>"; };
-               DCC78DF11D8085FC00865A7C /* login.yahoo.com.1.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.yahoo.com.1.cer.h; sourceTree = "<group>"; };
-               DCC78DF21D8085FC00865A7C /* login.yahoo.com.2.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.yahoo.com.2.cer.h; sourceTree = "<group>"; };
-               DCC78DF31D8085FC00865A7C /* login.yahoo.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = login.yahoo.com.cer.h; sourceTree = "<group>"; };
-               DCC78DF41D8085FC00865A7C /* mail.google.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mail.google.com.cer.h; sourceTree = "<group>"; };
-               DCC78DF51D8085FC00865A7C /* www.google.com.cer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = www.google.com.cer.h; sourceTree = "<group>"; };
-               DCC78DF71D8085FC00865A7C /* si-67-sectrust-blocklist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-67-sectrust-blocklist.c"; sourceTree = "<group>"; };
                DCC78DF81D8085FC00865A7C /* si-68-secmatchissuer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-68-secmatchissuer.c"; sourceTree = "<group>"; };
                DCC78DF91D8085FC00865A7C /* si-69-keydesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-69-keydesc.c"; sourceTree = "<group>"; };
                DCC78DFA1D8085FC00865A7C /* si-70-sectrust-unified.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-70-sectrust-unified.c"; sourceTree = "<group>"; };
                DCC78DFB1D8085FC00865A7C /* si-71-mobile-store-policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-71-mobile-store-policy.c"; sourceTree = "<group>"; };
                DCC78DFC1D8085FC00865A7C /* si-72-syncableitems.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-72-syncableitems.c"; sourceTree = "<group>"; };
                DCC78DFD1D8085FC00865A7C /* si-73-secpasswordgenerate.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-73-secpasswordgenerate.c"; sourceTree = "<group>"; };
-               DCC78DFE1D8085FC00865A7C /* si-74-OTAPKISigner.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-74-OTAPKISigner.c"; sourceTree = "<group>"; };
                DCC78DFF1D8085FC00865A7C /* si-76-shared-credentials.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-76-shared-credentials.c"; sourceTree = "<group>"; };
                DCC78E001D8085FC00865A7C /* si_77_SecAccessControl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = si_77_SecAccessControl.c; sourceTree = "<group>"; };
                DCC78E011D8085FC00865A7C /* si-78-query-attrs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "si-78-query-attrs.c"; sourceTree = "<group>"; };
                DCD7DD9D22B868C200161396 /* TPPBDispositionDuplicateMachineID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TPPBDispositionDuplicateMachineID.h; sourceTree = "<group>"; };
                DCD7EE9B1F4F51D9007D9804 /* ios_tapi_hacks.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ios_tapi_hacks.h; sourceTree = "<group>"; };
                DCD8A1991E09EE0F00E4FA0A /* libSecureObjectSyncFramework.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSecureObjectSyncFramework.a; sourceTree = BUILT_PRODUCTS_DIR; };
+               DCDACB5724A3F1AA0054080C /* com.apple.security.ckks.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.security.ckks.plist; sourceTree = "<group>"; };
                DCDCC7DD1D9B54DF006487E8 /* secd-202-recoverykey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-202-recoverykey.m"; sourceTree = "<group>"; };
                DCDCC7E41D9B551C006487E8 /* SOSAccountSync.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountSync.m; sourceTree = "<group>"; };
                DCDCCB8D1DF7B8D4006E840E /* CKKSItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSItem.h; sourceTree = "<group>"; };
                DCE405C423A04A7F00C4343B /* OctagonTests+CKKSConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OctagonTests+CKKSConfiguration.swift"; sourceTree = "<group>"; };
                DCE4E6A41D7A37FA00AFB96E /* security2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = security2; sourceTree = BUILT_PRODUCTS_DIR; };
                DCE4E6A71D7A38C000AFB96E /* security2.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = security2.1; sourceTree = "<group>"; };
-               DCE4E6D41D7A41E400AFB96E /* bc-10-knife-on-bread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "bc-10-knife-on-bread.m"; path = "OSX/Breadcrumb/bc-10-knife-on-bread.m"; sourceTree = "<group>"; };
                DCE4E6D71D7A420D00AFB96E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = OSX/SecurityTestsOSX/main.m; sourceTree = "<group>"; };
                DCE4E6E71D7A427200AFB96E /* SecurityFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SecurityFoundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/SecurityFoundation.framework; sourceTree = DEVELOPER_DIR; };
                DCE4E72E1D7A436300AFB96E /* si-82-sectrust-ct-logs.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "si-82-sectrust-ct-logs.plist"; path = "OSX/shared_regressions/si-82-sectrust-ct-logs.plist"; sourceTree = SOURCE_ROOT; };
                DCEA5D541E2826DB0089CF55 /* CKKSSIV.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSSIV.m; sourceTree = "<group>"; };
                DCEA5D831E2F14810089CF55 /* OctagonAPSReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OctagonAPSReceiver.h; sourceTree = "<group>"; };
                DCEA5D841E2F14810089CF55 /* OctagonAPSReceiver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OctagonAPSReceiver.m; sourceTree = "<group>"; };
-               DCEA5D951E3014250089CF55 /* CKKSZone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSZone.h; sourceTree = "<group>"; };
-               DCEA5D961E3014250089CF55 /* CKKSZone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSZone.m; sourceTree = "<group>"; };
                DCEE1E851D93424D00DC0EB7 /* com.apple.securityd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.securityd.plist; path = OSX/sec/ipc/com.apple.securityd.plist; sourceTree = SOURCE_ROOT; };
                DCF12671218A7579000124C6 /* OTLeaveCliqueOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OTLeaveCliqueOperation.h; sourceTree = "<group>"; };
                DCF12672218A757A000124C6 /* OTLeaveCliqueOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = OTLeaveCliqueOperation.m; sourceTree = "<group>"; };
                DCFABF8D20081E2F001128B5 /* CKKSDeviceStateUploadTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CKKSDeviceStateUploadTests.m; sourceTree = "<group>"; };
                DCFAEDC81D999851005187E4 /* SOSAccountGhost.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SOSAccountGhost.m; sourceTree = "<group>"; };
                DCFAEDC91D999851005187E4 /* SOSAccountGhost.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SOSAccountGhost.h; sourceTree = "<group>"; };
-               DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-668-ghosts.m"; sourceTree = "<group>"; };
                DCFAEDD51D99A464005187E4 /* secd-36-ks-encrypt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "secd-36-ks-encrypt.m"; sourceTree = "<group>"; };
                DCFB12C31E95A4C000510F5F /* CKKSAccountStateTracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKKSAccountStateTracker.h; sourceTree = "<group>"; };
                DCFB12C41E95A4C000510F5F /* CKKSAccountStateTracker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKKSAccountStateTracker.m; sourceTree = "<group>"; };
                E7F4809D1C74E86D00390FDB /* KCAESGCMTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCAESGCMTest.m; path = Tests/KCAESGCMTest.m; sourceTree = "<group>"; };
                E7F4826F1C74FDD100390FDB /* KCJoiningSessionTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = KCJoiningSessionTest.m; path = Tests/KCJoiningSessionTest.m; sourceTree = "<group>"; };
                E7F482A21C7544E600390FDB /* libctkclient_test.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkclient_test.a; path = ../../../../../usr/local/lib/libctkclient_test.a; sourceTree = "<group>"; };
-               E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcoreauthd_test_client.a; path = ../../../../../usr/local/lib/libcoreauthd_test_client.a; sourceTree = "<group>"; };
                E7F482A91C7554F500390FDB /* NSError+KCCreationHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+KCCreationHelpers.m"; sourceTree = "<group>"; };
                E7F482AB1C7558F700390FDB /* KCJoiningAcceptSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KCJoiningAcceptSession.m; sourceTree = "<group>"; };
                E7FC30AB1332DE9000802946 /* MobileKeyBag.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileKeyBag.framework; path = System/Library/PrivateFrameworks/MobileKeyBag.framework; sourceTree = SDKROOT; };
                EB433A1E1CC3242C00A7EACE /* secitemstresstest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = secitemstresstest.m; path = secitemstresstest/secitemstresstest.m; sourceTree = "<group>"; };
                EB433A281CC3243600A7EACE /* secitemstresstest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = secitemstresstest; sourceTree = BUILT_PRODUCTS_DIR; };
                EB433A2D1CC325E900A7EACE /* secitemstresstest.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = secitemstresstest.entitlements; path = secitemstresstest/secitemstresstest.entitlements; sourceTree = "<group>"; };
+               EB45ED2E24749DE9008A1F6F /* gen_test_plist.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = gen_test_plist.py; path = tests/TrustTests/gen_test_plist.py; sourceTree = "<group>"; };
+               EB45ED3024749E63008A1F6F /* gen_test_plist.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = gen_test_plist.py; sourceTree = "<group>"; };
+               EB45ED3124749ECC008A1F6F /* OTTests-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "OTTests-Info.plist"; sourceTree = "<group>"; };
+               EB45ED3224749ECC008A1F6F /* gen_test_plist.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = gen_test_plist.py; sourceTree = "<group>"; };
                EB48C19E1E573EDC00EC5E57 /* sos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = sos.m; sourceTree = "<group>"; };
                EB490153211C0026001E6D6A /* UserManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserManagement.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/PrivateFrameworks/UserManagement.framework; sourceTree = DEVELOPER_DIR; };
                EB49B2AE202D877F003F34A0 /* secdmockaks.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = secdmockaks.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
                EB8021411D3D90BB008540C4 /* Security.iOS.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = Security.iOS.modulemap; path = Modules/Security.iOS.modulemap; sourceTree = "<group>"; };
                EB8021421D3D90BB008540C4 /* Security.macOS.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = Security.macOS.modulemap; path = Modules/Security.macOS.modulemap; sourceTree = "<group>"; };
                EB80DE57219600CF005B10FA /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
-               EB82A2A41FAFF26900CA64A9 /* SFBehavior.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SFBehavior.h; sourceTree = "<group>"; };
-               EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SFBehavior.m; sourceTree = "<group>"; };
                EB89088621F17D3C00F0DDDB /* recovery_securityd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = recovery_securityd; sourceTree = BUILT_PRODUCTS_DIR; };
                EB8908BB21F20E0200F0DDDB /* com.apple.recovery_securityd.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.recovery_securityd.plist; sourceTree = "<group>"; };
                EB89111020E3C15D00DE533F /* UserManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UserManagement.framework; path = System/Library/PrivateFrameworks/UserManagement.framework; sourceTree = SDKROOT; };
                EBF374721DC055580065D840 /* security-sysdiagnose */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "security-sysdiagnose"; sourceTree = BUILT_PRODUCTS_DIR; };
                EBF374741DC055590065D840 /* security-sysdiagnose.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "security-sysdiagnose.m"; sourceTree = "<group>"; };
                EBF3747F1DC057FE0065D840 /* security-sysdiagnose.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = "security-sysdiagnose.1"; sourceTree = "<group>"; };
-               EBF3749A1DC064200065D840 /* SecADWrapper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SecADWrapper.c; sourceTree = "<group>"; };
-               EBF3749B1DC064200065D840 /* SecADWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecADWrapper.h; sourceTree = "<group>"; };
                EBF9AE171F536D0300FECBF7 /* Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Version.xcconfig; path = xcconfig/Version.xcconfig; sourceTree = "<group>"; };
                F619D71D1ED70BB0005B5F46 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = OSX/authorizationdump/main.m; sourceTree = "<group>"; };
                F621D07F1ED6DCE7000EA569 /* authorizationdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = authorizationdump; sourceTree = BUILT_PRODUCTS_DIR; };
                F667EC551E96E94800203D5C /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = OSX/authd/tests/main.m; sourceTree = "<group>"; };
                F667EC601E96E9B100203D5C /* authdtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = authdtest; sourceTree = BUILT_PRODUCTS_DIR; };
+               F681C3A82386B8B40083F22C /* PreloginUserDb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PreloginUserDb.m; path = OSX/authd/PreloginUserDb.m; sourceTree = "<group>"; };
+               F681C3AA2386B8B40083F22C /* PreloginUserDb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PreloginUserDb.h; path = OSX/authd/PreloginUserDb.h; sourceTree = "<group>"; };
                F682C1CE1F4486F600F1B029 /* libctkloginhelper.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkloginhelper.a; path = usr/local/lib/libctkloginhelper.a; sourceTree = SDKROOT; };
                F6A0971E1E953A1500B1E7D6 /* authdtestlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = authdtestlist.h; path = OSX/authd/tests/authdtestlist.h; sourceTree = "<group>"; };
                F6A0971F1E953ABD00B1E7D6 /* authdtests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = authdtests.m; path = OSX/authd/tests/authdtests.m; sourceTree = "<group>"; };
                F6A3CB0D1E7062BA00E7821F /* authd-Entitlements.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "authd-Entitlements.plist"; path = "OSX/authd/authd-Entitlements.plist"; sourceTree = "<group>"; };
+               F6B1B48924144B5E00CB3E3F /* libctkloginhelperlite.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libctkloginhelperlite.a; path = usr/local/lib/libctkloginhelperlite.a; sourceTree = SDKROOT; };
                F6D600702166551800F9F7C9 /* AuthorizationTrampolinePriv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AuthorizationTrampolinePriv.h; path = OSX/libsecurity_authorization/lib/AuthorizationTrampolinePriv.h; sourceTree = "<group>"; };
                F9B458272183E01100F6BCEB /* SignatureEditing.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = SignatureEditing.sh; path = OSX/codesign_tests/SignatureEditing.sh; sourceTree = "<group>"; };
                F9F77E96223C2F7B00E5CBF6 /* requirement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = requirement.c; sourceTree = "<group>"; };
                F9F77E97223C2F7C00E5CBF6 /* requirement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = requirement.h; sourceTree = "<group>"; };
+               FC637229237B5CF800973738 /* SecItemServer+SWC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SecItemServer+SWC.h"; sourceTree = "<group>"; };
+               FC63722A237B5CF900973738 /* SecItemServer+SWC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "SecItemServer+SWC.m"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                                0C0BDB881756A51000BC1A7E /* libsqlite3.dylib in Frameworks */,
                                BE8ABDD81DC2DD9100EC2D58 /* libz.dylib in Frameworks */,
                                4469FBFF1AA0A4820021AA26 /* libctkclient_test.a in Frameworks */,
+                               DA53FC4523A9C801002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C3810F123EF6FC4002D7E19 /* OctagonTrust.framework in Frameworks */,
                                0C84D83D1FCF449700B822E3 /* Security.framework in Frameworks */,
                                0CE902352395D0A3005E3F8C /* AuthKit.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               0C9AEEB020783FBB00BF6237 /* Frameworks */ = {
+               0CCC226123F357EE00E1FCD0 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C9AEEBB20783FF900BF6237 /* Security.framework in Frameworks */,
+                               0CCC22B323F38B6D00E1FCD0 /* AuthKit.framework in Frameworks */,
+                               0CCC22B623F38BCD00E1FCD0 /* CoreData.framework in Frameworks */,
+                               0CCC22C723F3904D00E1FCD0 /* Foundation.framework in Frameworks */,
+                               0C570B7C23F3A0E3001FEB3B /* IOKit.framework in Frameworks */,
+                               0CCC22C823F390E400E1FCD0 /* OCMock.framework in Frameworks */,
+                               0CCC22A423F374EB00E1FCD0 /* OctagonTrust.framework in Frameworks */,
+                               0CCC22AE23F38B2D00E1FCD0 /* SystemConfiguration.framework in Frameworks */,
+                               0CCC22A923F38AFD00E1FCD0 /* libSecureObjectSyncServer.a in Frameworks */,
+                               0CCC22A823F38AD600E1FCD0 /* libsecurityd_ios.a in Frameworks */,
+                               0CCC22A523F3763C00E1FCD0 /* libutilities.a in Frameworks */,
+                               0CCC22BD23F38D4B00E1FCD0 /* libbsm.tbd in Frameworks */,
+                               0CCC22BC23F38D3500E1FCD0 /* libz.tbd in Frameworks */,
+                               0CCC22B223F38B5B00E1FCD0 /* libsqlite3.0.tbd in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               0CF406342072E3E3003D6A7F /* Frameworks */ = {
+               0CD743A323C3EC8000FA0EC5 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C5663EF20BE2E220035F362 /* libutilities.a in Frameworks */,
-                               0C9AEEBE207843D000BF6237 /* Security.framework in Frameworks */,
+                               0CCC21FF23F3577A00E1FCD0 /* Security.framework in Frameworks */,
+                               0CD743AF23C3ECEB00FA0EC5 /* ProtocolBuffer.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                3DD1FFA5201FC59D0086D049 /* libsecurity_ssl.a in Frameworks */,
                                3DD1FFA4201FC58F0086D049 /* libutilities.a in Frameworks */,
                                3DD1FFA3201FC5870086D049 /* libDiagnosticMessagesClient.tbd in Frameworks */,
-                               3DD1FFA2201FC5800086D049 /* SecurityFoundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                3DD1FFC6201FDB1D0086D049 /* Foundation.framework in Frameworks */,
                                3DD1FFC8201FDB1D0086D049 /* libsecurity_ssl.a in Frameworks */,
                                3DD1FFC9201FDB1D0086D049 /* libutilities.a in Frameworks */,
-                               3DD1FFCB201FDB1D0086D049 /* SecurityFoundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               3E88360B24F068EF00E9F4D6 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               3E88361B24F08DA100E9F4D6 /* Security.framework in Frameworks */,
+                               3E88360D24F068EF00E9F4D6 /* Foundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                438169E41B4EE13B00C54D58 /* Accounts.framework in Frameworks */,
                                438169E51B4EE14D00C54D58 /* Security.framework in Frameworks */,
                                4381690D1B4EDCBD00C54D58 /* Foundation.framework in Frameworks */,
+                               DA2F592723A99F2900C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                4718AE23205B39620068EC3F /* IOKit.framework in Frameworks */,
                                4718AE24205B39620068EC3F /* libaks_acl.a in Frameworks */,
                                4718AE25205B39620068EC3F /* libsqlite3.dylib in Frameworks */,
+                               DA2F592523A99E8400C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                4727FBD51F9920510003AE36 /* ProtocolBuffer.framework in Frameworks */,
                                D4911172209559630066A1E4 /* CoreData.framework in Frameworks */,
                                4727FBD31F9920290003AE36 /* CloudKit.framework in Frameworks */,
-                               4727FBD11F991F990003AE36 /* libMobileGestalt.dylib in Frameworks */,
                                4727FBCE1F991F820003AE36 /* SecurityFoundation.framework in Frameworks */,
                                4727FBCD1F991F660003AE36 /* libsqlite3.dylib in Frameworks */,
                                4727FBC91F991E5A0003AE36 /* libutilities.a in Frameworks */,
                                4727FBC61F991DE90003AE36 /* libsecdRegressions.a in Frameworks */,
                                4727FBC51F991C470003AE36 /* Foundation.framework in Frameworks */,
+                               DA53FC3E23A9C180002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               478D427D1FD72A8100CAB645 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               DC4A76AA22126993006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C6C0FD221F146E700CD5B9E /* CoreCDP.framework in Frameworks */,
-                               EB7732DB21963BC100FCF513 /* libz.tbd in Frameworks */,
-                               482FE56A2177C7980031C11E /* AuthKit.framework in Frameworks */,
-                               479231EE2065B32200B2718C /* libsecurityd_ios.a in Frameworks */,
-                               477A1F5320320E5100ACD81D /* Accounts.framework in Frameworks */,
-                               478D429F1FD72C8400CAB645 /* AppleSystemInfo.framework in Frameworks */,
-                               478D429E1FD72C4800CAB645 /* CrashReporterSupport.framework in Frameworks */,
-                               478D427F1FD72A8100CAB645 /* libprequelite.dylib in Frameworks */,
-                               478D42801FD72A8100CAB645 /* OCMock.framework in Frameworks */,
-                               478D42811FD72A8100CAB645 /* libregressionBase.a in Frameworks */,
-                               478D42821FD72A8100CAB645 /* libACM.a in Frameworks */,
-                               D4911173209559630066A1E4 /* CoreData.framework in Frameworks */,
-                               478D42831FD72A8100CAB645 /* ApplePushService.framework in Frameworks */,
-                               478D42841FD72A8100CAB645 /* SharedWebCredentials.framework in Frameworks */,
-                               478D42851FD72A8100CAB645 /* MobileKeyBag.framework in Frameworks */,
-                               478D42861FD72A8100CAB645 /* IOKit.framework in Frameworks */,
-                               478D42871FD72A8100CAB645 /* libaks.a in Frameworks */,
-                               478D42881FD72A8100CAB645 /* libaks_acl.a in Frameworks */,
-                               478D42891FD72A8100CAB645 /* WirelessDiagnostics.framework in Frameworks */,
-                               478D428A1FD72A8100CAB645 /* SystemConfiguration.framework in Frameworks */,
-                               478D428B1FD72A8100CAB645 /* libSecureObjectSyncServer.a in Frameworks */,
-                               478D428C1FD72A8100CAB645 /* libSecureObjectSyncFramework.a in Frameworks */,
-                               478D428D1FD72A8100CAB645 /* ProtocolBuffer.framework in Frameworks */,
-                               478D428E1FD72A8100CAB645 /* CloudKit.framework in Frameworks */,
-                               DC066DF02102563300694EAF /* Security.framework in Frameworks */,
-                               478D42901FD72A8100CAB645 /* SecurityFoundation.framework in Frameworks */,
-                               478D42911FD72A8100CAB645 /* libsqlite3.dylib in Frameworks */,
-                               478D42931FD72A8100CAB645 /* libutilities.a in Frameworks */,
-                               478D42951FD72A8100CAB645 /* libsecurity.a in Frameworks */,
-                               478D42961FD72A8100CAB645 /* libsecdRegressions.a in Frameworks */,
-                               478D42971FD72A8100CAB645 /* Foundation.framework in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                47C2F1802059CB680062DE30 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                438166ED1B4ECF9400C54D58 /* CoreFoundation.framework in Frameworks */,
                                4CAF67AC0F3A70220064A534 /* IOKit.framework in Frameworks */,
                                0940F6F82151316500C06F18 /* libACM.a in Frameworks */,
+                               0C2B32A523C4001900A97B18 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C9FB40720D872A600864612 /* CoreCDP.framework in Frameworks */,
+                               0CCC22D623F39B2E00E1FCD0 /* CoreCDP.framework in Frameworks */,
                                43DB54551BB1F8920083C3F1 /* ProtectedCloudStorage.framework in Frameworks */,
                                4C8A38C917B93DF10001B4C0 /* CloudServices.framework in Frameworks */,
                                4381603B1B4DCEFF00C54D58 /* AggregateDictionary.framework in Frameworks */,
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0CC9403023F39E84004B71AA /* CoreCDP.framework in Frameworks */,
                                D47AB2D12356B2FE005A3801 /* Network.framework in Frameworks */,
                                DC4A76AD22126A17006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C6C0FD621F14D3900CD5B9E /* CoreCDP.framework in Frameworks */,
                                EB80DE5B219600FC005B10FA /* libz.tbd in Frameworks */,
                                482FE56F2177CF520031C11E /* AuthKit.framework in Frameworks */,
                                D4C6C5CF1FB3B44D007EA57E /* libarchive.2.dylib in Frameworks */,
                                4C711D6D13AFCD0900FE865D /* Security.framework in Frameworks */,
                                D418CC701E690CAD00330A44 /* MobileAsset.framework in Frameworks */,
                                E71F3E4216EA6A6300FAF9B4 /* SystemConfiguration.framework in Frameworks */,
+                               DA3862AA23AAD959001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DC4A76A5221268A6006F2D8F /* CloudServices.framework in Frameworks */,
                                EB7732C221963B0500FCF513 /* libz.tbd in Frameworks */,
                                482FE56C2177CEEF0031C11E /* AuthKit.framework in Frameworks */,
-                               0C9FB40920D8735500864612 /* CoreCDP.framework in Frameworks */,
                                47D13F631E8447FB0063B6E2 /* SecurityFoundation.framework in Frameworks */,
                                EBE9019A1C22852C007308C6 /* AggregateDictionary.framework in Frameworks */,
                                438168BB1B4ED42300C54D58 /* CoreFoundation.framework in Frameworks */,
                                DC00AB8E1D821D4900513D74 /* libSOSCommands.a in Frameworks */,
+                               0CCC22D723F39B7200E1FCD0 /* CoreCDP.framework in Frameworks */,
                                5296CB4F1655B92F009912AF /* libMobileGestalt.dylib in Frameworks */,
                                4432B0B71A014987000958DC /* libaks_acl.a in Frameworks */,
                                DC65E7361D8CB35E00152EF0 /* libutilities.a in Frameworks */,
                                52D82BEE16A622370078DFE5 /* Security.framework in Frameworks */,
                                52D82BDF16A621F70078DFE5 /* Foundation.framework in Frameworks */,
                                E72D462B175FBF3E00F70B9B /* IOKit.framework in Frameworks */,
+                               DA53FC3D23A9BF28002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                DC4A76A02212676D006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C6C0FCB21F1415B00CD5B9E /* CoreCDP.framework in Frameworks */,
                                EB80DE5D21960C0A005B10FA /* libz.tbd in Frameworks */,
                                482FE5662177C6E40031C11E /* AuthKit.framework in Frameworks */,
                                482FE5652177C6D90031C11E /* Accounts.framework in Frameworks */,
                                5E43C48D1B00D07000E5ECB2 /* CoreFoundation.framework in Frameworks */,
                                5E43C4961B00D3B500E5ECB2 /* IOKit.framework in Frameworks */,
                                5E43C49A1B00D4D800E5ECB2 /* Security.framework in Frameworks */,
+                               DA53FC4623A9CB13002D5EA9 /* SoftLinking.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6C2045E72424BA7E00F9461D /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               6CB0C5F824ACDB5300479FB4 /* Security.framework in Frameworks */,
+                               6CA9690A24ACC2D100C08B5E /* libutilities.a in Frameworks */,
+                               6C2045F52424BBDD00F9461D /* Foundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               6C8FF4B3224C1A8D00E5C812 /* TrustedPeers.framework in Frameworks */,
                                6C540C3922289A3B0032B5BC /* CloudServices.framework in Frameworks */,
                                6C39235B21F13E4D00D018AD /* libz.dylib in Frameworks */,
                                6C39235C21F13E4D00D018AD /* AuthKit.framework in Frameworks */,
                                6C39237221F13E4D00D018AD /* libutilities.a in Frameworks */,
                                6C39237321F13E4D00D018AD /* libsecdRegressions.a in Frameworks */,
                                6C39237421F13E4D00D018AD /* Foundation.framework in Frameworks */,
+                               DA53FC3F23A9C26F002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                D4119E882032A8FA0048587B /* OCMock.framework in Frameworks */,
                                6C13AE481F8E9FC800F047E3 /* libutilities.a in Frameworks */,
                                6C4605A51F882B9B001421B6 /* Foundation.framework in Frameworks */,
+                               DA53FC4123A9C3CE002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6C9808481E788AEB00E70590 /* Frameworks */ = {
+               6C7BE2D223C3DD64003BB2CA /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               DC4A76A822126959006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C4D96A721F25F2C00617E60 /* CoreCDP.framework in Frameworks */,
-                               482FE5672177C7260031C11E /* AuthKit.framework in Frameworks */,
-                               6CAA8CDD1F82EDEF007B6E03 /* Security.framework in Frameworks */,
-                               D46246BC1F9AE82B00D63882 /* libDER.a in Frameworks */,
-                               6C98084A1E788AEB00E70590 /* libASN1.a in Frameworks */,
-                               6C98084D1E788AEB00E70590 /* libSecureObjectSyncFramework.a in Frameworks */,
-                               6C98084E1E788AEB00E70590 /* libSecureObjectSyncServer.a in Frameworks */,
-                               DC93C4C5214713C5008F8362 /* libaks_mock.a in Frameworks */,
-                               DC93C4D021471FD8008F8362 /* libsecurityd_ios.a in Frameworks */,
-                               6C98084F1E788AEB00E70590 /* libsecurity.a in Frameworks */,
-                               6C9808501E788AEB00E70590 /* libutilities.a in Frameworks */,
-                               6C9808511E788AEB00E70590 /* CFNetwork.framework in Frameworks */,
-                               6C9808521E788AEB00E70590 /* Foundation.framework in Frameworks */,
-                               6C9808531E788AEB00E70590 /* IOKit.framework in Frameworks */,
-                               6C9808541E788AEB00E70590 /* OCMock.framework in Frameworks */,
-                               DCB515DE1ED3CF86001F1152 /* SecurityFoundation.framework in Frameworks */,
-                               6C9808551E788AEB00E70590 /* SystemConfiguration.framework in Frameworks */,
-                               6C9808561E788AEB00E70590 /* libACM.a in Frameworks */,
-                               6C9808571E788AEB00E70590 /* libaks_acl.a in Frameworks */,
-                               6C9808581E788AEB00E70590 /* libbsm.dylib in Frameworks */,
-                               6C9808591E788AEB00E70590 /* libcoreauthd_client.a in Frameworks */,
-                               6C98085A1E788AEB00E70590 /* libctkclient_sep.a in Frameworks */,
-                               6C98085B1E788AEB00E70590 /* libsqlite3.0.dylib in Frameworks */,
-                               6C98085C1E788AEB00E70590 /* libz.dylib in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               6C9808841E788AFD00E70590 /* Frameworks */ = {
+                               6C16258823C5001C0086A0FF /* libSecureObjectSyncServer.a in Frameworks */,
+                               6C16258723C4FFEC0086A0FF /* libMobileGestalt.tbd in Frameworks */,
+                               6C7BE2EB23C3DDC3003BB2CA /* libsecurityd_bridge.a in Frameworks */,
+                               6C7BE2D423C3DD64003BB2CA /* libz.tbd in Frameworks */,
+                               6C7BE2D723C3DD64003BB2CA /* SecurityFoundation.framework in Frameworks */,
+                               6C7BE2D823C3DD64003BB2CA /* AggregateDictionary.framework in Frameworks */,
+                               6C7BE2D923C3DD64003BB2CA /* CoreFoundation.framework in Frameworks */,
+                               6C7BE2DC23C3DD64003BB2CA /* libaks_acl.a in Frameworks */,
+                               6C7BE2DD23C3DD64003BB2CA /* libutilities.a in Frameworks */,
+                               6C7BE2E023C3DD64003BB2CA /* Security.framework in Frameworks */,
+                               6C7BE2E323C3DD64003BB2CA /* Foundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6C96327E242A279B00C53CE2 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               DC4A76A72212694F006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C6C0FD021F145F600CD5B9E /* CoreCDP.framework in Frameworks */,
-                               482FE5682177C73C0031C11E /* AuthKit.framework in Frameworks */,
-                               6CAA8CEE1F83E417007B6E03 /* Security.framework in Frameworks */,
-                               D46246BD1F9AE83600D63882 /* libDER.a in Frameworks */,
-                               6C9808861E788AFD00E70590 /* libASN1.a in Frameworks */,
-                               6C9808891E788AFD00E70590 /* libSecureObjectSyncFramework.a in Frameworks */,
-                               6C98088A1E788AFD00E70590 /* libSecureObjectSyncServer.a in Frameworks */,
-                               DC93C4CB214713ED008F8362 /* libaks_mock.a in Frameworks */,
-                               DC93C4CA214713E5008F8362 /* libsecurityd_ios.a in Frameworks */,
-                               6C98088B1E788AFD00E70590 /* libsecurity.a in Frameworks */,
-                               6C98088C1E788AFD00E70590 /* libutilities.a in Frameworks */,
-                               6C98088D1E788AFD00E70590 /* CFNetwork.framework in Frameworks */,
-                               6C98088E1E788AFD00E70590 /* Foundation.framework in Frameworks */,
-                               6C98088F1E788AFD00E70590 /* IOKit.framework in Frameworks */,
-                               6C9808901E788AFD00E70590 /* OCMock.framework in Frameworks */,
-                               DCB515DF1ED3CF95001F1152 /* SecurityFoundation.framework in Frameworks */,
-                               6C9808911E788AFD00E70590 /* SystemConfiguration.framework in Frameworks */,
-                               6C9808921E788AFD00E70590 /* libACM.a in Frameworks */,
-                               6C9808931E788AFD00E70590 /* libaks_acl.a in Frameworks */,
-                               6C9808941E788AFD00E70590 /* libbsm.dylib in Frameworks */,
-                               6C9808951E788AFD00E70590 /* libcoreauthd_client.a in Frameworks */,
-                               6C9808961E788AFD00E70590 /* libctkclient_sep.a in Frameworks */,
-                               6C9808971E788AFD00E70590 /* libsqlite3.0.dylib in Frameworks */,
-                               6C9808981E788AFD00E70590 /* libz.dylib in Frameworks */,
+                               6C61D3E9242A2C14008AB9BB /* Security.framework in Frameworks */,
+                               6C96328A242A284C00C53CE2 /* MobileKeyBag.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               DCCA5E841E539EE7009EE93D /* AppKit.framework in Frameworks */,
                                6CAB39C71E521BEA00566A79 /* Foundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6CF4A0DD1E4549F200ECD7B5 /* Frameworks */ = {
-                       isa = PBXFrameworksBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               6CE22D701E49206600974785 /* UIKit.framework in Frameworks */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                790851B40CA9859F0083CC4D /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                                E71F3E3116EA69A900FAF9B4 /* SystemConfiguration.framework in Frameworks */,
                                4CAF66190F3A6FCD0064A534 /* IOKit.framework in Frameworks */,
                                4C2215220F3A612C00835155 /* libsqlite3.dylib in Frameworks */,
+                               0C2B32A423C4000F00A97B18 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                D401E8B420A26F1F00CD8BB4 /* CoreData.framework in Frameworks */,
                                DC340C54208E828F004D7EEC /* TrustedPeers.framework in Frameworks */,
                                BE9F8D15206C2E0200B53D16 /* libutilities.a in Frameworks */,
+                               DA53FC4923A9CC8D002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DC00C92320B3B80500628BEB /* libbsm.tbd in Frameworks */,
                                DC00C92420B3B82600628BEB /* libz.tbd in Frameworks */,
                                DC00C92020B3B7CC00628BEB /* libDER.a in Frameworks */,
-                               DC6013312147220F00863C1A /* libaks_mock.a in Frameworks */,
                                DC60132E2147220600863C1A /* libsecurityd_ios.a in Frameworks */,
                                BE53602D209BBF630027E25A /* libMobileGestalt.tbd in Frameworks */,
                                DC9C06712149E6B900C6F7B8 /* AuthKit.framework in Frameworks */,
                                BED987DF209918A500607A5F /* SecurityFoundation.framework in Frameworks */,
                                BED987D82099145300607A5F /* TrustedPeers.framework in Frameworks */,
                                DC00C93520B48BA800628BEB /* IOKit.framework in Frameworks */,
-                               DC00C91D20B3B79600628BEB /* libsecurity.a in Frameworks */,
-                               BE53601C209BB8970027E25A /* libSecureObjectSyncFramework.a in Frameworks */,
                                BE53601B209BB8390027E25A /* libSecureObjectSyncServer.a in Frameworks */,
                                BE53601A209BB7F80027E25A /* libutilities.a in Frameworks */,
+                               DA3862A723A9CD2E001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                D41257E21E94138600781F23 /* CoreFoundation.framework in Frameworks */,
                                D41257D01E9410A300781F23 /* Foundation.framework in Frameworks */,
                                D450686A1E948D2200FA7675 /* Security.framework in Frameworks */,
+                               DA53FC3C23A9BDD5002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D49BD0762476F74B00FC7E1C /* libMobileGestalt.tbd in Frameworks */,
                                D4FD4225217D7BEE002B7EE2 /* libarchive.2.tbd in Frameworks */,
                                D453A4B22122236D00850A26 /* libz.tbd in Frameworks */,
                                D453A4B32122236D00850A26 /* libsqlite3.tbd in Frameworks */,
                                D453A4B92122236D00850A26 /* Foundation.framework in Frameworks */,
                                D453A4BA2122236D00850A26 /* IOKit.framework in Frameworks */,
                                D40B7CA021605BF800AC9A75 /* OCMock.framework in Frameworks */,
+                               DA3862AB23AAE3A8001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                D458C512214E20850043D982 /* XCTest.framework in Frameworks */,
                                D458C507214E20540043D982 /* Foundation.framework in Frameworks */,
+                               DA2F592623A99EC900C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D49BD0742476F67700FC7E1C /* libMobileGestalt.tbd in Frameworks */,
                                D4FD4224217D7BE4002B7EE2 /* libarchive.2.tbd in Frameworks */,
                                D4B68C62211A80CE009FED69 /* libz.tbd in Frameworks */,
                                D4B68C5F211A80B1009FED69 /* libsqlite3.tbd in Frameworks */,
                                D4B68C60211A80BC009FED69 /* CoreFoundation.framework in Frameworks */,
                                D4B68C61211A80C4009FED69 /* Foundation.framework in Frameworks */,
                                D4B68C63211A80DA009FED69 /* IOKit.framework in Frameworks */,
+                               DA53FC4723A9CBAA002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D49BD0772476F7C000FC7E1C /* libMobileGestalt.tbd in Frameworks */,
                                4C47FA9420A51DD800384CB6 /* AppleFSCompression.framework in Frameworks */,
                                DCD22D4B1D8CBF54001C9B81 /* libASN1.a in Frameworks */,
+                               F6B1B48B24144B5F00CB3E3F /* libctkloginhelperlite.a in Frameworks */,
                                DC00AB6F1D821C3400513D74 /* libSecItemShimOSX.a in Frameworks */,
                                DC00AB701D821C3800513D74 /* libSecOtrOSX.a in Frameworks */,
                                DC00AB6B1D821C1A00513D74 /* libSecTrustOSX.a in Frameworks */,
                                DC1789251D7799CD00B50D50 /* CoreFoundation.framework in Frameworks */,
                                DC1789271D7799D400B50D50 /* IOKit.framework in Frameworks */,
                                0940F6F92151316600C06F18 /* libACM.a in Frameworks */,
+                               DA2F591823A32BC100C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                DCF465742201155000BA6EEA /* CloudServices.framework in Frameworks */,
-                               0C6C0FD121F1465500CD5B9E /* CoreCDP.framework in Frameworks */,
                                DC391FAE21C1903E00772585 /* libutilities.a in Frameworks */,
                                EBD531772198AF19003A57E6 /* Accounts.framework in Frameworks */,
                                EBD531762198AF0B003A57E6 /* AppleAccount.framework in Frameworks */,
                                DC222C361E02419B00B09171 /* libbsm.dylib in Frameworks */,
                                DC3502CA1E020DC100BC0587 /* libsqlite3.0.dylib in Frameworks */,
                                DC222C321E0240D300B09171 /* libz.dylib in Frameworks */,
+                               DA53FC4023A9C351002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DC5AC0C91D8353D100CF422C /* libbsm.dylib in Frameworks */,
                                DCD22D701D8CC733001C9B81 /* libutilities.a in Frameworks */,
                                DC63D70820B3931100D088AD /* libxar.tbd in Frameworks */,
-                               DC5AC0C71D8353C800CF422C /* PCSC.framework in Frameworks */,
                                DC5AC0C51D8353C200CF422C /* Security.framework in Frameworks */,
                                DC5AC0C41D8353BB00CF422C /* System.framework in Frameworks */,
+                               D4E6D8592404EAD40074CB26 /* libDER.a in Frameworks */,
                                DC5AC0C21D83538D00CF422C /* CoreFoundation.framework in Frameworks */,
                                DC5AC0C11D83538800CF422C /* IOKit.framework in Frameworks */,
                        );
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C570B8123F3A1EC001FEB3B /* CoreCDP.framework in Frameworks */,
                                D47AB2D62357955F005A3801 /* Network.framework in Frameworks */,
                                DCF46573220114F000BA6EEA /* CloudServices.framework in Frameworks */,
-                               0C4D96A621F24E5700617E60 /* CoreCDP.framework in Frameworks */,
                                EB80DE56219600C6005B10FA /* libz.tbd in Frameworks */,
                                DC9C066F2149E36900C6F7B8 /* AuthKit.framework in Frameworks */,
                                47C2F1762059A2300062DE30 /* libprequelite.tbd in Frameworks */,
                                474B5FC81E662E79007546F8 /* SecurityFoundation.framework in Frameworks */,
                                D43B88721E72298500F86F19 /* MobileAsset.framework in Frameworks */,
                                DC4EA5961E70A237008840B4 /* libsecurity.a in Frameworks */,
+                               D49BD07824770E2D00FC7E1C /* libMobileGestalt.tbd in Frameworks */,
                                6C5B36BA1E2F9B95008AD443 /* WirelessDiagnostics.framework in Frameworks */,
                                DC610A3D1D78F25C002223DE /* libDiagnosticMessagesClient.dylib in Frameworks */,
                                DC610A3B1D78F234002223DE /* libACM.a in Frameworks */,
                                DCD22D6B1D8CC685001C9B81 /* AppleSystemInfo.framework in Frameworks */,
                                DC610A291D78F129002223DE /* IOKit.framework in Frameworks */,
                                DC610A271D78F129002223DE /* Security.framework in Frameworks */,
+                               DA3862AE23AAE65E001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0CD5040523F39DEA0036C279 /* CoreCDP.framework in Frameworks */,
                                DCF465762201162800BA6EEA /* CloudServices.framework in Frameworks */,
                                DC3E18C82125015300073D80 /* libsecurityd_ios.a in Frameworks */,
                                DCCFB14E212394EC003D2DA2 /* libaks_mock.a in Frameworks */,
                                DC99B88920EACA470065B73B /* libSecureObjectSyncServer.a in Frameworks */,
                                DC99B88A20EACA470065B73B /* libutilities.a in Frameworks */,
                                DC99B88B20EACA470065B73B /* libASN1.a in Frameworks */,
+                               DA3862A923AAD1FD001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               DCBF4AC121FFC82100539F0A /* CoreCDP.framework in Frameworks */,
                                DCBF4AC221FFC82100539F0A /* libutilities.a in Frameworks */,
                                DCBF4AC321FFC82100539F0A /* Accounts.framework in Frameworks */,
                                DCBF4AC421FFC82100539F0A /* AppleAccount.framework in Frameworks */,
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C570B7B23F3A09A001FEB3B /* CoreCDP.framework in Frameworks */,
                                DC4A76AE22126C49006F2D8F /* CloudServices.framework in Frameworks */,
                                EB80DE38219600A8005B10FA /* libz.tbd in Frameworks */,
                                482FE5642177C6850031C11E /* libprequelite.tbd in Frameworks */,
                                482FE5632177C5E80031C11E /* Accounts.framework in Frameworks */,
                                482FE5602177C5DA0031C11E /* AuthKit.framework in Frameworks */,
-                               0C4C548020E1A53D00BA61BA /* CoreCDP.framework in Frameworks */,
                                6C1F93111DD5E41A00585608 /* libDiagnosticMessagesClient.dylib in Frameworks */,
                                DCE4E6AE1D7A3C6A00AFB96E /* AppleSystemInfo.framework in Frameworks */,
                                DCE4E6AD1D7A3B9700AFB96E /* libaks.a in Frameworks */,
                        files = (
                                D47AB2D02356B2F6005A3801 /* Network.framework in Frameworks */,
                                09EF431B21A5A8CC0066CF20 /* libaks_acl.a in Frameworks */,
+                               097CE59F246966A100958AF8 /* libMobileGestalt.dylib in Frameworks */,
                                D4C6C5CD1FB3B423007EA57E /* libarchive.tbd in Frameworks */,
                                D46246B71F9AE76500D63882 /* libDER.a in Frameworks */,
                                DC3A81EC1D99F568000C7419 /* libcoretls.dylib in Frameworks */,
                                DCD504C320CB293700F37D26 /* Security.framework in Frameworks */,
                                DC4DB16A1E26E9F900CD6769 /* ProtocolBuffer.framework in Frameworks */,
                                DCE4E82C1D7A56FF00AFB96E /* AppleSystemInfo.framework in Frameworks */,
+                               DA53FC3923A9BA68002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                D40B6A9E1E2B6A6F00CD6EE5 /* libtrustd.a in Frameworks */,
                                D40B6A931E2B67E500CD6EE5 /* libutilities.a in Frameworks */,
                                D40B6A831E2B5F5B00CD6EE5 /* libASN1.a in Frameworks */,
-                               D40B6A9D1E2B6A2700CD6EE5 /* login.framework in Frameworks */,
+                               D4981B8F24F723EA004B033B /* IOKit.framework in Frameworks */,
                                D4ADA3311E2B43450031CEA3 /* CFNetwork.framework in Frameworks */,
                                D47AB2CC2356AD7C005A3801 /* Network.framework in Frameworks */,
                                D4ADA3301E2B433B0031CEA3 /* Security.framework in Frameworks */,
                                D4ADA32E1E2B43220031CEA3 /* CoreFoundation.framework in Frameworks */,
                                D4ADA32F1E2B43220031CEA3 /* Foundation.framework in Frameworks */,
                                D4C7CD661E71E92D00139817 /* MobileAsset.framework in Frameworks */,
+                               DA2F592123A9874800C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                5E01F5B1227C859200BC884C /* Foundation.framework in Frameworks */,
                                DCE4E8C91D7F356500AFB96E /* libsqlite3.dylib in Frameworks */,
                                DCE4E8C81D7F355F00AFB96E /* libbsm.dylib in Frameworks */,
+                               F6F4105324AC622F00369037 /* libaks.a in Frameworks */,
                                DCE4E8C71D7F355900AFB96E /* Security.framework in Frameworks */,
                                DCE4E8C61D7F354700AFB96E /* CoreFoundation.framework in Frameworks */,
                                DCE4E8C51D7F354300AFB96E /* IOKit.framework in Frameworks */,
                                F6AF96681E646CAF00917214 /* libcoreauthd_client.a in Frameworks */,
                                F682C1D41F4486F700F1B029 /* libctkloginhelper.a in Frameworks */,
+                               DA2F591E23A986A300C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C4C547620E1A0B400BA61BA /* CoreCDP.framework in Frameworks */,
+                               0C570B7923F3A015001FEB3B /* CoreCDP.framework in Frameworks */,
                                CD112FC51DDA31AD00C77A07 /* Accounts.framework in Frameworks */,
                                0CC319241DA46FBF005D42EA /* ProtectedCloudStorage.framework in Frameworks */,
                                DCE4E9401D7F3E4D00AFB96E /* Security.framework in Frameworks */,
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C147A2823F39CD10034F08B /* CoreCDP.framework in Frameworks */,
                                D47AB2CF2356B2ED005A3801 /* Network.framework in Frameworks */,
                                DC4A76A62212691F006F2D8F /* CloudServices.framework in Frameworks */,
-                               0C6C0FCF21F1457600CD5B9E /* CoreCDP.framework in Frameworks */,
                                EB80DE5C2196010F005B10FA /* libz.tbd in Frameworks */,
                                482FE56D2177CF150031C11E /* AuthKit.framework in Frameworks */,
                                D4C6C5D01FB3B45E007EA57E /* libarchive.2.dylib in Frameworks */,
                                E71F3E4116EA6A5100FAF9B4 /* SystemConfiguration.framework in Frameworks */,
                                D418CC711E690CBC00330A44 /* MobileAsset.framework in Frameworks */,
                                0CFC029C1D41650700E6283B /* libcoretls.dylib in Frameworks */,
+                               DA53FC4423A9C779002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DCD22D531D8CC0EF001C9B81 /* libASN1.a in Frameworks */,
                                E7F482A11C7543E500390FDB /* libsqlite3.dylib in Frameworks */,
                                E7F482A31C7544E600390FDB /* libctkclient_test.a in Frameworks */,
-                               E7F482A61C75453900390FDB /* libcoreauthd_test_client.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                EB75B48C1E75407C00E469CC /* libutilities.a in Frameworks */,
                                EB75B48D1E75408900E469CC /* libASN1.a in Frameworks */,
                                EB75B48F1E75409A00E469CC /* libsqlite3.dylib in Frameworks */,
-                               EB75B4901E7540AA00E469CC /* libctkclient_test.a in Frameworks */,
-                               EB75B4911E7540BF00E469CC /* libcoreauthd_test_client.a in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               DCAAF3362493F9C600D4EB55 /* LocalAuthentication.framework in Frameworks */,
+                               0CCC22D823F39BCA00E1FCD0 /* CoreCDP.framework in Frameworks */,
                                DC4A76AC221269E4006F2D8F /* CloudServices.framework in Frameworks */,
                                EB49B2BB202D8894003F34A0 /* libsecurityd_ios.a in Frameworks */,
-                               DC3E18EB2125FB8700073D80 /* libaks_mock.a in Frameworks */,
                                EB49B2DD202DF259003F34A0 /* libbsm.tbd in Frameworks */,
                                EB80DE59219600DF005B10FA /* libz.tbd in Frameworks */,
                                EB49B2C2202DF002003F34A0 /* libDER.a in Frameworks */,
                                482FE5692177C7670031C11E /* AuthKit.framework in Frameworks */,
-                               0C6C0FD321F1494C00CD5B9E /* CoreCDP.framework in Frameworks */,
                                EB49B2BE202DEF29003F34A0 /* libSecureObjectSyncServer.a in Frameworks */,
                                EB49B2C1202DEF8D003F34A0 /* libASN1.a in Frameworks */,
                                EB49B2C0202DEF7D003F34A0 /* libutilities.a in Frameworks */,
                                EB49B2CD202DF0F9003F34A0 /* SystemConfiguration.framework in Frameworks */,
                                EB49B2C7202DF0E9003F34A0 /* IOKit.framework in Frameworks */,
                                EB49B2BC202DEF14003F34A0 /* libsqlite3.tbd in Frameworks */,
+                               DA53FC4223A9C442002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                EB6952B1223B75C300F02C1C /* CoreData.framework in Frameworks */,
                                EB6952B2223B75C300F02C1C /* SystemConfiguration.framework in Frameworks */,
                                EB6952B3223B75C300F02C1C /* libsqlite3.dylib in Frameworks */,
+                               DA2F592823A99F6300C30285 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                EB89087921F17D3C00F0DDDB /* Security.framework in Frameworks */,
                                EB89087B21F17D3C00F0DDDB /* SystemConfiguration.framework in Frameworks */,
                                EB89087E21F17D3C00F0DDDB /* libsqlite3.dylib in Frameworks */,
+                               DA3862AC23AAE3D3001E21F1 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                EBB8521D22F7948B00424FD0 /* libutilities.a in Frameworks */,
                                EBB8521B22F7945600424FD0 /* XCTest.framework in Frameworks */,
                                EBB852CF22F7A05600424FD0 /* OCMock.framework in Frameworks */,
+                               DA53FC4823A9CC16002D5EA9 /* SoftLinking.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+               0C0203DE23A855B8005D0A68 /* proto */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0C0203E023A8564E005D0A68 /* OTEscrowRecord.proto */,
+                               0C0D920523BFEA740070A68C /* OTCDPRecoveryInformation.proto */,
+                               0C0203E523A85780005D0A68 /* generated_source */,
+                       );
+                       name = proto;
+                       sourceTree = "<group>";
+               };
+               0C0203E523A85780005D0A68 /* generated_source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0C468FEA23C7D4C8006F4582 /* OTCDPRecoveryInformation.h */,
+                               0C468FEE23C7D4CA006F4582 /* OTCDPRecoveryInformation.m */,
+                               0C468FE823C7D4C8006F4582 /* OTEscrowAuthenticationInformation.h */,
+                               0C468FEC23C7D4C9006F4582 /* OTEscrowAuthenticationInformation.m */,
+                               0C468FDE23C7D471006F4582 /* OTEscrowRecord.h */,
+                               0C468FDD23C7D471006F4582 /* OTEscrowRecord.m */,
+                               0C468FDA23C7D41D006F4582 /* OTEscrowRecordMetadata.h */,
+                               0C468FD823C7D41C006F4582 /* OTEscrowRecordMetadata.m */,
+                               0C468FDB23C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.h */,
+                               0C468FD923C7D41D006F4582 /* OTEscrowRecordMetadataClientMetadata.m */,
+                               0C468FE723C7D4C7006F4582 /* OTICDPRecordContext.h */,
+                               0C468FED23C7D4C9006F4582 /* OTICDPRecordContext.m */,
+                               0C468FE923C7D4C8006F4582 /* OTICDPRecordSilentContext.h */,
+                               0C468FEB23C7D4C9006F4582 /* OTICDPRecordSilentContext.m */,
+                       );
+                       name = generated_source;
+                       sourceTree = "<group>";
+               };
                0C0BDB30175685B000BC1A7E /* secdtests */ = {
                        isa = PBXGroup;
                        children = (
                        path = Categories;
                        sourceTree = "<group>";
                };
-               0C4C546C20E19CF200BA61BA /* Recovered References */ = {
-                       isa = PBXGroup;
-                       children = (
-                               0C9FB40120D8729A00864612 /* CoreCDP.framework */,
-                       );
-                       name = "Recovered References";
-                       sourceTree = "<group>";
-               };
                0C7382E52386379E004F98CB /* ResetCloudKeychainAccount */ = {
                        isa = PBXGroup;
                        children = (
                        path = regressions;
                        sourceTree = "<group>";
                };
-               0C7CEA391FE9CE3900125C79 /* behavior */ = {
-                       isa = PBXGroup;
-                       children = (
-                               EB82A2A41FAFF26900CA64A9 /* SFBehavior.h */,
-                               EB82A2A51FAFF26900CA64A9 /* SFBehavior.m */,
-                       );
-                       path = behavior;
-                       sourceTree = "<group>";
-               };
-               0C8BBE831FC9DA1700580909 /* Octagon Trust */ = {
+               0C8BBE831FC9DA1700580909 /* OT */ = {
                        isa = PBXGroup;
                        children = (
                                DCD33D7D220B9D98000A390B /* State Machine Machinery */,
                                BE34059B1FD71BA700933DAC /* Protocol Buffers */,
                                0C8BBEB11FC9DCAC00580909 /* tests */,
                        );
-                       name = "Octagon Trust";
+                       name = OT;
                        path = ot;
                        sourceTree = "<group>";
                };
                        isa = PBXGroup;
                        children = (
                                DC99B89720EAD4D20065B73B /* Octagon */,
+                               EB45ED3124749ECC008A1F6F /* OTTests-Info.plist */,
+                               EB45ED3224749ECC008A1F6F /* gen_test_plist.py */,
                        );
                        path = tests;
                        sourceTree = "<group>";
                        path = generated_source;
                        sourceTree = "<group>";
                };
+               0CCC227B23F3586F00E1FCD0 /* ot-tests */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0CCC229223F35D4300E1FCD0 /* OctagonTrustTests-Info.plist */,
+                               0C9A54B7250C290800FF007B /* OctagonTrustTests.h */,
+                               0CCC229F23F367D100E1FCD0 /* OctagonTrustTests-EscrowRecords.m */,
+                               0CCC22A323F36DD300E1FCD0 /* OctagonTrustTests-EscrowTestVectors.h */,
+                               0C9A54B4250C27F100FF007B /* OctagonTrustTests+Errors.m */,
+                       );
+                       path = "ot-tests";
+                       sourceTree = "<group>";
+               };
+               0CCC22CB23F3958B00E1FCD0 /* categories */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0CCC22CC23F395A100E1FCD0 /* OctagonTrustEscrowRecoverer.h */,
+                       );
+                       path = categories;
+                       sourceTree = "<group>";
+               };
+               0CD743A723C3EC8000FA0EC5 /* OctagonTrust */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0C9F65AC23E3ACF700B1A2C5 /* OTEscrowTranslation.h */,
+                               0C9F65AA23E3ACF700B1A2C5 /* OTEscrowTranslation.m */,
+                               0CD743A823C3EC8000FA0EC5 /* OctagonTrust.h */,
+                               0CD743B723C3ED7E00FA0EC5 /* OctagonTrust.m */,
+                               0CD743A923C3EC8000FA0EC5 /* Info.plist */,
+                               0CCC22CB23F3958B00E1FCD0 /* categories */,
+                               0CCC227B23F3586F00E1FCD0 /* ot-tests */,
+                       );
+                       path = OctagonTrust;
+                       sourceTree = "<group>";
+               };
                0CE15E29222DF5FF00B7EAA4 /* RecoveryKey */ = {
                        isa = PBXGroup;
                        children = (
                                0CF405FB2072E351003D6A7F /* Resources */,
                                0CD9E33E235928D1002995DE /* OctagonSignPosts.h */,
                                0CD9E340235928E9002995DE /* OctagonSignPosts.m */,
-                               0CF0E2E71F8EE40700BD18E4 /* SFSignInAnalytics.h */,
-                               0CF0E2E31F8EE3B000BD18E4 /* SFSignInAnalytics.m */,
-                               0C108C4B208A677100E8CF70 /* SFSignInAnalytics+Internal.h */,
                                0CF405F32072E295003D6A7F /* tests */,
                        );
                        path = SigninMetrics;
                0CF405F32072E295003D6A7F /* tests */ = {
                        isa = PBXGroup;
                        children = (
-                               0CF405F42072E2BF003D6A7F /* SFSignInAnalyticsTests.m */,
                        );
                        path = tests;
                        sourceTree = "<group>";
                                0C78F1C816A5E13400654E08 /* regressions */,
                                107226D00D91DB32003CF14F /* SecTask.c */,
                                4C7CE56E0DC7DB0A00AE53FC /* SecEntitlements.h */,
+                               6C54BE0C23F41497004716CB /* SystemEntitlements.h */,
                        );
                        name = sectask;
                        path = ../../../sectask;
                        path = SecureTransportTests;
                        sourceTree = "<group>";
                };
+               3E88361224F0693200E9F4D6 /* secseccodeapitest */ = {
+                       isa = PBXGroup;
+                       children = (
+                               3E88361324F0699F00E9F4D6 /* secseccodeapitest.c */,
+                       );
+                       name = secseccodeapitest;
+                       sourceTree = "<group>";
+               };
                4381690E1B4EDCBD00C54D58 /* SOSCCAuthPlugin */ = {
                        isa = PBXGroup;
                        children = (
                4727FBB81F9918590003AE36 /* secdxctests */ = {
                        isa = PBXGroup;
                        children = (
+                               6CD8412B23F5D871003DDF34 /* KeychainBackupTests.m */,
                                477A1FEB2037A0E000ACD81D /* KeychainXCTest.h */,
                                477A1FEC2037A0E000ACD81D /* KeychainXCTest.m */,
                                4727FBB91F9918590003AE36 /* KeychainCryptoTests.m */,
                                47B503C5203B97A000722164 /* SFCredentialStoreTests.m */,
                                477A1FE1203763A500ACD81D /* KeychainAPITests.m */,
                                09BFE35A20A32E0E008511E9 /* KeychainEntitlementsTest.m */,
+                               6C84E3C723ECBC84003C9710 /* KeychainAppClipTests.m */,
                                4727FBBB1F9918590003AE36 /* Info.plist */,
+                               6C5D62A5221B6E3F00AF79DC /* secdxctests-entitlements.plist */,
                        );
                        path = secdxctests;
                        sourceTree = "<group>";
                                47922D171FAA65120008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.proto */,
                                47922D201FAA75FF0008F7E0 /* SecDbKeychainSerializedMetadata.proto */,
                                47922D2C1FAA77970008F7E0 /* SecDbKeychainSerializedSecretData.proto */,
+                               6C6AF178221A03930091CE0A /* SecDbKeychainSerializedMetadataKey.proto */,
                        );
                        path = "SecDbKeychainV7-protobufs";
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                DCE4E80D1D7A4E3A00AFB96E /* com.apple.securityd.plist */,
+                               DCDACB5724A3F1AA0054080C /* com.apple.security.ckks.plist */,
                                EB3FB9B7231C12A800DF52EA /* com.apple.security.trustedpeers.plist */,
                                48284A041D1DB06E00C76CB7 /* README_os_log_prefs.txt */,
                        );
                4C35DB67094F906D002917C4 = {
                        isa = PBXGroup;
                        children = (
+                               3DC5BD58241830D50039ABF4 /* SecureTransportTests_macos.xctestplan */,
+                               3DC5BD59241845100039ABF4 /* SecureTransportTests_ios.xctestplan */,
                                DC6D2C941DD3B20400BE372D /* keychain */,
                                DC5AC2021D83668700CF422C /* Security.framework */,
                                DC5AC1FD1D83647300CF422C /* SecureObjectSync */,
                                4CAB97FD1114CC5300EFB38D /* README.keychain */,
                                4C4CE9070AF81ED80056B01D /* TODO */,
                                EBAC4A512189743D00FBEC43 /* rio.yml */,
-                               0C4C546C20E19CF200BA61BA /* Recovered References */,
                        );
                        sourceTree = "<group>";
                };
                                D4ADA3191E2B41670031CEA3 /* libtrustd.a */,
                                6CCDF7841E3C25FA003F2555 /* KeychainEntitledTestRunner */,
                                6CF4A0B41E45488B00ECD7B5 /* KeychainEntitledTestApp.app */,
-                               6CF4A0E01E4549F200ECD7B5 /* KeychainEntitledTestApp.app */,
                                EB27FF111E402CD300EC9E3A /* ckksctl */,
                                470415CF1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */,
                                47702B1E1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */,
                                EB108F411E6CE4D2003B0456 /* KCPairingTests.xctest */,
                                F667EC601E96E9B100203D5C /* authdtest */,
                                D41257CF1E9410A300781F23 /* trustd */,
-                               6C9808611E788AEB00E70590 /* CKKSCloudKitTests.xctest */,
-                               6C98089D1E788AFD00E70590 /* CKKSCloudKitTests.xctest */,
                                ACBAF6DD1E9417F40007BA2F /* libsecurity_transform_regressions.a */,
                                BEF88C281EAFFC3F00357577 /* TrustedPeers.framework */,
                                BEF88C301EAFFC3F00357577 /* TrustedPeersTests.xctest */,
                                BED208DD1EDF950E00753952 /* manifeststresstest */,
                                47C51B841EEA657D0032D9E5 /* SecurityUnitTests.xctest */,
                                EB2D54AA1F02A45E00E46890 /* secatomicfile */,
-                               4727FBB71F9918580003AE36 /* secdxctests_ios.xctest */,
+                               4727FBB71F9918580003AE36 /* secdxctests.xctest */,
                                0C85E0031FB38BB6000343A7 /* OTTests.xctest */,
                                6C9AA79E1F7C1D8F00D08296 /* supdctl */,
                                6CAA8D201F842FB3007B6E03 /* securityuploadd */,
                                3DD1FF4D201C07F30086D049 /* SecureTransport_macos_tests.xctest */,
                                3DD1FFD0201FDB1D0086D049 /* SecureTransport_ios_tests.xctest */,
                                BEAA002B202A832500E51F45 /* TrustedPeersHelper.xpc */,
-                               478D429C1FD72A8100CAB645 /* secdxctests_mac.xctest */,
                                EB49B2AE202D877F003F34A0 /* secdmockaks.xctest */,
                                47C2F1832059CB680062DE30 /* KeychainResources.bundle */,
                                4718AE2D205B39620068EC3F /* securityd */,
                                4718AEE2205B39C40068EC3F /* libsecurityd_bridge.a */,
-                               0CF406502072E3E3003D6A7F /* SignInAnalyticsTests_ios.xctest */,
-                               0C9AEEB720783FBB00BF6237 /* SignInAnalyticsTests_osx.xctest */,
                                DAE40BCE20CF3E47002D5674 /* secitemcanarytest */,
                                DC0EF8EF208697C600AB9E95 /* tpctl */,
                                BED987D32099145300607A5F /* TrustedPeersHelperUnitTests.xctest */,
                                DA41FE0E2241ADC000838FB3 /* otpaird */,
                                EBB851EC22F7912400424FD0 /* SecurityUtilitiesTests.xctest */,
                                5A442F90233C330F00918373 /* experimentTool */,
+                               0CD743A623C3EC8000FA0EC5 /* OctagonTrust.framework */,
+                               6C7BE2E723C3DD64003BB2CA /* securitytool_bridge */,
+                               0CCC227923F357EE00E1FCD0 /* OctagonTrustTests.xctest */,
+                               6C2045EA2424BA7E00F9461D /* KeychainStasher */,
+                               6C963281242A279B00C53CE2 /* stashtester */,
+                               3E88361124F068EF00E9F4D6 /* secseccodeapitest */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        path = secacltests;
                        sourceTree = "<group>";
                };
+               6C0535F422B7043B0064BA50 /* TestHostBinaries */ = {
+                       isa = PBXGroup;
+                       children = (
+                               6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner.entitlements */,
+                               6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp */,
+                               6CB5F4771E402D6D00DBF3F0 /* KeychainEntitledTestRunner */,
+                       );
+                       name = TestHostBinaries;
+                       path = tests/TestHostBinaries;
+                       sourceTree = "<group>";
+               };
                6C34464D1E2534C200F9522B /* analytics */ = {
                        isa = PBXGroup;
                        children = (
                        path = analytics;
                        sourceTree = "<group>";
                };
+               6C534E0422C3E52600D4781F /* Discovery Plists */ = {
+                       isa = PBXGroup;
+                       children = (
+                       );
+                       name = "Discovery Plists";
+                       path = "tests/Discovery Plists";
+                       sourceTree = "<group>";
+               };
                6C69517B1F758E1000F68F91 /* supd */ = {
                        isa = PBXGroup;
                        children = (
                                6C1260F21F7D5F25001B2EEC /* securityuploadd-osx.plist */,
                                6C5B10211F9164F5009B091E /* securityuploadd.8 */,
                                6CDB600E1FA92C1700410924 /* securityuploadd-Entitlements.plist */,
+                               D42D044124733BEA004E7AA2 /* com.apple.securityuploadd.sb */,
                        );
                        path = supd;
                        sourceTree = "<group>";
                6C7E8F1D21F7BD1C008A2D56 /* SecDbBackupTests */ = {
                        isa = PBXGroup;
                        children = (
-                               6C2008EF220BB4B500674B3A /* Entitlements.plist */,
-                               6C02134F21F7ED45009D5C80 /* Info.plist */,
+                               6C6579FC2394878700701C8B /* SecDbBackupTestsBase.m */,
+                               6CD224E7239493E8001B70FD /* SecDbBackupTestsBase.h */,
                                6C02134D21F7ED16009D5C80 /* SecDbBackupTests.m */,
-                               6C02134C21F7ED16009D5C80 /* SecDbBackupTests.plist */,
+                               6C02134F21F7ED45009D5C80 /* Info.plist */,
+                               6C2008EF220BB4B500674B3A /* SecDbBackupTests-Entitlements.plist */,
                        );
                        name = SecDbBackupTests;
                        path = tests/SecDbBackupTests;
                        path = generated_source;
                        sourceTree = "<group>";
                };
+               6C963282242A279B00C53CE2 /* stashtester */ = {
+                       isa = PBXGroup;
+                       children = (
+                               6C963283242A279B00C53CE2 /* main.m */,
+                               6C963289242A27F300C53CE2 /* stashtester.entitlements */,
+                       );
+                       name = stashtester;
+                       path = tests/stashtester;
+                       sourceTree = "<group>";
+               };
+               6C997868242362EC008C498D /* KeychainStasher */ = {
+                       isa = PBXGroup;
+                       children = (
+                               6C997869242362EC008C498D /* KeychainStasherProtocol.h */,
+                               6C99786A242362EC008C498D /* KeychainStasher.h */,
+                               6C99786B242362EC008C498D /* KeychainStasher.m */,
+                               6C99786D242362EC008C498D /* main.m */,
+                               6C99786F242362EC008C498D /* KeychainStasher-Info.plist */,
+                               6C48D10D2423A2F3004AF950 /* KeychainStasher.entitlements */,
+                               6C48D10F2423A3C0004AF950 /* com.apple.security.KeychainStasher.sb */,
+                               6C2045F92424BCB800F9461D /* com.apple.security.KeychainStasher.plist */,
+                       );
+                       path = KeychainStasher;
+                       sourceTree = "<group>";
+               };
                6C9AA79F1F7C1D9000D08296 /* supdctl */ = {
                        isa = PBXGroup;
                        children = (
                        path = supdctl;
                        sourceTree = "<group>";
                };
-               6CB5F4771E402D6D00DBF3F0 /* testrunner */ = {
+               6CB5F4771E402D6D00DBF3F0 /* KeychainEntitledTestRunner */ = {
                        isa = PBXGroup;
                        children = (
-                               6CB5F4791E402E5700DBF3F0 /* KeychainEntitledTestRunner-Entitlements.plist */,
                                6CB5F47A1E402E5700DBF3F0 /* KeychainEntitledTestRunner.m */,
                        );
-                       path = testrunner;
+                       path = KeychainEntitledTestRunner;
                        sourceTree = "<group>";
                };
                6CB6CBFE2198D40B0080AD6F /* SecDbBackupManager-protobufs */ = {
                        path = "SecDbBackupManager-protobufs";
                        sourceTree = "<group>";
                };
-               6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */ = {
+               6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp */ = {
                        isa = PBXGroup;
                        children = (
                                6CF4A0B61E45488B00ECD7B5 /* AppDelegate.h */,
                                6CF4A0C41E45488B00ECD7B5 /* Info.plist */,
                                6CF4A0B91E45488B00ECD7B5 /* Supporting Files */,
                        );
-                       name = KeychainEntitledTestApp_mac;
-                       path = ../../../KeychainEntitledTestApp_mac;
+                       path = KeychainEntitledTestApp;
                        sourceTree = "<group>";
                };
                6CF4A0B91E45488B00ECD7B5 /* Supporting Files */ = {
                        name = "Supporting Files";
                        sourceTree = "<group>";
                };
-               6CF4A0E11E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */ = {
-                       isa = PBXGroup;
-                       children = (
-                               6CF4A0E51E4549F200ECD7B5 /* AppDelegate.h */,
-                               6CF4A0E61E4549F300ECD7B5 /* AppDelegate.m */,
-                               6CF4A0E81E4549F300ECD7B5 /* ViewController.h */,
-                               6CF4A0E91E4549F300ECD7B5 /* ViewController.m */,
-                               6CF4A0EE1E4549F300ECD7B5 /* Assets.xcassets */,
-                               6CF4A0F31E4549F300ECD7B5 /* Info.plist */,
-                               6CF4A0E21E4549F200ECD7B5 /* Supporting Files */,
-                       );
-                       name = KeychainEntitledTestApp_ios;
-                       path = ../../../KeychainEntitledTestApp_ios;
-                       sourceTree = "<group>";
-               };
-               6CF4A0E21E4549F200ECD7B5 /* Supporting Files */ = {
-                       isa = PBXGroup;
-                       children = (
-                               6CF4A0E31E4549F200ECD7B5 /* main.m */,
-                       );
-                       name = "Supporting Files";
-                       sourceTree = "<group>";
-               };
                7908507E0CA87CF00083CC4D /* ipc */ = {
                        isa = PBXGroup;
                        children = (
                BE3405A21FD71CDE00933DAC /* generated */ = {
                        isa = PBXGroup;
                        children = (
+                               0C3C47C524902D470084B951 /* OTGlobalEnums.h */,
+                               0C3C47C424902D470084B951 /* OTSupportOctagonMessage.h */,
+                               0C3C47C024902D450084B951 /* OTSupportOctagonMessage.m */,
+                               0C3C47C224902D460084B951 /* OTSupportSOSMessage.h */,
+                               0C3C47C324902D460084B951 /* OTSupportSOSMessage.m */,
                                0C89BDA121554DD3003F3CC0 /* OTAccountMetadataClassC.h */,
                                0C89BDA021554DD2003F3CC0 /* OTAccountMetadataClassC.m */,
                                0C9AE28B214054F5003BFDB5 /* OTApplicantToSponsorRound2M1.h */,
                BEAA002C202A832500E51F45 /* TrustedPeersHelper */ = {
                        isa = PBXGroup;
                        children = (
-                               0CE15E29222DF5FF00B7EAA4 /* RecoveryKey */,
                                DCB0C28F222F5DF80083AECB /* CuttlefishErrors.swift */,
+                               0CE15E29222DF5FF00B7EAA4 /* RecoveryKey */,
                                0C3BB3312187EC4D0018FC14 /* Categories */,
                                0C0C4F80216FB53A00C14C61 /* BottledPeer */,
                                BE9F4F852072D834004A52C2 /* Cuttlefish Client */,
                                BE55C77B2044D0C90045863D /* Client.swift */,
                                BE9F8D0F206C099800B53D16 /* Container.swift */,
                                DC3A9B2523A9D6120073ED06 /* Container_BottledPeers.swift */,
-                               DCAA209823AAF8BD00DCB594 /* Container_RecoveryKey.swift */,
+                               0C0CB73723AD71400020C6BF /* Container_EscrowRecords.swift */,
                                DCAD8F8422C43EAD007C3872 /* Container_MachineIDs.swift */,
+                               0C3DF8C524789C04009CF03A /* Container_Peers.swift */,
+                               DCAA209823AAF8BD00DCB594 /* Container_RecoveryKey.swift */,
+                               DC9978B72404AA3200A5EE2F /* Container_UserSync.swift */,
                                BE9F8D18206C4AD300B53D16 /* ContainerMap.swift */,
                                BE9F8D11206C121400B53D16 /* Decrypter.swift */,
                                BECFA43C20F9493000B11002 /* Policy.swift */,
                                0CB582BA218915010040C5F2 /* proto */,
                                DC391FA521C04D1500772585 /* OctagonPeerKeys.swift */,
                                DCF6320421C074F30030CCC0 /* CuttlefishAPIHelpers.swift */,
+                               DCBDA460245A39A300B0938B /* com.apple.TrustedPeersHelper.sb */,
                        );
                        path = TrustedPeersHelper;
                        sourceTree = "<group>";
                                BEF88C5B1EB0005E00357577 /* TPPolicy.m */,
                                BEF88C5C1EB0005E00357577 /* TPPolicyDocument.h */,
                                BEF88C5D1EB0005E00357577 /* TPPolicyDocument.m */,
+                               DCC03FA223FF521100A4DA3F /* TPSyncingPolicy.h */,
+                               DCC03FA323FF521100A4DA3F /* TPSyncingPolicy.m */,
                                BEF88C5E1EB0005E00357577 /* TPKey.h */,
                                BECFA46320FFB87400B11002 /* TPKey.m */,
                                BEF88C5F1EB0005E00357577 /* TPTypes.h */,
                                D458C4CA214E1A420043D982 /* AppDelegate.m */,
                                D458C4C8214E1A410043D982 /* AppDelegate.h */,
                                D458C4C5214E1A400043D982 /* Assets.xcassets */,
-                               D458C4C7214E1A400043D982 /* Base.lproj */,
                                D458C4CC214E1A420043D982 /* Info.plist */,
                                D458C4C6214E1A400043D982 /* main.m */,
                                D458C4CB214E1A420043D982 /* trusttests_entitlements.plist */,
                                D4A0F8BB211E69CB00443CA1 /* TestMacroConversions.h */,
                                D44282FE22D68556001746B3 /* TrustEvaluationTestHelpers.m */,
                                D4A7946D22D7DD6E00D1B2B7 /* TrustEvaluationTestHelpers.h */,
+                               EB45ED2E24749DE9008A1F6F /* gen_test_plist.py */,
                        );
                        name = TrustTests;
                        sourceTree = "<group>";
                                D4EA5CF622B225C000883439 /* LoggingServerTests.m */,
                                D49A370B23877ECC0065719F /* OCSPCacheTests.m */,
                                D4BA4FD22388687A000B9E64 /* OCSPCacheTests_data.h */,
-                               D49A370523873BD30065719F /* TrustDaemonTestCase.m */,
-                               D49A370823873BF10065719F /* TrustDaemonTestCase.h */,
+                               D477CB5B237B6E0E00C02355 /* PersonalizationTests.m */,
+                               D477CB69237CBA2C00C02355 /* TrustDaemonTestCase.m */,
+                               D477CB6D237CBACD00C02355 /* TrustDaemonTestCase.h */,
                        );
                        name = DaemonTests;
                        sourceTree = "<group>";
                D4A0F8BE211E69DF00443CA1 /* EvaluationTests */ = {
                        isa = PBXGroup;
                        children = (
+                               D477CB8A237F8DBB00C02355 /* AllowlistBlocklistTests.m */,
+                               D477CB8D237F8EB200C02355 /* AllowlistBlocklistTests_data.h */,
+                               D477CB86237F8B2F00C02355 /* CAIssuerTests.m */,
+                               D477CB89237F8CB300C02355 /* CAIssuerTests_data.h */,
                                D458C4AA214E198D0043D982 /* CTTests.m */,
                                D4EF3222215F102F000A31A5 /* CTTests_data.h */,
                                D4AC5766214E195300A32C01 /* ECTests.m */,
                                D4FD421F217D7B27002B7EE2 /* PathScoringTests.m */,
                                D4FD4222217D7B48002B7EE2 /* PathScoringTests_data.h */,
                                D458C513214E27620043D982 /* PolicyTests.m */,
+                               D477CB81237F692400C02355 /* RevocationTests.m */,
+                               D477CB85237F6A0700C02355 /* RevocationTests_data.h */,
                                D458C4B7214E19AF0043D982 /* SignatureAlgorithmTests.m */,
                                D458C4B6214E19AE0043D982 /* SignatureAlgorithmTests_data.h */,
+                               D423114223725F9F000E470A /* SMIMEPolicyTests.m */,
                                D4056A1922712A650026E24E /* SSLPolicyTests.m */,
                                D4056A1C22712AD80026E24E /* SSLPolicyTests_data.h */,
-                               D49A370023873A570065719F /* RevocationTests.m */,
-                               D49A370223873A570065719F /* RevocationTests_data.h */,
+                               D458DAC22375FEA300E5890E /* TrustSettingsTests.m */,
+                               D458DAC52375FEE900E5890E /* TrustSettingsTests_data.h */,
+                               D477CB8E237F975500C02355 /* ValidTests.m */,
                                D4AC5764214E195200A32C01 /* VerifyDateTests.m */,
                                D4AC5765214E195300A32C01 /* VerifyDateTests_data.h */,
                                D4A0F8CB211E6A8200443CA1 /* TrustEvaluationTestCase.h */,
                D4A0F8C0211E69F500443CA1 /* TestData */ = {
                        isa = PBXGroup;
                        children = (
+                               D4231147237261F7000E470A /* SMIMEPolicyTests-data */,
                                D4B2966822DBFDB100DCF250 /* TestCopyProperties_ios-data */,
                                D4D92DA72278904F0009A7CF /* nist-certs */,
                                D4AC8BED2132127A006E9871 /* si-18-certificate-parse */,
                        isa = PBXGroup;
                        children = (
                                DC0BC9DB1D8B827200070CB0 /* CipherSuite.h */,
-                               DC0BC9DC1D8B827200070CB0 /* SecureTransport.h */,
                        );
                        name = "Public Headers";
                        path = ../Security;
                        isa = PBXGroup;
                        children = (
                                DC0BC9DE1D8B827200070CB0 /* sslTypes.h */,
+                               DC0BC9DC1D8B827200070CB0 /* SecureTransport.h */,
                                DC0BC9DF1D8B827200070CB0 /* SecureTransportPriv.h */,
                        );
                        name = "Private Headers";
                                DC0BCB191D8B898100070CB0 /* SecTranslocateUtilities.cpp */,
                                DC0BCB1A1D8B898100070CB0 /* SecTranslocateUtilities.hpp */,
                                DC0BCB1B1D8B898100070CB0 /* SecTranslocateInterface.cpp */,
+                               61BDC97E242932A100A2ABD8 /* SecTranslocateEnumUtils.hpp */,
                        );
                        path = lib;
                        sourceTree = "<group>";
                                DC0BCC3B1D8C68CF00070CB0 /* iCloudKeychainTrace.h */,
                                EB3FBBF42320629400DF52EA /* SecABC.h */,
                                EB3FBBF52320629400DF52EA /* SecABC.m */,
-                               EBF3749A1DC064200065D840 /* SecADWrapper.c */,
-                               EBF3749B1DC064200065D840 /* SecADWrapper.h */,
                                DC0BCC3C1D8C68CF00070CB0 /* SecAKSWrappers.c */,
                                DC0BCC3D1D8C68CF00070CB0 /* SecAKSWrappers.h */,
                                DA5B871A2065A8410093F083 /* SecAutorelease.h */,
                                DC0BCC521D8C68CF00070CB0 /* debugging.c */,
                                DC0BCC531D8C68CF00070CB0 /* debugging.h */,
                                DC0BCC541D8C68CF00070CB0 /* debugging_test.h */,
+                               5F4C21FE2489C68900F0C425 /* simulatecrash_assert.h */,
                                DC0BCC551D8C68CF00070CB0 /* der_array.c */,
                                DC0BCC561D8C68CF00070CB0 /* der_boolean.c */,
                                DC0BCC571D8C68CF00070CB0 /* der_null.c */,
                                DC0BCC611D8C68CF00070CB0 /* der_set.c */,
                                DC0BCC621D8C68CF00070CB0 /* der_set.h */,
                                DC0BCC631D8C68CF00070CB0 /* der_string.c */,
+                               A6BF3B3123EB94A7009AF079 /* entitlements.h */,
+                               A6BF3B3223EB94A7009AF079 /* entitlements.c */,
                                DC0BCC641D8C68CF00070CB0 /* fileIo.c */,
                                DC0BCC651D8C68CF00070CB0 /* fileIo.h */,
                                7221843E1EC6782A004C7BED /* sec_action.c */,
                                E7C787311DD0FED50087FC34 /* NSURL+SOSPlistStore.m */,
                                DC0BCC6B1D8C68CF00070CB0 /* SecDb.c */,
                                DC0BCC6C1D8C68CF00070CB0 /* SecDb.h */,
+                               6C915BE3242E14BC00DBDAFB /* SecDbInternal.h */,
                                DC0BCC6D1D8C68CF00070CB0 /* SecFileLocations.c */,
                                DC0BCC6E1D8C68CF00070CB0 /* SecFileLocations.h */,
                                DC0BCC6F1D8C68CF00070CB0 /* SecXPCError.h */,
                        children = (
                                DCC78E281D8085FC00865A7C /* AppleBaselineEscrowCertificates.h */,
                                D41149A01E7C935D00C078C7 /* AppleiPhoneDeviceCACertificates.h */,
+                               D47A085B2486EC1A000F2C49 /* AppleExternalRootCertificates.h */,
                                DCC78E301D8085FC00865A7C /* SecAccessControl.m */,
                                443381DA18A3D81400215606 /* SecAccessControlPriv.h */,
                                DCC78E351D8085FC00865A7C /* SecBase64.c */,
                                DC4269031E82EDAC002B7110 /* SecItem.m */,
                                DCC78E5A1D8085FC00865A7C /* SecItemBackup.c */,
                                4CE7EA561AEAE8D60067F5BD /* SecItemBackup.h */,
+                               6C513A37244F007B00207D5E /* SecItemRateLimit.h */,
+                               6CF1B5C5245077E400FD8CC4 /* SecItemRateLimit_tests.h */,
+                               6C513A38244F007B00207D5E /* SecItemRateLimit.m */,
                                52AA92881E662A4A004301A6 /* SecBackupKeybagEntry.m */,
                                52AA92871E662A4A004301A6 /* SecBackupKeybagEntry.h */,
                                DCC78E5C1D8085FC00865A7C /* SecItemConstants.c */,
                                DCC78E8A1D8085FC00865A7C /* SecServerEncryptionSupport.c */,
                                E7676DB519411DF300498DD4 /* SecServerEncryptionSupport.h */,
                                DCC78E8C1D8085FC00865A7C /* SecSharedCredential.c */,
+                               BE7B8E112415579800E1CF4F /* SecSharedCredential.m */,
                                DCC78E8E1D8085FC00865A7C /* SecSignatureVerificationSupport.c */,
                                DCC78E8F1D8085FC00865A7C /* SecSignatureVerificationSupport.h */,
                                DCC78E901D8085FC00865A7C /* SecTrust.c */,
                        name = headers;
                        sourceTree = "<group>";
                };
-               DC17899F1D779DD600B50D50 /* SecBreadcrumb */ = {
-                       isa = PBXGroup;
-                       children = (
-                               DC1787731D77915500B50D50 /* SecBreadcrumb.h */,
-                               DC1789A01D779DEE00B50D50 /* SecBreadcrumb.c */,
-                               DC24B5701DA3274000330B48 /* breadcrumb_regressions.h */,
-                               DCE4E6D41D7A41E400AFB96E /* bc-10-knife-on-bread.m */,
-                       );
-                       name = SecBreadcrumb;
-                       sourceTree = "<group>";
-               };
                DC1789A31D779E2400B50D50 /* Security.framework macOS */ = {
                        isa = PBXGroup;
                        children = (
-                               DC17899F1D779DD600B50D50 /* SecBreadcrumb */,
                                DCF783091D88B4B500E694BB /* apple_csp */,
                                DCF785E61D88B96800E694BB /* apple_cspdl */,
                                DCF787341D88C84300E694BB /* apple_file_dl */,
                                D4C263C51F8FF2A9001317EA /* generateErrStrings.pl */,
                                DC178A321D77A1F500B50D50 /* SecDebugErrorMessages.strings */,
                                DC178A331D77A1F500B50D50 /* SecErrorMessages.strings */,
-                               DC178A351D77A1F500B50D50 /* framework.sb */,
                                DC178A381D77A1F500B50D50 /* InfoPlist.strings */,
                                DC178A3A1D77A1F500B50D50 /* TimeStampingPrefs.plist */,
                                DC178A3B1D77A1F500B50D50 /* authorization.dfr.prompts.strings */,
                                DC15F79B1E68EAD5003B9A40 /* CKKSTests+API.m */,
                                DC6593C91ED8DA9200C19462 /* CKKSTests+CurrentPointerAPI.m */,
                                DC9A2C5E1EB3F556008FAC27 /* CKKSTests+Coalesce.m */,
+                               DC86122B2408AC190092E93B /* CKKSTests+ItemSyncChoice.m */,
+                               DCBA6F2824105399009A5187 /* CKKSTests+ForwardCompatibility.m */,
                                DC62DC6E22A8721C000D2D5D /* CKKSTests+MultiZone.h */,
                                DC62DC6B22A87128000D2D5D /* CKKSTests+MultiZone.m */,
                                EBC1023022EBF8AC0083D356 /* CKKSTests+LockStateTracker.m */,
                                DCE7F2081F21726500DDB0F7 /* OctagonAPSReceiverTests.m */,
                                DC9C95951F748D0B000D19E5 /* CKKSServerValidationRecoveryTests.m */,
                                EB0E1AD723576273002B6037 /* CKKSPBFileStorageTests.m */,
+                               EB45ED3024749E63008A1F6F /* gen_test_plist.py */,
                        );
                        name = "Tests (Local)";
                        path = tests;
                                DC8506A42097E8CF00C712EC /* iOS Resources */,
                                DCC78E1C1D8085FC00865A7C /* add_internet_password.c */,
                                DC52EA8E1D80CC2A00B0A59C /* builtin_commands.h */,
+                               BE57B1162509E0FF0045B7FD /* ca_revocation_additions.m */,
                                DCC78E1E1D8085FC00865A7C /* codesign.c */,
                                D4A3A596217A85CB00F0A8DA /* ct_exceptions.m */,
                                DC52EA8F1D80CC2A00B0A59C /* digest_calc.c */,
                                DC5ABFD11D83511A00CF422C /* notifications.cpp */,
                                DC5ABFD21D83511A00CF422C /* SharedMemoryServer.h */,
                                DC5ABFD31D83511A00CF422C /* SharedMemoryServer.cpp */,
+                               6C755604242121F000025D78 /* keychainstasherinterface.h */,
+                               6C755603242121F000025D78 /* keychainstasherinterface.m */,
                        );
                        name = Support;
                        sourceTree = "<group>";
                DC5AC2011D83663C00CF422C /* tests */ = {
                        isa = PBXGroup;
                        children = (
+                               6C534E0422C3E52600D4781F /* Discovery Plists */,
+                               6C0535F422B7043B0064BA50 /* TestHostBinaries */,
                                EBDAF14021C75FC800EAE89F /* SharedMocks */,
                                DC05037721409A4100A8EDB7 /* OCMockUmbrella */,
                                F667EC541E96E8C800203D5C /* authdtests */,
                                EB49B2AF202D8780003F34A0 /* secdmockaks */,
                                6C7E8F1D21F7BD1C008A2D56 /* SecDbBackupTests */,
                                D4A0F8B9211E69A800443CA1 /* TrustTests */,
+                               6C963282242A279B00C53CE2 /* stashtester */,
                        );
                        name = tests;
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                0CDBCD8620AD03FB007F8EA7 /* OTClique.h */,
+                               0CD743BA23C3EF0D00FA0EC5 /* OTClique+Private.h */,
                                0C2F336A20DD643B0031A92D /* OTClique.m */,
                                0C8BBF0B1FCB452200580909 /* OTControl.h */,
                                0C8BBF0E1FCB452400580909 /* OTControl.m */,
                                EB10A3E320356E2000E84270 /* OTConstants.h */,
                                EB10A3E420356E2000E84270 /* OTConstants.m */,
+                               0C0203DE23A855B8005D0A68 /* proto */,
                        );
                        name = Framework;
                        sourceTree = "<group>";
                        isa = PBXGroup;
                        children = (
                                6C34464D1E2534C200F9522B /* analytics */,
-                               0C7CEA391FE9CE3900125C79 /* behavior */,
                                DCAE1DCF2073FCA400B4F687 /* categories */,
                                EB27FF051E402C3C00EC9E3A /* ckksctl */,
+                               0CD743A723C3EC8000FA0EC5 /* OctagonTrust */,
                                DC9B7AD31DCBF336004E9385 /* CloudKit Syncing */,
                                470D96651FCDE45C0065FE90 /* CoreDataKeychain */,
                                4771D974209A755800BA9772 /* KeychainDataclassOwner */,
                                47C2F1852059CB680062DE30 /* KeychainResources */,
                                EB74CC182207E48000F1BBAD /* KeychainSettings */,
-                               0C8BBE831FC9DA1700580909 /* Octagon Trust */,
+                               6C997868242362EC008C498D /* KeychainStasher */,
+                               0C8BBE831FC9DA1700580909 /* OT */,
                                0C8BBEF61FCB402900580909 /* otctl */,
                                DA41FDFC2241A7CD00838FB3 /* otpaird */,
                                DC90A4BD21F275EC001300EB /* escrowrequest */,
                        path = OSX/libsecurity_asn1/lib;
                        sourceTree = "<group>";
                };
-               DC88467E223742CA00738068 /* View Matching */ = {
-                       isa = PBXGroup;
-                       children = (
-                       );
-                       name = "View Matching";
-                       path = view_matching;
-                       sourceTree = "<group>";
-               };
                DC90A4BD21F275EC001300EB /* escrowrequest */ = {
                        isa = PBXGroup;
                        children = (
                DC99B89720EAD4D20065B73B /* Octagon */ = {
                        isa = PBXGroup;
                        children = (
-                               DCC0A4C52152C4AB000AF654 /* Pairing */,
-                               DC27C3C820EADD8200F7839C /* OctagonTests-BridgingHeader.h */,
+                               DCEA0FF6213F1E6F0054A328 /* Octagon.plist */,
+                               DC7EB928211E20DF00516452 /* OctagonDataPersistenceTests.swift */,
                                DC85687C2284E7850088D3EF /* OctagonTestMocks.swift */,
-                               DC4CD9822372294D00EF55FC /* OctagonTests+Helpers.swift */,
+                               DC27C3C820EADD8200F7839C /* OctagonTests-BridgingHeader.h */,
+                               DC99B89320EACA480065B73B /* OctagonTests-Info.plist */,
                                DC27C3C020EAD9C300F7839C /* OctagonTests.swift */,
                                DC4415B323610BF40087981C /* OctagonTests+Account.swift */,
                                DC7F79B522EA4ED4001FB69A /* OctagonTests+CKKS.swift */,
                                DC5BEACC2217509A001681F0 /* OctagonTests+CloudKitAccount.swift */,
                                DC5F2BBD2310B941001ADA5D /* OctagonTests+CoreFollowUp.swift */,
                                DC2819B822F8F6FE007829F5 /* OctagonTests+DeviceList.swift */,
-                               DC7F6A7C233D7FAC00DF5769 /* OctagonTests+ForwardCompatibility.swift */,
-                               0C4CDE6D22922E360050C499 /* OctagonTests+RecoveryKey.swift */,
                                DC07090222936BCC002711B9 /* OctagonTests+ErrorHandling.swift */,
+                               0CBF883A23AAD9DC00652EDD /* OctagonTests+EscrowRecords.swift */,
                                DCDF03112284E34B008055BA /* OctagonTests+EscrowRecovery.swift */,
+                               DC7F6A7C233D7FAC00DF5769 /* OctagonTests+ForwardCompatibility.swift */,
                                0C5824A322860001009E8C15 /* OctagonTests+HealthCheck.swift */,
+                               DC4CD9822372294D00EF55FC /* OctagonTests+Helpers.swift */,
+                               0C4CDE6D22922E360050C499 /* OctagonTests+RecoveryKey.swift */,
                                DC72502D229600A800493D88 /* OctagonTests+Reset.swift */,
-                               DCB947592127534C00ED9272 /* OctagonTests+SOSUpgrade.swift */,
                                0C87D3E2229368A7007853B5 /* OctagonTests+SOS.swift */,
-                               DC7EB928211E20DF00516452 /* OctagonDataPersistenceTests.swift */,
-                               DC99B89320EACA480065B73B /* OctagonTests-Info.plist */,
-                               DCEA0FF6213F1E6F0054A328 /* Octagon.plist */,
-                               5A04BAF922973EA9001848A0 /* OTFollowupTests.m */,
+                               DCB947592127534C00ED9272 /* OctagonTests+SOSUpgrade.swift */,
+                               0CA1D0B223E9023100021038 /* OctagonTests+EscrowTestVectors.swift */,
                                DCFF82702162834C00D54B02 /* OctagonTestsXPCConnections.swift */,
+                               5A04BAF922973EA9001848A0 /* OTFollowupTests.m */,
+                               DCC0A4C52152C4AB000AF654 /* Pairing */,
                                0CBEF3422242C9BE00015691 /* TestsObjcTranslation.h */,
                                0CBEF3412242C9AE00015691 /* TestsObjcTranslation.m */,
+                               DCA7F7EE23A44AA200927989 /* OctagonPolicyTests.swift */,
                        );
                        name = Octagon;
                        path = octagon;
                DC9B7AD31DCBF336004E9385 /* CloudKit Syncing */ = {
                        isa = PBXGroup;
                        children = (
-                               DC88467E223742CA00738068 /* View Matching */,
                                DC9FD3161F857FF800C8AAC8 /* Protocol Buffers */,
                                DCD662F21E3294DE00188186 /* CloudKit Support */,
                                DCFE1C311F17ECC3007640C8 /* dispatch Support */,
                                DCD662EB1E32946000188186 /* Sync Objects */,
                                DCD662F11E32946E00188186 /* Operations */,
                                DC3502B61E0208BE00BC0587 /* Tests (Local) */,
-                               DCA4D2121E5651950056214F /* Tests (Live CloudKit) */,
                                DC1ED8C21DD5538C002BDCFA /* CKKS.h */,
                                DC1ED8C51DD55476002BDCFA /* CKKS.m */,
+                               DC880F67243D4CC00059806D /* CKKSLogging.m */,
+                               DCC40B0F2383786D00402CB9 /* CKKSStates.h */,
+                               DCC40B102383786D00402CB9 /* CKKSStates.m */,
                                DC391F9921BF2F4B00772585 /* CKKSConstants.m */,
                                DCF7A89F1F04502300CABE89 /* CKKSControlProtocol.h */,
                                DCF7A8A21F0450EB00CABE89 /* CKKSControlProtocol.m */,
                        path = generated_source;
                        sourceTree = "<group>";
                };
-               DCA4D2121E5651950056214F /* Tests (Live CloudKit) */ = {
-                       isa = PBXGroup;
-                       children = (
-                               6CF4A0B51E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */,
-                               6CF4A0E11E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */,
-                               6CB5F4771E402D6D00DBF3F0 /* testrunner */,
-                               6CCDF7911E3C2D69003F2555 /* CKKSCloudKitTests.m */,
-                               6CB5F4751E4025AB00DBF3F0 /* CKKSCloudKitTestsInfo.plist */,
-                       );
-                       name = "Tests (Live CloudKit)";
-                       path = tests;
-                       sourceTree = "<group>";
-               };
                DCA4D2191E569FFE0056214F /* Helpers */ = {
                        isa = PBXGroup;
                        children = (
                                EB4E0CD51FF36A1900CDCACC /* CKKSReachabilityTracker.m */,
                                DC207EB61ED4EAB600D46873 /* CKKSLockStateTracker.h */,
                                DC207EB71ED4EAB600D46873 /* CKKSLockStateTracker.m */,
+                               DC3412E5245780B9008ABD0A /* CKKSOperationDependencies.h */,
+                               DC3412E6245780BA008ABD0A /* CKKSOperationDependencies.m */,
                                DCCD88E61E42622200F5AA71 /* CKKSGroupOperation.h */,
                                DCCD88E71E42622200F5AA71 /* CKKSGroupOperation.m */,
                                DC1447881F5764C600236DB4 /* CKKSResultOperation.h */,
                                DCB344731D8A35270054D16E /* regressions */,
                                DCB342F81D8A32A20054D16E /* lib */,
                                DC1787281D77903700B50D50 /* SecAccessPriv.h */,
-                               DC1787291D77903700B50D50 /* SecCertificateBundle.h */,
                                DC17872A1D77903700B50D50 /* SecFDERecoveryAsymmetricCrypto.h */,
                                DC17872B1D77903700B50D50 /* SecIdentitySearchPriv.h */,
                                DC17872C1D77903700B50D50 /* SecKeychainItemExtendedAttributes.h */,
                                DCB342441D8A32A20054D16E /* SecBase.cpp */,
                                DCB342451D8A32A20054D16E /* SecBridge.h */,
                                DCB342461D8A32A20054D16E /* SecCertificate.cpp */,
-                               DCB342471D8A32A20054D16E /* SecCertificateBundle.cpp */,
                                DCB342491D8A32A20054D16E /* SecIdentity.cpp */,
                                DCB3424A1D8A32A20054D16E /* SecIdentitySearch.cpp */,
                                DCB3424B1D8A32A20054D16E /* SecItemConstants.c */,
                                DCB342551D8A32A20054D16E /* SecTrust.cpp */,
                                DCB342561D8A32A20054D16E /* SecTrustedApplication.cpp */,
                                DCB342571D8A32A20054D16E /* SecTrustSettings.cpp */,
+                               6C2D463924C88A700015C3C9 /* LegacyAPICounts.h */,
+                               6C2D463B24C88A870015C3C9 /* LegacyAPICounts.m */,
                        );
                        name = "API Bridge";
                        sourceTree = "<group>";
                                DCB342A51D8A32A20054D16E /* PolicyCursor.h */,
                                DCB342A61D8A32A20054D16E /* SecCFTypes.cpp */,
                                DCB342A71D8A32A20054D16E /* SecCFTypes.h */,
-                               DCB342A81D8A32A20054D16E /* SecKeychainAddIToolsPassword.cpp */,
                                DCB342AA1D8A32A20054D16E /* StorageManager.cpp */,
                                DCB342AB1D8A32A20054D16E /* Trust.cpp */,
                                DCB342AC1D8A32A20054D16E /* Trust.h */,
                        children = (
                                1BB1CAB6232C05BC001D0C71 /* CuttlefishXPCWrapper.h */,
                                1BB1CAB4232C05BB001D0C71 /* CuttlefishXPCWrapper.m */,
-                               DCB946AD22FCB88400BE4490 /* OTDetermineHSA2AccountStatusOperation.h */,
-                               DCB946AE22FCB88500BE4490 /* OTDetermineHSA2AccountStatusOperation.m */,
                                DCE772642290712F005862B4 /* OctagonCheckTrustStateOperation.h */,
                                DCE772652290712F005862B4 /* OctagonCheckTrustStateOperation.m */,
-                               DC047085218BCEF20078BDAA /* OTOperationDependencies.h */,
-                               DC047086218BCEF20078BDAA /* OTOperationDependencies.m */,
-                               1B5EAAD92252ABCC008D27E7 /* OTFetchViewsOperation.h */,
-                               1B5EAADB2252ABCC008D27E7 /* OTFetchViewsOperation.m */,
-                               DCBFF830222611A200C5C044 /* OTFetchCKKSKeysOperation.h */,
-                               DCBFF831222611A200C5C044 /* OTFetchCKKSKeysOperation.m */,
-                               DCF12671218A7579000124C6 /* OTLeaveCliqueOperation.h */,
-                               DCF12672218A757A000124C6 /* OTLeaveCliqueOperation.m */,
-                               DC221BA92267E2A60068DBCF /* OTUpdateTPHOperation.h */,
-                               DC221BAA2267E2A60068DBCF /* OTUpdateTPHOperation.m */,
-                               DCF46C2C214B1E0700319A93 /* OTUpdateTrustedDeviceListOperation.h */,
-                               DCF46C2D214B1E0700319A93 /* OTUpdateTrustedDeviceListOperation.m */,
-                               DC6DE897213076C000C6B56D /* OTSOSUpgradeOperation.h */,
-                               DC6DE898213076C000C6B56D /* OTSOSUpgradeOperation.m */,
-                               DC93F02722387A010072720A /* OTSOSUpdatePreapprovalsOperation.h */,
-                               DC93F02822387A010072720A /* OTSOSUpdatePreapprovalsOperation.m */,
-                               DCC67E2B20DDC07900A70A31 /* OTPrepareOperation.h */,
-                               DCC67E2C20DDC07900A70A31 /* OTPrepareOperation.m */,
-                               0C4F4DE121153659007F7E20 /* OTEpochOperation.h */,
-                               0C4F4DDA211535E8007F7E20 /* OTEpochOperation.m */,
+                               0CA7020B2280D99D0085AC54 /* OTCheckHealthOperation.h */,
+                               0CA702082280D5600085AC54 /* OTCheckHealthOperation.m */,
                                0CC8A9002123AA3B005D7F6A /* OTClientVoucherOperation.h */,
                                0CC8A8FA2123A9EB005D7F6A /* OTClientVoucherOperation.m */,
-                               0CC8A9052123AF16005D7F6A /* OTJoinWithVoucherOperation.h */,
-                               0CC8A9012123AEF7005D7F6A /* OTJoinWithVoucherOperation.m */,
-                               0C66046E2134985100BFBBB8 /* OTEstablishOperation.h */,
-                               0C6604692134983900BFBBB8 /* OTEstablishOperation.m */,
-                               DC0D15FF2363A1D6007F0951 /* OTSetCDPBitOperation.h */,
-                               DC0D16002363A1D6007F0951 /* OTSetCDPBitOperation.m */,
                                DC0D16042363BAF4007F0951 /* OTDetermineCDPBitStatusOperation.h */,
                                DC0D16052363BAF4007F0951 /* OTDetermineCDPBitStatusOperation.m */,
-                               DCFF82722162876400D54B02 /* OTResetOperation.h */,
-                               DCFF82732162876400D54B02 /* OTResetOperation.m */,
-                               0C00FC85217A972E00C8BF00 /* OTLocalCuttlefishReset.h */,
-                               0C00FC81217A971800C8BF00 /* OTLocalCuttlefishReset.m */,
+                               DCB946AD22FCB88400BE4490 /* OTDetermineHSA2AccountStatusOperation.h */,
+                               DCB946AE22FCB88500BE4490 /* OTDetermineHSA2AccountStatusOperation.m */,
+                               0C87D3DA229326CB007853B5 /* OTEnsureOctagonKeyConsistency.h */,
+                               0C87D3D6229326A2007853B5 /* OTEnsureOctagonKeyConsistency.m */,
+                               0C64C07F2485A54100D84A5D /* OTPreloadOctagonKeysOperation.h */,
+                               0C64C07C2485A53000D84A5D /* OTPreloadOctagonKeysOperation.m */,
+                               0C4F4DE121153659007F7E20 /* OTEpochOperation.h */,
+                               0C4F4DDA211535E8007F7E20 /* OTEpochOperation.m */,
+                               0C66046E2134985100BFBBB8 /* OTEstablishOperation.h */,
+                               0C6604692134983900BFBBB8 /* OTEstablishOperation.m */,
+                               DCBFF830222611A200C5C044 /* OTFetchCKKSKeysOperation.h */,
+                               DCBFF831222611A200C5C044 /* OTFetchCKKSKeysOperation.m */,
+                               1B5EAAD92252ABCC008D27E7 /* OTFetchViewsOperation.h */,
+                               1B5EAADB2252ABCC008D27E7 /* OTFetchViewsOperation.m */,
+                               0CC8A9052123AF16005D7F6A /* OTJoinWithVoucherOperation.h */,
+                               0CC8A9012123AEF7005D7F6A /* OTJoinWithVoucherOperation.m */,
+                               DCF12671218A7579000124C6 /* OTLeaveCliqueOperation.h */,
+                               DCF12672218A757A000124C6 /* OTLeaveCliqueOperation.m */,
                                DC7F79B822EA5C72001FB69A /* OTLocalCKKSResetOperation.h */,
                                DC7F79B922EA5C72001FB69A /* OTLocalCKKSResetOperation.m */,
+                               0C00FC85217A972E00C8BF00 /* OTLocalCuttlefishReset.h */,
+                               0C00FC81217A971800C8BF00 /* OTLocalCuttlefishReset.m */,
+                               DC6E02122405DDC300C61335 /* OTModifyUserControllableViewStatusOperation.h */,
+                               DC6E02132405DDC400C61335 /* OTModifyUserControllableViewStatusOperation.m */,
+                               DC047085218BCEF20078BDAA /* OTOperationDependencies.h */,
+                               DC047086218BCEF20078BDAA /* OTOperationDependencies.m */,
+                               DCC67E2B20DDC07900A70A31 /* OTPrepareOperation.h */,
+                               DCC67E2C20DDC07900A70A31 /* OTPrepareOperation.m */,
                                DC8757F2218D2003000E65F1 /* OTRemovePeersOperation.h */,
                                DC8757F3218D2003000E65F1 /* OTRemovePeersOperation.m */,
-                               DCC5417F225C05170095D926 /* OTUploadNewCKKSTLKsOperation.h */,
-                               DCC54180225C05180095D926 /* OTUploadNewCKKSTLKsOperation.m */,
                                DC7250352296056000493D88 /* OTResetCKKSZonesLackingTLKsOperation.h */,
                                DC7250362296056000493D88 /* OTResetCKKSZonesLackingTLKsOperation.m */,
-                               0CB8DC962194B1300021A7C8 /* OTVouchWithBottleOperation.h */,
-                               0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */,
-                               0C1B8BB3223323710094D5DA /* OTVouchWithRecoveryKeyOperation.h */,
-                               0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */,
+                               DCFF82722162876400D54B02 /* OTResetOperation.h */,
+                               DCFF82732162876400D54B02 /* OTResetOperation.m */,
+                               DC0D15FF2363A1D6007F0951 /* OTSetCDPBitOperation.h */,
+                               DC0D16002363A1D6007F0951 /* OTSetCDPBitOperation.m */,
                                0CD3D518224047B400024755 /* OTSetRecoveryKeyOperation.h */,
                                0CD3D5152240479600024755 /* OTSetRecoveryKeyOperation.m */,
+                               DC93F02722387A010072720A /* OTSOSUpdatePreapprovalsOperation.h */,
+                               DC93F02822387A010072720A /* OTSOSUpdatePreapprovalsOperation.m */,
+                               DC6DE897213076C000C6B56D /* OTSOSUpgradeOperation.h */,
+                               DC6DE898213076C000C6B56D /* OTSOSUpgradeOperation.m */,
                                0CDD6F78226E62BC009094C2 /* OTTriggerEscrowUpdateOperation.h */,
                                0CDD6F76226E62AD009094C2 /* OTTriggerEscrowUpdateOperation.m */,
-                               0CA7020B2280D99D0085AC54 /* OTCheckHealthOperation.h */,
-                               0CA702082280D5600085AC54 /* OTCheckHealthOperation.m */,
-                               0C87D3DA229326CB007853B5 /* OTEnsureOctagonKeyConsistency.h */,
-                               0C87D3D6229326A2007853B5 /* OTEnsureOctagonKeyConsistency.m */,
+                               DC221BA92267E2A60068DBCF /* OTUpdateTPHOperation.h */,
+                               DC221BAA2267E2A60068DBCF /* OTUpdateTPHOperation.m */,
+                               DCF46C2C214B1E0700319A93 /* OTUpdateTrustedDeviceListOperation.h */,
+                               DCF46C2D214B1E0700319A93 /* OTUpdateTrustedDeviceListOperation.m */,
+                               DCC5417F225C05170095D926 /* OTUploadNewCKKSTLKsOperation.h */,
+                               DCC54180225C05180095D926 /* OTUploadNewCKKSTLKsOperation.m */,
+                               0CB8DC962194B1300021A7C8 /* OTVouchWithBottleOperation.h */,
+                               0CB8DC992194B1440021A7C8 /* OTVouchWithBottleOperation.m */,
+                               0C1B8BB3223323710094D5DA /* OTVouchWithRecoveryKeyOperation.h */,
+                               0C1B8BB52233241E0094D5DA /* OTVouchWithRecoveryKeyOperation.m */,
                        );
                        name = Operations;
                        sourceTree = "<group>";
                                DCC78C5F1D8085D800865A7C /* secd-64-circlereset.m */,
                                48CC58971DA5FF0B00EBD9DB /* secd-66-account-recovery.m */,
                                483E79891DC875F2005C0008 /* secd-67-prefixedKeyIDs.m */,
+                               487A65F3245B65F1005F51D6 /* secd-68-fullPeerInfoIntegrity.m */,
                                DCC78C601D8085D800865A7C /* secd-70-engine.m */,
                                DCC78C611D8085D800865A7C /* secd-70-engine-corrupt.m */,
                                DCC78C621D8085D800865A7C /* secd-70-engine-smash.m */,
                                DCDCC7DD1D9B54DF006487E8 /* secd-202-recoverykey.m */,
                                7281E08E1DFD0D810021E1B7 /* secd-210-keyinterest.m */,
                                522B28081E64B48E002B5638 /* secd-230-keybagtable.m */,
-                               DCFAEDD11D9998DD005187E4 /* secd-668-ghosts.m */,
                                DCC78C791D8085D800865A7C /* SOSAccountTesting.h */,
                                DCC78C7A1D8085D800865A7C /* SecdTestKeychainUtilities.c */,
                                DCC78C7B1D8085D800865A7C /* SecdTestKeychainUtilities.h */,
                                DCC78C991D8085D800865A7C /* SecItemSchema.h */,
                                DCC78C9A1D8085D800865A7C /* SecItemServer.c */,
                                DCC78C9B1D8085D800865A7C /* SecItemServer.h */,
+                               FC637229237B5CF800973738 /* SecItemServer+SWC.h */,
+                               FC63722A237B5CF900973738 /* SecItemServer+SWC.m */,
                                DCC78C9C1D8085D800865A7C /* SecItemBackupServer.c */,
                                DCC78C9D1D8085D800865A7C /* SecItemBackupServer.h */,
                                DCC78C9E1D8085D800865A7C /* SecKeybagSupport.c */,
                        path = "si-66-smime";
                        sourceTree = "<group>";
                };
-               DCC78DF61D8085FC00865A7C /* si-67-sectrust-blocklist */ = {
-                       isa = PBXGroup;
-                       children = (
-                               DCC78DEC1D8085FC00865A7C /* Global Trustee.cer.h */,
-                               DCC78DED1D8085FC00865A7C /* UTN-USERFirst-Hardware.cer.h */,
-                               DCC78DEE1D8085FC00865A7C /* addons.mozilla.org.cer.h */,
-                               DCC78DEF1D8085FC00865A7C /* login.live.com.cer.h */,
-                               DCC78DF01D8085FC00865A7C /* login.skype.com.cer.h */,
-                               DCC78DF11D8085FC00865A7C /* login.yahoo.com.1.cer.h */,
-                               DCC78DF21D8085FC00865A7C /* login.yahoo.com.2.cer.h */,
-                               DCC78DF31D8085FC00865A7C /* login.yahoo.com.cer.h */,
-                               DCC78DF41D8085FC00865A7C /* mail.google.com.cer.h */,
-                               DCC78DF51D8085FC00865A7C /* www.google.com.cer.h */,
-                       );
-                       path = "si-67-sectrust-blocklist";
-                       sourceTree = "<group>";
-               };
                DCC78E121D8085FC00865A7C /* secitem */ = {
                        isa = PBXGroup;
                        children = (
                                DCC78DBD1D8085FC00865A7C /* si-21-sectrust-asr.c */,
                                DCC78DBE1D8085FC00865A7C /* si-22-sectrust-iap.c */,
                                DCC78DBF1D8085FC00865A7C /* si-22-sectrust-iap.h */,
-                               DCC78DC01D8085FC00865A7C /* si-23-sectrust-ocsp.c */,
-                               D46513072097954B005D93FE /* si-23-sectrust-ocsp.h */,
                                DCC78DC11D8085FC00865A7C /* si-24-sectrust-digicert-malaysia.c */,
                                DCC78DC21D8085FC00865A7C /* si-24-sectrust-diginotar.c */,
                                DCC78DC31D8085FC00865A7C /* si-24-sectrust-itms.c */,
                                DC0B62261D90973900D43BCB /* si-25-cms-skid.h */,
                                DC0B62271D90973900D43BCB /* si-25-cms-skid.m */,
                                DCC78DC61D8085FC00865A7C /* si-26-sectrust-copyproperties.c */,
-                               DCC78DC81D8085FC00865A7C /* si-28-sectrustsettings.m */,
-                               DCC78DC91D8085FC00865A7C /* si-28-sectrustsettings.h */,
                                D4AA0D9922FB959600D77FA4 /* si-29-cms-chain-mode.m */,
                                D4AA0D9C22FB962300D77FA4 /* si-29-cms-chain-mode.h */,
                                DCC78DCA1D8085FC00865A7C /* si-30-keychain-upgrade.c */,
                                DCC78DE81D8085FC00865A7C /* si-65-cms-cert-policy.c */,
                                DCC78DEA1D8085FC00865A7C /* si-66-smime */,
                                DCC78DEB1D8085FC00865A7C /* si-66-smime.c */,
-                               DCC78DF61D8085FC00865A7C /* si-67-sectrust-blocklist */,
-                               DCC78DF71D8085FC00865A7C /* si-67-sectrust-blocklist.c */,
                                DCC78DF81D8085FC00865A7C /* si-68-secmatchissuer.c */,
                                DCC78DF91D8085FC00865A7C /* si-69-keydesc.c */,
                                DCC78DFA1D8085FC00865A7C /* si-70-sectrust-unified.c */,
                                DCC78DFB1D8085FC00865A7C /* si-71-mobile-store-policy.c */,
                                DCC78DFC1D8085FC00865A7C /* si-72-syncableitems.c */,
                                DCC78DFD1D8085FC00865A7C /* si-73-secpasswordgenerate.c */,
-                               DCC78DFE1D8085FC00865A7C /* si-74-OTAPKISigner.c */,
                                DCC78DFF1D8085FC00865A7C /* si-76-shared-credentials.c */,
                                DCC78E001D8085FC00865A7C /* si_77_SecAccessControl.c */,
                                DCC78E011D8085FC00865A7C /* si-78-query-attrs.c */,
                                DCC78E021D8085FC00865A7C /* si-80-empty-data.c */,
                                DCC78E051D8085FC00865A7C /* si-82-token-ag.c */,
                                DCC78E061D8085FC00865A7C /* si-83-seccertificate-sighashalg.c */,
-                               BE6215BD1DB6E69100961E15 /* si-84-sectrust-allowlist.m */,
-                               BE9B8B49202BB4A10081EF87 /* si-88-sectrust-valid.m */,
                                DCC78E0B1D8085FC00865A7C /* si-89-cms-hash-agility.m */,
                                DCC78E0D1D8085FC00865A7C /* si-90-emcs.m */,
                                DCC78E0E1D8085FC00865A7C /* si-95-cms-basic.c */,
                        isa = PBXGroup;
                        children = (
                                DCA4D2191E569FFE0056214F /* Helpers */,
+                               DC947E812463831E005B8669 /* CKKSCheckKeyHierarchyOperation.h */,
+                               DC947E832463831F005B8669 /* CKKSCheckKeyHierarchyOperation.m */,
+                               DCB5516A247F3DB50009A859 /* CKKSCreateCKZoneOperation.h */,
+                               DCB5516B247F3DB50009A859 /* CKKSCreateCKZoneOperation.m */,
+                               DCB55173247F48290009A859 /* CKKSDeleteCKZoneOperation.h */,
+                               DCB55174247F48290009A859 /* CKKSDeleteCKZoneOperation.m */,
                                DC5BB4F01E0C86800010F836 /* CKKSIncomingQueueOperation.h */,
                                DC5BB4F11E0C86800010F836 /* CKKSIncomingQueueOperation.m */,
                                DC5BB4FC1E0C98320010F836 /* CKKSOutgoingQueueOperation.h */,
                                DCD662F41E329B6800188186 /* CKKSNewTLKOperation.m */,
                                DCBF2F831F913EF000ED0CA4 /* CKKSHealTLKSharesOperation.h */,
                                DCBF2F841F913EF000ED0CA4 /* CKKSHealTLKSharesOperation.m */,
+                               DC061A6E246211DD0026ADB3 /* CKKSLocalResetOperation.h */,
+                               DC061A70246211DE0026ADB3 /* CKKSLocalResetOperation.m */,
                                DC7A17EB1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h */,
                                DC7A17EC1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.m */,
                                DC5F65AC2225C22C0051E9FA /* CKKSProvideKeySetOperation.h */,
                                DC222CA91E08C57400B09171 /* CloudKitDependencies.h */,
                                DCEA5D831E2F14810089CF55 /* OctagonAPSReceiver.h */,
                                DCEA5D841E2F14810089CF55 /* OctagonAPSReceiver.m */,
-                               DCEA5D951E3014250089CF55 /* CKKSZone.h */,
-                               DCEA5D961E3014250089CF55 /* CKKSZone.m */,
                                DC18F76D1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.h */,
                                DC18F76E1E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m */,
                                DCFB12C31E95A4C000510F5F /* CKKSAccountStateTracker.h */,
                        isa = PBXGroup;
                        children = (
                                BE7089991F9AAF57001ACC20 /* generated */,
-                               BE7089911F9AA027001ACC20 /* TPPBVoucher.proto */,
-                               BE7089CB1FA3B19A001ACC20 /* TPPBPeerDynamicInfo.proto */,
+                               BEC373A820D810DA00DBDF5B /* TPPBAncientEpoch.proto */,
+                               DC88466922373A4000738068 /* TPPBDictionaryMatchingRule.proto */,
                                BEC3739B20CF2AA200DBDF5B /* TPPBDisposition.proto */,
                                BEC373C120D8224A00DBDF5B /* TPPBDispositionEntry.proto */,
-                               BEC373A820D810DA00DBDF5B /* TPPBAncientEpoch.proto */,
-                               BEC373A620D810D800DBDF5B /* TPPBPolicyProhibits.proto */,
-                               BEC373A720D810D900DBDF5B /* TPPBUnknownMachineID.proto */,
-                               BE7089CC1FA3B332001ACC20 /* TPPBPeerStableInfo.proto */,
+                               BE7089CB1FA3B19A001ACC20 /* TPPBPeerDynamicInfo.proto */,
                                BE7089DB1FA407E4001ACC20 /* TPPBPeerPermanentInfo.proto */,
-                               BE7089D91FA3F0AF001ACC20 /* TPPBPolicySecret.proto */,
+                               BE7089CC1FA3B332001ACC20 /* TPPBPeerStableInfo.proto */,
                                6C0C807D20EAF86100334E33 /* TPPBPolicyDocument.proto */,
                                6C0C807F20EAFB9600334E33 /* TPPBPolicyCategoriesByView.proto */,
                                6C0C808020EAFB9600334E33 /* TPPBPolicyModelToCategory.proto */,
                                6C0C808320EAFD7A00334E33 /* TPPBPolicyIntroducersByCategory.proto */,
-                               6C70D8D520EBDE4500AB6FAF /* TPPBPolicyRedaction.proto */,
                                1B8341B72239AD39002BF18A /* TPPBPolicyKeyViewMapping.proto */,
-                               DC88466922373A4000738068 /* TPPBDictionaryMatchingRule.proto */,
+                               BEC373A620D810D800DBDF5B /* TPPBPolicyProhibits.proto */,
+                               6C70D8D520EBDE4500AB6FAF /* TPPBPolicyRedaction.proto */,
+                               BE7089D91FA3F0AF001ACC20 /* TPPBPolicySecret.proto */,
+                               BEC373A720D810D900DBDF5B /* TPPBUnknownMachineID.proto */,
+                               BE7089911F9AA027001ACC20 /* TPPBVoucher.proto */,
                        );
                        path = proto;
                        sourceTree = "<group>";
                DCE0777C21ADE96C002662FD /* generated */ = {
                        isa = PBXGroup;
                        children = (
+                               6C6AF17D221A06F70091CE0A /* SecDbKeychainSerializedMetadataKey.h */,
+                               6C6AF17E221A06F80091CE0A /* SecDbKeychainSerializedMetadataKey.m */,
                                47922D501FAA7DF60008F7E0 /* SecDbKeychainSerializedItemV7.h */,
                                47922D511FAA7DF70008F7E0 /* SecDbKeychainSerializedItemV7.m */,
                                47922D371FAA7C040008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.h */,
                                DC24B5641DA326B900330B48 /* Info.plist */,
                                DC24B5651DA326B900330B48 /* mechanism.h */,
                                DC24B5661DA326B900330B48 /* object.h */,
+                               F681C3AA2386B8B40083F22C /* PreloginUserDb.h */,
                                DC24B5671DA326B900330B48 /* process.h */,
                                DC24B5681DA326B900330B48 /* rule.h */,
                                DC24B5691DA326B900330B48 /* server.h */,
                                DCE4E8AB1D7F353900AFB96E /* main.c */,
                                DCE4E8AC1D7F353900AFB96E /* mechanism.c */,
                                DCE4E8AD1D7F353900AFB96E /* object.c */,
+                               F681C3A82386B8B40083F22C /* PreloginUserDb.m */,
                                DCE4E8AE1D7F353900AFB96E /* process.c */,
                                DCE4E8AF1D7F353900AFB96E /* rule.c */,
                                DCE4E8B01D7F353900AFB96E /* server.c */,
                                0C0C88771CCEC5BD00617D1B /* si-82-sectrust-ct-data */,
                                DCE4E72E1D7A436300AFB96E /* si-82-sectrust-ct-logs.plist */,
                                D4C6C5C71FB2AD3F007EA57E /* si-87-sectrust-name-constraints */,
-                               BE9B8B43202BB42C0081EF87 /* si-88-sectrust-valid-data */,
                                4C50ACFB1410671D00EE92DE /* DigiNotar */,
                                79679E241462028800CF997F /* DigicertMalaysia */,
                                E710C74B1331946500F85568 /* Supporting Files */,
                E7FCBE401314471B000DE34E /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               D47A55892466100A0039285D /* MSUDataAccessor.framework */,
+                               6C99787C242364FB008C498D /* CoreFoundation.framework */,
+                               6C997879242364E5008C498D /* Foundation.framework */,
+                               F6B1B48924144B5E00CB3E3F /* libctkloginhelperlite.a */,
+                               0CCC22D523F39B2E00E1FCD0 /* CoreCDP.framework */,
+                               0CCC22B123F38B5B00E1FCD0 /* libsqlite3.0.tbd */,
+                               DA2F591523A32BB400C30285 /* SoftLinking.framework */,
                                DC89608C2395C75500D339D9 /* CoreServices.framework */,
                                BEC6A9142331992800080069 /* Network.framework */,
                                D47AB2CA2356AD72005A3801 /* Network.framework */,
                                0C75AC642141F18D0073A2F9 /* KeychainCircle.framework */,
                                D4B68C5C211A7D98009FED69 /* libDER.a */,
                                EB490153211C0026001E6D6A /* UserManagement.framework */,
-                               472E184F20D9A20D00ECE7C9 /* libcoreauthd_client.a */,
                                475EDD0720D9A031009D2409 /* LocalAuthenticationPrivateUI.framework */,
                                475EDD0520D98CE2009D2409 /* LocalAuthentication.framework */,
                                475EDD0320D98CD0009D2409 /* libctkclient.a */,
                                475EDD0120D98C81009D2409 /* libaks_acl.a */,
                                475EDCFF20D98C64009D2409 /* IOKit.framework */,
                                475EDCFD20D98C53009D2409 /* libaks.a */,
-                               475EDCFB20D98C3C009D2409 /* libDER.a */,
                                475EDCF920D98C0D009D2409 /* CryptoTokenKit.framework */,
                                475EDCF720D98BF6009D2409 /* CoreCDP.framework */,
                                475EDCF520D98BCF009D2409 /* libACM.a */,
                                EB2CA4D81D2C28C800AB770F /* libaks.a */,
                                4432AF8C1A01472C000958DC /* libaks_acl.a */,
                                DC1789181D77998C00B50D50 /* libbsm.dylib */,
-                               E7F482A51C75453900390FDB /* libcoreauthd_test_client.a */,
                                0CFC029B1D41650700E6283B /* libcoretls.dylib */,
                                E7F482A21C7544E600390FDB /* libctkclient_test.a */,
                                EBE54D771BE33227000C4856 /* libmis.dylib */,
                                DC5225091E402D8B0021640A /* PlatformLibraries.xcconfig */,
                                DC976C581E3AC5E50012A6DD /* PlatformFeatures.xcconfig */,
                                EB2CA5561D2C30F700AB770F /* Security.xcconfig */,
-                               D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */,
                                DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */,
                                DC8E04901D7F6780006D80EB /* lib_ios.xcconfig */,
                                DC71D8DD1D94CF3C0065FB93 /* lib_ios_shim.xcconfig */,
                                D47C56AB1DCA831C00E18518 /* lib_ios_x64.xcconfig */,
                                D47C56AF1DCA841D00E18518 /* lib_ios_x64_shim.xcconfig */,
                                DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */,
-                               BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */,
                                EBF9AE171F536D0300FECBF7 /* Version.xcconfig */,
                                DC340C53208E7BAE004D7EEC /* swift_binary.xcconfig */,
                                DCC1849220EEEC4400F3B26C /* security_framework.xcconfig */,
                EB80211C1D3D9044008540C4 /* Modules */ = {
                        isa = PBXGroup;
                        children = (
+                               0CF7613D23F24B5D00A3C3AD /* KeychainCircle.modulemap */,
+                               0CF7613F23F24B5E00A3C3AD /* OctagonTrust.modulemap */,
                                EB8021411D3D90BB008540C4 /* Security.iOS.modulemap */,
                                EB8021421D3D90BB008540C4 /* Security.macOS.modulemap */,
                                617570BA22C2D19E00EFBA37 /* Security.macOS.private.modulemap */,
                EB9C1DAA1BDFD0FE00F89272 /* RegressionTests */ = {
                        isa = PBXGroup;
                        children = (
+                               3E88361224F0693200E9F4D6 /* secseccodeapitest */,
+                               6CF33CA2238714C900D1E75D /* bats_utd_plist.h */,
+                               6CF33CA4238714C900D1E75D /* PreprocessPlist.sh */,
                                EB9C1DAD1BDFD49400F89272 /* Security.plist */,
                                EBDAA7E320EC46CF003EA6E5 /* SecurityLocalKeychain.plist */,
                                EBE202752092913500B48020 /* SecurityInduceLowDisk.plist */,
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
+               0CD743A123C3EC8000FA0EC5 /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               0C468FE323C7D487006F4582 /* OTEscrowRecordMetadata.h in Headers */,
+                               0C468FF523C7D4D5006F4582 /* OTICDPRecordSilentContext.h in Headers */,
+                               0CD743AA23C3EC8000FA0EC5 /* OctagonTrust.h in Headers */,
+                               0C468FF323C7D4D5006F4582 /* OTICDPRecordContext.h in Headers */,
+                               0C468FE523C7D487006F4582 /* OTEscrowRecordMetadataClientMetadata.h in Headers */,
+                               0C468FEF23C7D4D5006F4582 /* OTCDPRecoveryInformation.h in Headers */,
+                               0C468FE123C7D487006F4582 /* OTEscrowRecord.h in Headers */,
+                               0C468FF123C7D4D5006F4582 /* OTEscrowAuthenticationInformation.h in Headers */,
+                               0C9F65AD23E3AD2E00B1A2C5 /* OTEscrowTranslation.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                225394B01E3080A600D3CD9B /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                                4718AEB5205B39C40068EC3F /* CloudKitCategories.h in Headers */,
                                4718AEB6205B39C40068EC3F /* CKKSDeviceStateEntry.h in Headers */,
                                4718AEB8205B39C40068EC3F /* CKKSAccountStateTracker.h in Headers */,
+                               6C6AF183221A07240091CE0A /* SecDbKeychainSerializedMetadataKey.h in Headers */,
                                4718AEB9205B39C40068EC3F /* CKKSZoneStateEntry.h in Headers */,
                                DC5A01E921BB428500D87AB9 /* CKKSTLKShare.h in Headers */,
                                4718AEBA205B39C40068EC3F /* CKKSTLKShareRecord.h in Headers */,
                                DC3C73541D837B1900F6A832 /* SOSCloudCircle.h in Headers */,
                                524492941AFD6D480043695A /* der_plist.h in Headers */,
                                DC3C73531D837AF800F6A832 /* SOSPeerInfo.h in Headers */,
-                               5A061198229ED8F3006AF14A /* NSDate+SFAnalytics.h in Headers */,
                                D47079F321128C74005BCFDA /* SecCMS.h in Headers */,
+                               A6BC648824897C5E00A21CD7 /* CSCommonPriv.h in Headers */,
                                4C12828D0BB4957D00985BB0 /* SecTrustSettingsPriv.h in Headers */,
                                DCD45355209A5B260086CBFC /* si-cms-signing-identity-p12.h in Headers */,
                                1BE85ED5235CEC250051E1D8 /* sslDeprecated.h in Headers */,
                                CDDE9BD11729ABFA0013B0E8 /* SecPasswordGenerate.h in Headers */,
                                4C7072860AC9EA4F007CC205 /* SecKey.h in Headers */,
+                               0CD743BB23C3EF1D00FA0EC5 /* OTClique+Private.h in Headers */,
                                D4B3B1CC2115150D00A43409 /* SecCmsDigestedData.h in Headers */,
                                476541651F339F6300413F65 /* SecdWatchdog.h in Headers */,
                                D47079FB211355C9005BCFDA /* CMSEncoder.h in Headers */,
                                DCD7EE981F4F4DE9007D9804 /* SecBase64.h in Headers */,
                                4791B4652118BBFF00977C3F /* OTControlProtocol.h in Headers */,
                                4C7073CA0ACB2BAD007CC205 /* SecRSAKey.h in Headers */,
+                               A6BC6491248B0AB400A21CD7 /* SecStaticCodePriv.h in Headers */,
                                EB6928C51D9C9C6E00062A18 /* SecRecoveryKey.h in Headers */,
                                4C0B906E0ACCBD240077CD03 /* SecFramework.h in Headers */,
                                EBF252222155E910000204D6 /* OTJoiningConfiguration.h in Headers */,
-                               EB9B283321C7755700173DC2 /* OTDefines.h in Headers */,
                                4C7391790B01745000C4CBFA /* vmdh.h in Headers */,
                                6CDB5FFB1FA78D2C00410924 /* SFAnalyticsMultiSampler.h in Headers */,
                                4C64E01C0B8FBC71009B306C /* SecIdentity.h in Headers */,
                                6C8CE6C11FA248DA0032ADF0 /* SFAnalyticsActivityTracker+Internal.h in Headers */,
                                D4707A262113EBC1005BCFDA /* SecCmsDecoder.h in Headers */,
                                DC3C7ABA1D838C9F00F6A832 /* sslTypes.h in Headers */,
+                               6C06CB902408602900025303 /* SecItemInternal.h in Headers */,
                                6CE3654B1FA100D00012F6AB /* SFAnalytics.h in Headers */,
                                5A442FA6233C34FE00918373 /* SecExperimentInternal.h in Headers */,
                                4AF7000515AFB73800B9D400 /* SecOTRSession.h in Headers */,
                                22A23B3D1E3AAC9800C41830 /* SecStaticCode.h in Headers */,
                                22A23B3E1E3AAC9800C41830 /* SecRequirement.h in Headers */,
                                DC9C95BE1F79DC5F000D19E5 /* CKKSControl.h in Headers */,
-                               0CBFEACC200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */,
                                DC3C7AB61D838C2D00F6A832 /* SecAsn1Types.h in Headers */,
                                1B2BD397235E050E009A8624 /* Security-tapi.h in Headers */,
                                D43D8B2D20AB8A54005BEEC4 /* Security.apinotes in Headers */,
                                BEC373CB20D822DA00DBDF5B /* TPPBDispositionEntry.h in Headers */,
                                BEF88C7F1EB000BE00357577 /* TPModel.h in Headers */,
                                BE61F5AF1EB0060C00556CCF /* TrustedPeers.h in Headers */,
+                               DCC03FA423FF521100A4DA3F /* TPSyncingPolicy.h in Headers */,
                                BEF88C891EB000BE00357577 /* TPPolicy.h in Headers */,
                                BEF88C871EB000BE00357577 /* TPPeerStableInfo.h in Headers */,
                                BEF88C7B1EB000BE00357577 /* TPDecrypter.h in Headers */,
                                DC0BC7CF1D8B7B7F00070CB0 /* cssmconfig.h in Headers */,
                                DC0BC7DB1D8B7B7F00070CB0 /* oidsbase.h in Headers */,
                                DC0BC7D51D8B7B7F00070CB0 /* cssmspi.h in Headers */,
+                               6C97434824D1C8CB00A2025C /* LegacyAPICounts.h in Headers */,
                                DC0BC7D01D8B7B7F00070CB0 /* cssmcspi.h in Headers */,
                                DC0BC7AD1D8B773000070CB0 /* modload_static.h in Headers */,
                                DC0BC7D21D8B7B7F00070CB0 /* cssmerr.h in Headers */,
                                DC0BCDB21D8C6A1F00070CB0 /* SecInternalReleasePriv.h in Headers */,
                                DC0BCD831D8C6A1E00070CB0 /* SecCFWrappers.h in Headers */,
                                DC0BCDB01D8C6A1F00070CB0 /* SecAppleAnchorPriv.h in Headers */,
+                               5F4C22002489C6AB00F0C425 /* simulatecrash_assert.h in Headers */,
                                B61577EC1F201562004A3930 /* SecPaddingConfigurationsPriv.h in Headers */,
-                               EB4B6E261DC0683600AFC494 /* SecADWrapper.h in Headers */,
                                DC36895921235F2A003A3735 /* SecAKSWrappers.h in Headers */,
                                DC0BCDAA1D8C6A1F00070CB0 /* SecXPCError.h in Headers */,
                                72CDF5131EC679A4002D233B /* sec_action.h in Headers */,
                                DC2671071F3E8A0900816EED /* SecECKey.h in Headers */,
                                DC17877C1D77919500B50D50 /* SecBasePriv.h in Headers */,
                                5F00F95C230614AD00B832E0 /* SecImportExportPriv.h in Headers */,
-                               DC1787741D77915500B50D50 /* SecBreadcrumb.h in Headers */,
                                6CB420AB2051FDE000FF2D44 /* LocalKeychainAnalytics.h in Headers */,
                                1BE85ED0235CEB620051E1D8 /* cms-tapi.h in Headers */,
                                DC1787761D77916600B50D50 /* SecCFAllocator.h in Headers */,
                                DC0C343A21FA7DEB00417D04 /* SecEscrowRequest.h in Headers */,
                                DC17859F1D778C8D00B50D50 /* SecCertificate.h in Headers */,
-                               DC1787361D77903700B50D50 /* SecCertificateBundle.h in Headers */,
                                DC1785501D778ACD00B50D50 /* SecCertificateOIDs.h in Headers */,
                                DC1787821D7791BE00B50D50 /* SecCertificatePriv.h in Headers */,
                                5A6D1B9E20810EF40057CAC8 /* SecProtocolTypes.h in Headers */,
                                DC1787511D7790A500B50D50 /* SecCodePriv.h in Headers */,
                                DC1787521D7790A500B50D50 /* SecCodeSigner.h in Headers */,
                                DC1785301D778A0100B50D50 /* SecCustomTransform.h in Headers */,
-                               0CBFEACD200FCD33009A60E9 /* SFSignInAnalytics.h in Headers */,
                                5A442FA8233C34FF00918373 /* SecExperimentInternal.h in Headers */,
                                DC1787771D77916A00B50D50 /* SecDH.h in Headers */,
                                DC1785311D778A0100B50D50 /* SecDecodeTransform.h in Headers */,
                                DC1787781D77917100B50D50 /* SecItemBackup.h in Headers */,
                                DC17877F1D7791A800B50D50 /* SecItemPriv.h in Headers */,
                                DC17859D1D778C8000B50D50 /* SecKey.h in Headers */,
-                               EB9B283421C7755800173DC2 /* OTDefines.h in Headers */,
                                6CC952481FB4CB2C0051A823 /* SFAnalytics+Internal.h in Headers */,
                                DC1787801D7791AD00B50D50 /* SecKeyPriv.h in Headers */,
                                DC1785521D778ACD00B50D50 /* SecKeychain.h in Headers */,
                                DCA9D84221FFE62A00B27421 /* EscrowRequestXPCProtocol.h in Headers */,
                                DC1786F91D778F2500B50D50 /* SecNullTransform.h in Headers */,
                                DC17873D1D77903700B50D50 /* SecPassword.h in Headers */,
+                               6C06CB912408602A00025303 /* SecItemInternal.h in Headers */,
                                DC1787791D77917700B50D50 /* SecPasswordGenerate.h in Headers */,
                                1BE85ED6235CEC250051E1D8 /* sslDeprecated.h in Headers */,
                                F6EEF77521675EF000FB7F79 /* AuthorizationTrampolinePriv.h in Headers */,
                                DC1785351D778A0100B50D50 /* SecReadTransform.h in Headers */,
                                DC17873F1D77903700B50D50 /* SecRecoveryPassword.h in Headers */,
                                6CE3654C1FA100D10012F6AB /* SFAnalytics.h in Headers */,
+                               D4593EFF24C131180069F577 /* SecTrustStore.h in Headers */,
                                DC17858B1D778B8000B50D50 /* SecRequirement.h in Headers */,
                                DC1787551D7790A500B50D50 /* SecRequirementPriv.h in Headers */,
                                DC17877A1D77917D00B50D50 /* SecServerEncryptionSupport.h in Headers */,
                                D4B3B1D921151BBF00A43409 /* SecCmsSignedData.h in Headers */,
                                DC17857E1D778B4A00B50D50 /* oidscrl.h in Headers */,
                                DC1787701D77911D00B50D50 /* osKeyTemplates.h in Headers */,
-                               5A061199229ED8F4006AF14A /* NSDate+SFAnalytics.h in Headers */,
                                D4707A302114C316005BCFDA /* SecCmsDigestContext.h in Headers */,
                                DC2C5F511F0D935300FEBDA7 /* CKKSControlProtocol.h in Headers */,
                                AA7C71B72185429900EB314F /* SecProtocolTypesPriv.h in Headers */,
                                4723C9C31F152EB60082882F /* SFObjCType.h in Headers */,
                                DCB3323C1F46833E00178C30 /* SecLogging.h in Headers */,
                                DC9C95BD1F79DC5A000D19E5 /* CKKSControl.h in Headers */,
+                               0CD743BC23C3EF1E00FA0EC5 /* OTClique+Private.h in Headers */,
                                DC3C73561D837B9B00F6A832 /* SOSPeerInfoPriv.h in Headers */,
                                EB6928C61D9C9C6F00062A18 /* SecRecoveryKey.h in Headers */,
                                D4B3B1D0211516A100A43409 /* SecCmsEncryptedData.h in Headers */,
                                DC0FA6B02291F63F00FE01C4 /* OctagonPendingFlag.h in Headers */,
                                47922D421FAA7C240008F7E0 /* SecDbKeychainSerializedAKSWrappedKey.h in Headers */,
                                DCFE1C341F17ECE5007640C8 /* CKKSCondition.h in Headers */,
+                               DCB55175247F48290009A859 /* CKKSDeleteCKZoneOperation.h in Headers */,
                                DC1E5AB623063A4E00918162 /* CKKSPeerProvider.h in Headers */,
                                DC047081218BB21E0078BDAA /* OTCuttlefishAccountStateHolder.h in Headers */,
                                DC1DA65E1E4554620094CE7F /* CKKSScanLocalItemsOperation.h in Headers */,
                                DC7A17ED1E36ABC200EF14CE /* CKKSProcessReceivedKeysOperation.h in Headers */,
                                DC52E7E31D80BDA600B0A59C /* SecDbQuery.h in Headers */,
                                470D96711FCDE55B0065FE90 /* SecCDKeychain.h in Headers */,
+                               DCC40B112383786D00402CB9 /* CKKSStates.h in Headers */,
                                DC378B2D1DEF9DF000A3DAFA /* CKKSMirrorEntry.h in Headers */,
                                DC94BCCA1F10448600E07CEB /* CloudKitCategories.h in Headers */,
                                DCC67E2D20DDC07900A70A31 /* OTPrepareOperation.h in Headers */,
                                DCBF2F851F913EF000ED0CA4 /* CKKSHealTLKSharesOperation.h in Headers */,
                                DCE278E81ED7A5B40083B485 /* CKKSUpdateCurrentItemPointerOperation.h in Headers */,
                                DCEA5D851E2F14810089CF55 /* OctagonAPSReceiver.h in Headers */,
+                               6C6AF182221A07230091CE0A /* SecDbKeychainSerializedMetadataKey.h in Headers */,
                                DC1447961F5766D200236DB4 /* NSOperationCategories.h in Headers */,
                                DC4DB1501E24692100CD6769 /* CKKSKey.h in Headers */,
                                DCE278DD1ED789EF0083B485 /* CKKSCurrentItemPointer.h in Headers */,
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C78827520132074002B7475 /* SFSignInAnalytics.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DCB3439C1D8A32A20054D16E /* SecImportExportOpenSSH.h in Headers */,
                                DCB343A61D8A32A20054D16E /* SecPkcs8Templates.h in Headers */,
                                DCB343461D8A32A20054D16E /* ExtendedAttribute.h in Headers */,
+                               6C2D463E24C88AA60015C3C9 /* LegacyAPICounts.h in Headers */,
                                DCB343601D8A32A20054D16E /* Trust.h in Headers */,
                                DCB3437B1D8A32A20054D16E /* PrimaryKey.h in Headers */,
                                DCB343911D8A32A20054D16E /* TokenLogin.h in Headers */,
                                DCD06B491D8E0D7D007602F1 /* blob.h in Headers */,
                                DCD06B911D8E0D7D007602F1 /* unix++.h in Headers */,
                                DCD06B9D1D8E0D7D007602F1 /* macho++.h in Headers */,
+                               5F4C22012489C6AC00F0C425 /* simulatecrash_assert.h in Headers */,
                                DCD06BAA1D8E0D7D007602F1 /* cfmunge.h in Headers */,
                                DCD06B6A1D8E0D7D007602F1 /* seccfobject.h in Headers */,
                                DC2670F21F3E6EC500816EED /* debugging.h in Headers */,
                                DCD06B841D8E0D7D007602F1 /* utility_config.h in Headers */,
                                DCD06B8D1D8E0D7D007602F1 /* pcsc++.h in Headers */,
                                DCD06B9B1D8E0D7D007602F1 /* cfmach++.h in Headers */,
+                               A6BF3B3623EB95F0009AF079 /* entitlements.h in Headers */,
                                DCD06B441D8E0D7D007602F1 /* crc.h in Headers */,
                                DCD06B6D1D8E0D7D007602F1 /* simpleprefs.h in Headers */,
                                DCD06B8B1D8E0D7D007602F1 /* muscle++.h in Headers */,
                        productReference = 0C8BBF081FCB446400580909 /* otctl */;
                        productType = "com.apple.product-type.tool";
                };
-               0C9AEEAB20783FBB00BF6237 /* SignInAnalyticsTests_osx */ = {
+               0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 0C9AEEB420783FBB00BF6237 /* Build configuration list for PBXNativeTarget "SignInAnalyticsTests_osx" */;
+                       buildConfigurationList = 0CCC227623F357EE00E1FCD0 /* Build configuration list for PBXNativeTarget "OctagonTrustTests" */;
                        buildPhases = (
-                               0C9AEEAE20783FBB00BF6237 /* Sources */,
-                               0C9AEEB020783FBB00BF6237 /* Frameworks */,
-                               0C9AEEB320783FBB00BF6237 /* Embed OCMock */,
+                               0CCC220B23F357EE00E1FCD0 /* Sources */,
+                               0CCC226123F357EE00E1FCD0 /* Frameworks */,
+                               0CCC227423F357EE00E1FCD0 /* Resources */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               0C9AEEBA20783FE000BF6237 /* PBXTargetDependency */,
+                               0C7EB14F23F3D1480089097B /* PBXTargetDependency */,
+                               0C7EB14D23F3D13C0089097B /* PBXTargetDependency */,
+                               0CCC22AD23F38B0E00E1FCD0 /* PBXTargetDependency */,
+                               0CCC22AB23F38B0600E1FCD0 /* PBXTargetDependency */,
                        );
-                       name = SignInAnalyticsTests_osx;
-                       productName = CKKSTests;
-                       productReference = 0C9AEEB720783FBB00BF6237 /* SignInAnalyticsTests_osx.xctest */;
+                       name = OctagonTrustTests;
+                       productName = TrustedPeersHelperUnitTests;
+                       productReference = 0CCC227923F357EE00E1FCD0 /* OctagonTrustTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               0CF406042072E3E3003D6A7F /* SignInAnalyticsTests_ios */ = {
+               0CD743A523C3EC8000FA0EC5 /* OctagonTrust */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 0CF4064D2072E3E3003D6A7F /* Build configuration list for PBXNativeTarget "SignInAnalyticsTests_ios" */;
+                       buildConfigurationList = 0CD743AB23C3EC8000FA0EC5 /* Build configuration list for PBXNativeTarget "OctagonTrust" */;
                        buildPhases = (
-                               0CF406112072E3E3003D6A7F /* Sources */,
-                               0CF406342072E3E3003D6A7F /* Frameworks */,
-                               0CF4064A2072E3E3003D6A7F /* Embed OCMock */,
+                               0CD743A123C3EC8000FA0EC5 /* Headers */,
+                               0CD743A223C3EC8000FA0EC5 /* Sources */,
+                               0CD743A323C3EC8000FA0EC5 /* Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               0C5663EE20BE2E1A0035F362 /* PBXTargetDependency */,
-                               0C3E2EA92073F5C400F5B95B /* PBXTargetDependency */,
                        );
-                       name = SignInAnalyticsTests_ios;
-                       productName = CKKSTests;
-                       productReference = 0CF406502072E3E3003D6A7F /* SignInAnalyticsTests_ios.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       name = OctagonTrust;
+                       productName = Clique;
+                       productReference = 0CD743A623C3EC8000FA0EC5 /* OctagonTrust.framework */;
+                       productType = "com.apple.product-type.framework";
                };
                225394AC1E3080A600D3CD9B /* security_codesigning_ios */ = {
                        isa = PBXNativeTarget;
                        productReference = 3DD1FFD0201FDB1D0086D049 /* SecureTransport_ios_tests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
+               3E88360824F068EF00E9F4D6 /* secseccodeapitest */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 3E88360E24F068EF00E9F4D6 /* Build configuration list for PBXNativeTarget "secseccodeapitest" */;
+                       buildPhases = (
+                               3E88360924F068EF00E9F4D6 /* Sources */,
+                               3E88360B24F068EF00E9F4D6 /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = secseccodeapitest;
+                       productName = secbackupntest;
+                       productReference = 3E88361124F068EF00E9F4D6 /* secseccodeapitest */;
+                       productType = "com.apple.product-type.tool";
+               };
                4381690B1B4EDCBD00C54D58 /* SOSCCAuthPlugin */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 438169381B4EDCBD00C54D58 /* Build configuration list for PBXNativeTarget "SOSCCAuthPlugin" */;
                        productReference = 4718AEE2205B39C40068EC3F /* libsecurityd_bridge.a */;
                        productType = "com.apple.product-type.library.static";
                };
-               4727FBB61F9918580003AE36 /* secdxctests_ios */ = {
+               4727FBB61F9918580003AE36 /* secdxctests */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 4727FBC31F9918590003AE36 /* Build configuration list for PBXNativeTarget "secdxctests_ios" */;
+                       buildConfigurationList = 4727FBC31F9918590003AE36 /* Build configuration list for PBXNativeTarget "secdxctests" */;
                        buildPhases = (
                                4727FBB31F9918580003AE36 /* Sources */,
                                4727FBB41F9918580003AE36 /* Frameworks */,
                        buildRules = (
                        );
                        dependencies = (
+                               6CE2AEAB22B2C1BE00C96AE7 /* PBXTargetDependency */,
+                               6CC638EB226695C300E5DB0B /* PBXTargetDependency */,
+                               6CC638ED226695C300E5DB0B /* PBXTargetDependency */,
                                D4BFFD692227B30700163B4B /* PBXTargetDependency */,
                                EB74CBD622077CC600F1BBAD /* PBXTargetDependency */,
-                               EBD7DF8121FF475B0089F2DF /* PBXTargetDependency */,
-                               EBD7DF8321FF475B0089F2DF /* PBXTargetDependency */,
                                47A6FC6A206B461700BD6C54 /* PBXTargetDependency */,
                                47DE88D91FA7ADBB00DD3254 /* PBXTargetDependency */,
                                47DE88D71FA7ADAC00DD3254 /* PBXTargetDependency */,
                                47DE88CE1FA7AD6200DD3254 /* PBXTargetDependency */,
                        );
-                       name = secdxctests_ios;
+                       name = secdxctests;
                        productName = secdxctests;
-                       productReference = 4727FBB71F9918580003AE36 /* secdxctests_ios.xctest */;
+                       productReference = 4727FBB71F9918580003AE36 /* secdxctests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
                47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */ = {
                        productReference = 4771D972209A755800BA9772 /* KeychainDataclassOwner.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
-               478D426C1FD72A8100CAB645 /* secdxctests_mac */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 478D42991FD72A8100CAB645 /* Build configuration list for PBXNativeTarget "secdxctests_mac" */;
-                       buildPhases = (
-                               478D42751FD72A8100CAB645 /* Sources */,
-                               478D427D1FD72A8100CAB645 /* Frameworks */,
-                               090585D020AEF9D300BB7490 /* Install OCMock framework */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                               DC69A5872165298500512BD6 /* PBXTargetDependency */,
-                               47A6FC6C206B462400BD6C54 /* PBXTargetDependency */,
-                               DC34CD3620326C3B00302481 /* PBXTargetDependency */,
-                               DC34CD3420326C3100302481 /* PBXTargetDependency */,
-                               DC34CD2D20326C2C00302481 /* PBXTargetDependency */,
-                               478D426D1FD72A8100CAB645 /* PBXTargetDependency */,
-                               478D426F1FD72A8100CAB645 /* PBXTargetDependency */,
-                               478D42731FD72A8100CAB645 /* PBXTargetDependency */,
-                       );
-                       name = secdxctests_mac;
-                       productName = secdxctests;
-                       productReference = 478D429C1FD72A8100CAB645 /* secdxctests_mac.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
-               };
                47C2F1822059CB680062DE30 /* KeychainResources */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 47C2F1872059CB690062DE30 /* Build configuration list for PBXNativeTarget "KeychainResources" */;
                        productReference = 5EBE247A1B00CCAE0007DB0E /* secacltests */;
                        productType = "com.apple.product-type.tool";
                };
+               6C2045E92424BA7E00F9461D /* KeychainStasher */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 6C2045EE2424BA7F00F9461D /* Build configuration list for PBXNativeTarget "KeychainStasher" */;
+                       buildPhases = (
+                               6C2045E62424BA7E00F9461D /* Sources */,
+                               6C2045E72424BA7E00F9461D /* Frameworks */,
+                               6C2045F32424BBB900F9461D /* Install Sandbox Profile */,
+                               6C2045FA2424BCC300F9461D /* Install LaunchAgent plist */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                               6CA9690D24ACC5C100C08B5E /* PBXTargetDependency */,
+                       );
+                       name = KeychainStasher;
+                       productName = KeychainStasher;
+                       productReference = 6C2045EA2424BA7E00F9461D /* KeychainStasher */;
+                       productType = "com.apple.product-type.tool";
+               };
                6C39234421F13E4D00D018AD /* SecDbBackupTests */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 6C39237621F13E4D00D018AD /* Build configuration list for PBXNativeTarget "SecDbBackupTests" */;
                        buildPhases = (
                                6C39234D21F13E4D00D018AD /* Sources */,
                                6C39235A21F13E4D00D018AD /* Frameworks */,
-                               6C7E8F1F21F7BE64008A2D56 /* Copy BATS Test Discovery Plist */,
-                               6C7E8F2121F7BE7F008A2D56 /* Chown BATS Test Discovery Plist */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               6C8FF4B6224C1A9800E5C812 /* PBXTargetDependency */,
+                               6CC638E7226695B900E5DB0B /* PBXTargetDependency */,
+                               6CC638E9226695B900E5DB0B /* PBXTargetDependency */,
                                D4BFFD622227578900163B4B /* PBXTargetDependency */,
                                D4BFFD602227576E00163B4B /* PBXTargetDependency */,
                                D4BFFD5E2227575C00163B4B /* PBXTargetDependency */,
                                D4BFFD5C2227574C00163B4B /* PBXTargetDependency */,
                                D4BFFD592227574200163B4B /* PBXTargetDependency */,
+                               6CE2AEAD22B2C1C300C96AE7 /* PBXTargetDependency */,
                        );
                        name = SecDbBackupTests;
                        productName = secdxctests;
                        productReference = 6C4605B81F882B9B001421B6 /* KeychainAnalyticsTests.xctest */;
                        productType = "com.apple.product-type.bundle.unit-test";
                };
-               6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */ = {
+               6C7BE2A923C3DD64003BB2CA /* securitytool_bridge */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 6C98085E1E788AEB00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_mac" */;
+                       buildConfigurationList = 6C7BE2E423C3DD64003BB2CA /* Build configuration list for PBXNativeTarget "securitytool_bridge" */;
                        buildPhases = (
-                               6C98083D1E788AEB00E70590 /* Sources */,
-                               6C9808481E788AEB00E70590 /* Frameworks */,
-                               6C98085D1E788AEB00E70590 /* Resources */,
+                               6C7BE2B623C3DD64003BB2CA /* Sources */,
+                               6C7BE2D223C3DD64003BB2CA /* Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               DCD6BF5421E919610015F7A8 /* PBXTargetDependency */,
-                               DC93C4C9214713DC008F8362 /* PBXTargetDependency */,
-                               6C98082F1E788AEB00E70590 /* PBXTargetDependency */,
-                               6C9808311E788AEB00E70590 /* PBXTargetDependency */,
-                               6C9808351E788AEB00E70590 /* PBXTargetDependency */,
-                               6C9808371E788AEB00E70590 /* PBXTargetDependency */,
-                               6C9808391E788AEB00E70590 /* PBXTargetDependency */,
-                               6C9808A01E788B9400E70590 /* PBXTargetDependency */,
-                       );
-                       name = CKKSCloudKitTests_mac;
-                       productName = CKKSTests;
-                       productReference = 6C9808611E788AEB00E70590 /* CKKSCloudKitTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                               6C16258423C4FFD40086A0FF /* PBXTargetDependency */,
+                               6C16258623C4FFD40086A0FF /* PBXTargetDependency */,
+                               6C16258123C4FFC40086A0FF /* PBXTargetDependency */,
+                               6C14CA0423C4F6830097B572 /* PBXTargetDependency */,
+                               6C7BE2AA23C3DD64003BB2CA /* PBXTargetDependency */,
+                               6C7BE2AC23C3DD64003BB2CA /* PBXTargetDependency */,
+                       );
+                       name = securitytool_bridge;
+                       productName = security;
+                       productReference = 6C7BE2E723C3DD64003BB2CA /* securitytool_bridge */;
+                       productType = "com.apple.product-type.tool";
                };
-               6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */ = {
+               6C963280242A279B00C53CE2 /* stashtester */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 6C98089A1E788AFD00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_ios" */;
+                       buildConfigurationList = 6C963288242A279B00C53CE2 /* Build configuration list for PBXNativeTarget "stashtester" */;
                        buildPhases = (
-                               6C9808791E788AFD00E70590 /* Sources */,
-                               6C9808841E788AFD00E70590 /* Frameworks */,
-                               6C9808991E788AFD00E70590 /* Resources */,
+                               6C96327D242A279B00C53CE2 /* Sources */,
+                               6C96327E242A279B00C53CE2 /* Frameworks */,
                        );
                        buildRules = (
                        );
                        dependencies = (
-                               DCD6BF5621E9196E0015F7A8 /* PBXTargetDependency */,
-                               DC93C4CD21471401008F8362 /* PBXTargetDependency */,
-                               6C9808A41E788CB100E70590 /* PBXTargetDependency */,
-                               6C98086B1E788AFD00E70590 /* PBXTargetDependency */,
-                               6C98086D1E788AFD00E70590 /* PBXTargetDependency */,
-                               6C9808711E788AFD00E70590 /* PBXTargetDependency */,
-                               6C9808731E788AFD00E70590 /* PBXTargetDependency */,
-                               6C9808751E788AFD00E70590 /* PBXTargetDependency */,
-                       );
-                       name = CKKSCloudKitTests_ios;
-                       productName = CKKSTests;
-                       productReference = 6C98089D1E788AFD00E70590 /* CKKSCloudKitTests.xctest */;
-                       productType = "com.apple.product-type.bundle.unit-test";
+                       );
+                       name = stashtester;
+                       productName = stashtester;
+                       productReference = 6C963281242A279B00C53CE2 /* stashtester */;
+                       productType = "com.apple.product-type.tool";
                };
                6C9AA79D1F7C1D8F00D08296 /* supdctl */ = {
                        isa = PBXNativeTarget;
                                6CAA8D1D1F842FB3007B6E03 /* Frameworks */,
                                6CAA8D1E1F842FB3007B6E03 /* Copy Manpage */,
                                6CAA8D361F84317F007B6E03 /* Install launchd plist */,
+                               D42D044424734050004E7AA2 /* Install sandbox profile for macOS */,
                        );
                        buildRules = (
                        );
                        productReference = 6CCDF7841E3C25FA003F2555 /* KeychainEntitledTestRunner */;
                        productType = "com.apple.product-type.tool";
                };
-               6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */ = {
+               6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_mac" */;
+                       buildConfigurationList = 6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp" */;
                        buildPhases = (
                                6CF4A0B01E45488B00ECD7B5 /* Sources */,
                                6CF4A0B11E45488B00ECD7B5 /* Frameworks */,
                        );
                        dependencies = (
                        );
-                       name = KeychainEntitledTestApp_mac;
+                       name = KeychainEntitledTestApp;
                        productName = KeychainEntitledTestApp_mac;
                        productReference = 6CF4A0B41E45488B00ECD7B5 /* KeychainEntitledTestApp.app */;
                        productType = "com.apple.product-type.application";
                };
-               6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */ = {
-                       isa = PBXNativeTarget;
-                       buildConfigurationList = 6CF4A0F41E4549F300ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_ios" */;
-                       buildPhases = (
-                               6CF4A0DC1E4549F200ECD7B5 /* Sources */,
-                               6CF4A0DD1E4549F200ECD7B5 /* Frameworks */,
-                               6CF4A0DE1E4549F200ECD7B5 /* Resources */,
-                       );
-                       buildRules = (
-                       );
-                       dependencies = (
-                       );
-                       name = KeychainEntitledTestApp_ios;
-                       productName = KeychainEntitledTestApp_ios;
-                       productReference = 6CF4A0E01E4549F200ECD7B5 /* KeychainEntitledTestApp.app */;
-                       productType = "com.apple.product-type.application";
-               };
                790851B50CA9859F0083CC4D /* securityd_ios */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = 790851C90CA985C10083CC4D /* Build configuration list for PBXNativeTarget "securityd_ios" */;
                                BEAA0029202A832500E51F45 /* Resources */,
                                BEAA0028202A832500E51F45 /* Frameworks */,
                                EB3FB9A3231C125400DF52EA /* Copy Logging Files */,
+                               DC2C884D245B4B3E0040CBEB /* Copy Sandbox Profile (macOS only) */,
                        );
                        buildRules = (
                        );
                                D4707A0221136E69005BCFDA /* Frameworks */,
                                D4707A0321136E69005BCFDA /* Resources */,
                                D4428B432122718400EB8448 /* Generate BATS Plist */,
+                               D428337D24E1D0B10068B2F5 /* Remove Name Constraints Resources from watchOS */,
                        );
                        buildRules = (
                        );
                                DCE4E8541D7A57AE00AFB96E /* Copy LaunchDaemon Files */,
                                BEB463AD1E64F3C1008EB77E /* Copy Sandbox */,
                                D4ADA3111E2B209C0031CEA3 /* Install man8 page */,
+                               D459364124BFBA700066FB43 /* Install Apple Corporate Roots */,
                        );
                        buildRules = (
                        );
                4C35DB69094F906D002917C4 /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
-                               LastSwiftUpdateCheck = 1000;
-                               LastUpgradeCheck = 1120;
+                               LastSwiftUpdateCheck = 1200;
+                               LastUpgradeCheck = 1200;
                                TargetAttributes = {
+                                       0CD743A523C3EC8000FA0EC5 = {
+                                               CreatedOnToolsVersion = 12.0;
+                                       };
                                        4381690B1B4EDCBD00C54D58 = {
                                                CreatedOnToolsVersion = 7.0;
                                        };
                                                CreatedOnToolsVersion = 10.0;
                                                ProvisioningStyle = Automatic;
                                        };
-                                       478D426C1FD72A8100CAB645 = {
-                                               ProvisioningStyle = Automatic;
-                                       };
                                        47C2F1822059CB680062DE30 = {
                                                CreatedOnToolsVersion = 10.0;
                                                ProvisioningStyle = Automatic;
                                        5EBE24791B00CCAE0007DB0E = {
                                                CreatedOnToolsVersion = 7.0;
                                        };
-                                       6C39234421F13E4D00D018AD = {
-                                               ProvisioningStyle = Manual;
+                                       6C2045E92424BA7E00F9461D = {
+                                               CreatedOnToolsVersion = 12.0;
                                        };
-                                       6C98082C1E788AEB00E70590 = {
-                                               TestTargetID = 6CF4A0B31E45488B00ECD7B5;
+                                       6C39234421F13E4D00D018AD = {
+                                               ProvisioningStyle = Automatic;
                                        };
-                                       6C9808681E788AFD00E70590 = {
-                                               TestTargetID = 6CF4A0DF1E4549F200ECD7B5;
+                                       6C963280242A279B00C53CE2 = {
+                                               CreatedOnToolsVersion = 12.0;
                                        };
                                        6C9AA79D1F7C1D8F00D08296 = {
                                                CreatedOnToolsVersion = 9.0;
                                                CreatedOnToolsVersion = 8.3;
                                                ProvisioningStyle = Automatic;
                                        };
-                                       6CF4A0DF1E4549F200ECD7B5 = {
-                                               CreatedOnToolsVersion = 8.3;
-                                               ProvisioningStyle = Automatic;
-                                       };
                                        BEAA002A202A832500E51F45 = {
                                                CreatedOnToolsVersion = 9.3;
                                                LastSwiftMigration = 0930;
                                        };
                                        DCF216D621ADD5B10029CCC1 = {
                                                CreatedOnToolsVersion = 11.0;
+                                               LastSwiftMigration = 1200;
                                                ProvisioningStyle = Automatic;
                                        };
                                        DCF7889C1D88CB5200E694BB = {
                        };
                        buildConfigurationList = 4C35DB6A094F906D002917C4 /* Build configuration list for PBXProject "Security" */;
                        compatibilityVersion = "Xcode 3.2";
-                       developmentRegion = English;
+                       developmentRegion = en;
                        hasScannedForEncodings = 0;
                        knownRegions = (
-                               English,
-                               Japanese,
-                               French,
-                               German,
                                en,
                                Base,
+                               de,
+                               fr,
+                               ja,
                        );
                        mainGroup = 4C35DB67094F906D002917C4;
                        productRefGroup = 4C35DC36094F9120002917C4 /* Products */;
                                DC1789031D77980500B50D50 /* Security_osx */,
                                E7D847C41C6BE9710025BB44 /* KeychainCircle */,
                                BEF88C271EAFFC3F00357577 /* TrustedPeers */,
+                               0CD743A523C3EC8000FA0EC5 /* OctagonTrust */,
                                DC8E04911D7F6CED006D80EB /* ======= Daemons ========= */,
                                DCE4E8931D7F34F600AFB96E /* authd */,
                                DCE4E7F51D7A4DA800AFB96E /* secd */,
                                DC0BC5631D8B6E3D00070CB0 /* XPCTimeStampingService */,
                                BEAA002A202A832500E51F45 /* TrustedPeersHelper */,
                                DA41FE0D2241ADC000838FB3 /* otpaird */,
+                               6C2045E92424BA7E00F9461D /* KeychainStasher */,
                                DC8E04B11D7F6EC9006D80EB /* ======= Libraries ========= */,
                                DCDA5E4F2124B9C5009B11B2 /* aks_support */,
                                DC36895D21235F42003A3735 /* aks_mock */,
                                DC0067921D87876F005AF8DB /* securityd_server_macos */,
                                DC0067C51D878898005AF8DB /* securityd_ucspc */,
                                DC8E04951D7F6D80006D80EB /* ========= CLI =========== */,
+                               6C7BE2A923C3DD64003BB2CA /* securitytool_bridge */,
                                4CB740A20A47567C00D641BB /* securitytool_ios */,
                                DC5ABDC41D832DAB00CF422C /* securitytool_macos */,
                                DCE4E68A1D7A37FA00AFB96E /* security2tool_macos */,
                                DCE4E7311D7A43B500AFB96E /* SecurityTestsOSX */,
                                DC3502B41E0208BE00BC0587 /* CKKSTests */,
                                0C85DFD11FB38BB6000343A7 /* OTTests */,
+                               0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */,
                                DC99B85B20EACA470065B73B /* OctagonTests */,
-                               0CF406042072E3E3003D6A7F /* SignInAnalyticsTests_ios */,
-                               0C9AEEAB20783FBB00BF6237 /* SignInAnalyticsTests_osx */,
                                DC610AAD1D7910C3002223DE /* gk_reset_check_macos */,
                                DC610A551D78F9D2002223DE /* codesign_tests_macos */,
                                DC610A461D78F48F002223DE /* SecTaskTest_macos */,
                                EB433A201CC3243600A7EACE /* secitemstresstest */,
                                EBA9AA7D1CE30E58004E2B68 /* secitemnotifications */,
                                DAE40BC520CF3E46002D5674 /* secitemcanarytest */,
+                               3E88360824F068EF00E9F4D6 /* secseccodeapitest */,
                                DCE4E7CB1D7A4AED00AFB96E /* sectests_macos */,
                                470415CE1E5E14B5001F3D95 /* seckeychainnetworkextensionstest */,
                                47702B1D1E5F409700B29577 /* seckeychainnetworkextensionsystemdaemontest */,
                                4CE5A54C09C796E100D27A3F /* sslViewer */,
                                DC0BC5C51D8B72E700070CB0 /* test-checkpw */,
                                DC0BC5D51D8B73B000070CB0 /* perf-checkpw */,
-                               6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */,
-                               6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */,
-                               6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */,
-                               6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */,
+                               6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp */,
                                6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */,
                                6C46056B1F882B9B001421B6 /* KeychainAnalyticsTests */,
                                47C51B831EEA657D0032D9E5 /* SecurityUnitTests */,
-                               4727FBB61F9918580003AE36 /* secdxctests_ios */,
-                               478D426C1FD72A8100CAB645 /* secdxctests_mac */,
+                               4727FBB61F9918580003AE36 /* secdxctests */,
                                EB49B2AD202D877F003F34A0 /* secdmockaks */,
                                6C39234421F13E4D00D018AD /* SecDbBackupTests */,
                                3DD1FEF5201C07F30086D049 /* SecureTransportTests_macos */,
                                D458C4E0214E1DE00043D982 /* TrustTestsRunner_ios */,
                                D4707A0421136E69005BCFDA /* TrustTests_ios */,
                                D453A4A42122236D00850A26 /* TrustTests_macos */,
+                               6C963280242A279B00C53CE2 /* stashtester */,
                                DC5AC1351D835D9700CF422C /* ===== Source Gen ===== */,
                                DC008B451D90CE53004002A3 /* securityd_macos_mig */,
                                DC6BC26C1D90CFEF00DD57B3 /* securityd_macos_startup */,
 /* End PBXReferenceProxy section */
 
 /* Begin PBXResourcesBuildPhase section */
+               0CCC227423F357EE00E1FCD0 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                4381690A1B4EDCBD00C54D58 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                                4C198F220ACDB4BF00AAB142 /* Certificate.strings in Resources */,
                                4C198F230ACDB4BF00AAB142 /* OID.strings in Resources */,
                                D479F6E21F980FAB00388D28 /* Trust.strings in Resources */,
+                               6C5D62A6221B6E3F00AF79DC /* secdxctests-entitlements.plist in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                52A23EDD161DEC3F00E271E0 /* Default-568h@2x.png in Resources */,
                                D4D886E91CEBDD2A00DC7583 /* nist-certs in Resources */,
-                               BE9B8B4B202BB4D10081EF87 /* si-88-sectrust-valid-data in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6C98085D1E788AEB00E70590 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               6C9808991E788AFD00E70590 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                6CF4A0B21E45488B00ECD7B5 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6CF4A0DE1E4549F200ECD7B5 /* Resources */ = {
-                       isa = PBXResourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                BE197F2419116FD100BA91D1 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               BE197F61191173F200BA91D1 /* entitlements.plist in Resources */,
                                BE197F2C19116FD100BA91D1 /* InfoPlist.strings in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        files = (
                                D4B2966B22DBFDD300DCF250 /* TestCopyProperties_ios-data in Resources */,
                                D4D92DA9227890500009A7CF /* nist-certs in Resources */,
+                               D4231149237261F8000E470A /* SMIMEPolicyTests-data in Resources */,
                                D4056A2022712D750026E24E /* ssl-policy-certs in Resources */,
                                D4AC8BEF213212A7006E9871 /* si-18-certificate-parse in Resources */,
                                D458C51A214E2CC80043D982 /* si-20-sectrust-policies-data in Resources */,
                        files = (
                                D458C51F214E2E0C0043D982 /* Main.storyboard in Resources */,
                                D458C51C214E2DEB0043D982 /* Assets.xcassets in Resources */,
-                               D458C51D214E2DEB0043D982 /* Base.lproj in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                D4B2966A22DBFDC700DCF250 /* TestCopyProperties_ios-data in Resources */,
                                D4D92DA8227890500009A7CF /* nist-certs in Resources */,
+                               D4231148237261F8000E470A /* SMIMEPolicyTests-data in Resources */,
                                D4056A1F22712D750026E24E /* ssl-policy-certs in Resources */,
                                D4AC8BEE21321291006E9871 /* si-18-certificate-parse in Resources */,
                                D458C517214E2C690043D982 /* si-20-sectrust-policies-data in Resources */,
                                DC178A471D77A1F600B50D50 /* InfoPlist.strings in Resources */,
                                DC178A241D77A1E700B50D50 /* cspdl_common.mdsinfo in Resources */,
                                DC178A2B1D77A1E700B50D50 /* cl_primary.mdsinfo in Resources */,
-                               DC178A451D77A1F600B50D50 /* framework.sb in Resources */,
                                DC178A2D1D77A1E700B50D50 /* tp_policyOids.mdsinfo in Resources */,
                                DC178A231D77A1E700B50D50 /* csp_primary.mdsinfo in Resources */,
                                DC178A251D77A1E700B50D50 /* cspdl_csp_capabilities.mdsinfo in Resources */,
                DC99B88E20EACA470065B73B /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
-                       files = (
-                       );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                DCE4E76B1D7A43B500AFB96E /* Resources */ = {
                        buildActionMask = 2147483647;
                        files = (
                                DCE4E76D1D7A43B500AFB96E /* nist-certs in Resources */,
-                               BE9B8B4D202BB4F30081EF87 /* si-88-sectrust-valid-data in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                52A23EDC161DEC3800E271E0 /* Default-568h@2x.png in Resources */,
                                D4D886EA1CEBDE0800DC7583 /* nist-certs in Resources */,
-                               BE9B8B4C202BB4E30081EF87 /* si-88-sectrust-valid-data in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* End PBXResourcesBuildPhase section */
 
 /* Begin PBXShellScriptBuildPhase section */
-               090585D020AEF9D300BB7490 /* Install OCMock framework */ = {
+               090585D120AEF9FE00BB7490 /* Install OCMock framework */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        shellPath = /bin/sh;
                        shellScript = "sh xcscripts/install-test-framework.sh OCMock.framework\n";
                };
-               090585D120AEF9FE00BB7490 /* Install OCMock framework */ = {
+               0C85DFFF1FB38BB6000343A7 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
-                       name = "Install OCMock framework";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "sh xcscripts/install-test-framework.sh OCMock.framework\n";
+                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\n#Disable until this places a plist in this directory\n#chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n";
                };
-               0C85DFFF1FB38BB6000343A7 /* ShellScript */ = {
+               3DD1FF49201C07F30086D049 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\n#Disable until this places a plist in this directory\n#chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n";
+                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\nchown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n";
                };
-               3DD1FF49201C07F30086D049 /* ShellScript */ = {
+               3DD1FFCC201FDB1D0086D049 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\nchown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n";
+                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\nchown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist";
                };
-               3DD1FFCC201FDB1D0086D049 /* ShellScript */ = {
+               6CAA8D361F84317F007B6E03 /* Install launchd plist */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
                        );
+                       name = "Install launchd plist";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\nchown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist";
+                       shellScript = "mkdir -p \"$LAUNCHD_PLIST_LOCATION\"\nplutil -convert binary1 -o \"$LAUNCHD_PLIST_LOCATION/com.apple.securityuploadd.plist\" \"$LAUNCHD_PLIST\"\n";
                };
-               6C7E8F2121F7BE7F008A2D56 /* Chown BATS Test Discovery Plist */ = {
+               8E64DB4E1C18A5B80076C9DF /* Install launchd plist */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
-                       inputFileListPaths = (
-                       );
                        inputPaths = (
+                               "$(PROJECT_DIR)/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.ios.plist",
+                               "$(PROJECT_DIR)/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist",
                        );
-                       name = "Chown BATS Test Discovery Plist";
-                       outputFileListPaths = (
-                       );
+                       name = "Install launchd plist";
                        outputPaths = (
+                               "$(INSTALL_ROOT)/$(INSTALL_DAEMON_AGENT_DIR)/com.apple.security.cloudkeychainproxy3.plist",
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "[ \"$(whoami)\" == \"root\" ] || exit 0\n chown -f root:wheel ${DSTROOT}/AppleInternal/CoreOS/BATS/unit_tests/*.plist\n";
+                       shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist\n";
                };
-               6CAA8D361F84317F007B6E03 /* Install launchd plist */ = {
+               D428337D24E1D0B10068B2F5 /* Remove Name Constraints Resources from watchOS */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
+                       inputFileListPaths = (
+                       );
                        inputPaths = (
                        );
-                       name = "Install launchd plist";
+                       name = "Remove Name Constraints Resources from watchOS";
+                       outputFileListPaths = (
+                       );
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "mkdir -p \"$LAUNCHD_PLIST_LOCATION\"\nplutil -convert binary1 -o \"$LAUNCHD_PLIST_LOCATION/com.apple.securityuploadd.plist\" \"$LAUNCHD_PLIST\"\n";
+                       shellScript = "# see <rdar://66792084>\nif [ \"${PLATFORM_NAME}\" == \"watchos\" ]; then\n    rm -rf \"$DSTROOT/AppleInternal/XCTests/com.apple.security/TrustTests.xctest/si-87-sectrust-name-constraints\"\nfi\n";
                };
-               8E64DB4E1C18A5B80076C9DF /* Install launchd plist */ = {
+               D42D044424734050004E7AA2 /* Install sandbox profile for macOS */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
+                       inputFileListPaths = (
+                       );
                        inputPaths = (
-                               "$(PROJECT_DIR)/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.ios.plist",
-                               "$(PROJECT_DIR)/KVSKeychainSyncingProxy/com.apple.security.cloudkeychainproxy3.osx.plist",
+                               "$(SRCROOT)/supd/com.apple.securityuploadd.sb",
+                       );
+                       name = "Install sandbox profile for macOS";
+                       outputFileListPaths = (
                        );
-                       name = "Install launchd plist";
                        outputPaths = (
-                               "$(INSTALL_ROOT)/$(INSTALL_DAEMON_AGENT_DIR)/com.apple.security.cloudkeychainproxy3.plist",
+                               "$(DSTROOT)/System/Library/Sandbox/Profiles/com.apple.securityuploadd.sb",
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "PLIST_FILE_NAME=com.apple.security.cloudkeychainproxy3\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.ios.plist\n\nif [ ${PLATFORM_NAME} = \"macosx\" ]\nthen\nFILE_TO_COPY=${PROJECT_DIR}/KVSKeychainSyncingProxy/${PLIST_FILE_NAME}.osx.plist\nfi\n\ncp ${FILE_TO_COPY} ${INSTALL_ROOT}/${INSTALL_DAEMON_AGENT_DIR}/${PLIST_FILE_NAME}.plist\n";
+                       shellScript = "if [ \"${PLATFORM_NAME}\" == \"macosx\" ]; then\n    mkdir /System/Library/Sandbox/Profiles\n    cp \"$SRCROOT/supd/com.apple.securityuploadd.sb\" \"$DSTROOT/System/Library/Sandbox/Profiles/com.apple.securityuploadd.sb\"\nfi\n";
                };
                D4428B432122718400EB8448 /* Generate BATS Plist */ = {
                        isa = PBXShellScriptBuildPhase;
                        shellPath = /bin/sh;
                        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";
                };
+               D459364124BFBA700066FB43 /* Install Apple Corporate Roots */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA.cer",
+                               "$(SRCROOT)/trust/trustd/iOS/AppleCorporateRootCA2.cer",
+                       );
+                       name = "Install Apple Corporate Roots";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                               "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA.cer",
+                               "$(DSTROOT)/AppleInternal/Library/Security/AppleCorporateRootCA2.cer",
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       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\n";
+               };
                D4C263C41F8FEAA8001317EA /* Run Script Generate Error Strings */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        shellPath = /bin/sh;
                        shellScript = "if [ ! -h ${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/XPCServices ]; then\n    ln -s Versions/Current/XPCServices ${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}/XPCServices\nfi\n\nexit 0\n";
                };
+               DC2C884D245B4B3E0040CBEB /* Copy Sandbox Profile (macOS only) */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                               "$(SRCROOT)/keychain/TrustedPeersHelper/com.apple.TrustedPeersHelper.sb",
+                       );
+                       name = "Copy Sandbox Profile (macOS only)";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = /bin/sh;
+                       shellScript = "if [ \"$PLATFORM_FAMILY_NAME\" = \"macOS\" ]; then\n    mkdir -p ${INSTALL_ROOT}/System/Library/Sandbox/Profiles/\n    cp ${SRCROOT}/keychain/TrustedPeersHelper/com.apple.TrustedPeersHelper.sb ${INSTALL_ROOT}/System/Library/Sandbox/Profiles/\nfi\n";
+               };
                DC58C4381D77BE5E003C25A4 /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                                DCDB297E1FD8849D00B5D242 /* SFObjCType.m in Sources */,
                                5A061197229ED6EB006AF14A /* NSDate+SFAnalytics.m in Sources */,
                                DCDB297C1FD8848A00B5D242 /* SFSQLite.m in Sources */,
+                               A6C737BD23F37AB20009C930 /* entitlements.c in Sources */,
                                0CA4EBF4202B8DBE002B1D96 /* CloudKitKeychainSyncingTestsBase.m in Sources */,
                                DCDB297D1FD8849A00B5D242 /* SFSQLiteStatement.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 */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               0C9AEEAE20783FBB00BF6237 /* Sources */ = {
+               0CCC220B23F357EE00E1FCD0 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C9AEEAF20783FBB00BF6237 /* SFSignInAnalyticsTests.m in Sources */,
+                               0CCC22A623F3868400E1FCD0 /* OTControl.m in Sources */,
+                               0CCC22CA23F3933000E1FCD0 /* CloudKitKeychainSyncingMockXCTest.m in Sources */,
+                               0CCC22C023F38DA100E1FCD0 /* SecdWatchdog.m in Sources */,
+                               0CCC22B723F38BF500E1FCD0 /* CloudKitMockXCTest.m in Sources */,
+                               0CCC22BB23F38C8800E1FCD0 /* server_entitlement_helpers.c in Sources */,
+                               0CCC22C123F38DC100E1FCD0 /* server_security_helpers.m in Sources */,
+                               0CCC22C923F3932600E1FCD0 /* CloudKitKeychainSyncingTestsBase.m in Sources */,
+                               0CCC22BF23F38D8E00E1FCD0 /* server_endpoint.m in Sources */,
+                               0CCC22B823F38C0E00E1FCD0 /* MockCloudKit.m in Sources */,
+                               0CCC22BE23F38D7C00E1FCD0 /* spi.c in Sources */,
+                               0CCC22B923F38C3000E1FCD0 /* CKKSMockSOSPresentAdapter.m in Sources */,
+                               0C9A54B6250C286100FF007B /* OctagonTrustTests+Errors.m in Sources */,
+                               0CCC22A023F367D100E1FCD0 /* OctagonTrustTests-EscrowRecords.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               0CF406112072E3E3003D6A7F /* Sources */ = {
+               0CD743A223C3EC8000FA0EC5 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0C5663EC20BE2DF30035F362 /* SFSignInAnalytics.m in Sources */,
-                               0CF406522072E422003D6A7F /* SFSignInAnalyticsTests.m in Sources */,
+                               0C468FF623C7D4D5006F4582 /* OTICDPRecordSilentContext.m in Sources */,
+                               0C468FF223C7D4D5006F4582 /* OTEscrowAuthenticationInformation.m in Sources */,
+                               0C468FE423C7D487006F4582 /* OTEscrowRecordMetadata.m in Sources */,
+                               0C9F65AE23E3AD3200B1A2C5 /* OTEscrowTranslation.m in Sources */,
+                               0C468FE623C7D487006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */,
+                               0C79213D23C3F6E100193389 /* OctagonTrust.m in Sources */,
+                               0C468FF023C7D4D5006F4582 /* OTCDPRecoveryInformation.m in Sources */,
+                               0C468FE223C7D487006F4582 /* OTEscrowRecord.m in Sources */,
+                               0C468FF423C7D4D5006F4582 /* OTICDPRecordContext.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                225394CA1E3082D500D3CD9B /* macho++.cpp in Sources */,
                                225394CB1E30831D00D3CD9B /* machorep.cpp in Sources */,
                                225394CC1E30832A00D3CD9B /* sigblob.cpp in Sources */,
+                               A6C737B923F37A480009C930 /* entitlements.c in Sources */,
                                225394CD1E30833400D3CD9B /* resources.cpp in Sources */,
                                225394CE1E30833F00D3CD9B /* cfmunge.cpp in Sources */,
                                225394CF1E30835700D3CD9B /* csutilities.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               3E88360924F068EF00E9F4D6 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               3E88361424F0699F00E9F4D6 /* secseccodeapitest.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                438169081B4EDCBD00C54D58 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                                4718AE44205B39C40068EC3F /* SFKeychainControlManager.m in Sources */,
                                DC3AF52F2229E770006577E8 /* CKKSListenerCollection.m in Sources */,
                                0C29BF2523232897003C807E /* OTDefines.m in Sources */,
+                               6C6AF17F221A07090091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */,
                                4718AE46205B39C40068EC3F /* CKKSIncomingQueueOperation.m in Sources */,
                                4718AE47205B39C40068EC3F /* CKKSOutgoingQueueOperation.m in Sources */,
                                4718AE48205B39C40068EC3F /* CKKSZoneStateEntry.m in Sources */,
                                4718AE4D205B39C40068EC3F /* CKKSLocalSynchronizeOperation.m in Sources */,
                                4718AE4E205B39C40068EC3F /* OTManager.m in Sources */,
                                4718AE50205B39C40068EC3F /* CKKSCurrentKeyPointer.m in Sources */,
+                               DC880F69243D4CE50059806D /* CKKSLogging.m in Sources */,
                                4718AE51205B39C40068EC3F /* CKKSControlServer.m in Sources */,
                                4718AE52205B39C40068EC3F /* CKKSUpdateDeviceStateOperation.m in Sources */,
                                4718AE53205B39C40068EC3F /* SecDbKeychainSerializedMetadata.m in Sources */,
                                6C4AEF89218A09E80012C5DA /* CheckV12DevEnabled.m in Sources */,
                                4718AE81205B39C40068EC3F /* SecDbKeychainSerializedSecretData.m in Sources */,
                                4718AE82205B39C40068EC3F /* CKKSKeychainView.m in Sources */,
+                               FC637231237B5D2200973738 /* SecItemServer+SWC.m in Sources */,
                                4718AE83205B39C40068EC3F /* SecuritydXPC.c in Sources */,
                                4718AE84205B39C40068EC3F /* SecDbKeychainSerializedItemV7.m in Sources */,
                                4718AE86205B39C40068EC3F /* CKKSProcessReceivedKeysOperation.m in Sources */,
                                4718AE96205B39C40068EC3F /* CKKSZoneChangeFetcher.m in Sources */,
                                4718AE97205B39C40068EC3F /* CKKSCondition.m in Sources */,
                                EB0E1ACE2353A704002B6037 /* CKKSPBFileStorage.m in Sources */,
-                               4718AE98205B39C40068EC3F /* CKKSZone.m in Sources */,
                                4718AE99205B39C40068EC3F /* SFKeychainServer.m in Sources */,
                                4718AE9B205B39C40068EC3F /* swcagent_client.c in Sources */,
                                DC5A01EB21BB428500D87AB9 /* CKKSTLKShare.m in Sources */,
                                477A1FED2037A0E000ACD81D /* KeychainXCTest.m in Sources */,
                                4727FBEB1F99227F0003AE36 /* spi.c in Sources */,
                                4727FBEC1F99235B0003AE36 /* SecdWatchdog.m in Sources */,
+                               6CD8412C23F5D871003DDF34 /* KeychainBackupTests.m in Sources */,
                                4764E9272059D866005497C9 /* KeychainModel.xcdatamodeld in Sources */,
+                               6C6B3ADF23F1B3E0002827C2 /* KeychainAppClipTests.m in Sources */,
                                4727FBBA1F9918590003AE36 /* KeychainCryptoTests.m in Sources */,
                                6C9791C921C2EAB60074C609 /* NSError+UsefulConstructors.m in Sources */,
+                               6C912AA1227A3E9700671FC6 /* CheckV12DevEnabled.m in Sources */,
                                477A1FE4203763A500ACD81D /* KeychainAPITests.m in Sources */,
                                4727FBED1F99249A0003AE36 /* server_endpoint.m in Sources */,
-                               096C647020AB1BC700D7B7D5 /* KeychainEntitlementsTest.m in Sources */,
+                               6C6B3AC623F1A820002827C2 /* KeychainEntitlementsTest.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               478D42751FD72A8100CAB645 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               478D42761FD72A8100CAB645 /* server_xpc.m in Sources */,
-                               4764E92D2059D8BF005497C9 /* KeychainModel.xcdatamodeld in Sources */,
-                               478D42771FD72A8100CAB645 /* server_security_helpers.m in Sources */,
-                               478D42781FD72A8100CAB645 /* server_entitlement_helpers.c in Sources */,
-                               477A1FEE2037A0E000ACD81D /* KeychainXCTest.m in Sources */,
-                               09BFE35C20A32E0E008511E9 /* KeychainEntitlementsTest.m in Sources */,
-                               478D42791FD72A8100CAB645 /* spi.c in Sources */,
-                               478D427A1FD72A8100CAB645 /* SecdWatchdog.m in Sources */,
-                               6C9791CA21C2EAB70074C609 /* NSError+UsefulConstructors.m in Sources */,
-                               478D427B1FD72A8100CAB645 /* KeychainCryptoTests.m in Sources */,
-                               477A1FE5203763A500ACD81D /* KeychainAPITests.m in Sources */,
-                               478D427C1FD72A8100CAB645 /* server_endpoint.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                47C2F17F2059CB680062DE30 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                                6CAA8CFF1F83E800007B6E03 /* SFSQLite.m in Sources */,
                                6CDB5FF61FA78D1B00410924 /* SFAnalyticsMultiSampler.m in Sources */,
-                               0CBFEACB200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */,
                                5A06118E229ED5EB006AF14A /* NSDate+SFAnalytics.m in Sources */,
                                0C8884012154C4E80053224D /* OTJoiningConfiguration.m in Sources */,
-                               0CBD55B31FE883F200A8CE21 /* SFBehavior.m in Sources */,
                                6C814A4D2050B4B600CB391B /* LocalKeychainAnalytics.m in Sources */,
                                220179E91E3BF03200EFB6F3 /* dummy.cpp in Sources */,
                                5A442FA9233C351000918373 /* SecExperiment.m in Sources */,
                                DC3AA2862097E22A007CA68A /* codesign.c in Sources */,
                                DC8506AC2097EEBA00C712EC /* sos.m in Sources */,
                                E78A9ADA1D34959200006B5B /* NSFileHandle+Formatting.m in Sources */,
+                               BE57B1192509E1000045B7FD /* ca_revocation_additions.m in Sources */,
                                DC3AA28A2097E23B007CA68A /* keychain_find.m in Sources */,
                                DC3AA2782097DF70007CA68A /* readline.c in Sources */,
                                DC3AA2812097E216007CA68A /* add_internet_password.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               6C2045E62424BA7E00F9461D /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               6C2045F12424BAC900F9461D /* main.m in Sources */,
+                               6C2045F22424BACE00F9461D /* KeychainStasher.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                6C39234D21F13E4D00D018AD /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               6CD224E623949132001B70FD /* SecDbBackupTestsBase.m in Sources */,
+                               6C912AA0227A3E9600671FC6 /* CheckV12DevEnabled.m in Sources */,
                                6C39237B21F13EB400D018AD /* SecDbBackupManager.m in Sources */,
                                6C39237C21F13EB400D018AD /* SecDbBackupBag.m in Sources */,
                                6C39237D21F13EB400D018AD /* SecDbBackupBagIdentity.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6C98083D1E788AEB00E70590 /* Sources */ = {
+               6C7BE2B623C3DD64003BB2CA /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               6CBF65431FA2257100A68667 /* SFAnalyticsActivityTracker.m in Sources */,
-                               6CAA8CF71F83E79E007B6E03 /* SFSQLite.m in Sources */,
-                               476541A41F33EDED00413F65 /* SecdWatchdog.m in Sources */,
-                               47B011991F17D78D0030B49F /* SFSQLiteStatement.m in Sources */,
-                               DC2D438F1F0EEC2A0005D382 /* MockCloudKit.m in Sources */,
-                               6CDF8DEF1F96495600140B54 /* SFAnalyticsSampler.m in Sources */,
-                               DCB515E21ED3D134001F1152 /* SecTask.c in Sources */,
-                               DCB515E11ED3D11A001F1152 /* client.c in Sources */,
-                               6C9808A61E788CD200E70590 /* CKKSCloudKitTests.m in Sources */,
-                               6C98083E1E788AEB00E70590 /* spi.c in Sources */,
-                               5A061192229ED6E5006AF14A /* NSDate+SFAnalytics.m in Sources */,
-                               DC2353301ECA658900D7C1BE /* server_security_helpers.m in Sources */,
-                               6CAA8CF01F83E65E007B6E03 /* SFObjCType.m in Sources */,
-                               6CAA8D131F83ECD4007B6E03 /* SFAnalytics.m in Sources */,
-                               DC2353321ECA659000D7C1BE /* server_xpc.m in Sources */,
-                               6CDB5FF91FA78D2400410924 /* SFAnalyticsMultiSampler.m in Sources */,
-                               DC5F35B11EE0F28B00900966 /* server_entitlement_helpers.c in Sources */,
-                               DC2353291ECA658300D7C1BE /* server_endpoint.m in Sources */,
-                               6CAA8CF91F83E7AA007B6E03 /* SFAnalyticsSQLiteStore.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
-               6C9808791E788AFD00E70590 /* Sources */ = {
+                               6C7BE2B823C3DD64003BB2CA /* SecurityTool.c in Sources */,
+                               6C7BE2B923C3DD64003BB2CA /* scep.c in Sources */,
+                               6C7BE2BA23C3DD64003BB2CA /* trust_update.m in Sources */,
+                               6C7BE2BB23C3DD64003BB2CA /* keychain_backup.c in Sources */,
+                               6C7BE2BC23C3DD64003BB2CA /* whoami.m in Sources */,
+                               6C7BE2BE23C3DD64003BB2CA /* KeychainCheck.m in Sources */,
+                               6C7BE2BF23C3DD64003BB2CA /* log_control.c in Sources */,
+                               6C7BE2C023C3DD64003BB2CA /* not_on_this_platorm.c in Sources */,
+                               6C7BE2C123C3DD64003BB2CA /* keychain_util.c in Sources */,
+                               6C7BE2C223C3DD64003BB2CA /* security_tool_commands.c in Sources */,
+                               6C7BE2C323C3DD64003BB2CA /* codesign.c in Sources */,
+                               6C7BE2C523C3DD64003BB2CA /* NSFileHandle+Formatting.m in Sources */,
+                               6C7BE2C623C3DD64003BB2CA /* keychain_find.m in Sources */,
+                               6C7BE2C723C3DD64003BB2CA /* readline.c in Sources */,
+                               6C7BE2C823C3DD64003BB2CA /* add_internet_password.c in Sources */,
+                               6C7BE2C923C3DD64003BB2CA /* digest_calc.c in Sources */,
+                               6C7BE2CA23C3DD64003BB2CA /* leaks.c in Sources */,
+                               6C7BE2CB23C3DD64003BB2CA /* show_certificates.c in Sources */,
+                               6C7BE2CC23C3DD64003BB2CA /* spc.c in Sources */,
+                               6C7BE2CD23C3DD64003BB2CA /* verify_cert.c in Sources */,
+                               6C7BE2CE23C3DD64003BB2CA /* ct_exceptions.m in Sources */,
+                               BE57B1182509E1000045B7FD /* ca_revocation_additions.m in Sources */,
+                               6C7BE2CF23C3DD64003BB2CA /* keychain_add.c in Sources */,
+                               6C7BE2D023C3DD64003BB2CA /* pkcs12_util.c in Sources */,
+                               6C7BE2D123C3DD64003BB2CA /* print_cert.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               6C96327D242A279B00C53CE2 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               6CAA8CF61F83E79D007B6E03 /* SFSQLite.m in Sources */,
-                               6CDB5FF81FA78D2300410924 /* SFAnalyticsMultiSampler.m in Sources */,
-                               5A061193229ED6E6006AF14A /* NSDate+SFAnalytics.m in Sources */,
-                               476541A51F33EE1E00413F65 /* SecdWatchdog.m in Sources */,
-                               DC2D43951F0EEC300005D382 /* MockCloudKit.m in Sources */,
-                               6CAA8CF81F83E7A9007B6E03 /* SFAnalyticsSQLiteStore.m in Sources */,
-                               6C9808A51E788CD100E70590 /* CKKSCloudKitTests.m in Sources */,
-                               6CBF65441FA2257200A68667 /* SFAnalyticsActivityTracker.m in Sources */,
-                               DCB515E31ED3D135001F1152 /* SecTask.c in Sources */,
-                               6CAA8CEF1F83E65D007B6E03 /* SFObjCType.m in Sources */,
-                               DCB515E01ED3D111001F1152 /* client.c in Sources */,
-                               DCB515E41ED3D15A001F1152 /* client_endpoint.m in Sources */,
-                               6CAA8D141F83ECD5007B6E03 /* SFAnalytics.m in Sources */,
-                               6C98087A1E788AFD00E70590 /* spi.c in Sources */,
-                               6CAA8D0D1F83EC57007B6E03 /* SFSQLiteStatement.m in Sources */,
-                               DC5F35B21EE0F28C00900966 /* server_entitlement_helpers.c in Sources */,
-                               DC2353311ECA658B00D7C1BE /* server_security_helpers.m in Sources */,
-                               DC2353331ECA659000D7C1BE /* server_xpc.m in Sources */,
-                               DC23532F1ECA658400D7C1BE /* server_endpoint.m in Sources */,
-                               6CDF8DF01F96495700140B54 /* SFAnalyticsSampler.m in Sources */,
+                               6C963284242A279B00C53CE2 /* main.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               6CF4A0DC1E4549F200ECD7B5 /* Sources */ = {
-                       isa = PBXSourcesBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               6CF4A0EA1E4549F300ECD7B5 /* ViewController.m in Sources */,
-                               6CF4A0E71E4549F300ECD7B5 /* AppDelegate.m in Sources */,
-                               6CF4A0E41E4549F200ECD7B5 /* main.m in Sources */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                790851B30CA9859F0083CC4D /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C468FF823C7D4E3006F4582 /* OTEscrowRecordMetadata.m in Sources */,
                                0CE15E2F222DF63600B7EAA5 /* SetValueTransformer.swift in Sources */,
                                0CE15E2C222DF63600B7EAA4 /* RecoveryKey.swift in Sources */,
                                0CE15E43222DF6A800B7EAA4 /* Recovery.m in Sources */,
                                DC391F8D21BF244000772585 /* CKKSSIV.m in Sources */,
                                0CE15E30222DF63600B7EAA4 /* RecoverKeySet.swift in Sources */,
                                0C3BB3582188E18C0018FC14 /* OTPrivateKey+SF.m in Sources */,
+                               0C468FF723C7D4E3006F4582 /* OTEscrowRecord.m in Sources */,
                                BECFA43D20F9493000B11002 /* Policy.swift in Sources */,
                                0CB582D1218920090040C5F2 /* OTAuthenticatedCiphertext.m in Sources */,
                                0CF70BD9218BED1000EC3515 /* CuttlefishExtensionWorkaround.swift in Sources */,
                                DCAA209C23AAF93700DCB594 /* Container_RecoveryKey.swift in Sources */,
                                BE9F8D19206C4AD300B53D16 /* ContainerMap.swift in Sources */,
                                BE9F4F8C2072D881004A52C2 /* Cuttlefish.pb.swift in Sources */,
+                               DC9978B82404AA3200A5EE2F /* Container_UserSync.swift in Sources */,
                                DC391F9D21BF2F8100772585 /* CKKSConstants.m in Sources */,
                                BE9F8D10206C099800B53D16 /* Container.swift in Sources */,
                                0CB582D3218920090040C5F2 /* OTPrivateKey.m in Sources */,
                                DCAD8F8622C43EC1007C3872 /* Container_MachineIDs.swift in Sources */,
                                DCB0C295222F5EF60083AECB /* CuttlefishErrors.swift in Sources */,
                                0CB582D021891FF40040C5F2 /* OTBottle.m in Sources */,
+                               DC880F6B243D4D730059806D /* CKKSLogging.m in Sources */,
                                0C0C4F86216FB73C00C14C61 /* EscrowKeys.swift in Sources */,
                                DCB9475621274A1900ED9272 /* TPHObjcTranslation.m in Sources */,
                                0C3BB35A2188E18C0018FC14 /* OTAuthenticatedCiphertext+SF.m in Sources */,
+                               0C468FF923C7D4E3006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */,
+                               0C0CB73923AD714D0020C6BF /* Container_EscrowRecords.swift in Sources */,
                                0CE15E3E222DF6A800B7EAA4 /* OTRecovery.m in Sources */,
                                DC391F8E21BF274600772585 /* CKKSPeer.m in Sources */,
                                DC391F8A21BF222500772585 /* CKKSKeychainBackedKey.m in Sources */,
                                0C0C4F87216FB73F00C14C61 /* BottledPeer.swift in Sources */,
+                               0C3DF8C824789C3C009CF03A /* Container_Peers.swift in Sources */,
                                0CB582D2218920090040C5F2 /* OTBottleContents.m in Sources */,
                                DC391F8F21BF284D00772585 /* CKKSSerializedKey.m in Sources */,
                                BEC0A96420B362EC00DBD772 /* Utils.swift in Sources */,
                                0CA4B4722171410200B17169 /* EscrowKeys.swift in Sources */,
                                BE536030209BC1FD0027E25A /* spi.c in Sources */,
                                BEA8558120B5DC7D00D5AD11 /* FakeCuttlefish.swift in Sources */,
+                               DC9978BB2404B26900A5EE2F /* Container_UserSync.swift in Sources */,
                                0CB5C678218B803C0044F730 /* OTPrivateKey+SF.m in Sources */,
                                DC05035E214083B200A8EDB7 /* TPHObjcTranslation.m in Sources */,
                                0CE15E41222DF6A800B7EAA4 /* OTRecovery.m in Sources */,
                                BE536031209BC2F90027E25A /* SecdWatchdog.m in Sources */,
                                0CB582C82189157F0040C5F2 /* OTAuthenticatedCiphertext.m in Sources */,
+                               0C468FFC23C7D4EF006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */,
                                BED987E320991C4D00607A5F /* MockCuttlefish.swift in Sources */,
                                BEC373D020D87B4D00DBDF5B /* SecFramework.c in Sources */,
                                0CB582CA2189157F0040C5F2 /* OTBottleContents.m in Sources */,
+                               0C3DF8C924789D06009CF03A /* Container_Peers.swift in Sources */,
                                BE536032209BC3250027E25A /* server_endpoint.m in Sources */,
                                BE536034209BC3C40027E25A /* server_security_helpers.m in Sources */,
                                BECFA43E20F9493000B11002 /* Policy.swift in Sources */,
                                0CA2282F2187A5CA00A1C56C /* BottledPeer.swift in Sources */,
+                               DC880F6A243D4D640059806D /* CKKSLogging.m in Sources */,
                                DC747993222720C8001E0E8C /* MockCloudKit.m in Sources */,
                                0CB5C677218B803C0044F730 /* OTAuthenticatedCiphertext+SF.m in Sources */,
                                BE727824209CBCA800F0DA77 /* Cuttlefish.pb.swift in Sources */,
                                BE536033209BC3B30027E25A /* server_entitlement_helpers.c in Sources */,
                                DCAA209B23AAF8FD00DCB594 /* Container_RecoveryKey.swift in Sources */,
                                BED987E020991B1100607A5F /* TrustedPeersHelper.xcdatamodeld in Sources */,
+                               0C468FFA23C7D4EF006F4582 /* OTEscrowRecord.m in Sources */,
                                BED987D62099145300607A5F /* TrustedPeersHelperUnitTests.swift in Sources */,
                                BE4C6AB820CAF4F700EAD6BE /* ContainerSync.swift in Sources */,
                                0CE15E46222DF6A800B7EAA4 /* Recovery.m in Sources */,
                                0CE15E33222DF63600B7EAA4 /* RecoverKeySet.swift in Sources */,
                                0CE15E2F222DF63600B7EAA4 /* RecoveryKey.swift in Sources */,
+                               0C468FFB23C7D4EF006F4582 /* OTEscrowRecordMetadata.m in Sources */,
                                DCF6320721C075210030CCC0 /* CuttlefishAPIHelpers.swift in Sources */,
+                               0C0CB73B23AD71650020C6BF /* Container_EscrowRecords.swift in Sources */,
                                BED987DE2099156B00607A5F /* Container.swift in Sources */,
                                DCB0C292222F5E1D0083AECB /* CuttlefishErrors.swift in Sources */,
                                BECFA44320FD0A4B00B11002 /* LocalKeychainAnalytics.m in Sources */,
                                DCE0776A21ADD71C002662FD /* TPPBPeerDynamicInfo.m in Sources */,
                                DCE0776C21ADD71C002662FD /* TPPBPolicySecret.m in Sources */,
                                DCE0776E21ADD71C002662FD /* TPPBPeerStableInfo.m in Sources */,
+                               DCC03FA523FF521100A4DA3F /* TPSyncingPolicy.m in Sources */,
                                DCE0777021ADD71C002662FD /* TPPBVoucher.m in Sources */,
                                DCE0777221ADD71C002662FD /* TPPBPolicyDocument.m in Sources */,
                                DCE0777421ADD71C002662FD /* TPPBPolicyCategoriesByView.m in Sources */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               D49A370723873BD30065719F /* TrustDaemonTestCase.m in Sources */,
-                               D49A370423873A580065719F /* RevocationTests.m in Sources */,
+                               D477CB83237F692400C02355 /* RevocationTests.m in Sources */,
                                D40881F5217573C900180E81 /* SecTrustStatusCodes.c in Sources */,
                                D4FD421D217D789C002B7EE2 /* NameConstraintsTests.m in Sources */,
                                D4FD4221217D7B2E002B7EE2 /* PathScoringTests.m in Sources */,
+                               D477CB88237F8B2F00C02355 /* CAIssuerTests.m in Sources */,
                                D40881F42175738C00180E81 /* SecPolicyLeafCallbacks.c in Sources */,
                                D40881F32175733F00180E81 /* SecPolicy.c in Sources */,
                                D477CB7C237E4BD700C02355 /* ExceptionTests.m in Sources */,
                                D40881F22175733500180E81 /* SecSignatureVerificationSupport.c in Sources */,
                                D40881F12175732E00180E81 /* SecCertificate.c in Sources */,
                                D40881F02175732600180E81 /* SecTrustStore.c in Sources */,
+                               D477CB90237F975500C02355 /* ValidTests.m in Sources */,
                                D40881EF2175731E00180E81 /* SecTrust.c in Sources */,
                                D458C523214E33380043D982 /* KeySizeTests.m in Sources */,
+                               D477CB8C237F8DBC00C02355 /* AllowlistBlocklistTests.m in Sources */,
                                D458C4BD214E19AF0043D982 /* SignatureAlgorithmTests.m in Sources */,
+                               D477CB6B237CBA2C00C02355 /* TrustDaemonTestCase.m in Sources */,
                                D458C4B1214E198F0043D982 /* CTTests.m in Sources */,
                                D458C4B9214E19AF0043D982 /* PathParseTests.m in Sources */,
                                D458C516214E286D0043D982 /* PolicyTests.m in Sources */,
                                D453A4AD2122236D00850A26 /* TrustFrameworkTestCase.m in Sources */,
                                D49A370D23877ECC0065719F /* OCSPCacheTests.m in Sources */,
                                D4EA5CF922B225D100883439 /* LoggingServerTests.m in Sources */,
+                               D458DAC42375FEA300E5890E /* TrustSettingsTests.m in Sources */,
                                D4056A1B22712A650026E24E /* SSLPolicyTests.m in Sources */,
                                D458C4C4214E19FC0043D982 /* TrustInterfaceTests.m in Sources */,
                                D453A4AF2122236D00850A26 /* CertificateInterfaceTests.m in Sources */,
                                D458C4C2214E19FC0043D982 /* TrustSettingsInterfaceTests.m in Sources */,
+                               D423114423725F9F000E470A /* SMIMEPolicyTests.m in Sources */,
+                               D477CB5D237B6E0E00C02355 /* PersonalizationTests.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D477CB6A237CBA2C00C02355 /* TrustDaemonTestCase.m in Sources */,
                                D49A370C23877ECC0065719F /* OCSPCacheTests.m in Sources */,
                                D40881FA217573F800180E81 /* SecPolicy.c in Sources */,
+                               D477CB8B237F8DBC00C02355 /* AllowlistBlocklistTests.m in Sources */,
                                D40881FB217573F800180E81 /* SecPolicyLeafCallbacks.c in Sources */,
                                D40881F9217573EF00180E81 /* SecSignatureVerificationSupport.c in Sources */,
                                D40881F8217573E700180E81 /* SecCertificate.c in Sources */,
                                D4FD4220217D7B2E002B7EE2 /* PathScoringTests.m in Sources */,
                                D458C4BC214E19AF0043D982 /* SignatureAlgorithmTests.m in Sources */,
                                D4FD421C217D789C002B7EE2 /* NameConstraintsTests.m in Sources */,
+                               D477CB5C237B6E0E00C02355 /* PersonalizationTests.m in Sources */,
                                D4A0F8CC211E6A8300443CA1 /* TrustEvaluationTestCase.m in Sources */,
+                               D477CB87237F8B2F00C02355 /* CAIssuerTests.m in Sources */,
                                D4A0F8C7211E6A5800443CA1 /* TrustFrameworkTestCase.m in Sources */,
                                D458C4C3214E19FC0043D982 /* TrustInterfaceTests.m in Sources */,
                                D4AC8BE821320AD0006E9871 /* CertificateParseTests.m in Sources */,
                                D4A0F8C8211E6A5800443CA1 /* CertificateInterfaceTests.m in Sources */,
+                               D423114323725F9F000E470A /* SMIMEPolicyTests.m in Sources */,
                                D458C4B0214E198F0043D982 /* CTTests.m in Sources */,
+                               D477CB8F237F975500C02355 /* ValidTests.m in Sources */,
                                D458C4B2214E198F0043D982 /* EvaluationBasicTests.m in Sources */,
-                               D49A370323873A580065719F /* RevocationTests.m in Sources */,
+                               D477CB82237F692400C02355 /* RevocationTests.m in Sources */,
                                D458C4BA214E19AF0043D982 /* iAPTests.m in Sources */,
                                D458C4B8214E19AF0043D982 /* PathParseTests.m in Sources */,
                                D458C525214E33440043D982 /* VerifyDateTests.m in Sources */,
-                               D49A370623873BD30065719F /* TrustDaemonTestCase.m in Sources */,
                                D458C515214E286C0043D982 /* PolicyTests.m in Sources */,
+                               D458DAC32375FEA300E5890E /* TrustSettingsTests.m in Sources */,
                                D477CB7B237E4BD700C02355 /* ExceptionTests.m in Sources */,
                                D4EF32182156DDEB000A31A5 /* TrustSettingsInterfaceTests.m in Sources */,
                                D44282FF22D68564001746B3 /* TrustEvaluationTestHelpers.m in Sources */,
                                DC0BC7A21D8B773000070CB0 /* cssmcontext.cpp in Sources */,
                                DC0BC7B21D8B773000070CB0 /* oidsalg.c in Sources */,
                                DC0BC7AA1D8B773000070CB0 /* modload_plugin.cpp in Sources */,
+                               6C97434A24D1C8DE00A2025C /* LegacyAPICounts.m in Sources */,
                                DC0BC7B41D8B773000070CB0 /* oidscrl.cpp in Sources */,
                                DC0BC79B1D8B773000070CB0 /* attachfactory.cpp in Sources */,
                                DC0BC7A51D8B773000070CB0 /* cssmmds.cpp in Sources */,
                                DC0BCD961D8C6A1E00070CB0 /* der_dictionary.c in Sources */,
                                DC0BCD751D8C6A1E00070CB0 /* iCloudKeychainTrace.c in Sources */,
                                DC0BCD821D8C6A1E00070CB0 /* SecCFWrappers.c in Sources */,
-                               EB4B6E201DC0682A00AFC494 /* SecADWrapper.c in Sources */,
                                DC0BCD941D8C6A1E00070CB0 /* der_date.c in Sources */,
                                DC0BCD9F1D8C6A1F00070CB0 /* fileIo.c in Sources */,
                                DC0BCDA81D8C6A1F00070CB0 /* SecFileLocations.c in Sources */,
                                DC74799A222722BC001E0E8C /* CKKSKeychainBackedKey.m in Sources */,
                                DC747999222722B2001E0E8C /* CKKSConstants.m in Sources */,
                                DC7479982227229D001E0E8C /* CKKSTLKShare.m in Sources */,
+                               DC880F6C243D4DC00059806D /* CKKSLogging.m in Sources */,
                                DC0EF8F2208697C600AB9E95 /* main.swift in Sources */,
                                EB7ECF9623467FB400CE2D3C /* Cuttlefish.pb.swift in Sources */,
                                DCD48BFE20BF3D83009A3224 /* tpctl-objc.m in Sources */,
                        buildActionMask = 2147483647;
                        files = (
                                DC2B757621F2A270003C9356 /* SecEscrowRequest.m in Sources */,
+                               BE7B8E142415579900E1CF4F /* SecSharedCredential.m in Sources */,
                                0C84D8381FCF43BF00B822E3 /* OTControlProtocol.m in Sources */,
                                DCC585FF20BF8A7E005C7269 /* SecFramework.c in Sources */,
                                DCA85B991E8D980B00BA7241 /* client_endpoint.m in Sources */,
                                6CDB5FF51FA78D1A00410924 /* SFAnalyticsMultiSampler.m in Sources */,
                                DCA85B941E8D97E400BA7241 /* client.c in Sources */,
                                DCDF0A4F1D81D76F007AF174 /* Security.exp-in in Sources */,
-                               0CBFEACA200FCD2D009A60E9 /* SFSignInAnalytics.m in Sources */,
                                DC1789A51D779E3B00B50D50 /* dummy.cpp in Sources */,
                                5A061191229ED6DB006AF14A /* NSDate+SFAnalytics.m in Sources */,
                                EB9B285821C77C8D00173DC2 /* OTDefines.m in Sources */,
                                6CAA8CFE1F83E800007B6E03 /* SFSQLite.m in Sources */,
                                DC9C95C01F79DC89000D19E5 /* CKKSControl.m in Sources */,
                                5AF594001FA0EE5300A5C1EC /* SecProtocol.c in Sources */,
+                               BE7B8E152415580D00E1CF4F /* SecSharedCredential.c in Sources */,
                                5A442FAA233C351100918373 /* SecExperiment.m in Sources */,
                                0C8884042154C4EA0053224D /* OTJoiningConfiguration.m in Sources */,
                                0C0E60E020D033E400E654F2 /* OTControl.m in Sources */,
                                6CE3654D1FA100E50012F6AB /* SFAnalytics.m in Sources */,
                                5A7E037A22272E0E003DB3A0 /* SecProtocolHelper.m in Sources */,
                                6CAA8CFD1F83E7EB007B6E03 /* SFObjCType.m in Sources */,
-                               DC1789A21D779DF400B50D50 /* SecBreadcrumb.c in Sources */,
                                78ADC62C1FA0FACE001EB8B6 /* SecProtocolTypes.m in Sources */,
-                               0CE079F41FEA15B20040A3F1 /* SFBehavior.m in Sources */,
                                6CBF65411FA1481100A68667 /* SFAnalyticsActivityTracker.m in Sources */,
                                0CD9E34623592EA7002995DE /* OctagonSignPosts.m in Sources */,
                        );
                                DC9C98C722E264F30021E29F /* CKKSFetchTests.m in Sources */,
                                EB0E1ADA2357627F002B6037 /* CKKSPBFileStorageTests.m in Sources */,
                                DC9C75161E4BCE1800F1CA0D /* CKKSOperationTests.m in Sources */,
+                               DC86122C2408AC190092E93B /* CKKSTests+ItemSyncChoice.m in Sources */,
                                DC8D238D2064649400E163C8 /* CKKSAPSHandlingTests.m in Sources */,
                                EBC1024422EBF93E0083D356 /* CKKSTests+LockStateTracker.m in Sources */,
                                DCB221561E8B08BF001598BC /* server_xpc.m in Sources */,
                                DC4268FE1E820371002B7110 /* server_endpoint.m in Sources */,
                                DC752F1921C1B69C00216089 /* SFSQLite.m in Sources */,
                                DCFE1C3D1F17EFB5007640C8 /* CKKSConditionTests.m in Sources */,
+                               DCBA6F2924105399009A5187 /* CKKSTests+ForwardCompatibility.m in Sources */,
                                DCCD33C91E3FE95900AA4AD1 /* spi.c in Sources */,
                                DC5B391720C08B38005B09F6 /* SecFramework.c in Sources */,
                                DC9C95971F748D0B000D19E5 /* CKKSServerValidationRecoveryTests.m in Sources */,
                                DC7341FE1F84642C00AB9BDF /* CKKSTLKSharingEncryptionTests.m in Sources */,
                                DC5F35AC1EE0F27900900966 /* server_entitlement_helpers.c in Sources */,
                                DAEE055C1FAD3FC700DF27F3 /* AutoreleaseTest.c in Sources */,
+                               A6C737BB23F37AB00009C930 /* entitlements.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                1BB1CAB7232C05BD001D0C71 /* CuttlefishXPCWrapper.m in Sources */,
+                               DC6E02162405DE3900C61335 /* OTModifyUserControllableViewStatusOperation.m in Sources */,
                                1BB1CAB8232C05BD001D0C71 /* CuttlefishXPCWrapper.h in Sources */,
                                DCE0778021ADEC4B002662FD /* CKKSSerializedKey.m in Sources */,
                                DCE0777F21ADEC07002662FD /* OTAccountMetadataClassC.m in Sources */,
                                0C00FC86217A980100C8BF00 /* OTLocalCuttlefishReset.m in Sources */,
                                DCAE1DDD2073FDCC00B4F687 /* NSError+UsefulConstructors.m in Sources */,
                                6C4AEF88218A09E70012C5DA /* CheckV12DevEnabled.m in Sources */,
+                               DCC40B122383786D00402CB9 /* CKKSStates.m in Sources */,
                                DC797E1A1DD3F9A400CC9E42 /* CKKSSQLDatabaseObject.m in Sources */,
                                6CC1859F1E24E8EB009657D8 /* CKKSRateLimiter.m in Sources */,
                                DCD33D7C220B99CC000A390B /* EscrowRequestController.m in Sources */,
                                DC54DD0F1EA7D9E700108E92 /* CKKSManifestLeafRecord.m in Sources */,
                                DCDCCB901DF7B8D4006E840E /* CKKSItem.m in Sources */,
                                DC1ED8C11DD5197E002BDCFA /* CKKSItemEncrypter.m in Sources */,
+                               DCB55176247F48290009A859 /* CKKSDeleteCKZoneOperation.m in Sources */,
                                0CDD6F79226E83F6009094C2 /* OTTriggerEscrowUpdateOperation.m in Sources */,
                                DC0D16072363BAF4007F0951 /* OTDetermineCDPBitStatusOperation.m in Sources */,
                                DC6D2C921DD2835A00BE372D /* CKKSOutgoingQueueEntry.m in Sources */,
                                6C880FC821C3351400D38D66 /* SecDbBackupBag.m in Sources */,
                                0C87D3D9229326AA007853B5 /* OTEnsureOctagonKeyConsistency.m in Sources */,
                                6C588D801EAA20AB00D7E322 /* RateLimiter.m in Sources */,
+                               DCB55177247F483D0009A859 /* CKKSCreateCKZoneOperation.m in Sources */,
                                DC8DF6DC212F8A7C007B3FE8 /* OTSOSAdapter.m in Sources */,
                                0C66046A2134983900BFBBB8 /* OTEstablishOperation.m in Sources */,
                                DC15F7681E67A6F6003B9A40 /* CKKSHealKeyHierarchyOperation.m in Sources */,
                                DCE278DF1ED789EF0083B485 /* CKKSCurrentItemPointer.m in Sources */,
+                               DC061A722462136F0026ADB3 /* CKKSOperationDependencies.m in Sources */,
                                DC3D748E1FD2217900AC57DA /* CKKSLocalSynchronizeOperation.m in Sources */,
                                DCC67E2F20DDC07900A70A31 /* OTPrepareOperation.m in Sources */,
                                DCB41DFC216D5E5B00F219E0 /* OTAccountMetadataClassC+KeychainSupport.m in Sources */,
                                DC762AA01E57A86A00B03A2C /* CKKSRecordHolder.m in Sources */,
                                DC52E7DF1D80BD8700B0A59C /* SOSChangeTracker.c in Sources */,
                                DCD33D94220CFF8A000A390B /* EscrowRequestPerformEscrowEnrollOperation.m in Sources */,
+                               DC947E8524638320005B8669 /* CKKSCheckKeyHierarchyOperation.m in Sources */,
                                DC1DA6681E4555D80094CE7F /* CKKSScanLocalItemsOperation.m in Sources */,
                                0CC8A9032123AF06005D7F6A /* OTJoinWithVoucherOperation.m in Sources */,
+                               DC061A71246213660026ADB3 /* CKKSLocalResetOperation.m in Sources */,
                                DC18F7711E43E116006B8B43 /* CKKSFetchAllRecordZoneChangesOperation.m in Sources */,
                                DC45D43E22EB619D00CEB6B7 /* OctagonStateMachineObservers.m in Sources */,
                                DC2C5F601F0EB97E00FEBDA7 /* CKKSNotifier.m in Sources */,
                                DC7250382296056000493D88 /* OTResetCKKSZonesLackingTLKsOperation.m in Sources */,
                                DC221BAC2267E2A70068DBCF /* OTUpdateTPHOperation.m in Sources */,
                                DC93F02A22387A010072720A /* OTSOSUpdatePreapprovalsOperation.m in Sources */,
+                               DC880F68243D4CC00059806D /* CKKSLogging.m in Sources */,
                                6C4AEF90218A0C170012C5DA /* SecDbBackupManager.m in Sources */,
                                DC5060ED20E2D88300925005 /* OTCuttlefishContext.m in Sources */,
                                DC0FA6B12291F63F00FE01C4 /* OctagonPendingFlag.m in Sources */,
                                DC52E7CB1D80BCD800B0A59C /* SecItemBackupServer.c in Sources */,
                                0C2F337220DD64930031A92D /* OTRamping.m in Sources */,
                                DCF12674218A757A000124C6 /* OTLeaveCliqueOperation.m in Sources */,
+                               FC63722F237B5D1C00973738 /* SecItemServer+SWC.m in Sources */,
                                DC52E7CD1D80BCE700B0A59C /* SecItemDataSource.c in Sources */,
                                0C8FD52521483EF20098E3FB /* OT.m in Sources */,
                                DC9C066B2149DFE400C6F7B8 /* OTAuthKitAdapter.m in Sources */,
                                DCB837321ED5045000015C07 /* CKKSLockStateTracker.m in Sources */,
                                EB80DE162195EDA4005B10FA /* SecC2DeviceInfo.m in Sources */,
                                47922D4C1FAA7C4A0008F7E0 /* SecDbKeychainSerializedSecretData.m in Sources */,
+                               6C6AF180221A070A0091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */,
                                DCBDB3B71E57C82300B61300 /* CKKSKeychainView.m in Sources */,
                                DC52E7D61D80BD2800B0A59C /* SecuritydXPC.c in Sources */,
                                0C4F4DE221153E9E007F7E20 /* OTEpochOperation.m in Sources */,
                                6C4AEF96218A127F0012C5DA /* SecDbKeychainMetadataKeyStore.m in Sources */,
                                DCFE1C361F17ECE5007640C8 /* CKKSCondition.m in Sources */,
                                EB7E91172194847A00B1FA21 /* SecEventMetric.m in Sources */,
-                               DCEA5D971E3015830089CF55 /* CKKSZone.m in Sources */,
+                               0C64C0802485B2EF00D84A5D /* OTPreloadOctagonKeysOperation.m in Sources */,
                                DCAB17D22200D26900E1DFCF /* SecEscrowPendingRecord.m in Sources */,
                                DC047082218BB21E0078BDAA /* OTCuttlefishAccountStateHolder.m in Sources */,
                                DC047088218BCEF20078BDAA /* OTOperationDependencies.m in Sources */,
                                DC52EDBC1D80D5C500B0A59C /* secd-02-upgrade-while-locked.m in Sources */,
                                DC52EDBD1D80D5C500B0A59C /* secd-20-keychain_upgrade.m in Sources */,
                                DC52EDBE1D80D5C500B0A59C /* secd-21-transmogrify.m in Sources */,
-                               DCFAEDD21D99991F005187E4 /* secd-668-ghosts.m in Sources */,
                                DC52EDBF1D80D5C500B0A59C /* secd-30-keychain-upgrade.m in Sources */,
                                DC52EDC11D80D5C500B0A59C /* secd-31-keychain-unreadable.m in Sources */,
                                0CCDE7171EEB08220021A946 /* secd-156-timers.m in Sources */,
                                DC52EDD41D80D5C500B0A59C /* secd-60-account-cloud-identity.m in Sources */,
                                DC52EDD51D80D5C500B0A59C /* secd60-account-cloud-exposure.m in Sources */,
                                DC52EDD61D80D5C500B0A59C /* secd-61-account-leave-not-in-kansas-anymore.m in Sources */,
-                               0C78826F20132069002B7475 /* SFSignInAnalytics.m in Sources */,
                                DC52EDD71D80D5C500B0A59C /* secd-62-account-backup.m in Sources */,
                                DC52EDD91D80D5C500B0A59C /* secd-63-account-resurrection.m in Sources */,
                                DC52EDDA1D80D5C500B0A59C /* secd-65-account-retirement-reset.m in Sources */,
                                DC52EDDF1D80D5C500B0A59C /* secd-70-otr-remote.m in Sources */,
                                DC52EDE21D80D5C500B0A59C /* secd-74-engine-beer-servers.m in Sources */,
                                7281E0901DFD0E0A0021E1B7 /* CKDKVSProxy.m in Sources */,
+                               487A65F4245B65F1005F51D6 /* secd-68-fullPeerInfoIntegrity.m in Sources */,
                                DC52EDE31D80D5C500B0A59C /* secd-75-engine-views.m in Sources */,
                                DC52EDE61D80D5C500B0A59C /* secd-80-views-basic.m in Sources */,
                                DC52EDE81D80D5C500B0A59C /* secd-81-item-acl-stress.m in Sources */,
                        buildActionMask = 2147483647;
                        files = (
                                DC52EE611D80D79E00B0A59C /* si-71-mobile-store-policy.c in Sources */,
-                               DC52EE601D80D79900B0A59C /* si-74-OTAPKISigner.c in Sources */,
                                D4AD87701E452CE000CA1B7F /* si-68-secmatchissuer.c in Sources */,
                                EB6928CA1D9C9E1800062A18 /* rk_01_recoverykey.m in Sources */,
                                D42CDC351DC12FE90090E2C9 /* si-66-smime.c in Sources */,
                                DC0B62291D90974600D43BCB /* si-25-cms-skid.m in Sources */,
                                09CB49701F2F64E300C8E4DE /* si-44-seckey-fv.m in Sources */,
                                D48BD18D206C45F00075DDC9 /* si-89-cms-hash-agility.m in Sources */,
-                               BE6215BE1DB6E69100961E15 /* si-84-sectrust-allowlist.m in Sources */,
                                D4B6D57C2069D8450099FBEF /* si-34-cms-timestamp.m in Sources */,
                                D4096E031ED5F21C000AC459 /* si-65-cms-cert-policy.c in Sources */,
                                DC52EE441D80D71900B0A59C /* si-21-sectrust-asr.c in Sources */,
                                D4AA0D9A22FB959600D77FA4 /* si-29-cms-chain-mode.m in Sources */,
                                DC52EE451D80D71900B0A59C /* si-22-sectrust-iap.c in Sources */,
-                               DC52EE471D80D71900B0A59C /* si-23-sectrust-ocsp.c in Sources */,
                                D48E4E241E42F0620011B4BA /* si-62-csr.m in Sources */,
                                DC52EE481D80D71900B0A59C /* si-24-sectrust-digicert-malaysia.c in Sources */,
                                DC52EE491D80D71900B0A59C /* si-24-sectrust-diginotar.c in Sources */,
                                DC52EE4C1D80D71900B0A59C /* si-24-sectrust-passbook.c in Sources */,
                                DC52EE4D1D80D71900B0A59C /* si-26-sectrust-copyproperties.c in Sources */,
                                5E7793751E5F025A0074A2D1 /* si-44-seckey-aks.m in Sources */,
-                               DC52EE4F1D80D71900B0A59C /* si-28-sectrustsettings.m in Sources */,
                                DC52EE531D80D73800B0A59C /* si-44-seckey-gen.m in Sources */,
                                DC52EE541D80D73800B0A59C /* si-44-seckey-rsa.m in Sources */,
                                DC52EE551D80D73800B0A59C /* si-44-seckey-ec.m in Sources */,
                                D4096E011ED5F0B5000AC459 /* si-60-cms.c in Sources */,
                                D4CFAA7E1E660BB3004746AA /* si-32-sectrust-pinning-required.m in Sources */,
-                               BE9B8B4A202BB4A20081EF87 /* si-88-sectrust-valid.m in Sources */,
                                D48BD194206C47530075DDC9 /* si-35-cms-expiration-time.m in Sources */,
                                DC52EE561D80D73800B0A59C /* si-44-seckey-ies.m in Sources */,
-                               DC52EE571D80D73800B0A59C /* si-67-sectrust-blocklist.c in Sources */,
                                D4096E021ED5F207000AC459 /* si-64-ossl-cms.c in Sources */,
                                478014541FBF577000C4043D /* si-44-seckey-proxy.m in Sources */,
                                DCD45357209A5BA10086CBFC /* si-cms-signing-identity-p12.c in Sources */,
                                DC52EE721D80D86400B0A59C /* SecuritydXPC.c in Sources */,
                                DC52EE711D80D85F00B0A59C /* SecECKey.m in Sources */,
                                DC52EE701D80D84700B0A59C /* SecItemConstants.c in Sources */,
+                               6C22008A244F0760000A4557 /* SecItemRateLimit.m in Sources */,
                                DC52EE6F1D80D83F00B0A59C /* SecPasswordGenerate.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                                DC5AC1031D83552000CF422C /* selfServer.cpp in Sources */,
                                DC5AC1041D83552000CF422C /* selfUser.cpp in Sources */,
                                DC5AC0D81D8354CA00CF422C /* main.cpp in Sources */,
+                               6C75560624212B4400025D78 /* keychainstasherinterface.m in Sources */,
                                DC5AC0D91D8354CA00CF422C /* connection.cpp in Sources */,
                                DC5AC0DA1D8354CA00CF422C /* database.cpp in Sources */,
                                DC5AC0DB1D8354CA00CF422C /* key.cpp in Sources */,
                                DC5AC0E61D8354CA00CF422C /* tokendatabase.cpp in Sources */,
                                DC5AC0E71D8354CA00CF422C /* tokenkey.cpp in Sources */,
                                DC5AC0E81D8354CA00CF422C /* tokenaccess.cpp in Sources */,
-                               DC5AC0E91D8354CA00CF422C /* pcscmonitor.cpp in Sources */,
                                DC5AC0EA1D8354CA00CF422C /* reader.cpp in Sources */,
                                DC5AC0EB1D8354CA00CF422C /* token.cpp in Sources */,
                                DC5AC0EC1D8354CA00CF422C /* tokend.cpp in Sources */,
                        files = (
                                DCE405C523A04A7F00C4343B /* OctagonTests+CKKSConfiguration.swift in Sources */,
                                1B8D2D96226E1FA500C94238 /* SetValueTransformer.swift in Sources */,
+                               0CCC21FC23F33DA900E1FCD0 /* OTICDPRecordContext.m in Sources */,
                                DC5F2BBE2310B941001ADA5D /* OctagonTests+CoreFollowUp.swift in Sources */,
                                DCB468E520EC262C00BA7E5B /* ContainerMap.swift in Sources */,
+                               0CA1D0B923E9034600021038 /* OctagonTests+EscrowTestVectors.swift in Sources */,
                                0C4CDE6F22922E550050C499 /* OctagonTests+RecoveryKey.swift in Sources */,
                                EBDE5E0F22BA3DEA00A229C8 /* CKKSMockOctagonAdapter.m in Sources */,
                                DCB468DF20EC25FF00BA7E5B /* Client.swift in Sources */,
                                0C5824A52286002D009E8C15 /* OctagonTests+HealthCheck.swift in Sources */,
+                               0C468FFD23C7D4F9006F4582 /* OTEscrowRecord.m in Sources */,
                                DC27C3CE20EAFE9C00F7839C /* CloudKitMockXCTest.m in Sources */,
                                DCB9475821274F9D00ED9272 /* TPHObjcTranslation.m in Sources */,
                                DC27C3CB20EADF3500F7839C /* CloudKitKeychainSyncingMockXCTest.m in Sources */,
                                0C87D3E4229368BD007853B5 /* OctagonTests+SOS.swift in Sources */,
                                DC27C3C920EADEE700F7839C /* MockCloudKit.m in Sources */,
+                               0CCC21FD23F33DCE00E1FCD0 /* OTCDPRecoveryInformation.m in Sources */,
                                0CF70BE0218CF26600EC3515 /* BottledPeer.swift in Sources */,
                                DC99B86B20EACA470065B73B /* spi.c in Sources */,
                                DC4CD9842372294E00EF55FC /* OctagonTests+Helpers.swift in Sources */,
+                               0C3C47C924902DA50084B951 /* OTSupportOctagonMessage.m in Sources */,
                                DCAA209A23AAF8F600DCB594 /* Container_RecoveryKey.swift in Sources */,
+                               DCA7F7EF23A44AA200927989 /* OctagonPolicyTests.swift in Sources */,
                                DCDF03122284E34B008055BA /* OctagonTests+EscrowRecovery.swift in Sources */,
                                DCFF82712162834D00D54B02 /* OctagonTestsXPCConnections.swift in Sources */,
                                DC5BEACD2217509A001681F0 /* OctagonTests+CloudKitAccount.swift in Sources */,
                                DC07090422936DB2002711B9 /* OctagonTests+ErrorHandling.swift in Sources */,
                                DC99B86C20EACA470065B73B /* FakeCuttlefish.swift in Sources */,
                                0CBEF3432242CA0600015691 /* TestsObjcTranslation.m in Sources */,
+                               0C468FFE23C7D4F9006F4582 /* OTEscrowRecordMetadata.m in Sources */,
                                5A04BB0222982733001848A0 /* OTFollowupTests.m in Sources */,
                                DCB24B45221B901700BE73FE /* CKKSMockSOSPresentAdapter.m in Sources */,
                                DC33D7BE2374FD0A00A68155 /* OTSponsorToApplicantRound2M2.m in Sources */,
                                0CE15E31222DF63600B7EAA4 /* RecoverKeySet.swift in Sources */,
+                               0C3C47C824902DA50084B951 /* OTSupportSOSMessage.m in Sources */,
+                               0C468FFF23C7D4F9006F4582 /* OTEscrowRecordMetadataClientMetadata.m in Sources */,
                                0CADDF0721545CF100DF8B06 /* OctagonPairingTests.swift in Sources */,
                                DC99B86D20EACA470065B73B /* SecdWatchdog.m in Sources */,
                                DC26666C21CAC97000F19960 /* OTControlCLI.m in Sources */,
                                DC99B86E20EACA470065B73B /* MockCuttlefish.swift in Sources */,
                                0CF70BE3218CF2AA00EC3515 /* OTBottle.m in Sources */,
                                DC27C3CA20EADF1700F7839C /* CloudKitKeychainSyncingTestsBase.m in Sources */,
+                               0C3DF8CA24789D0A009CF03A /* Container_Peers.swift in Sources */,
                                0CF70BE4218CF2AA00EC3515 /* OTBottleContents.m in Sources */,
                                0C61F1F92194FC82009566D4 /* OTAuthenticatedCiphertext+SF.m in Sources */,
                                DCB0C291222F5E130083AECB /* CuttlefishErrors.swift in Sources */,
                                DC99B86F20EACA470065B73B /* SecFramework.c in Sources */,
+                               0CBF883D23AAD9F100652EDD /* OctagonTests+EscrowRecords.swift in Sources */,
                                0C5258BB21BB128000B32C96 /* FakeSOSControl.m in Sources */,
                                DC3A9B2723A9D8BD0073ED06 /* Container_BottledPeers.swift in Sources */,
                                DC99B87020EACA470065B73B /* server_endpoint.m in Sources */,
                                DC99B87320EACA470065B73B /* Decrypter.swift in Sources */,
                                DC99B87420EACA470065B73B /* server_entitlement_helpers.c in Sources */,
                                DC99B87520EACA470065B73B /* TrustedPeersHelper.xcdatamodeld in Sources */,
+                               DC9978B92404AA3200A5EE2F /* Container_UserSync.swift in Sources */,
                                0CE15E2D222DF63600B7EAA4 /* RecoveryKey.swift in Sources */,
                                DC27C3C120EAD9C300F7839C /* OctagonTests.swift in Sources */,
                                0CE15E3F222DF6A800B7EAA4 /* OTRecovery.m in Sources */,
+                               0C0CB73A23AD715A0020C6BF /* Container_EscrowRecords.swift in Sources */,
                                DCB9475A2127534C00ED9272 /* OctagonTests+SOSUpgrade.swift in Sources */,
                                DC7F6A7D233D7FAC00DF5769 /* OctagonTests+ForwardCompatibility.swift in Sources */,
                                DC99B87720EACA470065B73B /* ContainerSync.swift in Sources */,
                                DC33D7BD2374FD0500A68155 /* OTSponsorToApplicantRound1M2.m in Sources */,
+                               0CCC21FE23F33DD400E1FCD0 /* OTEscrowAuthenticationInformation.m in Sources */,
                                0C61F1F62194FC79009566D4 /* OTPrivateKey+SF.m in Sources */,
                                DC391FA821C04DAE00772585 /* OctagonPeerKeys.swift in Sources */,
                                DC99B87820EACA470065B73B /* Container.swift in Sources */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               6C2D463D24C88AA10015C3C9 /* LegacyAPICounts.m in Sources */,
                                DCB3433D1D8A32A20054D16E /* ACL.cpp in Sources */,
                                DCB3433B1D8A32A20054D16E /* Access.cpp in Sources */,
                                DCB3436A1D8A32A20054D16E /* CCallbackMgr.cp in Sources */,
                                DCB342FB1D8A32A20054D16E /* SecBase.cpp in Sources */,
                                DCB3435B1D8A32A20054D16E /* SecCFTypes.cpp in Sources */,
                                DCB342FD1D8A32A20054D16E /* SecCertificate.cpp in Sources */,
-                               DCB342FE1D8A32A20054D16E /* SecCertificateBundle.cpp in Sources */,
                                DCB343921D8A32A20054D16E /* SecExport.cpp in Sources */,
                                DCB343931D8A32A20054D16E /* SecExternalRep.cpp in Sources */,
                                DCB343371D8A32A20054D16E /* SecFDERecoveryAsymmetricCrypto.cpp in Sources */,
                                DCB343021D8A32A20054D16E /* SecItemConstants.c in Sources */,
                                DCB343041D8A32A20054D16E /* SecKey.cpp in Sources */,
                                DCB343051D8A32A20054D16E /* SecKeychain.cpp in Sources */,
-                               DCB3435D1D8A32A20054D16E /* SecKeychainAddIToolsPassword.cpp in Sources */,
                                DCB343061D8A32A20054D16E /* SecKeychainItem.cpp in Sources */,
                                DCB343071D8A32A20054D16E /* SecKeychainItemExtendedAttributes.cpp in Sources */,
                                DCB343081D8A32A20054D16E /* SecKeychainSearch.cpp in Sources */,
                                DCAB17CE21FFF75B00E1DFCF /* MockSynchronousEscrowServer.m in Sources */,
                                DCBF4ABB21FFC82100539F0A /* SecFramework.c in Sources */,
                                DCBF4ABE21FFC82100539F0A /* server_entitlement_helpers.c in Sources */,
+                               A6C737C123F37AC00009C930 /* entitlements.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DCC78EE41D808B1B00865A7C /* SecCFAllocator.c in Sources */,
                                DCC78EE31D808B1300865A7C /* SecCMS.c in Sources */,
                                BEEB47D91EA189F5004AA5C6 /* SecTrustStatusCodes.c in Sources */,
+                               6C220088244F075E000A4557 /* SecItemRateLimit.m in Sources */,
                                DCC78EE21D808B0E00865A7C /* SecCTKKey.m in Sources */,
                                DCC78EE11D808B0900865A7C /* SecCertificate.c in Sources */,
                                DC4269041E82EDAC002B7110 /* SecItem.m in Sources */,
                                DCD068201D8CDF7E007602F1 /* SecRequirement.cpp in Sources */,
                                DCD0681D1D8CDF7E007602F1 /* SecStaticCode.cpp in Sources */,
                                1F631C5622387FFE005920D8 /* legacydevid.cpp in Sources */,
+                               A6C737BA23F37A4B0009C930 /* entitlements.c in Sources */,
                                DCD0682C1D8CDF7E007602F1 /* StaticCode.cpp in Sources */,
                                DCD0693D1D8CDFFF007602F1 /* String.cpp in Sources */,
                                DCD0693E1D8CDFFF007602F1 /* Token.cpp in Sources */,
                                DC3AA2852097E22A007CA68A /* codesign.c in Sources */,
                                DC8506AD2097EEBC00C712EC /* sos.m in Sources */,
                                DCE4E6931D7A37FA00AFB96E /* NSFileHandle+Formatting.m in Sources */,
+                               BE57B11A2509E1000045B7FD /* ca_revocation_additions.m in Sources */,
                                DC3AA2892097E23A007CA68A /* keychain_find.m in Sources */,
                                DC3AA2792097DF71007CA68A /* readline.c in Sources */,
                                DC3AA2822097E218007CA68A /* add_internet_password.c in Sources */,
                        buildActionMask = 2147483647;
                        files = (
                                DCE4E7B51D7A43FF00AFB96E /* main.m in Sources */,
-                               DCE4E7B61D7A440A00AFB96E /* bc-10-knife-on-bread.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                DCE4E7E21D7A4B7F00AFB96E /* main.c in Sources */,
-                               DCE4E7DF1D7A4B4C00AFB96E /* bc-10-knife-on-bread.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                DCE4E8C31D7F353900AFB96E /* session.c in Sources */,
                                DCE4E8BC1D7F353900AFB96E /* engine.c in Sources */,
                                DCE4E8C41D7F353900AFB96E /* connection.c in Sources */,
+                               F681C3AB2386B8C30083F22C /* PreloginUserDb.m in Sources */,
                                DCE4E8C11D7F353900AFB96E /* rule.c in Sources */,
                                DCE4E8C01D7F353900AFB96E /* process.c in Sources */,
                                DCE4E8B31D7F353900AFB96E /* agent.c in Sources */,
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               0C0203E623A857C1005D0A68 /* OTEscrowRecord.proto in Sources */,
+                               BE7B8E132415579900E1CF4F /* SecSharedCredential.m in Sources */,
                                EBDCC002233DD45700806566 /* MockAKSRefKey.proto in Sources */,
                                0CE15E39222DF67800B7EAA4 /* OTRecovery.proto in Sources */,
+                               6C6AF17A221A06790091CE0A /* SecDbKeychainSerializedMetadataKey.proto in Sources */,
                                DCE0775621ADD665002662FD /* OTPrivateKey.proto in Sources */,
                                DCE0775321ADD65E002662FD /* OTAuthenticatedCiphertext.proto in Sources */,
                                DCE0775521ADD663002662FD /* OTBottleContents.proto in Sources */,
                                DCE0775421ADD661002662FD /* OTBottle.proto in Sources */,
                                DCF216DE21ADD5F90029CCC1 /* CKKSSerializedKey.proto in Sources */,
+                               DCA992AD2400BB99007959AF /* TPPBAncientEpoch.proto in Sources */,
                                DCF216DF21ADD5FB0029CCC1 /* OTPairingMessage.proto in Sources */,
                                DCF216E121ADD6060029CCC1 /* TPPBVoucher.proto in Sources */,
                                DCF216E021ADD5FD0029CCC1 /* OTAccountMetadataClassC.proto in Sources */,
                                DCE0774721ADD63A002662FD /* TPPBDispositionEntry.proto in Sources */,
-                               DCE0774821ADD63C002662FD /* TPPBAncientEpoch.proto in Sources */,
                                DCE0774621ADD638002662FD /* TPPBDisposition.proto in Sources */,
                                DCE0774921ADD63E002662FD /* TPPBPolicyProhibits.proto in Sources */,
                                DCE0774A21ADD640002662FD /* TPPBUnknownMachineID.proto in Sources */,
                                5A47FFB3228F5E5500F781B8 /* KCInitialMessageData.proto in Sources */,
                                DCE0775021ADD655002662FD /* TPPBPolicyModelToCategory.proto in Sources */,
                                DCE0775121ADD658002662FD /* TPPBPolicyIntroducersByCategory.proto in Sources */,
+                               0C0D920C23BFEAB30070A68C /* OTCDPRecoveryInformation.proto in Sources */,
                                DCE0774F21ADD651002662FD /* TPPBPolicyCategoriesByView.proto in Sources */,
                                DC88466B22373A5E00738068 /* TPPBDictionaryMatchingRule.proto in Sources */,
                                DCE0775221ADD65A002662FD /* TPPBPolicyRedaction.proto in Sources */,
                        files = (
                                EB413B801E663AEB00592085 /* PairingChannel.m in Sources */,
                                0CB72D9E21E42FCF00D8BC9B /* OTPairingMessage.m in Sources */,
+                               0C3C47C624902D960084B951 /* OTSupportOctagonMessage.m in Sources */,
                                0CB72DA121E42FCF00D8BC9B /* OTSponsorToApplicantRound2M2.m in Sources */,
                                E7F480151C73980D00390FDB /* KCJoiningRequestSecretSession.m in Sources */,
                                E7F480331C73FC4C00390FDB /* KCAESGCMDuplexSession.m in Sources */,
                                E7F482AC1C7558F700390FDB /* KCJoiningAcceptSession.m in Sources */,
                                E71454F01C741E0800B5B20B /* KCError.m in Sources */,
                                E772FD471CC15EFA00D63E41 /* NSData+SecRandom.m in Sources */,
+                               0C3C47C724902D960084B951 /* OTSupportSOSMessage.m in Sources */,
                                0CB72D9D21E42FCF00D8BC9B /* OTApplicantToSponsorRound2M1.m in Sources */,
                                E7F482AA1C7554FB00390FDB /* NSError+KCCreationHelpers.m in Sources */,
                                E75C0E831C6FC31D00E6953B /* KCSRPContext.m in Sources */,
                        files = (
                                6C32BB9920EAE6B00042DF59 /* LocalKeychainAnalytics.m in Sources */,
                                EB1E069D211E16260088F0B1 /* mockaksxcbase.m in Sources */,
-                               0CC3771320A222BC00B58D2D /* SFSignInAnalytics.m in Sources */,
                                EB49B2DB202DF20F003F34A0 /* spi.c in Sources */,
                                EB49B2D7202DF1F7003F34A0 /* server_endpoint.m in Sources */,
                                EBC73F2020993F8600AE3350 /* SFAnalyticsSQLiteStore.m in Sources */,
                                EB49B2D9202DF1F7003F34A0 /* server_security_helpers.m in Sources */,
                                EBC73F2B2099785900AE3350 /* SFObjCType.m in Sources */,
                                480ADDB22155A0CE00318FC6 /* SOSAnalytics.m in Sources */,
+                               A6C737C023F37AB90009C930 /* entitlements.c in Sources */,
                                EB49B2E0202DF5D7003F34A0 /* server_entitlement_helpers.c in Sources */,
                                5A061196229ED6E8006AF14A /* NSDate+SFAnalytics.m in Sources */,
                                EBC73F2A20996AD400AE3350 /* SFSQLiteStatement.m in Sources */,
                                EB6952A4223B75C300F02C1C /* server_xpc.m in Sources */,
                                EB6952A5223B75C300F02C1C /* SecDbKeychainSerializedItemV7.m in Sources */,
                                EB6952A6223B75C300F02C1C /* SecDbQuery.c in Sources */,
+                               6C2138C4225183FE007DEDD3 /* SecDbKeychainSerializedMetadataKey.m in Sources */,
                                EB6952A7223B75C300F02C1C /* SecuritydXPC.c in Sources */,
                                EB6952A8223B75C300F02C1C /* server_endpoint.m in Sources */,
                                EB6952A9223B75C300F02C1C /* SecDbKeychainItemV7.m in Sources */,
                                EB89086C21F17D3C00F0DDDB /* server_security_helpers.m in Sources */,
                                EB8908B021F18D7B00F0DDDB /* SecDbKeychainSerializedMetadata.m in Sources */,
                                EB89086D21F17D3C00F0DDDB /* server_xpc.m in Sources */,
+                               6C6AF181221A070C0091CE0A /* SecDbKeychainSerializedMetadataKey.m in Sources */,
                                EB8908B221F18E1400F0DDDB /* SecDbKeychainSerializedItemV7.m in Sources */,
                                EB8908A821F1886100F0DDDB /* SecDbQuery.c in Sources */,
                                EB8908AD21F18CEF00F0DDDB /* SecuritydXPC.c in Sources */,
                        target = DC0BCC211D8C684F00070CB0 /* utilities */;
                        targetProxy = 0C10C93B1DD548BD000602A8 /* PBXContainerItemProxy */;
                };
+               0C2B36C323C42EBC00000718 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CD743A523C3EC8000FA0EC5 /* OctagonTrust */;
+                       targetProxy = 0C2B36C223C42EBC00000718 /* PBXContainerItemProxy */;
+               };
+               0C2B36C523C42EC800000718 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CD743A523C3EC8000FA0EC5 /* OctagonTrust */;
+                       targetProxy = 0C2B36C423C42EC800000718 /* PBXContainerItemProxy */;
+               };
                0C2BCBBC1D0640B200ED7A2F /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 0C2BCBA81D06401F00ED7A2F /* dtlsEchoClient */;
                        target = 0C2BCBBD1D0648D100ED7A2F /* dtlsEchoServer */;
                        targetProxy = 0C2BCBD01D0648FA00ED7A2F /* PBXContainerItemProxy */;
                };
-               0C3E2EA92073F5C400F5B95B /* PBXTargetDependency */ = {
+               0C65BB4D23C3F31B0063D2B7 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = 4C32C0AE0A4975F6002891BD /* Security_ios */;
-                       targetProxy = 0C3E2EA82073F5C400F5B95B /* PBXContainerItemProxy */;
+                       target = 0CD743A523C3EC8000FA0EC5 /* OctagonTrust */;
+                       targetProxy = 0C65BB4C23C3F31B0063D2B7 /* PBXContainerItemProxy */;
                };
-               0C5663EE20BE2E1A0035F362 /* PBXTargetDependency */ = {
+               0C65BB4F23C3F3270063D2B7 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
-                       targetProxy = 0C5663ED20BE2E1A0035F362 /* PBXContainerItemProxy */;
+                       target = 0CD743A523C3EC8000FA0EC5 /* OctagonTrust */;
+                       targetProxy = 0C65BB4E23C3F3270063D2B7 /* PBXContainerItemProxy */;
                };
                0C78CCE51FCC97E7008B4B24 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 0C8BBEFD1FCB446400580909 /* otctl */;
                        targetProxy = 0C78CCE61FCC97F1008B4B24 /* PBXContainerItemProxy */;
                };
+               0C7EB14D23F3D13C0089097B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
+                       targetProxy = 0C7EB14C23F3D13C0089097B /* PBXContainerItemProxy */;
+               };
+               0C7EB14F23F3D1480089097B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
+                       targetProxy = 0C7EB14E23F3D1480089097B /* PBXContainerItemProxy */;
+               };
                0C85DFD81FB38BB6000343A7 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC8834011D8A218F00CE0ACA /* ASN1 */;
                        target = DCC78EA81D8088E200865A7C /* security */;
                        targetProxy = 0C85DFE11FB38BB6000343A7 /* PBXContainerItemProxy */;
                };
-               0C9AEEBA20783FE000BF6237 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC1789031D77980500B50D50 /* Security_osx */;
-                       targetProxy = 0C9AEEB920783FE000BF6237 /* PBXContainerItemProxy */;
-               };
                0CA378E923876E0900090B7E /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 0CA378E123876DD100090B7E /* reset_account */;
                        target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
                        targetProxy = 0CC593F72299EDFC006C34B5 /* PBXContainerItemProxy */;
                };
+               0CCC22AB23F38B0600E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
+                       targetProxy = 0CCC22AA23F38B0600E1FCD0 /* PBXContainerItemProxy */;
+               };
+               0CCC22AD23F38B0E00E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
+                       targetProxy = 0CCC22AC23F38B0E00E1FCD0 /* PBXContainerItemProxy */;
+               };
+               0CCC22CE23F39A6300E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */;
+                       targetProxy = 0CCC22CD23F39A6300E1FCD0 /* PBXContainerItemProxy */;
+               };
+               0CCC22D023F39A6A00E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */;
+                       targetProxy = 0CCC22CF23F39A6A00E1FCD0 /* PBXContainerItemProxy */;
+               };
+               0CCC22D223F39A7500E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */;
+                       targetProxy = 0CCC22D123F39A7500E1FCD0 /* PBXContainerItemProxy */;
+               };
+               0CCC22D423F39A7C00E1FCD0 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 0CCC220023F357EE00E1FCD0 /* OctagonTrustTests */;
+                       targetProxy = 0CCC22D323F39A7C00E1FCD0 /* PBXContainerItemProxy */;
+               };
                0CF09210219649DB002B0AEE /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 5346480017331E1100FE9172 /* KeychainSyncAccountNotification */;
                        target = DC0BCC211D8C684F00070CB0 /* utilities */;
                        targetProxy = 3DD258A1204B7DA800F5DA78 /* PBXContainerItemProxy */;
                };
+               3E88361D24F08F5400E9F4D6 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 3E88360824F068EF00E9F4D6 /* secseccodeapitest */;
+                       targetProxy = 3E88361C24F08F5400E9F4D6 /* PBXContainerItemProxy */;
+               };
                438169E71B4EE4B300C54D58 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 4381690B1B4EDCBD00C54D58 /* SOSCCAuthPlugin */;
                        target = 4771D971209A755800BA9772 /* KeychainDataclassOwner */;
                        targetProxy = 4771D981209A76B100BA9772 /* PBXContainerItemProxy */;
                };
-               478D426D1FD72A8100CAB645 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52EDA61D80D58400B0A59C /* secdRegressions */;
-                       targetProxy = 478D426E1FD72A8100CAB645 /* PBXContainerItemProxy */;
-               };
-               478D426F1FD72A8100CAB645 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC0BCBD91D8C648C00070CB0 /* regressionBase */;
-                       targetProxy = 478D42701FD72A8100CAB645 /* PBXContainerItemProxy */;
-               };
-               478D42731FD72A8100CAB645 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCC78EA81D8088E200865A7C /* security */;
-                       targetProxy = 478D42741FD72A8100CAB645 /* PBXContainerItemProxy */;
-               };
                47A6FC6A206B461700BD6C54 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
                        targetProxy = 47A6FC69206B461700BD6C54 /* PBXContainerItemProxy */;
                };
-               47A6FC6C206B462400BD6C54 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
-                       targetProxy = 47A6FC6B206B462400BD6C54 /* PBXContainerItemProxy */;
-               };
                47C2F18C2059CBEA0062DE30 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 47C2F1822059CB680062DE30 /* KeychainResources */;
                        target = DC1789031D77980500B50D50 /* Security_osx */;
                        targetProxy = 47C51B8A1EEA657D0032D9E5 /* PBXContainerItemProxy */;
                };
-               47D991D020407F7E0078CAE2 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 4727FBB61F9918580003AE36 /* secdxctests_ios */;
-                       targetProxy = 47D991CF20407F7E0078CAE2 /* PBXContainerItemProxy */;
-               };
                47DE88CE1FA7AD6200DD3254 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DCC78EA81D8088E200865A7C /* security */;
                        target = 5346480017331E1100FE9172 /* KeychainSyncAccountNotification */;
                        targetProxy = 5346481A17331ED800FE9172 /* PBXContainerItemProxy */;
                };
-               6C4AA1AA2228B640006FA945 /* PBXTargetDependency */ = {
+               5AAE383623D261CF0025CF9E /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = EB9C1DAE1BDFD4DE00F89272 /* SecurityBatsTests */;
-                       targetProxy = 6C4AA1A92228B640006FA945 /* PBXContainerItemProxy */;
+                       target = 5A442F81233C330F00918373 /* experimentTool */;
+                       targetProxy = 5AAE383523D261CF0025CF9E /* PBXContainerItemProxy */;
                };
-               6C8FF4B6224C1A9800E5C812 /* PBXTargetDependency */ = {
+               6C14CA0423C4F6830097B572 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = BEF88C271EAFFC3F00357577 /* TrustedPeers */;
-                       targetProxy = 6C8FF4B5224C1A9800E5C812 /* PBXContainerItemProxy */;
-               };
-               6C98082F1E788AEB00E70590 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC8834011D8A218F00CE0ACA /* ASN1 */;
-                       targetProxy = 6C9808301E788AEB00E70590 /* PBXContainerItemProxy */;
+                       target = 4718AE2E205B39C40068EC3F /* libsecurityd_bridge */;
+                       targetProxy = 6C14CA0323C4F6830097B572 /* PBXContainerItemProxy */;
                };
-               6C9808311E788AEB00E70590 /* PBXTargetDependency */ = {
+               6C16258123C4FFC40086A0FF /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
-                       targetProxy = 6C9808321E788AEB00E70590 /* PBXContainerItemProxy */;
+                       target = D4ADA3181E2B41670031CEA3 /* libtrustd */;
+                       targetProxy = 6C16258023C4FFC40086A0FF /* PBXContainerItemProxy */;
                };
-               6C9808351E788AEB00E70590 /* PBXTargetDependency */ = {
+               6C16258423C4FFD40086A0FF /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
-                       targetProxy = 6C9808361E788AEB00E70590 /* PBXContainerItemProxy */;
+                       targetProxy = 6C16258323C4FFD40086A0FF /* PBXContainerItemProxy */;
                };
-               6C9808371E788AEB00E70590 /* PBXTargetDependency */ = {
+               6C16258623C4FFD40086A0FF /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
-                       targetProxy = 6C9808381E788AEB00E70590 /* PBXContainerItemProxy */;
+                       targetProxy = 6C16258523C4FFD40086A0FF /* PBXContainerItemProxy */;
                };
-               6C9808391E788AEB00E70590 /* PBXTargetDependency */ = {
+               6C2045F82424BC4400F9461D /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DCC78EA81D8088E200865A7C /* security */;
-                       targetProxy = 6C98083A1E788AEB00E70590 /* PBXContainerItemProxy */;
+                       target = 6C2045E92424BA7E00F9461D /* KeychainStasher */;
+                       targetProxy = 6C2045F72424BC4400F9461D /* PBXContainerItemProxy */;
                };
-               6C98086B1E788AFD00E70590 /* PBXTargetDependency */ = {
+               6C2D797322C06CEB00C3CE32 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DC8834011D8A218F00CE0ACA /* ASN1 */;
-                       targetProxy = 6C98086C1E788AFD00E70590 /* PBXContainerItemProxy */;
+                       target = 6C39234421F13E4D00D018AD /* SecDbBackupTests */;
+                       targetProxy = 6C2D797222C06CEB00C3CE32 /* PBXContainerItemProxy */;
                };
-               6C98086D1E788AFD00E70590 /* PBXTargetDependency */ = {
+               6C2D797522C06CEF00C3CE32 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
-                       targetProxy = 6C98086E1E788AFD00E70590 /* PBXContainerItemProxy */;
+                       target = 4727FBB61F9918580003AE36 /* secdxctests */;
+                       targetProxy = 6C2D797422C06CEF00C3CE32 /* PBXContainerItemProxy */;
                };
-               6C9808711E788AFD00E70590 /* PBXTargetDependency */ = {
+               6C4AA1AA2228B640006FA945 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
-                       targetProxy = 6C9808721E788AFD00E70590 /* PBXContainerItemProxy */;
+                       target = EB9C1DAE1BDFD4DE00F89272 /* SecurityBatsTests */;
+                       targetProxy = 6C4AA1A92228B640006FA945 /* PBXContainerItemProxy */;
                };
-               6C9808731E788AFD00E70590 /* PBXTargetDependency */ = {
+               6C61D3E8242A29BA008AB9BB /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
-                       targetProxy = 6C9808741E788AFD00E70590 /* PBXContainerItemProxy */;
+                       target = 6C963280242A279B00C53CE2 /* stashtester */;
+                       targetProxy = 6C61D3E7242A29BA008AB9BB /* PBXContainerItemProxy */;
                };
-               6C9808751E788AFD00E70590 /* PBXTargetDependency */ = {
+               6C7BE2AA23C3DD64003BB2CA /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = DCC78EA81D8088E200865A7C /* security */;
-                       targetProxy = 6C9808761E788AFD00E70590 /* PBXContainerItemProxy */;
+                       target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
+                       targetProxy = 6C7BE2AB23C3DD64003BB2CA /* PBXContainerItemProxy */;
                };
-               6C9808A01E788B9400E70590 /* PBXTargetDependency */ = {
+               6C7BE2AC23C3DD64003BB2CA /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */;
-                       targetProxy = 6C98089F1E788B9400E70590 /* PBXContainerItemProxy */;
+                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
+                       targetProxy = 6C7BE2AD23C3DD64003BB2CA /* PBXContainerItemProxy */;
                };
-               6C9808A41E788CB100E70590 /* PBXTargetDependency */ = {
+               6C7BE2EA23C3DD9C003BB2CA /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = 6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */;
-                       targetProxy = 6C9808A31E788CB100E70590 /* PBXContainerItemProxy */;
+                       target = 6C7BE2A923C3DD64003BB2CA /* securitytool_bridge */;
+                       targetProxy = 6C7BE2E923C3DD9C003BB2CA /* PBXContainerItemProxy */;
                };
                6C9A49B21FAB647D00239D58 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC0BCC211D8C684F00070CB0 /* utilities */;
                        targetProxy = 6C9A49B11FAB647D00239D58 /* PBXContainerItemProxy */;
                };
+               6CA9690D24ACC5C100C08B5E /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
+                       targetProxy = 6CA9690C24ACC5C100C08B5E /* PBXContainerItemProxy */;
+               };
                6CAA8D3D1F8431BC007B6E03 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 6CAA8D1F1F842FB3007B6E03 /* securityuploadd */;
                        target = 6CAA8D1F1F842FB3007B6E03 /* securityuploadd */;
                        targetProxy = 6CAA8D3E1F8431C9007B6E03 /* PBXContainerItemProxy */;
                };
+               6CC638E7226695B900E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
+                       targetProxy = 6CC638E6226695B900E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CC638E9226695B900E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
+                       targetProxy = 6CC638E8226695B900E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CC638EB226695C300E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
+                       targetProxy = 6CC638EA226695C300E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CC638ED226695C300E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
+                       targetProxy = 6CC638EC226695C300E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CC638FE2266AE0A00E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 4727FBB61F9918580003AE36 /* secdxctests */;
+                       targetProxy = 6CC638FD2266AE0A00E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CC639002266AE0A00E5DB0B /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 6C39234421F13E4D00D018AD /* SecDbBackupTests */;
+                       targetProxy = 6CC638FF2266AE0A00E5DB0B /* PBXContainerItemProxy */;
+               };
+               6CE2AEAB22B2C1BE00C96AE7 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp */;
+                       targetProxy = 6CE2AEAA22B2C1BE00C96AE7 /* PBXContainerItemProxy */;
+               };
+               6CE2AEAD22B2C1C300C96AE7 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp */;
+                       targetProxy = 6CE2AEAC22B2C1C300C96AE7 /* PBXContainerItemProxy */;
+               };
+               6CF33CA62387156600D1E75D /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 4727FBB61F9918580003AE36 /* secdxctests */;
+                       targetProxy = 6CF33CA52387156600D1E75D /* PBXContainerItemProxy */;
+               };
+               6CF33CA82387157200D1E75D /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 4727FBB61F9918580003AE36 /* secdxctests */;
+                       targetProxy = 6CF33CA72387157200D1E75D /* PBXContainerItemProxy */;
+               };
                873C14B221540FED003C9C00 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC0BCC211D8C684F00070CB0 /* utilities */;
                        target = 6CCDF7831E3C25FA003F2555 /* KeychainEntitledTestRunner */;
                        targetProxy = D45D8F812224DBE300D6C124 /* PBXContainerItemProxy */;
                };
-               D45D8F842224DBEF00D6C124 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 6C9808681E788AFD00E70590 /* CKKSCloudKitTests_ios */;
-                       targetProxy = D45D8F832224DBEF00D6C124 /* PBXContainerItemProxy */;
-               };
                D45D8F862224DBF800D6C124 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC3502B41E0208BE00BC0587 /* CKKSTests */;
                        target = BEF88C2F1EAFFC3F00357577 /* TrustedPeersTests */;
                        targetProxy = D477EE8021ED48DF00C9AAFF /* PBXContainerItemProxy */;
                };
-               D477EE8321ED48E800C9AAFF /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 478D426C1FD72A8100CAB645 /* secdxctests_mac */;
-                       targetProxy = D477EE8221ED48E800C9AAFF /* PBXContainerItemProxy */;
-               };
                D4794E6B21222E72007C6725 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC8834011D8A218F00CE0ACA /* ASN1 */;
                        target = DC3502B41E0208BE00BC0587 /* CKKSTests */;
                        targetProxy = D4A763D82224BD990063B2B9 /* PBXContainerItemProxy */;
                };
-               D4A763DB2224BDAB0063B2B9 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 6C98082C1E788AEB00E70590 /* CKKSCloudKitTests_mac */;
-                       targetProxy = D4A763DA2224BDAB0063B2B9 /* PBXContainerItemProxy */;
-               };
-               D4A763DD2224BDCC0063B2B9 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 6CF4A0B31E45488B00ECD7B5 /* KeychainEntitledTestApp_mac */;
-                       targetProxy = D4A763DC2224BDCC0063B2B9 /* PBXContainerItemProxy */;
-               };
                D4A763DF2224BDDC0063B2B9 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = EB9C1DAE1BDFD4DE00F89272 /* SecurityBatsTests */;
                        target = 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */;
                        targetProxy = D4E0E9732224DE8200A802E0 /* PBXContainerItemProxy */;
                };
-               D4E0E9762224DE9100A802E0 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 4727FBB61F9918580003AE36 /* secdxctests_ios */;
-                       targetProxy = D4E0E9752224DE9100A802E0 /* PBXContainerItemProxy */;
-               };
-               D4E0E97A2224DEE600A802E0 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 6CF4A0DF1E4549F200ECD7B5 /* KeychainEntitledTestApp_ios */;
-                       targetProxy = D4E0E9792224DEE600A802E0 /* PBXContainerItemProxy */;
-               };
                D4E0E97C2224DF0300A802E0 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 4CB740A20A47567C00D641BB /* securitytool_ios */;
                        target = 47702B2D1E5F492C00B29577 /* seckeychainnetworkextensionunauthorizedaccesstest */;
                        targetProxy = D4E0E9A92224DFDD00A802E0 /* PBXContainerItemProxy */;
                };
-               D4E0E9AC2224DFEB00A802E0 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 4727FBB61F9918580003AE36 /* secdxctests_ios */;
-                       targetProxy = D4E0E9AB2224DFEB00A802E0 /* PBXContainerItemProxy */;
-               };
                D4E0E9AE2224E00600A802E0 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 4CB740A20A47567C00D641BB /* securitytool_ios */;
                        target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
                        targetProxy = DC311E662124A9D2002F5EAE /* PBXContainerItemProxy */;
                };
-               DC34CD2D20326C2C00302481 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
-                       targetProxy = DC34CD2C20326C2C00302481 /* PBXContainerItemProxy */;
-               };
-               DC34CD3420326C3100302481 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
-                       targetProxy = DC34CD3320326C3100302481 /* PBXContainerItemProxy */;
-               };
-               DC34CD3620326C3B00302481 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC0BCC211D8C684F00070CB0 /* utilities */;
-                       targetProxy = DC34CD3520326C3B00302481 /* PBXContainerItemProxy */;
-               };
                DC3502C41E020D4D00BC0587 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC8834011D8A218F00CE0ACA /* ASN1 */;
                        target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
                        targetProxy = DC69A5822165295F00512BD6 /* PBXContainerItemProxy */;
                };
-               DC69A5872165298500512BD6 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
-                       targetProxy = DC69A5862165298500512BD6 /* PBXContainerItemProxy */;
-               };
                DC6BC2741D90D07800DD57B3 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC6BC26C1D90CFEF00DD57B3 /* securityd_macos_startup */;
                        target = DC8834011D8A218F00CE0ACA /* ASN1 */;
                        targetProxy = DC89998A1E410DBF00E6E604 /* PBXContainerItemProxy */;
                };
-               DC93C4C9214713DC008F8362 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
-                       targetProxy = DC93C4C8214713DC008F8362 /* PBXContainerItemProxy */;
-               };
-               DC93C4CD21471401008F8362 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52E7731D80BC8000B0A59C /* libsecurityd_ios */;
-                       targetProxy = DC93C4CC21471401008F8362 /* PBXContainerItemProxy */;
-               };
                DC99B85C20EACA470065B73B /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DC8834011D8A218F00CE0ACA /* ASN1 */;
                        target = DCD66DC41D8205C400DB1393 /* SecOtrOSX */;
                        targetProxy = DCD66DE51D82061F00DB1393 /* PBXContainerItemProxy */;
                };
-               DCD6BF5421E919610015F7A8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
-                       targetProxy = DCD6BF5321E919610015F7A8 /* PBXContainerItemProxy */;
-               };
-               DCD6BF5621E9196E0015F7A8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
-                       targetProxy = DCD6BF5521E9196E0015F7A8 /* PBXContainerItemProxy */;
-               };
                DCD6BF5821E919820015F7A8 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
                        target = DCDA5E4F2124B9C5009B11B2 /* aks_support */;
                        targetProxy = DCDA5E632124BCA9009B11B2 /* PBXContainerItemProxy */;
                };
+               DCE27861245B81BD00381FE8 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 4771D971209A755800BA9772 /* KeychainDataclassOwner */;
+                       targetProxy = DCE27860245B81BD00381FE8 /* PBXContainerItemProxy */;
+               };
                DCE4E8D81D7F37F200AFB96E /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = DCE4E8931D7F34F600AFB96E /* authd */;
                        target = DC0BC5501D8B6D2D00070CB0 /* XPCKeychainSandboxCheck */;
                        targetProxy = EBD31B411E0A18A600FBE9FA /* PBXContainerItemProxy */;
                };
-               EBD7DF8121FF475B0089F2DF /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DC52E8BE1D80C25800B0A59C /* SecureObjectSyncServer */;
-                       targetProxy = EBD7DF8021FF475B0089F2DF /* PBXContainerItemProxy */;
-               };
-               EBD7DF8321FF475B0089F2DF /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = DCD8A1061E09EE0F00E4FA0A /* SecureObjectSyncFramework */;
-                       targetProxy = EBD7DF8221FF475B0089F2DF /* PBXContainerItemProxy */;
-               };
                EBF374821DC058B60065D840 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = EBF374711DC055580065D840 /* security-sysdiagnose */;
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = secdtests;
                                STRIP_STYLE = debugging;
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = secdtests;
                                STRIP_STYLE = debugging;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "keychain/otctl/otctl-Entitlements.plist";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = YES;
+                               OTHER_LDFLAGS = "";
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                        name = Debug;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "keychain/otctl/otctl-Entitlements.plist";
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = NO;
+                               OTHER_LDFLAGS = "";
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                        name = Release;
                };
-               0C9AEEB520783FBB00BF6237 /* Debug */ = {
+               0CA378E423876DD100090B7E /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               0CA378E523876DD100090B7E /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               0CCC227723F357EE00E1FCD0 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       baseConfigurationReference = 725D438D212CAA3B007B49E4 /* xcconfig/swift_binary_shim.xcconfig */;
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(SDKROOT)/../../AppleInternal/Library/Frameworks",
+                               );
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "NO_SERVER=1",
+                                       "DEBUG=1",
                                        "$(inherited)",
                                );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = "keychain/Signin Metrics/Resources/SFTMTests-Info.plist";
+                               INFOPLIST_FILE = "keychain/OctagonTrust/ot-tests/OctagonTrustTests-Info.plist";
                                INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
+                                       /AppleInternal/CoreOS/BATS/unit_tests/Frameworks/OCMockUmbrella.framework/Frameworks,
                                );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*]" = (
+                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
                                        "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
+                                       /AppleInternal/CoreOS/BATS/unit_tests/Frameworks/OCMockUmbrella.framework/Versions/A/Frameworks,
                                );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
+                               LIBRARY_SEARCH_PATHS = (
                                        "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
+                                       "$(SDKROOT)/usr/local/lib/security_libDER",
                                );
-                               MTL_ENABLE_DEBUG_INFO = YES;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                        "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
                                        "$(OTHER_LDFLAGS_MOBILEGESTALT)",
                                        "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
                                        "$(OTHER_LDFLAGS_APS)",
                                        "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
                                        "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
                                        "$(OTHER_LDFLAGS_PREQUELITE)",
                                        "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
                                        "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
                                        "-ObjC",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
                                        "$(OTHER_LDFLAGS_CORECDP)",
                                        "$(OTHER_LDFLAGS_IMCORE)",
+                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                        "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "-framework",
+                                       Security,
+                                       "$(OTHER_LDFLAGS_UserManagement)",
+                                       "$(OTHER_LDFLAGS_CLOUDSERVICES)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.SFTMTests;
+                               OTHER_SWIFT_FLAGS = "";
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.OctagonTrustTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               USE_XCTRUNNER = YES;
+                               SKIP_INSTALL = NO;
+                               SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
+                               SWIFT_OBJC_BRIDGING_HEADER = "";
+                               SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
+                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+                               SWIFT_VERSION = "";
                        };
                        name = Debug;
                };
-               0C9AEEB620783FBB00BF6237 /* Release */ = {
+               0CCC227823F357EE00E1FCD0 /* Release */ = {
                        isa = XCBuildConfiguration;
+                       baseConfigurationReference = 725D438D212CAA3B007B49E4 /* xcconfig/swift_binary_shim.xcconfig */;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
+                               FRAMEWORK_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "$(SDKROOT)/../../AppleInternal/Library/Frameworks",
+                               );
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "NO_SERVER=1",
+                                       "NDEBUG=1",
                                        "$(inherited)",
                                );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = "keychain/Signin Metrics/Resources/SFTMTests-Info.plist";
+                               INFOPLIST_FILE = "keychain/OctagonTrust/ot-tests/OctagonTrustTests-Info.plist";
                                INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
+                                       /AppleInternal/CoreOS/BATS/unit_tests/Frameworks/OCMockUmbrella.framework/Frameworks,
                                );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*]" = (
+                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
                                        "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
+                                       /AppleInternal/CoreOS/BATS/unit_tests/Frameworks/OCMockUmbrella.framework/Versions/A/Frameworks,
                                );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
+                               LIBRARY_SEARCH_PATHS = (
                                        "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
+                                       "$(SDKROOT)/usr/local/lib/security_libDER",
                                );
-                               MTL_ENABLE_DEBUG_INFO = NO;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                        "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
                                        "$(OTHER_LDFLAGS_MOBILEGESTALT)",
                                        "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
                                        "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
                                        "-ObjC",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
+                                       "$(OTHER_LDFLAGS_CORECDP)",
                                        "$(OTHER_LDFLAGS_IMCORE)",
+                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                        "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "-framework",
+                                       Security,
+                                       "$(OTHER_LDFLAGS_UserManagement)",
+                                       "$(OTHER_LDFLAGS_CLOUDSERVICES)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.SFTMTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USE_XCTRUNNER = YES;
-                               VALIDATE_PRODUCT = YES;
-                       };
-                       name = Release;
-               };
-               0CA378E423876DD100090B7E /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
-               0CA378E523876DD100090B7E /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
+                               OTHER_SWIFT_FLAGS = "";
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.OctagonTrustTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               SKIP_INSTALL = NO;
+                               SWIFT_OBJC_BRIDGING_HEADER = "";
+                               SWIFT_OBJC_INTERFACE_HEADER_NAME = "";
+                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+                               SWIFT_VERSION = "";
                        };
                        name = Release;
                };
-               0CF4064E2072E3E3003D6A7F /* Debug */ = {
+               0CD743AC23C3EC8000FA0EC5 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
                                CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "$(inherited)",
-                               );
+                               CODE_SIGN_STYLE = Automatic;
+                               CURRENT_PROJECT_VERSION = 1;
+                               DEFINES_MODULE = YES;
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               DYLIB_INSTALL_NAME_BASE = "$(INSTALL_PATH)";
+                               EXPORTED_SYMBOLS_FILE = "";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = "keychain/Signin Metrics/Resources/SFTMTests-Info.plist";
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*]" = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = YES;
+                               INFOPLIST_FILE = keychain/OctagonTrust/Info.plist;
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+                               IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+                               LD_RUNPATH_SEARCH_PATHS = "";
+                               MODULEMAP_FILE = Modules/OctagonTrust.modulemap;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
-                                       "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "$(OTHER_LDFLAGS_UPWARD_PROTOCOLBUFFER)",
+                                       "$(OTHER_LDFLAGS_UPWARD_FOUNDATION)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.SFTMTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USE_XCTRUNNER = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.octagontrust;
+                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = NO;
+                               TAPI_VERIFY_MODE = ErrorsAndWarnings;
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                               VERSIONING_SYSTEM = "apple-generic";
+                               VERSION_INFO_PREFIX = "";
                        };
                        name = Debug;
                };
-               0CF4064F2072E3E3003D6A7F /* Release */ = {
+               0CD743AD23C3EC8000FA0EC5 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
                                CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "$(inherited)",
-                               );
+                               CODE_SIGN_STYLE = Automatic;
+                               CURRENT_PROJECT_VERSION = 1;
+                               DEFINES_MODULE = YES;
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               DYLIB_INSTALL_NAME_BASE = "$(INSTALL_PATH)";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               EXPORTED_SYMBOLS_FILE = "";
+                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = "keychain/Signin Metrics/Resources/SFTMTests-Info.plist";
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*]" = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
-                               "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = (
-                                       "$(inherited)",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
+                               INFOPLIST_FILE = keychain/OctagonTrust/Info.plist;
+                               INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+                               IPHONEOS_DEPLOYMENT_TARGET = 14.0;
+                               LD_RUNPATH_SEARCH_PATHS = "";
+                               MODULEMAP_FILE = Modules/OctagonTrust.modulemap;
                                MTL_ENABLE_DEBUG_INFO = NO;
+                               MTL_FAST_MATH = YES;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_CORECDP)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-ObjC",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "$(OTHER_LDFLAGS_UPWARD_PROTOCOLBUFFER)",
+                                       "$(OTHER_LDFLAGS_UPWARD_FOUNDATION)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.SFTMTests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               USE_XCTRUNNER = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.octagontrust;
+                               PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = NO;
+                               TAPI_VERIFY_MODE = ErrorsAndWarnings;
+                               TARGETED_DEVICE_FAMILY = "1,2";
                                VALIDATE_PRODUCT = YES;
+                               VERSIONING_SYSTEM = "apple-generic";
+                               VERSION_INFO_PREFIX = "";
                        };
                        name = Release;
                };
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                        "-Wglobal-constructors",
                                        "-Wmost",
                                        "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
                                        "$(inherited)",
-                                       "-Wno-error=c++11-narrowing",
                                );
                        };
                        name = Debug;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                        "-Wglobal-constructors",
                                        "-Wmost",
                                        "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
                                        "$(inherited)",
-                                       "-Wno-error=c++11-narrowing",
                                );
                        };
                        name = Release;
                        };
                        name = Release;
                };
+               3E88360F24F068EF00E9F4D6 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
+                       };
+                       name = Debug;
+               };
+               3E88361024F068EF00E9F4D6 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "";
+                               COPY_PHASE_STRIP = NO;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator";
+                               VALIDATE_PRODUCT = YES;
+                       };
+                       name = Release;
+               };
                438169101B4EDCBD00C54D58 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionstest/seckeychainnetworkextensionstest.entitlements;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                );
                                PRODUCT_NAME = securityd;
                                STRIP_STYLE = debugging;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                );
                                PRODUCT_NAME = securityd;
                                STRIP_STYLE = debugging;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                        "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)",
                                        "$(OTHER_LDFLAGS_UserManagement)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
+                                       "$(OTHER_LDFLAGS_COREANALYTICS)",
+                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
+                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
+                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
                                        "$(OTHER_LDFLAGS_CORECDP)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                );
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                        "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)",
                                        "$(OTHER_LDFLAGS_UserManagement)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
+                                       "$(OTHER_LDFLAGS_COREANALYTICS)",
+                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
+                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
+                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
+                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
                                        "$(OTHER_LDFLAGS_CORECDP)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                );
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionsystemdaemontest/seckeychainnetworkextensionsystemdaemontest.entitlements;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = RegressionTests/seckeychainnetworkextensionunauthorizedaccesstest/seckeychainnetworkextensionunauthorizedaccesstest.entitlements;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                MTL_ENABLE_DEBUG_INFO = NO;
                4771D976209A755800BA9772 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INFOPLIST_FILE = keychain/KeychainDataclassOwner/Info.plist;
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Accounts/DataclassOwners";
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.KeychainDataclassOwner;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = iphoneos.internal;
-                               TARGETED_DEVICE_FAMILY = "1,2";
+                               TARGETED_DEVICE_FAMILY = "1,2,6";
                                WRAPPER_EXTENSION = bundle;
                        };
                        name = Debug;
                4771D977209A755800BA9772 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_STYLE = Automatic;
                                ENABLE_NS_ASSERTIONS = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INFOPLIST_FILE = keychain/KeychainDataclassOwner/Info.plist;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.KeychainDataclassOwner;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = iphoneos.internal;
-                               TARGETED_DEVICE_FAMILY = "1,2";
+                               TARGETED_DEVICE_FAMILY = "1,2,6";
                                VALIDATE_PRODUCT = YES;
                                WRAPPER_EXTENSION = bundle;
                        };
                        name = Release;
                };
-               478D429A1FD72A8100CAB645 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_MODULES = NO;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_STRICT_PROTOTYPES = NO;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "secdtests/secdtests-entitlements.plist";
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Automatic;
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = secdxctests/Info.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.secdxctests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                       };
-                       name = Debug;
-               };
-               478D429B1FD72A8100CAB645 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
-                               CLANG_ENABLE_MODULES = NO;
-                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
-                               CLANG_WARN_COMMA = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_STRICT_PROTOTYPES = NO;
-                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "secdtests/secdtests-entitlements.plist";
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Automatic;
-                               COPY_PHASE_STRIP = NO;
-                               ENABLE_NS_ASSERTIONS = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = secdxctests/Info.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@executable_path/../Frameworks",
-                                       "@loader_path/Frameworks",
-                                       "@loader_path/../Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_AKS_ACL_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.secdxctests;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               TARGETED_DEVICE_FAMILY = "1,2";
-                               VALIDATE_PRODUCT = YES;
-                       };
-                       name = Release;
-               };
                47C2F1882059CB690062DE30 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                CODE_SIGN_ENTITLEMENTS = CircleJoinRequested/entitlements.plist;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "DEBUG=1",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                CODE_SIGN_ENTITLEMENTS = CircleJoinRequested/entitlements.plist;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                HEADER_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(OTHER_LDFLAGS_SECUREKEYVAULT)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}";
                                PRODUCT_NAME = SecurityDevTests;
                                        "$(OTHER_LDFLAGS_SECUREKEYVAULT)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}";
                                PRODUCT_NAME = SecurityDevTests;
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                COPY_PHASE_STRIP = NO;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES = "";
                                HEADER_SEARCH_PATHS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = "KeychainSyncAccountNotification/KeychainSyncAccountNotification-Prefix.pch";
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = "KeychainSyncAccountNotification/KeychainSyncAccountNotification-Prefix.pch";
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "experiment/tool/experimentTool-Entitlements.plist";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "experiment/tool/experimentTool-Entitlements.plist";
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = NO;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "DEBUG=1",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                        };
                        name = Release;
                };
-               6C39237721F13E4D00D018AD /* Debug */ = {
+               6C2045EF2424BA7F00F9461D /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/KeychainStasher/KeychainStasher.entitlements";
+                               CODE_SIGN_STYLE = Automatic;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               INFOPLIST_FILE = "$(SRCROOT)/keychain/KeychainStasher/KeychainStasher-Info.plist";
+                               INSTALL_PATH = /usr/libexec;
+                               MACOSX_DEPLOYMENT_TARGET = 10.16;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainStasher;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                       };
+                       name = Debug;
+               };
+               6C2045F02424BA7F00F9461D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/KeychainStasher/KeychainStasher.entitlements";
+                               CODE_SIGN_STYLE = Automatic;
+                               ENABLE_NS_ASSERTIONS = NO;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               INFOPLIST_FILE = "$(SRCROOT)/keychain/KeychainStasher/KeychainStasher-Info.plist";
+                               INSTALL_PATH = /usr/libexec;
+                               MACOSX_DEPLOYMENT_TARGET = 10.16;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainStasher;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                       };
+                       name = Release;
+               };
+               6C39237721F13E4D00D018AD /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_MODULES = NO;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_STRICT_PROTOTYPES = NO;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = tests/SecDbBackupTests/Entitlements.plist;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
+                               CODE_SIGN_ENTITLEMENTS = "tests/SecDbBackupTests/SecDbBackupTests-Entitlements.plist";
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               DEVELOPMENT_TEAM = "";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.secdbbackuptests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               USES_XCTRUNNER = YES;
+                               REEXPORTED_LIBRARY_PATHS = "";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Debug;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = NO;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = tests/SecDbBackupTests/Entitlements.plist;
-                               CODE_SIGN_IDENTITY = "-";
-                               CODE_SIGN_STYLE = Manual;
+                               CODE_SIGN_ENTITLEMENTS = "tests/SecDbBackupTests/SecDbBackupTests-Entitlements.plist";
                                COPY_PHASE_STRIP = NO;
-                               DEVELOPMENT_TEAM = "";
                                ENABLE_NS_ASSERTIONS = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.secdbbackuptests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE_SPECIFIER = "";
-                               USES_XCTRUNNER = YES;
+                               REEXPORTED_LIBRARY_PATHS = "";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                                VALIDATE_PRODUCT = YES;
                        };
                        name = Release;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INFOPLIST_FILE = "$(SRCROOT)/supd/Tests/Info.plist";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INFOPLIST_FILE = "$(SRCROOT)/supd/Tests/Info.plist";
                        };
                        name = Release;
                };
-               6C98085F1E788AEB00E70590 /* Debug */ = {
+               6C7BE2E523C3DD64003BB2CA /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "NO_LIBTRUSTD=1",
-                                       "$(inherited)",
-                               );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CODE_SIGN_ENTITLEMENTS = SecurityTool/sharedTool/iOS/entitlements.plist;
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = YES;
+                               GCC_WARN_SHADOW = NO;
+                               INSTALL_PATH = /usr/local/bin;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
+                                       "-lsqlite3",
+                                       "-framework",
+                                       CFNetwork,
+                                       "-framework",
+                                       IOKit,
+                                       "$(OTHER_LDFLAGS_ACM_LIBRARY)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
                                        "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+                                       "$(OTHER_LDFLAGS_SECURITYFOUNDATION)",
                                        "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "-framework",
-                                       CrashReporterSupport,
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests;
-                               PRODUCT_NAME = CKKSCloudKitTests;
-                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_mac.app/Contents/MacOS/KeychainEntitledTestApp_mac";
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               REEXPORTED_LIBRARY_PATHS = "";
+                               STRIP_STYLE = debugging;
                        };
                        name = Debug;
                };
-               6C9808601E788AEB00E70590 /* Release */ = {
+               6C7BE2E623C3DD64003BB2CA /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "NO_LIBTRUSTD=1",
-                                       "$(inherited)",
-                               );
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CODE_SIGN_ENTITLEMENTS = SecurityTool/sharedTool/iOS/entitlements.plist;
+                               GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = NO;
+                               GCC_WARN_SHADOW = NO;
+                               INSTALL_PATH = /usr/local/bin;
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
+                                       "-lsqlite3",
+                                       "-framework",
+                                       CFNetwork,
+                                       "-framework",
+                                       IOKit,
+                                       "$(OTHER_LDFLAGS_ACM_LIBRARY)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
                                        "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+                                       "$(OTHER_LDFLAGS_SECURITYFOUNDATION)",
                                        "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests;
-                               PRODUCT_NAME = CKKSCloudKitTests;
-                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_mac.app/Contents/MacOS/KeychainEntitledTestApp_mac";
-                               VALIDATE_PRODUCT = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               REEXPORTED_LIBRARY_PATHS = "";
+                               STRIP_STYLE = debugging;
                        };
                        name = Release;
                };
-               6C98089B1E788AFD00E70590 /* Debug */ = {
+               6C963285242A279B00C53CE2 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "NO_LIBTRUSTD=1",
-                                       "$(inherited)",
-                               );
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/stashtester/stashtester.entitlements";
+                               CODE_SIGN_STYLE = Manual;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               DEVELOPMENT_TEAM = "";
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests;
-                               PRODUCT_NAME = CKKSCloudKitTests;
-                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_ios.app/KeychainEntitledTestApp_ios";
+                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               MACOSX_DEPLOYMENT_TARGET = 10.16;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE_SPECIFIER = "";
+                               SDKROOT = macosx.internal;
                        };
                        name = Debug;
                };
-               6C98089C1E788AFD00E70590 /* Release */ = {
+               6C963286242A279B00C53CE2 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_ENABLE_MODULES = NO;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_IDENTITY = "";
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "NO_SERVER=1",
-                                       "NO_LIBTRUSTD=1",
-                                       "$(inherited)",
-                               );
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/stashtester/stashtester.entitlements";
+                               CODE_SIGN_STYLE = Manual;
+                               DEVELOPMENT_TEAM = "";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = keychain/ckks/tests/CKKSCloudKitTestsInfo.plist;
-                               INSTALL_PATH = "$(SECURITY_XCTEST_DIRECTORY)";
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                                       "@loader_path/Frameworks",
-                               );
+                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               MACOSX_DEPLOYMENT_TARGET = 10.16;
                                MTL_ENABLE_DEBUG_INFO = NO;
-                               OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
-                                       "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
-                                       "$(OTHER_LDFLAGS_PROTOBUF)",
-                                       "$(OTHER_LDFLAGS_MOBILEGESTALT)",
-                                       "$(OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT)",
-                                       "$(OTHER_LDFLAGS_APPLESYSTEMINFO)",
-                                       "$(OTHER_LDFLAGS_APS)",
-                                       "$(OTHER_LDFLAGS_CLOUDKIT)",
-                                       "$(OTHER_LDFLAGS_PREQUELITE)",
-                                       "$(OTHER_LDFLAGS_WIRELESSDIAGNOSTICS)",
-                                       "$(OTHER_LDFLAGS_SHAREDWEBCREDENTIALS)",
-                                       "$(OTHER_LDFLAGS_CrashReporterSupport)",
-                                       "$(OTHER_LDFLAGS_IMCORE)",
-                                       "$(OTHER_LDFLAGS_ACCOUNTS)",
-                                       "$(OTHER_LDFLAGS_UserManagement)",
-                                       "$(OTHER_LDFLAGS_FOR_SECURITYD)",
-                               );
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.CKKSCloudKitTests;
-                               PRODUCT_NAME = CKKSCloudKitTests;
-                               TEST_HOST = "$(BUILT_PRODUCTS_DIR)/KeychainEntitledTestApp_ios.app/KeychainEntitledTestApp_ios";
-                               VALIDATE_PRODUCT = YES;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               PROVISIONING_PROFILE_SPECIFIER = "";
+                               SDKROOT = macosx.internal;
                        };
                        name = Release;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements";
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(PLATFORM_DIR)/Developer/Library/Frameworks",
-                                       "$(PLATFORM_DIR)/Developer/AppleInternal/Library/Frameworks",
-                               );
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               FRAMEWORK_SEARCH_PATHS = "$(inherited)";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        /Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Debug;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements";
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(PLATFORM_DIR)/Developer/Library/Frameworks",
-                                       "$(PLATFORM_DIR)/Developer/AppleInternal/Library/Frameworks",
-                               );
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               FRAMEWORK_SEARCH_PATHS = "$(inherited)";
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        /Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Release;
                };
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements";
                                COMBINE_HIDPI_IMAGES = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = KeychainEntitledTestApp_mac/Info.plist;
-                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               INFOPLIST_FILE = "$(SOURCE_ROOT)/tests/TestHostBinaries/KeychainEntitledTestApp/Info.plist";
+                               INFOPLIST_PREPROCESS = YES;
+                               INSTALL_PATH = /AppleInternal/Applications;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "@executable_path/../Frameworks",
                                );
                                MTL_ENABLE_DEBUG_INFO = YES;
                                OTHER_CODE_SIGN_FLAGS = "--deep";
-                               PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-mac";
+                               OTHER_LDFLAGS = "$(OTHER_LDFLAGS_AppFrameworks)";
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainEntitledTestApp;
                                PRODUCT_NAME = KeychainEntitledTestApp;
                        };
                        name = Debug;
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements";
                                COMBINE_HIDPI_IMAGES = YES;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               INFOPLIST_FILE = KeychainEntitledTestApp_mac/Info.plist;
-                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
+                               INSTALL_PATH = /AppleInternal/Applications;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "@executable_path/../Frameworks",
                                );
                                MTL_ENABLE_DEBUG_INFO = NO;
                                OTHER_CODE_SIGN_FLAGS = "--deep";
-                               PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-mac";
+                               OTHER_LDFLAGS = "$(OTHER_LDFLAGS_AppFrameworks)";
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainEntitledTestApp;
                                PRODUCT_NAME = KeychainEntitledTestApp;
                        };
                        name = Release;
                };
-               6CF4A0F51E4549F300ECD7B5 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
-                               DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               INFOPLIST_FILE = KeychainEntitledTestApp_ios/Info.plist;
-                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.0;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = YES;
-                               OTHER_CODE_SIGN_FLAGS = "--deep";
-                               PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-ios";
-                               PRODUCT_NAME = KeychainEntitledTestApp;
-                               VALIDATE_PRODUCT = NO;
-                       };
-                       name = Debug;
-               };
-               6CF4A0F61E4549F300ECD7B5 /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
-                               CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
-                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
-                               CLANG_WARN_UNREACHABLE_CODE = YES;
-                               CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist";
-                               COPY_PHASE_STRIP = NO;
-                               ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
-                               INFOPLIST_FILE = KeychainEntitledTestApp_ios/Info.plist;
-                               INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
-                               IPHONEOS_DEPLOYMENT_TARGET = 11.0;
-                               LD_RUNPATH_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "@executable_path/Frameworks",
-                               );
-                               MTL_ENABLE_DEBUG_INFO = NO;
-                               OTHER_CODE_SIGN_FLAGS = "--deep";
-                               PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.KeychainEntitledTestApp-ios";
-                               PRODUCT_NAME = KeychainEntitledTestApp;
-                               VALIDATE_PRODUCT = NO;
-                       };
-                       name = Release;
-               };
                7913B20D0D172B3900601FE9 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = DCC1849220EEEC4400F3B26C /* security_framework.xcconfig */;
                        buildSettings = {
+                               CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
                                COMBINE_HIDPI_IMAGES = YES;
                                DEAD_CODE_STRIPPING = YES;
                                DEFINES_MODULE = YES;
                        isa = XCBuildConfiguration;
                        baseConfigurationReference = DCC1849220EEEC4400F3B26C /* security_framework.xcconfig */;
                        buildSettings = {
+                               CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = NO;
                                COMBINE_HIDPI_IMAGES = YES;
                                DEAD_CODE_STRIPPING = YES;
                                DEFINES_MODULE = YES;
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                        buildSettings = {
                                APPLY_RULES_IN_COPY_FILES = YES;
                                CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++14";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_STATIC_ANALYZER_MODE = shallow;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
                                CLANG_WARN_EMPTY_BODY = YES;
                                CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_SUSPICIOUS_MOVE = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
                                EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(SRCROOT)/sslViewer/ecc-secp256r1-client.pfx";
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "$(inherited)",
                                );
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
                                GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES = NO;
                                INSTALL_DAEMON_AGENT_DIR = "$(SYSTEM_LIBRARY_DIR)/LaunchDaemons";
                                "INSTALL_DAEMON_AGENT_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/LaunchAgents";
-                               LLVM_LTO = YES_THIN;
+                               LLVM_LTO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                OTHER_LDFLAGS = "";
+                               RUN_CLANG_STATIC_ANALYZER = YES;
                                SDKROOT = macosx.internal;
                                SECURITY_FRAMEWORK_RESOURCES_DIR = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/";
                                "SECURITY_FRAMEWORK_RESOURCES_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Versions/A/Resources";
                                SERVICETYPE_USER_OR_SYSTEM = System;
                                "SERVICETYPE_USER_OR_SYSTEM[sdk=macosx*]" = User;
                                STRIP_INSTALLED_PRODUCT = NO;
-                               SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchos macosx appletvos appletvsimulator watchsimulator";
+                               SUPPORTED_PLATFORMS = "bridgeos iphoneos iphonesimulator macosx appletvos appletvsimulator watchos watchsimulator";
                                SUPPORTS_TEXT_BASED_API = YES;
                                Sim_Name = "";
                                "Sim_Name[sdk=embeddedsimulator*][arch=*]" = _sim;
                        buildSettings = {
                                APPLY_RULES_IN_COPY_FILES = YES;
                                CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++14";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_STATIC_ANALYZER_MODE = shallow;
                                CLANG_WARN_COMMA = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
                                CLANG_WARN_EMPTY_BODY = YES;
                                CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_INFINITE_RECURSION = YES;
                                CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
                                CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
                                CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+                               CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
                                CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
                                CLANG_WARN_STRICT_PROTOTYPES = YES;
                                CLANG_WARN_SUSPICIOUS_MOVE = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS = "$(SRCROOT)/sslViewer/ecc-secp256r1-client.pfx";
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_OPTIMIZATION_LEVEL = s;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "$(inherited)",
                                );
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
-                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
                                GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                "INSTALL_DAEMON_AGENT_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/LaunchAgents";
                                LLVM_LTO = YES;
                                OTHER_LDFLAGS = "";
+                               RUN_CLANG_STATIC_ANALYZER = YES;
                                SDKROOT = macosx.internal;
                                SECURITY_FRAMEWORK_RESOURCES_DIR = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/";
                                "SECURITY_FRAMEWORK_RESOURCES_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Versions/A/Resources";
                                "SECURITY_FRAMEWORK_XPCSERVICES_DIR[sdk=macosx*]" = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Versions/A/XPCServices";
                                SERVICETYPE_USER_OR_SYSTEM = System;
                                "SERVICETYPE_USER_OR_SYSTEM[sdk=macosx*]" = User;
-                               SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchos macosx appletvos appletvsimulator watchsimulator";
+                               SUPPORTED_PLATFORMS = "bridgeos iphoneos iphonesimulator macosx appletvos appletvsimulator watchos watchsimulator";
                                SUPPORTS_TEXT_BASED_API = YES;
                                SWIFT_COMPILATION_MODE = wholemodule;
                                Sim_Name = "";
                        baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        COM_APPLE_SECURITY_SANE_INCLUDES,
                                        "$(inherited)",
                        baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        COM_APPLE_SECURITY_SANE_INCLUDES,
                                        "$(inherited)",
                                ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
                                AXLE_ENABLE_DEBUG_INFO = YES;
                                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_ASSIGN_ENUM = YES;
                                CODE_SIGN_ENTITLEMENTS = "$(TARGET_NAME)/entitlements.plist";
                                "CODE_SIGN_IDENTITY[sdk=embedded*]" = "-";
                                COMBINE_HIDPI_IMAGES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = "$(TARGET_NAME)/$(TARGET_NAME)-Prefix.pch";
                                        "$(inherited)",
                                );
                                GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
                                AXLE_ENABLE_DEBUG_INFO = NO;
                                CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_ASSIGN_ENUM = YES;
                                "CODE_SIGN_IDENTITY[sdk=embedded*]" = "-";
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = "$(TARGET_NAME)/$(TARGET_NAME)-Prefix.pch";
-                               GCC_WARN_ABOUT_MISSING_NEWLINE = NO;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                        "$(SDKROOT)/usr/local/lib/security_libDER",
                                );
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
                                        "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
                                        "$(OTHER_LDFLAGS_MOBILEGESTALT)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                        "-framework",
                                        Security,
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeersHelperUnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                        "$(SDKROOT)/usr/local/lib/security_libDER",
                                );
                                OTHER_LDFLAGS = (
-                                       "$(OTHER_LDFLAGS_AKS_LIBRARY)",
                                        "$(OTHER_LDFLAGS_APPLEIDAUTHSUPPORT)",
                                        "$(OTHER_LDFLAGS_PROTOBUF)",
                                        "$(OTHER_LDFLAGS_MOBILEGESTALT)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                        "-framework",
                                        Security,
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustedPeersHelperUnitTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                };
                BEF88C391EAFFC4000357577 /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                };
                BEF88C3A1EAFFC4000357577 /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = BE8351D41EC0EEDD00ACD5FD /* framework_requiring_modern_objc_runtime.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                OTHER_LDFLAGS = (
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = trustd;
                                STRIP_STYLE = debugging;
                                OTHER_LDFLAGS = (
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = trustd;
                                STRIP_STYLE = debugging;
                                OTHER_LDFLAGS = (
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustTests;
                                PRODUCT_NAME = TrustTests;
                                OTHER_LDFLAGS = (
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustTests;
                                PRODUCT_NAME = TrustTests;
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "@executable_path/Frameworks",
+                                       /Developer/Library/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
                                MTL_FAST_MATH = YES;
                                ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "@executable_path/Frameworks",
+                                       /Developer/Library/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = NO;
                                MTL_FAST_MATH = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CODE_SIGN_ENTITLEMENTS = tests/TrustTests/TestRunners/trusttests_entitlements.plist;
                                CODE_SIGN_STYLE = Automatic;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(PLATFORM_DIR)/Developer/Library/Frameworks",
-                                       "$(PLATFORM_DIR)/Developer/AppleInternal/Library/Frameworks",
-                               );
+                               ENABLE_TESTING_SEARCH_PATHS = YES;
+                               FRAMEWORK_SEARCH_PATHS = "$(inherited)";
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INFOPLIST_FILE = tests/TrustTests/TestRunners/Info.plist;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        /Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
                                MTL_FAST_MATH = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Debug;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CODE_SIGN_ENTITLEMENTS = tests/TrustTests/TestRunners/trusttests_entitlements.plist;
                                CODE_SIGN_STYLE = Automatic;
                                ENABLE_NS_ASSERTIONS = NO;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(PLATFORM_DIR)/Developer/Library/Frameworks",
-                                       "$(PLATFORM_DIR)/Developer/AppleInternal/Library/Frameworks",
-                               );
+                               ENABLE_TESTING_SEARCH_PATHS = YES;
+                               FRAMEWORK_SEARCH_PATHS = "$(inherited)";
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INFOPLIST_FILE = tests/TrustTests/TestRunners/Info.plist;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                LD_RUNPATH_SEARCH_PATHS = (
                                        /Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks,
-                                       /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/Frameworks,
+                                       /AppleInternal/Developer/Library/Frameworks,
                                );
                                MTL_ENABLE_DEBUG_INFO = NO;
                                MTL_FAST_MATH = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                TARGETED_DEVICE_FAMILY = "1,2";
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                                VALIDATE_PRODUCT = YES;
                        };
                        name = Release;
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_OCMOCK)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustTests;
                                PRODUCT_NAME = TrustTests;
                                        "$(OTHER_LDFLAGS_MOBILEASSET)",
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_OCMOCK)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.TrustTests;
                                PRODUCT_NAME = TrustTests;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        };
                };
                DC0BC9CD1D8B824700070CB0 /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_ENUM_CONVERSION = NO;
                };
                DC0BC9CE1D8B824700070CB0 /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_ENUM_CONVERSION = NO;
                                SKIP_INSTALL = YES;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
-                                       "-Wno-int-to-void-pointer-cast",
                                        "-Wno-sign-compare",
                                );
                        };
                                SKIP_INSTALL = YES;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
-                                       "-Wno-int-to-void-pointer-cast",
                                        "-Wno-sign-compare",
                                );
                        };
                        baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        COM_APPLE_SECURITY_SANE_INCLUDES,
                                        "$(inherited)",
                        baseConfigurationReference = DC0067911D87816C005AF8DB /* macos_legacy_lib.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu11;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        COM_APPLE_SECURITY_SANE_INCLUDES,
                                        "$(inherited)",
                };
                DC0BCC341D8C684F00070CB0 /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                GCC_WARN_SHADOW = NO;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
                                STRIP_INSTALLED_PRODUCT = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-unused-function",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                DC0BCC351D8C684F00070CB0 /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                GCC_WARN_SHADOW = NO;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
                                STRIP_INSTALLED_PRODUCT = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-unused-function",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
                                        "-Wno-sign-compare",
-                                       "-Wno-unused-function",
                                );
                        };
                        name = Debug;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
                                        "-Wno-sign-compare",
-                                       "-Wno-unused-function",
                                );
                        };
                        name = Release;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++98";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++98";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ORDER_FILE = securityd/src/securityd.order;
-                               OTHER_CPLUSPLUSFLAGS = (
-                                       "$(OTHER_CFLAGS)",
-                                       "-Wno-deprecated-register",
-                               );
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
                                PRODUCT_NAME = securityd;
                                SUPPORTED_PLATFORMS = macosx;
                        };
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                ORDER_FILE = securityd/src/securityd.order;
-                               OTHER_CPLUSPLUSFLAGS = (
-                                       "$(OTHER_CFLAGS)",
-                                       "-Wno-deprecated-register",
-                               );
+                               OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)";
                                PRODUCT_NAME = securityd;
                                SUPPORTED_PLATFORMS = macosx;
                        };
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                        "$(OTHER_LDFLAGS_IMCORE)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = secdtests;
                                STRIP_STYLE = debugging;
                                        "$(OTHER_LDFLAGS_IMCORE)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_NAME = secdtests;
                                STRIP_STYLE = debugging;
                };
                DC8834061D8A218F00CE0ACA /* Debug */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ENABLE_MODULES = NO;
                };
                DC8834071D8A218F00CE0ACA /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = D47C56FB1DCA8F4900E18518 /* all_arches.xcconfig */;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ENABLE_MODULES = NO;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-switch",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)";
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-switch",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                                APPLY_RULES_IN_COPY_FILES = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
-                               CLANG_WARN_ENUM_CONVERSION = NO;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                HEADER_SEARCH_PATHS = (
                                MTL_ENABLE_DEBUG_INFO = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=c++11-narrowing",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                APPLY_RULES_IN_COPY_FILES = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_WARN_DOCUMENTATION_COMMENTS = NO;
-                               CLANG_WARN_ENUM_CONVERSION = NO;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                HEADER_SEARCH_PATHS = (
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = NO;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=c++11-narrowing",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
                                        "-Wno-sign-compare",
-                                       "-Wno-deprecated-register",
                                );
                        };
                        name = Debug;
                                WARNING_CFLAGS = (
                                        "$(inherited)",
                                        "-Wno-sign-compare",
-                                       "-Wno-deprecated-register",
                                );
                        };
                        name = Release;
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                );
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
                                );
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                INSTALL_PATH = /usr/libexec;
                                MTL_ENABLE_DEBUG_INFO = YES;
-                               PRODUCT_NAME = trustd;
-                               WARNING_CFLAGS = (
-                                       "-Wextra",
-                                       "-Wno-unused-parameter",
-                                       "-Wno-missing-field-initializers",
-                                       "-Wno-error=deprecated-declarations",
+                               OTHER_LDFLAGS = (
+                                       "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
+                               PRODUCT_NAME = trustd;
                        };
                        name = Debug;
                };
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
-                               GCC_WARN_UNUSED_FUNCTION = NO;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
                                INSTALL_PATH = /usr/libexec;
                                MTL_ENABLE_DEBUG_INFO = NO;
-                               PRODUCT_NAME = trustd;
-                               WARNING_CFLAGS = (
-                                       "-Wextra",
-                                       "-Wno-unused-parameter",
-                                       "-Wno-missing-field-initializers",
-                                       "-Wno-error=deprecated-declarations",
+                               OTHER_LDFLAGS = (
+                                       "$(OTHER_LDFLAGS_IMG4DECODE)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
+                               PRODUCT_NAME = trustd;
                        };
                        name = Release;
                };
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               GCC_WARN_UNINITIALIZED_AUTOS = NO;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
                                INFOPLIST_FILE = OSX/authd/Info.plist;
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Versions/${FRAMEWORK_VERSION}/XPCServices";
                                MTL_ENABLE_DEBUG_INFO = YES;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
-                               GCC_WARN_UNINITIALIZED_AUTOS = NO;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
                                INFOPLIST_FILE = OSX/authd/Info.plist;
                                INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/Versions/${FRAMEWORK_VERSION}/XPCServices";
                                MTL_ENABLE_DEBUG_INFO = NO;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_MODULES = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                EXECUTABLE_PREFIX = lib;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                                       "@loader_path/Frameworks",
+                               );
                                MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
                                MTL_FAST_MATH = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
+                               SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+                               SWIFT_VERSION = 5.0;
                        };
                        name = Debug;
                };
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_MODULES = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                EXECUTABLE_PREFIX = lib;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               LD_RUNPATH_SEARCH_PATHS = (
+                                       "$(inherited)",
+                                       "@executable_path/Frameworks",
+                                       "@loader_path/Frameworks",
+                               );
                                MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                MTL_FAST_MATH = YES;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SKIP_INSTALL = YES;
+                               SWIFT_VERSION = 5.0;
                        };
                        name = Release;
                };
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_MODULES = NO;
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}";
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                        "$(OTHER_LDFLAGS_IMG4DECODE)",
                                        "$(OTHER_LDFLAGS_MOBILE_KEYBAG)",
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MSUDATAACCESSOR)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = "com.apple.security.${PRODUCT_NAME:identifier}";
                                PRODUCT_NAME = "$(TARGET_NAME)";
                E7B01BF0166594AB000485F1 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_PRECOMPILE_PREFIX_HEADER = NO;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                E7B01BF1166594AB000485F1 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                COMBINE_HIDPI_IMAGES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_PRECOMPILE_PREFIX_HEADER = NO;
                                HEADER_SEARCH_PATHS = (
                                        "$(inherited)",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DYLIB_CURRENT_VERSION = 1;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                FRAMEWORK_VERSION = A;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "DEBUG=1",
                                TAPI_VERIFY_MODE = ErrorsOnly;
                                VERSIONING_SYSTEM = "apple-generic";
                                VERSION_INFO_PREFIX = "";
-                               WARNING_CFLAGS = "-Wno-objc-designated-initializers";
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                FRAMEWORK_VERSION = A;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUGGING_SYMBOLS = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
                                GCC_NO_COMMON_BLOCKS = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_MODULES = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                DYLIB_COMPATIBILITY_VERSION = 1;
                                DYLIB_CURRENT_VERSION = 1;
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                DYLIB_CURRENT_VERSION = 1;
                                ENABLE_NS_ASSERTIONS = NO;
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO;
                                INSTALL_PATH = "$(SECURITY_FUZZER_BASE_DIR)/lib";
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                COMBINE_HIDPI_IMAGES = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SUPPORTS_TEXT_BASED_API = YES;
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Debug;
                };
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.security.KeychainCircle.KeychainCircleTests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SUPPORTS_TEXT_BASED_API = YES;
+                               TEST_BUILD_STYLE = _APPLEINTERNAL;
                        };
                        name = Release;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "keychain/ckksctl/ckksctl-Entitlements.plist";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "keychain/ckksctl/ckksctl-Entitlements.plist";
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/sbin;
                                MTL_ENABLE_DEBUG_INFO = NO;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                        "-framework",
                                        Security,
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.Security.secdmockaks;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
                                CLANG_WARN_COMMA = YES;
                                        "-framework",
                                        Security,
                                        "$(OTHER_LDFLAGS_FOR_SECURITYD)",
+                                       "$(OTHER_LDFLAGS_MOCK_AKS_LIBRARY)",
                                );
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.Security.secdmockaks;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = YES;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = YES;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
                                CLANG_ENABLE_OBJC_WEAK = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = YES;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Debug;
                };
                                REEXPORTED_LIBRARY_NAMES = "";
                                STRIP_STYLE = debugging;
                                USE_HEADERMAP = YES;
-                               WARNING_CFLAGS = (
-                                       "$(inherited)",
-                                       "-Wno-error=modules-ambiguous-internal-linkage",
-                               );
+                               WARNING_CFLAGS = "$(inherited)";
                        };
                        name = Release;
                };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = "$(SECURITY_FUZZER_BASE_DIR)";
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = "$(SECURITY_FUZZER_BASE_DIR)";
                                MTL_ENABLE_DEBUG_INFO = NO;
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
                                ENABLE_TESTABILITY = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                        baseConfigurationReference = DCE4E82B1D7A54D300AFB96E /* ios_on_macos.xcconfig */;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
                                ENABLE_NS_ASSERTIONS = NO;
                                ENABLE_STRICT_OBJC_MSGSEND = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_SUSPICIOUS_MOVES = YES;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                CODE_SIGN_ENTITLEMENTS = "security-sysdiagnose/security-sysdiagnose.entitlements.plist";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/libexec;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CODE_SIGN_ENTITLEMENTS = "security-sysdiagnose/security-sysdiagnose.entitlements.plist";
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /usr/libexec;
                                MTL_ENABLE_DEBUG_INFO = NO;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++98";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
-                               CLANG_CXX_LANGUAGE_STANDARD = "c++98";
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_CONSTANT_CONVERSION = YES;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                DEBUG_INFORMATION_FORMAT = dwarf;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                CLANG_WARN_UNREACHABLE_CODE = YES;
                                COPY_PHASE_STRIP = NO;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                INSTALL_PATH = /AppleInternal/CoreOS/tests/Security;
                                MTL_ENABLE_DEBUG_INFO = NO;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               0C9AEEB420783FBB00BF6237 /* Build configuration list for PBXNativeTarget "SignInAnalyticsTests_osx" */ = {
+               0CA378E323876DD100090B7E /* Build configuration list for PBXAggregateTarget "reset_account" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               0C9AEEB520783FBB00BF6237 /* Debug */,
-                               0C9AEEB620783FBB00BF6237 /* Release */,
+                               0CA378E423876DD100090B7E /* Debug */,
+                               0CA378E523876DD100090B7E /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               0CA378E323876DD100090B7E /* Build configuration list for PBXAggregateTarget "reset_account" */ = {
+               0CCC227623F357EE00E1FCD0 /* Build configuration list for PBXNativeTarget "OctagonTrustTests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               0CA378E423876DD100090B7E /* Debug */,
-                               0CA378E523876DD100090B7E /* Release */,
+                               0CCC227723F357EE00E1FCD0 /* Debug */,
+                               0CCC227823F357EE00E1FCD0 /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               0CF4064D2072E3E3003D6A7F /* Build configuration list for PBXNativeTarget "SignInAnalyticsTests_ios" */ = {
+               0CD743AB23C3EC8000FA0EC5 /* Build configuration list for PBXNativeTarget "OctagonTrust" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               0CF4064E2072E3E3003D6A7F /* Debug */,
-                               0CF4064F2072E3E3003D6A7F /* Release */,
+                               0CD743AC23C3EC8000FA0EC5 /* Debug */,
+                               0CD743AD23C3EC8000FA0EC5 /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               3E88360E24F068EF00E9F4D6 /* Build configuration list for PBXNativeTarget "secseccodeapitest" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               3E88360F24F068EF00E9F4D6 /* Debug */,
+                               3E88361024F068EF00E9F4D6 /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                438169381B4EDCBD00C54D58 /* Build configuration list for PBXNativeTarget "SOSCCAuthPlugin" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               4727FBC31F9918590003AE36 /* Build configuration list for PBXNativeTarget "secdxctests_ios" */ = {
+               4727FBC31F9918590003AE36 /* Build configuration list for PBXNativeTarget "secdxctests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                4727FBBC1F9918590003AE36 /* Debug */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               478D42991FD72A8100CAB645 /* Build configuration list for PBXNativeTarget "secdxctests_mac" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               478D429A1FD72A8100CAB645 /* Debug */,
-                               478D429B1FD72A8100CAB645 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                47C2F1872059CB690062DE30 /* Build configuration list for PBXNativeTarget "KeychainResources" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               6C2045EE2424BA7F00F9461D /* Build configuration list for PBXNativeTarget "KeychainStasher" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               6C2045EF2424BA7F00F9461D /* Debug */,
+                               6C2045F02424BA7F00F9461D /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                6C39237621F13E4D00D018AD /* Build configuration list for PBXNativeTarget "SecDbBackupTests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               6C98085E1E788AEB00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_mac" */ = {
+               6C7BE2E423C3DD64003BB2CA /* Build configuration list for PBXNativeTarget "securitytool_bridge" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               6C98085F1E788AEB00E70590 /* Debug */,
-                               6C9808601E788AEB00E70590 /* Release */,
+                               6C7BE2E523C3DD64003BB2CA /* Debug */,
+                               6C7BE2E623C3DD64003BB2CA /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               6C98089A1E788AFD00E70590 /* Build configuration list for PBXNativeTarget "CKKSCloudKitTests_ios" */ = {
+               6C963288242A279B00C53CE2 /* Build configuration list for PBXNativeTarget "stashtester" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               6C98089B1E788AFD00E70590 /* Debug */,
-                               6C98089C1E788AFD00E70590 /* Release */,
+                               6C963285242A279B00C53CE2 /* Debug */,
+                               6C963286242A279B00C53CE2 /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_mac" */ = {
+               6CF4A0CC1E45488B00ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                6CF4A0C51E45488B00ECD7B5 /* Debug */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               6CF4A0F41E4549F300ECD7B5 /* Build configuration list for PBXNativeTarget "KeychainEntitledTestApp_ios" */ = {
-                       isa = XCConfigurationList;
-                       buildConfigurations = (
-                               6CF4A0F51E4549F300ECD7B5 /* Debug */,
-                               6CF4A0F61E4549F300ECD7B5 /* Release */,
-                       );
-                       defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Release;
-               };
                790851C90CA985C10083CC4D /* Build configuration list for PBXNativeTarget "securityd_ios" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
index 577b55c3ec2157a7abfbc876fc0f5f6dae384209..ac6fde2d58cbc6f704d9dd43674360ba66e39eb4 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
index 0ecee1d0459596f53538a366d836ff1da55f10c7..9c9e101dfc25f40c7cd8ed1ba6fa0c1641800002 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
diff --git a/Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_ios.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_ios.xcscheme
new file mode 100644 (file)
index 0000000..f812cfa
--- /dev/null
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1200"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "NO"
+      buildImplicitDependencies = "NO">
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <TestPlans>
+         <TestPlanReference
+            reference = "container:OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_ios.xctestplan"
+            default = "YES">
+         </TestPlanReference>
+      </TestPlans>
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3DD1FFAC201FDB1D0086D049"
+               BuildableName = "SecureTransport_ios_tests.xctest"
+               BlueprintName = "SecureTransportTests_ios"
+               ReferencedContainer = "container:Security.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_macos.xcscheme b/Security.xcodeproj/xcshareddata/xcschemes/SecureTransportTests_macos.xcscheme
new file mode 100644 (file)
index 0000000..f2cae49
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1200"
+   version = "1.7">
+   <BuildAction
+      parallelizeBuildables = "NO"
+      buildImplicitDependencies = "NO">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "NO"
+            buildForArchiving = "NO"
+            buildForAnalyzing = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3DD1FEF5201C07F30086D049"
+               BuildableName = "SecureTransport_macos_tests.xctest"
+               BlueprintName = "SecureTransportTests_macos"
+               ReferencedContainer = "container:Security.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <TestPlans>
+         <TestPlanReference
+            reference = "container:OSX/libsecurity_ssl/regressions/SecureTransportTests/SecureTransportTests_macos.xctestplan"
+            default = "YES">
+         </TestPlanReference>
+      </TestPlans>
+      <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3DD1FEF5201C07F30086D049"
+               BuildableName = "SecureTransport_macos_tests.xctest"
+               BlueprintName = "SecureTransportTests_macos"
+               ReferencedContainer = "container:Security.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Release"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
index 51730e53983b9985a8c43ea2428c00671b8cdb83..a9b4f2f98b9293c5c06d379feccdbf586e6b6b57 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       shouldUseLaunchSchemeArgsEnv = "YES"
       codeCoverageEnabled = "YES"
       onlyGenerateCoverageForSpecifiedTargets = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "D4707A0421136E69005BCFDA"
-            BuildableName = "TrustTests.xctest"
-            BlueprintName = "TrustTests_ios"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <CodeCoverageTargets>
          <BuildableReference
             BuildableIdentifier = "primary"
index f14558e0d3b23a307fb502020f108cc5019fd2a7..d829f6b1663a43f7a22e58fbebb272e2f19111c8 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       shouldUseLaunchSchemeArgsEnv = "YES"
       codeCoverageEnabled = "YES"
       onlyGenerateCoverageForSpecifiedTargets = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "D453A4A42122236D00850A26"
-            BuildableName = "TrustTests.xctest"
-            BlueprintName = "TrustTests_macos"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <CodeCoverageTargets>
          <BuildableReference
             BuildableIdentifier = "primary"
index 52c6d628822d5f1afbf46d8dd220771cf82c954a..34e832efe1c6ad3cce912ceb81c0121a21d63ac7 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES"
       codeCoverageEnabled = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "BEF88C271EAFFC3F00357577"
-            BuildableName = "TrustedPeers.framework"
-            BlueprintName = "TrustedPeers"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
index d5c67142667dbf17aa6c3eeab45273f9bbd2f50f..fcc30b514124a6b86c03ffe6f8cedef590d4717e 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.8">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "4C711D5813AFCD0900FE865D"
-            BuildableName = "SecurityDevTests.app"
-            BlueprintName = "SecurityDevTests"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
                ReferencedContainer = "container:Security.xcodeproj">
             </BuildableReference>
          </TestableReference>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "4727FBB61F9918580003AE36"
-               BuildableName = "secdxctests_ios.xctest"
-               BlueprintName = "secdxctests_ios"
-               ReferencedContainer = "container:Security.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
          <TestableReference
             skipped = "NO">
             <BuildableReference
             argument = "si_22_sectrust_iap"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_23_sectrust_ocsp"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_24_sectrust_itms"
             isEnabled = "NO">
             argument = "si_26_sectrust_copyproperties"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_28_sectrustsettings"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_29_cms_chain_mode"
             isEnabled = "NO">
             argument = "si_66_smime"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_67_sectrust_blocklist"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_68_secmatchissuer"
             isEnabled = "NO">
             argument = "si_73_secpasswordgenerate"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_74_OTA_PKI_Signer"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_76_shared_credentials"
             isEnabled = "NO">
             argument = "si_83_seccertificate_sighashalg"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_84_sectrust_allowlist"
-            isEnabled = "NO">
-         </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_88_sectrust_valid"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_89_cms_hash_agility"
             isEnabled = "NO">
index 06344ef9ad7f0687967aa5345d6089ad92235139..9eb5f6310b2ce3ee1da005de2422f4addcf0c0ea 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "E710C7411331946400F85568"
-            BuildableName = "SecurityTests.app"
-            BlueprintName = "SecurityTests"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
             argument = "si_22_sectrust_iap"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_23_sectrust_ocsp"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si-23-sectrust-ocsp-wwdr"
             isEnabled = "NO">
             argument = "si_26_sectrust_copyproperties"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_28_sectrustsettings"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_29_cms_chain_mode"
             isEnabled = "NO">
             argument = "si_66_smime"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_67_sectrust_blocklist"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_68_secmatchissuer"
             isEnabled = "NO">
             argument = "si_73_secpasswordgenerate"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_74_OTA_PKI_Signer"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_76_shared_credentials"
             isEnabled = "NO">
             argument = "si_83_seccertificate_sighashalg"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_84_sectrust_allowlist"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_87_sectrust_name_constraints"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_88_sectrust_valid"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_89_cms_hash_agility"
             isEnabled = "NO">
index cf5cb28f9ffa2bd44de96c89a0e5177b82a3b81b..15062dd98475fb31c35ddc7975427f70c65a8d9a 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "2.0">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "0C0BDB2E175685B000BC1A7E"
-            BuildableName = "secdtests"
-            BlueprintName = "secdtests_ios"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
             <BuildableReference
                BuildableIdentifier = "primary"
                BlueprintIdentifier = "4727FBB61F9918580003AE36"
-               BuildableName = "secdxctests_ios.xctest"
-               BlueprintName = "secdxctests_ios"
+               BuildableName = "secdxctests.xctest"
+               BlueprintName = "secdxctests"
                ReferencedContainer = "container:Security.xcodeproj">
             </BuildableReference>
          </TestableReference>
index cb70464e3ab66128eb1c69764ee8977dce6b496e..09e298ee544b26d5746699b015e9314d78c9a0fc 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "DCE4E7311D7A43B500AFB96E"
-            BuildableName = "SecurityTestsOSX.app"
-            BlueprintName = "SecurityTestsOSX"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
                ReferencedContainer = "container:Security.xcodeproj">
             </BuildableReference>
          </TestableReference>
-         <TestableReference
-            skipped = "NO">
-            <BuildableReference
-               BuildableIdentifier = "primary"
-               BlueprintIdentifier = "478D426C1FD72A8100CAB645"
-               BuildableName = "secdxctests_mac.xctest"
-               BlueprintName = "secdxctests_mac"
-               ReferencedContainer = "container:Security.xcodeproj">
-            </BuildableReference>
-         </TestableReference>
          <TestableReference
             skipped = "NO">
             <BuildableReference
                ReferencedContainer = "container:Security.xcodeproj">
             </BuildableReference>
          </TestableReference>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "4727FBB61F9918580003AE36"
+               BuildableName = "secdxctests.xctest"
+               BlueprintName = "secdxctests"
+               ReferencedContainer = "container:Security.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
    </TestAction>
    <LaunchAction
             argument = "smime_cms_test"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "bc_10_password"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "kc_40_seckey"
             isEnabled = "NO">
             argument = "si_22_sectrust_iap"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_23_sectrust_ocsp"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_24_sectrust_itms"
             isEnabled = "NO">
             argument = "si_26_sectrust_copyproperties"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_28_sectrustsettings"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_29_cms_chain_mode"
             isEnabled = "NO">
             argument = "si_68_secmatchissuer"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_67_sectrust_blocklist"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_70_sectrust_unified"
             isEnabled = "NO">
             argument = "si_71_mobile_store_policy"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_74_OTA_PKI_Signer"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_83_seccertificate_sighashalg"
             isEnabled = "NO">
          </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_84_sectrust_allowlist"
-            isEnabled = "NO">
-         </CommandLineArgument>
-         <CommandLineArgument
-            argument = "si_88_sectrust_valid"
-            isEnabled = "NO">
-         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_89_cms_hash_agility"
             isEnabled = "NO">
index 034c0652363faa5987811bf6ca2881ea658b7d48..d10c4ae2a339dfef4c891cdf32f3c56521f120ae 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "DC610A021D78F129002223DE"
-            BuildableName = "secdtests"
-            BlueprintName = "secdtests_macos"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
          <TestableReference
             skipped = "NO">
             argument = "secd_61_account_leave_not_in_kansas_anymore"
             isEnabled = "NO">
          </CommandLineArgument>
+         <CommandLineArgument
+            argument = "secd_68_fullPeerInfoIntegrity"
+            isEnabled = "NO">
+         </CommandLineArgument>
          <CommandLineArgument
             argument = "secd_70_engine"
             isEnabled = "NO">
             argument = "secd_71_engine_save"
             isEnabled = "NO">
          </CommandLineArgument>
+         <CommandLineArgument
+            argument = "secd_74_engine_beer_servers"
+            isEnabled = "NO">
+         </CommandLineArgument>
          <CommandLineArgument
             argument = "secd_76_idstransport"
             isEnabled = "NO">
             isEnabled = "NO">
          </CommandLineArgument>
       </CommandLineArguments>
+      <EnvironmentVariables>
+         <EnvironmentVariable
+            key = ""
+            value = ""
+            isEnabled = "YES">
+         </EnvironmentVariable>
+         <EnvironmentVariable
+            key = ""
+            value = ""
+            isEnabled = "YES">
+         </EnvironmentVariable>
+      </EnvironmentVariables>
    </LaunchAction>
    <ProfileAction
       buildConfiguration = "Release"
index a64e3fd148f8c68adab0b9cead97a11e535b72f4..63cde06592c975f1e42f6db303f482405557d6d3 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
-      <MacroExpansion>
-         <BuildableReference
-            BuildableIdentifier = "primary"
-            BlueprintIdentifier = "DCE4E7CB1D7A4AED00AFB96E"
-            BuildableName = "sectests"
-            BlueprintName = "sectests_macos"
-            ReferencedContainer = "container:Security.xcodeproj">
-         </BuildableReference>
-      </MacroExpansion>
       <Testables>
       </Testables>
    </TestAction>
index ac9beb1a97a88d2e0fa92ee2237780a234bba7c5..69540ff7217eb9e97f3dfd7ae22d5ca9bb454dd3 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1120"
+   LastUpgradeVersion = "1200"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "NO"
index b116d81220c88dca188b2411ccbef56ad5c7d6cd..ed5e504a56abd0cf22fb78030f305f7e6a33ded9 100644 (file)
                <string>123456.test.group</string>
                <string>123456.test.group2</string>
                <string>com.apple.bluetooth</string>
+               <string>com.apple.token</string>
        </array>
        <key>com.apple.developer.associated-domains</key>
        <array>
                <string>webcredentials:localhost</string>
        </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_Root.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_Root.cer
new file mode 100644 (file)
index 0000000..70cd962
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_Root.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_ca.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_ca.cer
new file mode 100644 (file)
index 0000000..f32740d
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_ca.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_leaf.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_leaf.cer
new file mode 100644 (file)
index 0000000..bdb982a
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_anyEKU_leaf.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_ca.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_ca.cer
new file mode 100644 (file)
index 0000000..c223669
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_ca.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_leaf.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_leaf.cer
new file mode 100644 (file)
index 0000000..b5763b8
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_noEKU_leaf.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_smime_ca.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_smime_ca.cer
new file mode 100644 (file)
index 0000000..7342c2f
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_smime_ca.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_smime_leaf.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_smime_leaf.cer
new file mode 100644 (file)
index 0000000..0a1651c
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_smime_leaf.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_ca.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_ca.cer
new file mode 100644 (file)
index 0000000..58ed701
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_ca.cer differ
diff --git a/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_leaf.cer b/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_leaf.cer
new file mode 100644 (file)
index 0000000..8531402
Binary files /dev/null and b/SecurityTests/ssl-policy-certs/subCA_EKU_ssl_leaf.cer differ
index 00208dd4c75ca7a338f994049cbe1b140ecb1925..de5579f70e64c241dd20b42841bbf3a96a44107c 100644 (file)
@@ -678,10 +678,11 @@ authorize(int argc, char * const *argv)
 
     retval = (status ? -1 : 0);
 bail:
-    if (rights)
+    if (rights) {
         free(rights);
-    
-       return retval;
+    }
+
+    return retval;
 }
 
 
index 36671610c8b0405e9bde22bffe4ed86a23979813..9965ce025b480323b45a8ab91c7e00c7d49981cf 100644 (file)
@@ -101,8 +101,11 @@ OSStatus makeMasterPassword(const char *fvmkcName, const char *masterPasswordPas
     OSStatus status = SecKeychainCreate(fvmkcName, (UInt32) strlen(masterPasswordPassword), masterPasswordPassword, false, initialAccess, keychainRef);
     if (status!=noErr)
     {
-               if (status==errSecDuplicateKeychain || status==CSSMERR_DL_DATASTORE_ALREADY_EXISTS)
+        if (status==errSecDuplicateKeychain || status==CSSMERR_DL_DATASTORE_ALREADY_EXISTS) {
             sec_error("The keychain file %s already exists", fvmkcName);
+        } else if (status != errSecSuccess) {
+            sec_error("Could not create keychain file %s: %s", fvmkcName, sec_errstr(status));
+        }
         return status;
     }
 
@@ -199,18 +202,24 @@ OSStatus createPair(CFStringRef hostName,CFStringRef userName,SecKeychainRef key
 
     // cleanup
 xit:
-    if (certRef)
+    if (certRef) {
         CFRelease(certRef);
-    if (certData.Data)
+    }
+    if (certData.Data) {
         free(certData.Data);
-       if (hostStr)
-               free(hostStr);
-       if (userStr)
-               free(userStr);
-       if (tpHand)
-               CSSM_ModuleDetach(tpHand);
-       if (clHand)
-               CSSM_ModuleDetach(clHand);
+    }
+    if (hostStr) {
+        free(hostStr);
+    }
+    if (userStr) {
+        free(userStr);
+    }
+    if (tpHand) {
+        CSSM_ModuleDetach(tpHand);
+    }
+    if (clHand) {
+        CSSM_ModuleDetach(clHand);
+    }
        if (pubKey)
     {
                CSSM_FreeKey(cspHand,
@@ -707,8 +716,9 @@ keychain_createMFV(int argc, char * const *argv)
         return SHOW_USAGE_MESSAGE;
 
     keychainName = (argc == 1)?*argv:_masterKeychainName;
-    if (!keychainName || *keychainName == '\0')
+    if (!keychainName || *keychainName == '\0') {
         return -1;
+    }
 
        if (!password && !do_prompt)
        {
index 381501f9bf1d5b59363713f295b95f18431d2a43..89655f697392e2b718890b1c81db20a34bd0e44f 100644 (file)
@@ -43,7 +43,7 @@ do_db_create(const CSSM_GUID guid, const char *dbname, Boolean do_openparams, Bo
        try
        {
                CSSM_APPLEDL_OPEN_PARAMETERS openParameters = { sizeof(CSSM_APPLEDL_OPEN_PARAMETERS),
-                       (do_version_0_params ? 0 : CSSM_APPLEDL_OPEN_PARAMETERS_VERSION) };
+                       (do_version_0_params ? 0u : CSSM_APPLEDL_OPEN_PARAMETERS_VERSION) };
                Cssm cssm;
                Module module(guid, cssm);
                DL dl(module);
index 1b3e562ff7c60fe91a53f3a639339e7661df1f57..932361ed65dd1a700c7da934dbd88257b709db9e 100644 (file)
@@ -391,7 +391,7 @@ do_identity_search_with_policy(CFTypeRef keychainOrArray,
 
        safe_CFRelease(&idStr);
        safe_CFRelease(&policy);
-       safe_CFRelease(policySearch);
+       safe_CFRelease(&policySearch);
 }
 
 static void
index e14f64d26d7898f4f1a86806ab92b860b4316f9f..8e5688f7d4998b6938cdf08354c0ed11b538e9a8 100644 (file)
@@ -163,11 +163,13 @@ parse_time(const char *time, CFAbsoluteTime *ptime)
                sec_error("%s is not a valid date", time);
                result = 1;
        }
-    if (formatter)
+    if (formatter) {
         CFRelease(formatter);
-    if (time_string)
+    }
+    if (time_string) {
         CFRelease(time_string);
-       return result;
+    }
+    return result;
 }
 
 int
index 506ea3a0fdf9b82371528aeea95496ef689f0833..cd5dc33e5e655fd3135e3ca2b45b5386336f32af 100644 (file)
@@ -764,14 +764,17 @@ keychain_add_generic_password(int argc, char * const *argv)
                                                                         update_item);
 
 cleanup:
-    if (mustFreePasswordData)
+    if (mustFreePasswordData) {
         free(passwordData);
-       if (trusted_list)
-               CFRelease(trusted_list);
-       if (access)
-               CFRelease(access);
+    }
+    if (trusted_list) {
+        CFRelease(trusted_list);
+    }
+    if (access) {
+        CFRelease(access);
+    }
 
-       return result;
+    return result;
 }
 
 int
@@ -976,12 +979,15 @@ keychain_add_internet_password(int argc, char * const *argv)
                                                                          update_item);
 
 cleanup:
-    if (mustFreePasswordData)
+    if (mustFreePasswordData) {
         free(passwordData);
-       if (trusted_list)
-               CFRelease(trusted_list);
-       if (access)
-               CFRelease(access);
+    }
+    if (trusted_list) {
+        CFRelease(trusted_list);
+    }
+    if (access) {
+        CFRelease(access);
+    }
 
        return result;
 }
index d27b211b2caaae9ba866136e60c136dddc982ef8..61e1401dcd7b898fa47295b1a6eb7979b127b88b 100644 (file)
@@ -416,12 +416,14 @@ keychain_import(int argc, char * const *argv)
        if(kcName) {
                kcRef = keychain_open(kcName);
                if(kcRef == NULL) {
-                       return 1;
+                       result = 1;
+                       goto cleanup;
                }
        } else {
                OSStatus status = SecKeychainCopyDefault(&kcRef);
                if (status != noErr || kcRef == NULL) {
-                       return 1;
+                       result = 1;
+                       goto cleanup;
                }
        }
        if(readFileSizet(inFile, &inFileData, &inFileLen)) {
index 20a8d54958b1d49d45c19c80dd0106d84418b5d4..3cb1670dea3dc5667a724d8e6226ef0f405388a7 100644 (file)
@@ -39,10 +39,11 @@ static int
 do_lock_all(void)
 {
        OSStatus result = SecKeychainLockAll();
-    if (result)
+    if (result) {
         sec_perror("SecKeychainLockAll", result);
+    }
 
-       return result;
+    return result;
 }
 
 static int
index bee380fcda132dc836525d3ecb18f04aa7db89fb..ff8dd7ebe4733f640df454ff89d0ff1a23250539 100644 (file)
@@ -507,8 +507,9 @@ print_keychain_item_attributes(FILE *stream, SecKeychainItemRef item, Boolean sh
     fputs("version: ", stream);
     result = print_keychain_version(stream, keychain);
     fputc('\n', stream);
-    if (result)
+    if (result) {
         goto loser;
+    }
 
        /* First find out the item class. */
        status = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
@@ -903,7 +904,7 @@ fromHex(const char *hexDigits, CSSM_DATA *data)
 CFDataRef CF_RETURNS_RETAINED
 cfFromHex(CFStringRef hex) {
     // behavior is undefined if you pass in a non-hex string. Don't do that.
-    char* chex;
+    char* chex = NULL;
     size_t len;
 
     GetCStringFromCFString(hex, &chex, &len);
@@ -916,6 +917,7 @@ cfFromHex(CFStringRef hex) {
     CFDataIncreaseLength(bin, bytes);
 
     if(!bin || (size_t) CFDataGetLength(bin) != bytes) {
+        free(chex);
         CFReleaseNull(bin);
         return NULL;
     }
@@ -925,6 +927,7 @@ cfFromHex(CFStringRef hex) {
         data[i] = (uint8)(hexValue(chex[2*i]) << 4 | hexValue(chex[2*i+1]));
     }
 
+    free(chex);
     return bin;
 }
 
index a6ef891a40dc870cb221a462c4a6252d9589dde4..3976cc6aa5f1332f1e9522315b8f884f31d835ff 100644 (file)
@@ -140,10 +140,12 @@ read_file(const char *name, CSSM_DATA *outData)
        return result;
 
 loser:
-    if (fd != -1)
+    if (fd != -1) {
         close(fd);
-       if (buffer)
-               free(buffer);
+    }
+    if (buffer) {
+        free(buffer);
+    }
 
        return result;
 }
index 0215b80e9295ebec8bdf194c84ae3004a7776849..abb7fec7eb51b879bc36356ef9e2072fed99634b 100644 (file)
@@ -62,6 +62,7 @@ int requirement_evaluate(int argc, char * const *argv)
         fprintf(stderr, "parsing requirement failed (%d): %s\n", status, errorStr);
         
         free(errorStr);
+        CFReleaseSafe(errorDesc);
         
         err = 1;
     }
@@ -82,7 +83,7 @@ int requirement_evaluate(int argc, char * const *argv)
         }
         
         CFArrayAppendValue(certs, cert);
-        CFRelease(cert);
+        CFReleaseSafe(cert);
     }
     
     // Evaluate!
index 24ee1bf8d9980628677f39695ae10ab44e5e59aa..18effdf64fe83b5c0d4b9b5781a66c8b463cf8ea 100644 (file)
 
 - (id)initWithURLString:(const char *)urlstr verbose:(int)level
 {
-    _url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%s", urlstr]];
-    _udp = NO;
-    _finished = NO;
-    _verbose = level;
-    _error = nil;
-    _trust = NULL;
-    _queue = dispatch_get_main_queue();
-    _connection = [self createConnection];
+    if ((self = [super init])) {
+        _url = [[NSURL alloc] initWithString:[NSString stringWithFormat:@"%s", urlstr]];
+        _udp = NO;
+        _finished = NO;
+        _verbose = level;
+        _error = nil;
+        _trust = NULL;
+        _queue = dispatch_get_main_queue();
+        _connection = [self createConnection];
+    }
 
     return self;
 }
index 724082bd08b3947566c1d11a8dd95dc36dd19666..1eb76c7dfe87ef839a3633a056c4c6b80c37b831 100644 (file)
@@ -137,15 +137,9 @@ int verify_backup_integrity(int argc, char * const *argv) {
     }
 
     NSLog(@"Running backup integrity validation in %@ mode", lightweight ? @"lightweight" : @"default");
-    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
     SecItemVerifyBackupIntegrity(lightweight, ^(NSDictionary* results, NSError *error) {
         NSLog(@"%@", results);
-        dispatch_semaphore_signal(sema);
     });
 
-    if (dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 30))) {
-        NSLog(@"Timed out waiting for backup integrity validation");
-    }
-
     return 0;
 }
index 1792878a435cb0a09c23ead37cb6866dba50724b..85477d7da66778c81539cc334a0b5f975297f081 100644 (file)
@@ -41,9 +41,11 @@ SECURITY_COMMAND("item", keychain_item,
                  "SAC object for deleting item added by default\n",
                  "Manipulate keychain items.")
 
+#if !TARGET_OS_BRIDGE
 SECURITY_COMMAND("policy-dryrun", policy_dryrun,
                  "",
                  "Try to evaluate policy old/new.")
+#endif
 
 SECURITY_COMMAND("keychain-item-digest", keychain_item_digest,
                  "itemClass keychainAccessGroup\n"
@@ -223,3 +225,24 @@ SECURITY_COMMAND("show-ct-exceptions", show_ct_exceptions,
                  "   -c             Output certificate exceptions (as SPKI hash).\n"
                  "                      Default is both domains and certs.\n",
                  "Display exceptions for Certificate Transparency enforcement in json.")
+
+SECURITY_COMMAND("add-ca-revocation-checking", add_ca_revocation_checking,
+                 "[options]\n"
+                 "   -c cert    Cert for which revocation checking should be enabled.\n"
+                 "                 Specify a CA cert to enable checking for all its issued certs.\n"
+                 "                 Can be specified multiple times.\n"
+                 "   -p plist   plist containing entries to enable explicit revocation checking.\n"
+                 "                 Resets existing entries, if present.\n"
+                 "                 Overrides -c\n"
+                 "                 For detailed specification, see SecTrustSettingsPriv.h.\n"
+                 "   -r which   Resets cert entries for \"cert\" or \"all\".\n"
+                 "                 Overrides -c and -p\n",
+                 "Specify additional CA certs for which revocation checking is enabled")
+
+SECURITY_COMMAND("show-ca-revocation-checking", show_ca_revocation_checking,
+                 "[options]\n"
+                 "   -a             Output all combined CA revocation checking additions.\n"
+                 "   -i identifier  Output CA revocation additions for specified identifier.\n"
+                 "                      Default is the additions for this tool. Overridden by -a.\n"
+                 "   -c             Output CA revocation additions (as certificate SPKI hash).\n",
+                 "Display CA revocation checking additions in json.")
index 1a8f54d8f395e2ce7bc254ab7d4ea832cb1b7756..7599c9c5ac16e406f6188f08135c810382d1a5bc 100644 (file)
@@ -93,14 +93,16 @@ do_addinternetpassword(const char *keychainName, const char *serverName,
        /* @@@ For performance reasons we could choose to make the dictionaries
      CFRetain callback a no op and let the dictionary deal with the
      releasing. */
-    for (; ix-- > 0;)
+    for (; ix-- > 0;) {
         CFRelease(values[ix]);
+    }
     
        result = SecItemAdd(attributes, NULL);
     
-    if (attributes)
+    if (attributes) {
         CFRelease(attributes);
-    
+    }
+
        if (result)
        {
                sec_perror("SecItemAdd", result);
index 8e57592a267febc6308811cc94060256b27cc2a6..79783228442d62e39c117b030f528fb6b3ca4093 100644 (file)
@@ -23,6 +23,7 @@
 
 
 #include "SecurityTool/sharedTool/security_tool_commands.h"
+#include <TargetConditionals.h>
 
 SECURITY_COMMAND("help", help,
                  "[command ...]",
@@ -40,6 +41,7 @@ SECURITY_COMMAND("whoami", command_whoami,
                  "",
                  "Ask securityd who you are.")
 
+#if !TARGET_OS_BRIDGE
 SECURITY_COMMAND("sos-stats", command_sos_stats,
                  "",
                  "SOS for performance numbers.")
@@ -60,6 +62,7 @@ SECURITY_COMMAND("watchdog", command_watchdog,
                      "    check-period <x>\n"
                      "    graceful-exit-time <x>\n",
                      "Show current watchdog parameters or set an individual parameter")
+#endif
 
 SECURITY_COMMAND("keychain-check", command_keychain_check,
                     "",
diff --git a/SecurityTool/sharedTool/ca_revocation_additions.m b/SecurityTool/sharedTool/ca_revocation_additions.m
new file mode 100644 (file)
index 0000000..b725ac4
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2020 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@
+ *
+ * ca_revocation_additions.m
+ */
+
+#import <Foundation/Foundation.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecCertificatePriv.h>
+#include <utilities/fileIo.h>
+#include <utilities/SecCFWrappers.h>
+
+#include "SecurityCommands.h"
+
+NSString* secToolAppID = @"com.apple.security";
+
+static int addCertFile(const char *fileName, NSMutableArray *array) {
+    SecCertificateRef certRef = NULL;
+    NSData *data = NULL;
+    unsigned char *buf = NULL;
+    size_t numBytes;
+    int rtn = 0;
+
+    if (readFileSizet(fileName, &buf, &numBytes)) {
+        rtn = -1;
+        goto errOut;
+    }
+
+    data = [NSData dataWithBytes:buf length:numBytes];
+    certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)data);
+    if (!certRef) {
+        certRef = SecCertificateCreateWithPEM(NULL, (__bridge CFDataRef)data);
+        if (!certRef) {
+            rtn = -1;
+            goto errOut;
+        }
+    }
+
+    [array addObject:(__bridge id)certRef];
+
+errOut:
+    /* Cleanup */
+    free(buf);
+    CFReleaseNull(certRef);
+    return rtn;
+}
+
+static int returnCFError(CFErrorRef CF_CONSUMED error) {
+    CFStringRef errorString = CFErrorCopyDescription(error);
+    CFStringPerformWithCString(errorString, ^(const char *utf8Str) {
+        fprintf(stderr, "Failed to copy CA revocation additions: %s\n", utf8Str);
+    });
+    CFIndex errCode = CFErrorGetCode(error);
+    CFReleaseNull(error);
+    return (int)errCode;
+}
+
+static int resetRevocationAdditions(bool resetCerts) {
+    bool result = false;
+    CFErrorRef error = NULL;
+    if (resetCerts) {
+        NSDictionary *resetCertsDict = @{ (__bridge NSString*)kSecCARevocationAdditionsKey: @[] };
+        result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)resetCertsDict, &error);
+    }
+    if (!result) {
+        return returnCFError(error);
+    }
+    return 0;
+}
+
+static int addRevocationAdditions(CFStringRef key, NSArray *newAdditions) {
+    CFErrorRef error = NULL;
+    NSDictionary *currentAdditions = CFBridgingRelease(SecTrustStoreCopyCARevocationAdditions((__bridge CFStringRef)secToolAppID, &error));
+    if (!currentAdditions && error) {
+        return returnCFError(error);
+    }
+
+    NSMutableArray *additionsForKey = nil;
+    if (currentAdditions && currentAdditions[(__bridge NSString*)key]) {
+        additionsForKey = [currentAdditions[(__bridge NSString*)key] mutableCopy];
+        [additionsForKey addObjectsFromArray:newAdditions];
+    } else {
+        additionsForKey = [newAdditions copy];
+    }
+
+    NSDictionary *newAdditionsDict = @{ (__bridge NSString*)key: additionsForKey };
+    bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)newAdditionsDict, &error);
+    if (!result) {
+        return returnCFError(error);
+    }
+
+    return 0;
+}
+
+int add_ca_revocation_checking(int argc, char * const *argv) {
+    int arg;
+
+    bool resetCerts = false;
+
+    NSMutableArray *certs = [NSMutableArray array];
+    NSDictionary *plist = nil;
+
+    /* parse args */
+    if (argc == 1) {
+        return SHOW_USAGE_MESSAGE;
+    }
+
+    while ((arg = getopt(argc, argv, "c:r:p:")) != -1) {
+        switch(arg) {
+            case 'c':
+                if (addCertFile(optarg, certs)) {
+                    fprintf(stderr, "Failed to read cert file\n");
+                    return 1;
+                }
+                break;
+            case 'r':
+                if (!strcmp(optarg, "all")) {
+                    resetCerts = true;
+                } else if (!strcmp(optarg, "cert")) {
+                    resetCerts = true;
+                } else {
+                    return SHOW_USAGE_MESSAGE;
+                }
+                break;
+            case 'p':
+                plist = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithCString:optarg encoding:NSUTF8StringEncoding]];
+                break;
+            case '?':
+            default:
+                return SHOW_USAGE_MESSAGE;
+        }
+    }
+
+    /* handle reset operation */
+    if (resetCerts) {
+        return resetRevocationAdditions(resetCerts);
+    }
+
+    /* set plist */
+    if (plist) {
+        CFErrorRef error = NULL;
+        bool result = SecTrustStoreSetCARevocationAdditions(NULL, (__bridge CFDictionaryRef)plist, &error);
+        if (!result) {
+            return returnCFError(error);
+        } else {
+            return 0;
+        }
+    }
+
+    /* add certs */
+    int status = 0;
+    if ([certs count]) {
+        NSMutableArray<NSDictionary *>*valuesForCAsKey = [NSMutableArray arrayWithCapacity:[certs count]];
+        [certs enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+            SecCertificateRef cert = (__bridge SecCertificateRef)obj;
+            NSData* hash = CFBridgingRelease(SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert));
+            NSDictionary *value = @{ (__bridge NSString*)kSecCARevocationHashAlgorithmKey:@"sha256",
+                                     (__bridge NSString*)kSecCARevocationSPKIHashKey:hash };
+            [valuesForCAsKey addObject:value];
+        }];
+        status = addRevocationAdditions(kSecCARevocationAdditionsKey, valuesForCAsKey);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to add cert revocation additions\n");
+        return status;
+    }
+
+    return 0;
+}
+
+static int printRevocationAdditions(CFStringRef key, NSDictionary *allAdditions) {
+    if (!allAdditions || !allAdditions[(__bridge NSString*)key] ||
+        [allAdditions[(__bridge NSString*)key] count] == 0) {
+        CFStringPerformWithCString(key, ^(const char *utf8Str) {
+            fprintf(stdout, "No revocation additions for %s\n", utf8Str);
+        });
+        return 0;
+    }
+
+    NSArray *additionsForKey = allAdditions[(__bridge NSString*)key];
+    NSMutableString *additionsString = [NSMutableString stringWithFormat:@"\t%@ : [",key];
+    [additionsForKey enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if ([obj isKindOfClass:[NSString class]]) {
+            if (idx == 0) {
+                [additionsString appendFormat:@"\"%@\"",obj];
+            } else {
+                [additionsString appendFormat:@", \"%@\"", obj];
+            }
+        } else if ([obj isKindOfClass:[NSDictionary class]]) {
+            if (idx == 0) {
+                [additionsString appendString:@"\n\t    "];
+            } else {
+                [additionsString appendString:@"\t    "];
+            }
+            [additionsString appendFormat:@"\"%@:", obj[(__bridge NSString*)kSecCARevocationHashAlgorithmKey]];
+            NSString *hashHex = CFBridgingRelease(CFDataCopyHexString((__bridge CFDataRef)obj[(__bridge NSString*)kSecCARevocationSPKIHashKey]));
+            [additionsString appendString:hashHex];
+            if ([additionsForKey count] == idx + 1) { // last entry
+                [additionsString appendString:@"\"\n"];
+            } else {
+                [additionsString appendString:@"\",\n"];
+            }
+        }
+    }];
+    [additionsString appendString:@"]\n"];
+    CFStringPerformWithCString((__bridge CFStringRef)additionsString, ^(const char *utf8Str) {
+        fprintf(stdout, "\n%s\n", utf8Str);
+    });
+
+    return 0;
+}
+
+int show_ca_revocation_checking(int argc, char * const *argv) {
+    int arg;
+    bool allAdditions = false;
+    NSString *identifier = nil;
+    bool certAdditions = false;
+
+    /* parse args */
+    while ((arg = getopt(argc, argv, "ai:c")) != -1) {
+        switch(arg) {
+            case 'a':
+                allAdditions = true;
+                break;
+            case 'i':
+                identifier = [NSString stringWithCString:optarg encoding:NSUTF8StringEncoding];
+                break;
+            case 'c':
+                certAdditions = true;
+                break;
+            case '?':
+            default:
+                return SHOW_USAGE_MESSAGE;
+        }
+    }
+
+    if (allAdditions) {
+        identifier = nil;
+        fprintf(stdout, "Showing revocation additions for all apps\n");
+    } else if (!identifier) {
+        identifier = secToolAppID;
+    }
+
+    if (identifier) {
+        CFStringPerformWithCString((__bridge CFStringRef)identifier, ^(const char *utf8Str) {
+            fprintf(stdout, "Showing revocation additions for %s\n", utf8Str);
+        });
+    }
+
+    CFErrorRef error = NULL;
+    NSDictionary *results = CFBridgingRelease(SecTrustStoreCopyCARevocationAdditions((__bridge CFStringRef)identifier, &error));
+
+    /* Copy failed, return error */
+    if (!results && error) {
+        return returnCFError(error);
+    }
+
+    /* print cert revocation additions */
+    int status = 0;
+    if (certAdditions) {
+        status = printRevocationAdditions(kSecCARevocationAdditionsKey, results);
+    }
+    if (status != 0) {
+        fprintf(stderr, "failed to print revocation additions\n");
+        return status;
+    }
+
+
+    return 0;
+}
index ecb877f855b5774357efcd453b62de579f336771..8cdb7c53726942a8ddf14ccdeef4e954168508bc 100644 (file)
@@ -17,6 +17,8 @@
        <string>com.apple.security</string>
        <key>com.apple.private.keychain.keychaincontrol</key>
        <true/>
+       <key>com.apple.private.keychain.inet_expansion_fields</key>
+       <true/>
        <key>com.apple.developer.icloud-services</key>
        <array>
                <string>CloudKit</string>
index dc75012f96d40012d3785d08c64103396fb644d5..461763d5b33f6cd0167cf7da7ccd23a0185dfa5c 100644 (file)
@@ -12,6 +12,8 @@
        </array>
        <key>com.apple.private.keychain.keychaincontrol</key>
        <true/>
+       <key>com.apple.private.keychain.inet_expansion_fields</key>
+       <true/>
        <key>com.apple.private.syncbubble-keychain</key>
        <true/>
        <key>com.apple.private.system-keychain</key>
index dc1668ecdb3e72d8995934c8398459c170636847..ff46b5a8e47f7ee821b8cca113e3edc8d4059706 100644 (file)
@@ -158,11 +158,11 @@ static void reportStats(unsigned expected_mismatches, unsigned real_mismatches,
 int policy_dryrun(int argc, char * const *argv) {
     @autoreleasepool {
         NSError* error = nil;
-        // From Swift.policy, policy v5
+        // From Swift.policy, policy v7
 
-        TPPolicyDocument *tpd = [TPPolicyDocument policyDocWithHash:@"SHA256:O/ECQlWhvNlLmlDNh2+nal/yekUC87bXpV3k+6kznSo="
+        TPPolicyDocument *tpd = [TPPolicyDocument policyDocWithHash:@"SHA256:dL8Qujqzprhp6FdH5GzNMtPlnZtLWMwfiiF7aykr8WU="
                                                   data:[[NSData alloc] initWithBase64EncodedString:
-                                                                           @"CAUSDgoGaVBob25lEgRmdWxsEgwKBGlQYWQSBGZ1bGwSDAoEaVBvZBIEZnVsbBILCgNNYWMSBGZ1bGwSDAoEaU1hYxIEZnVsbBINCgdBcHBsZVRWEgJ0dhIOCgVXYXRjaBIFd2F0Y2gSFwoOQXVkaW9BY2Nlc3NvcnkSBWF1ZGlvGhsKDEFwcGxpY2F0aW9ucxIEZnVsbBIFd2F0Y2gaHwoQU2VjdXJlT2JqZWN0U3luYxIEZnVsbBIFd2F0Y2gaHAoNRGV2aWNlUGFpcmluZxIEZnVsbBIFd2F0Y2gaGgoLQ3JlZGl0Q2FyZHMSBGZ1bGwSBXdhdGNoGhUKBkhlYWx0aBIEZnVsbBIFd2F0Y2gaLQoTTGltaXRlZFBlZXJzQWxsb3dlZBIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxokChVQcm90ZWN0ZWRDbG91ZFN0b3JhZ2USBGZ1bGwSBXdhdGNoGhcKCEFwcGxlUGF5EgRmdWxsEgV3YXRjaBoZCgpBdXRvVW5sb2NrEgRmdWxsEgV3YXRjaBoWCgdNYW5hdGVlEgRmdWxsEgV3YXRjaBoYCglQYXNzd29yZHMSBGZ1bGwSBXdhdGNoGhUKBkVuZ3JhbRIEZnVsbBIFd2F0Y2gaHgoEV2lGaRIEZnVsbBIFd2F0Y2gSAnR2EgVhdWRpbxoTCgRIb21lEgRmdWxsEgV3YXRjaCIbCgVhdWRpbxIEZnVsbBIFd2F0Y2gSBWF1ZGlvIhMKBGZ1bGwSBGZ1bGwSBXdhdGNoIhUKAnR2EgRmdWxsEgV3YXRjaBICdHYiFAoFd2F0Y2gSBGZ1bGwSBXdhdGNoMiIKFgAEIhICBHZ3aHQKCl5BcHBsZVBheSQSCEFwcGxlUGF5MiYKGAAEIhQCBHZ3aHQKDF5BdXRvVW5sb2NrJBIKQXV0b1VubG9jazIeChQABCIQAgR2d2h0CgheRW5ncmFtJBIGRW5ncmFtMh4KFAAEIhACBHZ3aHQKCF5IZWFsdGgkEgZIZWFsdGgyGgoSAAQiDgIEdndodAoGXkhvbWUkEgRIb21lMiAKFQAEIhECBHZ3aHQKCV5NYW5hdGVlJBIHTWFuYXRlZTI4CiEABCIdAgR2d2h0ChVeTGltaXRlZFBlZXJzQWxsb3dlZCQSE0xpbWl0ZWRQZWVyc0FsbG93ZWQyXQpQAAISHgAEIhoCBHZ3aHQKEl5Db250aW51aXR5VW5sb2NrJBIVAAQiEQIEdndodAoJXkhvbWVLaXQkEhUABCIRAgR2d2h0CgleQXBwbGVUViQSCU5vdFN5bmNlZDIrChsABCIXAgRhZ3JwCg9eWzAtOUEtWl17MTB9XC4SDEFwcGxpY2F0aW9uczLFAQqwAQACEjQAAQoTAAQiDwIFY2xhc3MKBl5nZW5wJAobAAQiFwIEYWdycAoPXmNvbS5hcHBsZS5zYmQkEj0AAQoTAAQiDwIFY2xhc3MKBl5rZXlzJAokAAQiIAIEYWdycAoYXmNvbS5hcHBsZS5zZWN1cml0eS5zb3MkEhkABCIVAgR2d2h0Cg1eQmFja3VwQmFnVjAkEhwABCIYAgR2d2h0ChBeaUNsb3VkSWRlbnRpdHkkEhBTZWN1cmVPYmplY3RTeW5jMmMKWwACEhIABCIOAgR2d2h0CgZeV2lGaSQSQwABChMABCIPAgVjbGFzcwoGXmdlbnAkChMABCIPAgRhZ3JwCgdeYXBwbGUkChUABCIRAgRzdmNlCgleQWlyUG9ydCQSBFdpRmkynQMKgwMAAhIYAAQiFAIEdndodAoMXlBDUy1CYWNrdXAkEhoABCIWAgR2d2h0Cg5eUENTLUNsb3VkS2l0JBIYAAQiFAIEdndodAoMXlBDUy1Fc2Nyb3ckEhUABCIRAgR2d2h0CgleUENTLUZERSQSGgAEIhYCBHZ3aHQKDl5QQ1MtRmVsZHNwYXIkEhoABCIWAgR2d2h0Cg5eUENTLU1haWxEcm9wJBIaAAQiFgIEdndodAoOXlBDUy1NYWlsZHJvcCQSGwAEIhcCBHZ3aHQKD15QQ1MtTWFzdGVyS2V5JBIXAAQiEwIEdndodAoLXlBDUy1Ob3RlcyQSGAAEIhQCBHZ3aHQKDF5QQ1MtUGhvdG9zJBIZAAQiFQIEdndodAoNXlBDUy1TaGFyaW5nJBIeAAQiGgIEdndodAoSXlBDUy1pQ2xvdWRCYWNrdXAkEh0ABCIZAgR2d2h0ChFeUENTLWlDbG91ZERyaXZlJBIaAAQiFgIEdndodAoOXlBDUy1pTWVzc2FnZSQSFVByb3RlY3RlZENsb3VkU3RvcmFnZTI6CisABCInAgRhZ3JwCh9eY29tLmFwcGxlLnNhZmFyaS5jcmVkaXQtY2FyZHMkEgtDcmVkaXRDYXJkczIuCiEABCIdAgRhZ3JwChVeY29tLmFwcGxlLmNmbmV0d29yayQSCVBhc3N3b3JkczJtClwAAhIeAAQiGgIEdndodAoSXkFjY2Vzc29yeVBhaXJpbmckEhoABCIWAgR2d2h0Cg5eTmFub1JlZ2lzdHJ5JBIcAAQiGAIEdndodAoQXldhdGNoTWlncmF0aW9uJBINRGV2aWNlUGFpcmluZzIOCgIABhIIQmFja3N0b3A=" options:0]];
+                                                                           @"CAcSDgoGaVBob25lEgRmdWxsEgwKBGlQYWQSBGZ1bGwSDAoEaVBvZBIEZnVsbBILCgNNYWMSBGZ1bGwSDAoEaU1hYxIEZnVsbBINCgdBcHBsZVRWEgJ0dhIOCgVXYXRjaBIFd2F0Y2gSFwoOQXVkaW9BY2Nlc3NvcnkSBWF1ZGlvGh4KBEhvbWUSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aJAoVUHJvdGVjdGVkQ2xvdWRTdG9yYWdlEgRmdWxsEgV3YXRjaBoYCglQYXNzd29yZHMSBGZ1bGwSBXdhdGNoGh8KEFNlY3VyZU9iamVjdFN5bmMSBGZ1bGwSBXdhdGNoGh4KBFdpRmkSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aGgoLQ3JlZGl0Q2FyZHMSBGZ1bGwSBXdhdGNoGhcKCEFwcGxlUGF5EgRmdWxsEgV3YXRjaBoVCgZIZWFsdGgSBGZ1bGwSBXdhdGNoGhkKCkF1dG9VbmxvY2sSBGZ1bGwSBXdhdGNoGi0KE0xpbWl0ZWRQZWVyc0FsbG93ZWQSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aHAoNRGV2aWNlUGFpcmluZxIEZnVsbBIFd2F0Y2gaFgoHTWFuYXRlZRIEZnVsbBIFd2F0Y2gaFQoGRW5ncmFtEgRmdWxsEgV3YXRjaBoXCghCYWNrc3RvcBIEZnVsbBIFd2F0Y2gaGwoMQXBwbGljYXRpb25zEgRmdWxsEgV3YXRjaCITCgRmdWxsEgRmdWxsEgV3YXRjaCIVCgJ0dhIEZnVsbBIFd2F0Y2gSAnR2IhQKBXdhdGNoEgRmdWxsEgV3YXRjaCIbCgVhdWRpbxIEZnVsbBIFd2F0Y2gSBWF1ZGlvMiIKFgAEIhICBHZ3aHQKCl5BcHBsZVBheSQSCEFwcGxlUGF5MiYKGAAEIhQCBHZ3aHQKDF5BdXRvVW5sb2NrJBIKQXV0b1VubG9jazIeChQABCIQAgR2d2h0CgheRW5ncmFtJBIGRW5ncmFtMh4KFAAEIhACBHZ3aHQKCF5IZWFsdGgkEgZIZWFsdGgyGgoSAAQiDgIEdndodAoGXkhvbWUkEgRIb21lMiAKFQAEIhECBHZ3aHQKCV5NYW5hdGVlJBIHTWFuYXRlZTI4CiEABCIdAgR2d2h0ChVeTGltaXRlZFBlZXJzQWxsb3dlZCQSE0xpbWl0ZWRQZWVyc0FsbG93ZWQyXQpQAAISHgAEIhoCBHZ3aHQKEl5Db250aW51aXR5VW5sb2NrJBIVAAQiEQIEdndodAoJXkhvbWVLaXQkEhUABCIRAgR2d2h0CgleQXBwbGVUViQSCU5vdFN5bmNlZDIrChsABCIXAgRhZ3JwCg9eWzAtOUEtWl17MTB9XC4SDEFwcGxpY2F0aW9uczLKAQq1AQACEjYAAQoTAAQiDwIFY2xhc3MKBl5nZW5wJAodAAQiGQIEYWdycAoRXmNvbVwuYXBwbGVcLnNiZCQSQAABChMABCIPAgVjbGFzcwoGXmtleXMkCicABCIjAgRhZ3JwChteY29tXC5hcHBsZVwuc2VjdXJpdHlcLnNvcyQSGQAEIhUCBHZ3aHQKDV5CYWNrdXBCYWdWMCQSHAAEIhgCBHZ3aHQKEF5pQ2xvdWRJZGVudGl0eSQSEFNlY3VyZU9iamVjdFN5bmMyYwpbAAISEgAEIg4CBHZ3aHQKBl5XaUZpJBJDAAEKEwAEIg8CBWNsYXNzCgZeZ2VucCQKEwAEIg8CBGFncnAKB15hcHBsZSQKFQAEIhECBHN2Y2UKCV5BaXJQb3J0JBIEV2lGaTKdAwqDAwACEhgABCIUAgR2d2h0CgxeUENTLUJhY2t1cCQSGgAEIhYCBHZ3aHQKDl5QQ1MtQ2xvdWRLaXQkEhgABCIUAgR2d2h0CgxeUENTLUVzY3JvdyQSFQAEIhECBHZ3aHQKCV5QQ1MtRkRFJBIaAAQiFgIEdndodAoOXlBDUy1GZWxkc3BhciQSGgAEIhYCBHZ3aHQKDl5QQ1MtTWFpbERyb3AkEhoABCIWAgR2d2h0Cg5eUENTLU1haWxkcm9wJBIbAAQiFwIEdndodAoPXlBDUy1NYXN0ZXJLZXkkEhcABCITAgR2d2h0CgteUENTLU5vdGVzJBIYAAQiFAIEdndodAoMXlBDUy1QaG90b3MkEhkABCIVAgR2d2h0Cg1eUENTLVNoYXJpbmckEh4ABCIaAgR2d2h0ChJeUENTLWlDbG91ZEJhY2t1cCQSHQAEIhkCBHZ3aHQKEV5QQ1MtaUNsb3VkRHJpdmUkEhoABCIWAgR2d2h0Cg5eUENTLWlNZXNzYWdlJBIVUHJvdGVjdGVkQ2xvdWRTdG9yYWdlMj0KLgAEIioCBGFncnAKIl5jb21cLmFwcGxlXC5zYWZhcmlcLmNyZWRpdC1jYXJkcyQSC0NyZWRpdENhcmRzMjAKIwAEIh8CBGFncnAKF15jb21cLmFwcGxlXC5jZm5ldHdvcmskEglQYXNzd29yZHMybQpcAAISHgAEIhoCBHZ3aHQKEl5BY2Nlc3NvcnlQYWlyaW5nJBIaAAQiFgIEdndodAoOXk5hbm9SZWdpc3RyeSQSHAAEIhgCBHZ3aHQKEF5XYXRjaE1pZ3JhdGlvbiQSDURldmljZVBhaXJpbmcyDgoCAAYSCEJhY2tzdG9w" options:0]];
         TPPolicy *policy = [tpd policyWithSecrets:@{} decrypter:nil error:&error];
         if (error != nil) {
             NSLog(@"policy error: %@", error);
@@ -172,6 +172,15 @@ int policy_dryrun(int argc, char * const *argv) {
             NSLog(@"policy is nil");
             return 1;
         }
+
+        TPSyncingPolicy* syncingPolicy = [policy syncingPolicyForModel:@"iPhone"
+                                             syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_UNKNOWN
+                                                                 error:&error];
+        if(syncingPolicy == nil || error != nil) {
+            NSLog(@"syncing policy is nil: %@", error);
+            return 1;
+        }
+
         unsigned real_mismatches = 0;
         unsigned expected_mismatches = 0;
         NSMutableArray<NSDictionary*>* reportedMismatches = [[NSMutableArray<NSDictionary*> alloc] init];
@@ -219,7 +228,7 @@ int policy_dryrun(int argc, char * const *argv) {
                 NSMutableDictionary* mutA = [a mutableCopy];
                 mutA[(id)kSecClass] = (id)itemClass;
 
-                NSString* newView = [policy mapKeyToView:mutA];
+                NSString* newView = [syncingPolicy mapDictionaryToView:mutA];
                 if (newView != nil) {
                     NSLog(@"new: %@", newView);
                 }
index 304c92706eb4a689be358ee6b307e8686cda8153..39e2f744df7a344376620ac592e3d76c37cf858c 100644 (file)
@@ -441,30 +441,44 @@ extern int command_scep(int argc, char * const *argv)
 
     (void) scep_signing_certificate; // Silence analyzer
 
-#if 0
+/*
         GetCACaps capabilities advertised by SCEP server:
 
-   +--------------------+----------------------------------------------+
-   | Keyword            | Description                                  |
-   +--------------------+----------------------------------------------+
-   | "GetNextCACert"    | CA Supports the GetNextCACert message.       |
-   | "POSTPKIOperation" | PKIOPeration messages may be sent via HTTP   |
-   |                    | POST.                                        |
-   | "Renewal"          | Clients may use current certificate and key  |
-   |                    | to authenticate an enrollment request for a  |
-   |                    | new certificate.                             |
-   | "SHA-512"          | CA Supports the SHA-512 hashing algorithm in |
-   |                    | signatures and fingerprints.                 |
-   | "SHA-256"          | CA Supports the SHA-256 hashing algorithm in |
-   |                    | signatures and fingerprints.                 |
-   | "SHA-1"            | CA Supports the SHA-1 hashing algorithm in   |
-   |                    | signatures and fingerprints.                 |
-   | "DES3"             | CA Supports triple-DES for encryption.       |
-   +--------------------+----------------------------------------------+
-#endif
+    +--------------------+----------------------------------------------+
+    | Keyword            | Description                                  |
+    +--------------------+----------------------------------------------+
+    | "AES"              | CA supports the AES128-CBC encryption        |
+    |                    | algorithm.                                   |
+    |                    |                                              |
+    | "DES3"             | CA supports the triple DES-CBC encryption    |
+    |                    | algorithm.                                   |
+    |                    |                                              |
+    | "GetNextCACert"    | CA supports the GetNextCACert                |
+    |                    | message.                                     |
+    |                    |                                              |
+    | "POSTPKIOperation" | CA supports PKIOPeration messages sent       |
+    |                    | via HTTP POST.                               |
+    |                    |                                              |
+    | "Renewal"          | CA supports the Renewal CA operation.        |
+    |                    |                                              |
+    | "SHA-1"            | CA supports the SHA-1 hashing algorithm.     |
+    |                    |                                              |
+    | "SHA-256"          | CA supports the SHA-256 hashing algorithm.   |
+    |                    |                                              |
+    | "SHA-512"          | CA supports the SHA-512 hashing algorithm.   |
+    |                    |                                              |
+    | "SCEPStandard"     | CA supports all mandatory-to-implement       |
+    |                    | sections of the SCEP standard.  This keyword |
+    |                    | implies "AES",                               |
+    |                    | "POSTPKIOperation", and "SHA-256", as well   |
+    |                    | as the provisions of                         |
+    |                    | Section 2.9.                                 |
+    +--------------------+----------------------------------------------+
+*/
 
     bool scep_can_use_post = false;
-    bool scep_use_3des = false;
+    bool scep_can_use_3des = false;
+    bool scep_can_use_aes = false;
     bool scep_can_use_sha1 = false;
     bool scep_can_use_sha512 = false;
     bool scep_can_use_sha256 = false;
@@ -496,21 +510,14 @@ extern int command_scep(int argc, char * const *argv)
 
         CFRange caps_length = CFRangeMake(0, CFArrayGetCount(caps));
         scep_can_use_post = CFArrayContainsValue(caps, caps_length, CFSTR("POSTPKIOperation"));
-        scep_use_3des = CFArrayContainsValue(caps, caps_length, CFSTR("DES3"));
+        scep_can_use_3des = CFArrayContainsValue(caps, caps_length, CFSTR("DES3"));
+        scep_can_use_aes = CFArrayContainsValue(caps, caps_length, CFSTR("AES"));
         scep_can_use_sha1 = CFArrayContainsValue(caps, caps_length, CFSTR("SHA-1"));
         scep_can_use_sha256 = CFArrayContainsValue(caps, caps_length, CFSTR("SHA-256"));
         scep_can_use_sha512 = CFArrayContainsValue(caps, caps_length, CFSTR("SHA-512"));
-
-        // We probably inteded these to be the values and not override them below..
-        // but for now to quiet the analyzer we reference them here. see <rdar://problem/15010402> scep.c, command_scep assumes 3des and sha1
-        (void) scep_use_3des;
-        (void) scep_can_use_sha1;
         CFRelease(caps);
     }
 
-    scep_use_3des = true;
-    scep_can_use_sha1 = true;
-
     csr_parameters = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 
         &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     if (scep_key_usage)
@@ -520,11 +527,14 @@ extern int command_scep(int argc, char * const *argv)
     else
         fprintf(stderr, "No SCEP challenge provided, hope that's ok.\n");
 
-    if (!scep_use_3des) {
-        CFDictionarySetValue(csr_parameters, kSecCMSBulkEncryptionAlgorithm, kSecCMSEncryptionAlgorithmDESCBC);
-        fprintf(stderr, "SCEP server does not support 3DES, falling back to DES.  You should reconfigure your server.\n");
+    // set encryption algorithm for CMS
+    if (scep_can_use_aes) {
+        CFDictionarySetValue(csr_parameters, kSecCMSBulkEncryptionAlgorithm, kSecCMSEncryptionAlgorithmAESCBC);
+    } else if (!scep_can_use_3des) {
+        fprintf(stderr, "SCEP server does not support 3DES -- using it anyway.  You must reconfigure your server.\n");
     }
 
+    // set hash algorithmn for CMS
     if (scep_can_use_sha512) {
         CFDictionarySetValue(csr_parameters, kSecCMSSignHashAlgorithm, kSecCMSHashingAlgorithmSHA512);
     } else if (scep_can_use_sha256) {
@@ -532,7 +542,7 @@ extern int command_scep(int argc, char * const *argv)
     } else if (scep_can_use_sha1) {
         CFDictionarySetValue(csr_parameters, kSecCMSSignHashAlgorithm, kSecCMSHashingAlgorithmSHA1);
     } else {
-        fprintf(stderr, "SCEP server does not support SHA-1.  You must reconfigure your server.\n");
+        fprintf(stderr, "SCEP server does not support SHA-1 -- using it anyway.  You must reconfigure your server.\n");
     }
 
     if (scep_subject_alt_name) {
index 1fae8a91028717474093470da2301457d4c8da3d..0a3d7214d225591f117ef8126b6033706b1aa698 100644 (file)
@@ -184,12 +184,15 @@ command_sos_control(__unused int argc, __unused char * const * argv)
         bool gbinfo = false;
         bool gbtriggered = false;
         bool circleHash = false;
+        bool triggerRingUpdate = false;
+        bool iCloudIdentityStatus = false;
 
         static struct option long_options[] =
         {
             /* These options set a flag. */
             {"assertStashAccountKey",   no_argument, NULL, 'a'},
             {"trigger-backup",   optional_argument, NULL, 'B'},
+            {"trigger-ring-update",   no_argument, NULL, 'R'},
             {"trigger-sync",   optional_argument, NULL, 's'},
             {"circle-hash", optional_argument, NULL, 'H'},
             {"ghostbustByMID",   optional_argument, NULL, 'M'},
@@ -198,10 +201,11 @@ command_sos_control(__unused int argc, __unused char * const * argv)
             {"ghostbustByAge",   optional_argument, NULL, 'A'},
             {"ghostbustInfo",   optional_argument, NULL, 'G'},
             {"ghostbustTriggered",   optional_argument, NULL, 'T'},
+            {"icloudIdentityStatus",   optional_argument, NULL, 'i'},
             {0, 0, 0, 0}
         };
 
-        while ((ch = getopt_long(argc, argv, "as:AB:GHMSIT", long_options, &option_index)) != -1) {
+        while ((ch = getopt_long(argc, argv, "as:AB:GHIMRSTi", long_options, &option_index)) != -1) {
             switch  (ch) {
                 case 'a': {
                     assertStashAccountKey = true;
@@ -239,6 +243,9 @@ command_sos_control(__unused int argc, __unused char * const * argv)
                     gboptions |= SOSGhostBustByMID;
                     break;
                 }
+                case 'R':
+                    triggerRingUpdate = true;
+                    break;
                 case 'S': {
                     gboptions |= SOSGhostBustBySerialNumber;
                     break;
@@ -254,6 +261,9 @@ command_sos_control(__unused int argc, __unused char * const * argv)
                 case 'H':
                     circleHash = true;
                     break;
+                case 'i':
+                    iCloudIdentityStatus = true;
+                    break;
                 case '?':
                 default:
                 {
@@ -300,7 +310,7 @@ command_sos_control(__unused int argc, __unused char * const * argv)
         } else if (triggerSync) {
             [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
                 printControlFailureMessage(error);
-            }] triggerSync:syncingPeers complete:^(bool res, NSError *error) {
+            }] rpcTriggerSync:syncingPeers complete:^(bool res, NSError *error) {
                 if (res) {
                     printf("starting to sync was successful\n");
                 } else {
@@ -310,11 +320,21 @@ command_sos_control(__unused int argc, __unused char * const * argv)
         } else if (triggerBackup) {
             [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
                 printControlFailureMessage(error);
-            }] triggerBackup:backupPeers complete:^(NSError *error) {
+            }] rpcTriggerBackup:backupPeers complete:^(NSError *error) {
                 if (error == NULL) {
                     printf("trigger backup was successful\n");
                 } else {
-                    printf("%s", [[NSString stringWithFormat:@"Failed to start sync: %@\n", error] UTF8String]);
+                    printf("%s", [[NSString stringWithFormat:@"Failed to start backup: %@\n", error] UTF8String]);
+                }
+            }];
+        } else if (triggerRingUpdate) {
+            [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
+                printControlFailureMessage(error);
+            }] rpcTriggerRingUpdate:^(NSError *error) {
+                if (error == NULL) {
+                    printf("trigger ring update was successful\n");
+                } else {
+                    printf("%s", [[NSString stringWithFormat:@"Failed to start ring update: %@\n", error] UTF8String]);
                 }
             }];
 
@@ -339,6 +359,17 @@ command_sos_control(__unused int argc, __unused char * const * argv)
                 }
             }];
 
+        } else if (iCloudIdentityStatus) {
+            [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
+                printControlFailureMessage(error);
+            }] iCloudIdentityStatus:^(NSData *json, NSError *error) {
+                if (json) {
+                    printf("iCloudIdentityStatus:\n%s\n", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]);
+                } else {
+                    printf("%s", [[NSString stringWithFormat:@"failed to get iCloudIdentityStatus: %@\n", error] UTF8String]);
+                }
+            }];
+
         } else {
 
             [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
index 61f5d813a2d66149385b33a0e006e4573c5e4649..e6d5b1c4ecc0dd671a30f8dd92f69b20b8cc3e66 100644 (file)
 // This file can't be once, it gets included multiple times to get definitions and declarations.
 
 #include "SecurityTool/sharedTool/SecurityCommands.h"
+
+#if !TARGET_OS_BRIDGE
 #include "keychain/SecureObjectSync/Tool/keychain_sync.h"
 #include "keychain/SecureObjectSync/Tool/keychain_sync_test.h"
 #include "keychain/SecureObjectSync/Tool/keychain_log.h"
 #include "keychain/SecureObjectSync/Tool/recovery_key.h"
+#endif
index 1732340814cfcb015a9875d84795a0f5c2efee04..8111e2cb1c3018c8c7d4e781d5fc8b8bc7572680 100644 (file)
@@ -80,6 +80,26 @@ static int check_OTA_sec_experiment_asset(void) {
     return 0;
 }
 
+static int check_valid_update(void) {
+    CFErrorRef error = NULL;
+    bool result = SecTrustTriggerValidUpdate(&error);
+    if (!result) {
+        CFStringRef errorDescription = error ? CFErrorCopyDescription(error) : NULL;
+        if (errorDescription) {
+            char *errMsg = CFStringToCString(errorDescription);
+            fprintf(stdout, "Update failed: %s\n", errMsg ? errMsg : "no error message");
+            free(errMsg);
+            CFRelease(errorDescription);
+        } else {
+            fprintf(stdout, "Update failed: no description\n");
+        }
+        CFReleaseNull(error);
+    } else {
+        fprintf(stdout, "Updated triggered\n");
+    }
+    return 0;
+}
+
 int check_trust_update(int argc, char * const *argv) {
     int arg;
 
@@ -87,12 +107,14 @@ int check_trust_update(int argc, char * const *argv) {
         return SHOW_USAGE_MESSAGE;
     }
 
-    while ((arg = getopt(argc, argv, "se")) != -1) {
+    while ((arg = getopt(argc, argv, "ser")) != -1) {
         switch(arg) {
             case 's':
                 return check_OTA_Supplementals_asset();
             case 'e':
                 return check_OTA_sec_experiment_asset();
+            case 'r':
+                return check_valid_update();
             case '?':
             default:
                 return SHOW_USAGE_MESSAGE;
index f667d23cada9163406010d815b545a55efed7085..89102a499c5d7e98dfc3b0dbb3a8dd2c2c6a17c9 100644 (file)
@@ -14,8 +14,7 @@
 @implementation NSXPCConnectionMock
 - (instancetype) initWithRealObject:(id)reality
 {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _reality = reality;
     }
     return self;
index 3ac3843efcaeab5ac982b2ff66c2da4d3267c147..9b047a7ddc370174dcd687f281905bf8e952daad 100755 (executable)
@@ -6,7 +6,9 @@
 //
 
 #import <UIKit/UIKit.h>
+#if !TARGET_OS_TV
 #import <SpringBoardUIServices/SBSUIRemoteAlertItemContentViewController.h>
+#endif
 
 @interface SWCViewController : SBSUIRemoteAlertItemContentViewController <UITableViewDelegate, UITableViewDataSource>
 
index 25e643ca88112d187aad1ced8216477f1f7ec435..23bf5312ecf551094de62b1817b3ce0f5f8cfb92 100755 (executable)
@@ -109,7 +109,7 @@ const NSString* SWC_SERVER_KEY   = @"srvr";
         self.backgroundView = [[UIView alloc] init];
         self.backgroundView.backgroundColor = [UIColor systemBackgroundColor];
 
-        self.imageView.image = [UIImage symbolImageNamed:@"checkmark"];
+        self.imageView.image = [UIImage systemImageNamed:@"checkmark"];
         self.imageView.hidden = YES;
     }
     
index ef81b9b78e1b5821a64c05e0b70957e8387dd2c4..7f7625056580f39104039e982124a775a6578021 100755 (executable)
@@ -6,5 +6,24 @@
        <true/>
        <key>com.apple.private.associated-domains</key>
        <true/>
+       <key>com.apple.security.iokit-user-client-class</key>
+       <array>
+               <string>AGXDevice</string>
+               <string>AGXDeviceUserClient</string>
+               <string>AGXSharedUserClient</string>
+               <string>AGXCommandQueue</string>
+               <string>IOAccelContext</string>
+               <string>IOAccelContext2</string>
+               <string>IOAccelDevice</string>
+               <string>IOAccelDevice2</string>
+               <string>IOAccelSharedUserClient</string>
+               <string>IOAccelSharedUserClient2</string>
+               <string>IOAccelSubmitter</string>
+               <string>IOAccelSubmitter2</string>
+               <string>IOAVControllerConcreteUserClient</string>
+               <string>IOMobileFramebufferUserClient</string>
+               <string>IOSurfaceRootUserClient</string>
+               <string>RootDomainUserClient</string>
+       </array>
 </dict>
 </plist>
diff --git a/TestPlan.xctestplan b/TestPlan.xctestplan
deleted file mode 100644 (file)
index 551dd81..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "configurations" : [
-    {
-      "id" : "E61600EC-4F68-414B-932D-2A0655D233A4",
-      "name" : "Configuration 1",
-      "options" : {
-
-      }
-    }
-  ],
-  "defaultOptions" : {
-
-  },
-  "testTargets" : [
-
-  ],
-  "version" : 1
-}
index 104b0315c9a6d6031a040a74c49e8641dde89178..028df74248ded1b8df41d3936451235570781783 100644 (file)
@@ -30,7 +30,7 @@
 
 // Truth table for following declarations:
 //
-//                          TARGET_OS_OSX   TARGET_OS_OSX   TARGET_OS_IPHONE    TARGET_OS_IPHONE    TARGET_OS_IOSMAC
+//                          TARGET_OS_OSX   TARGET_OS_OSX   TARGET_OS_IPHONE    TARGET_OS_IPHONE    TARGET_OS_MACCATALYST
 //                                          SEC_IOS_ON_OSX                      SEC_IOS_ON_OSX
 // =================================================================================================================
 // SEC_OS_IPHONE            0               1               1                   1                   1
   #endif // SEC_IOS_ON_OSX
 #endif // TARGET_OS_OSX
 
-#if TARGET_OS_IOSMAC
+#if TARGET_OS_MACCATALYST
   #define SEC_OS_IPHONE 1
 
   #define SEC_OS_OSX 0
   #define SEC_OS_OSX_INCLUDES 0
-#endif // TARGET_OS_IOSMAC
+#endif // TARGET_OS_MACCATALYST
 
 #ifndef SEC_OS_IPHONE
     // block above did not fire; set flags to current platform
@@ -71,7 +71,7 @@
 #define SEC_DEPRECATED_ATTRIBUTE
 #endif
 
-#define CSSM_DEPRECATED API_DEPRECATED("CSSM is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac)
+#define CSSM_DEPRECATED API_DEPRECATED("CSSM is not supported", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst)
 
 __BEGIN_DECLS
 
@@ -139,19 +139,19 @@ typedef struct CF_BRIDGED_TYPE(id) __SecKeychain *SecKeychainRef
     @typedef SecKeychainItemRef
     @abstract Contains information about a keychain item.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecKeychainItem *SecKeychainItemRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecKeychainItem *SecKeychainItemRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainSearchRef
     @abstract Contains information about a keychain search.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecKeychainSearch *SecKeychainSearchRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecKeychainSearch *SecKeychainSearchRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainAttrType
     @abstract Represents a keychain attribute type.
 */
-typedef OSType SecKeychainAttrType API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef OSType SecKeychainAttrType API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @struct SecKeychainAttribute
@@ -160,19 +160,19 @@ typedef OSType SecKeychainAttrType API_UNAVAILABLE(ios, watchos, tvos, bridgeos,
     @field length The length of the buffer pointed to by data.
     @field data A pointer to the attribute data.
 */
-struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) SecKeychainAttribute
+struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst) SecKeychainAttribute
 {
     SecKeychainAttrType tag;
     UInt32 length;
     void * __nullable data;
 };
-typedef struct SecKeychainAttribute SecKeychainAttribute API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct SecKeychainAttribute SecKeychainAttribute API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainAttributePtr
     @abstract Represents a pointer to a keychain attribute structure.
 */
-typedef SecKeychainAttribute *SecKeychainAttributePtr API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef SecKeychainAttribute *SecKeychainAttributePtr API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainAttributeList
@@ -180,30 +180,30 @@ typedef SecKeychainAttribute *SecKeychainAttributePtr API_UNAVAILABLE(ios, watch
     @field count An unsigned 32-bit integer that represents the number of keychain attributes in the array.
     @field attr A pointer to the first keychain attribute in the array.
 */
-struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) SecKeychainAttributeList
+struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst) SecKeychainAttributeList
 {
     UInt32 count;
     SecKeychainAttribute * __nullable attr;
 };
-typedef struct SecKeychainAttributeList SecKeychainAttributeList API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct SecKeychainAttributeList SecKeychainAttributeList API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainStatus
     @abstract Represents the status of a keychain.
 */
-typedef UInt32 SecKeychainStatus API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef UInt32 SecKeychainStatus API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecTrustedApplicationRef
     @abstract Contains information about a trusted application.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecTrustedApplication *SecTrustedApplicationRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecTrustedApplication *SecTrustedApplicationRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecAccessRef
     @abstract Contains information about an access.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecAccess *SecAccessRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecAccess *SecAccessRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 #if TARGET_OS_OSX
 typedef struct __SecAccess OpaqueSecAccessRef;
@@ -213,13 +213,13 @@ typedef struct __SecAccess OpaqueSecAccessRef;
     @typedef SecACLRef
     @abstract Contains information about an access control list (ACL) entry.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecACL *SecACLRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecACL *SecACLRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecPasswordRef
     @abstract Contains information about a password.
 */
-typedef struct CF_BRIDGED_TYPE(id) __SecPassword *SecPasswordRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct CF_BRIDGED_TYPE(id) __SecPassword *SecPasswordRef API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @typedef SecKeychainAttributeInfo
@@ -229,13 +229,13 @@ typedef struct CF_BRIDGED_TYPE(id) __SecPassword *SecPasswordRef API_UNAVAILABLE
     @field format A pointer to the first CSSM_DB_ATTRIBUTE_FORMAT in the array.
     @discussion Each tag and format item form a pair.
 */
-struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac) SecKeychainAttributeInfo
+struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst) SecKeychainAttributeInfo
 {
     UInt32 count;
     UInt32 *tag;
     UInt32 * __nullable format;
 };
-typedef struct SecKeychainAttributeInfo SecKeychainAttributeInfo API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+typedef struct SecKeychainAttributeInfo SecKeychainAttributeInfo API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @function SecCopyErrorMessageString
@@ -336,6 +336,7 @@ CF_ENUM(OSStatus)
     errSecCoreFoundationUnknown              = -4960,
 
     errSecMissingEntitlement                 = -34018,    /* A required entitlement isn't present. */
+    errSecRestrictedAPI                      = -34020,    /* Client is restricted and is not permitted to perform this operation. */
 
     errSecNotAvailable                       = -25291,    /* No keychain is available. You may need to restart your computer. */
     errSecReadOnly                           = -25292,    /* This keychain cannot be modified. */
@@ -704,6 +705,7 @@ CF_ENUM(OSStatus)
     errSecCertificatePolicyNotAllowed        = -67899,    /* The requested policy is not allowed for this certificate. */
     errSecCertificateNameNotAllowed          = -67900,    /* The requested name is not allowed for this certificate. */
     errSecCertificateValidityPeriodTooLong   = -67901,    /* The validity period in the certificate exceeds the maximum allowed. */
+    errSecCertificateIsCA                    = -67902,    /* The verified certificate is a CA rather than an end-entity */
 };
 
 
@@ -785,6 +787,7 @@ CF_ENUM(OSStatus)
  @constant errSSLATSLeafCertificateHashAlgorithmViolation ATS violation: peer leaf certificate hash algorithm is not ATS compliant
  @constant errSSLATSCertificateHashAlgorithmViolation ATS violation: peer certificate hash algorithm is not ATS compliant
  @constant errSSLATSCertificateTrustViolation ATS violation: peer certificate is not issued by trusted peer
+ @constant errSSLEarlyDataRejected Early application data rejected by peer
  */
 
 /*
@@ -883,6 +886,9 @@ CF_ENUM(OSStatus) {
     errSSLATSLeafCertificateHashAlgorithmViolation  = -9884,    /* ATS violation: peer leaf certificate hash algorithm is not ATS compliant */
     errSSLATSCertificateHashAlgorithmViolation      = -9885,    /* ATS violation: peer certificate hash algorithm is not ATS compliant */
     errSSLATSCertificateTrustViolation              = -9886,    /* ATS violation: peer certificate is not issued by trusted peer */
+
+    /* early data errors */
+    errSSLEarlyDataRejected                         = -9890,    /* Early application data rejected by peer */
 };
 
 CF_IMPLICIT_BRIDGING_DISABLED
index d27326070ebe7735086c791eae65b754f09455b9..165781545a602431ec0fb6bde9f2ed75126452a1 100644 (file)
@@ -125,7 +125,7 @@ OSStatus SecKeychainErrFromOSStatus(OSStatus osStatus)
  * This only apply to MacOS where background session exists.
  */
 void _SecSetSecuritydTargetUID(uid_t uid)
-    API_AVAILABLE(macos(10.13.5)) API_UNAVAILABLE(ios, iosmac, watchos, tvos, bridgeos);
+    API_AVAILABLE(macos(10.13.5)) API_UNAVAILABLE(ios, macCatalyst, watchos, tvos, bridgeos);
 
 
 
index 92d8f3a9eecd7c2c3b7a2db02c481f97a2144ec9..aaa000f4f736f0b5108556f8f3bc641780b93922 100644 (file)
@@ -29,7 +29,7 @@
 #ifndef _SECURITY_SECINTERNAL_H_
 #define _SECURITY_SECINTERNAL_H_
 
-#include <assert.h>
+#include "utilities/simulatecrash_assert.h"
 #include <CoreFoundation/CFNumber.h>
 #include <CoreFoundation/CFString.h>
 
index 0ab4da769782083a1daa3d90211c07f3b514387f..68633e06011eee457d53131b88a61c4c04aae49e 100644 (file)
@@ -15,7 +15,7 @@
 #include <errno.h>
 #include <string.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <signal.h>
 #include <sys/stat.h>
 #include <sys/socket.h>
index 456174f96dbcd41d07772fc32bafe456f135642d..8fcb758250b09e2bece67d9839b3ab010d75bccb 100644 (file)
@@ -570,6 +570,8 @@ enum
        CSSMERR_APPLETP_IDENTIFIER_MISSING =            -2147408837,
        /* Certificate authority pinning mismatch */
        CSSMERR_APPLETP_CA_PIN_MISMATCH =               -2147408836,
+       /* Leaf pinning mismatch */
+       CSSMERR_APPLETP_LEAF_PIN_MISMATCH =             -2147408835,
 };
 
 /* Apple .mac TP private error codes. */
@@ -605,7 +607,7 @@ enum
 
 enum
 {
-       CSSM_APPLEDL_OPEN_PARAMETERS_VERSION =                  1
+       CSSM_APPLEDL_OPEN_PARAMETERS_VERSION =                  1u
 };
 
 enum cssm_appledl_open_parameters_mask
index c39ddaa5210d70186b149dd77b7ef2f9b5fafd64..f6e828959b9c77e1e64803441b1507be83969ad7 100644 (file)
@@ -154,11 +154,10 @@ SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment,
         return SEC_EXP_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
-        return SEC_EXP_NIL_OUT_OF_MEMORY;
-    } else {
+    if ((self = [super init])) {
         self->innerExperiment = [[SecExperiment alloc] initWithName:name];
+    } else {
+        return SEC_EXP_NIL_OUT_OF_MEMORY;
     }
     return self;
 }
@@ -169,11 +168,10 @@ SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment,
         return SEC_EXP_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
-        return SEC_EXP_NIL_OUT_OF_MEMORY;
-    } else {
+    if ((self = [super init])) {
         self->innerExperiment = experiment;
+    } else {
+        return SEC_EXP_NIL_OUT_OF_MEMORY;
     }
     return self;
 }
@@ -224,11 +222,10 @@ SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment,
         return SEC_EXP_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
-        return SEC_EXP_NIL_OUT_OF_MEMORY;
-    } else {
+    if ((self = [super init])) {
         self.name = [NSString stringWithUTF8String:name];
+    } else {
+        return SEC_EXP_NIL_OUT_OF_MEMORY;
     }
     return self;
 }
@@ -381,10 +378,7 @@ SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment,
         return SEC_EXP_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
-        return SEC_EXP_NIL_OUT_OF_MEMORY;
-    } else {
+    if ((self = [super init])) {
         // Parse out experiment information from the configuration dictionary
         self.config = configuration;
         self.identifier = [configuration objectForKey:SecExperimentConfigurationKeyExperimentIdentifier];
@@ -400,7 +394,10 @@ SEC_EXP_OBJECT_IMPL_INTERNAL_OBJC(sec_experiment,
         }
 
         self.configurationData = [configuration objectForKey:SecExperimentConfigurationKeyConfigurationData];
+    } else {
+        return SEC_EXP_NIL_OUT_OF_MEMORY;
     }
+
     return self;
 }
 
index 2e05a8139104f0c38ebb4645f5dd1f2ba46858ec..efb4f251951dadb9fc7901b87417261b15b03bf0 100644 (file)
@@ -30,7 +30,7 @@ extern const NSString *SecExperimentConfigurationKeyConfigurationData;
 
 @interface SecExperiment : NSObject
 @property (readonly) NSString *name;
-@property (readonly) NSString *identifier;
+@property (readonly, nullable) NSString *identifier;
 @property (readonly) BOOL samplingDisabled;
 - (instancetype)initWithName:(const char *)name;
 - (BOOL)experimentIsAllowedForProcess;
@@ -51,7 +51,7 @@ extern const NSString *SecExperimentConfigurationKeyConfigurationData;
  *      Create an ARC-able `sec_experiment_t` instance wrapping an internal `SecExperiment` object.
  *
  * @param experiment
- *      Name of the experiment.
+ *      The experiment
  *
  * @return a `sec_experiment_t` instance.
  */
index e08c385d8de47310e3d893283504e1d339acb139..84aa3f6102b34be79f1a59c7903474782e643b09 100644 (file)
@@ -22,9 +22,9 @@ run_experiment(const char *experiment_name, size_t num_runs, bool sampling_disab
     for (size_t i = 0; i < num_runs; i++) {
         (void)sec_experiment_run_with_sampling_disabled(experiment_name, ^bool(const char *identifier, xpc_object_t experiment_config) {
             runs++;
-            CFDictionaryRef configuration = (CFDictionaryRef)_CFXPCCreateCFObjectFromXPCObject(experiment_config);
+            NSDictionary* configuration = (__bridge_transfer NSDictionary*)_CFXPCCreateCFObjectFromXPCObject(experiment_config);
             if (configuration != NULL) {
-                [configurations addObject:(__bridge NSDictionary *)configuration];
+                [configurations addObject:configuration];
             }
             return true;
         }, ^(const char * _Nonnull identifier) {
@@ -58,6 +58,7 @@ main(int argc, const char *argv[])
     while ((arg = getopt(argc, gargv, "e:n:sruh")) != -1) {
         switch (arg) {
             case 'e':
+                free(experiment_name);      // Only the last instance of -e counts
                 experiment_name = strdup(optarg);
                 break;
             case 'n':
@@ -77,6 +78,7 @@ main(int argc, const char *argv[])
                 break;
             default:
                 fprintf(stderr, "%s: FAILURE: unknown option \"%c\"\n", argv[0], arg);
+                free(experiment_name);
                 return -1;
         }
     }
index 1ffb729d4693b03df68ca6173cce5bd37958335e..19d4b09739da32bf304e200fef6bd0a139bd7d1b 100644 (file)
@@ -2,6 +2,16 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+       <key>SecErrorNestedErrorCapping</key>
+       <dict>
+               <key>Enabled</key>
+               <true/>
+       </dict>
+       <key>OctagonEscrowRecordFetch</key>
+       <dict>
+               <key>Enabled</key>
+               <true/>
+       </dict>
        <key>EnableSecureObjectSync</key>
        <dict>
                <key>Enabled</key>
@@ -30,7 +40,7 @@
        <key>CKKSViewsFromPolicy</key>
        <dict>
                <key>Enabled</key>
-               <false/>
+               <true/>
        </dict>
        <key>securitydReportPolicy</key>
        <dict>
                <key>Enabled</key>
                <false/>
        </dict>
+       <key>OctagonOptimization</key>
+       <dict>
+               <key>Enabled</key>
+               <true/>
+       </dict>
+       <key>SecItemRateLimiting</key>
+       <dict>
+               <key>Enabled</key>
+               <false/>
+       </dict>
+       <key>LegacyAPICounts</key>
+       <dict>
+               <key>Enabled</key>
+               <true/>
+       </dict>
 </dict>
 </plist>
diff --git a/header_symlinks/OctagonTrust/OTCDPRecoveryInformation.h b/header_symlinks/OctagonTrust/OTCDPRecoveryInformation.h
new file mode 120000 (symlink)
index 0000000..2ce370d
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTCDPRecoveryInformation.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTEscrowAuthenticationInformation.h b/header_symlinks/OctagonTrust/OTEscrowAuthenticationInformation.h
new file mode 120000 (symlink)
index 0000000..e50cdc1
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTEscrowRecord.h b/header_symlinks/OctagonTrust/OTEscrowRecord.h
new file mode 120000 (symlink)
index 0000000..13ded54
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTEscrowRecord.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTEscrowRecordMetadata.h b/header_symlinks/OctagonTrust/OTEscrowRecordMetadata.h
new file mode 120000 (symlink)
index 0000000..eeaa348
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTEscrowRecordMetadataClientMetadata.h b/header_symlinks/OctagonTrust/OTEscrowRecordMetadataClientMetadata.h
new file mode 120000 (symlink)
index 0000000..a875bda
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTEscrowTranslation.h b/header_symlinks/OctagonTrust/OTEscrowTranslation.h
new file mode 120000 (symlink)
index 0000000..3d26489
--- /dev/null
@@ -0,0 +1 @@
+./../keychain/OctagonTrust/OTEscrowTranslation.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTICDPRecordContext.h b/header_symlinks/OctagonTrust/OTICDPRecordContext.h
new file mode 120000 (symlink)
index 0000000..c06c0ba
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTICDPRecordContext.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OTICDPRecordSilentContext.h b/header_symlinks/OctagonTrust/OTICDPRecordSilentContext.h
new file mode 120000 (symlink)
index 0000000..882187b
--- /dev/null
@@ -0,0 +1 @@
+./..//keychain/ot/proto/generated_source/OTICDPRecordSilentContext.h
\ No newline at end of file
diff --git a/header_symlinks/OctagonTrust/OctagonTrust.h b/header_symlinks/OctagonTrust/OctagonTrust.h
new file mode 120000 (symlink)
index 0000000..54e11ad
--- /dev/null
@@ -0,0 +1 @@
+./../keychain/OctagonTrust/OctagonTrust.h
\ No newline at end of file
diff --git a/header_symlinks/Security/SFSignInAnalytics.h b/header_symlinks/Security/SFSignInAnalytics.h
deleted file mode 120000 (symlink)
index fca39ae..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./../keychain/Signin Metrics/SFSignInAnalytics.h
\ No newline at end of file
index eac6c122260c0132b412ce54eaae16da059509ba..778afb6a3f73eb824754c1c925e55b582cf98c60 120000 (symlink)
@@ -1 +1 @@
-./../SecExperiment/SecExperimentPriv.h
\ No newline at end of file
+./../experiment/SecExperimentPriv.h
\ No newline at end of file
index 4ec4d929de54e70a7099b67a88e833ae3debd8e4..fefd8c309e7e6ee0632a3899eee354aff7214538 120000 (symlink)
@@ -1 +1 @@
-./OSX/libsecurity_asn1/lib/certExtensionTemplates.h
\ No newline at end of file
+./../OSX/libsecurity_asn1/lib/certExtensionTemplates.h
\ No newline at end of file
diff --git a/header_symlinks/macOS/Security/SecBreadcrumb.h b/header_symlinks/macOS/Security/SecBreadcrumb.h
deleted file mode 120000 (symlink)
index fb71c7f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./../../OSX/Breadcrumb/SecBreadcrumb.h
\ No newline at end of file
diff --git a/header_symlinks/macOS/Security/SecCertificateBundle.h b/header_symlinks/macOS/Security/SecCertificateBundle.h
deleted file mode 120000 (symlink)
index b651860..0000000
+++ /dev/null
@@ -1 +0,0 @@
-./../../OSX/libsecurity_keychain/lib/SecCertificateBundle.h
\ No newline at end of file
index 77ac968996a1d134138b82a01c569d3a37abcc37..1261774435bca7858a78d7e5d6e41018a95671e2 100644 (file)
@@ -302,6 +302,7 @@ SecCDKeychainLookupValueType* const SecCDKeychainLookupValueTypeDate = (SecCDKey
 
 - (NSData*)_onQueueGetDatabaseKeyDataWithError:(NSError**)error
 {
+    dispatch_assert_queue(_queue);
     NSData* keyData = nil;
     NSDictionary* databaseKeyQuery = @{ (id)kSecClass : (id)kSecClassGenericPassword,
                                         (id)kSecAttrAccessGroup : @"com.apple.security.securityd",
@@ -458,6 +459,7 @@ SecCDKeychainLookupValueType* const SecCDKeychainLookupValueTypeDate = (SecCDKey
 
 - (void)_onQueueDropClassAPersistentStore
 {
+    dispatch_assert_queue(_queue);
     for (NSPersistentStore* store in _classAPersistentStores) {
         NSError* error = nil;
         if (![_persistentStoreCoordinator removePersistentStore:store error:&error]) {
index b79201ec3d83c65057cd3549b6c8572b5eb6323b..28dafff829c3f7d5617f1289e83fe03b839b9312 100644 (file)
@@ -93,19 +93,29 @@ static NSString* const KeychainDataclass = @"KeychainDataclass";
         creditCardsQuery[(id)kSecAttrAccessGroup] = @"com.apple.safari.credit-cards";
         OSStatus creditCardsResult = SecItemDelete((__bridge CFDictionaryRef)creditCardsQuery);
 
-        if (inetResult != errSecSuccess) {
+        if (inetResult == errSecSuccess) {
+            secnotice("itemDelete", "deleted synchronizable passwords from table inet");
+        } else {
             secwarning("failed to delete synchronizable passwords from table inet: %d", (int)inetResult);
         }
-        if (genpResult != errSecSuccess) {
+        if (genpResult == errSecSuccess) {
+            secnotice("itemDelete", "deleted synchronizable passwords from table genp");
+        } else {
             secwarning("failed to delete synchronizable passwords from table genp: %d", (int)genpResult);
         }
-        if (certResult != errSecSuccess) {
-            secwarning("failed to delete synchronizable passwords from table cert: %d", (int)certResult);
+        if (certResult == errSecSuccess) {
+            secnotice("itemDelete", "deleted synchronizable certificates from table cert");
+        } else {
+            secwarning("failed to delete synchronizable certificates from table cert: %d", (int)certResult);
         }
-        if (keyResult != errSecSuccess) {
-            secwarning("failed to delete synchronizable passwords from table keys: %d", (int)keyResult);
+        if (keyResult == errSecSuccess) {
+            secnotice("itemDelete", "deleted synchronizable keys from table keys");
+        } else {
+            secwarning("failed to delete synchronizable keys from table keys: %d", (int)keyResult);
         }
-        if (creditCardsResult != errSecSuccess) {
+        if (creditCardsResult == errSecSuccess) {
+            secnotice("itemDelete", "deleted credit cards from table genp");
+        } else {
             secwarning("failed to delete credit cards from table genp: %d", (int)creditCardsResult);
         }
     }
diff --git a/keychain/KeychainStasher/KeychainStasher-Info.plist b/keychain/KeychainStasher/KeychainStasher-Info.plist
new file mode 100644 (file)
index 0000000..777a5d4
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleDisplayName</key>
+       <string>KeychainStasher</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+</dict>
+</plist>
diff --git a/keychain/KeychainStasher/KeychainStasher.entitlements b/keychain/KeychainStasher/KeychainStasher.entitlements
new file mode 100644 (file)
index 0000000..7a31b99
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>application-identifier</key>
+       <string>com.apple.security.KeychainStasher</string>
+       <key>com.apple.private.keychain.sysbound</key>
+       <true/>
+</dict>
+</plist>
diff --git a/keychain/KeychainStasher/KeychainStasher.h b/keychain/KeychainStasher/KeychainStasher.h
new file mode 100644 (file)
index 0000000..c723ceb
--- /dev/null
@@ -0,0 +1,5 @@
+#import <Foundation/Foundation.h>
+#import "KeychainStasherProtocol.h"
+
+@interface KeychainStasher : NSObject <KeychainStasherProtocol>
+@end
diff --git a/keychain/KeychainStasher/KeychainStasher.m b/keychain/KeychainStasher/KeychainStasher.m
new file mode 100644 (file)
index 0000000..efc8cdd
--- /dev/null
@@ -0,0 +1,116 @@
+#import <xpc/private.h>
+
+#import "utilities/debugging.h"
+#import <Security/SecItemPriv.h>
+#import "LocalKeychainAnalytics.h"
+
+#import "KeychainStasher.h"
+
+NSString* const kApplicationIdentifier = @"com.apple.security.KeychainStasher";
+
+@implementation KeychainStasher
+
+- (NSError*)errorWithStatus:(OSStatus)status message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3)
+{
+    if (status == errSecSuccess) {
+        return nil;
+    }
+
+    NSString* desc;
+    if (format) {
+        va_list ap;
+        va_start(ap, format);
+        desc = [[NSString alloc] initWithFormat:format arguments:ap];
+        va_end(ap);
+    }
+    return [NSError errorWithDomain:NSOSStatusErrorDomain
+                               code:status
+                           userInfo:desc ? @{NSLocalizedDescriptionKey : desc} : nil];
+}
+
+- (NSMutableDictionary*)baseQuery {
+    return [@{
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrAccessible : (id)kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
+        // Prevents backups in case this ever comes to the Mac, prevents sync
+        (id)kSecAttrSysBound : @(kSecSecAttrSysBoundPreserveDuringRestore),
+        // Belt-and-suspenders prohibition on syncing
+        (id)kSecAttrSynchronizable : @NO,
+        (id)kSecClass : (id)kSecClassKey,
+        (id)kSecAttrApplicationLabel : @"loginstash",
+        // This is the default, but just making sure
+        (id)kSecAttrAccessGroup : kApplicationIdentifier,
+    } mutableCopy];
+}
+
+- (void)stashKey:(NSData*)key withReply:(void (^)(NSError*))reply {
+    secnotice("stashkey", "Will attempt to stash key");
+    if (!key || key.length == 0) {
+        reply([self errorWithStatus:errSecParam message:@"nil or empty key passed"]);
+        return;
+    }
+
+    NSMutableDictionary* query = [self baseQuery];
+    query[(id)kSecValueData] = key;
+
+    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
+    secnotice("stashkey", "SecItemAdd result: %ld", (long)status);
+
+    if (status == errSecDuplicateItem) {
+        [[LocalKeychainAnalytics logger] logResultForEvent:LKAEventStash hardFailure:NO result:[self errorWithStatus:status message:nil]];
+        query[(id)kSecValueData] = nil;
+        NSDictionary* update = @{(id)kSecValueData : key};
+        status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
+        secnotice("stashkey", "SecItemUpdate result: %ld", (long)status);
+    }
+
+    [[LocalKeychainAnalytics logger] logResultForEvent:LKAEventStash hardFailure:YES result:[self errorWithStatus:status message:nil]];
+    if (status == errSecSuccess) {
+        reply(nil);
+    } else {
+        reply([self errorWithStatus:status message:@"Stash failed with keychain error"]);
+    }
+}
+
+- (void)loadKeyWithReply:(void (^)(NSData*, NSError*))reply {
+    secnotice("KeychainStasher", "Will attempt to retrieve stashed key");
+
+    NSMutableDictionary* query = [self baseQuery];
+    query[(id)kSecReturnData] = @YES;
+
+    CFTypeRef object = NULL;
+    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &object);
+
+    if (status != errSecSuccess) {
+        if (status == errSecItemNotFound) {
+            reply(nil, [self errorWithStatus:status message:@"No stashed key found"]);
+        } else {
+            reply(nil, [self errorWithStatus:status message:@"Keychain error"]);
+        }
+        [[LocalKeychainAnalytics logger] logResultForEvent:LKAEventStashLoad hardFailure:YES result:[self errorWithStatus:status message:nil]];
+        return;
+    }
+
+    NSData* key;
+    if (!object || CFGetTypeID(object) != CFDataGetTypeID() || !(key = CFBridgingRelease(object))) {
+        reply(nil, [self errorWithStatus:errSecInternalError
+                                 message:@"No or bad object: %d / %lu / %d",
+                                         object != NULL, object ? CFGetTypeID(object) : 0, key != nil]);
+        [[LocalKeychainAnalytics logger] logResultForEvent:LKAEventStashLoad
+                                               hardFailure:YES
+                                                    result:[self errorWithStatus:errSecInternalError message:nil]];
+        return;
+    }
+
+    // Caller does not need to wait for our delete
+    reply(key, nil);
+
+    query[(id)kSecReturnData] = nil;
+    status = SecItemDelete((__bridge CFDictionaryRef)query);
+    if (status != errSecSuccess) {
+        seccritical("Unable to delete masterkey after load: %d", (int)status);
+    }
+    [[LocalKeychainAnalytics logger] logResultForEvent:LKAEventStashLoad hardFailure:NO result:[self errorWithStatus:status message:nil]];
+}
+
+@end
diff --git a/keychain/KeychainStasher/KeychainStasherProtocol.h b/keychain/KeychainStasher/KeychainStasherProtocol.h
new file mode 100644 (file)
index 0000000..c837e32
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef KeychainStasherProtocol_h
+#define KeychainStasherProtocol_h
+
+#import <Foundation/Foundation.h>
+
+@protocol KeychainStasherProtocol
+
+- (void)stashKey:(NSData*)key withReply:(void (^)(NSError*))reply;
+- (void)loadKeyWithReply:( void (^)(NSData*, NSError*))reply;
+    
+@end
+
+#endif /* KeychainStasherProtocol_h */
diff --git a/keychain/KeychainStasher/com.apple.security.KeychainStasher.plist b/keychain/KeychainStasher/com.apple.security.KeychainStasher.plist
new file mode 100644 (file)
index 0000000..df467bc
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+    <dict>
+        <key>EnablePressuredExit</key>
+        <true/>
+        <key>EnableTransactions</key>
+        <true/>
+        <key>LimitLoadToSessionType</key>
+        <string>Background</string>
+        <key>POSIXSpawnType</key>
+        <string>Adaptive</string>
+        <key>Label</key>
+        <string>com.apple.security.KeychainStasher</string>
+        <key>MachServices</key>
+        <dict>
+            <key>com.apple.security.KeychainStasher</key>
+            <true/>
+        </dict>
+        <key>ProgramArguments</key>
+        <array>
+            <string>/usr/libexec/KeychainStasher</string>
+        </array>
+    </dict>
+</plist>
diff --git a/keychain/KeychainStasher/com.apple.security.KeychainStasher.sb b/keychain/KeychainStasher/com.apple.security.KeychainStasher.sb
new file mode 100644 (file)
index 0000000..5c86637
--- /dev/null
@@ -0,0 +1,22 @@
+(version 1)
+
+(deny default)
+(deny file-map-executable process-info* nvram*)
+(deny dynamic-code-generation)
+
+(import "system.sb")
+(import "com.apple.corefoundation.sb")
+(corefoundation)
+
+(allow process-info-dirtycontrol (target self))
+
+(allow mach-lookup (global-name "com.apple.securityd.xpc"))
+
+(allow file-read-metadata)
+
+(if (param "ANALYTICSDIR")
+    (allow file-read* file-write* (subpath (param "ANALYTICSDIR"))))
+
+(allow file-read* (subpath "/usr/libexec"))
+
+(allow user-preference-read (preference-domain "kCFPreferencesAnyApplication"))
diff --git a/keychain/KeychainStasher/main.m b/keychain/KeychainStasher/main.m
new file mode 100644 (file)
index 0000000..45be5ed
--- /dev/null
@@ -0,0 +1,72 @@
+#import <Foundation/Foundation.h>
+#import <Foundation/NSXPCConnection_Private.h>
+#import <unistd.h>
+#import <xpc/private.h>
+#import <sandbox.h>
+
+#import <Security/SecEntitlements.h>
+#import <utilities/debugging.h>
+#import <utilities/SecFileLocations.h>
+
+#import "KeychainStasher.h"
+
+NSString* const KeychainStasherMachServiceName = @"com.apple.security.KeychainStasher";
+
+@interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
+@end
+
+@implementation ServiceDelegate
+
+- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
+    // We should encounter no more than 1 transaction per boot in normal conditions, so get out of everyone's way ASAP
+    xpc_transaction_exit_clean();
+
+    NSNumber* value = [newConnection valueForEntitlement:kSecEntitlementPrivateStashService];
+    if (value == nil || ![value boolValue]) {
+        secerror("KeychainStasher: client not entitled, rejecting connection");
+        [newConnection invalidate];
+        return NO;
+    }
+
+    newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(KeychainStasherProtocol)];
+    newConnection.exportedObject = [KeychainStasher new];
+    [newConnection resume];
+    return YES;
+}
+
+@end
+
+int main(int argc, const char *argv[])
+{
+    if (geteuid() == 0) {
+        secerror("KeychainStasher invoked as root, do not want.");
+        return 1;
+    } else {
+        secnotice("KeychainStasher", "Invoked with uid %d", geteuid());
+    }
+
+    NSString* analyticsdir = [[(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(nil) URLByAppendingPathComponent:@"Analytics/"] path];
+    if (analyticsdir) {
+        const char* sandbox_parameters[] = {"ANALYTICSDIR", analyticsdir.UTF8String, NULL};
+        char* sandbox_error = NULL;
+        if (0 != sandbox_init_with_parameters("com.apple.security.KeychainStasher", SANDBOX_NAMED, sandbox_parameters, &sandbox_error)) {
+            secerror("unable to enter sandbox with parameter: %s", sandbox_error);
+            sandbox_free_error(sandbox_error);
+            abort();
+        }
+    } else {    // If this fails somehow we will go ahead without analytics
+        char* sandbox_error = NULL;
+        if (0 != sandbox_init("com.apple.security.KeychainStasher", SANDBOX_NAMED, &sandbox_error)) {
+            secerror("unable to enter sandbox: %s", sandbox_error);
+            sandbox_free_error(sandbox_error);
+            abort();
+        }
+    }
+
+    ServiceDelegate *delegate = [ServiceDelegate new];
+    NSXPCListener *listener = [[NSXPCListener alloc] initWithMachServiceName:KeychainStasherMachServiceName];
+    listener.delegate = delegate;
+    [listener resume];
+    [[NSRunLoop currentRunLoop] run];
+    return 0;
+}
diff --git a/keychain/OctagonTrust/Info.plist b/keychain/OctagonTrust/Info.plist
new file mode 100644 (file)
index 0000000..9bcb244
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>$(CURRENT_PROJECT_VERSION)</string>
+</dict>
+</plist>
diff --git a/keychain/OctagonTrust/OTEscrowTranslation.h b/keychain/OctagonTrust/OTEscrowTranslation.h
new file mode 100644 (file)
index 0000000..700c2d0
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+* Copyright (c) 2020 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 EscrowTranslation_h
+#define EscrowTranslation_h
+#if __OBJC2__
+
+#import <Foundation/Foundation.h>
+#import <Security/Security.h>
+#import <OctagonTrust/OTEscrowRecord.h>
+#import <OctagonTrust/OTEscrowAuthenticationInformation.h>
+#import <OctagonTrust/OTICDPRecordContext.h>
+#import <OctagonTrust/OTCDPRecoveryInformation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OTEscrowTranslation : NSObject
+
+//dictionary to escrow auth
++ (OTEscrowAuthenticationInformation* _Nullable )dictionaryToEscrowAuthenticationInfo:(NSDictionary*)dictionary;
+
+//escrow auth to dictionary
++ (NSDictionary* _Nullable)escrowAuthenticationInfoToDictionary:(OTEscrowAuthenticationInformation*)escrowAuthInfo;
+
+//dictionary to escrow record
++ (OTEscrowRecord* _Nullable)dictionaryToEscrowRecord:(NSDictionary*)dictionary;
+
+//escrow record to dictionary
++ (NSDictionary* _Nullable)escrowRecordToDictionary:(OTEscrowRecord*)escrowRecord;
+
+//dictionary to icdp record context
++ (OTICDPRecordContext* _Nullable)dictionaryToCDPRecordContext:(NSDictionary*)dictionary;
+
+//icdp record context to dictionary
++ (NSDictionary* _Nullable)CDPRecordContextToDictionary:(OTICDPRecordContext*)context;
+
++ (NSDictionary * _Nullable) metadataToDictionary:(OTEscrowRecordMetadata*)metadata;
+
++ (OTEscrowRecordMetadata * _Nullable) dictionaryToMetadata:(NSDictionary*)dictionary;
+
++ (BOOL)supportedRestorePath:(OTICDPRecordContext*)cdpContext;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif
+
+#endif /* EscrowTranslation_h */
diff --git a/keychain/OctagonTrust/OTEscrowTranslation.m b/keychain/OctagonTrust/OTEscrowTranslation.m
new file mode 100644 (file)
index 0000000..3d55896
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+* Copyright (c) 2020 Apple Inc. All Rights Reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#import <Foundation/Foundation.h>
+#import "OTEscrowTranslation.h"
+
+#import <SoftLinking/SoftLinking.h>
+#import <CloudServices/SecureBackup.h>
+#import <CloudServices/SecureBackupConstants.h>
+#import "keychain/ot/categories/OctagonEscrowRecoverer.h"
+#import <OctagonTrust/OTEscrowRecordMetadata.h>
+#import <OctagonTrust/OTEscrowRecordMetadataClientMetadata.h>
+#import <Security/OTConstants.h>
+#import "keychain/ot/OTClique+Private.h"
+#import <utilities/debugging.h>
+
+SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CloudServices);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+
+SOFT_LINK_CLASS(CloudServices, SecureBackup);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain);
+
+/* Escrow Authentication Information used for SRP*/
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationAppleID, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationPassword, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationiCloudEnvironment, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationAuthToken, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationEscrowProxyURL, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupIDMSRecoveryKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupFMiPRecoveryKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupFMiPUUIDKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAuthenticationDSID, NSString*);
+
+/* CDP recovery information */
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUseCachedPassphraseKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPassphraseKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryKeyKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupContainsiCDPDataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSilentRecoveryAttemptKey, NSString*);
+
+
+/* Escrow Record Fields set by SecureBackup*/
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupIsEnabledKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesRecoveryKeyKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupLastBackupTimestampKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupLastBackupDateKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowTrustStatusKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordStatusKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordIDKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoDataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoSerialNumberKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupPeerInfoOSVersionKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAlliCDPRecordsKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordLabelKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowedSPKIKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBottleIDKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSerialNumberKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBuildVersionKey, NSString*);
+
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesRandomPassphraseKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesComplexPassphraseKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesNumericPassphraseKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupNumericPassphraseLengthKey, NSString*);
+
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryRequiresVerificationTokenKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupAccountIsHighSecurityKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupSMSTargetInfoKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupMetadataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupUsesMultipleiCSCKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupClientMetadataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBottleValidityKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupEscrowDateKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRemainingAttemptsKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupCoolOffEndKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecoveryStatusKey, NSString*);
+
+#pragma clang diagnostic pop
+
+static NSString * const kCliqueSecureBackupTimestampKey                = @"com.apple.securebackup.timestamp";
+static NSString * const kCliqueEscrowServiceRecordMetadataKey          = @"metadata";
+static NSString * const kCliqueSecureBackupEncodedMetadataKey          = @"encodedMetadata";
+static NSString * const kCliqueSecureBackupKeybagDigestKey             = @"BackupKeybagDigest";
+static NSString * const kCliqueSecureBackupMetadataTimestampKey        = @"SecureBackupMetadataTimestamp";
+static NSString * const kCliqueSecureBackupDeviceColor                 = @"device_color";
+static NSString * const kCliqueSecureBackupDeviceEnclosureColor        = @"device_enclosure_color";
+static NSString * const kCliqueSecureBackupDeviceMID                   = @"device_mid";
+static NSString * const kCliqueSecureBackupDeviceModel                 = @"device_model";
+static NSString * const kCliqueSecureBackupDeviceModelClass            = @"device_model_class";
+static NSString * const kCliqueSecureBackupDeviceModelVersion          = @"device_model_version";
+static NSString * const kCliqueSecureBackupDeviceName                  = @"device_name";
+static NSString * const kCliqueSecureBackupDevicePlatform              = @"device_platform";
+static NSString * const kCliqueSecureBackupSilentAttemptAllowed        = @"silentAttemptAllowed";
+
+@implementation OTEscrowTranslation
+
+//dictionary to escrow auth
++ (OTEscrowAuthenticationInformation*) dictionaryToEscrowAuthenticationInfo:(NSDictionary*)dictionary
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+    
+    OTEscrowAuthenticationInformation* escrowAuthInfo = [[OTEscrowAuthenticationInformation alloc] init];
+    escrowAuthInfo.authenticationAppleid = dictionary[getkSecureBackupAuthenticationAppleID()];
+    escrowAuthInfo.authenticationAuthToken = dictionary[getkSecureBackupAuthenticationAuthToken()];
+    escrowAuthInfo.authenticationDsid = dictionary[getkSecureBackupAuthenticationDSID()];
+    escrowAuthInfo.authenticationEscrowproxyUrl = dictionary[getkSecureBackupAuthenticationEscrowProxyURL()];
+    escrowAuthInfo.authenticationIcloudEnvironment = dictionary[getkSecureBackupAuthenticationiCloudEnvironment()];
+    escrowAuthInfo.authenticationPassword = dictionary[getkSecureBackupAuthenticationPassword()];
+    escrowAuthInfo.fmipUuid = dictionary[getkSecureBackupFMiPUUIDKey()];
+    escrowAuthInfo.fmipRecovery = [dictionary[getkSecureBackupFMiPRecoveryKey()] boolValue];
+    escrowAuthInfo.idmsRecovery = [dictionary[getkSecureBackupIDMSRecoveryKey()] boolValue];
+
+    return escrowAuthInfo;
+}
+
+//escrow auth to dictionary
++ (NSDictionary*) escrowAuthenticationInfoToDictionary:(OTEscrowAuthenticationInformation*)escrowAuthInfo
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
+    if(![escrowAuthInfo.authenticationAppleid isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationAppleID()] = escrowAuthInfo.authenticationAppleid;
+    }
+    if(![escrowAuthInfo.authenticationAuthToken isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationAuthToken()] = escrowAuthInfo.authenticationAuthToken;
+    }
+    if(![escrowAuthInfo.authenticationDsid isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationDSID()] = escrowAuthInfo.authenticationDsid;
+    }
+    if(![escrowAuthInfo.authenticationEscrowproxyUrl isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationEscrowProxyURL()] = escrowAuthInfo.authenticationEscrowproxyUrl;
+    }
+    if(![escrowAuthInfo.authenticationIcloudEnvironment isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationiCloudEnvironment()] = escrowAuthInfo.authenticationIcloudEnvironment;
+    }
+    if(![escrowAuthInfo.authenticationPassword isEqualToString:@""]){
+        dictionary[getkSecureBackupAuthenticationPassword()] = escrowAuthInfo.authenticationPassword;
+    }
+    if(![escrowAuthInfo.fmipUuid isEqualToString:@""]){
+        dictionary[getkSecureBackupFMiPUUIDKey()] = escrowAuthInfo.fmipUuid;
+    }
+    dictionary[getkSecureBackupFMiPRecoveryKey()] = escrowAuthInfo.fmipRecovery ? @YES : @NO;
+    dictionary[getkSecureBackupIDMSRecoveryKey()] = escrowAuthInfo.idmsRecovery ? @YES : @NO;
+
+    return dictionary;
+}
+
++ (OTCDPRecoveryInformation*)dictionaryToCDPRecoveryInformation:(NSDictionary*)dictionary
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    OTCDPRecoveryInformation* info = [[OTCDPRecoveryInformation alloc] init];
+    info.recoverySecret = dictionary[getkSecureBackupPassphraseKey()];
+    info.useCachedSecret = [dictionary[getkSecureBackupUseCachedPassphraseKey()] boolValue];
+    info.recoveryKey = dictionary[getkSecureBackupRecoveryKeyKey()];
+    info.usePreviouslyCachedRecoveryKey = [dictionary[getkSecureBackupUsesRecoveryKeyKey()] boolValue];
+    info.silentRecoveryAttempt = [dictionary[@"SecureBackupSilentRecoveryAttempt"] boolValue];
+    info.containsIcdpData =[dictionary[getkSecureBackupContainsiCDPDataKey()] boolValue];
+    info.usesMultipleIcsc = [dictionary[getkSecureBackupUsesMultipleiCSCKey()] boolValue];
+    return info;
+}
+
++ (NSDictionary*)cdpRecoveryInformationToDictionary:(OTCDPRecoveryInformation*)info
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
+    dictionary[getkSecureBackupPassphraseKey()] = info.recoverySecret;
+    dictionary[getkSecureBackupUseCachedPassphraseKey()] = info.useCachedSecret ? @YES : @NO;
+    dictionary[getkSecureBackupRecoveryKeyKey()] = info.recoveryKey;
+    dictionary[getkSecureBackupUsesRecoveryKeyKey()] = info.usePreviouslyCachedRecoveryKey ? @YES : @NO;
+    dictionary[@"SecureBackupSilentRecoveryAttempt"] = info.silentRecoveryAttempt ? @YES : @NO;
+    dictionary[getkSecureBackupContainsiCDPDataKey()] = info.containsIcdpData ? @YES : @NO;
+    dictionary[getkSecureBackupUsesMultipleiCSCKey()] = info.usesMultipleIcsc ? @YES : @NO;
+    
+    return dictionary;
+}
+
++ (NSDate *)_dateWithSecureBackupDateString:(NSString *)dateString
+{
+    NSDateFormatter *dateFormatter = [NSDateFormatter new];
+    dateFormatter.dateFormat = @"dd-MM-yyyy HH:mm:ss";
+    NSDate *ret = [dateFormatter dateFromString:dateString];
+
+    if (ret) {
+        return ret;
+    }
+    // New date format is GMT
+    dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+    dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
+    return [dateFormatter dateFromString:dateString];
+}
+
++ (NSString*)_stringWithSecureBackupDate:(NSDate*) date
+{
+    NSDateFormatter *dateFormatter = [NSDateFormatter new];
+    dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
+    dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss";
+    return [dateFormatter stringFromDate: date];
+}
+
++ (OTEscrowRecordMetadata *) dictionaryToMetadata:(NSDictionary*)dictionary
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    OTEscrowRecordMetadata *metadata = [[OTEscrowRecordMetadata alloc] init];
+
+    metadata.backupKeybagDigest = dictionary[kCliqueSecureBackupKeybagDigestKey];
+    metadata.secureBackupUsesMultipleIcscs = [dictionary[getkSecureBackupUsesMultipleiCSCKey()] boolValue];
+    metadata.bottleId = dictionary[getkSecureBackupBottleIDKey()];
+    metadata.bottleValidity = dictionary[@"bottleValid"];
+    NSDate* secureBackupTimestamp = [OTEscrowTranslation _dateWithSecureBackupDateString: dictionary[kCliqueSecureBackupTimestampKey]];
+
+    metadata.secureBackupTimestamp = [secureBackupTimestamp timeIntervalSince1970];
+    metadata.escrowedSpki = dictionary[getkSecureBackupEscrowedSPKIKey()];
+    metadata.peerInfo = dictionary[getkSecureBackupPeerInfoDataKey()];
+    metadata.serial = dictionary[getkSecureBackupSerialNumberKey()];
+
+    NSDictionary* escrowInformationMetadataClientMetadata = dictionary[getkSecureBackupClientMetadataKey()];
+    metadata.clientMetadata = [[OTEscrowRecordMetadataClientMetadata alloc] init];
+    NSNumber *platform = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDevicePlatform];
+    metadata.clientMetadata.devicePlatform = [platform longLongValue];
+
+    NSDate* secureBackupMetadataTimestamp = [OTEscrowTranslation _dateWithSecureBackupDateString: escrowInformationMetadataClientMetadata[kCliqueSecureBackupMetadataTimestampKey]];
+    metadata.clientMetadata.secureBackupMetadataTimestamp = [secureBackupMetadataTimestamp timeIntervalSince1970];
+
+    NSNumber *passphraseLength = escrowInformationMetadataClientMetadata[getkSecureBackupNumericPassphraseLengthKey()];
+    metadata.clientMetadata.secureBackupNumericPassphraseLength = [passphraseLength longLongValue];
+    metadata.clientMetadata.secureBackupUsesComplexPassphrase = [escrowInformationMetadataClientMetadata[getkSecureBackupUsesComplexPassphraseKey()] boolValue];
+    metadata.clientMetadata.secureBackupUsesNumericPassphrase = [escrowInformationMetadataClientMetadata[getkSecureBackupUsesNumericPassphraseKey()] boolValue];
+    metadata.clientMetadata.deviceColor = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceColor];
+    metadata.clientMetadata.deviceEnclosureColor = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceEnclosureColor];
+    metadata.clientMetadata.deviceMid = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceMID];
+    metadata.clientMetadata.deviceModel = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModel];
+    metadata.clientMetadata.deviceModelClass = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModelClass];
+    metadata.clientMetadata.deviceModelVersion = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceModelVersion];
+    metadata.clientMetadata.deviceName = escrowInformationMetadataClientMetadata[kCliqueSecureBackupDeviceName];
+
+    return metadata;
+}
+
+//dictionary to escrow record
++ (OTEscrowRecord*) dictionaryToEscrowRecord:(NSDictionary*)dictionary
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    OTEscrowRecord* record = [[OTEscrowRecord alloc] init];
+    NSDate* creationDate = dictionary[getkSecureBackupEscrowDateKey()];
+    record.creationDate = [creationDate timeIntervalSince1970];
+    NSDictionary* escrowInformationMetadata = dictionary[kCliqueEscrowServiceRecordMetadataKey];
+    record.escrowInformationMetadata = [OTEscrowTranslation dictionaryToMetadata:escrowInformationMetadata];
+
+    NSNumber *remainingAttempts = dictionary[getkSecureBackupRemainingAttemptsKey()];
+
+    record.remainingAttempts = [remainingAttempts longLongValue];
+    record.label = dictionary[getkSecureBackupRecordLabelKey()];
+    record.recordStatus = [dictionary[getkSecureBackupRecordStatusKey()] isEqualToString:@"valid"] ? OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID : OTEscrowRecord_RecordStatus_RECORD_STATUS_INVALID;
+    record.silentAttemptAllowed = [dictionary[kCliqueSecureBackupSilentAttemptAllowed] boolValue];
+    record.recordId = dictionary[getkSecureBackupRecordIDKey()];
+    record.serialNumber = dictionary[getkSecureBackupPeerInfoSerialNumberKey()];
+    if(dictionary[getkSecureBackupCoolOffEndKey()]) {
+        record.coolOffEnd = [dictionary[getkSecureBackupCoolOffEndKey()] longLongValue];
+    }
+    record.recoveryStatus = [dictionary[getkSecureBackupRecoveryStatusKey()] intValue];
+    return record;
+}
+
++ (NSDictionary *) metadataToDictionary:(OTEscrowRecordMetadata*)metadata
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+    dictionary[getkSecureBackupClientMetadataKey()] = [NSMutableDictionary dictionary];
+
+    dictionary[kCliqueSecureBackupKeybagDigestKey] = metadata.backupKeybagDigest;
+    dictionary[getkSecureBackupUsesMultipleiCSCKey()]  = [[NSNumber alloc]initWithUnsignedLongLong:metadata.secureBackupUsesMultipleIcscs];
+    dictionary[getkSecureBackupBottleIDKey()] = metadata.bottleId;
+    dictionary[@"bottleValid"] = metadata.bottleValidity;
+    dictionary[kCliqueSecureBackupTimestampKey]  = [OTEscrowTranslation _stringWithSecureBackupDate: [NSDate dateWithTimeIntervalSince1970: metadata.secureBackupTimestamp]];
+    dictionary[getkSecureBackupEscrowedSPKIKey()] = metadata.escrowedSpki;
+    dictionary[getkSecureBackupPeerInfoDataKey()] = metadata.peerInfo;
+    dictionary[getkSecureBackupSerialNumberKey()] = metadata.serial;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDevicePlatform] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.devicePlatform];
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupMetadataTimestampKey] = [OTEscrowTranslation _stringWithSecureBackupDate: [NSDate dateWithTimeIntervalSince1970: metadata.clientMetadata.secureBackupMetadataTimestamp]];
+    dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupNumericPassphraseLengthKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupNumericPassphraseLength];
+    dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupUsesComplexPassphraseKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupUsesComplexPassphrase];
+    dictionary[getkSecureBackupClientMetadataKey()][getkSecureBackupUsesNumericPassphraseKey()] = [[NSNumber alloc]initWithUnsignedLongLong: metadata.clientMetadata.secureBackupUsesNumericPassphrase];
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceColor] = metadata.clientMetadata.deviceColor;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceEnclosureColor] = metadata.clientMetadata.deviceEnclosureColor;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceMID] = metadata.clientMetadata.deviceMid;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModel] = metadata.clientMetadata.deviceModel;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModelClass] = metadata.clientMetadata.deviceModelClass;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceModelVersion] = metadata.clientMetadata.deviceModelVersion;
+    dictionary[getkSecureBackupClientMetadataKey()][kCliqueSecureBackupDeviceName] = metadata.clientMetadata.deviceName;
+
+    return dictionary;
+}
+
+//escrow record to dictionary
++ (NSDictionary*) escrowRecordToDictionary:(OTEscrowRecord*)escrowRecord
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
+    dictionary[getkSecureBackupEscrowDateKey()] = [NSDate dateWithTimeIntervalSince1970: escrowRecord.creationDate];
+
+    dictionary[kCliqueEscrowServiceRecordMetadataKey] = [OTEscrowTranslation metadataToDictionary: escrowRecord.escrowInformationMetadata];
+
+    dictionary[getkSecureBackupRemainingAttemptsKey()] = [[NSNumber alloc]initWithUnsignedLongLong:escrowRecord.remainingAttempts];
+    dictionary[getkSecureBackupRecordLabelKey()] = escrowRecord.label;
+    dictionary[getkSecureBackupRecordStatusKey()] = escrowRecord.recordStatus == OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID ? @"valid" : @"invalid";
+    dictionary[kCliqueSecureBackupSilentAttemptAllowed] = [[NSNumber alloc] initWithUnsignedLongLong: escrowRecord.silentAttemptAllowed];
+    dictionary[getkSecureBackupRecordIDKey()] = escrowRecord.recordId;
+    dictionary[getkSecureBackupPeerInfoSerialNumberKey()] = escrowRecord.serialNumber;
+    dictionary[getkSecureBackupCoolOffEndKey()] = @(escrowRecord.coolOffEnd);
+    dictionary[getkSecureBackupRecoveryStatusKey()] = @(escrowRecord.recoveryStatus);
+
+    return dictionary;
+}
+
++ (OTICDPRecordContext*)dictionaryToCDPRecordContext:(NSDictionary*)dictionary
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    OTICDPRecordContext* context = [[OTICDPRecordContext alloc] init];
+    context.authInfo = [OTEscrowTranslation dictionaryToEscrowAuthenticationInfo:dictionary];
+    context.cdpInfo = [OTEscrowTranslation dictionaryToCDPRecoveryInformation:dictionary];
+
+    return context;
+}
+
++ (NSDictionary*)CDPRecordContextToDictionary:(OTICDPRecordContext*)context
+{
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        return nil;
+    }
+
+    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
+
+    [dictionary addEntriesFromDictionary:[OTEscrowTranslation escrowAuthenticationInfoToDictionary:context.authInfo]];
+    [dictionary addEntriesFromDictionary:[OTEscrowTranslation cdpRecoveryInformationToDictionary:context.cdpInfo]];
+
+    return dictionary;
+}
+
++ (BOOL)supportedRestorePath:(OTICDPRecordContext *)cdpContext
+{
+    return (cdpContext.authInfo.idmsRecovery == false
+            && (cdpContext.authInfo.fmipUuid == nil || [cdpContext.authInfo.fmipUuid isEqualToString:@""])
+            && cdpContext.authInfo.fmipRecovery == false
+            && (cdpContext.cdpInfo.recoveryKey == nil || [cdpContext.cdpInfo.recoveryKey isEqualToString:@""])
+            && cdpContext.cdpInfo.usePreviouslyCachedRecoveryKey == false);
+}
+
+@end
+
diff --git a/keychain/OctagonTrust/OctagonTrust.h b/keychain/OctagonTrust/OctagonTrust.h
new file mode 100644 (file)
index 0000000..72d31de
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#if __OBJC2__
+
+#import <Foundation/Foundation.h>
+#import <Security/OTClique.h>
+#import <OctagonTrust/OTEscrowRecord.h>
+#import <OctagonTrust/OTEscrowTranslation.h>
+#import <OctagonTrust/OTEscrowAuthenticationInformation.h>
+#import <OctagonTrust/OTICDPRecordContext.h>
+#import <OctagonTrust/OTICDPRecordSilentContext.h>
+#import <OctagonTrust/OTEscrowRecordMetadata.h>
+#import <OctagonTrust/OTEscrowRecordMetadataClientMetadata.h>
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+//! Project version number for OctagonTrust.
+FOUNDATION_EXPORT double OctagonTrustVersionNumber;
+
+//! Project version string for OctagonTrust.
+FOUNDATION_EXPORT const unsigned char OctagonTrustVersionString[];
+
+extern NSString* OTCKContainerName;
+
+@interface OTConfigurationContext(Framework)
+@property (nonatomic, copy, nullable) OTEscrowAuthenticationInformation* escrowAuth;
+@end
+
+@interface OTClique(Framework)
+
+/* *
+ * @abstract   Fetch recommended iCDP escrow records
+ *
+ * @param   data, context containing parameters to setup OTClique
+ * @param  error, error gets filled if something goes horribly wrong
+ *
+ * @return  array of escrow records that can get a device back into trust
+ */
++ (NSArray<OTEscrowRecord*>* _Nullable)fetchEscrowRecords:(OTConfigurationContext*)data error:(NSError**)error;
+
+
+/* *
+ * @abstract   Fetch all iCDP escrow records
+ *
+ * @param   data, context containing parameters to setup OTClique
+ * @param  error, error gets filled if something goes horribly wrong
+ *
+ * @return  array of all escrow records (viable and legacy)
+ */
++ (NSArray<OTEscrowRecord*>* _Nullable)fetchAllEscrowRecords:(OTConfigurationContext*)data error:(NSError**)error;
+
+/* *
+ * @abstract   Perform escrow recovery of a particular record (not silent)
+ *
+ * @param   data, context containing parameters to setup OTClique
+ * @param   cdpContext, context containing parameters used in recovery
+ * @param   escrowRecord, the chosen escrow record to recover from
+ * @param  error, error gets filled if something goes horribly wrong
+ *
+ * @return  clique, returns a new clique instance
+ */
++ (instancetype _Nullable)performEscrowRecovery:(OTConfigurationContext*)data
+                                     cdpContext:(OTICDPRecordContext*)cdpContext
+                                   escrowRecord:(OTEscrowRecord*)escrowRecord
+                                          error:(NSError**)error;
+
+/* *
+ * @abstract   Perform a silent escrow recovery
+ *
+ * @param   data, context containing parameters to setup OTClique
+ * @param   cdpContext, context containing parameters used in recovery
+ * @param   allRecords, all fetched escrow records
+ * @param  error, error gets filled if something goes horribly wrong
+ * @return  clique, returns a new clique instance
+ */
++ (instancetype _Nullable)performSilentEscrowRecovery:(OTConfigurationContext*)data
+                                           cdpContext:(OTICDPRecordContext*)cdpContext
+                                           allRecords:(NSArray<OTEscrowRecord*>*)allRecords
+                                                error:(NSError**)error;
+
++ (BOOL) invalidateEscrowCache:(OTConfigurationContext*)data error:(NSError**)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/keychain/OctagonTrust/OctagonTrust.m b/keychain/OctagonTrust/OctagonTrust.m
new file mode 100644 (file)
index 0000000..b24f535
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+* Copyright (c) 2020 Apple Inc. All Rights Reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#if __OBJC2__
+
+#import "OctagonTrust.h"
+#import <Security/OTClique+Private.h>
+#import <utilities/debugging.h>
+#import "OTEscrowTranslation.h"
+
+#import <SoftLinking/SoftLinking.h>
+#import <CloudServices/SecureBackup.h>
+#import <CloudServices/SecureBackupConstants.h>
+#import "keychain/OctagonTrust/categories/OctagonTrustEscrowRecoverer.h"
+#import "keychain/ot/OTDefines.h"
+#import "keychain/ot/OTControl.h"
+#import "keychain/ot/OTClique+Private.h"
+#import <Security/OctagonSignPosts.h>
+#include <utilities/SecCFRelease.h>
+
+SOFT_LINK_FRAMEWORK(PrivateFrameworks, KeychainCircle);
+SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CloudServices);
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstrict-prototypes"
+SOFT_LINK_CLASS(CloudServices, SecureBackup);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupErrorDomain, NSErrorDomain);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupiCDPRecordsKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupMetadataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordIDKey, NSString*);
+
+SOFT_LINK_CONSTANT(CloudServices, kEscrowServiceRecordDataKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupKeybagDigestKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupBagPasswordKey, NSString*);
+SOFT_LINK_CONSTANT(CloudServices, kSecureBackupRecordLabelKey, NSString*);
+
+#pragma clang diagnostic pop
+
+static NSString * const kOTEscrowAuthKey = @"kOTEscrowAuthKey";
+NSString* OTCKContainerName = @"com.apple.security.keychain";
+
+@implementation OTConfigurationContext(Framework)
+
+@dynamic escrowAuth;
+
+-(void) setEscrowAuth:(id)e
+{
+    objc_setAssociatedObject(self, (__bridge const void * _Nonnull)(kOTEscrowAuthKey), e, OBJC_ASSOCIATION_ASSIGN);
+
+}
+- (id) escrowAuth
+{
+    return objc_getAssociatedObject(self, (__bridge const void * _Nonnull)(kOTEscrowAuthKey));
+}
+
+@end
+
+@implementation OTClique(Framework)
+
++ (NSArray<OTEscrowRecord*>*)filterViableSOSRecords:(NSArray<OTEscrowRecord*>*)nonViable
+{
+    NSMutableArray<OTEscrowRecord*>* viableSOS = [NSMutableArray array];
+    for(OTEscrowRecord* record in nonViable) {
+        if (record.viabilityStatus == OTEscrowRecord_SOSViability_SOS_VIABLE) {
+            [viableSOS addObject:record];
+        }
+    }
+
+    return viableSOS;
+}
+
+/*
+ * desired outcome from filtering on an iOS/macOS platform:
+ *              Escrow Record data validation outcome               Outcome of fetch records
+                Octagon Viable, SOS Viable                          Record gets recommended, normal Octagon and SOS join
+                Octagon Viable, SOS Doesn't work                    Record gets recommended, normal Octagon join, SOS reset
+                Octagon Doesn't work, SOS Viable                    Record gets recommended, Octagon reset, normal SOS join
+                Octagon Doesn't work, SOS Doesn't work              no records recommended.  Force user to reset all protected data
+
+ * desired outcome from filtering on an watchOS/tvOS/etc:
+ Escrow Record data validation outcome                           Outcome of fetch records
+             Octagon Viable, SOS Viable                          Record gets recommended, normal Octagon and SOS noop
+             Octagon Viable, SOS Doesn't work                    Record gets recommended, normal Octagon join, SOS noop
+             Octagon Doesn't work, SOS Viable                    Record gets recommended, Octagon reset, SOS noop
+             Octagon Doesn't work, SOS Doesn't work              no records recommended.  Force user to reset all protected data
+*/
+
++ (NSArray<OTEscrowRecord*>* _Nullable)filterRecords:(NSArray<OTEscrowRecord*>*)allRecords
+{
+    NSMutableArray<OTEscrowRecord*>* viable = [NSMutableArray array];
+    NSMutableArray<OTEscrowRecord*>* partial = [NSMutableArray array];
+    NSMutableArray<OTEscrowRecord*>* nonViable = [NSMutableArray array];
+
+    for (OTEscrowRecord* record in allRecords) {
+        if(record.recordViability == OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE &&
+           record.escrowInformationMetadata.bottleId != nil &&
+           [record.escrowInformationMetadata.bottleId length] != 0) {
+            [viable addObject:record];
+        } else if(record.recordViability == OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE &&
+                  record.escrowInformationMetadata.bottleId != nil &&
+                  [record.escrowInformationMetadata.bottleId length] != 0) {
+            [partial addObject:record];
+        } else {
+            [nonViable addObject:record];
+        }
+    }
+
+    for(OTEscrowRecord* record in viable) {
+        secnotice("octagontrust-fetchescrowrecords", "viable record: %@ serial:%@ bottleID:%@ silent allowed:%d",
+                  record.label,
+                  record.escrowInformationMetadata.serial,
+                  record.escrowInformationMetadata.bottleId,
+                  (int)record.silentAttemptAllowed);
+    }
+    for(OTEscrowRecord* record in partial) {
+        secnotice("octagontrust-fetchescrowrecords", "partially viable record: %@ serial:%@ bottleID:%@ silent allowed:%d",
+                  record.label,
+                  record.escrowInformationMetadata.serial,
+                  record.escrowInformationMetadata.bottleId,
+                  (int)record.silentAttemptAllowed);
+    }
+    for(OTEscrowRecord* record in nonViable) {
+        secnotice("octagontrust-fetchescrowrecords", "nonviable record: %@ serial:%@ bottleID:%@ silent allowed:%d",
+                  record.label,
+                  record.escrowInformationMetadata.serial,
+                  record.escrowInformationMetadata.bottleId,
+                  (int)record.silentAttemptAllowed);
+    }
+
+    if ([viable count] > 0) {
+        secnotice("octagontrust-fetchescrowrecords", "Returning %d viable records", (int)[viable count]);
+        return viable;
+    }
+
+    if ([partial count] > 0) {
+        secnotice("octagontrust-fetchescrowrecords", "Returning %d partially viable records", (int)[partial count]);
+        return partial;
+    }
+
+    if (OctagonPlatformSupportsSOS()) {
+        NSArray<OTEscrowRecord*>* viableSOSRecords = [self filterViableSOSRecords:nonViable];
+        secnotice("octagontrust-fetchescrowrecords", "Returning %d sos viable records", (int)[viableSOSRecords count]);
+        return viableSOSRecords;
+    }
+
+    secnotice("octagontrust-fetchescrowrecords", "no viable records!");
+
+    return nil;
+}
+
++ (NSArray<OTEscrowRecord*>* _Nullable)fetchAndHandleEscrowRecords:(OTConfigurationContext*)data shouldFilter:(BOOL)shouldFiler error:(NSError**)error
+{
+    OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameFetchEscrowRecords);
+    bool subTaskSuccess = false;
+
+    NSError* localError = nil;
+    NSArray* escrowRecordDatas = [OTClique fetchEscrowRecordsInternal:data error:&localError];
+    if(localError) {
+        secerror("octagontrust-fetchAndHandleEscrowRecords: failed to fetch escrow records: %@", localError);
+        if(error){
+            *error = localError;
+        }
+        OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowRecords, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowRecords), (int)subTaskSuccess);
+        return nil;
+    }
+
+    NSMutableArray<OTEscrowRecord*>* escrowRecords = [NSMutableArray array];
+
+    for(NSData* recordData in escrowRecordDatas){
+        OTEscrowRecord* translated = [[OTEscrowRecord alloc] initWithData:recordData];
+        if(translated.escrowInformationMetadata.bottleValidity == nil || [translated.escrowInformationMetadata.bottleValidity isEqualToString:@""]){
+            switch(translated.recordViability) {
+                case OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE:
+                    translated.escrowInformationMetadata.bottleValidity = @"valid";
+                    break;
+                case OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE:
+                    translated.escrowInformationMetadata.bottleValidity = @"valid";
+                    break;
+                case OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY:
+                    translated.escrowInformationMetadata.bottleValidity = @"invalid";
+                    break;
+            }
+        }
+        if(translated.recordId == nil || [translated.recordId isEqualToString:@""]){
+            translated.recordId = [[translated.label stringByReplacingOccurrencesOfString:OTEscrowRecordPrefix withString:@""] mutableCopy];
+        }
+        if((translated.serialNumber == nil || [translated.serialNumber isEqualToString:@""]) && translated.escrowInformationMetadata.peerInfo != nil && [translated.escrowInformationMetadata.peerInfo length] > 0) {
+            CFErrorRef cfError = NULL;
+            SOSPeerInfoRef peer = SOSPeerInfoCreateFromData(kCFAllocatorDefault, &cfError, (__bridge CFDataRef)translated.escrowInformationMetadata.peerInfo);
+            if(cfError != NULL){
+                secnotice("octagontrust-handleEscrowRecords", "failed to create sos peer info: %@", cfError);
+            } else {
+                translated.serialNumber = (NSString*)CFBridgingRelease(SOSPeerInfoCopySerialNumber(peer));
+            }
+        }
+
+        [escrowRecords addObject:translated];
+    }
+    subTaskSuccess = true;
+    OctagonSignpostEnd(signPost, OctagonSignpostNameFetchEscrowRecords, OctagonSignpostNumber1(OctagonSignpostNameFetchEscrowRecords), (int)subTaskSuccess);
+
+    if (shouldFiler == YES) {
+        return [OTClique filterRecords:escrowRecords];
+    }
+
+    return escrowRecords;
+}
+
++ (NSArray<OTEscrowRecord*>* _Nullable)fetchAllEscrowRecords:(OTConfigurationContext*)data error:(NSError**)error
+{
+#if OCTAGON
+    secnotice("octagontrust-fetchallescrowrecords", "fetching all escrow records for context :%@, altdsid:%@", data.context, data.altDSID);
+    return [OTClique fetchAndHandleEscrowRecords:data shouldFilter:NO error:error];
+#else
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return nil;
+#endif
+}
+
++ (NSArray<OTEscrowRecord*>* _Nullable)fetchEscrowRecords:(OTConfigurationContext*)data error:(NSError**)error
+{
+#if OCTAGON
+    if (OctagonIsOptimizationEnabled() && OctagonIsEscrowRecordFetchEnabled()) {
+        secnotice("octagontrust-fetchescrowrecords", "fetching filtered escrow records for context with feature flag enabled:%@, altdsid:%@", data.context, data.altDSID);
+        return [OTClique fetchAndHandleEscrowRecords:data shouldFilter:YES error:error];
+    } else {
+        if ([OTClique isCloudServicesAvailable] == NO) {
+            if (error) {
+                *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+            }
+            return NULL;
+        }
+
+        OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameGetAccountInfo);
+        secnotice("octagontrust-fetchescrowrecords", "fetching escrow records for context with feature flag disabled:%@, altdsid:%@", data.context, data.altDSID);
+        id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
+
+        OTEscrowAuthenticationInformation *escrowAuth = nil;
+        NSDictionary* escrowAuthDictionary = nil;
+        if(data.escrowAuth != nil) {
+            escrowAuth = data.escrowAuth;
+            escrowAuthDictionary = [OTEscrowTranslation escrowAuthenticationInfoToDictionary:escrowAuth];
+        }
+        NSDictionary* results = nil;
+        NSError* recoverError = [sb getAccountInfoWithInfo:escrowAuthDictionary results:&results];
+        bool subTaskSuccess = false;
+        if(recoverError || results == nil) {
+            secerror("octagontrust-fetchescrowrecords: error fetching escrow records: %@", recoverError);
+            if(error){
+                *error = recoverError;
+            }
+            OctagonSignpostEnd(signPost, OctagonSignpostNameGetAccountInfo, OctagonSignpostNumber1(OctagonSignpostNameGetAccountInfo), (int)subTaskSuccess);
+            return nil;
+        } else {
+            secnotice("octagontrust-fetchescrowrecords", "recovered accountWithInfo results: %@", results);
+            NSArray *icdpRecords = results[getkSecureBackupiCDPRecordsKey()];
+            secnotice("octagontrust-fetchescrowrecords", "recovered iCDP records: %@", icdpRecords);
+
+            NSMutableArray<OTEscrowRecord*>* records = [NSMutableArray array];
+            for (NSDictionary *dictionaryRecord in icdpRecords) {
+                OTEscrowRecord* otEscrowRecord = [OTEscrowTranslation dictionaryToEscrowRecord:dictionaryRecord];
+                [records addObject:otEscrowRecord];
+            }
+            secnotice("octagontrust-fetchescrowrecords", "translated dictionary records to escrow record protos: %@", records);
+
+            subTaskSuccess = true;
+            OctagonSignpostEnd(signPost, OctagonSignpostNameGetAccountInfo, OctagonSignpostNumber1(OctagonSignpostNameGetAccountInfo), (int)subTaskSuccess);
+
+            return records;
+        }
+    }
+#else
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return nil;
+#endif
+}
+
++ (OTClique* _Nullable)handleRecoveryResults:(OTConfigurationContext*)data recoveredInformation:(NSDictionary*)recoveredInformation sosViability:(OTEscrowRecord_SOSViability)sosViability performedSilentBurn:(BOOL)performedSilentBurn recoverError:(NSError*)recoverError error:(NSError**)error
+{
+    if ([self isCloudServicesAvailable] == NO) {
+        if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+        }
+        return nil;
+    }
+
+    OTClique* clique = [[OTClique alloc] initWithContextData:data];
+    BOOL resetToOfferingOccured = NO;
+
+    if(recoverError) {
+        secnotice("octagontrust-handleRecoveryResults", "sbd escrow recovery failed: %@", recoverError);
+        if(recoverError.code == 40 /* kSecureBackupRestoringLegacyBackupKeychainError */ && [recoverError.domain isEqualToString:getkSecureBackupErrorDomain()]) {
+            if([OTClique platformSupportsSOS]) {
+                secnotice("octagontrust-handleRecoveryResults", "Can't restore legacy backup with no keybag. Resetting SOS to offering");
+                CFErrorRef resetToOfferingError = NULL;
+                bool successfulReset = SOSCCResetToOffering(&resetToOfferingError);
+                resetToOfferingOccured = YES;
+                if(!successfulReset || resetToOfferingError) {
+                    secerror("octagontrust-handleRecoveryResults: failed to reset to offering:%@", resetToOfferingError);
+                } else {
+                    secnotice("octagontrust-handleRecoveryResults", "resetting SOS circle successful");
+                }
+                CFReleaseNull(resetToOfferingError);
+            } else {
+                secnotice("octagontrust-handleRecoveryResults", "Legacy restore failed on a non-SOS platform");
+            }
+        } else {
+            if(error) {
+                *error = recoverError;
+            }
+            return nil;
+        }
+    }
+
+    NSError* localError = nil;
+    OTControl* control = nil;
+
+    if (data.otControl) {
+        control = data.otControl;
+    } else {
+        control = [data makeOTControl:&localError];
+    }
+    if (!control) {
+        secerror("octagontrust-handleRecoveryResults: unable to create otcontrol: %@", localError);
+        if (error) {
+            *error = localError;
+        }
+        return nil;
+    }
+
+    // look for OT Bottles
+    NSString *bottleID = recoveredInformation[@"bottleID"];
+    NSString *isValid = recoveredInformation[@"bottleValid"];
+    NSData *bottledPeerEntropy = recoveredInformation[@"EscrowServiceEscrowData"][@"BottledPeerEntropy"];
+    bool shouldResetOctagon = false;
+
+    if(bottledPeerEntropy && bottleID && [isValid isEqualToString:@"valid"]){
+        secnotice("octagontrust-handleRecoveryResults", "recovering from bottle: %@", bottleID);
+        __block NSError* restoreBottleError = nil;
+        OctagonSignpost bottleRestoreSignPost = performedSilentBurn ? OctagonSignpostBegin(OctagonSignpostNamePerformOctagonJoinForSilent) : OctagonSignpostBegin(OctagonSignpostNamePerformOctagonJoinForNonSilent);
+
+        //restore bottle!
+        [control restore:OTCKContainerName
+               contextID:data.context
+              bottleSalt:data.altDSID
+                 entropy:bottledPeerEntropy
+                bottleID:bottleID
+                   reply:^(NSError * _Nullable restoreError) {
+            if(restoreError) {
+                secnotice("octagontrust-handleRecoveryResults", "restore bottle errored: %@", restoreError);
+            } else {
+                secnotice("octagontrust-handleRecoveryResults", "restoring bottle succeeded");
+            }
+            restoreBottleError = restoreError;
+            if (performedSilentBurn) {
+                OctagonSignpostEnd(bottleRestoreSignPost, OctagonSignpostNamePerformOctagonJoinForSilent, OctagonSignpostNumber1(OctagonSignpostNamePerformOctagonJoinForSilent), (int)true);
+            } else {
+                OctagonSignpostEnd(bottleRestoreSignPost, OctagonSignpostNamePerformOctagonJoinForNonSilent, OctagonSignpostNumber1(OctagonSignpostNamePerformOctagonJoinForNonSilent), (int)true);
+            }
+        }];
+
+        if(restoreBottleError) {
+            if(error){
+                *error = restoreBottleError;
+            }
+            return nil;
+        }
+    } else {
+        shouldResetOctagon = true;
+    }
+
+    if(shouldResetOctagon) {
+        secnotice("octagontrust-handleRecoveryResults", "bottle %@ is not valid, resetting octagon", bottleID);
+        NSError* resetError = nil;
+        [clique resetAndEstablish:CuttlefishResetReasonNoBottleDuringEscrowRecovery error:&resetError];
+        if(resetError) {
+            secerror("octagontrust-handleRecoveryResults: failed to reset octagon: %@", resetError);
+            if(error){
+                *error = resetError;
+            }
+            return nil;
+        } else{
+            secnotice("octagontrust-handleRecoveryResults", "reset octagon succeeded");
+        }
+    }
+
+    // Join SOS circle if platform is supported and we didn't previously reset SOS
+    if (OctagonPlatformSupportsSOS() && resetToOfferingOccured == NO) {
+        if (sosViability == OTEscrowRecord_SOSViability_SOS_NOT_VIABLE) {
+            secnotice("octagontrust-handleRecoveryResults", "Record will not allow device to join SOS.  Invoking reset to offering");
+            CFErrorRef resetToOfferingError = NULL;
+            bool successfulReset = SOSCCResetToOffering(&resetToOfferingError);
+            if(!successfulReset || resetToOfferingError) {
+                secerror("octagontrust-handleRecoveryResults: failed to reset to offering:%@", resetToOfferingError);
+            } else {
+                secnotice("octagontrust-handleRecoveryResults", "resetting SOS circle successful");
+            }
+            CFReleaseNull(resetToOfferingError);
+        } else {
+            NSError* joinAfterRestoreError = nil;
+            secnotice("octagontrust-handleRecoveryResults", "attempting joinAfterRestore");
+            BOOL joinAfterRestoreResult = [clique joinAfterRestore:&joinAfterRestoreError];
+            if(joinAfterRestoreError || joinAfterRestoreResult == NO) {
+                secnotice("octagontrust-handleRecoveryResults", "failed to join after restore: %@", joinAfterRestoreError);
+            } else {
+                secnotice("octagontrust-handleRecoveryResults", "joinAfterRestore succeeded");
+            }
+        }
+    }
+
+
+    // call SBD to kick off keychain data restore
+    id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
+    NSError* restoreError = nil;
+
+    NSMutableSet <NSString *> *viewsNotToBeRestored = [NSMutableSet set];
+    [viewsNotToBeRestored addObject:@"iCloudIdentity"];
+    [viewsNotToBeRestored addObject:@"PCS-MasterKey"];
+    [viewsNotToBeRestored addObject:@"KeychainV0"];
+
+    NSDictionary *escrowRecords = recoveredInformation[getkEscrowServiceRecordDataKey()];
+    if (escrowRecords == nil) {
+        secnotice("octagontrust-handleRecoveryResults", "unable to request keychain restore, record data missing");
+        return clique;
+    }
+
+
+    NSData *keybagDigest = escrowRecords[getkSecureBackupKeybagDigestKey()];
+    NSData *password = escrowRecords[getkSecureBackupBagPasswordKey()];
+    if (keybagDigest == nil || password == nil) {
+        secnotice("octagontrust-handleRecoveryResults", "unable to request keychain restore, digest or password missing");
+        return clique;
+    }
+
+    BOOL haveBottledPeer = (bottledPeerEntropy && bottleID && [isValid isEqualToString:@"valid"]) || shouldResetOctagon;
+    [sb restoreKeychainAsyncWithPassword:password
+                            keybagDigest:keybagDigest
+                         haveBottledPeer:haveBottledPeer
+                    viewsNotToBeRestored:viewsNotToBeRestored
+                                   error:&restoreError];
+
+    if (restoreError) {
+        secerror("octagontrust-handleRecoveryResults: error restoring keychain items: %@", restoreError);
+    }
+
+    return clique;
+}
+
++ (instancetype _Nullable)performEscrowRecovery:(OTConfigurationContext*)data
+                                     cdpContext:(OTICDPRecordContext*)cdpContext
+                                   escrowRecord:(OTEscrowRecord*)escrowRecord
+                                          error:(NSError**)error
+{
+#if OCTAGON
+    secnotice("octagontrust-performEscrowRecovery", "performEscrowRecovery invoked for context:%@, altdsid:%@", data.context, data.altDSID);
+
+    if ([self isCloudServicesAvailable] == NO) {
+        if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+        }
+        return nil;
+    }
+
+    OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNamePerformEscrowRecovery);
+    bool subTaskSuccess = true;
+
+    id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
+    NSDictionary* recoveredInformation = nil;
+    NSError* recoverError = nil;
+
+    BOOL supportedRestorePath = [OTEscrowTranslation supportedRestorePath:cdpContext];
+    secnotice("octagontrust-performEscrowRecovery", "restore path is supported? %@", supportedRestorePath ? @"YES" : @"NO");
+
+    if (OctagonIsOptimizationEnabled() && supportedRestorePath) {
+        secnotice("octagontrust-performEscrowRecovery", "optimization flag turned on");
+        OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNameRecoverWithCDPContext);
+        recoveredInformation = [sb recoverWithCDPContext:cdpContext escrowRecord:escrowRecord error:&recoverError];
+        subTaskSuccess = (recoverError == nil) ? true : false;
+        OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNameRecoverWithCDPContext, OctagonSignpostNumber1(OctagonSignpostNameRecoverWithCDPContext), (int)subTaskSuccess);
+    } else {
+        secnotice("octagontrust-performEscrowRecovery", "optimization flag turned off");
+        NSMutableDictionary* sbdRecoveryArguments = [[OTEscrowTranslation CDPRecordContextToDictionary:cdpContext] mutableCopy];
+        NSDictionary* metadata = [OTEscrowTranslation metadataToDictionary:escrowRecord.escrowInformationMetadata];
+        sbdRecoveryArguments[getkSecureBackupMetadataKey()] = metadata;
+        sbdRecoveryArguments[getkSecureBackupRecordIDKey()] = escrowRecord.recordId;
+        secnotice("octagontrust-performEscrowRecovery", "using sbdRecoveryArguments: %@", sbdRecoveryArguments);
+
+        OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformRecoveryFromSBD);
+        recoverError = [sb recoverWithInfo:sbdRecoveryArguments results:&recoveredInformation];
+        subTaskSuccess = (recoverError == nil) ? true : false;
+        OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNamePerformRecoveryFromSBD, OctagonSignpostNumber1(OctagonSignpostNamePerformRecoveryFromSBD), (int)subTaskSuccess);
+    }
+
+    OTEscrowRecord_SOSViability viableForSOS = escrowRecord.viabilityStatus;
+
+    OTClique* clique = [OTClique handleRecoveryResults:data recoveredInformation:recoveredInformation sosViability:viableForSOS performedSilentBurn:NO recoverError:recoverError error:error];
+
+    if(recoverError) {
+        subTaskSuccess = false;
+        OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
+    } else {
+        OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
+    }
+    return clique;
+
+#else
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return nil;
+#endif
+}
+
++ (OTEscrowRecord* _Nullable) recordMatchingLabel:(NSString*)label allRecords:(NSArray<OTEscrowRecord*>*)allRecords
+{
+    for(OTEscrowRecord* record in allRecords) {
+        if ([record.label isEqualToString:label]) {
+            return record;
+        }
+    }
+    return nil;
+}
+
++ (instancetype _Nullable)performSilentEscrowRecovery:(OTConfigurationContext*)data
+                                           cdpContext:(OTICDPRecordContext*)cdpContext
+                                           allRecords:(NSArray<OTEscrowRecord*>*)allRecords
+                                                error:(NSError**)error
+{
+#if OCTAGON
+    secnotice("octagontrust-performSilentEscrowRecovery", "performSilentEscrowRecovery invoked for context:%@, altdsid:%@", data.context, data.altDSID);
+
+    if ([self isCloudServicesAvailable] == NO) {
+        if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+        }
+        return nil;
+    }
+
+    OctagonSignpost performSilentEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNamePerformSilentEscrowRecovery);
+    bool subTaskSuccess = true;
+
+    id<OctagonEscrowRecovererPrococol> sb = data.sbd ?: [[getSecureBackupClass() alloc] init];
+    NSDictionary* recoveredInformation = nil;
+    NSError* recoverError = nil;
+
+    BOOL supportedRestorePath = [OTEscrowTranslation supportedRestorePath:cdpContext];
+    secnotice("octagontrust-performSilentEscrowRecovery", "restore path is supported? %@", supportedRestorePath ? @"YES" : @"NO");
+
+    if (OctagonIsOptimizationEnabled() && supportedRestorePath) {
+        secnotice("octagontrust-performSilentEscrowRecovery", "optimization flag turned on");
+        OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNameRecoverSilentWithCDPContext);
+        recoveredInformation = [sb recoverSilentWithCDPContext:cdpContext allRecords:allRecords error:&recoverError];
+        subTaskSuccess = (recoverError == nil) ? true : false;
+        OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNameRecoverSilentWithCDPContext, OctagonSignpostNumber1(OctagonSignpostNameRecoverSilentWithCDPContext), (int)subTaskSuccess);
+    } else {
+        secnotice("octagontrust-performSilentEscrowRecovery", "optimization flag turned off");
+        NSDictionary* sbdRecoveryArguments = [OTEscrowTranslation CDPRecordContextToDictionary:cdpContext];
+
+        OctagonSignpost recoverFromSBDSignPost = OctagonSignpostBegin(OctagonSignpostNamePerformRecoveryFromSBD);
+        recoverError = [sb recoverWithInfo:sbdRecoveryArguments results:&recoveredInformation];
+        subTaskSuccess = (recoverError == nil) ? true : false;
+        OctagonSignpostEnd(recoverFromSBDSignPost, OctagonSignpostNamePerformRecoveryFromSBD, OctagonSignpostNumber1(OctagonSignpostNamePerformRecoveryFromSBD), (int)subTaskSuccess);
+    }
+
+    NSString* label = recoveredInformation[getkSecureBackupRecordLabelKey()];
+    OTEscrowRecord* chosenRecord = [OTClique recordMatchingLabel:label allRecords:allRecords];
+    OTEscrowRecord_SOSViability viableForSOS = chosenRecord ? chosenRecord.viabilityStatus : OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN;
+
+    OTClique *clique = [OTClique handleRecoveryResults:data recoveredInformation:recoveredInformation sosViability:viableForSOS performedSilentBurn:YES recoverError:recoverError error:error];
+
+    if(recoverError) {
+        subTaskSuccess = false;
+        OctagonSignpostEnd(performSilentEscrowRecoverySignpost, OctagonSignpostNamePerformSilentEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformSilentEscrowRecovery), (int)subTaskSuccess);
+    } else {
+        OctagonSignpostEnd(performSilentEscrowRecoverySignpost, OctagonSignpostNamePerformSilentEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformSilentEscrowRecovery), (int)subTaskSuccess);
+    }
+
+    return clique;
+
+#else
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return nil;
+#endif
+}
+
++ (BOOL) invalidateEscrowCache:(OTConfigurationContext*)configurationContext error:(NSError**)error
+{
+#if OCTAGON
+    secnotice("octagontrust-invalidateEscrowCache", "invalidateEscrowCache invoked for context:%@, altdsid:%@", configurationContext.context, configurationContext.altDSID);
+    __block NSError* localError = nil;
+    __block BOOL invalidatedCache = NO;
+
+    OTControl *control = [configurationContext makeOTControl:&localError];
+    if (!control) {
+        secnotice("clique-invalidateEscrowCache", "unable to create otcontrol: %@", localError);
+        if (error) {
+            *error = localError;
+        }
+        return invalidatedCache;
+    }
+
+    [control invalidateEscrowCache:OTCKContainerName
+                         contextID:configurationContext.context
+                             reply:^(NSError * _Nullable invalidateError) {
+        if(invalidateError) {
+            secnotice("clique-invalidateEscrowCache", "invalidateEscrowCache errored: %@", invalidateError);
+        } else {
+            secnotice("clique-invalidateEscrowCache", "invalidateEscrowCache succeeded");
+            invalidatedCache = YES;
+        }
+        localError = invalidateError;
+    }];
+
+    if(error && localError) {
+        *error = localError;
+    }
+
+    secnotice("clique-invalidateEscrowCache", "invalidateEscrowCache complete");
+
+    return invalidatedCache;
+#else
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return NO;
+#endif
+}
+
+@end
+
+#endif
diff --git a/keychain/OctagonTrust/categories/OctagonTrustEscrowRecoverer.h b/keychain/OctagonTrust/categories/OctagonTrustEscrowRecoverer.h
new file mode 100644 (file)
index 0000000..1bd2261
--- /dev/null
@@ -0,0 +1,27 @@
+
+#if OCTAGON
+
+#ifndef OctagonTrustEscrowRecoverer_h
+#define OctagonTrustEscrowRecoverer_h
+
+@protocol OctagonEscrowRecovererPrococol <NSObject>
+- (NSError*)recoverWithInfo:(NSDictionary*)info results:(NSDictionary**)results;
+- (NSError *)getAccountInfoWithInfo:(NSDictionary *)info results:(NSDictionary**)results;
+- (NSError *)disableWithInfo:(NSDictionary *)info;
+- (NSDictionary*)recoverWithCDPContext:(OTICDPRecordContext*)cdpContext
+                                    escrowRecord:(OTEscrowRecord*)escrowRecord
+                                           error:(NSError**)error;
+- (NSDictionary*)recoverSilentWithCDPContext:(OTICDPRecordContext*)cdpContext
+                                            allRecords:(NSArray<OTEscrowRecord*>*)allRecords
+                                                 error:(NSError**)error;
+- (void)restoreKeychainAsyncWithPassword:password
+                            keybagDigest:(NSData *)keybagDigest
+                         haveBottledPeer:(BOOL)haveBottledPeer
+                    viewsNotToBeRestored:(NSMutableSet <NSString*>*)viewsNotToBeRestored
+                                   error:(NSError **)error;
+
+@end
+
+#endif /* OctagonTrustEscrowRecoverer_h */
+
+#endif // OCTAGON
diff --git a/keychain/OctagonTrust/ot-tests/OctagonTrustTests+Errors.m b/keychain/OctagonTrust/ot-tests/OctagonTrustTests+Errors.m
new file mode 100644 (file)
index 0000000..baf2212
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#import <Foundation/Foundation.h>
+#import "OctagonTrustTests.h"
+
+#if OCTAGON
+
+NS_ASSUME_NONNULL_BEGIN
+
+
+@implementation OctagonTrustTests (OctagonTrustTestsErrors)
+- (void) testDepthCountOnErrors
+{
+    SecErrorSetOverrideNestedErrorCappingIsEnabled(true);
+    //previousError == nil case
+    CFErrorRef errorWithoutPreviousSet = NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, &errorWithoutPreviousSet, NULL, CFSTR("no previous error"));
+    XCTAssertNotNil((__bridge NSError*) errorWithoutPreviousSet, "errorWithoutPreviousSet should not be nil");
+    NSDictionary *userInfo = [(__bridge NSError*)errorWithoutPreviousSet userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    NSNumber *depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 0, "depth should be 0");
+
+    //previousError is set with a depth of 0
+    CFErrorRef newError = NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, errorWithoutPreviousSet, &newError, NULL, CFSTR("previousError exists!"));
+    XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+    userInfo = [(__bridge NSError*)newError userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 1, "depth should be 1");
+
+    //previousError is set with a dpeth of 1
+    CFErrorRef secondError = NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, newError, &secondError, NULL, CFSTR("using previous error that already has a chain"));
+    XCTAssertNotNil((__bridge NSError*) secondError, "secondError should not be nil");
+    userInfo = [(__bridge NSError*)secondError userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 2, "depth should be 2");
+}
+- (void) testErrorCap
+{
+    SecErrorSetOverrideNestedErrorCappingIsEnabled(true);
+    //previousError == nil case
+    CFErrorRef previous= NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, &previous, NULL, CFSTR("no previous error"));
+    XCTAssertNotNil((__bridge NSError*) previous, "errorWithoutPreviousSet should not be nil");
+    NSDictionary *userInfo = [(__bridge NSError*)previous userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    NSNumber *depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 0, "depth should be 0");
+
+    //stay within the cap limit
+    CFErrorRef newError = NULL;
+    for(int i = 0; i<200; i++) {
+        SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("previousError exists %d!"), i);
+        XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+        userInfo = [(__bridge NSError*)newError userInfo];
+        XCTAssertNotNil(userInfo, "userInfo should not be nil");
+        depth = userInfo[@"numberOfErrorsDeep"];
+        XCTAssertNotNil(depth, "depth should not be nil");
+        XCTAssertEqual([depth longValue], i+1, "depth should be i+1");
+        previous = newError;
+        newError = nil;
+    }
+
+    //now blow the cap limit
+    previous = NULL;
+    newError = NULL;
+    int depthCounter = 0;
+
+    for(int i = 0; i < 500; i++) {
+        SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("previousError exists %d!"), i);
+        XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+        userInfo = [(__bridge NSError*)newError userInfo];
+        XCTAssertNotNil(userInfo, "userInfo should not be nil");
+        depth = userInfo[@"numberOfErrorsDeep"];
+        if (i >= 201) {
+            NSDictionary* previousUserInfo = [(__bridge NSError*)previous userInfo];
+            NSDictionary* newErrorUserInfo = [(__bridge NSError*)newError userInfo];
+            XCTAssertTrue([previousUserInfo isEqualToDictionary:newErrorUserInfo], "newError should equal previous error");
+        }
+
+        if (i <= 199) {
+            XCTAssertNotNil(depth, "depth should not be nil");
+            XCTAssertEqual([depth longValue], depthCounter, "depth should be %d", depthCounter);
+            depthCounter++;
+        } else {
+            userInfo = [(__bridge NSError*)newError userInfo];
+            depth = userInfo[@"numberOfErrorsDeep"];
+            XCTAssertNotNil(depth, "depth should not be nil");
+            XCTAssertEqual([depth longValue], 200, "depth should be 200");
+        }
+        
+        previous = newError;
+        newError = nil;
+    }
+}
+
+- (void) testErrorCapWithFeatureFlagDisable
+{
+    SecErrorSetOverrideNestedErrorCappingIsEnabled(false);
+    //previousError == nil case
+    CFErrorRef previous= NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, &previous, NULL, CFSTR("no previous error"));
+    XCTAssertNotNil((__bridge NSError*) previous, "errorWithoutPreviousSet should not be nil");
+    NSDictionary *userInfo = [(__bridge NSError*)previous userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    NSNumber *depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 0, "depth should be 0");
+
+    //stay within the cap limit
+    CFErrorRef newError = NULL;
+    for(int i = 0; i<200; i++) {
+        SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("previousError exists %d!"), i);
+        XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+        userInfo = [(__bridge NSError*)newError userInfo];
+        XCTAssertNotNil(userInfo, "userInfo should not be nil");
+        depth = userInfo[@"numberOfErrorsDeep"];
+        XCTAssertNotNil(depth, "depth should not be nil");
+        XCTAssertEqual([depth longValue], i+1, "depth should be i+1");
+        previous = newError;
+        newError = nil;
+    }
+
+    //now blow the cap limit
+    previous = NULL;
+    newError = NULL;
+
+    for(int i = 0; i < 500; i++) {
+        SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("previousError exists %d!"), i);
+        XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+        userInfo = [(__bridge NSError*)newError userInfo];
+        XCTAssertNotNil(userInfo, "userInfo should not be nil");
+        depth = userInfo[@"numberOfErrorsDeep"];
+        XCTAssertNotNil(depth, "depth should not be nil");
+        XCTAssertEqual([depth longValue], i, "depth should be %d", i);
+        previous = newError;
+        newError = nil;
+    }
+}
+
+- (void) testNestedErrorCreationUsingSameErrorParameters
+{
+    SecErrorSetOverrideNestedErrorCappingIsEnabled(true);
+    //previousError == nil case
+    CFErrorRef previous= NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, &previous, NULL, CFSTR("no previous error"));
+    XCTAssertNotNil((__bridge NSError*) previous, "previous should not be nil");
+    NSDictionary *userInfo = [(__bridge NSError*)previous userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    NSNumber *depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 0, "depth should be 0");
+
+    //now pass the exact same error
+    CFErrorRef newError = NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("no previous error"));
+    XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+    userInfo = [(__bridge NSError*)newError userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 0, "depth should be 0");
+
+    previous = newError;
+    newError = NULL;
+    SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("no previous error1"));
+    XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+    userInfo = [(__bridge NSError*)newError userInfo];
+    XCTAssertNotNil(userInfo, "userInfo should not be nil");
+    depth = userInfo[@"numberOfErrorsDeep"];
+    XCTAssertNotNil(depth, "depth should not be nil");
+    XCTAssertEqual([depth longValue], 1, "depth should be 1");
+
+    previous = newError;
+    newError = NULL;
+    for(int i = 0; i < 500; i++) {
+        SOSCreateErrorWithFormat(kSOSErrorNoCircle, previous, &newError, NULL, CFSTR("no previous error1"));
+        XCTAssertNotNil((__bridge NSError*) newError, "newError should not be nil");
+        userInfo = [(__bridge NSError*)newError userInfo];
+        XCTAssertNotNil(userInfo, "userInfo should not be nil");
+        depth = userInfo[@"numberOfErrorsDeep"];
+        XCTAssertNotNil(depth, "depth should not be nil");
+        XCTAssertEqual([depth longValue], 1, "depth should be 1");
+        previous = newError;
+        newError = nil;
+    }
+}
+
+@end
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowRecords.m b/keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowRecords.m
new file mode 100644 (file)
index 0000000..0f7fb0b
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+* Copyright (c) 2020 Apple Inc. All Rights Reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+
+#import <Foundation/Foundation.h>
+#import <XCTest/XCTest.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
+#import <OCMock/OCMock.h>
+#pragma clang diagnostic pop
+
+#import <OctagonTrust/OctagonTrust.h>
+#import "OctagonTrustTests-EscrowTestVectors.h"
+
+#import "keychain/ot/OTConstants.h"
+#import "keychain/ot/OTManager.h"
+#import "keychain/ot/OTDefines.h"
+#import "keychain/ot/OTClique+Private.h"
+
+#import "keychain/OctagonTrust/categories/OctagonTrustEscrowRecoverer.h"
+
+#import <Foundation/NSPropertyList.h>
+
+#import "keychain/ckks/tests/MockCloudKit.h"
+#import "keychain/ckks/tests/CKKSMockSOSPresentAdapter.h"
+#import "utilities/SecCFError.h"
+#import "keychain/categories/NSError+UsefulConstructors.h"
+
+#import "OctagonTrustTests.h"
+
+@implementation ProxyXPCConnection
+
+- (instancetype)initWithInterface:(NSXPCInterface*)interface obj:(id)obj
+{
+    if(self = [super init]) {
+        self.obj = obj;
+        self.serverInterface = interface;
+        self.listener = [NSXPCListener anonymousListener];
+
+        self.listener.delegate = self;
+        [self.listener resume];
+    }
+
+    return self;
+}
+
+- (NSXPCConnection*)connection
+{
+    NSXPCConnection* connection = [[NSXPCConnection alloc] initWithListenerEndpoint:self.listener.endpoint];
+    connection.remoteObjectInterface = self.serverInterface;
+    [connection resume];
+    return connection;
+}
+
+- (BOOL)listener:(NSXPCListener*)listener newConnection:(NSXPCConnection*)newConnection {
+    newConnection.exportedInterface = self.serverInterface;
+    newConnection.exportedObject = self.obj;
+    [newConnection resume];
+    return true;
+  }
+
+@end
+
+@interface FakeOTControlEntitlementBearer : NSObject <OctagonEntitlementBearerProtocol>
+@property NSMutableDictionary* entitlements;
+-(instancetype)init;
+- (nullable id)valueForEntitlement:(NSString *)entitlement;
+@end
+
+@implementation FakeOTControlEntitlementBearer
+
+-(instancetype)init
+{
+    if(self = [super init]) {
+        self.entitlements = [NSMutableDictionary dictionary];
+        self.entitlements[kSecEntitlementPrivateOctagonEscrow] = @YES;
+    }
+    return self;
+}
+-(id)valueForEntitlement:(NSString*)entitlement
+{
+    return self.entitlements[entitlement];
+}
+
+@end
+
+@interface OTMockSecureBackup : NSObject <OctagonEscrowRecovererPrococol>
+@property (nonatomic) NSString * bottleID;
+@property (nonatomic) NSData* entropy;
+
+@end
+
+@implementation OTMockSecureBackup
+
+-(instancetype) initWithBottleID:(NSString*)b entropy:(NSData*)e {
+    if(self = [super init]) {
+        self.bottleID = b;
+        self.entropy = e;
+    }
+    return self;
+}
+
+- (NSError *)disableWithInfo:(NSDictionary *)info {
+    return nil;
+}
+
+- (NSError *)getAccountInfoWithInfo:(NSDictionary *)info results:(NSDictionary *__autoreleasing *)results {
+    NSError* localError = nil;
+    NSData *testVectorData = [accountInfoWithInfoSample dataUsingEncoding:kCFStringEncodingUTF8];
+    NSPropertyListFormat format;
+    NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localError];
+    *results = testVectorPlist;
+
+    return nil;
+}
+
+- (NSDictionary *)recoverSilentWithCDPContext:(OTICDPRecordContext *)cdpContext allRecords:(NSArray<OTEscrowRecord *> *)allRecords error:(NSError *__autoreleasing *)error {
+    return nil;
+}
+
+- (NSDictionary *)recoverWithCDPContext:(OTICDPRecordContext *)cdpContext escrowRecord:(OTEscrowRecord *)escrowRecord error:(NSError *__autoreleasing *)error {
+    return nil;
+}
+
+- (NSError *)recoverWithInfo:(NSDictionary *)info results:(NSDictionary *__autoreleasing *)results {
+    return nil;
+}
+
+- (void)restoreKeychainAsyncWithPassword:(id)password keybagDigest:(NSData *)keybagDigest haveBottledPeer:(BOOL)haveBottledPeer viewsNotToBeRestored:(NSMutableSet<NSString *> *)viewsNotToBeRestored error:(NSError *__autoreleasing *)error {
+}
+
+
+@end
+
+@implementation OctagonTrustTests
+
+- (OTEscrowRecord*)createLegacyRecord
+{
+    OTEscrowRecord *nonViableRecord = [[OTEscrowRecord alloc] init];
+    nonViableRecord.creationDate = [NSDate date].timeIntervalSince1970;
+    nonViableRecord.label = [[NSUUID UUID] UUIDString];
+    nonViableRecord.recordStatus = OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    nonViableRecord.recordViability = OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY;
+    nonViableRecord.serialNumber = [[NSUUID UUID] UUIDString];
+    nonViableRecord.silentAttemptAllowed = 1;
+    nonViableRecord.escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+    nonViableRecord.escrowInformationMetadata.bottleValidity = @"invalid";
+
+    // It even has a bottleId! Not a useful one, though.
+    nonViableRecord.escrowInformationMetadata.bottleId = [[NSUUID UUID] UUIDString];
+    return nonViableRecord;
+}
+
+- (OTEscrowRecord*)createLegacyRecordWithSOSNotViable
+{
+    OTEscrowRecord *nonViableRecord = [[OTEscrowRecord alloc] init];
+    nonViableRecord.creationDate = [NSDate date].timeIntervalSince1970;
+    nonViableRecord.label = [[NSUUID UUID] UUIDString];
+    nonViableRecord.recordStatus = OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    nonViableRecord.recordViability = OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY;
+    nonViableRecord.viabilityStatus = OTEscrowRecord_SOSViability_SOS_NOT_VIABLE;
+    nonViableRecord.serialNumber = [[NSUUID UUID] UUIDString];
+    nonViableRecord.silentAttemptAllowed = 1;
+    nonViableRecord.escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+    nonViableRecord.escrowInformationMetadata.bottleValidity = @"invalid";
+
+    // It even has a bottleId! Not a useful one, though.
+    nonViableRecord.escrowInformationMetadata.bottleId = [[NSUUID UUID] UUIDString];
+    return nonViableRecord;
+}
+
+- (OTEscrowRecord*)createPartialRecord
+{
+    OTEscrowRecord *partiallyViableRecord = [[OTEscrowRecord alloc] init];
+    partiallyViableRecord.creationDate = [NSDate date].timeIntervalSince1970;
+    partiallyViableRecord.label = [[NSUUID UUID] UUIDString];
+    partiallyViableRecord.recordStatus = OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    partiallyViableRecord.recordViability = OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE;
+    partiallyViableRecord.escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+    partiallyViableRecord.escrowInformationMetadata.bottleValidity = @"valid";
+    partiallyViableRecord.escrowInformationMetadata.bottleId = [[NSUUID UUID] UUIDString];
+
+    partiallyViableRecord.serialNumber =[[NSUUID UUID] UUIDString];
+    partiallyViableRecord.silentAttemptAllowed = 1;
+    return partiallyViableRecord;
+}
+
+- (OTEscrowRecord*)createOctagonViableSOSViableRecord
+{
+    OTEscrowRecord *octagonAndSOSViableRecord = [[OTEscrowRecord alloc] init];
+    octagonAndSOSViableRecord.creationDate = [NSDate date].timeIntervalSince1970;
+    octagonAndSOSViableRecord.label = [[NSUUID UUID] UUIDString];
+    octagonAndSOSViableRecord.recordStatus = OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    octagonAndSOSViableRecord.recordViability = OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE;
+    octagonAndSOSViableRecord.viabilityStatus = OTEscrowRecord_SOSViability_SOS_VIABLE;
+
+    octagonAndSOSViableRecord.escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+    octagonAndSOSViableRecord.escrowInformationMetadata.bottleValidity = @"valid";
+    octagonAndSOSViableRecord.escrowInformationMetadata.bottleId = [[NSUUID UUID] UUIDString];
+
+    octagonAndSOSViableRecord.serialNumber =[[NSUUID UUID] UUIDString];
+    octagonAndSOSViableRecord.silentAttemptAllowed = 1;
+    return octagonAndSOSViableRecord;
+}
+
+- (OTEscrowRecord*)createOctagonNotViableSOSViableRecord
+{
+    OTEscrowRecord *octagonAndSOSViableRecord = [[OTEscrowRecord alloc] init];
+    octagonAndSOSViableRecord.creationDate = [NSDate date].timeIntervalSince1970;
+    octagonAndSOSViableRecord.label = [[NSUUID UUID] UUIDString];
+    octagonAndSOSViableRecord.recordStatus = OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    octagonAndSOSViableRecord.recordViability = OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY;
+    octagonAndSOSViableRecord.viabilityStatus = OTEscrowRecord_SOSViability_SOS_VIABLE;
+
+    octagonAndSOSViableRecord.escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+    octagonAndSOSViableRecord.escrowInformationMetadata.bottleValidity = @"invalid";
+    octagonAndSOSViableRecord.escrowInformationMetadata.bottleId = [[NSUUID UUID] UUIDString];
+
+    octagonAndSOSViableRecord.serialNumber =[[NSUUID UUID] UUIDString];
+    octagonAndSOSViableRecord.silentAttemptAllowed = 1;
+    return octagonAndSOSViableRecord;
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnOneRecord:(OTConfigurationContext*)data
+                                                                       error:(NSError* __autoreleasing *)error
+{
+    NSError* localError = nil;
+    NSData *testVectorData = [accountInfoWithInfoSample dataUsingEncoding:kCFStringEncodingUTF8];
+    NSPropertyListFormat format;
+    NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localError];
+
+    NSArray *testVectorICDPRecords = testVectorPlist[@"SecureBackupAlliCDPRecords"];
+    XCTAssertNotNil(testVectorICDPRecords, "should not be nil");
+
+    NSDictionary *testVectorRecord = testVectorICDPRecords[0];
+
+    OTEscrowRecord *record = [OTEscrowTranslation dictionaryToEscrowRecord:testVectorRecord];
+
+    NSArray *records = @[record.data];
+    return records;
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnMixedRecords:(OTConfigurationContext*)data
+                                                                          error:(NSError* __autoreleasing *)error
+{
+    NSError* localError = nil;
+    NSData *testVectorData = [accountInfoWithInfoSample dataUsingEncoding:kCFStringEncodingUTF8];
+    NSPropertyListFormat format;
+    NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localError];
+
+    NSArray *testVectorICDPRecords = testVectorPlist[@"SecureBackupAlliCDPRecords"];
+    XCTAssertNotNil(testVectorICDPRecords, "should not be nil");
+
+    NSDictionary *testVectorRecord = testVectorICDPRecords[0];
+
+    OTEscrowRecord *record = [OTEscrowTranslation dictionaryToEscrowRecord:testVectorRecord];
+
+    NSArray *records = @[record.data, [self createLegacyRecord].data, [self createLegacyRecord].data];
+    return records;
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnPartiallyViableRecords:(OTConfigurationContext*)data
+                                                                                    error:(NSError* __autoreleasing *)error
+{
+    return @[[self createPartialRecord].data, [self createPartialRecord].data];
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnOctagonViableSOSViableRecords:(OTConfigurationContext*)data
+                                                                                           error:(NSError* __autoreleasing *)error
+{
+    return @[[self createOctagonViableSOSViableRecord].data, [self createOctagonViableSOSViableRecord].data];
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnLegacyRecords:(OTConfigurationContext*)data
+                                                                           error:(NSError* __autoreleasing *)error
+{
+    return @[[self createLegacyRecord].data, [self createLegacyRecord].data];
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnLegacyNonViableSOSRecords:(OTConfigurationContext*)data
+                                                                                       error:(NSError* __autoreleasing *)error
+{
+    return @[[self createLegacyRecordWithSOSNotViable].data, [self createLegacyRecordWithSOSNotViable].data];
+}
+
+- (NSArray<NSData*>* _Nullable)mockFetchEscrowRecordsInternalReturnOctagonNotViableSOSViableRecords:(OTConfigurationContext*)data
+                                                                                              error:(NSError* __autoreleasing *)error
+{
+    return @[[self createOctagonNotViableSOSViableRecord].data, [self createOctagonNotViableSOSViableRecord].data];
+}
+
+- (void)setUp
+{
+    [super setUp];
+
+    FakeOTControlEntitlementBearer *otControlEntitlementBearer = [[FakeOTControlEntitlementBearer alloc]init];
+    id otControlEntitlementChecker = [OctagonXPCEntitlementChecker createWithManager:self.injectedOTManager entitlementBearer:otControlEntitlementBearer];
+
+    NSXPCInterface *interface = OTSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(OTControlProtocol)]);
+    self.otXPCProxy = [[ProxyXPCConnection alloc] initWithInterface:interface obj: otControlEntitlementChecker];
+
+    self.otControl = [[OTControl alloc] initWithConnection:self.otXPCProxy.connection sync: true];
+
+    self.mockClique = OCMClassMock([OTClique class]);
+}
+
+- (void)testFetchOneViableEscrowRecord
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnOneRecord:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 1, "should only return 1 record");
+    OTEscrowRecord *firstRecord = escrowRecords[0];
+    XCTAssertTrue([firstRecord.label isEqualToString:@"com.apple.icdp.record"], "label should be com.apple.icdp.record");
+    XCTAssertTrue([firstRecord.serialNumber isEqualToString:@"C39V209AJ9L5"], "serial number should be C39V209AJ9L5");
+    XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE, "record viability should be fully viable");
+}
+
+- (void)testFetchTwoPartiallyViableEscrowRecords
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnPartiallyViableRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 2, "should only return 2 records");
+    OTEscrowRecord *firstRecord = escrowRecords[0];
+    XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE, "record viability should be partial");
+
+    OTEscrowRecord *secondRecord = escrowRecords[1];
+    XCTAssertTrue([secondRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(secondRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE, "record viability should be partial");
+}
+
+- (void)testFetchViableAndLegacyEscrowRecords
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnMixedRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertEqual(escrowRecords.count, 1, "should only return 1 record");
+    XCTAssertNil(localErrror, "error should be nil");
+
+    OTEscrowRecord *firstRecord = escrowRecords[0];
+    XCTAssertTrue([firstRecord.label isEqualToString:@"com.apple.icdp.record"], "label should be com.apple.icdp.record");
+    XCTAssertTrue([firstRecord.serialNumber isEqualToString:@"C39V209AJ9L5"], "serial number should be C39V209AJ9L5");
+    XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE, "record viability should be fully viable");
+}
+
+- (void)testFetchLegacyEscrowRecords
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnLegacyRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertEqual(escrowRecords.count, 0, "should return zero records");
+    XCTAssertNil(localErrror, "error should be nil");
+}
+
+- (void)testFetchRecordsOctagonViableSOSUnknownViability
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnOneRecord:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 1, "should only return 1 record");
+    OTEscrowRecord *firstRecord = escrowRecords[0];
+    XCTAssertTrue([firstRecord.label isEqualToString:@"com.apple.icdp.record"], "label should be com.apple.icdp.record");
+    XCTAssertTrue([firstRecord.serialNumber isEqualToString:@"C39V209AJ9L5"], "serial number should be C39V209AJ9L5");
+    XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE, "record viability should be fully viable");
+    XCTAssertEqual(firstRecord.viabilityStatus, OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN, "record SOS viability should be unknown");
+}
+
+- (void)testFetchRecordsOctagonViableSOSViable
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnOctagonViableSOSViableRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 2, "should only return 2 records");
+    OTEscrowRecord *firstRecord = escrowRecords[0];
+    XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE, "record viability should be fully viable");
+    XCTAssertEqual(firstRecord.viabilityStatus, OTEscrowRecord_SOSViability_SOS_VIABLE, "record sos viability should be fully viable");
+
+    OTEscrowRecord *secondRecord = escrowRecords[1];
+    XCTAssertTrue([secondRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"valid"], "bottle validity should be valid");
+    XCTAssertEqual(secondRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE, "record viability should be fully viable");
+    XCTAssertEqual(secondRecord.viabilityStatus, OTEscrowRecord_SOSViability_SOS_VIABLE, "record sos viability should be fully viable");
+}
+
+- (void)testFetchRecordsOctagonNotViableSOSViable
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnOctagonNotViableSOSViableRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    if (OctagonPlatformSupportsSOS()) {
+        XCTAssertEqual(escrowRecords.count, 2, "should only return 2 records");
+        OTEscrowRecord *firstRecord = escrowRecords[0];
+        XCTAssertTrue([firstRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"invalid"], "bottle validity should be invalid");
+        XCTAssertEqual(firstRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY, "record viability should be set to legacy");
+        XCTAssertEqual(firstRecord.viabilityStatus, OTEscrowRecord_SOSViability_SOS_VIABLE, "record sos viability should be fully viable");
+
+        OTEscrowRecord *secondRecord = escrowRecords[1];
+        XCTAssertTrue([secondRecord.escrowInformationMetadata.bottleValidity isEqualToString: @"invalid"], "bottle validity should be invalid");
+        XCTAssertEqual(secondRecord.recordViability, OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY, "record viability should be set to legacy");
+        XCTAssertEqual(secondRecord.viabilityStatus, OTEscrowRecord_SOSViability_SOS_VIABLE, "record sos viability should be fully viable");
+    } else {
+        XCTAssertEqual(escrowRecords.count, 0, "should return 0 records");
+
+    }
+}
+
+- (void)testFetchRecordsOctagonNotViableSOSNotViable
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnLegacyNonViableSOSRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 0, "should return 0 records");
+}
+
+- (void)testFetchAllRecords
+{
+    OctagonSetOptimizationEnabled(true);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    OCMStub([self.mockClique fetchEscrowRecordsInternal:[OCMArg any] error:[OCMArg anyObjectRef]]).andCall(self, @selector(mockFetchEscrowRecordsInternalReturnLegacyNonViableSOSRecords:error:));
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchAllEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+
+    XCTAssertEqual(escrowRecords.count, 2, "should return 2 records");
+}
+
+- (void)testFetchEscrowRecordOptimizationOff
+{
+    OctagonSetOptimizationEnabled(false);
+
+    OTConfigurationContext *cliqueContextConfiguration = [[OTConfigurationContext alloc]init];
+    cliqueContextConfiguration.context = OTDefaultContext;
+    cliqueContextConfiguration.dsid = @"1234";
+    cliqueContextConfiguration.altDSID = @"altdsid";
+    cliqueContextConfiguration.sbd = [[OTMockSecureBackup alloc]initWithBottleID:@"" entropy:[NSData data]];
+    cliqueContextConfiguration.otControl = self.otControl;
+
+    NSError* localErrror = nil;
+    NSArray* escrowRecords = [OTClique fetchEscrowRecords:cliqueContextConfiguration error:&localErrror];
+    XCTAssertNil(localErrror, "error should be nil");
+    XCTAssertNotNil(escrowRecords, "escrow records should not be nil");
+
+    for (OTEscrowRecord* record in escrowRecords) {
+        XCTAssertEqual(record.creationDate, 1580440060, "escrow record creation date should be 1580440060");
+        XCTAssertNotNil(record.escrowInformationMetadata.backupKeybagDigest, "escrow record backup key bag digest should not be nil");
+        XCTAssertTrue([record.label isEqualToString:@"com.apple.icdp.record"], "escrow record label should be com.apple.icdp.record");
+        XCTAssertEqual(record.recordStatus, OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID, "escrow record record status should be valid");
+        XCTAssertEqual(record.remainingAttempts, 10, "escrow record remaining attempts should be 10");
+        XCTAssertEqual(record.silentAttemptAllowed, 1, "escrow record silent attempted allowed should be true");
+        XCTAssertTrue([record.serialNumber isEqualToString:@"C39V209AJ9L5"], "escrow record serial number should be equal");
+        XCTAssertTrue([record.recordId isEqualToString:@"sNs6voV0N35D/T91SuGmJnGO29"], "escrow record record id should be true");
+        XCTAssertEqual(record.silentAttemptAllowed, 1, "escrow record silent attempted allowed should be true");
+
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceColor isEqualToString: @"1"], "escrow record device color should be 1");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceEnclosureColor isEqualToString:@"1"], "escrow record ");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceMid isEqualToString:@"yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X"], "escrow record MID should be yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceModel isEqualToString:@"iPhone 8 Plus"], "escrow record device model should be iPhone 8 Plus");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceModelClass isEqualToString: @"iPhone"], "escrow record model calss should be iPhone");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceModelVersion isEqualToString:@"iPhone10,5"], "escrow record model version should be iPhone10,5");
+        XCTAssertTrue([record.escrowInformationMetadata.clientMetadata.deviceName isEqualToString:@"iPhone"], "escrow record device name should be iPhone ");
+        XCTAssertEqual(record.escrowInformationMetadata.clientMetadata.secureBackupMetadataTimestamp, 1580440060, "escrow record timestamp should be 1580440060");
+        XCTAssertEqual(record.escrowInformationMetadata.clientMetadata.secureBackupNumericPassphraseLength, 6, "escrow record passphrase length should be 6");
+        XCTAssertEqual(record.escrowInformationMetadata.clientMetadata.secureBackupUsesComplexPassphrase, 1, "escrow record uses complex passphrase should be 1");
+        XCTAssertEqual(record.escrowInformationMetadata.clientMetadata.secureBackupUsesNumericPassphrase, 1, "escrow record uses numeric passphrase should be 1");
+        XCTAssertNotNil(record.escrowInformationMetadata.escrowedSpki, "escrow record escrowed spki should not be nil");
+        XCTAssertNotNil(record.escrowInformationMetadata.peerInfo, "escrow record peer info should be not nil");
+        XCTAssertEqual(record.escrowInformationMetadata.secureBackupTimestamp, 1580440060, "escrow record timestamp should be 1580440060");
+        XCTAssertEqual(record.escrowInformationMetadata.secureBackupUsesMultipleIcscs, 1, "escrow record uses multiple icscs should be 1");
+
+        NSData *testVectorData = [accountInfoWithInfoSample dataUsingEncoding:kCFStringEncodingUTF8];
+        NSPropertyListFormat format;
+        NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localErrror];
+
+        //now translate back to dictionary!
+        NSDictionary *translatedBackToDictionary = [OTEscrowTranslation escrowRecordToDictionary:record];
+        XCTAssertNotNil(translatedBackToDictionary, "should not be nil");
+
+        NSArray *testVectorICDPRecords = testVectorPlist[@"SecureBackupAlliCDPRecords"];
+        XCTAssertNotNil(testVectorICDPRecords, "should not be nil");
+
+        NSDictionary *testVectorRecord = testVectorICDPRecords[0];
+        XCTAssertNotNil(testVectorRecord, "should not be nil");
+        XCTAssertTrue([testVectorRecord[@"SecureBackupEscrowDate"] isEqualToDate: translatedBackToDictionary[@"SecureBackupEscrowDate"]], "should be equal");
+        XCTAssertTrue([testVectorRecord[@"recordStatus"] isEqualToString:translatedBackToDictionary[@"recordStatus"]], "should be equal");
+        XCTAssertTrue([testVectorRecord[@"silentAttemptAllowed"] isEqualToNumber:translatedBackToDictionary[@"silentAttemptAllowed"]], "should be equal");
+
+        XCTAssertTrue([testVectorRecord[@"peerInfoSerialNumber"] isEqualToString:translatedBackToDictionary[@"peerInfoSerialNumber"]], "should be equal");
+        XCTAssertTrue([testVectorRecord[@"recordID"] isEqualToString:translatedBackToDictionary[@"recordID"]], "should be equal");
+
+        NSDictionary *testVectorMetadata = testVectorRecord[@"metadata"];
+        XCTAssertNotNil(testVectorMetadata, "should not be nil");
+
+        NSDictionary *translatedMetadata = translatedBackToDictionary[@"metadata"];
+        XCTAssertNotNil(translatedMetadata, "should not be nil");
+
+        XCTAssertTrue([testVectorMetadata[@"com.apple.securebackup.timestamp"] isEqualToString: translatedMetadata[@"com.apple.securebackup.timestamp"]], "should be equal");
+        XCTAssertTrue([testVectorMetadata[@"bottleID"] isEqualToString:translatedMetadata[@"bottleID"]], "should be equal");
+        XCTAssertTrue([testVectorMetadata[@"escrowedSPKI"] isEqualToData:translatedMetadata[@"escrowedSPKI"]], "should be equal");
+        XCTAssertTrue([testVectorMetadata[@"SecureBackupUsesMultipleiCSCs"] isEqualToNumber: translatedMetadata[@"SecureBackupUsesMultipleiCSCs"]], "should be equal");
+        XCTAssertTrue([testVectorMetadata[@"peerInfo"] isEqualToData:translatedMetadata[@"peerInfo"]], "should be equal");
+        XCTAssertTrue([testVectorMetadata[@"BackupKeybagDigest"] isEqualToData: translatedMetadata[@"BackupKeybagDigest"]], "should be equal");
+
+        NSDictionary *testVectorClientMetadata = testVectorMetadata[@"ClientMetadata"];
+        XCTAssertNotNil(testVectorClientMetadata, "should not be nil");
+        NSDictionary *translatedClientMetadata = translatedMetadata[@"ClientMetadata"];
+        XCTAssertNotNil(translatedClientMetadata, "should not be nil");
+        XCTAssertTrue([testVectorClientMetadata isEqualToDictionary:translatedClientMetadata], "should be equal");
+    }
+
+}
+
+- (void)testCDPRecordContextTranslation
+{
+    NSError* localError = nil;
+    NSData *testVectorData = [testCDPRemoteRecordContextTestVector dataUsingEncoding:kCFStringEncodingUTF8];
+    NSPropertyListFormat format;
+    NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localError];
+    XCTAssertNotNil(testVectorPlist, "testVectorPlist should not be nil");
+    OTICDPRecordContext *cdpContext = [OTEscrowTranslation dictionaryToCDPRecordContext:testVectorPlist];
+    XCTAssertNotNil(cdpContext, "cdpContext should not be nil");
+    XCTAssertTrue([cdpContext.authInfo.authenticationAppleid isEqualToString:@"anna.535.paid@icloud.com"], "authenticationAppleid should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationAuthToken isEqualToString:@"EAAbAAAABLwIAAAAAF5PGvkRDmdzLmljbG91ZC5hdXRovQBx359KJvlZTwe1q6BwXvK4gQUYo2WQbKT8UDtn8rcA6FvEYBANaAk1ofWx/bcfB4pcLiXR3Y0kncELCwFCEEpqpZS+klD9AY1oT9zW6VtyOgQTZJ4mfWz103+FoMh8nLJAVpYVfM/UjsiNsLfTX+rUmevfeA=="], "authenticationAuthToken should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationDsid isEqualToString:@"16187698960"], "authenticationDsid should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationEscrowproxyUrl isEqualToString:@"https://p97-escrowproxy.icloud.com:443"], "authenticationEscrowproxyUrl should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationIcloudEnvironment isEqualToString:@"PROD"], "authenticationIcloudEnvironment should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationPassword isEqualToString: @"PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET"], "authenticationPassword should match");
+    XCTAssertFalse(cdpContext.authInfo.fmipRecovery, "fmipRecovery should be false");
+    XCTAssertFalse(cdpContext.authInfo.idmsRecovery, "idmsRecovery should be false");
+
+
+    XCTAssertTrue(cdpContext.cdpInfo.containsIcdpData, "containsIcdpData should be true");
+    XCTAssertFalse(cdpContext.cdpInfo.silentRecoveryAttempt, "silentRecoveryAttempt should be false");
+    XCTAssertTrue(cdpContext.cdpInfo.usesMultipleIcsc, "usesMultipleIcsc should match");
+    XCTAssertFalse(cdpContext.cdpInfo.useCachedSecret, "useCachedSecret should be false");
+    XCTAssertFalse(cdpContext.cdpInfo.usePreviouslyCachedRecoveryKey, "usePreviouslyCachedRecoveryKey should be false");
+    XCTAssertNil(cdpContext.cdpInfo.recoveryKey, "recoveryKey should be nil");
+    XCTAssertTrue([cdpContext.cdpInfo.recoverySecret isEqualToString:@"333333"], "recoverySecret should be 333333");
+
+    NSDictionary *translateBack = [OTEscrowTranslation CDPRecordContextToDictionary:cdpContext];
+    XCTAssertNotNil(translateBack, "translateBack should not be nil");
+
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationAppleID"]) isEqualToString:@"anna.535.paid@icloud.com"], "SecureBackupAuthenticationAppleID should be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationAuthToken"]) isEqualToString:@"EAAbAAAABLwIAAAAAF5PGvkRDmdzLmljbG91ZC5hdXRovQBx359KJvlZTwe1q6BwXvK4gQUYo2WQbKT8UDtn8rcA6FvEYBANaAk1ofWx/bcfB4pcLiXR3Y0kncELCwFCEEpqpZS+klD9AY1oT9zW6VtyOgQTZJ4mfWz103+FoMh8nLJAVpYVfM/UjsiNsLfTX+rUmevfeA=="], "SecureBackupAuthenticationAuthToken should be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationDSID"]) isEqualToString:@"16187698960"], "SecureBackupAuthenticationDSIDshould be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationEscrowProxyURL"]) isEqualToString:@"https://p97-escrowproxy.icloud.com:443"], "SecureBackupAuthenticationEscrowProxyURL be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationPassword"]) isEqualToString:@"PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET"], "SecureBackupAuthenticationPassword be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationiCloudEnvironment"]) isEqualToString:@"PROD"], "SecureBackupAuthenticationiCloudEnvironment be equal");
+    XCTAssertTrue(translateBack[@"SecureBackupContainsiCDPData"], "SecureBackupContainsiCDPData true");
+    XCTAssertTrue([translateBack[@"SecureBackupFMiPRecoveryKey"] isEqualToNumber:@NO], "SecureBackupFMiPRecoveryKey is false");
+    XCTAssertTrue([translateBack[@"SecureBackupIDMSRecovery"] isEqualToNumber:@NO], "SecureBackupIDMSRecovery false");
+    XCTAssertTrue([translateBack[@"SecureBackupPassphrase"] isEqualToString: @"333333"], "SecureBackupPassphrase true");
+    XCTAssertTrue([translateBack[@"SecureBackupSilentRecoveryAttempt"] isEqualToNumber:@NO], "SecureBackupSilentRecoveryAttempt false");
+    XCTAssertTrue([translateBack[@"SecureBackupUseCachedPassphrase"] isEqualToNumber:@NO], "SecureBackupUseCachedPassphrase false");
+    XCTAssertTrue([translateBack[@"SecureBackupUsesMultipleiCSCs"] isEqualToNumber:@YES], "SecureBackupUsesMultipleiCSCs true");
+    XCTAssertTrue([translateBack[@"SecureBackupUsesRecoveryKey"] isEqualToNumber:@NO], "SecureBackupUsesRecoveryKey false");
+}
+
+- (void)testCDPSilentRecordContextTranslation
+{
+    NSError* localError = nil;
+    NSData *testVectorData = [CDPRecordContextSilentTestVector dataUsingEncoding:kCFStringEncodingUTF8];
+    NSPropertyListFormat format;
+    NSDictionary *testVectorPlist = [NSPropertyListSerialization propertyListWithData:testVectorData options: NSPropertyListMutableContainersAndLeaves format:&format error:&localError];
+    XCTAssertNotNil(testVectorPlist, "testVectorPlist should not be nil");
+       OTICDPRecordContext *cdpContext = [OTEscrowTranslation dictionaryToCDPRecordContext:testVectorPlist];
+    XCTAssertNotNil(cdpContext, "cdpContext should not be nil");
+    XCTAssertTrue([cdpContext.authInfo.authenticationAppleid isEqualToString:@"anna.535.paid@icloud.com"], "authenticationAppleid should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationAuthToken isEqualToString:@"EAAbAAAABLwIAAAAAF5PHOERDmdzLmljbG91ZC5hdXRovQDwjwm2kXoklEtO/xeL3YCPlBr7IkVuV26y2BfLco+QhJFm4VhgFZSBFUg5l4g/uV2DG95xadgk0+rWLhyXDGZwHN2V9jju3eo6sRwGVj4g5iBFStuj4unTKylu3iFkNSKtTMXAyBXpn4EiRX+8dwumC2FKkA=="], "authenticationAuthToken should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationDsid isEqualToString:@"16187698960"], "authenticationDsid should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationEscrowproxyUrl isEqualToString:@"https://p97-escrowproxy.icloud.com:443"], "authenticationEscrowproxyUrl should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationIcloudEnvironment isEqualToString:@"PROD"], "authenticationIcloudEnvironment should match");
+    XCTAssertTrue([cdpContext.authInfo.authenticationPassword isEqualToString: @"PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET"], "authenticationPassword should match");
+    XCTAssertFalse(cdpContext.authInfo.fmipRecovery, "fmipRecovery should be false");
+    XCTAssertFalse(cdpContext.authInfo.idmsRecovery, "idmsRecovery should be false");
+
+
+    XCTAssertTrue(cdpContext.cdpInfo.containsIcdpData, "containsIcdpData should be true");
+    XCTAssertTrue(cdpContext.cdpInfo.silentRecoveryAttempt, "silentRecoveryAttempt should be true");
+    XCTAssertTrue(cdpContext.cdpInfo.usesMultipleIcsc, "usesMultipleIcsc should match");
+    XCTAssertFalse(cdpContext.cdpInfo.useCachedSecret, "useCachedSecret should be false");
+    XCTAssertFalse(cdpContext.cdpInfo.usePreviouslyCachedRecoveryKey, "usePreviouslyCachedRecoveryKey should be false");
+    XCTAssertNil(cdpContext.cdpInfo.recoveryKey, "recoveryKey should be nil");
+    XCTAssertTrue([cdpContext.cdpInfo.recoverySecret isEqualToString:@"333333"], "recoverySecret should be 333333");
+
+    NSDictionary *translateBack = [OTEscrowTranslation CDPRecordContextToDictionary:cdpContext];
+    XCTAssertNotNil(translateBack, "translateBack should not be nil");
+
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationAppleID"]) isEqualToString:@"anna.535.paid@icloud.com"], "SecureBackupAuthenticationAppleID should be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationAuthToken"]) isEqualToString:@"EAAbAAAABLwIAAAAAF5PHOERDmdzLmljbG91ZC5hdXRovQDwjwm2kXoklEtO/xeL3YCPlBr7IkVuV26y2BfLco+QhJFm4VhgFZSBFUg5l4g/uV2DG95xadgk0+rWLhyXDGZwHN2V9jju3eo6sRwGVj4g5iBFStuj4unTKylu3iFkNSKtTMXAyBXpn4EiRX+8dwumC2FKkA=="], "SecureBackupAuthenticationAuthToken should be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationDSID"]) isEqualToString:@"16187698960"], "SecureBackupAuthenticationDSIDshould be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationEscrowProxyURL"]) isEqualToString:@"https://p97-escrowproxy.icloud.com:443"], "SecureBackupAuthenticationEscrowProxyURL be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationPassword"]) isEqualToString:@"PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET"], "SecureBackupAuthenticationPassword be equal");
+    XCTAssertTrue([((NSString*)translateBack[@"SecureBackupAuthenticationiCloudEnvironment"]) isEqualToString:@"PROD"], "SecureBackupAuthenticationiCloudEnvironment be equal");
+    XCTAssertTrue(translateBack[@"SecureBackupContainsiCDPData"], "SecureBackupContainsiCDPData true");
+    XCTAssertTrue([translateBack[@"SecureBackupFMiPRecoveryKey"] isEqualToNumber:@NO], "SecureBackupFMiPRecoveryKey is false");
+    XCTAssertTrue([translateBack[@"SecureBackupIDMSRecovery"] isEqualToNumber:@NO], "SecureBackupIDMSRecovery false");
+    XCTAssertTrue([translateBack[@"SecureBackupPassphrase"] isEqualToString: @"333333"], "SecureBackupPassphrase true");
+    XCTAssertTrue([translateBack[@"SecureBackupSilentRecoveryAttempt"] isEqualToNumber:@YES], "SecureBackupSilentRecoveryAttempt true");
+    XCTAssertTrue([translateBack[@"SecureBackupUseCachedPassphrase"] isEqualToNumber:@NO], "SecureBackupUseCachedPassphrase false");
+    XCTAssertTrue([translateBack[@"SecureBackupUsesMultipleiCSCs"] isEqualToNumber:@YES], "SecureBackupUsesMultipleiCSCs true");
+    XCTAssertTrue([translateBack[@"SecureBackupUsesRecoveryKey"] isEqualToNumber:@NO], "SecureBackupUsesRecoveryKey false");
+}
+
+@end
+
diff --git a/keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowTestVectors.h b/keychain/OctagonTrust/ot-tests/OctagonTrustTests-EscrowTestVectors.h
new file mode 100644 (file)
index 0000000..aa9ddc7
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+* Copyright (c) 2020 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
+
+NSString *accountInfoWithInfoSample = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\
+<plist version=\"1.0\">\
+<dict>\
+    <key>SecureBackupAccountIsHighSecurity</key>\
+    <false/>\
+    <key>SecureBackupAlliCDPRecords</key>\
+    <array>\
+        <dict>\
+            <key>SecureBackupEscrowDate</key>\
+            <date>2020-01-31T03:07:40Z</date>\
+            <key>SecureBackupRemainingAttempts</key>\
+            <integer>10</integer>\
+            <key>encodedMetadata</key>\
+            <string>YnBsaXN0MDDZAQIDBAUGBwgJCgsMDQ4PECYgVnNlcmlhbF8QEkJhY2t1cEtleWJhZ0RpZ2VzdFVidWlsZFhwZWVySW5mb18QIGNvbS5hcHBsZS5zZWN1cmViYWNrdXAudGltZXN0YW1wWGJvdHRsZUlEXkNsaWVudE1ldGFkYXRhXGVzY3Jvd2VkU1BLSV8QHVNlY3VyZUJhY2t1cFVzZXNNdWx0aXBsZWlDU0NzXEMzOVYyMDlBSjlMNU8QFMhRrcsWNmcw7dI/9uhpDUpq4FZ2VjE4QTIxNE8RBLIwggSuMYIEYTAUDA9Db25mbGljdFZlcnNpb24CAQMwKwwPQXBwbGljYXRpb25EYXRlBBgYFjIwMjAwMTMwMjI0MTI2LjI4MDA1N1owVQwQUHVibGljU2lnbmluZ0tleQRBBOW+fXyAnCMa6by/cKGf1iHkcz9VEsa6rocBXgrLGVSb7Dy4XzT7fa1jf+X2co6ZTrXr3Vt56TBJZx8X6YNMY+swWAwPQXBwbGljYXRpb25Vc2lnBEUwQwIgY4hdZ7zcWd+Ue77JKF2OK99No8MUe9f5Fg2AzLviJKcCH04d5DOYNyFk6LTzWVuHD/2uMR7zASajNdfXbpFQ578wcAwNRGV2aWNlR2VzdGFsdDFfMBMMCU1vZGVsTmFtZQwGaVBob25lMBMMCU9TVmVyc2lvbgwGMThBMjE0MBYMDENvbXB1dGVyTmFtZQwGaVBob25lMBsMFk1lc3NhZ2VQcm90b2NvbFZlcnNpb24CAQAwfAwXT2N0YWdvblB1YmxpY1NpZ25pbmdLZXkEYQSguiFhjcalFK/bQBPruMsnWzZ0qv7VtPwmhjbdCQJ4mCMY1v6+60RCEsWMs+wQ200Tv40DvCBpzRABcsM70f8tuk1Q/wMXVDQ2kVfgmIVmobzvqNLwcSBHpU44nOEnNRkwfwwaT2N0YWdvblB1YmxpY0VuY3J5cHRpb25LZXkEYQQNGdKw9D+ZMSXl2YwRidBiFyb2GI/MGdDSCFDNvvRq5ig9sJHGMKgbswKltv7gkYzgvvg51slkltO0d5nQm0Juqj3dnIh9QtbPXfUew7LGjBNJIj3IOI8DJdnPqdGee+cwggH4DBBWMkRpY3Rpb25hcnlEYXRhBIIB4jGCAd4wEAwMRXNjcm93UmVjb3JkBQAwHAwMU2VyaWFsTnVtYmVyDAxDMzlWMjA5QUo5TDUwLQwJQmFja3VwS2V5BCBmWfEWzk0k71iVH/hINYf572sP/4l/uVZaMyhNb36frzBgDAxNYWNoaW5lSURLZXkMUHlXbkk4dmROZzZFV2F5ZVcvRlA0Y0RaUnNlM0xNbjhQeGcveC9zUHpaSklTNWNzM1JLbzQvc3RPVzQ2blE5OGlObHBTSHJuUjBrZnNiUjNYMIIBGQwFVmlld3PRggEODAdBcHBsZVRWDAdIb21lS2l0DAdQQ1MtRkRFDAlQQ1MtTm90ZXMMClBDUy1CYWNrdXAMClBDUy1Fc2Nyb3cMClBDUy1QaG90b3MMC0JhY2t1cEJhZ1YwDAtQQ1MtU2hhcmluZwwMTmFub1JlZ2lzdHJ5DAxQQ1MtQ2xvdWRLaXQMDFBDUy1GZWxkc3BhcgwMUENTLU1haWxkcm9wDAxQQ1MtaU1lc3NhZ2UMDVBDUy1NYXN0ZXJLZXkMDldhdGNoTWlncmF0aW9uDA5pQ2xvdWRJZGVudGl0eQwPUENTLWlDbG91ZERyaXZlDBBBY2Nlc3NvcnlQYWlyaW5nDBBDb250aW51aXR5VW5sb2NrBEcwRQIgRLmiTIo/hgxmoOMgZEygsTzdJiHOMTI68Y8DQGgXpWICIQCHr913nsr4kFaYZd3i/ioYQum8B5KOpxFR90u1CPgPEl8QEzIwMjAtMDEtMzEgMDM6MDc6NDBfECRERDVFM0Y5Ri0zNzAyLTQ3ODktOEFDRi0yRDI4QkM4NkE5NEPcERITFBUWFxgZGhscHQ4eHR8gISIjICMlXxAWZGV2aWNlX2VuY2xvc3VyZV9jb2xvcl8QHVNlY3VyZUJhY2t1cE1ldGFkYXRhVGltZXN0YW1wXxAPZGV2aWNlX3BsYXRmb3JtXGRldmljZV9jb2xvcl8QI1NlY3VyZUJhY2t1cE51bWVyaWNQYXNzcGhyYXNlTGVuZ3RoXxAhU2VjdXJlQmFja3VwVXNlc0NvbXBsZXhQYXNzcGhyYXNlWmRldmljZV9taWRfEBRkZXZpY2VfbW9kZWxfdmVyc2lvbltkZXZpY2VfbmFtZV8QIVNlY3VyZUJhY2t1cFVzZXNOdW1lcmljUGFzc3BocmFzZV8QEmRldmljZV9tb2RlbF9jbGFzc1xkZXZpY2VfbW9kZWxRMRQAAAAAAAAAAAAAAAAAAAABEAYJXxBQeVduSTh2ZE5nNkVXYXllVy9GUDRjRFpSc2UzTE1uOFB4Zy94L3NQelpKSVM1Y3MzUktvNC9zdE9XNDZuUTk4aU5scFNIcm5SMGtmc2JSM1haaVBob25lMTAsNVZpUGhvbmUJXWlQaG9uZSA4IFBsdXNPEHgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATIde8QFJDJYQJa6NrxP5WDLEhPNga9732ZGyoVoKi0RnxT6aIlb/LBrRvnrdZFyGUMlSYGSY3GIgrLz3YJ0A0W4BN6YKMtsgGCDONSD5/KHRzTEAE5e3Yp26nshhMavOcJAAgAGwAiADcAPQBGAGkAcgCBAI4ArgC7ANIA2QWPBaUFzAXlBf4GHgYwBj0GYwaHBpIGqQa1BtkG7gb7Bv0HDgcQBxEHZAdvB3YHdweFCAAAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAAIAQ==</string>\
+            <key>label</key>\
+            <string>com.apple.icdp.record</string>\
+            <key>metadata</key>\
+            <dict>\
+                <key>BackupKeybagDigest</key>\
+                <data>\
+                yFGtyxY2ZzDt0j/26GkNSmrgVnY=\
+                </data>\
+                <key>ClientMetadata</key>\
+                <dict>\
+                    <key>SecureBackupMetadataTimestamp</key>\
+                    <string>2020-01-31 03:07:40</string>\
+                    <key>SecureBackupNumericPassphraseLength</key>\
+                    <integer>6</integer>\
+                    <key>SecureBackupUsesComplexPassphrase</key>\
+                    <true/>\
+                    <key>SecureBackupUsesNumericPassphrase</key>\
+                    <true/>\
+                    <key>device_color</key>\
+                    <string>1</string>\
+                    <key>device_enclosure_color</key>\
+                    <string>1</string>\
+                    <key>device_mid</key>\
+                    <string>yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X</string>\
+                    <key>device_model</key>\
+                    <string>iPhone 8 Plus</string>\
+                    <key>device_model_class</key>\
+                    <string>iPhone</string>\
+                    <key>device_model_version</key>\
+                    <string>iPhone10,5</string>\
+                    <key>device_name</key>\
+                    <string>iPhone</string>\
+                    <key>device_platform</key>\
+                    <integer>1</integer>\
+                </dict>\
+                <key>SecureBackupUsesMultipleiCSCs</key>\
+                <true/>\
+                <key>bottleID</key>\
+                <string>DD5E3F9F-3702-4789-8ACF-2D28BC86A94C</string>\
+                <key>build</key>\
+                <string>18A214</string>\
+                <key>com.apple.securebackup.timestamp</key>\
+                <string>2020-01-31 03:07:40</string>\
+                <key>escrowedSPKI</key>\
+                <data>\
+                MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyHXvEBSQyWEC\
+                Wuja8T+VgyxITzYGve99mRsqFaCotEZ8U+miJW/ywa0b\
+                563WRchlDJUmBkmNxiIKy892CdANFuATemCjLbIBggzj\
+                Ug+fyh0c0xABOXt2Kdup7IYTGrzn\
+                </data>\
+                <key>peerInfo</key>\
+                <data>\
+                MIIErjGCBGEwFAwPQ29uZmxpY3RWZXJzaW9uAgEDMCsM\
+                D0FwcGxpY2F0aW9uRGF0ZQQYGBYyMDIwMDEzMDIyNDEy\
+                Ni4yODAwNTdaMFUMEFB1YmxpY1NpZ25pbmdLZXkEQQTl\
+                vn18gJwjGum8v3Chn9Yh5HM/VRLGuq6HAV4KyxlUm+w8\
+                uF80+32tY3/l9nKOmU61691beekwSWcfF+mDTGPrMFgM\
+                D0FwcGxpY2F0aW9uVXNpZwRFMEMCIGOIXWe83FnflHu+\
+                yShdjivfTaPDFHvX+RYNgMy74iSnAh9OHeQzmDchZOi0\
+                81lbhw/9rjEe8wEmozXX126RUOe/MHAMDURldmljZUdl\
+                c3RhbHQxXzATDAlNb2RlbE5hbWUMBmlQaG9uZTATDAlP\
+                U1ZlcnNpb24MBjE4QTIxNDAWDAxDb21wdXRlck5hbWUM\
+                BmlQaG9uZTAbDBZNZXNzYWdlUHJvdG9jb2xWZXJzaW9u\
+                AgEAMHwMF09jdGFnb25QdWJsaWNTaWduaW5nS2V5BGEE\
+                oLohYY3GpRSv20AT67jLJ1s2dKr+1bT8JoY23QkCeJgj\
+                GNb+vutEQhLFjLPsENtNE7+NA7wgac0QAXLDO9H/LbpN\
+                UP8DF1Q0NpFX4JiFZqG876jS8HEgR6VOOJzhJzUZMH8M\
+                Gk9jdGFnb25QdWJsaWNFbmNyeXB0aW9uS2V5BGEEDRnS\
+                sPQ/mTEl5dmMEYnQYhcm9hiPzBnQ0ghQzb70auYoPbCR\
+                xjCoG7MCpbb+4JGM4L74OdbJZJbTtHeZ0JtCbqo93ZyI\
+                fULWz131HsOyxowTSSI9yDiPAyXZz6nRnnvnMIIB+AwQ\
+                VjJEaWN0aW9uYXJ5RGF0YQSCAeIxggHeMBAMDEVzY3Jv\
+                d1JlY29yZAUAMBwMDFNlcmlhbE51bWJlcgwMQzM5VjIw\
+                OUFKOUw1MC0MCUJhY2t1cEtleQQgZlnxFs5NJO9YlR/4\
+                SDWH+e9rD/+Jf7lWWjMoTW9+n68wYAwMTWFjaGluZUlE\
+                S2V5DFB5V25JOHZkTmc2RVdheWVXL0ZQNGNEWlJzZTNM\
+                TW44UHhnL3gvc1B6WkpJUzVjczNSS280L3N0T1c0Nm5R\
+                OThpTmxwU0hyblIwa2ZzYlIzWDCCARkMBVZpZXdz0YIB\
+                DgwHQXBwbGVUVgwHSG9tZUtpdAwHUENTLUZERQwJUENT\
+                LU5vdGVzDApQQ1MtQmFja3VwDApQQ1MtRXNjcm93DApQ\
+                Q1MtUGhvdG9zDAtCYWNrdXBCYWdWMAwLUENTLVNoYXJp\
+                bmcMDE5hbm9SZWdpc3RyeQwMUENTLUNsb3VkS2l0DAxQ\
+                Q1MtRmVsZHNwYXIMDFBDUy1NYWlsZHJvcAwMUENTLWlN\
+                ZXNzYWdlDA1QQ1MtTWFzdGVyS2V5DA5XYXRjaE1pZ3Jh\
+                dGlvbgwOaUNsb3VkSWRlbnRpdHkMD1BDUy1pQ2xvdWRE\
+                cml2ZQwQQWNjZXNzb3J5UGFpcmluZwwQQ29udGludWl0\
+                eVVubG9jawRHMEUCIES5okyKP4YMZqDjIGRMoLE83SYh\
+                zjEyOvGPA0BoF6ViAiEAh6/dd57K+JBWmGXd4v4qGELp\
+                vAeSjqcRUfdLtQj4DxI=\
+                </data>\
+                <key>serial</key>\
+                <string>C39V209AJ9L5</string>\
+            </dict>\
+            <key>osVersion</key>\
+            <string>18A214</string>\
+            <key>peerInfoSerialNumber</key>\
+            <string>C39V209AJ9L5</string>\
+            <key>recordID</key>\
+            <string>sNs6voV0N35D/T91SuGmJnGO29</string>\
+            <key>recordStatus</key>\
+            <string>valid</string>\
+            <key>silentAttemptAllowed</key>\
+            <true/>\
+        </dict>\
+    </array>\
+    <key>SecureBackupContainsiCloudIdentity</key>\
+    <true/>\
+    <key>SecureBackupEnabled</key>\
+    <true/>\
+    <key>SecureBackupEscrowTrustStatus</key>\
+    <integer>0</integer>\
+    <key>SecureBackupRecoveryRequiresVerificationToken</key>\
+    <false/>\
+    <key>SecureBackupUsesRecoveryKey</key>\
+    <false/>\
+    <key>SecureBackupiCDPRecords</key>\
+    <array>\
+        <dict>\
+            <key>SecureBackupEscrowDate</key>\
+            <date>2020-01-31T03:07:40Z</date>\
+            <key>SecureBackupRemainingAttempts</key>\
+            <integer>10</integer>\
+            <key>encodedMetadata</key>\
+            <string>YnBsaXN0MDDZAQIDBAUGBwgJCgsMDQ4PECYgVnNlcmlhbF8QEkJhY2t1cEtleWJhZ0RpZ2VzdFVidWlsZFhwZWVySW5mb18QIGNvbS5hcHBsZS5zZWN1cmViYWNrdXAudGltZXN0YW1wWGJvdHRsZUlEXkNsaWVudE1ldGFkYXRhXGVzY3Jvd2VkU1BLSV8QHVNlY3VyZUJhY2t1cFVzZXNNdWx0aXBsZWlDU0NzXEMzOVYyMDlBSjlMNU8QFMhRrcsWNmcw7dI/9uhpDUpq4FZ2VjE4QTIxNE8RBLIwggSuMYIEYTAUDA9Db25mbGljdFZlcnNpb24CAQMwKwwPQXBwbGljYXRpb25EYXRlBBgYFjIwMjAwMTMwMjI0MTI2LjI4MDA1N1owVQwQUHVibGljU2lnbmluZ0tleQRBBOW+fXyAnCMa6by/cKGf1iHkcz9VEsa6rocBXgrLGVSb7Dy4XzT7fa1jf+X2co6ZTrXr3Vt56TBJZx8X6YNMY+swWAwPQXBwbGljYXRpb25Vc2lnBEUwQwIgY4hdZ7zcWd+Ue77JKF2OK99No8MUe9f5Fg2AzLviJKcCH04d5DOYNyFk6LTzWVuHD/2uMR7zASajNdfXbpFQ578wcAwNRGV2aWNlR2VzdGFsdDFfMBMMCU1vZGVsTmFtZQwGaVBob25lMBMMCU9TVmVyc2lvbgwGMThBMjE0MBYMDENvbXB1dGVyTmFtZQwGaVBob25lMBsMFk1lc3NhZ2VQcm90b2NvbFZlcnNpb24CAQAwfAwXT2N0YWdvblB1YmxpY1NpZ25pbmdLZXkEYQSguiFhjcalFK/bQBPruMsnWzZ0qv7VtPwmhjbdCQJ4mCMY1v6+60RCEsWMs+wQ200Tv40DvCBpzRABcsM70f8tuk1Q/wMXVDQ2kVfgmIVmobzvqNLwcSBHpU44nOEnNRkwfwwaT2N0YWdvblB1YmxpY0VuY3J5cHRpb25LZXkEYQQNGdKw9D+ZMSXl2YwRidBiFyb2GI/MGdDSCFDNvvRq5ig9sJHGMKgbswKltv7gkYzgvvg51slkltO0d5nQm0Juqj3dnIh9QtbPXfUew7LGjBNJIj3IOI8DJdnPqdGee+cwggH4DBBWMkRpY3Rpb25hcnlEYXRhBIIB4jGCAd4wEAwMRXNjcm93UmVjb3JkBQAwHAwMU2VyaWFsTnVtYmVyDAxDMzlWMjA5QUo5TDUwLQwJQmFja3VwS2V5BCBmWfEWzk0k71iVH/hINYf572sP/4l/uVZaMyhNb36frzBgDAxNYWNoaW5lSURLZXkMUHlXbkk4dmROZzZFV2F5ZVcvRlA0Y0RaUnNlM0xNbjhQeGcveC9zUHpaSklTNWNzM1JLbzQvc3RPVzQ2blE5OGlObHBTSHJuUjBrZnNiUjNYMIIBGQwFVmlld3PRggEODAdBcHBsZVRWDAdIb21lS2l0DAdQQ1MtRkRFDAlQQ1MtTm90ZXMMClBDUy1CYWNrdXAMClBDUy1Fc2Nyb3cMClBDUy1QaG90b3MMC0JhY2t1cEJhZ1YwDAtQQ1MtU2hhcmluZwwMTmFub1JlZ2lzdHJ5DAxQQ1MtQ2xvdWRLaXQMDFBDUy1GZWxkc3BhcgwMUENTLU1haWxkcm9wDAxQQ1MtaU1lc3NhZ2UMDVBDUy1NYXN0ZXJLZXkMDldhdGNoTWlncmF0aW9uDA5pQ2xvdWRJZGVudGl0eQwPUENTLWlDbG91ZERyaXZlDBBBY2Nlc3NvcnlQYWlyaW5nDBBDb250aW51aXR5VW5sb2NrBEcwRQIgRLmiTIo/hgxmoOMgZEygsTzdJiHOMTI68Y8DQGgXpWICIQCHr913nsr4kFaYZd3i/ioYQum8B5KOpxFR90u1CPgPEl8QEzIwMjAtMDEtMzEgMDM6MDc6NDBfECRERDVFM0Y5Ri0zNzAyLTQ3ODktOEFDRi0yRDI4QkM4NkE5NEPcERITFBUWFxgZGhscHQ4eHR8gISIjICMlXxAWZGV2aWNlX2VuY2xvc3VyZV9jb2xvcl8QHVNlY3VyZUJhY2t1cE1ldGFkYXRhVGltZXN0YW1wXxAPZGV2aWNlX3BsYXRmb3JtXGRldmljZV9jb2xvcl8QI1NlY3VyZUJhY2t1cE51bWVyaWNQYXNzcGhyYXNlTGVuZ3RoXxAhU2VjdXJlQmFja3VwVXNlc0NvbXBsZXhQYXNzcGhyYXNlWmRldmljZV9taWRfEBRkZXZpY2VfbW9kZWxfdmVyc2lvbltkZXZpY2VfbmFtZV8QIVNlY3VyZUJhY2t1cFVzZXNOdW1lcmljUGFzc3BocmFzZV8QEmRldmljZV9tb2RlbF9jbGFzc1xkZXZpY2VfbW9kZWxRMRQAAAAAAAAAAAAAAAAAAAABEAYJXxBQeVduSTh2ZE5nNkVXYXllVy9GUDRjRFpSc2UzTE1uOFB4Zy94L3NQelpKSVM1Y3MzUktvNC9zdE9XNDZuUTk4aU5scFNIcm5SMGtmc2JSM1haaVBob25lMTAsNVZpUGhvbmUJXWlQaG9uZSA4IFBsdXNPEHgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATIde8QFJDJYQJa6NrxP5WDLEhPNga9732ZGyoVoKi0RnxT6aIlb/LBrRvnrdZFyGUMlSYGSY3GIgrLz3YJ0A0W4BN6YKMtsgGCDONSD5/KHRzTEAE5e3Yp26nshhMavOcJAAgAGwAiADcAPQBGAGkAcgCBAI4ArgC7ANIA2QWPBaUFzAXlBf4GHgYwBj0GYwaHBpIGqQa1BtkG7gb7Bv0HDgcQBxEHZAdvB3YHdweFCAAAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAAIAQ==</string>\
+            <key>label</key>\
+            <string>com.apple.icdp.record</string>\
+            <key>metadata</key>\
+            <dict>\
+                <key>BackupKeybagDigest</key>\
+                <data>\
+                yFGtyxY2ZzDt0j/26GkNSmrgVnY=\
+                </data>\
+                <key>ClientMetadata</key>\
+                <dict>\
+                    <key>SecureBackupMetadataTimestamp</key>\
+                    <string>2020-01-31 03:07:40</string>\
+                    <key>SecureBackupNumericPassphraseLength</key>\
+                    <integer>6</integer>\
+                    <key>SecureBackupUsesComplexPassphrase</key>\
+                    <true/>\
+                    <key>SecureBackupUsesNumericPassphrase</key>\
+                    <true/>\
+                    <key>device_color</key>\
+                    <string>1</string>\
+                    <key>device_enclosure_color</key>\
+                    <string>1</string>\
+                    <key>device_mid</key>\
+                    <string>yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X</string>\
+                    <key>device_model</key>\
+                    <string>iPhone 8 Plus</string>\
+                    <key>device_model_class</key>\
+                    <string>iPhone</string>\
+                    <key>device_model_version</key>\
+                    <string>iPhone10,5</string>\
+                    <key>device_name</key>\
+                    <string>iPhone</string>\
+                    <key>device_platform</key>\
+                    <integer>1</integer>\
+                </dict>\
+                <key>SecureBackupUsesMultipleiCSCs</key>\
+                <true/>\
+                <key>bottleID</key>\
+                <string>DD5E3F9F-3702-4789-8ACF-2D28BC86A94C</string>\
+                <key>bottleValid</key>\
+                <string>valid</string>\
+                <key>build</key>\
+                <string>18A214</string>\
+                <key>com.apple.securebackup.timestamp</key>\
+                <string>2020-01-31 03:07:40</string>\
+                <key>escrowedSPKI</key>\
+                <data>\
+                MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyHXvEBSQyWEC\
+                Wuja8T+VgyxITzYGve99mRsqFaCotEZ8U+miJW/ywa0b\
+                563WRchlDJUmBkmNxiIKy892CdANFuATemCjLbIBggzj\
+                Ug+fyh0c0xABOXt2Kdup7IYTGrzn\
+                </data>\
+                <key>peerInfo</key>\
+                <data>\
+                MIIErjGCBGEwFAwPQ29uZmxpY3RWZXJzaW9uAgEDMCsM\
+                D0FwcGxpY2F0aW9uRGF0ZQQYGBYyMDIwMDEzMDIyNDEy\
+                Ni4yODAwNTdaMFUMEFB1YmxpY1NpZ25pbmdLZXkEQQTl\
+                vn18gJwjGum8v3Chn9Yh5HM/VRLGuq6HAV4KyxlUm+w8\
+                uF80+32tY3/l9nKOmU61691beekwSWcfF+mDTGPrMFgM\
+                D0FwcGxpY2F0aW9uVXNpZwRFMEMCIGOIXWe83FnflHu+\
+                yShdjivfTaPDFHvX+RYNgMy74iSnAh9OHeQzmDchZOi0\
+                81lbhw/9rjEe8wEmozXX126RUOe/MHAMDURldmljZUdl\
+                c3RhbHQxXzATDAlNb2RlbE5hbWUMBmlQaG9uZTATDAlP\
+                U1ZlcnNpb24MBjE4QTIxNDAWDAxDb21wdXRlck5hbWUM\
+                BmlQaG9uZTAbDBZNZXNzYWdlUHJvdG9jb2xWZXJzaW9u\
+                AgEAMHwMF09jdGFnb25QdWJsaWNTaWduaW5nS2V5BGEE\
+                oLohYY3GpRSv20AT67jLJ1s2dKr+1bT8JoY23QkCeJgj\
+                GNb+vutEQhLFjLPsENtNE7+NA7wgac0QAXLDO9H/LbpN\
+                UP8DF1Q0NpFX4JiFZqG876jS8HEgR6VOOJzhJzUZMH8M\
+                Gk9jdGFnb25QdWJsaWNFbmNyeXB0aW9uS2V5BGEEDRnS\
+                sPQ/mTEl5dmMEYnQYhcm9hiPzBnQ0ghQzb70auYoPbCR\
+                xjCoG7MCpbb+4JGM4L74OdbJZJbTtHeZ0JtCbqo93ZyI\
+                fULWz131HsOyxowTSSI9yDiPAyXZz6nRnnvnMIIB+AwQ\
+                VjJEaWN0aW9uYXJ5RGF0YQSCAeIxggHeMBAMDEVzY3Jv\
+                d1JlY29yZAUAMBwMDFNlcmlhbE51bWJlcgwMQzM5VjIw\
+                OUFKOUw1MC0MCUJhY2t1cEtleQQgZlnxFs5NJO9YlR/4\
+                SDWH+e9rD/+Jf7lWWjMoTW9+n68wYAwMTWFjaGluZUlE\
+                S2V5DFB5V25JOHZkTmc2RVdheWVXL0ZQNGNEWlJzZTNM\
+                TW44UHhnL3gvc1B6WkpJUzVjczNSS280L3N0T1c0Nm5R\
+                OThpTmxwU0hyblIwa2ZzYlIzWDCCARkMBVZpZXdz0YIB\
+                DgwHQXBwbGVUVgwHSG9tZUtpdAwHUENTLUZERQwJUENT\
+                LU5vdGVzDApQQ1MtQmFja3VwDApQQ1MtRXNjcm93DApQ\
+                Q1MtUGhvdG9zDAtCYWNrdXBCYWdWMAwLUENTLVNoYXJp\
+                bmcMDE5hbm9SZWdpc3RyeQwMUENTLUNsb3VkS2l0DAxQ\
+                Q1MtRmVsZHNwYXIMDFBDUy1NYWlsZHJvcAwMUENTLWlN\
+                ZXNzYWdlDA1QQ1MtTWFzdGVyS2V5DA5XYXRjaE1pZ3Jh\
+                dGlvbgwOaUNsb3VkSWRlbnRpdHkMD1BDUy1pQ2xvdWRE\
+                cml2ZQwQQWNjZXNzb3J5UGFpcmluZwwQQ29udGludWl0\
+                eVVubG9jawRHMEUCIES5okyKP4YMZqDjIGRMoLE83SYh\
+                zjEyOvGPA0BoF6ViAiEAh6/dd57K+JBWmGXd4v4qGELp\
+                vAeSjqcRUfdLtQj4DxI=\
+                </data>\
+                <key>serial</key>\
+                <string>C39V209AJ9L5</string>\
+            </dict>\
+            <key>osVersion</key>\
+            <string>18A214</string>\
+            <key>peerInfoSerialNumber</key>\
+            <string>C39V209AJ9L5</string>\
+            <key>recordID</key>\
+            <string>sNs6voV0N35D/T91SuGmJnGO29</string>\
+            <key>recordStatus</key>\
+            <string>valid</string>\
+            <key>silentAttemptAllowed</key>\
+            <true/>\
+        </dict>\
+    </array>\
+    <key>SecureBackupiCloudDataProtectionEnabled</key>\
+    <false/>\
+</dict>\
+</plist>";
+
+NSString *testCDPRemoteRecordContextTestVector = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\
+<plist version=\"1.0\">\
+<dict>\
+    <key>SecureBackupAuthenticationAppleID</key>\
+    <string>anna.535.paid@icloud.com</string>\
+    <key>SecureBackupAuthenticationAuthToken</key>\
+    <string>EAAbAAAABLwIAAAAAF5PGvkRDmdzLmljbG91ZC5hdXRovQBx359KJvlZTwe1q6BwXvK4gQUYo2WQbKT8UDtn8rcA6FvEYBANaAk1ofWx/bcfB4pcLiXR3Y0kncELCwFCEEpqpZS+klD9AY1oT9zW6VtyOgQTZJ4mfWz103+FoMh8nLJAVpYVfM/UjsiNsLfTX+rUmevfeA==</string>\
+    <key>SecureBackupAuthenticationDSID</key>\
+    <string>16187698960</string>\
+    <key>SecureBackupAuthenticationEscrowProxyURL</key>\
+    <string>https://p97-escrowproxy.icloud.com:443</string>\
+    <key>SecureBackupAuthenticationPassword</key>\
+    <string>PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET</string>\
+    <key>SecureBackupAuthenticationiCloudEnvironment</key>\
+    <string>PROD</string>\
+    <key>SecureBackupContainsiCDPData</key>\
+    <true/>\
+    <key>SecureBackupMetadata</key>\
+    <dict>\
+        <key>BackupKeybagDigest</key>\
+        <data>\
+        uZ+vDf1JWIHh+MXIi487iENG2fk=\
+        </data>\
+        <key>ClientMetadata</key>\
+        <dict>\
+            <key>SecureBackupMetadataTimestamp</key>\
+            <string>2020-02-20 00:38:28</string>\
+            <key>SecureBackupNumericPassphraseLength</key>\
+            <integer>6</integer>\
+            <key>SecureBackupUsesComplexPassphrase</key>\
+            <true/>\
+            <key>SecureBackupUsesNumericPassphrase</key>\
+            <integer>1</integer>\
+            <key>device_color</key>\
+            <string>1</string>\
+            <key>device_enclosure_color</key>\
+            <string>1</string>\
+            <key>device_mid</key>\
+            <string>vsoWCkYtidlo3QGgt6jvLDfeTWqKKQwHITeUEuYM7ZoyWI6CRH/ZUqsdg1fT96TyAyxUuYUF3fjRs5b1</string>\
+            <key>device_model</key>\
+            <string>iPhone 8 Plus</string>\
+            <key>device_model_class</key>\
+            <string>iPhone</string>\
+            <key>device_model_version</key>\
+            <string>iPhone10,2</string>\
+            <key>device_name</key>\
+            <string>One</string>\
+            <key>device_platform</key>\
+            <integer>1</integer>\
+        </dict>\
+        <key>SecureBackupUsesMultipleiCSCs</key>\
+        <true/>\
+        <key>bottleID</key>\
+        <string>0125E97E-B124-4556-881A-A355805EBE47</string>\
+        <key>bottleValid</key>\
+        <string>valid</string>\
+        <key>build</key>\
+        <string>18A230</string>\
+        <key>com.apple.securebackup.timestamp</key>\
+        <string>2020-02-20 00:38:28</string>\
+        <key>escrowedSPKI</key>\
+        <data>\
+        MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEB48BVh0D++mTSm9ucXC/a5M0CxFm\
+        4QfFktDjGV0Oo3z7xLSBiqxOwvzl1Vt7m45Rbfk4YnyguNan7aDzD1X6S2zU\
+        HhJ8nXro1aAn8tnUX6+EGV2v4iScbkeOrWkqQoWw\
+        </data>\
+        <key>peerInfo</key>\
+        <data>\
+        MIIEyjGCBHwwFAwPQ29uZmxpY3RWZXJzaW9uAgEDMCsMD0FwcGxpY2F0aW9u\
+        RGF0ZQQYGBYyMDIwMDIyMDAwMzgyMi4yODc3NjNaMFUMEFB1YmxpY1NpZ25p\
+        bmdLZXkEQQQCECkiqu2q7lmL+UUs1fzJWfI7ECo+3JsbiKsrXe8yr/JJC96U\
+        oOz8qsdqgJOoA9pp4oaLtdGU9gzopNdRxTU8MFsMD0FwcGxpY2F0aW9uVXNp\
+        ZwRIMEYCIQCNUy7VzU5erma8k0EgvXdo0YsuSgC9T4c6w3UM30vnSwIhAKsw\
+        Sz6mVOEE3cVbv8WFlF88nb54MK51cyfI3pWp3rRlMG0MDURldmljZUdlc3Rh\
+        bHQxXDATDAlNb2RlbE5hbWUMBmlQaG9uZTATDAlPU1ZlcnNpb24MBjE4QTIz\
+        MDATDAxDb21wdXRlck5hbWUMA09uZTAbDBZNZXNzYWdlUHJvdG9jb2xWZXJz\
+        aW9uAgEAMHwMF09jdGFnb25QdWJsaWNTaWduaW5nS2V5BGEErqcLz3k64Qla\
+        asOxVOz9q6jNddI5ujH1zFYjhrTzkGvRCjfgTOK6cHbEbZS6/zgpXXXNMhj4\
+        jsZR+scCcbv5yvRfyaZiGAIT5KrsnEiTXygR9hYmVdRqrjmk0ZQkgXOPMH8M\
+        Gk9jdGFnb25QdWJsaWNFbmNyeXB0aW9uS2V5BGEEsP2N8X9uVz2lqLgeYCFE\
+        8kRIUduWj7rL0ioejawj10Qj2OqNhUGYZ0xPnnaGd0uSYFiSrMT04KYXPRqZ\
+        NoExp4z9Xda9JvJXjqk2wUeo+EL/smGJmgklfcFkAlY8RheCMIICEwwQVjJE\
+        aWN0aW9uYXJ5RGF0YQSCAf0xggH5MBwMDFNlcmlhbE51bWJlcgwMQzM5VjIw\
+        RUtKOUtUMC0MCUJhY2t1cEtleQQg+5p8h4Sbq3rSHuA6eHvUGHlVKxvMvtSh\
+        DsjZD/h9OBAwYAwMTWFjaGluZUlES2V5DFB2c29XQ2tZdGlkbG8zUUdndDZq\
+        dkxEZmVUV3FLS1F3SElUZVVFdVlNN1pveVdJNkNSSC9aVXFzZGcxZlQ5NlR5\
+        QXl4VXVZVUYzZmpSczViMTCCAUYMBVZpZXdz0YIBOwwEV2lGaQwHQXBwbGVU\
+        VgwHSG9tZUtpdAwHUENTLUZERQwJUENTLU5vdGVzDAlQYXNzd29yZHMMClBD\
+        Uy1CYWNrdXAMClBDUy1Fc2Nyb3cMClBDUy1QaG90b3MMC0JhY2t1cEJhZ1Yw\
+        DAtDcmVkaXRDYXJkcwwLUENTLVNoYXJpbmcMDE5hbm9SZWdpc3RyeQwMUENT\
+        LUNsb3VkS2l0DAxQQ1MtRmVsZHNwYXIMDFBDUy1NYWlsZHJvcAwMUENTLWlN\
+        ZXNzYWdlDA1PdGhlclN5bmNhYmxlDA1QQ1MtTWFzdGVyS2V5DA5XYXRjaE1p\
+        Z3JhdGlvbgwOaUNsb3VkSWRlbnRpdHkMD1BDUy1pQ2xvdWREcml2ZQwQQWNj\
+        ZXNzb3J5UGFpcmluZwwQQ29udGludWl0eVVubG9jawRIMEYCIQC9IebK7hYO\
+        N4bYG05pbavoyP3uVs2GrBTvaaxhNeO/WgIhAP/M+WSwsqzcUkg5zhT806au\
+        Ax7U0AMhq4OkV2yIuQd8\
+        </data>\
+        <key>serial</key>\
+        <string>C39V20EKJ9KT</string>\
+    </dict>\
+    <key>SecureBackupPassphrase</key>\
+    <string>333333</string>\
+    <key>SecureBackupUsesMultipleiCSCs</key>\
+    <true/>\
+    <key>recordID</key>\
+    <string>nDF7K/s5knTXbH6/+ERe2LPFZR</string>\
+</dict>\
+</plist>";
+
+NSString* CDPRecordContextSilentTestVector = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
+<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\
+<plist version=\"1.0\">\
+<dict>\
+    <key>SecureBackupAuthenticationAppleID</key>\
+    <string>anna.535.paid@icloud.com</string>\
+    <key>SecureBackupAuthenticationAuthToken</key>\
+    <string>EAAbAAAABLwIAAAAAF5PHOERDmdzLmljbG91ZC5hdXRovQDwjwm2kXoklEtO/xeL3YCPlBr7IkVuV26y2BfLco+QhJFm4VhgFZSBFUg5l4g/uV2DG95xadgk0+rWLhyXDGZwHN2V9jju3eo6sRwGVj4g5iBFStuj4unTKylu3iFkNSKtTMXAyBXpn4EiRX+8dwumC2FKkA==</string>\
+    <key>SecureBackupAuthenticationDSID</key>\
+    <string>16187698960</string>\
+    <key>SecureBackupAuthenticationEscrowProxyURL</key>\
+    <string>https://p97-escrowproxy.icloud.com:443</string>\
+    <key>SecureBackupAuthenticationPassword</key>\
+    <string>PETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPETPET</string>\
+    <key>SecureBackupAuthenticationiCloudEnvironment</key>\
+    <string>PROD</string>\
+    <key>SecureBackupContainsiCDPData</key>\
+    <true/>\
+    <key>SecureBackupPassphrase</key>\
+    <string>333333</string>\
+    <key>SecureBackupSilentRecoveryAttempt</key>\
+    <true/>\
+    <key>SecureBackupUsesMultipleiCSCs</key>\
+    <true/>\
+</dict>\
+</plist>";
+
+#endif
+
diff --git a/keychain/OctagonTrust/ot-tests/OctagonTrustTests-Info.plist b/keychain/OctagonTrust/ot-tests/OctagonTrustTests-Info.plist
new file mode 100644 (file)
index 0000000..6c40a6c
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+</dict>
+</plist>
diff --git a/keychain/OctagonTrust/ot-tests/OctagonTrustTests.h b/keychain/OctagonTrust/ot-tests/OctagonTrustTests.h
new file mode 100644 (file)
index 0000000..84ee897
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2020 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 OctagonTrustTests_h
+#define OctagonTrustTests_h
+
+#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h"
+#import "keychain/ckks/tests/CloudKitKeychainSyncingTestsBase.h"
+#import "keychain/ot/OTControl.h"
+#import "keychain/ot/OTControlProtocol.h"
+#import "keychain/ot/OctagonControlServer.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ProxyXPCConnection : NSObject <NSXPCListenerDelegate>
+@property NSXPCListener *listener;
+@property (nonatomic) id obj;
+@property (nonatomic) NSXPCInterface *serverInterface;
+- (instancetype)initWithInterface:(NSXPCInterface*)interface obj:(id)obj;
+- (BOOL)listener:(NSXPCListener*)listener newConnection:(NSXPCConnection*)newConnection;
+@end
+
+@interface OctagonTrustTests : CloudKitKeychainSyncingTestsBase
+@property (nonatomic) OTControl*  otControl;
+@property (nonatomic) ProxyXPCConnection*  otXPCProxy;
+@property (nonatomic) id mockClique;
+
+@end
+
+
+@interface OctagonTrustTests (OctagonTrustTestsErrors)
+@end
+
+NS_ASSUME_NONNULL_END
+#endif /* OctagonTrustTests_h */
old mode 100644 (file)
new mode 100755 (executable)
index 79e748b..ceb378b
@@ -1,5 +1,4 @@
-#!/usr/bin/python
-#
+#!/usr/local/bin/python3
 
 import sys
 from glob import glob
@@ -25,9 +24,9 @@ def set_security_ios_cmd():
 
 def security_cmd_by_platform():
         swVers = subprocess.check_output(["sw_vers"])
-        deviceInformation = str(swVers, 'utf-8')
-        if "Mac OS X" in deviceInformation:
-                print("using security2 command on macosx")
+        deviceInformation = swVers.decode('utf-8')
+        if "Mac OS X" in deviceInformation or "macOS" in deviceInformation:
+                print("using security2 command on macos")
                 return set_security_mac_cmd()
         elif "iPhone OS" in deviceInformation:
                 print("using security command on ios")
@@ -38,19 +37,16 @@ def security_cmd_by_platform():
 
 security_cmd = security_cmd_by_platform()
 
-print("resetting octagon")
-subprocess.check_output(["otctl", "resetoctagon"])
-
-print("resetting ckks")
-subprocess.check_output(["ckksctl", "reset-cloudkit"])
+print("deleting all escrow records")
+subprocess.check_output(["stingrayutil", "--deleteAll", "ReallyDeleteAll"])
 
 print("resetting SOS")
 subprocess.check_output([security_cmd, "sync", "-C"])
 subprocess.check_output([security_cmd, "sync", "-P", "$iCloudPassword"])
 subprocess.check_output([security_cmd, "sync", "-O"])
 
-print("deleting all escrow records")
-subprocess.check_output(["stingrayutil", "--deleteAll", "ReallyDeleteAll"])
+print("resetting octagon")
+subprocess.check_output(["otctl", "resetoctagon"])
 
 print("creating new escrow record")
 subprocess.check_output(["sbdtool", "passcode_request_trigger"])
index f2412f5b8f09729476b55cb4b42087ddedcfbdd9..fa0acac21f3e365d2d5806edbf9e8e6f72488b65 100644 (file)
@@ -145,7 +145,7 @@ static SOSCloudTransportRef SOSCloudTransportDefaultTransport(void)
         if (defaultTransport == NULL) {
             defaultTransport = SOSCloudTransportCreateXPCTransport();
             // provide state handler to sysdiagnose and logging
-            os_state_add_handler(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), kvsStateBlock);
+            os_state_add_handler(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), kvsStateBlock);
         }
     });
     return defaultTransport;
@@ -490,7 +490,7 @@ static bool SOSCloudTransportHasPendingKey(SOSCloudTransportRef transport, CFStr
     SecXPCDictionarySetCFObject(xpcmessage, kMessageKeyKey, keyName);
 
     dispatch_semaphore_t kvsWait = dispatch_semaphore_create(0);
-    bool kvsSent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(xpc_object_t reply) {
+    bool kvsSent = messageToProxy(xpcTransport, xpcmessage, error, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(xpc_object_t reply) {
         kvsHasMessage = xpc_dictionary_get_bool(reply, kMessageKeyValue);
         dispatch_semaphore_signal(kvsWait);
     });
index bcdc6f17aa66b6990725952b93858d96be9251b6..37fb187d29b96224410a94a031b91156dde9b5f3 100644 (file)
@@ -25,7 +25,7 @@
 
 - (NSDictionary<NSString *, id>*) copyAsDictionary;
 
-- (void)pushWrites;
+- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync;
 - (BOOL)pullUpdates:(NSError**) failure;
 - (void)addOneToOutGoing;
 
index f42bc0cff463794b678327582f6fdf110f606cd3..ffd82cbc7851e1e698bfe6ff0738e2f091203bf1 100644 (file)
 }
 
 - (instancetype)init {
-    self = [super init];
-
-    self.proxy = nil;
-    self.data = [NSMutableDictionary<NSString*, NSObject*> dictionary];
-
+    if ((self = [super init])) {
+        self.proxy = nil;
+        self.data = [NSMutableDictionary<NSString*, NSObject*> dictionary];
+    }
     return self;
 }
 
@@ -62,7 +61,8 @@
     [self.data removeAllObjects];
 }
 
-- (void)pushWrites {
+- (void)pushWrites:(NSArray<NSString*>*)keys requiresForceSync:(BOOL)requiresForceSync
+{
 }
 
 - (void)addOneToOutGoing{
index 311c75e946996ff0283e25c6a1c0d69acd6313ed..a67e6caec194586ecb76ee09f6b4fd418e59f6c3 100644 (file)
@@ -20,8 +20,7 @@
     return [[CKDSimulatedAccount alloc] init];
 }
 - (instancetype) init {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         self.keysToNotHandle = [NSMutableSet<NSString*> set];
         self.keyChanges = [NSMutableDictionary<NSString*, NSObject*> dictionary];
 
index d4810cc2a8c2639ad1329382f16a3ad8e231e78a..e7199d161569ee3ddf0c9c59bed9c4ae9bc768ac 100644 (file)
 #include <Security/SecKey.h>
 #include <Security/SecureObjectSync/SOSPeerInfo.h>
 #include "keychain/SecureObjectSync/SOSFullPeerInfo.h"
+#include <TargetConditionals.h>
 
 __BEGIN_DECLS
 
+#define SOS_ENABLED (TARGET_OS_OSX || TARGET_OS_IOS)
+
 CFStringRef myMacAddress(void);
 const char *cfabsoluteTimeToString(CFAbsoluteTime abstime);
 const char *cfabsoluteTimeToStringLocal(CFAbsoluteTime abstime);
index 1d3437067d07cb0a6a21ff08d5b2be293aa67d5c..405939c99fac80cc6a12380e73700c9e8992b639 100644 (file)
@@ -220,11 +220,12 @@ CFTypeRef testGetObjectsFromCloud(CFArrayRef keysToGet, dispatch_queue_t process
         dispatch_semaphore_signal(waitSemaphore);
     };
     
-    if (!keysToGet)
+    if (!keysToGet) {
         SOSCloudKeychainGetAllObjectsFromCloud(processQueue, replyBlock);
-    else
+    } else {
         SOSCloudKeychainGetObjectsFromCloud(keysToGet, processQueue, replyBlock);
-    
+    }
+
        dispatch_semaphore_wait(waitSemaphore, finishTime);
     if (object && (CFGetTypeID(object) == CFNullGetTypeID()))   // return a NULL instead of a CFNull
     {
@@ -315,7 +316,10 @@ SOSPeerInfoRef SOSCreatePeerInfoFromName(CFStringRef name,
     require(gestalt, exit);
 
     result = SOSPeerInfoCreate(NULL, gestalt, NULL, *outSigningKey,
-                               *outOctagonSigningKey, *outOctagonEncryptionKey, error);
+                               *outOctagonSigningKey, *outOctagonEncryptionKey,
+                               // Always support CKKS4All for now
+                               true,
+                               error);
 
 exit:
     CFReleaseNull(gestalt);
index e7e2ac8e7b79f8ebc7673488826ca7c8864e3ba3..e27c713db48e74dcdbd34dcd58b2d289bb3ed4a2 100644 (file)
@@ -220,7 +220,7 @@ static SOSObjectRef copyMergedObject(SOSObjectRef object1, SOSObjectRef object2,
             // Return the item with the smallest digest.
             CFDataRef digest1 = copyDigest(object1, error);
             CFDataRef digest2 = copyDigest(object2, error);
-            if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) {
+            if (digest1 && digest2) switch (CFDataCompareDERData(digest1, digest2)) {
                 case kCFCompareGreaterThan:
                 case kCFCompareEqualTo:
                     result = (SOSObjectRef)dict2;
index 5ad7629b3dffad7c1018276774ee5fa6ade7d97d..b0ba179bd777ed4dc239bdd07a0fb1e80fddf8cf 100644 (file)
@@ -41,6 +41,8 @@
 
 #include "SOSRegressionUtilities.h"
 
+#if SOS_ENABLED
+
 typedef struct piStuff_t {
     SecKeyRef signingKey;
     SecKeyRef octagonSigningKey;
@@ -150,13 +152,15 @@ static void tests(void)
     freeSimplePeer(iDrone);
 }
 
-static int kTestTestCount = 12;
+#endif
 
 int sc_130_resignationticket(int argc, char *const *argv)
 {
-    plan_tests(kTestTestCount);
-    
+#if SOS_ENABLED
+    plan_tests(12);
     tests();
-    
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 3120a20a6fe7df5fc7cbc9482615876119782bad..768fe6ae0e0e6054a745bb435ed25710fcbb7093 100644 (file)
@@ -40,6 +40,8 @@
 #include "SOSRegressionUtilities.h"
 #include "keychain/SecureObjectSync/SOSInternal.h"
 
+#if SOS_ENABLED
+
 #if 0
 static inline CFMutableDataRef CFDataCreateMutableWithRandom(CFAllocatorRef allocator, CFIndex size) {
     CFMutableDataRef result = NULL;
@@ -68,8 +70,6 @@ static const uint8_t sEntropy2[] = {   0xef, 0xbd, 0x72, 0x57, 0x02, 0xe6, 0xbd,
 
 static const uint8_t sEntropy3[] = {   0xea, 0x06, 0x34, 0x93, 0xd7, 0x8b, 0xd6, 0x0d, 0xce, 0x83, 0x00 };
 
-
-#define tests_count (6)
 static void tests(void)
 {
     ccec_const_cp_t cp = SOSGetBackupKeyCurveParameters();
@@ -112,14 +112,16 @@ static void tests(void)
     CFReleaseNull(entropy2);
     CFReleaseNull(entropy3);
 }
+#endif
 
-static int kTestTestCount = tests_count;
 
 int sc_150_backupkeyderivation(int argc, char *const *argv)
 {
-    plan_tests(kTestTestCount);
-
+#if SOS_ENABLED
+    plan_tests(6);
     tests();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index a1cefebae9b7119d9b3598678f88f140d88360cc..289836289b6751a70f684b9bb041ec12154aba7e 100644 (file)
 #include "SOSCircle_regressions.h"
 #include "SOSRegressionUtilities.h"
 
+#if SOS_ENABLED
+
 #define encode_decode_count 2
-#if !TARGET_OS_SIMULATOR
+
 static CF_RETURNS_RETAINED SOSBackupSliceKeyBagRef EncodeDecode(SOSBackupSliceKeyBagRef bag)
 {
     SOSBackupSliceKeyBagRef result = NULL;
@@ -54,17 +56,6 @@ static CF_RETURNS_RETAINED SOSBackupSliceKeyBagRef EncodeDecode(SOSBackupSliceKe
 
     return result;
 }
-#endif
-
-#if 0
-static CFDataRef CFDataCreateWithRandom(CFAllocatorRef allocator, size_t size) {
-    CFMutableDataRef result = CFDataCreateMutableWithScratch(allocator, size);
-
-    SecRandomCopyBytes(kSecRandomDefault, size, CFDataGetMutableBytePtr(result));
-
-    return result;
-}
-#endif
 
 static const uint8_t sEntropy1[] = {
     0xc4, 0xb9, 0xa6, 0x6e, 0xeb, 0x56, 0xa1, 0x5c, 0x1d, 0x30, 0x09, 0x40,
@@ -78,12 +69,6 @@ static const uint8_t sEntropy2[] = {
     0x3a, 0x91, 0x0d, 0xc1, 0x5f, 0x57, 0x98, 0x44
 };
 
-#if !TARGET_OS_SIMULATOR
-    #define tests_count (8 + encode_decode_count)
-#else
-    #define tests_count (6)
-#endif
-
 static void tests(void)
 {
     CFErrorRef localError = NULL;
@@ -132,7 +117,6 @@ static void tests(void)
 
     SOSBackupSliceKeyBagRef vb2 = NULL;
 
-#if !TARGET_OS_SIMULATOR
     vb = SOSBackupSliceKeyBagCreate(kCFAllocatorDefault, piSet, &localError);
     ok(vb != NULL, "Allocation: (%@)", localError);
     CFReleaseNull(localError);
@@ -140,20 +124,6 @@ static void tests(void)
     vb2 = EncodeDecode(vb);
 
     ok(vb2 != NULL, "transcoded");
-#endif
-#if 0
-    // <rdar://problem/20561988> Have helper functions for new security object that load bags
-    keybag_handle_t ourHandle = SOSBSKBLoadAndUnlockWithPeerSecret(vb, peer2WithBackup, entropy2, &localError);
-    ok(ourHandle != bad_keybag_handle, "loaded with peer secret, handle %d (%@)", ourHandle, localError);
-    CFReleaseNull(localError);
-
-    aks_unload_bag(ourHandle);
-#else
-TODO:{
-    todo("no simulator supprt");
-    ok(false);
-    }
-#endif
 
     CFReleaseNull(vb);
     CFReleaseNull(vb2);
@@ -172,14 +142,15 @@ TODO:{
     CFReleaseNull(entropy1);
     CFReleaseNull(entropy2);
 }
-
-static int kTestTestCount = tests_count;
+#endif
 
 int sc_153_backupslicekeybag(int argc, char *const *argv)
 {
-    plan_tests(kTestTestCount);
-
+#if SOS_ENABLED
+    plan_tests(12);
     tests();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index a37224904ef7372bfa27797d4627c154ee2e265e..ad74dbc820f076f37c755fccebdb5cd60872c69c 100644 (file)
@@ -43,6 +43,8 @@
 
 #include "SOSRegressionUtilities.h"
 
+#if SOS_ENABLED
+
 
 static int kTestTestCount = 15;
 static void tests(void)
@@ -130,12 +132,15 @@ static void tests(void)
     CFReleaseNull(retirement_peer_id);
 
 }
+#endif
 
 int sc_20_keynames(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     tests();
-
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 42859409e93e77ca400a4bc7376a46ecfb2a1531..bce0790384a33fba805e42feacc45acc401a5151 100644 (file)
@@ -48,6 +48,9 @@
 #include "SOSCircle_regressions.h"
 
 #include "SOSRegressionUtilities.h"
+
+#if SOS_ENABLED
+
 #include <corecrypto/ccrng.h>
 #include <corecrypto/ccrng_pbkdf2_prng.h>
 #include <corecrypto/ccec.h>
@@ -185,7 +188,6 @@ static SecKeyRef SOSOldUserKeygen(CFDataRef password, CFDataRef parameters, CFEr
         return NULL;
     }
 
-    debugDumpUserParameters(CFSTR("params-keygen"), parameters);
 
 
     const uint8_t *password_bytes = CFDataGetBytePtr(password);
@@ -198,7 +200,7 @@ static SecKeyRef SOSOldUserKeygen(CFDataRef password, CFDataRef parameters, CFEr
 
     ccec_full_ctx_decl_cp(cp, tmpkey);
 
-    secnotice("circleOps", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters);
+    debugDumpUserParameters(CFSTR("sc_25_soskeygen: Generating key for:"), parameters);
 
     if (ccrng_pbkdf2_prng_init(&pbkdf2_prng, maxbytes,
                                password_length, password_bytes,
@@ -275,15 +277,15 @@ static void tests(void) {
     CFReleaseNull(cfpassword);
 }
 
+#endif
+
 int sc_25_soskeygen(int argc, char *const *argv)
 {
-#if TARGET_OS_WATCH
-    plan_tests(NKEYS*(4+NPARMS*4));
-#else
+#if SOS_ENABLED
     plan_tests(850);
-#endif
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 66c959295d8bba22f975d6be4685355a8839fa88..4efa2918ebf416485ddb5d84f451fe5aa0636f20 100644 (file)
@@ -46,6 +46,8 @@
 
 #include "SOSRegressionUtilities.h"
 
+#if SOS_ENABLED
+
 #if TARGET_OS_IPHONE
 #include <MobileGestalt.h>
 #endif
@@ -152,12 +154,15 @@ static void tests(void)
     CFReleaseNull(octagonEncryptionKey);
     CFReleaseNull(fpi);
 }
+#endif
 
 int sc_30_peerinfo(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-       
     tests();
-
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 800a241d477defbf0966a930e896a3c82d0038d0..2774cbd92bd0f3be21279246677919dcd1076d08 100644 (file)
@@ -28,6 +28,7 @@
 #include "SOSCircle_regressions.h"
 
 #include "SOSRegressionUtilities.h"
+#if SOS_ENABLED
 
 #if TARGET_OS_IPHONE
 #include <MobileGestalt.h>
@@ -79,12 +80,15 @@ errOut:
     CFReleaseNull(octagonEncryptionKey);
     CFReleaseNull(fpi);
 }
+#endif
 
 int sc_31_peerinfo(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests((int)(kTestCount + kTestFuzzerCount));
-       
     tests();
-    
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 6f516bd166bea9f7bd5ced0c9b18dcb781fd0029..a4687f81fb69b0888070f951159af318b0e7c1a5 100644 (file)
@@ -47,6 +47,8 @@
 
 #include "SOSRegressionUtilities.h"
 
+#if SOS_ENABLED
+
 static int kTestGenerationCount = 2;
 static void test_generation(void)
 {
@@ -182,14 +184,16 @@ static void tests(void)
     CFReleaseNull(user_privkey);
     CFReleaseNull(circle);
 }
+#endif
 
 int sc_40_circle(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestGenerationCount + kTestTestCount);
-
     test_generation();
-
     tests();
-
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 7ee1573666cdd469ad1f30df46cf921c8110b897..f3ba599d3e93a5ffe6f2aba433e6c51aeb57049d 100644 (file)
@@ -31,8 +31,7 @@
 #include "SOSCircle_regressions.h"
 
 #include "SOSRegressionUtilities.h"
-
-static int kTestTestCount = 7;
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -66,12 +65,15 @@ static void tests(void)
     
     CFReleaseNull(circle);
 }
+#endif
 
 int sc_42_circlegencount(int argc, char *const *argv)
 {
-    plan_tests(kTestTestCount);
-    
+#if SOS_ENABLED
+    plan_tests(7);
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 7f86e64357397b36f9566f7f41ae3a82ac0c831b..8c177bcc3d68f48c8640b02a2308b98c779c94b0 100644 (file)
@@ -28,8 +28,7 @@
 
 #include <utilities/SecCFRelease.h>
 #include <stdlib.h>
-
-static int kTestTestCount = 15;
+#include "SOSRegressionUtilities.h"
 
 static void testNullDigestVector(void)
 {
@@ -158,9 +157,11 @@ static void tests(void)
 
 int sc_45_digestvector(int argc, char *const *argv)
 {
-    plan_tests(kTestTestCount);
-
+#if SOS_ENABLED
+    plan_tests(15);
     tests();
-
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 7d8881025fd3d822a43ad3461c2c632433d354a3..b2bf94a2b71c5fd4bf3cb701aa07ef1d85750b49 100644 (file)
 #import "keychain/SecureObjectSync/SOSAccountTransaction.h"
 #include <dispatch/dispatch.h>
 
+extern NSString* const kSOSIdentityStatusCompleteIdentity;
+extern NSString* const kSOSIdentityStatusKeyOnly;
+extern NSString* const kSOSIdentityStatusPeerOnly;
+
 @class SOSAccount;
 
 __BEGIN_DECLS
@@ -105,9 +109,9 @@ void SOSTransportEachMessage(SOSAccount*  account, CFDictionaryRef updates, CFEr
 
 CFStringRef SOSAccountGetSOSCCStatusString(SOSCCStatus status);
 SOSCCStatus SOSAccountGetSOSCCStatusFromString(CFStringRef status);
-bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error);
-bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error);
-bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error);
+bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, CFErrorRef* error);
+bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, CFErrorRef* error);
+bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, CFErrorRef* error);
 bool SOSAccountBail(SOSAccount*  account, uint64_t limit_in_seconds, CFErrorRef* error);
 bool SOSAccountAcceptApplicants(SOSAccount*  account, CFArrayRef applicants, CFErrorRef* error);
 bool SOSAccountRejectApplicants(SOSAccount*  account, CFArrayRef applicants, CFErrorRef* error);
@@ -158,6 +162,12 @@ void SOSAccountPeerGotInSync(SOSAccountTransaction* aTxn, CFStringRef peerID, CF
 
 bool SOSAccountHandleParametersChange(SOSAccount*  account, CFDataRef updates, CFErrorRef *error);
 
+//
+// MARK: Local device key access from account object - can call without lock without endangering peerinfo.
+//
+SecKeyRef SOSAccountCopyDevicePrivateKey(SOSAccount* account, CFErrorRef *error);
+SecKeyRef SOSAccountCopyDevicePublicKey(SOSAccount* account, CFErrorRef *error);
+
 //
 // MARK: Requests for syncing later
 //
@@ -192,7 +202,7 @@ CF_RETURNS_RETAINED SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccount*
 bool SOSAccountIsBackupRingEmpty(SOSAccount*  account, CFStringRef viewName);
 bool SOSAccountNewBKSBForView(SOSAccount*  account, CFStringRef viewName, CFErrorRef *error);
 
-void SOSAccountProcessBackupRings(SOSAccount*  account, CFErrorRef *error);
+void SOSAccountProcessBackupRings(SOSAccount*  account);
 bool SOSAccountValidateBackupRingForView(SOSAccount*  account, CFStringRef viewName, CFErrorRef *error);
 bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef backupKey, CFErrorRef *error);
 bool SOSAccountRemoveBackupPublickey(SOSAccountTransaction* aTxn, CFErrorRef *error);
@@ -281,6 +291,8 @@ void SOSAccountResetOTRNegotiationCoder(SOSAccount* account, CFStringRef peerid)
 void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* peerid, NSString* accessGroup);
 
 NSArray<NSDictionary *>* SOSAccountGetAllTLKs(void);
+NSArray<NSDictionary *>* SOSAccountGetSelectedTLKs(void);
+
 CF_RETURNS_RETAINED CFMutableArrayRef SOSAccountCopyiCloudIdentities(SOSAccount* account);
 
 bool SOSAccountEvaluateKeysAndCircle(SOSAccountTransaction *txn, CFErrorRef *block_error);
index 9976962f2b52276a21a649838002367854edaf6f..c68ab63bfa5a82cbfde284c7deaa71dd0aa81c3e 100644 (file)
@@ -63,7 +63,6 @@
 
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFError.h>
-#include <utilities/SecADWrapper.h>
 #include <utilities/SecFileLocations.h>
 
 #include <os/activity.h>
@@ -94,6 +93,10 @@ const CFStringRef kOTRConfigVersion = CFSTR("OTRConfigVersion");
 NSString* const SecSOSAggdReattemptOTRNegotiation   = @"com.apple.security.sos.otrretry";
 NSString* const SOSAccountUserDefaultsSuite = @"com.apple.security.sosaccount";
 NSString* const SOSAccountLastKVSCleanup = @"lastKVSCleanup";
+NSString* const kSOSIdentityStatusCompleteIdentity = @"completeIdentity";
+NSString* const kSOSIdentityStatusKeyOnly = @"keyOnly";
+NSString* const kSOSIdentityStatusPeerOnly = @"peerOnly";
+
 
 const uint64_t max_packet_size_over_idms = 500;
 
@@ -113,6 +116,7 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
 @property (readwrite) CKKSPBFileStorage<SOSAccountConfiguration*>* accountConfiguration;
 
 @property CKKSNearFutureScheduler *performBackups;
+@property CKKSNearFutureScheduler *performRingUpdates;
 @end
 #endif
 
@@ -123,6 +127,14 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
         CFReleaseNull(self->_accountKey);
         CFReleaseNull(self->_accountPrivateKey);
         CFReleaseNull(self->_previousAccountKey);
+        CFReleaseNull(self->_peerPublicKey);
+        CFReleaseNull(self->_octagonSigningFullKeyRef);
+        CFReleaseNull(self->_octagonEncryptionFullKeyRef);
+#if OCTAGON
+        [self.performBackups cancel];
+        [self.performRingUpdates cancel];
+        [self.stateMachine haltOperation];
+#endif
     }
 }
 
@@ -132,16 +144,22 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
     CFRetainAssign(self->_accountKey, key);
 }
 
+@synthesize accountPrivateKey = _accountPrivateKey;
+
+- (void) setAccountPrivateKey: (SecKeyRef) key {
+    CFRetainAssign(self->_accountPrivateKey, key);
+}
+
 @synthesize previousAccountKey = _previousAccountKey;
 
 - (void) setPreviousAccountKey: (SecKeyRef) key {
     CFRetainAssign(self->_previousAccountKey, key);
 }
 
-@synthesize accountPrivateKey = _accountPrivateKey;
+@synthesize peerPublicKey = _peerPublicKey;
 
-- (void) setAccountPrivateKey: (SecKeyRef) key {
-    CFRetainAssign(self->_accountPrivateKey, key);
+- (void) setPeerPublicKey: (SecKeyRef) key {
+    CFRetainAssign(self->_peerPublicKey, key);
 }
 
 // Syntactic sugar getters
@@ -164,16 +182,11 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
 
 -(bool) ensureFactoryCircles
 {
-    if (!self){
-        return false;
-    }
-
-    if (!self.factory){
+    if (self.factory == nil){
         return false;
     }
 
-    NSString* circle_name = (__bridge_transfer NSString*)SOSDataSourceFactoryCopyName(self.factory);
-
+    NSString* circle_name = CFBridgingRelease(SOSDataSourceFactoryCopyName(self.factory));
     if (!circle_name){
         return false;
     }
@@ -195,8 +208,7 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
 
 -(id) initWithGestalt:(CFDictionaryRef)newGestalt factory:(SOSDataSourceFactoryRef)f
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.queue = dispatch_queue_create("Account Queue", DISPATCH_QUEUE_SERIAL);
 
         self.gestalt = [[NSDictionary alloc] initWithDictionary:(__bridge NSDictionary * _Nonnull)(newGestalt)];
@@ -223,20 +235,26 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
         self.circle_rings_retirements_need_attention = false;
         self.engine_peer_state_needs_repair = false;
         self.key_interests_need_updating = false;
+        self.need_backup_peers_created_after_backup_key_set = false;
         
         self.backup_key =nil;
         self.deviceID = nil;
 
         self.waitForInitialSync_blocks = [NSMutableDictionary dictionary];
         self.accountKeyIsTrusted = false;
-        self.accountKeyDerivationParamters = NULL;
+        self.accountKeyDerivationParameters = NULL;
         self.accountKey = NULL;
         self.previousAccountKey = NULL;
+        self.peerPublicKey = NULL;
 
         self.saveBlock = nil;
 
         self.settings =  [[NSUserDefaults alloc] initWithSuiteName:SOSAccountUserDefaultsSuite];
 
+        [self ensureFactoryCircles];
+        SOSAccountEnsureUUID(self);
+        self.accountIsChanging = false;
+
 #if OCTAGON
         [self setupStateMachine];
 #endif
@@ -244,6 +262,13 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
     return self;
 }
 
+- (void)startStateMachine
+{
+#if OCTAGON
+    [self.stateMachine startOperation];
+#endif
+}
+
 -(BOOL)isEqual:(id) object
 {
     if(![object isKindOfClass:[SOSAccount class]])
@@ -283,7 +308,7 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void);
 - (void)kvsPerformanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *))reply
 {
     /* Need to collect performance counters from all subsystems, not just circle transport, don't have counters yet though */
-    SOSCloudKeychainRequestPerfCounters(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error)
+    SOSCloudKeychainRequestPerfCounters(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error)
     {
         reply((__bridge NSDictionary *)returnedValues);
     });
@@ -332,7 +357,7 @@ static bool SyncKVSAndWait(CFErrorRef *error) {
     secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
     
     os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
-        SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
+        SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
             secnotice("fresh", "EFP returned, callback error: %@", sync_error);
             
             success = (sync_error == NULL);
@@ -357,7 +382,7 @@ static bool Flush(CFErrorRef *error) {
     dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
     secnotice("flush", "Starting");
     
-    SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
+    SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
         success = (sync_error == NULL);
         if (error) {
             CFRetainAssign(*error, sync_error);
@@ -422,57 +447,63 @@ static bool Flush(CFErrorRef *error) {
         CFReleaseNull(error);
     });
 }
-
 - (void)stashAccountCredential:(NSData *)credential complete:(void(^)(bool success, NSError *error))complete
 {
-    CFErrorRef syncerror = NULL;
-
-    if (![self syncWaitAndFlush:&syncerror]) {
-        complete(NULL, (__bridge NSError *)syncerror);
-        CFReleaseNull(syncerror);
-        return;
-    }
 
-    sleep(1); // make up for keygen time in password based version - let syncdefaults catch up
+    dispatch_sync(SOSCCCredentialQueue(), ^{
+        CFErrorRef syncerror = NULL;
 
-    [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
-        SecKeyRef accountPrivateKey = NULL;
-        CFErrorRef error = NULL;
-        NSDictionary *attributes = @{
-            (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate,
-            (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC,
-        };
+        if (![self syncWaitAndFlush:&syncerror]) {
+            complete(NULL, (__bridge NSError *)syncerror);
+            CFReleaseNull(syncerror);
+        } else {
+            __block bool success = false;
+            sleep(1); // make up for keygen time in password based version - let syncdefaults catch up
+
+            [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
+                SecKeyRef accountPrivateKey = NULL;
+                CFErrorRef error = NULL;
+                NSDictionary *attributes = @{
+                    (__bridge id)kSecAttrKeyClass : (__bridge id)kSecAttrKeyClassPrivate,
+                    (__bridge id)kSecAttrKeyType : (__bridge id)kSecAttrKeyTypeEC,
+                };
+
+                accountPrivateKey = SecKeyCreateWithData((__bridge CFDataRef)credential, (__bridge CFDictionaryRef)attributes, &error);
+                if (accountPrivateKey == NULL) {
+                    complete(false, (__bridge NSError *)error);
+                    secnotice("pairing", "SecKeyCreateWithData failed: %@", error);
+                    CFReleaseNull(error);
+                    return;
+                }
 
-        accountPrivateKey = SecKeyCreateWithData((__bridge CFDataRef)credential, (__bridge CFDictionaryRef)attributes, &error);
-        if (accountPrivateKey == NULL) {
-            complete(false, (__bridge NSError *)error);
-            secnotice("pairing", "SecKeyCreateWithData failed: %@", error);
-            CFReleaseNull(error);
-            return;
-        }
+                if (!SOSAccountTryUserPrivateKey(self, accountPrivateKey, &error)) {
+                    CFReleaseNull(accountPrivateKey);
+                    complete(false, (__bridge NSError *)error);
+                    secnotice("pairing", "SOSAccountTryUserPrivateKey failed: %@", error);
+                    CFReleaseNull(error);
+                    return;
+                }
+                
+                success = true;
+                secnotice("pairing", "SOSAccountTryUserPrivateKey succeeded");
 
-        if (!SOSAccountTryUserPrivateKey(self, accountPrivateKey, &error)) {
-            CFReleaseNull(accountPrivateKey);
-            complete(false, (__bridge NSError *)error);
-            secnotice("pairing", "SOSAccountTryUserPrivateKey failed: %@", error);
-            CFReleaseNull(error);
-            return;
+                CFReleaseNull(accountPrivateKey);
+                complete(true, NULL);
+            }];
+            
+            // This makes getting the private key the same as Asserting the password - we read all the other things
+            // that we just expressed interest in.
+            
+            if(success) {
+                CFErrorRef localError = NULL;
+                if (!Flush(&localError)) {
+                    // we're still setup with the private key - just report this.
+                    secnotice("pairing", "failed final flush: %@", localError);
+                }
+                CFReleaseNull(localError);
+            }
         }
-        
-        secnotice("pairing", "SOSAccountTryUserPrivateKey succeeded");
-
-        CFReleaseNull(accountPrivateKey);
-        complete(true, NULL);
-    }];
-    
-    // This makes getting the private key the same as Asserting the password - we read all the other things
-    // that we just expressed interest in.
-    CFErrorRef error = NULL;
-    if (!Flush(&error)) {
-        secnotice("pairing", "failed final flush: %@", error ? error : NULL);
-        return;
-    }
-    CFReleaseNull(error);
+    });
 }
 
 - (void)myPeerInfo:(void (^)(NSData *, NSError *))complete
@@ -613,6 +644,75 @@ static bool Flush(CFErrorRef *error) {
     complete(json, err);
 }
 
+- (void) iCloudIdentityStatus_internal: (void(^)(NSDictionary *tableSpid, NSError *error))complete {
+    CFErrorRef localError = NULL;
+    NSMutableDictionary *tableSPID = [NSMutableDictionary new];
+
+    if(![self isInCircle: &localError]) {
+        complete(tableSPID, (__bridge NSError *)localError);
+        return;
+    }
+
+    // Make set of SPIDs for iCloud Identity PeerInfos
+    NSMutableSet<NSString*> *peerInfoSPIDs = [[NSMutableSet alloc] init];
+    SOSCircleForEachiCloudIdentityPeer(self.trust.trustedCircle , ^(SOSPeerInfoRef peer) {
+        NSString *peerID = CFBridgingRelease(CFStringCreateCopy(kCFAllocatorDefault, SOSPeerInfoGetPeerID(peer)));
+        if(peerID) {
+            [ peerInfoSPIDs addObject:peerID];
+        }
+    });
+
+    // Make set of SPIDs for iCloud Identity Private Keys
+    NSMutableSet<NSString*> *privateKeySPIDs = [[NSMutableSet alloc] init];
+    SOSiCloudIdentityPrivateKeyForEach(^(SecKeyRef privKey) {
+        CFErrorRef localError = NULL;
+        CFStringRef keyID = SOSCopyIDOfKey(privKey, &localError);
+        if(keyID) {
+            NSString *peerID = CFBridgingRelease(keyID);
+            [ privateKeySPIDs addObject:peerID];
+        } else {
+            secnotice("iCloudIdentity", "couldn't make ID from key (%@)", localError);
+        }
+        CFReleaseNull(localError);
+    });
+
+    NSMutableSet<NSString*> *completeIdentity = [peerInfoSPIDs mutableCopy];
+    if([peerInfoSPIDs count] > 0 && [privateKeySPIDs count] > 0) {
+        [ completeIdentity intersectSet:privateKeySPIDs];
+    } else {
+        completeIdentity = nil;
+    }
+
+    NSMutableSet<NSString*> *keyOnly = [privateKeySPIDs mutableCopy];
+    if([peerInfoSPIDs count] > 0 && [keyOnly count] > 0) {
+        [ keyOnly minusSet: peerInfoSPIDs ];
+    }
+
+    NSMutableSet<NSString*> *peerOnly = [peerInfoSPIDs mutableCopy];
+    if([peerOnly count] > 0 && [privateKeySPIDs count] > 0) {
+        [ peerOnly minusSet: privateKeySPIDs ];
+    }
+
+    tableSPID[kSOSIdentityStatusCompleteIdentity] = [completeIdentity allObjects];
+    tableSPID[kSOSIdentityStatusKeyOnly] = [keyOnly allObjects];
+    tableSPID[kSOSIdentityStatusPeerOnly] = [peerOnly allObjects];
+
+    complete(tableSPID, nil);
+}
+
+- (void)iCloudIdentityStatus: (void (^)(NSData *json, NSError *error))complete {
+    [self iCloudIdentityStatus_internal:^(NSDictionary *tableSpid, NSError *error) {
+        NSError *err = nil;
+        NSData *json = [NSJSONSerialization dataWithJSONObject:tableSpid
+                                                       options:(NSJSONWritingPrettyPrinted | NSJSONWritingSortedKeys)
+                                                         error:&err];
+        if (!json) {
+            secnotice("iCloudIdentity", "Error during iCloudIdentityStatus JSONification: %@", err.localizedDescription);
+        }
+        complete(json, err);
+    }];
+}
+
 #else
 
 + (SOSAccountGhostBustingOptions) ghostBustGetRampSettings {
@@ -649,7 +749,16 @@ static bool Flush(CFErrorRef *error) {
     return false;
 }
 
-#endif
+- (void)iCloudIdentityStatus:(void (^)(NSData *, NSError *))complete {
+    complete(nil, nil);
+}
+
+
+- (void)iCloudIdentityStatus_internal:(void (^)(NSDictionary *, NSError *))complete {
+    complete(nil, nil);
+}
+
+#endif // !(TARGET_OS_OSX || TARGET_OS_IOS)
 
 - (void)circleJoiningBlob:(NSData *)applicant complete:(void (^)(NSData *blob, NSError *))complete
 {
@@ -715,7 +824,7 @@ static bool Flush(CFErrorRef *error) {
     CFReleaseNull(error);
 }
 
-- (void)triggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
 {
     __block CFErrorRef localError = NULL;
     __block bool res = false;
@@ -740,7 +849,7 @@ static bool Flush(CFErrorRef *error) {
     CFReleaseNull(localError);
 }
 
-- (void)triggerBackup:(NSArray<NSString *>* _Nullable)backupPeers complete:(void (^)(NSError *error))complete
+- (void)rpcTriggerBackup:(NSArray<NSString *>* _Nullable)backupPeers complete:(void (^)(NSError *error))complete
 {
     __block CFErrorRef localError = NULL;
 
@@ -757,6 +866,14 @@ static bool Flush(CFErrorRef *error) {
     CFReleaseNull(localError);
 }
 
+- (void)rpcTriggerRingUpdate:(void (^)(NSError *error))complete
+{
+#if OCTAGON
+    [self triggerRingUpdate];
+#endif
+    complete(NULL);
+}
+
 - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete
 {
     // SecdWatchdog is only available in the secd/securityd - no other binary will contain that class
@@ -832,6 +949,17 @@ void SOSAccountAssertDSID(SOSAccount*  account, CFStringRef dsid) {
     }
 }
 
+SecKeyRef SOSAccountCopyDevicePrivateKey(SOSAccount* account, CFErrorRef *error) {
+    if(account.peerPublicKey) {
+        return SecKeyCopyMatchingPrivateKey(account.peerPublicKey, error);
+    }
+    return NULL;
+}
+
+SecKeyRef SOSAccountCopyDevicePublicKey(SOSAccount* account, CFErrorRef *error) {
+    return SecKeyCopyPublicKey(account.peerPublicKey);
+}
+
 
 void SOSAccountPendDisableViewSet(SOSAccount*  account, CFSetRef disabledViews)
 {
@@ -862,10 +990,10 @@ SOSAccount*  SOSAccountCreate(CFAllocatorRef allocator,
                                SOSDataSourceFactoryRef factory) {
 
     SOSAccount* a = [[SOSAccount alloc] initWithGestalt:gestalt factory:factory];
-    [a ensureFactoryCircles];
-    SOSAccountEnsureUUID(a);
-    secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreate");
-    a.key_interests_need_updating = true;
+    dispatch_sync(a.queue, ^{
+        secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreate");
+        a.key_interests_need_updating = true;
+    });
     
     return a;
 }
@@ -970,7 +1098,6 @@ void SOSAccountSetToNew(SOSAccount*  a)
     result = do_keychain_delete_sbd(); (void) result;
     secdebug("set to new", "result for deleting sbd: %d", result);
 
-    a.accountKeyIsTrusted = false;
 
     if (a.user_private_timer) {
         dispatch_source_cancel(a.user_private_timer);
@@ -995,11 +1122,30 @@ void SOSAccountSetToNew(SOSAccount*  a)
 
     a.circle_transport = NULL;
     a.kvs_message_transport = nil;
+    a._password_tmp = nil;
+    a.circle_rings_retirements_need_attention = true;
+    a.engine_peer_state_needs_repair = true;
+    a.key_interests_need_updating = true;
+    a.need_backup_peers_created_after_backup_key_set = true;
+
+    a.accountKeyIsTrusted = false;
+    a.accountKeyDerivationParameters = nil;
+    a.accountPrivateKey = NULL;
+    a.accountKey = NULL;
+    a.previousAccountKey = NULL;
+    a.peerPublicKey = NULL;
+    a.backup_key = nil;
+    a.notifyCircleChangeOnExit = true;
+    a.notifyViewChangeOnExit = true;
+    a.notifyBackupOnExit = true;
+
+    a.octagonSigningFullKeyRef = NULL;
+    a.octagonEncryptionFullKeyRef = NULL;
 
     a.trust = nil;
+    // setting a new trust object resets all the rings from this peer's point of view - they're in the SOSAccountTrustClassic dictionary
     a.trust = [[SOSAccountTrustClassic alloc]initWithRetirees:[NSMutableSet set] fpi:NULL circle:NULL departureCode:kSOSDepartureReasonError peerExpansion:[NSMutableDictionary dictionary]];
-
-    [a ensureFactoryCircles]; // Does rings too
+    [a ensureFactoryCircles];
 
     // By resetting our expansion dictionary we've reset our UUID, so we'll be notified properly
     SOSAccountEnsureUUID(a);
@@ -1121,50 +1267,24 @@ void SOSAccountRemoveChangeBlock(SOSAccount*  a, SOSAccountCircleMembershipChang
 
 void SOSAccountPurgeIdentity(SOSAccount*  account) {
     SOSAccountTrustClassic *trust = account.trust;
-    SOSFullPeerInfoRef identity = trust.fullPeerInfo;
-
-    if (identity) {
-        // Purge private key but don't return error if we can't.
-        CFErrorRef purgeError = NULL;
-        if (!SOSFullPeerInfoPurgePersistentKey(identity, &purgeError)) {
-            secwarning("Couldn't purge persistent key for %@ [%@]", identity, purgeError);
-        }
-        CFReleaseNull(purgeError);
-
-        trust.fullPeerInfo = nil;
-    }
+    [trust purgeIdentity];
 }
 
-bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error) {
+bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error) {
     SOSAccountTrustClassic *trust = account.trust;
     SOSFullPeerInfoRef identity = trust.fullPeerInfo;
     NSMutableSet* retirees = trust.retirees;
 
     NSError* localError = nil;
-    SFSignInAnalytics* parent = nil;
-    
-    if(parentData) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentData error:&localError];
-    }
-
     SOSFullPeerInfoRef fpi = identity;
     if(!fpi) return false;
 
     CFErrorRef retiredError = NULL;
 
     bool retval = false;
-
-    SFSignInAnalytics *promoteToRetiredEvent = nil;
-    
-    if(parent) {
-        promoteToRetiredEvent = [parent newSubTaskForEvent:@"promoteToRetiredEvent"];
-    }
     
     SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &retiredError);
     if(retiredError){
-        if(promoteToRetiredEvent) {
-            [promoteToRetiredEvent logRecoverableError:(__bridge NSError*)retiredError];
-        }
         secerror("SOSFullPeerInfoPromoteToRetiredAndCopy error: %@", retiredError);
         if(error){
             *error = retiredError;
@@ -1172,9 +1292,6 @@ bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* par
             CFReleaseNull(retiredError);
         }
     }
-    if(promoteToRetiredEvent) {
-        [promoteToRetiredEvent stopWithAttributes:nil];
-    }
 
     if (!retire_peer) {
         secerror("Create ticket failed for peer %@: %@", fpi, localError);
@@ -1186,17 +1303,9 @@ bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* par
         } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) {
             if (SOSCircleUpdatePeerInfo(circle, retire_peer)) {
                 CFErrorRef cleanupError = NULL;
-                SFSignInAnalytics *cleanupEvent = nil;
-
-                if(parent) {
-                    cleanupEvent = [parent newSubTaskForEvent:@"cleanupAfterPeerEvent"];
-                }
                 if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retire_peer err:&cleanupError]) {
                     secerror("Error cleanup up after peer (%@): %@", retire_peer, cleanupError);
                 }
-                if(cleanupEvent) {
-                    [cleanupEvent stopWithAttributes:nil];
-                }
                 CFReleaseSafe(cleanupError);
             }
         }
@@ -1208,46 +1317,22 @@ bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* par
 
         // Write retirement to Transport
         CFErrorRef postError = NULL;
-        SFSignInAnalytics *postRetirementEvent = nil;
-        
-        if(parent) {
-            postRetirementEvent = [parent newSubTaskForEvent:@"postRestirementEvent"];
-        }
-        
         if(![account.circle_transport postRetirement:SOSCircleGetName(circle) peer:retire_peer err:&postError]){
-            if(postRetirementEvent) {
-                [postRetirementEvent logRecoverableError:(__bridge NSError*)postError];
-            }
+
             secwarning("Couldn't post retirement (%@)", postError);
         }
-        if(postRetirementEvent) {
-            [postRetirementEvent stopWithAttributes:nil];
-        }
 
-        SFSignInAnalytics *flushChangesEvent = nil;
-        if(parent) {
-            flushChangesEvent = [parent newSubTaskForEvent:@"flushChangesEvent"];
-        }
+
 
         if(![account.circle_transport flushChanges:&postError]){
-            if(flushChangesEvent) {
-                [flushChangesEvent logRecoverableError:(__bridge NSError*)postError];
-            }
             secwarning("Couldn't flush retirement data (%@)", postError);
         }
-        if(flushChangesEvent) {
-            [flushChangesEvent stopWithAttributes:nil];
-        }
+
         CFReleaseNull(postError);
     }
-    SFSignInAnalytics *purgeIdentityEvent = nil;
-    if(parent) {
-        purgeIdentityEvent = [parent newSubTaskForEvent:@"purgeIdentityEvent"];
-    }
+
     SOSAccountPurgeIdentity(account);
-    if(purgeIdentityEvent) {
-        [purgeIdentityEvent stopWithAttributes:nil];
-    }
+
     retval = true;
 
     CFReleaseNull(retire_peer);
@@ -1345,26 +1430,28 @@ bool SOSAccountRemoveIncompleteiCloudIdentities(SOSAccount*  account, SOSCircleR
 //
 
 
-bool SOSAccountEnsureInBackupRings(SOSAccount*  account) {
+- (bool)_onQueueEnsureInBackupRings {
     __block bool result = false;
     __block CFErrorRef error = NULL;
     secnotice("backup", "Ensuring in rings");
 
-    if(!account.backup_key){
+    dispatch_assert_queue(self.queue);
+
+    if(!self.backup_key){
         return true;
     }
 
-    if(!SOSBSKBIsGoodBackupPublic((__bridge CFDataRef)account.backup_key, &error)){
+    if(!SOSBSKBIsGoodBackupPublic((__bridge CFDataRef)self.backup_key, &error)){
         secnotice("backupkey", "account backup key isn't valid: %@", error);
-        account.backup_key = nil;
+        self.backup_key = nil;
         CFReleaseNull(error);
         return false;
     }
 
-    NSData *peerBackupKey = (__bridge_transfer NSData*)SOSPeerInfoCopyBackupKey(account.peerInfo);
-    if(![peerBackupKey isEqual:account.backup_key]) {
-        result = SOSAccountUpdatePeerInfo(account, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
-            return SOSFullPeerInfoUpdateBackupKey(fpi, (__bridge CFDataRef)(account.backup_key), error);
+    NSData *peerBackupKey = (__bridge_transfer NSData*)SOSPeerInfoCopyBackupKey(self.peerInfo);
+    if(![peerBackupKey isEqual:self.backup_key]) {
+        result = SOSAccountUpdatePeerInfo(self, CFSTR("Backup public key"), &error, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
+            return SOSFullPeerInfoUpdateBackupKey(fpi, (__bridge CFDataRef)(self.backup_key), error);
         });
         if (!result) {
             secnotice("backupkey", "Failed to setup backup public key in peerInfo from account: %@", error);
@@ -1381,12 +1468,12 @@ bool SOSAccountEnsureInBackupRings(SOSAccount*  account) {
     CFReleaseNull(localError);
 
     // Setup backups the new way.
-    SOSAccountForEachBackupView(account, ^(const void *value) {
+    SOSAccountForEachBackupView(self, ^(const void *value) {
         CFStringRef viewName = asString(value, NULL);
-        bool resetRing = SOSAccountValidateBackupRingForView(account, viewName, NULL);
+        bool resetRing = SOSAccountValidateBackupRingForView(self, viewName, NULL);
         if(resetRing) {
-            SOSAccountUpdateBackupRing(account, viewName, NULL, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
-                SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
+            SOSAccountUpdateBackupRing(self, viewName, NULL, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
+                SOSRingRef newRing = SOSAccountCreateBackupRingForView(self, viewName, error);
                 return newRing;
             });
         }
@@ -1436,27 +1523,14 @@ CFDataRef SOSAccountCopyRecoveryPublicKey(SOSAccountTransaction* txn, CFErrorRef
 // MARK: Joining
 //
 
-static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key, bool use_cloud_peer, NSData* parentEvent, CFErrorRef* error) {
+static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key, bool use_cloud_peer, CFErrorRef* error) {
     SOSAccount* account = aTxn.account;
     SOSAccountTrustClassic *trust = account.trust;
     __block bool result = false;
     __block SOSFullPeerInfoRef cloud_full_peer = NULL;
-    SFSignInAnalytics *ensureFullPeerAvailableEvent = nil;
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = nil;
-    
-    if(parentEvent) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
-    }
-
     require_action_quiet(trust.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???")));
-    if(parent) {
-        ensureFullPeerAvailableEvent = [parent newSubTaskForEvent:@"ensureFullPeerAvailableEvent"];
-    }
-    require_quiet([account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)account.gestalt deviceID:(__bridge CFStringRef)account.deviceID backupKey:(__bridge CFDataRef)account.backup_key err:error], fail);
-    if(ensureFullPeerAvailableEvent) {
-        [ensureFullPeerAvailableEvent stopWithAttributes:nil];
-    }
+
+    require_quiet([account.trust ensureFullPeerAvailable: account err:error], fail);
     
     SOSFullPeerInfoRef myCirclePeer = trust.fullPeerInfo;
     if (SOSCircleCountPeers(trust.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) {
@@ -1464,15 +1538,11 @@ static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key
         // this also clears initial sync data
         result = [account.trust resetCircleToOffering:aTxn userKey:user_key err:error];
     } else {
-        SFSignInAnalytics *acceptApplicantEvent = nil;
-
         SOSAccountInitializeInitialSync(account);
         if (use_cloud_peer) {
             cloud_full_peer = SOSCircleCopyiCloudFullPeerInfoRef(trust.trustedCircle, NULL);
         }
-        if(parent) {
-            acceptApplicantEvent = [parent newSubTaskForEvent:@"acceptApplicantEvent"];
-        }
+
         [account.trust modifyCircle:account.circle_transport err:error action:^bool(SOSCircleRef circle) {
             result = SOSAccountAddEscrowToPeerInfo(account, myCirclePeer, error);
             result &= SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error);
@@ -1485,24 +1555,15 @@ static bool SOSAccountJoinCircle(SOSAccountTransaction* aTxn, SecKeyRef user_key
                 require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish);
             finish:
                 if (localError){
-                    if(acceptApplicantEvent) {
-                        [acceptApplicantEvent logRecoverableError:(__bridge NSError *)(localError)];
-                    }
                     secerror("Failed to join with cloud identity: %@", localError);
                     CFReleaseNull(localError);
                 }
             }
             return result;
         }];
-        if(acceptApplicantEvent) {
-            [acceptApplicantEvent stopWithAttributes:nil];
-        }
+
         if (use_cloud_peer) {
             SOSAccountUpdateOutOfSyncViews(aTxn, SOSViewsGetAllCurrent());
-            if(acceptApplicantEvent) {
-                SFSignInAnalytics *updateOutOfDateSyncViewsEvent = [acceptApplicantEvent newSubTaskForEvent:@"updateOutOfDateSyncViewsEvent"];
-                [updateOutOfDateSyncViewsEvent stopWithAttributes:nil];
-            }
         }
     }
 fail:
@@ -1510,7 +1571,7 @@ fail:
     return result;
 }
 
-static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, NSData* parentEvent, CFErrorRef* error) {
+static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use_cloud_identity, CFErrorRef* error) {
     SOSAccount* account = aTxn.account;
     SOSAccountTrustClassic *trust = account.trust;
     bool success = false;
@@ -1548,7 +1609,7 @@ static bool SOSAccountJoinCircles_internal(SOSAccountTransaction* aTxn, bool use
         }
     }
 
-    success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, parentEvent, error);
+    success = SOSAccountJoinCircle(aTxn, user_key, use_cloud_identity, error);
 
     require_quiet(success, done);
 
@@ -1558,37 +1619,29 @@ done:
     return success;
 }
 
-bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) {
+bool SOSAccountJoinCircles(SOSAccountTransaction* aTxn, CFErrorRef* error) {
     secnotice("circleOps", "Normal path circle join (SOSAccountJoinCircles)");
-    return SOSAccountJoinCircles_internal(aTxn, false, parentEvent, error);
+    return SOSAccountJoinCircles_internal(aTxn, false, error);
 }
 
-bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, NSData* parentEvent, CFErrorRef* error) {
+bool SOSAccountJoinCirclesAfterRestore(SOSAccountTransaction* aTxn, CFErrorRef* error) {
     secnotice("circleOps", "Joining after restore (SOSAccountJoinCirclesAfterRestore)");
-    return SOSAccountJoinCircles_internal(aTxn, true, parentEvent, error);
+    return SOSAccountJoinCircles_internal(aTxn, true, error);
 }
 
-bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSData* parentEvent, CFErrorRef* error)
+bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, CFErrorRef* error)
 {
-
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = nil;
-    
-    if(parentEvent) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
-    }
-
     bool result = false;
     CFMutableSetRef peersToRemove = NULL;
     SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error);
-    if(!user_key){
+    if (!user_key) {
         secnotice("circleOps", "Can't remove without userKey");
         return result;
     }
+    
     SOSFullPeerInfoRef me_full = account.fullPeerInfo;
     SOSPeerInfoRef me = account.peerInfo;
-    if(!(me_full && me))
-    {
+    if (!(me_full && me)) {
         secnotice("circleOps", "Can't remove without being active peer");
         SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("Can't remove without being active peer"));
         return result;
@@ -1597,8 +1650,7 @@ bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSD
     result = true; // beyond this point failures would be rolled up in AccountModifyCircle.
 
     peersToRemove = CFSetCreateMutableForSOSPeerInfosByIDWithArray(kCFAllocatorDefault, peers);
-    if(!peersToRemove)
-    {
+    if (!peersToRemove) {
         CFReleaseNull(peersToRemove);
         secnotice("circleOps", "No peerSet to remove");
         return result;
@@ -1611,29 +1663,16 @@ bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSD
     result &= [account.trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) {
         bool success = false;
 
-        if(CFSetGetCount(peersToRemove) != 0) {
+        if (CFSetGetCount(peersToRemove) != 0) {
             require_quiet(SOSCircleRemovePeers(circle, user_key, me_full, peersToRemove, error), done);
-            
-            SFSignInAnalytics *generationSignatureUpdateEvent = nil;
-            if(parent) {
-                generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"];
-            }
-            
             success = SOSAccountGenerationSignatureUpdate(account, error);
-            if(error && *error){
-                NSError* signatureUpdateError = (__bridge NSError*)*error;
-                if(generationSignatureUpdateEvent) {
-                    [generationSignatureUpdateEvent logUnrecoverableError:signatureUpdateError];
-                }
-            }
-            if(generationSignatureUpdateEvent) {
-                [generationSignatureUpdateEvent stopWithAttributes:nil];
-            }
-        } else success = true;
+        } else {
+            success = true;
+        }
 
         if (success && leaveCircle) {
             secnotice("circleOps", "Leaving circle by client request (SOSAccountRemovePeersFromCircle)");
-            success = sosAccountLeaveCircle(account, circle, parentEvent, error);
+            success = sosAccountLeaveCircle(account, circle, error);
         }
 
     done:
@@ -1641,7 +1680,7 @@ bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSD
 
     }];
 
-    if(result) {
+    if (result) {
         CFStringSetPerformWithDescription(peersToRemove, ^(CFStringRef description) {
             secnotice("circleOps", "Removed Peers from circle %@", description);
         });
@@ -1652,7 +1691,7 @@ bool SOSAccountRemovePeersFromCircle(SOSAccount*  account, CFArrayRef peers, NSD
 }
 
 bool SOSAccountBail(SOSAccount*  account, uint64_t limit_in_seconds, CFErrorRef* error) {
-    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+    dispatch_queue_t queue = dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0);
     dispatch_group_t group = dispatch_group_create();
     SOSAccountTrustClassic *trust = account.trust;
     __block bool result = false;
@@ -1661,7 +1700,7 @@ bool SOSAccountBail(SOSAccount*  account, uint64_t limit_in_seconds, CFErrorRef*
     dispatch_group_async(group, queue, ^{
         [trust modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) {
             secnotice("circleOps", "Leaving circle by client request (Bail)");
-            return sosAccountLeaveCircle(account, circle, nil, error);
+            return sosAccountLeaveCircle(account, circle, error);
         }];
     });
     dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, limit_in_seconds * NSEC_PER_SEC);
@@ -1672,7 +1711,6 @@ bool SOSAccountBail(SOSAccount*  account, uint64_t limit_in_seconds, CFErrorRef*
     return result;
 }
 
-
 //
 // MARK: Application
 //
@@ -1806,7 +1844,7 @@ bool SOSAccountEnsurePeerRegistration(SOSAccount*  account, CFErrorRef *error) {
             SOSEngineInitializePeerCoder((SOSEngineRef)[account.kvs_message_transport SOSTransportMessageGetEngine], trust.fullPeerInfo, peer, &localError);
             if (localError)
                 secnotice("updates", "can't initialize transport for peer %@ with %@ (%@)", peer, trust.fullPeerInfo, localError);
-            CFReleaseSafe(localError);
+            CFReleaseNull(localError);
         }
     });
     
@@ -1825,8 +1863,6 @@ CFTypeRef SOSAccountGetValue(SOSAccount*  account, CFStringRef key, CFErrorRef *
     return (__bridge CFTypeRef)([trust.expansion objectForKey:(__bridge NSString* _Nonnull)(key)]);
 }
 
-
-
 bool SOSAccountAddEscrowToPeerInfo(SOSAccount*  account, SOSFullPeerInfoRef myPeer, CFErrorRef *error){
     bool success = false;
     
@@ -1836,13 +1872,16 @@ bool SOSAccountAddEscrowToPeerInfo(SOSAccount*  account, SOSFullPeerInfoRef myPe
     return success;
 }
 
-void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) {
-    if (![account isInCircle:NULL]) {
+- (void)_onQueueRecordRetiredPeersInCircle {
+
+    dispatch_assert_queue(self.queue);
+
+    if (![self isInCircle:NULL]) {
         return;
     }
     __block bool updateRings = false;
-    SOSAccountTrustClassic *trust = account.trust;
-    [trust modifyCircle:account.circle_transport err:NULL action:^bool (SOSCircleRef circle) {
+    SOSAccountTrustClassic *trust = self.trust;
+    [trust modifyCircle:self.circle_transport err:NULL action:^bool (SOSCircleRef circle) {
         __block bool updated = false;
         CFSetForEach((__bridge CFMutableSetRef)trust.retirees, ^(CFTypeRef element){
             SOSPeerInfoRef retiree = asSOSPeerInfo(element);
@@ -1851,7 +1890,7 @@ void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) {
                 updated = true;
                 secnotice("retirement", "Updated retired peer %@ in %@", retiree, circle);
                 CFErrorRef cleanupError = NULL;
-                if (![account.trust cleanupAfterPeer:account.kvs_message_transport circleTransport:account.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retiree err:&cleanupError])
+                if (![self.trust cleanupAfterPeer:self.kvs_message_transport circleTransport:self.circle_transport seconds:RETIREMENT_FINALIZATION_SECONDS circle:circle cleanupPeer:retiree err:&cleanupError])
                     secerror("Error cleanup up after peer (%@): %@", retiree, cleanupError);
                 CFReleaseSafe(cleanupError);
                 updateRings = true;
@@ -1860,7 +1899,7 @@ void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account) {
         return updated;
     }];
     if(updateRings) {
-        SOSAccountProcessBackupRings(account, NULL);
+        SOSAccountProcessBackupRings(self);
     }
 }
 
@@ -1937,7 +1976,7 @@ static void SOSAccountWriteLastCleanupTimestampToKVS(SOSAccount* account)
     
     dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0);
     dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, maxTimeToWaitInSeconds);
-    dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+    dispatch_queue_t processQueue = dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0);
     
     CloudKeychainReplyBlock replyBlock = ^ (CFDictionaryRef returnedValues, CFErrorRef error){
         if (error){
@@ -1965,7 +2004,7 @@ bool SOSAccountCleanupAllKVSKeys(SOSAccount* account, CFErrorRef* error)
         return true;
     }
 
-    dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+    dispatch_queue_t processQueue = dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0);
     
     NSDictionary *keysAndValues = (__bridge_transfer NSDictionary*)SOSAccountGetObjectsFromCloud(processQueue, error);
     NSMutableArray *peerIDs = [NSMutableArray array];
@@ -2014,7 +2053,7 @@ SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount*  account, CFErrorRef* error
     SOSAccountTrustClassic *trust = account.trust;
     SecKeyRef userKey = SOSAccountGetPrivateCredential(account, error);
     if(!userKey) return false;
-    if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error])
+    if(![trust ensureFullPeerAvailable:account err:error])
         return applicant;
     if(!SOSFullPeerInfoPromoteToApplication(trust.fullPeerInfo, userKey, error))
         return applicant;
@@ -2023,6 +2062,36 @@ SOSPeerInfoRef SOSAccountCopyApplication(SOSAccount*  account, CFErrorRef* error
     return applicant;
 }
 
+#if OCTAGON
+static void
+AddStrippedTLKs(NSMutableArray* results, NSArray<CKKSKeychainBackedKey*>* tlks, NSMutableSet *seenUUID, bool authoritative)
+{
+    for(CKKSKeychainBackedKey* tlk in tlks) {
+        NSError* localerror = nil;
+        CKKSAESSIVKey* keyBytes = [tlk ensureKeyLoaded:&localerror];
+
+        if(!keyBytes || localerror) {
+            secnotice("piggy", "Failed to load TLK %@: %@", tlk, localerror);
+            continue;
+        }
+
+        NSMutableDictionary* strippedDown = [@{
+            (id)kSecValueData : [keyBytes keyMaterial],
+            (id)kSecAttrServer : tlk.zoneID.zoneName,
+            (id)kSecAttrAccount : tlk.uuid,
+        } mutableCopy];
+
+        if (authoritative) {
+            strippedDown[@"auth"] = @YES;
+        }
+
+        secnotice("piggy", "sending TLK %@", tlk);
+
+        [results addObject:strippedDown];
+        [seenUUID addObject:tlk.uuid];
+    }
+}
+#endif
 
 static void
 AddStrippedResults(NSMutableArray *results, NSArray *keychainItems, NSMutableSet *seenUUID, bool authoriative)
@@ -2064,34 +2133,32 @@ AddStrippedResults(NSMutableArray *results, NSArray *keychainItems, NSMutableSet
 }
 
 static void
-AddViewManagerResults(NSMutableArray *results, NSMutableSet *seenUUID)
+AddViewManagerResults(NSMutableArray *results, NSMutableSet *seenUUID, bool selectedTLKsOnly)
 {
 #if OCTAGON
-    CKKSViewManager* manager = [CKKSViewManager manager];
-
-    NSDictionary<NSString *,NSString *> *items = [manager activeTLKs];
-
-    for (NSString *view in items) {
-        NSString *uuid = items[view];
-        NSDictionary *query = @{
-            (id)kSecClass : (id)kSecClassInternetPassword,
-            (id)kSecUseDataProtectionKeychain : @YES,
-            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
-            (id)kSecAttrAccount : uuid,
-            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
-            (id)kSecMatchLimit : (id)kSecMatchLimitAll,
-            (id)kSecReturnAttributes: @YES,
-            (id)kSecReturnData: @YES,
-        };
-        CFTypeRef result = NULL;
-        if (SecItemCopyMatching((__bridge CFDictionaryRef)query, &result) == 0) {
-            AddStrippedResults(results, (__bridge NSArray*)result, seenUUID, true);
-        }
-        CFReleaseNull(result);
+    NSError* localError = nil;
+    NSArray<CKKSKeychainBackedKey*>* tlks = [[CKKSViewManager manager] currentTLKsFilteredByPolicy:selectedTLKsOnly error:&localError];
+
+    if(localError) {
+        secnotice("piggy", "unable to fetch TLKs: %@", localError);
+        return;
     }
+
+    AddStrippedTLKs(results, tlks, seenUUID, true);
 #endif
 }
 
+NSArray<NSDictionary *>*
+SOSAccountGetSelectedTLKs(void)
+{
+    NSMutableArray<NSDictionary *>* results = [NSMutableArray array];
+    NSMutableSet *seenUUID = [NSMutableSet set];
+
+    AddViewManagerResults(results, seenUUID, true);
+
+    return results;
+}
+
 
 NSArray<NSDictionary *>*
 SOSAccountGetAllTLKs(void)
@@ -2100,8 +2167,8 @@ SOSAccountGetAllTLKs(void)
     NSMutableArray<NSDictionary *>* results = [NSMutableArray array];
     NSMutableSet *seenUUID = [NSMutableSet set];
 
-    // first use the TLK from the view manager
-    AddViewManagerResults(results, seenUUID);
+    // first use all TLKs from the view manager
+    AddViewManagerResults(results, seenUUID, false);
 
     //try to grab tlk-piggy items
     NSDictionary* query = @{
@@ -2386,22 +2453,27 @@ CFDataRef SOSAccountCopyInitialSyncData(SOSAccount* account, SOSInitialSyncFlags
     NSMutableArray<NSData *>* encodedIdenities = [NSMutableArray array];
     NSArray<NSDictionary *>* 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];
+    if (flags & kSOSInitialSyncFlagTLKsRequestOnly) {
+        tlks = SOSAccountGetSelectedTLKs();
+    } else {
+        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);
         }
-        CFRelease(identities);
-    }
 
-    if (flags & kSOSInitialSyncFlagTLKs) {
-        tlks = SOSAccountGetAllTLKs();
+
+        if (flags & kSOSInitialSyncFlagTLKs) {
+            tlks = SOSAccountGetAllTLKs();
+        }
     }
 
     return CFBridgingRetain(SOSPiggyCreateInitialSyncData(encodedIdenities, tlks));
@@ -2552,10 +2624,10 @@ void SOSAccountLogState(SOSAccount*  account) {
 
     secnotice(ACCOUNTLOGSTATE, "Start");
 
-    secnotice(ACCOUNTLOGSTATE, "ACCOUNT: [keyStatus: %c%c%c hpub %@] [SOSCCStatus: %@]",
+    secnotice(ACCOUNTLOGSTATE, "ACCOUNT: [keyStatus: %c%c%c hpub %@] [SOSCCStatus: %@] [UID: %d  EUID: %d]",
               boolToChars(hasPubKey, 'U', 'u'), boolToChars(pubTrusted, 'T', 't'), boolToChars(hasPriv, 'I', 'i'),
               userPubKeyID,
-              SOSAccountGetSOSCCStatusString(stat)
+              SOSAccountGetSOSCCStatusString(stat), getuid(), geteuid()
               );
     CFReleaseNull(userPubKeyID);
     if(trust.trustedCircle)  SOSCircleLogState(ACCOUNTLOGSTATE, trust.trustedCircle, account.accountKey, (__bridge CFStringRef)(account.peerID));
@@ -2601,7 +2673,6 @@ void SOSAccountResetOTRNegotiationCoder(SOSAccount* account, CFStringRef peerid)
 {
     secnotice("otrtimer", "timer fired!");
     CFErrorRef error = NULL;
-    SecADAddValueForScalarKey((__bridge CFStringRef) SecSOSAggdReattemptOTRNegotiation,1);
 
     SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account.factory, SOSCircleGetName(account.trust.trustedCircle), NULL);
     SOSEngineWithPeerID(engine, peerid, &error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *forceSaveState) {
@@ -2674,10 +2745,12 @@ void SOSAccountTimerFiredSendNextMessage(SOSAccountTransaction* txn, NSString* p
  */
 
 OctagonFlag* SOSFlagTriggerBackup = (OctagonFlag*)@"trigger_backup";
+OctagonFlag* SOSFlagTriggerRingUpdate = (OctagonFlag*)@"trigger_ring_update";
 
 OctagonState* SOSStateReady = (OctagonState*)@"ready";
 OctagonState* SOSStateError = (OctagonState*)@"error";
 OctagonState* SOSStatePerformBackup = (OctagonState*)@"perform_backup";
+OctagonState* SOSStatePerformRingUpdate = (OctagonState*)@"perform_ring_update";
 
 static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void) {
     static NSDictionary<OctagonState*, NSNumber*>* map = nil;
@@ -2687,6 +2760,7 @@ static NSDictionary<OctagonState*, NSNumber*>* SOSStateMap(void) {
             SOSStateReady:                              @0U,
             SOSStateError:                              @1U,
             SOSStatePerformBackup:                      @2U,
+            SOSStatePerformRingUpdate:                  @3U,
         };
     });
     return map;
@@ -2697,7 +2771,8 @@ static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         set = [NSSet setWithArray:@[
-            SOSFlagTriggerBackup
+            SOSFlagTriggerBackup,
+            SOSFlagTriggerRingUpdate,
         ]];
     });
     return set;
@@ -2706,7 +2781,7 @@ static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
 
 
 + (NSURL *)urlForSOSAccountSettings {
-    return (__bridge NSURL *)SecCopyURLForFileInKeychainDirectory(CFSTR("SOSAccountSettings.pb"));
+    return (__bridge_transfer NSURL *)SecCopyURLForFileInKeychainDirectory(CFSTR("SOSAccountSettings.pb"));
 }
 
 
@@ -2714,9 +2789,9 @@ static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
     WEAKIFY(self);
 
     self.accountConfiguration = [[CKKSPBFileStorage alloc] initWithStoragePath:[[self class] urlForSOSAccountSettings]
-                                                                   storageClass:[SOSAccountConfiguration class]];
+                                                                  storageClass:[SOSAccountConfiguration class]];
 
-    NSAssert(self.stateMachine == nil, @"cant bootstrap more the once");
+    NSAssert(self.stateMachine == nil, @"can't bootstrap more than once");
 
     self.stateMachineQueue = dispatch_queue_create("SOS-statemachine", NULL);
 
@@ -2739,50 +2814,155 @@ static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
         [self addBackupFlag];
     }];
 
+    self.performRingUpdates = [[CKKSNearFutureScheduler alloc] initWithName:@"performRingUpdates"
+                                                               initialDelay:5*NSEC_PER_SEC
+                                                           expontialBackoff:2.0
+                                                               maximumDelay:15*60*NSEC_PER_SEC
+                                                           keepProcessAlive:YES
+                                                  dependencyDescriptionCode:CKKSResultDescriptionNone
+                                                                      block:^{
+        STRONGIFY(self);
+        [self addRingUpdateFlag];
+    }];
+
     SOSAccountConfiguration *conf = self.accountConfiguration.storage;
 
     if (conf.pendingBackupPeers.count) {
         [self addBackupFlag];
     }
-
-    [self.stateMachine startOperation];
+    if (conf.ringUpdateFlag) {
+        [self addRingUpdateFlag];
+    }
 }
 
 
+/*
+ * Flag adding to state machine
+ */
+
 - (void)addBackupFlag {
     OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:SOSFlagTriggerBackup
                                                                     conditions:OctagonPendingConditionsDeviceUnlocked];
     [self.stateMachine handlePendingFlag:pendingFlag];
 }
 
+- (void)addRingUpdateFlag {
+    OctagonPendingFlag *pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:SOSFlagTriggerRingUpdate
+                                                                    conditions:OctagonPendingConditionsDeviceUnlocked];
+    [self.stateMachine handlePendingFlag:pendingFlag];
+}
+
+//Mark: -- Set up state for state machine
+
+
 - (void)triggerBackupForPeers:(NSArray<NSString*>*)backupPeers
 {
-    dispatch_sync(self.stateMachineQueue, ^{
+    NSMutableSet *pending = [NSMutableSet set];
+    if (backupPeers) {
+        [pending addObjectsFromArray:backupPeers];
+    }
+
+    WEAKIFY(self);
+    dispatch_async(self.stateMachineQueue, ^{
+        STRONGIFY(self);
+
         SOSAccountConfiguration *storage = self.accountConfiguration.storage;
 
-        NSMutableSet *pending = [NSMutableSet set];
         if (storage.pendingBackupPeers) {
             [pending addObjectsFromArray:storage.pendingBackupPeers];
         }
-        if (backupPeers) {
-            [pending addObjectsFromArray:backupPeers];
-        }
         storage.pendingBackupPeers = [[pending allObjects] mutableCopy];
         [self.accountConfiguration setStorage:storage];
         [self.performBackups trigger];
-        secnotice("sos-sm", "trigger backup for peers: %@", backupPeers);
+        secnotice("sos-sm", "trigger backup for peers: %@ at %@",
+                  backupPeers, self.performBackups.nextFireTime);
     });
 }
 
+- (void)triggerRingUpdate
+{
+    WEAKIFY(self);
+    dispatch_async(self.stateMachineQueue, ^{
+        STRONGIFY(self);
+        SOSAccountConfiguration *storage = self.accountConfiguration.storage;
+        storage.ringUpdateFlag = YES;
+        [self.accountConfiguration setStorage:storage];
+        [self.performRingUpdates trigger];
+        secnotice("sos-sm", "trigger ring update at %@",
+                  self.performRingUpdates.nextFireTime);
+    });
+}
+
+//Mark: -- State machine and opertions
+
+- (OctagonStateTransitionOperation *)performBackup {
+
+    WEAKIFY(self);
+    return [OctagonStateTransitionOperation named:@"perform-backup-state"
+                                        intending:SOSStateReady
+                                       errorState:SOSStateError
+                              withBlockTakingSelf:^void(OctagonStateTransitionOperation * _Nonnull op) {
+        STRONGIFY(self);
+        SOSAccountConfiguration *storage = self.accountConfiguration.storage;
+
+        secnotice("sos-sm", "performing backup for %@", storage.pendingBackupPeers);
+
+        if (storage.pendingBackupPeers.count) {
+            SOSCCRequestSyncWithBackupPeerList((__bridge CFArrayRef)storage.pendingBackupPeers);
+            [storage clearPendingBackupPeers];
+        }
+        [self.accountConfiguration setStorage:storage];
+
+        op.nextState = SOSStateReady;
+    }];
+}
+
+- (OctagonStateTransitionOperation *)performRingUpdate {
+
+    WEAKIFY(self);
+    return [OctagonStateTransitionOperation named:@"perform-ring-update"
+                                        intending:SOSStateReady
+                                       errorState:SOSStateError
+                              withBlockTakingSelf:^void(OctagonStateTransitionOperation * _Nonnull op) {
+        STRONGIFY(self);
+
+        SOSAccountConfiguration *storage = self.accountConfiguration.storage;
+        storage.ringUpdateFlag = NO;
+        [self.accountConfiguration setStorage:storage];
+
+        [self performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
+            if([self accountKeyIsTrusted] && [self isInCircle:NULL]) {
+
+                [self _onQueueRecordRetiredPeersInCircle];
+
+                SOSAccountEnsureRecoveryRing(self);
+                [self _onQueueEnsureInBackupRings];
+
+                CFErrorRef localError = NULL;
+                if(![self.circle_transport flushChanges:&localError]){
+                    secerror("flush circle failed %@", localError);
+                }
+                CFReleaseNull(localError);
+
+                if(!SecCKKSTestDisableSOS()) {
+                    SOSAccountNotifyEngines(self);
+                }
+            }
+        }];
+
+        op.nextState = SOSStateReady;
+    }];
+
+}
+
+
 - (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueNextStateMachineTransition:(OctagonState*)currentState
                                                                                                         flags:(nonnull OctagonFlags *)flags
                                                                                                  pendingFlags:(nonnull id<OctagonStateOnqueuePendingFlagHandler>)pendingFlagHandler
 {
     dispatch_assert_queue(self.stateMachineQueue);
 
-    WEAKIFY(self);
-
-    secnotice("sos-sm", "currentState: %@ [flags: %@]", currentState, flags);
+    secnotice("sos-sm", "Entering state: %@ [flags: %@]", currentState, flags);
 
     if ([currentState isEqualToString:SOSStateReady]) {
         if([flags _onqueueContains:SOSFlagTriggerBackup]) {
@@ -2790,30 +2970,21 @@ static NSSet<OctagonFlag*>* SOSFlagsSet(void) {
             return [OctagonStateTransitionOperation named:@"perform-backup-flag"
                                                  entering:SOSStatePerformBackup];
         }
-        secnotice("sos-sm", "Entering state ready");
+
+        if ([flags _onqueueContains:SOSFlagTriggerRingUpdate]) {
+            [flags _onqueueRemoveFlag:SOSFlagTriggerRingUpdate];
+            return [OctagonStateTransitionOperation named:@"perform-ring-update-flag"
+                                                 entering:SOSStatePerformRingUpdate];
+        }
         return nil;
+
     } else if ([currentState isEqualToString:SOSStateError]) {
-        secnotice("sos-sm", "Entering state error");
         return nil;
-    } else if ([currentState isEqualToString:SOSStatePerformBackup]) {
-
-        return [OctagonStateTransitionOperation named:@"perform-backup-state"
-                                            intending:SOSStateReady
-                                           errorState:SOSStateError
-                                  withBlockTakingSelf:^void(OctagonStateTransitionOperation * _Nonnull op) {
-            STRONGIFY(self);
-            SOSAccountConfiguration *storage = self.accountConfiguration.storage;
-
-            secnotice("sos-sm", "performing backup for %@", storage.pendingBackupPeers);
+    } else if ([currentState isEqualToString:SOSStatePerformRingUpdate]) {
+        return [self performRingUpdate];
 
-            if (storage.pendingBackupPeers.count) {
-                SOSCCRequestSyncWithBackupPeerList((__bridge CFArrayRef)storage.pendingBackupPeers);
-                [storage clearPendingBackupPeers];
-            }
-            [self.accountConfiguration setStorage:storage];
-
-            op.nextState = SOSStateReady;
-        }];
+    } else if ([currentState isEqualToString:SOSStatePerformBackup]) {
+        return [self performBackup];
     }
 
     return nil;
index 17c724d5b63a762654f01034aefa5719fbc65196..c9f52dc39964466362664267f036348660c48a5a 100644 (file)
@@ -458,13 +458,18 @@ SOSRingRef SOSAccountCreateBackupRingForView(SOSAccount* account, CFStringRef ri
     return newRing;
 }
 
-void SOSAccountProcessBackupRings(SOSAccount*  account, CFErrorRef *error) {
+void SOSAccountProcessBackupRings(SOSAccount*  account) {
     SOSAccountForEachBackupView(account, ^(const void *value) {
+        CFErrorRef localError = NULL;
         CFStringRef viewName = (CFStringRef)value;
-        SOSAccountUpdateBackupRing(account, viewName, error, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
+        SOSAccountUpdateBackupRing(account, viewName, &localError, ^SOSRingRef(SOSRingRef existing, CFErrorRef *error) {
             SOSRingRef newRing = SOSAccountCreateBackupRingForView(account, viewName, error);
             return newRing;
         });
+        if(localError) {
+            secnotice("ring", "Error during SOSAccountProcessBackupRings (%@)", localError);
+            CFReleaseNull(localError);
+        }
     });
 }
 
@@ -524,7 +529,9 @@ bool SOSAccountSetBackupPublicKey(SOSAccountTransaction* aTxn, CFDataRef cfBacku
     })){
         return result;
     }
-    SOSAccountProcessBackupRings(account, NULL);
+    SOSAccountProcessBackupRings(account);
+    account.need_backup_peers_created_after_backup_key_set = true;
+    account.circle_rings_retirements_need_attention = true;
     return true;
 
 }
index 9da7355ed5366e62379b83ab6d7d49c414f4b07e..ae1f9b91de4c6e2e34bdc43953855c4564703c97 100644 (file)
@@ -30,14 +30,14 @@ static uint8_t* der_encode_cloud_parameters(SecKeyRef publicKey, CFDataRef param
 
 const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator,
                                                   CFIndex algorithmID, SecKeyRef* publicKey,
-                                                  CFDataRef *parameters,
+                                                  CFDataRef *pbkdfParams,
                                                   CFErrorRef* error,
                                                   const uint8_t* der, const uint8_t* der_end)
 {
     const uint8_t *sequence_end;
     der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
     der = der_decode_public_bytes(allocator, algorithmID, publicKey, error, der, sequence_end);
-    der = der_decode_data_or_null(allocator, parameters, error, der, sequence_end);
+    der = der_decode_data_or_null(allocator, pbkdfParams, error, der, sequence_end);
     
     return der;
 }
@@ -46,12 +46,12 @@ const uint8_t* der_decode_cloud_parameters(CFAllocatorRef allocator,
 bool SOSAccountPublishCloudParameters(SOSAccount* account, CFErrorRef* error){
     bool success = false;
     CFIndex cloud_der_len = der_sizeof_cloud_parameters(account.accountKey,
-                                                        (__bridge CFDataRef)(account.accountKeyDerivationParamters),
+                                                        (__bridge CFDataRef)(account.accountKeyDerivationParameters),
                                                         error);
 
     CFMutableDataRef cloudParameters = CFDataCreateMutableWithScratch(kCFAllocatorDefault, cloud_der_len);
     
-    if (der_encode_cloud_parameters(account.accountKey, (__bridge CFDataRef)(account.accountKeyDerivationParamters), error,
+    if (der_encode_cloud_parameters(account.accountKey, (__bridge CFDataRef)(account.accountKeyDerivationParameters), error,
                                     CFDataGetMutableBytePtr(cloudParameters),
                                     CFDataGetMutablePastEndPtr(cloudParameters)) != NULL) {
 
@@ -75,9 +75,9 @@ bool SOSAccountPublishCloudParameters(SOSAccount* account, CFErrorRef* error){
 
 bool SOSAccountRetrieveCloudParameters(SOSAccount* account, SecKeyRef *newKey,
                                        CFDataRef derparms,
-                                       CFDataRef *newParameters, CFErrorRef* error) {
+                                       CFDataRef *pbkdfParams, CFErrorRef* error) {
     const uint8_t *parse_end = der_decode_cloud_parameters(kCFAllocatorDefault, kSecECDSAAlgorithmID,
-                                                           newKey, newParameters, error,
+                                                           newKey, pbkdfParams, error,
                                                            CFDataGetBytePtr(derparms), CFDataGetPastEndPtr(derparms));
     
     if (parse_end == CFDataGetPastEndPtr(derparms)) return true;
index 8bba993c0d7917696448e3ac20e1c24eafb7e787..bb26993a25e8223d2d13c1b64582d8bf06f00fd4 100644 (file)
@@ -8,4 +8,5 @@ package SOS;
 
 message AccountConfiguration {
     repeated string pendingBackupPeers = 1;
+    optional bool ringUpdateFlag = 2;
 }
index efe750702edf085e9865f36b33aad181d03593b7..4297b789a92106b145315330bae63037343fb56e 100644 (file)
@@ -111,7 +111,9 @@ static void SOSAccountSetTrustedUserPublicKey(SOSAccount* account, bool public_w
 
     CFReleaseNull(publicKey);
 
-       secnotice("circleOps", "trusting new public key: %@", account.accountKey);
+    CFStringRef keyid = SOSCopyIDOfKeyWithLength(account.accountKey, 8, NULL);
+       secnotice("circleOps", "trusting new public key: %@", keyid);
+    CFReleaseNull(keyid);
     notify_post(kPublicKeyAvailable);
 }
 
@@ -127,8 +129,9 @@ void SOSAccountSetUnTrustedUserPublicKey(SOSAccount* account, SecKeyRef publicKe
     if(!account.previousAccountKey) {
         account.previousAccountKey = account.accountKey;
     }
-    
-    secnotice("circleOps", "not trusting new public key: %@", account.accountKey);
+    CFStringRef keyid = SOSCopyIDOfKeyWithLength(account.accountKey, 8, NULL);
+    secnotice("circleOps", "not trusting new public key: %@", keyid);
+    CFReleaseNull(keyid);
 }
 
 
@@ -310,8 +313,8 @@ static void sosAccountSetTrustedCredentials(SOSAccount* account, CFDataRef user_
 
 static SecKeyRef sosAccountCreateKeyIfPasswordIsCorrect(SOSAccount* account, CFDataRef user_password, CFErrorRef *error) {
     SecKeyRef user_private = NULL;
-    require_quiet(account.accountKey && account.accountKeyDerivationParamters, errOut);
-    user_private = SOSUserKeygen(user_password, (__bridge CFDataRef)(account.accountKeyDerivationParamters), error);
+    require_quiet(account.accountKey && account.accountKeyDerivationParameters, errOut);
+    user_private = SOSUserKeygen(user_password, (__bridge CFDataRef)(account.accountKeyDerivationParameters), error);
     require_quiet(user_private, errOut);
 
     require_action_quiet(SOSAccountValidateAccountCredential(account, user_private, error), errOut, CFReleaseNull(user_private));
@@ -322,7 +325,21 @@ errOut:
 static bool sosAccountValidatePasswordOrFail(SOSAccount* account, CFDataRef user_password, CFErrorRef *error) {
     SecKeyRef privKey = sosAccountCreateKeyIfPasswordIsCorrect(account, user_password, error);
     if(!privKey) {
-        if(account.accountKeyDerivationParamters) debugDumpUserParameters(CFSTR("sosAccountValidatePasswordOrFail"), (__bridge CFDataRef)(account.accountKeyDerivationParamters));
+        if(account.accountKeyDerivationParameters) {
+            SecKeyRef newKey = NULL;
+            CFDataRef pbkdfParams = NULL;
+            CFErrorRef localError = NULL;
+            if(SOSAccountRetrieveCloudParameters(account, &newKey, (__bridge CFDataRef)(account.accountKeyDerivationParameters), &pbkdfParams, &localError)) {
+                debugDumpUserParameters(CFSTR("sosAccountValidatePasswordOrFail"), pbkdfParams);
+            } else {
+                secnotice("circleOps", "Failed to retrieve cloud parameters - %@", localError);
+                if(error) {
+                    CFTransferRetained(*error, localError);
+                }
+            }
+            CFReleaseNull(newKey);
+            CFReleaseNull(pbkdfParams);
+        }
         SOSCreateError(kSOSErrorWrongPassword, CFSTR("Could not create correct key with password."), NULL, error);
         return false;
     }
@@ -332,7 +349,7 @@ static bool sosAccountValidatePasswordOrFail(SOSAccount* account, CFDataRef user
 }
 
 void SOSAccountSetParameters(SOSAccount* account, CFDataRef parameters) {
-    account.accountKeyDerivationParamters = (__bridge NSData *) parameters;
+    account.accountKeyDerivationParameters = (__bridge NSData *) parameters;
 }
 
 bool SOSAccountValidateAccountCredential(SOSAccount* account, SecKeyRef accountPrivateKey, CFErrorRef *error)
@@ -347,7 +364,7 @@ bool SOSAccountValidateAccountCredential(SOSAccount* account, SecKeyRef accountP
         CFStringRef accountHpub = SOSCopyIDOfKey(account.accountKey, NULL);
         CFStringRef candidateHpub = SOSCopyIDOfKey(publicCandidate, NULL);
         SOSCreateErrorWithFormat(kSOSErrorWrongPassword, NULL, &localError, NULL, CFSTR("Password generated pubkey doesn't match - candidate: %@  known: %@"), candidateHpub, accountHpub);
-        secnotice("circleop", "%@", localError);
+        secnotice("circleop", "Password generated pubkey doesn't match - candidate: %@  known: %@", candidateHpub, accountHpub);
         if (error) {
             *error = localError;
             localError = NULL;
index 834c75d7dca829e671eadbba8815a9997d268d70..100433b1d83e9628f3a51a6493910b5c718afee5 100644 (file)
@@ -39,15 +39,11 @@ static CFStringRef kicloud_identity_name = CFSTR("Cloud Identity");
 
 SecKeyRef SOSAccountCopyDeviceKey(SOSAccount* account, CFErrorRef *error) {
     SecKeyRef privateKey = NULL;
-    SOSFullPeerInfoRef identity = NULL;
-
-    SOSAccountTrustClassic *trust = account.trust;
-    identity = trust.fullPeerInfo;
-    require_action_quiet(identity, fail, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from")));
-
-    privateKey = SOSFullPeerInfoCopyDeviceKey(identity, error);
-
-fail:
+    if(account.peerPublicKey) {
+        privateKey = SecKeyCopyMatchingPrivateKey(account.peerPublicKey, error);
+    } else {
+        SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("No identity to get key from"));
+    }
     return privateKey;
 }
 
@@ -59,13 +55,13 @@ SOSFullPeerInfoRef CopyCloudKeychainIdentity(SOSPeerInfoRef cloudPeer, CFErrorRe
 static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey_internal(int keySize, CFStringRef name, CFTypeRef accessibility, CFBooleanRef sync,  CFErrorRef* error)
 {
     SecKeyRef full_key = NULL;
-    
+
     CFNumberRef key_size_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &keySize);
-    
+
     CFDictionaryRef priv_key_attrs = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                                                   kSecAttrIsPermanent,    kCFBooleanTrue,
                                                                   NULL);
-    
+
     CFDictionaryRef keygen_parameters = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
                                                                      kSecAttrKeyType,        kSecAttrKeyTypeEC,
                                                                      kSecAttrKeySizeInBits,  key_size_num,
@@ -76,19 +72,19 @@ static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKey_internal(int key
                                                                      kSecAttrSynchronizable, sync,
                                                                      kSecUseTombstones,      kCFBooleanTrue,
                                                                      NULL);
-    
+
     CFReleaseNull(priv_key_attrs);
-    
+
     CFReleaseNull(key_size_num);
     OSStatus status = SecKeyGeneratePair(keygen_parameters, NULL, &full_key);
     CFReleaseNull(keygen_parameters);
-    
+
     if (status)
         secerror("status: %ld", (long)status);
     if (status != errSecSuccess && error != NULL && *error == NULL) {
         *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
     }
-    
+
     return full_key;
 }
 
@@ -100,6 +96,69 @@ static CF_RETURNS_RETAINED SecKeyRef GeneratePermanentFullECKeyForCloudIdentity(
     return GeneratePermanentFullECKey_internal(keySize, name, kSecAttrAccessibleWhenUnlocked, kCFBooleanTrue, error);
 }
 
+static SecKeyRef sosKeyForLabel(CFStringRef label) {
+    CFTypeRef queryResult = NULL;
+    SecKeyRef retval = NULL;
+    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+        kSecMatchLimit,            kSecMatchLimitOne,
+        kSecClass,                 kSecClassKey,
+        kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
+        kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
+        kSecAttrAccessGroup,       kSOSInternalAccessGroup,
+        kSecAttrLabel,              label,
+        kSecReturnRef,             kCFBooleanTrue,
+        NULL);
+    OSStatus stat = SecItemCopyMatching(query, &queryResult);
+    if(errSecSuccess == stat) {
+        retval = (SecKeyRef) queryResult;
+        secnotice("iCloudIdentity", "Got key for label (%@)", label);
+    } else {
+        secnotice("iCloudIdentity", "Failed query(%d) for %@", (int) stat, label);
+    }
+    CFReleaseNull(query);
+    return retval;
+}
+
+void SOSiCloudIdentityPrivateKeyForEach(void (^complete)(SecKeyRef privKey)) {
+    CFTypeRef queryResult = NULL;
+    CFArrayRef iCloudPrivKeys = NULL;
+
+    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+        kSecMatchLimit,            kSecMatchLimitAll,
+        kSecClass,                 kSecClassKey,
+        kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
+        kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
+        kSecAttrAccessGroup,       kSOSInternalAccessGroup,
+        kSecReturnAttributes,      kCFBooleanTrue,
+        NULL);
+
+    if((errSecSuccess == SecItemCopyMatching(query, &queryResult)) && (iCloudPrivKeys = asArray(queryResult, NULL))) {
+        secnotice("iCloudIdentity", "Screening %ld icloud private key candidates", (long)CFArrayGetCount(iCloudPrivKeys));
+        CFReleaseNull(query);
+    } else {
+        secnotice("iCloudIdentity", "Can't get iCloud Identity private key candidates");
+        CFReleaseNull(query);
+        CFReleaseNull(queryResult);
+        return;
+    }
+
+    CFArrayForEach(iCloudPrivKeys, ^(const void *value) {
+        CFDictionaryRef privKeyDict = (CFDictionaryRef) value;
+        CFStringRef label = CFDictionaryGetValue(privKeyDict, kSecAttrLabel);
+        if(!label) {
+            return;
+        }
+        if(CFStringHasPrefix(label, CFSTR("Cloud Identity"))) {
+            SecKeyRef privKey = sosKeyForLabel(label);
+            if(privKey) {
+                complete(privKey);
+                CFReleaseNull(privKey);
+            }
+        }
+    });
+    CFReleaseNull(queryResult);
+}
+
 bool SOSAccountHasCircle(SOSAccount* account, CFErrorRef* error) {
     SOSAccountTrustClassic *trust = account.trust;
     SOSCircleRef circle = trust.trustedCircle;
index f8de69c2c5efa1ae7b374284f938f46eeb63b6e5..6a65ebf526783b8f87b04a11054a9cf6131df163 100644 (file)
@@ -18,6 +18,7 @@
 #include "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
 #include "keychain/SecureObjectSync/SOSAuthKitHelpers.h"
 #import "Analytics/Clients/SOSAnalytics.h"
+#import <Security/SecBase64.h>
 #include "utilities/SecTrace.h"
 
 
@@ -32,9 +33,9 @@ static bool sosGhostCheckValid(SOSPeerInfoRef pi) {
         case SOSPeerInfo_iOS:
         case SOSPeerInfo_tvOS:
         case SOSPeerInfo_watchOS:
-        case SOSPeerInfo_macOS:
             retval = true;
             break;
+        case SOSPeerInfo_macOS: // go back and quit killing macos ghosts so people can multi-boot
         case SOSPeerInfo_iCloud:
         case SOSPeerInfo_unknown:
         default:
@@ -140,28 +141,27 @@ static NSUInteger SOSGhostBustThinSerialClones(SOSCircleRef circle, NSString *my
 
     for(CFIndex i = CFArrayGetCount(sortPeers); i > 0; i--) {
         SOSPeerInfoRef pi = (SOSPeerInfoRef) CFArrayGetValueAtIndex(sortPeers, i-1);
-        
-        if(sosGhostCheckValid(pi)) {
+        NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(pi);
+
+        if(![peerID isEqualToString: myPeerID] && sosGhostCheckValid(pi)) {
             NSString *serial = CFBridgingRelease(SOSPeerInfoV2DictionaryCopyString(pi, sSerialNumberKey));
-            NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(pi);
             if(serial != nil) {
                 if([latestPeers objectForKey:serial] != nil) {
-                    if(peerID != myPeerID) {
-                        [removals addObject:peerID];
-                    } else {
-                        secnotice("ghostBust", "There is a more recent peer for this serial number");
-                    }
+                    secnotice("ghostBust", "There is a more recent peer than %@ for this serial number", SOSPeerInfoGetSPID(pi));
+                    [removals addObject:peerID];
                 } else {
                     [latestPeers setObject:peerID forKey:serial];
                 }
             } else {
-                secnotice("ghostBust", "Removing peerID (%@) with no serial number", peerID);
+                secnotice("ghostBust", "Removing peerID (%@) with no serial number", SOSPeerInfoGetSPID(pi));
                 [removals addObject:peerID];
             }
         }
     }
-    SOSCircleRemovePeersByIDUnsigned(circle, (__bridge CFSetRef)(removals));
     gbcount = [removals count];
+    if(gbcount > 0) {
+        SOSCircleRemovePeersByIDUnsigned(circle, (__bridge CFSetRef)(removals));
+    }
     CFReleaseNull(sortPeers);
     return gbcount;
 }
@@ -175,6 +175,42 @@ static void SOSCircleRemoveiCloudIdentities(SOSCircleRef circle) {
     SOSCircleRemovePeersByIDUnsigned(circle, (__bridge CFSetRef)(removals));
 }
 
+// this is only used to determine if we have a circle that can't accept new peers because of ghosts.
+static void SOSCircleRemoveWindowsPeers(SOSCircleRef circle) {
+    NSMutableSet *removals = [[NSMutableSet alloc] init];
+    SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
+        NSString *devType = (__bridge NSString *)SOSPeerInfoGetPeerDeviceType(peer);
+        if([devType hasPrefix: @"Windows"]) {
+            NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peer);
+            [removals addObject:peerID];
+        }
+    });
+    SOSCircleRemovePeersByIDUnsigned(circle, (__bridge CFSetRef)(removals));
+}
+
+static void SOSCircleRemovePeersNotInMidlist(SOSCircleRef circle) {
+    __block SOSAuthKitHelpers *akh = nil;
+
+    if([SOSAuthKitHelpers accountIsHSA2]) {
+        [SOSAuthKitHelpers activeMIDs:^(NSSet <SOSTrustedDeviceAttributes *> * _Nullable activeMIDs, NSError * _Nullable error) {
+            akh = [[SOSAuthKitHelpers alloc] initWithActiveMIDS:activeMIDs];
+        }];
+    }
+    
+    NSMutableSet *removals = [[NSMutableSet alloc] init];
+    if(akh) {
+        SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
+            NSString *mid = CFBridgingRelease(SOSPeerInfoV2DictionaryCopyString(peer, sMachineIDKey));
+            if(![akh midIsValidInList:mid]) {
+                NSString *peerID = (__bridge NSString *)SOSPeerInfoGetPeerID(peer);
+                [removals addObject:peerID];
+            }
+        });
+        SOSCircleRemovePeersByIDUnsigned(circle, (__bridge CFSetRef)(removals));
+    }
+}
+
+
 bool SOSAccountGhostResultsInReset(SOSAccount* account) {
     if(!account.peerID || !account.trust.trustedCircle) return false;
     SOSCircleRef newCircle = SOSCircleCopyCircle(kCFAllocatorDefault, account.trust.trustedCircle, NULL);
@@ -182,6 +218,8 @@ bool SOSAccountGhostResultsInReset(SOSAccount* account) {
     SOSCircleClearMyGhosts(newCircle, account.peerInfo);
     SOSCircleRemoveRetired(newCircle, NULL);
     SOSCircleRemoveiCloudIdentities(newCircle);
+    SOSCircleRemoveWindowsPeers(newCircle);
+    SOSCircleRemovePeersNotInMidlist(newCircle);
     int npeers = SOSCircleCountPeers(newCircle);
     CFReleaseNull(newCircle);
     return npeers == 0;
@@ -200,6 +238,7 @@ static NSUInteger SOSGhostBustThinByMIDList(SOSCircleRef circle, NSString *myPee
         if(options & SOSGhostBustByMID) {
             NSString *mid = CFBridgingRelease(SOSPeerInfoV2DictionaryCopyString(peer, sMachineIDKey));
             if(![akh midIsValidInList:mid]) {
+                secnotice("ghostBust", "Removing peerInfo %@ - mid is not in list", SOSPeerInfoGetSPID(peer));
                 [removals addObject:peerID];
                 gbmid++;
                 return;
@@ -208,6 +247,7 @@ static NSUInteger SOSGhostBustThinByMIDList(SOSCircleRef circle, NSString *myPee
         if(options & SOSGhostBustBySerialNumber) {
             NSString *serial = CFBridgingRelease(SOSPeerInfoV2DictionaryCopyString(peer, sSerialNumberKey));
             if(![akh serialIsValidInList: serial]) {
+                secnotice("ghostBust", "Removing peerInfo %@ - serial# is not in list", SOSPeerInfoGetSPID(peer));
                 [removals addObject:peerID];
                 gbserial++;
                 return;
@@ -222,92 +262,86 @@ static NSUInteger SOSGhostBustThinByMIDList(SOSCircleRef circle, NSString *myPee
     return [removals count];
 }
 
-static bool SOSGhostBustiCloudIdentityPrivateKeys(SOSAccount *account) {
-    __block bool cleaned = false;
-    SecKeyRef pubKey = NULL;
-    CFTypeRef queryResult = NULL;
-    CFDataRef pubKeyHash = NULL;
-    CFDictionaryRef query = NULL;
-    __block int removed = 0;
-
-    SOSFullPeerInfoRef iCloudIdentity = SOSCircleCopyiCloudFullPeerInfoVerifier(account.trust.trustedCircle, NULL);
-    require_action_quiet(iCloudIdentity, retOut, secnotice("ghostBust", "No iCloud Identity FPI"));
-    pubKey = SOSFullPeerInfoCopyPubKey(iCloudIdentity, NULL);
-    require_action_quiet(pubKey, retOut, secnotice("ghostBust", "Can't get iCloud Identity pubkey"));
-    pubKeyHash = SecKeyCopyPublicKeyHash(pubKey);
-    require_action_quiet(pubKeyHash, retOut, secnotice("ghostBust", "Can't get iCloud Identity pubkey hash"));
-    query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
-        kSecMatchLimit,            kSecMatchLimitAll,
-        kSecClass,                 kSecClassKey,
-        kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
-        kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
-        kSecReturnAttributes,      kCFBooleanTrue,
-        kSecAttrAccessGroup,       kSOSInternalAccessGroup,
-        NULL);
-    require_action_quiet(errSecSuccess == SecItemCopyMatching(query, &queryResult), retOut, secnotice("ghostBust", "Can't get iCloud Identity private keys"));
-    require_action_quiet(CFGetTypeID(queryResult) == CFArrayGetTypeID(), retOut, cleaned = true);
-    CFArrayRef iCloudPrivKeys = queryResult;
-    secnotice("ghostBust", "Screening %ld icloud private keys", (long)CFArrayGetCount(iCloudPrivKeys));
-    CFArrayForEach(iCloudPrivKeys, ^(const void *value) {
-        CFDictionaryRef privkey = asDictionary(value, NULL);
-        if(privkey) {
-            CFDataRef candidate = asData(CFDictionaryGetValue(privkey, kSecAttrApplicationLabel), NULL);
-            if(candidate && !CFEqual(pubKeyHash, candidate)) {
-                CFStringRef label = asString(CFDictionaryGetValue(privkey, kSecAttrLabel), NULL);
-                if(label) {
-                    if(CFStringHasPrefix(label, CFSTR("Cloud Identity"))) {
-
-                        CFDictionaryRef delQuery = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
-                            kSecClass,                 kSecClassKey,
-                            kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
-                            kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
-                            kSecAttrApplicationLabel,   candidate,
-                            NULL);
-
-                        OSStatus status = SecItemDelete(delQuery);
-                        if(errSecSuccess == status) {
-                            secnotice("ghostBust", "removed %@", label);
-                            removed++;
-                            cleaned = true;
-                        } else {
-                            secnotice("ghostbust", "Search for %@ returned %d", candidate, (int) status);
-                        }
-                        CFReleaseNull(delQuery);
-                    }
+static NSUInteger SOSGhostBustiCloudIdentityPrivateKeys(SOSAccount *account) {
+    __block NSUInteger cleaned = 0;
+
+    [ account iCloudIdentityStatus_internal:^(NSDictionary *tableSpid, NSError *error) {
+        if(!tableSpid) {
+            secnotice("ghostBust", "Couldn't work on iCloud Identities (%@)", error);
+        }
+
+        size_t keysToRemove = [tableSpid[kSOSIdentityStatusKeyOnly] count];
+
+        if(keysToRemove == 0) {
+            return;
+        }
+
+        if([tableSpid[kSOSIdentityStatusCompleteIdentity] count] == 0) {
+            secnotice("ghostBust", "No iCloud Identity FPI, can't remove iCloudIdentity extra keys");
+            return;
+        }
+
+        for (NSString *pid in tableSpid[kSOSIdentityStatusKeyOnly]) {
+            CFStringRef fullKeyLabel = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Cloud Identity - '%@'"), pid);
+
+            if(fullKeyLabel) {
+                CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                                                                     kSecClass,                 kSecClassKey,
+                                                                     kSecAttrKeyClass,          kSecAttrKeyClassPrivate,
+                                                                     kSecAttrSynchronizable,    kSecAttrSynchronizableAny,
+                                                                     kSecUseTombstones,         kCFBooleanTrue,
+                                                                     kSecAttrLabel,             fullKeyLabel,
+                                                                     NULL);
+                OSStatus status = SecItemDelete(query);
+                if(errSecSuccess == status) {
+                    secnotice("ghostBust", "removed %@", pid);
+                    cleaned++;
+                } else {
+                    secnotice("ghostbust", "Delete for %@ returned %d", pid, (int) status);
                 }
+                CFReleaseNull(query);
+                CFReleaseNull(fullKeyLabel);
             }
         }
-    });
-    secnotice("ghostBust", "Removed %d icloud private keys", removed);
-retOut:
-    CFReleaseNull(query);
-    CFReleaseNull(queryResult);
-    CFReleaseNull(pubKeyHash);
-    CFReleaseNull(pubKey);
-    CFReleaseNull(iCloudIdentity);
+        secnotice("ghostBust", "Removed %zu of %zu deserted icloud private keys", cleaned, keysToRemove);
+    }];
     return cleaned;
 }
 
 bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSAccountGhostBustingOptions options, int mincount) {
     __block bool result = false;
+    __block bool actionTaken = false;
     CFErrorRef localError = NULL;
     __block NSUInteger nbusted = 9999;
     NSMutableDictionary *attributes =[NSMutableDictionary new];
+
     int circleSize = SOSCircleCountPeers(account.trust.trustedCircle);
 
-    if ([akh isUseful] && [account isInCircle:nil] && circleSize > mincount) {
-        if(options & SOSGhostBustiCloudIdentities) {
-            secnotice("ghostBust", "Callout to cleanup icloud identities");
-            result = SOSGhostBustiCloudIdentityPrivateKeys(account);
-        } else {
+    if(options & SOSGhostBustiCloudIdentities && [account isInCircle:nil]) {
+        secnotice("ghostBust", "Callout to cleanup icloud identities");
+        nbusted = SOSGhostBustiCloudIdentityPrivateKeys(account);
+        if(nbusted) {
+            attributes[@"iCloudPrivKeysBusted"] = @(nbusted);
+            [[SOSAnalytics logger] logSoftFailureForEventNamed:@"GhostBust" withAttributes:attributes];
+            result = true;
+        }
+        actionTaken = true;
+    }
+
+    if(options &  (~SOSGhostBustiCloudIdentities)) {
+        if ([akh isUseful] && [account isInCircle:nil] && circleSize > mincount) {
             [account.trust modifyCircle:account.circle_transport err:&localError action:^(SOSCircleRef circle) {
-                nbusted = SOSGhostBustThinByMIDList(circle, account.peerID, akh, options, attributes);
-                secnotice("ghostbust", "Removed %lu ghosts from circle by midlist && serialNumber", (unsigned long)nbusted);
+                if((options & SOSGhostBustByMID) || (options & SOSGhostBustBySerialNumber)) {
+                    nbusted = SOSGhostBustThinByMIDList(circle, account.peerID, akh, options, attributes);
+                    secnotice("ghostbust", "Removed %lu ghosts from circle by midlist && serialNumber", (unsigned long)nbusted);
+                    actionTaken = true;
+                }
                 if(options & SOSGhostBustSerialByAge) {
                     NSUInteger thinBusted = 9999;
                     thinBusted = SOSGhostBustThinSerialClones(circle, account.peerID);
                     nbusted += thinBusted;
                     attributes[@"byAge"] = @(thinBusted);
+                    actionTaken = true;
                 }
                 attributes[@"total"] = @(SecBucket1Significant(nbusted));
                 attributes[@"startCircleSize"] = @(SecBucket1Significant(circleSize));
@@ -324,17 +358,17 @@ bool SOSAccountGhostBustCircle(SOSAccount *account, SOSAuthKitHelpers *akh, SOSA
             }];
             secnotice("circleOps", "Ghostbusting %@ (%@)", result ? CFSTR("Performed") : CFSTR("Not Performed"), localError);
         }
-    } else {
-        secnotice("circleOps", "Ghostbusting skipped");
     }
     CFReleaseNull(localError);
-    
-    if(result) {
-        [[SOSAnalytics logger] logSoftFailureForEventNamed:@"GhostBust" withAttributes:attributes];
-    } else if(nbusted == 0){
-        [[SOSAnalytics logger] logSuccessForEventNamed:@"GhostBust"];
-    } else {
-        [[SOSAnalytics logger] logHardFailureForEventNamed:@"GhostBust" withAttributes:nil];
+
+    if(actionTaken) {
+        if(result) {
+            [[SOSAnalytics logger] logSoftFailureForEventNamed:@"GhostBust" withAttributes:attributes];
+        } else if(nbusted == 0){
+            [[SOSAnalytics logger] logSuccessForEventNamed:@"GhostBust"];
+        } else {
+            [[SOSAnalytics logger] logHardFailureForEventNamed:@"GhostBust" withAttributes:nil];
+        }
     }
     return result;
 }
index 1eed7078adb74e6dff8109c85f01ecdd5dcb5878..26d6261ff295c3720986836edbf51cf71c280aff 100644 (file)
@@ -6,7 +6,6 @@
 #include "SOSAccountLog.h"
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <AssertMacros.h>
 #include "SOSAccountPriv.h"
 #include "SOSViews.h"
index 5b63e744296ff4a3370da4840f7b429bd1fbe1d3..758fcfb0fd20104dae71240d73ac56fdd4f4a7f5 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
 #include <AssertMacros.h>
 #include "SOSViews.h"
 
@@ -65,7 +64,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
     
     {
         CFDictionaryRef decoded_gestalt = NULL;
-        *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
+        *der_p = der_decode_dictionary(kCFAllocatorDefault, &decoded_gestalt, error,
                                        *der_p, der_end);
         
         if (*der_p == 0)
@@ -77,7 +76,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
     }
     SOSAccountTrustClassic *trust = account.trust;
 
-    *der_p = der_decode_array(kCFAllocatorDefault, 0, &array, error, *der_p, der_end);
+    *der_p = der_decode_array(kCFAllocatorDefault, &array, error, *der_p, der_end);
     
     uint64_t tmp_departure_code = kSOSNeverAppliedToCircle;
     *der_p = ccder_decode_uint64(&tmp_departure_code, *der_p, der_end);
@@ -99,10 +98,10 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v6(CFAllocatorRef allocator,
     {
         CFDataRef parms = NULL;
         *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
-        [account setAccountKeyDerivationParamters:(__bridge_transfer NSData*) parms];
+        [account setAccountKeyDerivationParameters:(__bridge_transfer NSData*) parms];
     }
 
-    *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end);
+    *der_p = der_decode_dictionary(kCFAllocatorDefault, (CFDictionaryRef *) &retiredPeers, error, *der_p, der_end);
 
     if(*der_p != der_end) {
         *der_p = NULL;
@@ -173,11 +172,11 @@ fail:
     return result;
 }
 
-static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_data_optional(CFAllocatorRef allocator,
                                         CFDataRef* data, CFErrorRef *error,
                                         const uint8_t* der, const uint8_t *der_end)
 {
-    const uint8_t *dt_end = der_decode_data(allocator, mutability, data, NULL, der, der_end);
+    const uint8_t *dt_end = der_decode_data(allocator, data, NULL, der, der_end);
 
     return dt_end ? dt_end : der;
 }
@@ -192,7 +191,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
     
     {
         CFDictionaryRef decoded_gestalt = NULL;
-        *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
+        *der_p = der_decode_dictionary(kCFAllocatorDefault, &decoded_gestalt, error,
                                        *der_p, der_end);
         
         if (*der_p == 0)
@@ -242,7 +241,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
     {
         CFDataRef parms = NULL;
         *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
-        account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms;
+        account.accountKeyDerivationParameters = (__bridge_transfer NSData*)parms;
     }
 
     {
@@ -252,7 +251,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v7(CFAllocatorRef allocator,
 
     {
         CFDataRef bKey = NULL;
-        *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end);
+        *der_p = der_decode_data_optional(kCFAllocatorDefault, &bKey, error, *der_p, der_end);
         if(bKey != NULL)
             [account setBackup_key:(__bridge_transfer NSData *)bKey];
     }
@@ -280,7 +279,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
 
     {
         CFDictionaryRef decoded_gestalt = NULL;
-        *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_gestalt, error,
+        *der_p = der_decode_dictionary(kCFAllocatorDefault, &decoded_gestalt, error,
                                        *der_p, der_end);
         
         if (*der_p == 0) {
@@ -332,7 +331,7 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
     {
         CFDataRef parms;
         *der_p = der_decode_data_or_null(kCFAllocatorDefault, &parms, error, *der_p, der_end);
-        account.accountKeyDerivationParamters = (__bridge_transfer NSData*)parms;
+        account.accountKeyDerivationParameters = (__bridge_transfer NSData*)parms;
         parms = NULL;
     }
 
@@ -343,10 +342,10 @@ static SOSAccount* SOSAccountCreateFromRemainingDER_v8(CFAllocatorRef allocator,
     }
 
     CFDataRef bKey = NULL;
-    *der_p = der_decode_data_optional(kCFAllocatorDefault, kCFPropertyListImmutable, &bKey, error, *der_p, der_end);
+    *der_p = der_decode_data_optional(kCFAllocatorDefault, &bKey, error, *der_p, der_end);
     {
         CFDictionaryRef expansion = NULL;
-        *der_p = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &expansion, error,
+        *der_p = der_decode_dictionary(kCFAllocatorDefault, &expansion, error,
                                        *der_p, der_end);
         
         if (*der_p == 0) {
@@ -440,9 +439,12 @@ static SOSAccount* SOSAccountCreateFromDER(CFAllocatorRef allocator,
             SOSUnregisterTransportKeyParameter(account.key_transport);
             SOSUnregisterTransportCircle((SOSCircleStorageTransport*)account.circle_transport);
             SOSUnregisterTransportMessage(account.kvs_message_transport);
-
             secnotice("account", "No private key associated with my_identity, resetting");
             return nil;
+        } else {
+            SecKeyRef ppk = SOSFullPeerInfoCopyPubKey(identity, NULL);
+            account.peerPublicKey = ppk;
+            CFReleaseNull(ppk);
         }
     }
 
@@ -457,9 +459,10 @@ static SOSAccount* SOSAccountCreateFromDER(CFAllocatorRef allocator,
     }
     CFReleaseNull(oldPI);
 
-    SOSAccountEnsureRecoveryRing(account);
 
     [account performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
+        SOSAccountEnsureRecoveryRing(account);
+
         secnotice("circleop", "Setting account.key_interests_need_updating to true in SOSAccountCreateFromDER");
         account.key_interests_need_updating = true;
     }];
index d90657dbe0e97db5561649366cb974c35e86a37c..b73f7487442ef6c92ae6684e5e5fa2c3c9a15367 100644 (file)
@@ -21,7 +21,6 @@
 #include <corecrypto/ccder.h>
 
 #include <AssertMacros.h>
-#include <assert.h>
 
 #import <notify.h>
 
@@ -97,16 +96,19 @@ typedef void (^SOSAccountSaveBlock)(CFDataRef flattenedAccount, CFErrorRef flatt
 @property   (nonatomic, assign)     BOOL                        circle_rings_retirements_need_attention;
 @property   (nonatomic, assign)     BOOL                        engine_peer_state_needs_repair;
 @property   (nonatomic, assign)     BOOL                        key_interests_need_updating;
+@property   (nonatomic, assign)     BOOL                        need_backup_peers_created_after_backup_key_set;
+
 
 @property   (nonatomic, retain)     NSMutableArray               *change_blocks;
 
 @property   (nonatomic, retain)     NSMutableDictionary          *waitForInitialSync_blocks;
 
-@property   (nonatomic, retain)     NSData*                     accountKeyDerivationParamters;
+@property   (nonatomic, retain)     NSData*                     accountKeyDerivationParameters;
 
 @property   (nonatomic, assign)     BOOL                        accountKeyIsTrusted;
 @property   (nonatomic)             SecKeyRef                   accountKey;
 @property   (nonatomic)             SecKeyRef                   previousAccountKey;
+@property   (nonatomic)             SecKeyRef                   peerPublicKey;
 
 @property   (copy)                  SOSAccountSaveBlock         saveBlock;
 
@@ -121,14 +123,18 @@ typedef void (^SOSAccountSaveBlock)(CFDataRef flattenedAccount, CFErrorRef flatt
 @property   (nonatomic, assign)     BOOL                        notifyViewChangeOnExit;
 @property   (nonatomic, assign)     BOOL                        notifyBackupOnExit;
 
-@property   (nonatomic, retain)     NSUserDefaults*              settings;
+@property   (nonatomic, retain)     NSUserDefaults*             settings;
+
+@property   (nonatomic)              SecKeyRef                  octagonSigningFullKeyRef;
+@property   (nonatomic)              SecKeyRef                  octagonEncryptionFullKeyRef;
 
+@property   (nonatomic, assign)     BOOL                        accountIsChanging;
 
 
 -(id) init NS_UNAVAILABLE;
 -(id) initWithGestalt:(CFDictionaryRef)gestalt factory:(SOSDataSourceFactoryRef)factory;
 
-//- (void)startStateMachine;
+- (void)startStateMachine;
 
 void SOSAccountAddSyncablePeerBlock(SOSAccount*  a,
                                     CFStringRef ds_name,
@@ -145,6 +151,7 @@ void SOSAccountAddSyncablePeerBlock(SOSAccount*  a,
 
 #if OCTAGON
 - (void)triggerBackupForPeers:(NSArray<NSString*>*)backupPeer;
+- (void)triggerRingUpdate;
 #endif
 
 
@@ -205,8 +212,6 @@ bool SOSAccountHandleCircleMessage(SOSAccount* account,
 CF_RETURNS_RETAINED
 CFDictionaryRef SOSAccountHandleRetirementMessages(SOSAccount* account, CFDictionaryRef circle_retirement_messages, CFErrorRef *error);
 
-void SOSAccountRecordRetiredPeersInCircle(SOSAccount* account);
-
 bool SOSAccountHandleUpdateCircle(SOSAccount* account,
                                   SOSCircleRef prospective_circle,
                                   bool writeUpdate,
@@ -247,6 +252,8 @@ bool SOSAccountIsAccountIdentity(SOSAccount* account, SOSPeerInfoRef peer_info,
 bool SOSAccountFullPeerInfoVerify(SOSAccount* account, SecKeyRef privKey, CFErrorRef *error);
 CF_RETURNS_RETAINED SOSPeerInfoRef GenerateNewCloudIdentityPeerInfo(CFErrorRef *error);
 
+void SOSiCloudIdentityPrivateKeyForEach(void (^complete)(SecKeyRef privKey));
+
 // Credentials
 bool SOSAccountHasPublicKey(SOSAccount* account, CFErrorRef* error);
 bool SOSAccountPublishCloudParameters(SOSAccount* account, CFErrorRef* error);
@@ -269,12 +276,11 @@ void SOSAccountSetLastDepartureReason(SOSAccount* account, enum DepartureReason
 void SOSAccountSetUserPublicTrustedForTesting(SOSAccount* account);
 
 void SOSAccountPurgeIdentity(SOSAccount*);
-bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, NSData* parentData, CFErrorRef* error);
+bool sosAccountLeaveCircle(SOSAccount* account, SOSCircleRef circle, CFErrorRef* error);
 
 bool SOSAccountForEachRing(SOSAccount* account, SOSRingRef (^action)(CFStringRef name, SOSRingRef ring));
 bool SOSAccountUpdateBackUp(SOSAccount* account, CFStringRef viewname, CFErrorRef *error);
 void SOSAccountEnsureRecoveryRing(SOSAccount* account);
-bool SOSAccountEnsureInBackupRings(SOSAccount* account);
 
 bool SOSAccountEnsurePeerRegistration(SOSAccount* account, CFErrorRef *error);
 
index cd272013ac04f9a12504e5306d4ab610891d012a..a477f5c4277b67d134aa225004db46c813f4bbbc 100644 (file)
@@ -36,7 +36,6 @@
 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
 
 #include "keychain/SecureObjectSync/SOSInternal.h"
-#include "SecADWrapper.h"
 
 #include "keychain/SecureObjectSync/SOSRecoveryKeyBag.h"
 #include "keychain/SecureObjectSync/SOSRingRecovery.h"
@@ -139,7 +138,7 @@ bool SOSAccountSetRecoveryKey(SOSAccount* account, CFDataRef pubData, CFErrorRef
     CFReleaseNull(rkbg);
 
     if(SOSPeerInfoHasBackupKey(account.trust.peerInfo)) {
-        SOSAccountProcessBackupRings(account, error);
+        SOSAccountProcessBackupRings(account);
     }
     account.circle_rings_retirements_need_attention = true;
     result = true;
@@ -196,6 +195,8 @@ static void sosRecoveryAlertAndNotify(SOSAccount* account, SOSRecoveryKeyBagRef
 }
 
 void SOSAccountEnsureRecoveryRing(SOSAccount* account) {
+    dispatch_assert_queue(account.queue);
+
     static SOSRecoveryKeyBagRef oldRingRKBG = NULL;
     SOSRecoveryKeyBagRef acctRKBG = SOSAccountCopyRecoveryKeyBagEntry(kCFAllocatorDefault, account, NULL);
     if(!CFEqualSafe(acctRKBG, oldRingRKBG)) {
index 2ebcd729985e0f6fc264387ccb4f76a98ae0b610..708940daec2d81e42efee92737988297256b3423 100644 (file)
@@ -116,6 +116,11 @@ SOSRingRef SOSAccountCopyRingNamed(SOSAccount* a, CFStringRef ringName, CFErrorR
 }
 
 bool SOSAccountUpdateRingFromRemote(SOSAccount* account, SOSRingRef newRing, CFErrorRef *error) {
+    if(account && account.accountIsChanging) {
+        secnotice("circleOps", "SOSAccountUpdateRingFromRemote called before signing in to new account");
+        return true; // we want to drop circle notifications when account is changing
+    }
+
     require_quiet(SOSAccountHasPublicKey(account, error), errOut);
   
     return [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:false err:error];
@@ -135,25 +140,22 @@ errOut:
 bool SOSAccountUpdateNamedRing(SOSAccount* account, CFStringRef ringName, CFErrorRef *error,
                                       SOSRingRef (^create)(CFStringRef ringName, CFErrorRef *error),
                                       SOSRingRef (^copyModified)(SOSRingRef existing, CFErrorRef *error)) {
+    if(![account isInCircle:NULL]) {
+        return false;
+    }
     bool result = false;
-    SOSRingRef found = [account.trust copyRing:ringName err:error];
-
+    SOSRingRef found = NULL;
     SOSRingRef newRing = NULL;
+    found = [account.trust copyRing:ringName err:error];
     if(!found) {
         found = create(ringName, error);
     }
-    require_quiet(found, errOut);
-    newRing = copyModified(found, error);
-    CFReleaseNull(found);
-    
-    require_quiet(newRing, errOut);
-
-    require_quiet(SOSAccountHasPublicKey(account, error), errOut);
-    require_quiet(SOSAccountHasCircle(account, error), errOut);
-
-    result = [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error];
-    
-errOut:
+    if(found) {
+        newRing = copyModified(found, error);
+        if(newRing) {
+            result = [account.trust handleUpdateRing:account prospectiveRing:newRing transport:account.circle_transport userPublicKey:account.accountKey writeUpdate:true err:error];
+        }
+    }
     CFReleaseNull(found);
     CFReleaseNull(newRing);
     return result;
index 1c014b29b2428662d3acfb5aecc156bd6e0d0c99..7e85439a0eb3dd1e250955aa5281637520d738e9 100644 (file)
     return circleStatus;
 }
 
+static inline SOSCCStatus reportAsSOSCCStatus(uint64_t x) {
+    return (SOSCCStatus) x & CC_MASK;
+}
+
 - (void) updateSOSCircleCachedStatus {
     // clearly invalid, overwritten by cached value in notify_get_state()
     // if its the second time we are launchded
@@ -92,7 +96,7 @@
             }
             return true;
         });
-        secnotice("sosnotify", "initial last circle status is: %llu", (unsigned long long)lastStatus);
+        secnotice("sosnotify", "initial last circle status is: %d", reportAsSOSCCStatus(lastStatus));
     });
 
     uint64_t currentStatus = [self currentTrustBitmask];
 
         lastStatus = currentStatus;
 
-        secnotice("sosnotify", "new last circle status is: %llu (notify: %s)",
-                  (unsigned long long)lastStatus,
+        secnotice("sosnotify", "new last circle status is: %d (notify: %s)",
+                  reportAsSOSCCStatus(lastStatus),
                   circleStatusChanged ? "yes" : "no");
 
         SOSCachedNotificationOperation(kSOSCCCircleChangedNotification, ^bool(int token, bool gtg) {
@@ -198,7 +202,7 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) {
     }
 
     self.initialUnsyncedViews = (__bridge_transfer NSMutableSet<NSString*>*)SOSAccountCopyOutstandingViews(self.account);
-    self.initialKeyParameters = self.account.accountKeyDerivationParamters ? [NSData dataWithData:self.account.accountKeyDerivationParamters] : nil;
+    self.initialKeyParameters = self.account.accountKeyDerivationParameters ? [NSData dataWithData:self.account.accountKeyDerivationParameters] : nil;
 
     SOSPeerInfoRef mpi = self.account.peerInfo;
     if (mpi) {
@@ -238,9 +242,10 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) {
     bool isInCircle = [self.account isInCircle:NULL];
 
     if (isInCircle && self.peersToRequestSync) {
-        SOSCCRequestSyncWithPeers((__bridge CFSetRef)(self.peersToRequestSync));
+        NSMutableSet<NSString*>* worklist = self.peersToRequestSync;
+        self.peersToRequestSync = nil;
+        SOSCCRequestSyncWithPeers((__bridge CFSetRef)(worklist));
     }
-    self.peersToRequestSync = nil;
 
     if (isInCircle) {
         SOSAccountEnsureSyncChecking(self.account);
@@ -277,19 +282,23 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) {
     }
    
     if(self.account.circle_rings_retirements_need_attention){
-        SOSAccountRecordRetiredPeersInCircle(self.account);
-
-        SOSAccountEnsureRecoveryRing(self.account);
-        SOSAccountEnsureInBackupRings(self.account);
-
-        CFErrorRef localError = NULL;
-        if(![self.account.circle_transport flushChanges:&localError]){
-            secerror("flush circle failed %@", localError);
-        }
-        CFReleaseSafe(localError);
-
+        self.account.circle_rings_retirements_need_attention = false;
+#if OCTAGON
+        [self.account triggerRingUpdate];
+#endif
+        // Also, there might be some view set change. Ensure that the engine knows...
         notifyEngines = true;
     }
+    if(self.account.need_backup_peers_created_after_backup_key_set){
+        self.account.need_backup_peers_created_after_backup_key_set = false;
+        notifyEngines = true;
+    }
+
+    // Always notify the engines if the view set has changed
+    CFSetRef currentViews = self.account.peerInfo ? SOSPeerInfoCopyEnabledViews(self.account.peerInfo) : NULL;
+    BOOL viewSetChanged = !NSIsEqualSafe(self.initialViews, (__bridge NSSet*)currentViews);
+    CFReleaseNull(currentViews);
+    notifyEngines |= viewSetChanged;
 
     if (notifyEngines) {
 #if OCTAGON
@@ -305,7 +314,6 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) {
         SOSUpdateKeyInterest(self.account);
     }
 
-    self.account.circle_rings_retirements_need_attention = false;
     self.account.engine_peer_state_needs_repair = false;
 
     [self.account flattenToSaveBlock];
@@ -332,7 +340,7 @@ static void SOSViewsSetCachedStatus(SOSAccount *account) {
     }
 
     // This is the logic to detect a new userKey:
-    bool userKeyChanged = !NSIsEqualSafe(self.initialKeyParameters, self.account.accountKeyDerivationParamters);
+    bool userKeyChanged = !NSIsEqualSafe(self.initialKeyParameters, self.account.accountKeyDerivationParameters);
     
     // This indicates we initiated a password change.
     bool weInitiatedKeyChange = (self.initialTrusted &&
index 8aafe1739cafc0508e58e9488600b6475f22bea7..c7303592c8393c32cc3af296df7d1f2b29efd945 100644 (file)
@@ -16,9 +16,7 @@
 
 -(id)init
 {
-    self = [super init];
-    if(self)
-    {
+    if ((self = [super init])) {
         self.retirees = [NSMutableSet set];
         self.fullPeerInfo = NULL;
         self.trustedCircle = NULL;
@@ -32,9 +30,7 @@
         departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)e
 {
 
-    self = [super init];
-    if(self)
-    {
+    if ((self = [super init])) {
         self.retirees = r;
         self.fullPeerInfo = fpi;
         self.trustedCircle = trusted_circle;
index 624badd02edd5ce4726d16cc8c985b36418ebb47..e38159662034d7ba8fe703befea36eb259119656 100644 (file)
 -(bool) isInCircleOnly:(CFErrorRef *)error;
 -(void) forEachCirclePeerExceptMe:(SOSIteratePeerBlock)block;
 -(bool) leaveCircle:(SOSAccount*)account err:(CFErrorRef*) error;
--(bool) leaveCircleWithAccount:(SOSAccount*)account withAnalytics:(NSData*)parentEvent err:(CFErrorRef*) error;
+-(bool) leaveCircleWithAccount:(SOSAccount*)account err:(CFErrorRef*) error;
 -(bool) resetToOffering:(SOSAccountTransaction*) aTxn key:(SecKeyRef)userKey err:(CFErrorRef*) error;
 -(bool) resetCircleToOffering:(SOSAccountTransaction*) aTxn userKey:(SecKeyRef) user_key err:(CFErrorRef *)error;
 -(SOSCCStatus) thisDeviceStatusInCircle:(SOSCircleRef) circle peer:(SOSPeerInfoRef) this_peer;
 -(bool) updateCircle:(SOSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef) newCircle err:(CFErrorRef*)error;
--(bool) updateCircleWithAnalytics:(SOSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef) newCircle parentEvent:(NSData*)parentEvent err:(CFErrorRef*)error;
 
 -(bool) updateCircleFromRemote:(SOSCircleStorageTransport*)circleTransport newCircle:(SOSCircleRef)newCircle err:(CFErrorRef*)error;
 
index ec3b56640c1640de0508ff12bc20e1e505e15405..3507aa1a0ec2fffaa38276d62906f6363b77958c 100644 (file)
@@ -348,44 +348,44 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO
                               old_circle_key, account.accountKey,
                                       me, error);
             
-            CFStringRef concStr = NULL;
-            switch(concstat) {
-                case kSOSConcordanceTrusted:
-                    circle_action = countersign;
-                    concStr = CFSTR("Trusted");
-                    break;
-                case kSOSConcordanceGenOld:
-                    circle_action = userTrustedOldCircle ? revert : ignore;
-                    concStr = CFSTR("Generation Old");
-                    break;
-                case kSOSConcordanceBadUserSig:
-                case kSOSConcordanceBadPeerSig:
-                    circle_action = userTrustedOldCircle ? revert : accept;
-                    concStr = CFSTR("Bad Signature");
-                    break;
-                case kSOSConcordanceNoUserSig:
-                    circle_action = userTrustedOldCircle ? revert : accept;
-                    concStr = CFSTR("No User Signature");
-                    break;
-                case kSOSConcordanceNoPeerSig:
-                    circle_action = accept; // We might like this one eventually but don't countersign.
-                    concStr = CFSTR("No trusted peer signature");
-                    secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later");
-                    break;
-                case kSOSConcordanceNoPeer:
-                    circle_action = leave;
-                    leave_reason = kSOSLeftUntrustedCircle;
-                    concStr = CFSTR("No trusted peer left");
-                    break;
-                case kSOSConcordanceNoUserKey:
-                    secerror("##### No User Public Key Available, this shouldn't ever happen!!!");
-                    abort();
-                    break;
-                default:
-                    secerror("##### Bad Error Return from ConcordanceTrust");
-                    abort();
-                    break;
-            }
+    CFStringRef concStr = NULL;
+    switch(concstat) {
+        case kSOSConcordanceTrusted:
+            circle_action = countersign;
+            concStr = CFSTR("Trusted");
+            break;
+        case kSOSConcordanceGenOld:
+            circle_action = userTrustedOldCircle ? revert : ignore;
+            concStr = CFSTR("Generation Old");
+            break;
+        case kSOSConcordanceBadUserSig:
+        case kSOSConcordanceBadPeerSig:
+            circle_action = userTrustedOldCircle ? revert : accept;
+            concStr = CFSTR("Bad Signature");
+            break;
+        case kSOSConcordanceNoUserSig:
+            circle_action = userTrustedOldCircle ? revert : accept;
+            concStr = CFSTR("No User Signature");
+            break;
+        case kSOSConcordanceNoPeerSig:
+            circle_action = accept; // We might like this one eventually but don't countersign.
+            concStr = CFSTR("No trusted peer signature");
+            secnotice("signing", "##### No trusted peer signature found, accepting hoping for concordance later");
+            break;
+        case kSOSConcordanceNoPeer:
+            circle_action = leave;
+            leave_reason = kSOSLeftUntrustedCircle;
+            concStr = CFSTR("No trusted peer left");
+            break;
+        case kSOSConcordanceNoUserKey:
+            secerror("##### No User Public Key Available, this shouldn't ever happen!!!");
+            abort();
+            break;
+        default:
+            secerror("##### Bad Error Return from ConcordanceTrust");
+            abort();
+            break;
+    }
     
     secnotice("signing", "Decided on action [%s] based on concordance state [%@] and [%s] circle.  My PeerID is %@", actionstring[circle_action], concStr, userTrustedOldCircle ? "trusted" : "untrusted", myPeerID);
     
@@ -402,7 +402,7 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO
             secnotice("account", "Key state: accountKey %@, previousAccountKey %@, old_circle_key %@",
                       account.accountKey, account.previousAccountKey, old_circle_key);
             
-            if (sosAccountLeaveCircle(account, newCircle, nil, error)) {
+            if (sosAccountLeaveCircle(account, newCircle, error)) {
                 secnotice("circleOps", "Leaving circle by newcircle state");
                 circleToPush = newCircle;
             } else {
@@ -464,8 +464,7 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO
             && !(SOSCircleCountPeers(oldCircle) == 1 && SOSCircleHasPeer(oldCircle, me, NULL)) // If it was our offering, don't change ID to avoid ghosts
             && !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) {
             secnotice("circle", "Purging my peer (ID: %@) for circle '%@'!!!", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle));
-            if (self.fullPeerInfo)
-                SOSFullPeerInfoPurgePersistentKey(self.fullPeerInfo, NULL);
+            [self purgeIdentity];
             me = NULL;
             me_full = NULL;
         }
@@ -476,8 +475,7 @@ static bool SOSCircleHasUpdatedPeerInfoWithOctagonKey(SOSCircleRef oldCircle, SO
                 secnotice("circle", "Rejected, Purging my applicant peer (ID: %@) for circle '%@'", SOSPeerInfoGetPeerID(me), SOSCircleGetName(oldCircle));
                 debugDumpCircle(CFSTR("oldCircle"), oldCircle);
                 debugDumpCircle(CFSTR("newCircle"), newCircle);
-                if (self.fullPeerInfo)
-                    SOSFullPeerInfoPurgePersistentKey(self.fullPeerInfo, NULL);
+                [self purgeIdentity];
                 me = NULL;
                 me_full = NULL;
             } else {
@@ -657,7 +655,7 @@ fail:
     // rdar://51233857 - don't gensign if there isn't a change in the userKey
     // also don't rebake the circle to fix the icloud identity if there isn't
     // a change as that will mess up piggybacking.
-    if(SOSAccountFullPeerInfoVerify(account, privKey, NULL) && SOSCircleVerify(account.trust.trustedCircle, account.accountKey, NULL)) {
+    if(account.trust.trustedCircle && SOSAccountFullPeerInfoVerify(account, privKey, NULL) && SOSCircleVerify(account.trust.trustedCircle, account.accountKey, NULL)) {
         secnotice("updatingGenSignature", "no change to userKey - skipping gensign");
         return;
     }
@@ -696,12 +694,12 @@ fail:
     }
 }
 
--(bool) leaveCircleWithAccount:(SOSAccount*)account withAnalytics:(NSData*)parentEvent err:(CFErrorRef*) error
+-(bool) leaveCircleWithAccount:(SOSAccount*)account err:(CFErrorRef*) error
 {
     bool result = true;
     secnotice("circleOps", "leaveCircleWithAccount: Leaving circle by client request");
     result &= [self modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) {
-        return sosAccountLeaveCircle(account, circle, parentEvent, error);
+        return sosAccountLeaveCircle(account, circle, error);
     }];
 
     self.departureCode = kSOSWithdrewMembership;
@@ -714,7 +712,7 @@ fail:
     bool result = true;
     secnotice("circleOps", "Leaving circle by client request");
     result &= [self modifyCircle:account.circle_transport err:error action:^(SOSCircleRef circle) {
-        return sosAccountLeaveCircle(account, circle, nil, error);
+        return sosAccountLeaveCircle(account, circle, error);
     }];
     account.backup_key = nil;
     self.departureCode = kSOSWithdrewMembership;
@@ -724,9 +722,8 @@ fail:
 
 -(bool) resetToOffering:(SOSAccountTransaction*) aTxn key:(SecKeyRef)userKey err:(CFErrorRef*) error
 {
-    SOSFullPeerInfoPurgePersistentKey(self.fullPeerInfo, NULL);
-    self.fullPeerInfo = nil;
-    
+    [self purgeIdentity];
+
     secnotice("resetToOffering", "Resetting circle to offering by request from client");
     
     return userKey && [self resetCircleToOffering:aTxn userKey:userKey err:error];
@@ -741,7 +738,7 @@ fail:
     if(![self hasCircle:error])
         return result;
     
-    if(![self ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error])
+    if(![self ensureFullPeerAvailable:account err:error])
         return result;
     
     (void)[self resetAllRings:account err:error];
@@ -807,7 +804,7 @@ void SOSAccountForEachCirclePeerExceptMe(SOSAccount* account, void (^action)(SOS
     __block SOSFullPeerInfoRef cloud_full_peer = NULL;
     __block SOSAccount* account = aTxn.account;
     require_action_quiet(self.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Don't have circle when joining???")));
-    require_quiet([self ensureFullPeerAvailable:(__bridge CFDictionaryRef)account.gestalt deviceID:(__bridge CFStringRef)account.deviceID backupKey:(__bridge CFDataRef)account.backup_key err:error], fail);
+    require_quiet([self ensureFullPeerAvailable:account err:error], fail);
     
     if (SOSCircleCountPeers(self.trustedCircle) == 0 || SOSAccountGhostResultsInReset(account)) {
         secnotice("resetToOffering", "Resetting circle to offering since there are no peers");
index 5d71675760403fbcead032155e4af96211ea0b05..e6855c86f9671e2338ea6a323615c47df09f623e 100644 (file)
@@ -21,7 +21,6 @@
 -(bool) handleUpdateRing:(SOSAccount*)account prospectiveRing:(SOSRingRef)prospectiveRing transport:(SOSKVSCircleStorageTransport*)circleTransport userPublicKey:(SecKeyRef)userPublic writeUpdate:(bool)writeUpdate err:(CFErrorRef *)error;
 -(bool) resetRing:(SOSAccount*)account ringName:(CFStringRef) ringName err:(CFErrorRef *)error;
 -(bool) resetAccountToEmpty:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*) error;
--(bool) resetAccountToEmptyWithAnalytics:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport parentEvent:(NSData*)parentEvent err:(CFErrorRef*) error;
 
 -(SOSRingRef) copyRing:(CFStringRef) ringName err:(CFErrorRef *)error;
 -(CFMutableDictionaryRef) getRings:(CFErrorRef *)error;
index b6273573b5b44caf305c8d2a80cd51c901f22b3c..7eaba5a11b3eb8b72f27ad61e4adf85cda33249e 100644 (file)
@@ -15,7 +15,6 @@
 #import "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
 #import "keychain/SecureObjectSync/SOSTransportCircleKVS.h"
 #import "keychain/SecureObjectSync/SOSRingRecovery.h"
-#import "keychain/SigninMetrics/SFSignInAnalytics.h"
 
 @implementation SOSAccountTrustClassic (Expansion)
 typedef enum {
@@ -202,29 +201,12 @@ errOut:
 }
 
 -(bool) resetAccountToEmpty:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport err:(CFErrorRef*) error
-{
-    return [self resetAccountToEmptyWithAnalytics:account transport:circleTransport parentEvent:nil err:error ];
-}
-
--(bool) resetAccountToEmptyWithAnalytics:(SOSAccount*)account transport: (SOSCircleStorageTransport*)circleTransport parentEvent:(NSData*)parentEvent err:(CFErrorRef*) error
 {
     __block bool result = true;
     CFErrorRef resetError = NULL;
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = nil;
-    SFSignInAnalytics *resetAllRingsEvent = nil;
-    bool doingAnalytics = parentEvent != nil;
-
-    if(doingAnalytics) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
-        resetAllRingsEvent = [parent newSubTaskForEvent:@"resetAllRingsEvent"];
-    }
 
     result &= [self resetAllRings:account err:&resetError];
     if(resetError){
-        if(doingAnalytics) {
-            [resetAllRingsEvent logRecoverableError:(__bridge NSError*)resetError];
-        }
         secerror("reset all rings error: %@", resetError);
         if(error){
             *error = resetError;
@@ -232,29 +214,17 @@ errOut:
             CFReleaseNull(resetError);
         }
     }
-    if(doingAnalytics) {
-        [resetAllRingsEvent stopWithAttributes:nil];
-    }
 
     self.fullPeerInfo = nil;
 
     self.departureCode = kSOSWithdrewMembership;
     secnotice("circleOps", "Reset Rings to empty by client request");
 
-    SFSignInAnalytics *resetCircleToEmptyEvent =  nil;
-    if(doingAnalytics) {
-        resetCircleToEmptyEvent = [parent newSubTaskForEvent:@"resetCircleToEmptyEvent"];
-    }
-
     result &= [self modifyCircle:circleTransport err:error action:^bool(SOSCircleRef circle) {
         result = SOSCircleResetToEmpty(circle, error);
         return result;
     }];
 
-    if(doingAnalytics) {
-        [resetCircleToEmptyEvent stopWithAttributes:nil];
-    }
-
     if (!result) {
         secerror("error: %@", error ? *error : NULL);
     } else {
@@ -332,6 +302,14 @@ errOut:
     CFStringRef modifierPeerID = CFStringCreateTruncatedCopy(SOSRingGetLastModifier(prospectiveRing), 8);
     secnotice("ring", "start:[%s] modifier: %@", localRemote, modifierPeerID);
     CFReleaseNull(modifierPeerID);
+
+    // don't act on our own echos from KVS (remote ring, our peerID as modifier)
+    if(!localUpdate && CFEqualSafe(peerID, SOSRingGetLastModifier(prospectiveRing))) {
+        secnotice("ring", "Ceasing ring handling for an echo of our own posted ring");
+        success = true;
+        goto errOut;
+    }
+    
     require_quiet(SOSAccountHasPublicKey(account, error), errOut);
     require_action_quiet(peerPubKey, errOut, SOSCreateError(kSOSErrorPublicKeyAbsent, CFSTR("No device public key to work with"), NULL, error));
     require_action_quiet(peerPrivKey, errOut, SOSCreateError(kSOSErrorPrivateKeyAbsent, CFSTR("No device private key to work with"), NULL, error));
@@ -424,6 +402,7 @@ errOut:
     // This will take care of modify, but we're always going to do this scan if we get this far
     CFSetRef ringPeerIDSet = SOSRingCopyPeerIDs(newRing);
     if(CFSetGetCount(ringPeerIDSet) == 0) { // this is a reset ring
+        secnotice("ring", "changing state to accept - we have a reset ring");
         ringAction = accept;
     } else {
         // Get the peerIDs appropriate for the ring
@@ -440,6 +419,9 @@ errOut:
         }
 
         if(!CFEqual(filteredPeerIDs, ringPeerIDSet)) {
+            secnotice("ring", "mismatch between filteredPeerIDs and ringPeerIDSet, fixing ring and gensigning");
+            secnotice("ring", "filteredPeerIDs %@", filteredPeerIDs);
+            secnotice("ring", "  ringPeerIDSet %@", ringPeerIDSet);
             SOSRingSetPeerIDs(newRing, filteredPeerIDs);
             SOSRingRemoveSignatures(newRing, NULL);
             ringAction = countersign;
@@ -457,14 +439,27 @@ errOut:
                 __block bool fixBSKB = false;
                 CFDataRef recoveryKeyData = SOSAccountCopyRecoveryPublic(kCFAllocatorDefault, account, NULL);
                 SOSBackupSliceKeyBagRef currentBSKB = SOSRingCopyBackupSliceKeyBag(newRing, NULL);
+                
+                if(currentBSKB == NULL) {
+                    secnotice("ring", "Backup ring contains no BSKB");
+                    fixBSKB = true;
+                }
+                
+                if(SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) == false) {
+                    secnotice("ring", "BSKB is missing some backup keys");
+                    fixBSKB = true;
+                }
 
-                fixBSKB = !currentBSKB ||
-                    !SOSBSKBAllPeersBackupKeysAreInKeyBag(currentBSKB, filteredPeerInfos) ||
-                    !SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData);
+                if(SOSBSKBHasThisRecoveryKey(currentBSKB, recoveryKeyData) == false) {
+                    secnotice("ring", "BSKB is missing recovery key");
+                    fixBSKB = true;
+                }
 
                 if(fixBSKB) {
                     CFErrorRef localError = NULL;
                     CFSetRef viewSet = SOSRingGetBackupViewset(newRing, NULL);
+                    secnotice("ring", "Need to fix BSKB - this will prompt a gensign");
+
                     SOSBackupSliceKeyBagRef bskb = NULL;
                     if(recoveryKeyData) {
                         CFMutableDictionaryRef additionalKeys = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
@@ -498,6 +493,7 @@ errOut:
         } else {
             CFErrorRef signingError = NULL;
             if (fpi && SOSRingConcordanceSign(newRing, fpi, &signingError)) {
+                secnotice("ring", "concordance signed");
                 ringToPush = newRing;
                 ringAction = accept;
             } else {
@@ -515,10 +511,12 @@ leaveAndAccept:
         if(ringIsRecovery) {
             if(!localUpdate) { // processing a remote ring - we accept the new recovery key here
                 if(SOSRingIsEmpty_Internal(newRing)) { // Reset ring will reset the recovery key
+                    secnotice("ring", "Reset ring for recovery from remote peer");
                     SOSRecoveryKeyBagRef ringRKBG = SOSRecoveryKeyBagCreateForAccount(kCFAllocatorDefault, (__bridge CFTypeRef)account, SOSRKNullKey(), error);
                     SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, ringRKBG, error);
                     CFReleaseNull(ringRKBG);
                 } else {                                // normal ring recovery key harvest
+                    secnotice("ring", "normal ring recovery key harvest");
                     SOSRecoveryKeyBagRef ringRKBG = SOSRingCopyRecoveryKeyBag(newRing, NULL);
                     SOSAccountSetRecoveryKeyBagEntry(kCFAllocatorDefault, account, ringRKBG, error);
                     CFReleaseNull(ringRKBG);
index 0bd9cd2267cb47a534eaae2907e02de802bc2687..0789068713779a46567d822d4f17b5f020c530e8 100644 (file)
@@ -17,7 +17,7 @@
 -(bool) fullPeerInfoVerify:(SecKeyRef) privKey err:(CFErrorRef *)error;
 -(bool) hasFullPeerInfo:(CFErrorRef*) error;
 -(SOSFullPeerInfoRef) CopyAccountIdentityPeerInfo CF_RETURNS_RETAINED;
--(bool) ensureFullPeerAvailable:(CFDictionaryRef)gestalt deviceID:(CFStringRef)deviceID backupKey:(CFDataRef)backup err:(CFErrorRef *) error;
+-(bool) ensureFullPeerAvailable:(SOSAccount*)account err:(CFErrorRef *) error;
 -(bool) isMyPeerActive:(CFErrorRef*) error;
 -(void) purgeIdentity;
 
index d72bd1257d291184fd3486f35f6f7ffac25b41f5..1cca6e0642a4d79e53350a064a0ae1fe715dd434 100644 (file)
 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Expansion.h"
 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Identity.h"
 #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
+#import <SecurityFoundation/SFSigningOperation.h>
+#import <SecurityFoundation/SFKey.h>
+#import <SecurityFoundation/SFKey_Private.h>
+#import <SecurityFoundation/SFDigestOperation.h>
 #if __OBJC2__
 #import "Analytics/Clients/SOSAnalytics.h"
 #endif // __OBJC2__
         secnotice("circleChange", "Already have Octagon signing key");
         CFReleaseNull(self->_cachedOctagonSigningKey);
         _cachedOctagonSigningKey = SecKeyCopyPublicKey(octagonSigningFullKey);
+
+        // Ensure that the agrp is correct.
+        SOSCCEnsureAccessGroupOfKey(_cachedOctagonSigningKey, @"sync", (__bridge NSString*)kSOSInternalAccessGroup);
+
     } else if (octagonSigningFullKey == NULL && copyError &&
         ((CFEqualSafe(CFErrorGetDomain(copyError), kCFErrorDomainOSStatus) && CFErrorGetCode(copyError) == errSecItemNotFound) ||
          (CFEqualSafe(CFErrorGetDomain(copyError), kCFErrorDomainOSStatus) && CFErrorGetCode(copyError) == errSecDecode) ||
         secnotice("circleChange", "Already have Octagon encryption key");
         CFReleaseNull(self->_cachedOctagonEncryptionKey);
         _cachedOctagonEncryptionKey = SecKeyCopyPublicKey(octagonEncryptionFullKey);
+
+        SOSCCEnsureAccessGroupOfKey(_cachedOctagonEncryptionKey, @"sync", (__bridge NSString*)kSOSInternalAccessGroup);
     } else if (octagonEncryptionFullKey == NULL && copyError &&
         ((CFEqualSafe(CFErrorGetDomain(copyError), kCFErrorDomainOSStatus) && CFErrorGetCode(copyError) == errSecItemNotFound) ||
          (CFEqualSafe(CFErrorGetDomain(copyError), kCFErrorDomainOSStatus) && CFErrorGetCode(copyError) == errSecDecode) ||
 #endif /* OCTAGON */
 }
 
--(bool) ensureFullPeerAvailable:(CFDictionaryRef)gestalt deviceID:(CFStringRef)deviceID backupKey:(CFDataRef)backup err:(CFErrorRef *) error
+-(bool) ensureFullPeerAvailable:(SOSAccount*) account err:(CFErrorRef *) error
 {
     require_action_quiet(self.trustedCircle, fail, SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("Don't have circle")));
-    
-    if (self.fullPeerInfo == NULL) {
+
+    if (self.fullPeerInfo == NULL || !SOSFullPeerInfoPrivKeyExists(self.fullPeerInfo)) {
+        if(self.fullPeerInfo) { // fullPeerInfo where privkey is gone
+            secnotice("circleOps", "FullPeerInfo has no matching private key - resetting FPI and attendant keys");
+            CFReleaseNull(self->fullPeerInfo);
+            if(self->peerInfo) CFReleaseNull(self->peerInfo);
+            if(self->_cachedOctagonSigningKey) CFReleaseNull(self->_cachedOctagonSigningKey);
+            if(self->_cachedOctagonEncryptionKey) CFReleaseNull(self->_cachedOctagonEncryptionKey);
+        }
+        
+        SecKeyRef fullKey = NULL;
         bool skipInitialSync = false; // This will be set if the set of initial sync views is empty
         NSString* octagonKeyName;
-        CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName(gestalt), SOSCircleGetName(self.trustedCircle));
-        SecKeyRef full_key = [self randomPermanentFullECKey:256 name:(__bridge NSString *)keyName error:NULL];
+        CFStringRef keyName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("ID for %@-%@"), SOSPeerGestaltGetName((__bridge CFDictionaryRef)(account.gestalt)), SOSCircleGetName(self.trustedCircle));
+        fullKey = [self randomPermanentFullECKey:256 name:(__bridge NSString *)keyName error:NULL];
         
         octagonKeyName = [@"Octagon Peer Signing " stringByAppendingString:(__bridge NSString*)keyName];
-        SecKeyRef octagonSigningFullKey = [self randomPermanentFullECKey:384 name:octagonKeyName error:NULL];
+
+        SecKeyRef octagonSigningFullKey = NULL;
+        if (account.octagonSigningFullKeyRef != NULL) {
+            octagonSigningFullKey = CFRetainSafe(account.octagonSigningFullKeyRef);
+        } else {
+            octagonSigningFullKey = [self randomPermanentFullECKey:384 name:octagonKeyName error:NULL];
+        }
 
         octagonKeyName = [@"Octagon Peer Encryption " stringByAppendingString:(__bridge NSString*)keyName];
-        SecKeyRef octagonEncryptionFullKey = [self randomPermanentFullECKey:384 name:octagonKeyName error:NULL];
 
-        if (full_key && octagonSigningFullKey && octagonEncryptionFullKey) {
+        SecKeyRef octagonEncryptionFullKey = NULL;
+        if (account.octagonEncryptionFullKeyRef != NULL){
+            octagonEncryptionFullKey = CFRetainSafe(account.octagonEncryptionFullKeyRef);
+        } else {
+            octagonEncryptionFullKey = [self randomPermanentFullECKey:384 name:octagonKeyName error:NULL];
+        }
+
+        if (fullKey && octagonSigningFullKey && octagonEncryptionFullKey) {
             CFMutableSetRef initialViews = SOSViewCopyViewSet(kViewSetInitial);
             CFMutableSetRef initialSyncDoneViews = SOSViewCopyViewSet(kViewSetAlwaysOn);
             CFSetRef defaultViews = SOSViewCopyViewSet(kViewSetDefault);
 
             // setting fullPeerInfo takes an extra ref, so...
             self.fullPeerInfo = nil;
-            SOSFullPeerInfoRef fpi = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, gestalt, backup, initialViews, full_key, octagonSigningFullKey, octagonEncryptionFullKey, error);
+            SOSFullPeerInfoRef fpi = SOSFullPeerInfoCreateWithViews(kCFAllocatorDefault, (__bridge CFDictionaryRef)(account.gestalt), (__bridge CFDataRef)(account.backup_key), initialViews, fullKey, octagonSigningFullKey, octagonEncryptionFullKey, error);
             self.fullPeerInfo = fpi;
+            SecKeyRef pubKey = SOSFullPeerInfoCopyPubKey(fpi, NULL);
+            account.peerPublicKey = pubKey;
+            CFReleaseNull(pubKey);
+            if(!account.peerPublicKey) {
+                secnotice("circleOp", "Failed to copy peer public key for account object");
+            }
             CFReleaseNull(fpi);
 
             CFDictionaryRef v2dictionaryTestUpdates = [self getValueFromExpansion:kSOSTestV2Settings err:NULL];
             
         }
 
-        CFReleaseNull(full_key);
+        CFReleaseNull(fullKey);
         CFReleaseNull(octagonSigningFullKey);
         CFReleaseNull(octagonEncryptionFullKey);
         CFReleaseNull(keyName);
@@ -292,7 +329,7 @@ fail:
         // Purge private key but don't return error if we can't.
         CFErrorRef purgeError = NULL;
         if (!SOSFullPeerInfoPurgePersistentKey(self.fullPeerInfo, &purgeError)) {
-            secwarning("Couldn't purge persistent key for %@ [%@]", self.fullPeerInfo, purgeError);
+            secwarning("Couldn't purge persistent keys for %@ [%@]", self.fullPeerInfo, purgeError);
         }
         CFReleaseNull(purgeError);
         
index a1a2e2378d9bda675f218aea970fe856c7e81b42..0188cf3602726dc840ddd0e3956b346f442e1854 100644 (file)
@@ -32,7 +32,7 @@
 //Views
 -(SOSViewResultCode) updateView:(SOSAccount*)account name:(CFStringRef) viewname code:(SOSViewActionCode) actionCode err:(CFErrorRef *)error;
 -(SOSViewResultCode) viewStatus:(SOSAccount*)account name:(CFStringRef) viewname err:(CFErrorRef *)error;
--(bool) updateViewSetsWithAnalytics:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews parentEvent:(NSData*)parentEvent;
+-(bool) updateViewSets:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews;
 
 -(CFSetRef) copyPeerSetForView:(CFStringRef) viewName;
 
index 104596378483bb9c8175a3140705fa883f29528f..7683126037c2ebe8275c0af3d6db5a1bfbf11e19 100644 (file)
@@ -36,9 +36,7 @@ extern CFStringRef kSOSAccountDebugScope;
 
 -(id)init
 {
-    self = [super init];
-    if(self)
-    {
+    if ((self = [super init])) {
         self.retirees = [NSMutableSet set];
         self.fullPeerInfo = NULL;
         self.trustedCircle = NULL;
@@ -52,9 +50,7 @@ extern CFStringRef kSOSAccountDebugScope;
 -(id)initWithRetirees:(NSMutableSet*)r fpi:(SOSFullPeerInfoRef)fpi circle:(SOSCircleRef) trusted_circle
         departureCode:(enum DepartureReason)code peerExpansion:(NSMutableDictionary*)e
 {
-    self = [super init];
-    if(self)
-    {
+    if ((self = [super init])) {
         self.retirees = [[NSMutableSet alloc] initWithSet:r] ;
         self.fullPeerInfo = CFRetainSafe(fpi);
         self.trustedCircle = CFRetainSafe(trusted_circle);
@@ -211,21 +207,11 @@ static bool SOSAccountScreenViewListForValidV0(SOSAccount*  account, CFMutableSe
     return retval;
 }
 
--(bool) updateViewSetsWithAnalytics:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews parentEvent:(NSData*)parentEvent
+-(bool) updateViewSets:(SOSAccount*)account enabled:(CFSetRef) origEnabledViews disabled:(CFSetRef) origDisabledViews
 {
     bool retval = false;
     bool updateCircle = false;
     SOSPeerInfoRef  pi = NULL;
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = NULL;
-    bool doAnalytics = (parentEvent != NULL);
-    
-    if(doAnalytics) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
-    }
-
-    SFSignInAnalytics *hasCompletedInitialSyncEvent = nil;
-    SFSignInAnalytics *updatePeerInCircleEvent = nil;
 
     CFMutableSetRef enabledViews = NULL;
     CFMutableSetRef disabledViews = NULL;
@@ -263,9 +249,7 @@ static bool SOSAccountScreenViewListForValidV0(SOSAccount*  account, CFMutableSe
 
     require_action_quiet(SOSAccountScreenViewListForValidV0(account, enabledViews, kSOSCCViewEnable), errOut, secnotice("viewChange", "Bad view change (enable) with kSOSViewKeychainV0"));
     require_action_quiet(SOSAccountScreenViewListForValidV0(account, disabledViews, kSOSCCViewDisable), errOut, secnotice("viewChange", "Bad view change (disable) with kSOSViewKeychainV0"));
-    if(doAnalytics) {
-        hasCompletedInitialSyncEvent = [parent newSubTaskForEvent:@"hasCompletedInitialSyncEvent"];
-    }
+
     if(SOSAccountHasCompletedInitialSync(account)) {
         if(enabledViews) updateCircle |= SOSViewSetEnable(pi, enabledViews);
         if(disabledViews) updateCircle |= SOSViewSetDisable(pi, disabledViews);
@@ -276,31 +260,21 @@ static bool SOSAccountScreenViewListForValidV0(SOSAccount*  account, CFMutableSe
         if(disabledViews) SOSAccountPendDisableViewSet(account, disabledViews);
         retval = true;
     }
-    if(doAnalytics) {
-        [hasCompletedInitialSyncEvent stopWithAttributes:nil];
-    }
+
     if(updateCircle) {
         /* UPDATE FULLPEERINFO VIEWS */
         require_quiet(SOSFullPeerInfoUpdateToThisPeer(fpi, pi, NULL), errOut);
-        if(doAnalytics) {
-            updatePeerInCircleEvent = [parent newSubTaskForEvent:@"updatePeerInCircleEvent"];
-        }
+
         require_quiet([self modifyCircle:account.circle_transport err:NULL action:^(SOSCircleRef circle_to_change) {
             secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for views or peerInfo change");
             bool updated= SOSCircleUpdatePeerInfo(circle_to_change, self.peerInfo);
             return updated;
         }], errOut);
-        if(doAnalytics) {
-            [updatePeerInCircleEvent stopWithAttributes:nil];
-        }
         // Make sure we update the engine
         account.circle_rings_retirements_need_attention = true;
     }
 
 errOut:
-    if(doAnalytics) {
-        [updatePeerInCircleEvent stopWithAttributes:nil];
-    }
     CFReleaseNull(enabledViews);
     CFReleaseNull(disabledViews);
     CFReleaseNull(pi);
@@ -564,7 +538,7 @@ static size_t der_sizeof_data_optional(CFDataRef data)
     require_quiet(accumulate_size(&sequence_size, ccder_sizeof_bool(account.accountKeyIsTrusted, &failure)),          fail);
     require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account.accountKey, &failure)),            fail);
     require_quiet(accumulate_size(&sequence_size, der_sizeof_public_bytes(account.previousAccountKey, &failure)),        fail);
-    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null((__bridge CFDataRef)account.accountKeyDerivationParamters, &failure)),    fail);
+    require_quiet(accumulate_size(&sequence_size, der_sizeof_data_or_null((__bridge CFDataRef)account.accountKeyDerivationParameters, &failure)),    fail);
     require_quiet(accumulate_size(&sequence_size, SOSPeerInfoSetGetDEREncodedArraySize((__bridge CFSetRef)self.retirees, &failure)),  fail);
     (void)accumulate_size(&sequence_size, der_sizeof_data_optional((__bridge CFDataRef)(account.backup_key)));
     require_quiet(accumulate_size(&sequence_size, der_sizeof_dictionary((__bridge CFDictionaryRef)(self.expansion), &failure)),  fail);
@@ -605,7 +579,7 @@ static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error,
                                         ccder_encode_bool(account.accountKeyIsTrusted, der,
                                         der_encode_public_bytes(account.accountKey, &failure, der,
                                         der_encode_public_bytes(account.previousAccountKey, &failure, der,
-                                        der_encode_data_or_null((__bridge CFDataRef)(account.accountKeyDerivationParamters), &failure, der,
+                                        der_encode_data_or_null((__bridge CFDataRef)(account.accountKeyDerivationParameters), &failure, der,
                                         SOSPeerInfoSetEncodeToArrayDER((__bridge CFSetRef)(self.retirees), &failure, der,
                                         der_encode_data_optional((__bridge CFDataRef)account.backup_key, &failure, der,
                                         der_encode_dictionary((__bridge CFDictionaryRef)(self.expansion), &failure, der,
@@ -717,6 +691,11 @@ static uint8_t* der_encode_data_optional(CFDataRef data, CFErrorRef *error,
 
 -(SOSEngineRef) getDataSourceEngine:(SOSDataSourceFactoryRef)factory
 {
+    // This is at least a piece of <rdar://problem/59045931> SecItemDataSourceFactoryCopyDataSource; looks like UaF
+    if(!self.trustedCircle) {
+        secnotice("engine", "Tried to set dataSourceEngine with no circle");
+        return NULL;
+    }
     return SOSDataSourceFactoryGetEngineForDataSourceName(factory, SOSCircleGetName(self.trustedCircle), NULL);
 }
 
index 9c0cad82bce4d5ffd64c75fd6184e09efaf03c71..f409827663026820635caa4af55db26c39d644c8 100644 (file)
@@ -162,6 +162,8 @@ bool SOSAccountSyncingV0(SOSAccount* account) {
 
 void SOSAccountNotifyEngines(SOSAccount* account)
 {
+    dispatch_assert_queue(account.queue);
+
     SOSAccountTrustClassic *trust = account.trust;
     SOSFullPeerInfoRef identity = trust.fullPeerInfo;
     SOSCircleRef circle = trust.trustedCircle;
@@ -179,7 +181,10 @@ void SOSAccountNotifyEngines(SOSAccount* account)
         // We add V0 views to everyone if we see a V0 peer, or a peer with the view explicity enabled
         // V2 peers shouldn't be explicity enabling the uber V0 view, though the seeds did.
         __block bool addV0Views = SOSAccountSyncingV0(account);
-        
+
+        bool selfSupportCKKSForAll = SOSPeerInfoSupportsCKKSForAll(myPi);
+        secnotice("engine-notify", "Self peer(%@) %@ CKKS For All", myPi_id, selfSupportCKKSForAll ? @"supports" : @"doesn't support");
+
         syncing_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
         zombie_peer_metas = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
         SOSAccountForEachCirclePeerExceptMe(account, ^(SOSPeerInfoRef peer) {
@@ -193,6 +198,12 @@ void SOSAccountNotifyEngines(SOSAccount* account)
             if(addV0Views) {
                 CFSetAddValue(views, kSOSViewKeychainV0);
             }
+
+            // If this peer supports CKKS4All, let's sync zero views to it.
+            if(selfSupportCKKSForAll && SOSPeerInfoSupportsCKKSForAll(peer)) {
+                secnotice("engine-notify", "Peer %@ supports CKKS For All; ignoring in SOS syncing", SOSPeerInfoGetPeerID(peer));
+                CFSetRemoveAllValues(views);
+            }
             
             CFStringSetPerformWithDescription(views, ^(CFStringRef viewsDescription) {
                 secnotice("engine-notify", "Meta: %@: %@", SOSPeerInfoGetPeerID(peer), viewsDescription);
@@ -345,6 +356,12 @@ bool SOSAccountHandleCircleMessage(SOSAccount* account,
                                    CFStringRef circleName, CFDataRef encodedCircleMessage, CFErrorRef *error) {
     bool success = false;
     CFErrorRef localError = NULL;
+
+    if(account && account.accountIsChanging) {
+        secnotice("circleOps", "SOSAccountHandleCircleMessage called before signing in to new account");
+        return true; // we want to drop circle notifications when account is changing
+    }
+
     SOSCircleRef circle = SOSAccountCreateCircleFrom(circleName, encodedCircleMessage, &localError);
     if (circle) {
         success = [account.trust updateCircleFromRemote:account.circle_transport newCircle:circle err:&localError];
@@ -372,14 +389,20 @@ bool SOSAccountHandleCircleMessage(SOSAccount* account,
 }
 
 bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef parameters, CFErrorRef *error){
+    if(account && account.accountIsChanging) {
+        secnotice("circleOps", "SOSAccountHandleParametersChange called before signing in to new account");
+        return true; // we want to drop parm notifications when account is changing
+    }
     
     SecKeyRef newKey = NULL;
-    CFDataRef newParameters = NULL;
+    CFDataRef pbkdfParams = NULL;
     bool success = false;
     
-    if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &newParameters, error)) {
-        debugDumpUserParameters(CFSTR("SOSAccountHandleParametersChange got new user key parameters:"), parameters);
-        secnotice("circleOps", "SOSAccountHandleParametersChange got new public key: %@", newKey);
+    if(SOSAccountRetrieveCloudParameters(account, &newKey, parameters, &pbkdfParams, error)) {
+        debugDumpUserParameters(CFSTR("SOSAccountHandleParametersChange got new user key parameters:"), pbkdfParams);
+        CFStringRef keyid = SOSCopyIDOfKeyWithLength(newKey, 8, NULL);
+        secnotice("circleOps", "SOSAccountHandleParametersChange got new public key: %@", keyid);
+        CFReleaseNull(keyid);
 
         if (CFEqualSafe(account.accountKey, newKey)) {
             secnotice("circleOps", "Got same public key sent our way. Ignoring.");
@@ -390,7 +413,7 @@ bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef parameters,
         } else {
             SOSAccountSetUnTrustedUserPublicKey(account, newKey);
             CFReleaseNull(newKey);
-            SOSAccountSetParameters(account, newParameters);
+            SOSAccountSetParameters(account, pbkdfParams);
 
             if(SOSAccountRetryUserCredentials(account)) {
                 secnotice("circleOps", "Successfully used cached password with new parameters");
@@ -408,7 +431,7 @@ bool SOSAccountHandleParametersChange(SOSAccount* account, CFDataRef parameters,
     }
     
     CFReleaseNull(newKey);
-    CFReleaseNull(newParameters);
+    CFReleaseNull(pbkdfParams);
     
     return success;
 }
index f619a750f7b5c37b6b560d8e775d7753eb8f3f3e..c592b0bd59585d37f3f022d353979c136e37bee4 100644 (file)
@@ -185,7 +185,7 @@ static bool SOSAccountResolvePendingViewSets(SOSAccount* account, CFErrorRef *er
     }
     CFReleaseNull(defaultOn);
 
-    bool status = [account.trust updateViewSetsWithAnalytics:account enabled:newPending disabled:pendingDisabled parentEvent: NULL];
+    bool status = [account.trust updateViewSets:account enabled:newPending disabled:pendingDisabled];
     CFReleaseNull(newPending);
 
     if(status){
index 03ea585d16dfff6c0be4428ae75ea0499b52cd6f..36ca8e09a1d1b01a36eee9ac763e4c8c9aeebc13 100644 (file)
@@ -30,7 +30,6 @@ SOFT_LINK_CLASS(AuthKit, AKAccountManager);
 SOFT_LINK_CLASS(AuthKit, AKAnisetteProvisioningController);
 SOFT_LINK_CLASS(AuthKit, AKAppleIDAuthenticationController);
 SOFT_LINK_CLASS(AuthKit, AKDeviceListRequestContext);
-SOFT_LINK_CLASS(Accounts, Accounts);
 SOFT_LINK_CLASS(Accounts, ACAccountStore);
 SOFT_LINK_CONSTANT(AuthKit, AKServiceNameiCloud, const NSString *);
 #pragma clang diagnostic pop
@@ -189,29 +188,27 @@ static ACAccount *GetPrimaryAccount(void) {
 
 -(id) initWithActiveMIDS: (NSSet <SOSTrustedDeviceAttributes *> *) theMidList
 {
-    self = [super init];
-    if(!self){
-        return nil;
-    }
-    NSMutableSet *MmachineIDs = [[NSMutableSet alloc] init];
-    NSMutableSet *MserialNumbers = [[NSMutableSet alloc] init];
-    _machineIDs = [[NSSet alloc] init];
-    _serialNumbers = [[NSSet alloc] init];
-
-    if(!theMidList) return nil;
-    _midList = theMidList;
+    if ((self = [super init])) {
+        NSMutableSet *MmachineIDs = [[NSMutableSet alloc] init];
+        NSMutableSet *MserialNumbers = [[NSMutableSet alloc] init];
+        _machineIDs = [[NSSet alloc] init];
+        _serialNumbers = [[NSSet alloc] init];
+
+        if(!theMidList) return nil;
+        _midList = theMidList;
+
+        for(SOSTrustedDeviceAttributes *dev in _midList) {
+            if(dev.machineID) {
+                [MmachineIDs addObject:dev.machineID];
+            }
+            if(dev.serialNumber) {
+                [MserialNumbers addObject:dev.serialNumber];
+            }
 
-    for(SOSTrustedDeviceAttributes *dev in _midList) {
-        if(dev.machineID) {
-            [MmachineIDs addObject:dev.machineID];
-        }
-        if(dev.serialNumber) {
-            [MserialNumbers addObject:dev.serialNumber];
         }
-
+        _machineIDs = MmachineIDs;
+        _serialNumbers = MserialNumbers;
     }
-    _machineIDs = MmachineIDs;
-    _serialNumbers = MserialNumbers;
     return self;
 }
 
index f41ad4b67d1d9758b390cefd268642caab22bcb9..847f74633f2abb3f9a2f34c3dfb3db1ae3480ea9 100644 (file)
@@ -49,7 +49,6 @@
 #include <Security/SecRecoveryKey.h>
 #include "SOSKeyedPubKeyIdentifier.h"
 #include "keychain/SecureObjectSync/SOSInternal.h"
-#include "SecADWrapper.h"
 #include "SecCFAllocator.h"
 
 CFStringRef bskbRkbgPrefix = CFSTR("RK");
@@ -131,10 +130,10 @@ const uint8_t* der_decode_BackupSliceKeyBag(CFAllocatorRef allocator,
     der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
     require_quiet(sequence_end == der_end, fail);
 
-    der = der_decode_data(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->aks_bag, error, der, sequence_end);
+    der = der_decode_data(kCFAllocatorDefault, &vb->aks_bag, error, der, sequence_end);
     vb->peers = SOSPeerInfoSetCreateFromArrayDER(kCFAllocatorDefault, &kSOSPeerSetCallbacks, error,
                                                  &der, der_end);
-    der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &vb->wrapped_keys, error, der, sequence_end);
+    der = der_decode_dictionary(kCFAllocatorDefault, &vb->wrapped_keys, error, der, sequence_end);
 
     require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail);
 
@@ -489,17 +488,17 @@ bool SOSBKSBPeerBackupKeyIsInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, S
     return result;
 }
 
-// returns true if all peers in (peers) and only those peers have matching backupKeys in the BSKB
 bool SOSBSKBAllPeersBackupKeysAreInKeyBag(SOSBackupSliceKeyBagRef backupSliceKeyBag, CFSetRef peers) {
-    __block bool result = false;
+    // earlier we had to accept BSKBs listing peers without backup keys for compatibility.  For that reason
+    // this routine will iterate over the peers given and only disqualify the BSKB if it doesn't include the backup key of a peer with one.
+    __block bool result = true;
     if(backupSliceKeyBag && peers) {
-        result = (SOSBSKBCountPeers(backupSliceKeyBag) == CFSetGetCount(peers));
-        if(result) {
-            CFSetForEach(peers, ^(const void *value) {
-                SOSPeerInfoRef pi = asSOSPeerInfo(value);
-                result &= pi && SOSBKSBPeerBackupKeyIsInKeyBag(backupSliceKeyBag, pi);
-            });
-        }
+        CFSetForEach(peers, ^(const void *value) {
+            SOSPeerInfoRef pi = asSOSPeerInfo(value);
+            if(pi && SOSPeerInfoHasBackupKey(pi)) {
+                result &= SOSBKSBPeerBackupKeyIsInKeyBag(backupSliceKeyBag, pi);
+            }
+        });
     }
     return result;
 }
index 0b68d4bcb3808248060b32aead63c8bde1e83db4..4731c9a892348be50000625d87b7af2fd4a41890 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "keychain/SecureObjectSync/SOSDataSource.h"
 
+#include "utilities/simulatecrash_assert.h"
+
 __BEGIN_DECLS
 
 enum {
index b80f1e0dc85b6f7ca156875eaa1011e1dc82d10a..4dc4ff301a79027dd0a76f30dfe6265e48017604 100644 (file)
@@ -59,7 +59,7 @@
 #include <corecrypto/ccsha2.h>
 
 #include <stdlib.h>
-#include <assert.h>
+#include <utilities/simulatecrash_assert.h>
 
 CFGiblisWithCompareFor(SOSCircle);
 
index b44e928752d51f4a27beb2bfb6fffbcaff6e59a3..f60ee4ce01095b7567e53840fb2af42f828b8f80 100644 (file)
 #include <utilities/der_plist_internal.h>
 #include <corecrypto/ccder.h>
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSCircleDer.h"
 
-static const uint8_t* der_decode_mutable_dictionary(CFAllocatorRef allocator, CFOptionFlags mutability,
-                                                    CFMutableDictionaryRef* dictionary, CFErrorRef *error,
-                                                    const uint8_t* der, const uint8_t *der_end)
-{
-    CFDictionaryRef theDict;
-    const uint8_t* result = der_decode_dictionary(allocator, mutability, &theDict, error, der, der_end);
-    
-    if (result != NULL)
-        *dictionary = (CFMutableDictionaryRef)theDict;
-    
-    return result;
-}
-
-
 SOSCircleRef SOSCircleCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
                                     const uint8_t** der_p, const uint8_t *der_end) {
     SOSCircleRef cir = CFTypeAllocate(SOSCircle, struct __OpaqueSOSCircle, allocator);
@@ -70,15 +55,17 @@ SOSCircleRef SOSCircleCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
     require_action_quiet(version == kOnlyCompatibleVersion, fail,
                          SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Bad Circle Version"), NULL, error));
     
-    *der_p = der_decode_string(allocator, 0, &cir->name, error, *der_p, sequence_end);
+    *der_p = der_decode_string(allocator, &cir->name, error, *der_p, sequence_end);
     cir->generation = SOSGenCountCreateFromDER(kCFAllocatorDefault, error, der_p, sequence_end);
     
     cir->peers = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
     cir->applicants = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
     cir->rejected_applicants = SOSPeerInfoSetCreateFromArrayDER(allocator, &kSOSPeerSetCallbacks, error, der_p, sequence_end);
     
-    *der_p = der_decode_mutable_dictionary(allocator, kCFPropertyListMutableContainersAndLeaves,
-                                           &cir->signatures, error, *der_p, sequence_end);
+    CFDictionaryRef tmp = NULL;
+    *der_p = der_decode_dictionary(allocator, &tmp, error, *der_p, sequence_end);
+    cir->signatures = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, tmp);
+    CFReleaseNull(tmp);
     
     require_action_quiet(*der_p == sequence_end, fail,
                          SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Circle DER"), (error != NULL) ? *error : NULL, error));
@@ -192,7 +179,7 @@ const uint8_t* der_decode_data_or_null(CFAllocatorRef allocator, CFDataRef* data
                                        const uint8_t* der, const uint8_t* der_end)
 {
     CFTypeRef value = NULL;
-    der = der_decode_plist(allocator, 0, &value, error, der, der_end);
+    der = der_decode_plist(allocator, &value, error, der, der_end);
     if (value && CFGetTypeID(value) != CFDataGetTypeID()) {
         CFReleaseNull(value);
     }
index 79852a34d1ba501830a6f2f2326aac15d65e8da5..21aa0947467a87654e564bf7ac6ca75ff13a401f 100644 (file)
@@ -13,6 +13,8 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include "keychain/SecureObjectSync/SOSGenCount.h"
 
+#include <security_utilities/simulatecrash_assert.h>
+
 enum {
     kOnlyCompatibleVersion = 1, // Sometime in the future this name will be improved to reflect history.
     kAlwaysIncompatibleVersion = UINT64_MAX,
index 0f3df9b60b6e81dc9d6bf2cc94d73632a889d5ee..4026c2996925cbda501d3dea6ee74d4ae16f7c5e 100644 (file)
@@ -39,7 +39,6 @@
 
 #include <Security/SecureObjectSync/SOSTypes.h>
 #include <Security/SecureObjectSync/SOSPeerInfo.h>
-#import <Security/SFSignInAnalytics.h>
 
 __BEGIN_DECLS
 
@@ -72,6 +71,7 @@ enum {
 typedef CF_OPTIONS(uint32_t, SOSInitialSyncFlags) {
     kSOSInitialSyncFlagTLKs = (1UL << 0),
     kSOSInitialSyncFlagiCloudIdentity = (1UL << 1),
+    kSOSInitialSyncFlagTLKsRequestOnly = (1UL << 2), // Note that this overrides the other two flags, as it's used for aborting the piggybacking session early and returning a very small number of TLKs
 };
 
 
@@ -126,7 +126,6 @@ bool SOSCCSetUserCredentials(CFStringRef user_label, CFDataRef user_password, CF
  */
 
 bool SOSCCSetUserCredentialsAndDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error);
-bool SOSCCSetUserCredentialsAndDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentevent, CFErrorRef *error);
 
 /*!
  @function SOSCCTryUserCredentials
@@ -158,7 +157,6 @@ bool SOSCCRegisterUserCredentials(CFStringRef user_label, CFDataRef user_passwor
  @return if we waited successfully
  */
 bool SOSCCWaitForInitialSync(CFErrorRef* error);
-bool SOSCCWaitForInitialSyncWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
 
 /*!
  @function SOSCCCanAuthenticate
@@ -247,7 +245,6 @@ bool SOSCCIsContinuityUnlockSyncing(void);
  @discussion Requests to join the user's circle or all the pending circles (other than his) if there are multiple pending circles.
  */
 bool SOSCCRequestToJoinCircle(CFErrorRef* error);
-bool SOSCCRequestToJoinCircleWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
 
 
 /*!
@@ -258,7 +255,6 @@ bool SOSCCRequestToJoinCircleWithAnalytics(CFDataRef parentEvent, CFErrorRef* er
  @discussion Uses the cloud identity to get in the circle if it can. If it cannot it falls back on simple application.
  */
 bool SOSCCRequestToJoinCircleAfterRestore(CFErrorRef* error);
-bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
 
 /*!
  @function SOSCCAccountSetToNew
@@ -283,7 +279,6 @@ bool SOSCCResetToOffering(CFErrorRef* error);
  @result true if we posted the circle successfully. False if there was an error.
  */
 bool SOSCCResetToEmpty(CFErrorRef* error);
-bool SOSCCResetToEmptyWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
 
 /*!
  @function SOSCCRemoveThisDeviceFromCircle
@@ -294,7 +289,6 @@ bool SOSCCResetToEmptyWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
  */
 bool SOSCCRemoveThisDeviceFromCircle(CFErrorRef* error);
 
-bool SOSCCRemoveThisDeviceFromCircleWithAnalytics(CFDataRef parentEvent, CFErrorRef* error);
 
 /*!
  @function SOSCCRemoveThisDeviceFromCircle
@@ -306,14 +300,18 @@ bool SOSCCRemoveThisDeviceFromCircleWithAnalytics(CFDataRef parentEvent, CFError
              that we don't have the user credentail (need to prompt for password)
  */
 bool SOSCCRemovePeersFromCircle(CFArrayRef peerList, CFErrorRef* error);
-bool SOSCCRemovePeersFromCircleWithAnalytics(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error);
 
 /*!
- @function SOSCCRemoveThisDeviceFromCircle
- @abstract Removes the current device from the circle.
- @param error What went wrong trying to remove ourselves.
- @result true if we posted the removal. False if there was an error.
- @discussion This removes us from the circle.
+ @function SOSCCLoggedIntoAccount
+ @param error value set if there are xpc errors.
+ @abstract Notifies the account object that the device logged into an icloud account
+ */
+bool SOSCCLoggedIntoAccount(CFErrorRef* error);
+
+/*!
+ @function SOSCCLoggedOutOfAccount
+ @param error value set if there are xpc errors.
+ @abstract Removes the current device from the circle.  Clears the account object
  */
 bool SOSCCLoggedOutOfAccount(CFErrorRef* error);
 
@@ -578,7 +576,6 @@ SOSViewResultCode SOSCCView(CFStringRef view, SOSViewActionCode action, CFErrorR
  */
 
 bool SOSCCViewSet(CFSetRef enabledviews, CFSetRef disabledviews);
-bool SOSCCViewSetWithAnalytics(CFSetRef enabledviews, CFSetRef disabledviews, CFDataRef parentEvent);
 /*
  Security Attributes for PeerInfos
  
index a186bb76c64809e481a912de45e45684dcde2ede..98c8dcd5205487592f774f7b1e60369d41d55851 100644 (file)
@@ -84,8 +84,18 @@ static bool xpc_dictionary_entry_is_type(xpc_object_t dictionary, const char *ke
     return value && (xpc_get_type(value) == type);
 }
 
+static void setSOSDisabledError(CFErrorRef *error) {
+    SecCFCreateErrorWithFormat(0, kSOSErrorDomain, NULL, error, NULL, CFSTR("SOS Disabled for this platform"));
+}
+
 SOSCCStatus SOSCCThisDeviceIsInCircle(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return kSOSCCError;
+    }
+    
     SOSCCStatus retval = SOSGetCachedCircleStatus(error);
     if(retval != kSOSNoCachedValue) {
         secdebug("circleOps", "Retrieved cached circle value %d", retval);
@@ -97,6 +107,12 @@ SOSCCStatus SOSCCThisDeviceIsInCircle(CFErrorRef *error)
 
 SOSCCStatus SOSCCThisDeviceIsInCircleNonCached(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return kSOSCCError;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(SOSCCStatus, ^{
         SOSCCStatus result = kSOSCCError;
@@ -128,20 +144,6 @@ SOSCCStatus SOSCCThisDeviceIsInCircleNonCached(CFErrorRef *error)
     }, CFSTR("SOSCCStatus=%d"))
 }
 
-static bool sfsigninanalytics_bool_error_request(enum SecXPCOperation op, CFDataRef parentEvent, CFErrorRef* error)
-{
-    __block bool result = false;
-
-    secdebug("sosops","enter - operation: %d", op);
-    securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
-        return SecXPCDictionarySetData(message, kSecXPCKeySignInAnalytics, parentEvent, error);
-    }, ^bool(xpc_object_t response, __unused CFErrorRef *error) {
-        result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
-        return result;
-    });
-    return result;
-}
-
 static bool simple_bool_error_request(enum SecXPCOperation op, CFErrorRef* error)
 {
     __block bool result = false;
@@ -237,7 +239,7 @@ static CF_RETURNS_RETAINED CFArrayRef der_array_error_request(enum SecXPCOperati
     if (securityd_send_sync_and_do(op, error, NULL, ^bool(xpc_object_t response, CFErrorRef *error) {
         size_t length = 0;
         const uint8_t* bytes = xpc_dictionary_get_data(response, kSecXPCKeyResult, &length);
-        der_decode_plist(kCFAllocatorDefault, 0, (CFPropertyListRef*) &result, error, bytes, bytes + length);
+        der_decode_plist(kCFAllocatorDefault, (CFPropertyListRef*) &result, error, bytes, bytes + length);
 
         return result != NULL;
     })) {
@@ -447,24 +449,6 @@ static bool info_array_to_bool_error_request(enum SecXPCOperation op, CFArrayRef
     return result;
 }
 
-static bool info_array_data_to_bool_error_request(enum SecXPCOperation op, CFArrayRef peer_infos, CFDataRef parentEvent, CFErrorRef* error)
-{
-    __block bool result = false;
-
-    secdebug("sosops", "enter - operation: %d", op);
-    securityd_send_sync_and_do(op, error, ^bool(xpc_object_t message, CFErrorRef *error) {
-        SecXPCDictionarySetData(message, kSecXPCKeySignInAnalytics, parentEvent, error);
-        xpc_object_t encoded_peers = CreateXPCObjectWithArrayOfPeerInfo(peer_infos, error);
-        if (encoded_peers)
-            xpc_dictionary_set_value(message, kSecXPCKeyPeerInfoArray, encoded_peers);
-        return encoded_peers != NULL;
-    }, ^bool(xpc_object_t response, __unused CFErrorRef *error) {
-        result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
-        return result;
-    });
-    return result;
-}
-
 static bool uint64_t_to_bool_error_request(enum SecXPCOperation op,
                                            uint64_t number,
                                            CFErrorRef* error)
@@ -534,6 +518,12 @@ static CFDataRef cfdata_error_request_returns_cfdata(enum SecXPCOperation op, CF
 
 bool SOSCCRequestToJoinCircle(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_RequestToJoinCircle, error);
@@ -542,18 +532,14 @@ bool SOSCCRequestToJoinCircle(CFErrorRef* error)
     }, NULL)
 }
 
-bool SOSCCRequestToJoinCircleWithAnalytics(CFDataRef parentEvent, CFErrorRef* error)
-{
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_RequestToJoinCircleWithAnalytics, parentEvent, error);
-
-        return sfsigninanalytics_bool_error_request(kSecXPCOpRequestToJoinWithAnalytics, parentEvent, error);
-    }, NULL)
-}
-
 bool SOSCCRequestToJoinCircleAfterRestore(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_RequestToJoinCircleAfterRestore, error);
@@ -562,18 +548,14 @@ bool SOSCCRequestToJoinCircleAfterRestore(CFErrorRef* error)
     }, NULL)
 }
 
-bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics(CFDataRef parentEvent, CFErrorRef* error)
-{
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_RequestToJoinCircleAfterRestoreWithAnalytics, parentEvent, error);
-
-        return sfsigninanalytics_bool_error_request(kSecXPCOpRequestToJoinAfterRestoreWithAnalytics, parentEvent, error);
-    }, NULL)
-}
-
 bool SOSCCAccountHasPublicKey(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+    
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_AccountHasPublicKey, error);
@@ -583,18 +565,14 @@ bool SOSCCAccountHasPublicKey(CFErrorRef *error)
     
 }
 
-bool SOSCCWaitForInitialSyncWithAnalytics(CFDataRef parentEvent, CFErrorRef* error)
-{
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_WaitForInitialSyncWithAnalytics, parentEvent, error);
-
-        return sfsigninanalytics_bool_error_request(kSecXPCOpWaitForInitialSyncWithAnalytics, parentEvent, error);
-    }, NULL)
-}
-
 bool SOSCCWaitForInitialSync(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_WaitForInitialSync, error);
@@ -605,6 +583,12 @@ bool SOSCCWaitForInitialSync(CFErrorRef* error)
 
 bool SOSCCAccountSetToNew(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
        secwarning("SOSCCAccountSetToNew called");
        sec_trace_enter_api(NULL);
        sec_trace_return_bool_api(^{
@@ -615,6 +599,12 @@ bool SOSCCAccountSetToNew(CFErrorRef *error)
 
 bool SOSCCResetToOffering(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secwarning("SOSCCResetToOffering called");
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
@@ -626,6 +616,12 @@ bool SOSCCResetToOffering(CFErrorRef* error)
 
 bool SOSCCResetToEmpty(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secwarning("SOSCCResetToEmpty called");
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
@@ -635,18 +631,14 @@ bool SOSCCResetToEmpty(CFErrorRef* error)
     }, NULL)
 }
 
-bool SOSCCResetToEmptyWithAnalytics(CFDataRef parentEvent, CFErrorRef* error)
-{
-    secwarning("SOSCCResetToEmptyWithAnalytics called");
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_ResetToEmptyWithAnalytics, parentEvent, error);
-
-        return sfsigninanalytics_bool_error_request(kSecXPCOpResetToEmptyWithAnalytics, parentEvent, error);
-    }, NULL)
-}
 bool SOSCCRemovePeersFromCircle(CFArrayRef peers, CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_RemovePeersFromCircle, peers, error);
@@ -655,38 +647,39 @@ bool SOSCCRemovePeersFromCircle(CFArrayRef peers, CFErrorRef* error)
     }, NULL)
 }
 
-bool SOSCCRemovePeersFromCircleWithAnalytics(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error)
+bool SOSCCRemoveThisDeviceFromCircle(CFErrorRef* error)
 {
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_RemovePeersFromCircleWithAnalytics, peers, parentEvent, error);
-
-        return info_array_data_to_bool_error_request(kSecXPCOpRemovePeersFromCircleWithAnalytics, peers, parentEvent, error);
-    }, NULL)
-}
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
 
-bool SOSCCRemoveThisDeviceFromCircleWithAnalytics(CFDataRef parentEvent, CFErrorRef* error)
-{
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
-        do_if_registered(soscc_RemoveThisDeviceFromCircleWithAnalytics, parentEvent, error);
-
-        return sfsigninanalytics_bool_error_request(kSecXPCOpRemoveThisDeviceFromCircleWithAnalytics, parentEvent, error);
+        do_if_registered(soscc_RemoveThisDeviceFromCircle, error);
+        
+        return simple_bool_error_request(kSecXPCOpRemoveThisDeviceFromCircle, error);
     }, NULL)
 }
 
-bool SOSCCRemoveThisDeviceFromCircle(CFErrorRef* error)
-{
+bool SOSCCLoggedIntoAccount(CFErrorRef* error) {
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
-        do_if_registered(soscc_RemoveThisDeviceFromCircle, error);
-        
-        return simple_bool_error_request(kSecXPCOpRemoveThisDeviceFromCircle, error);
+        do_if_registered(soscc_LoggedIntoAccount, error);
+
+        return simple_bool_error_request(kSecXPCOpLoggedIntoAccount, error);
     }, NULL)
 }
 
 bool SOSCCLoggedOutOfAccount(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_LoggedOutOfAccount, error);
@@ -697,6 +690,12 @@ bool SOSCCLoggedOutOfAccount(CFErrorRef* error)
 
 bool SOSCCBailFromCircle_BestEffort(uint64_t limit_in_seconds, CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_BailFromCircle, limit_in_seconds, error);
@@ -707,6 +706,12 @@ bool SOSCCBailFromCircle_BestEffort(uint64_t limit_in_seconds, CFErrorRef* error
 
 CFArrayRef SOSCCCopyPeerPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyPeerInfo, error);
@@ -717,6 +722,12 @@ CFArrayRef SOSCCCopyPeerPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyConcurringPeerPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyConcurringPeerInfo, error);
@@ -727,6 +738,12 @@ CFArrayRef SOSCCCopyConcurringPeerPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyGenerationPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyGenerationPeerInfo, error);
@@ -737,6 +754,12 @@ CFArrayRef SOSCCCopyGenerationPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyApplicantPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyApplicantPeerInfo, error);
@@ -746,6 +769,12 @@ CFArrayRef SOSCCCopyApplicantPeerInfo(CFErrorRef* error)
 }
 
 bool SOSCCValidateUserPublic(CFErrorRef* error){
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(bool, ^{
         do_if_registered(soscc_ValidateUserPublic, error);
@@ -756,6 +785,12 @@ bool SOSCCValidateUserPublic(CFErrorRef* error){
 
 CFArrayRef SOSCCCopyValidPeerPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyValidPeerPeerInfo, error);
@@ -766,6 +801,12 @@ CFArrayRef SOSCCCopyValidPeerPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyNotValidPeerPeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyNotValidPeerPeerInfo, error);
@@ -776,7 +817,13 @@ CFArrayRef SOSCCCopyNotValidPeerPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyRetirementPeerInfo(CFErrorRef* error)
 {
-    sec_trace_enter_api(NULL);
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
+   sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyRetirementPeerInfo, error);
 
@@ -786,6 +833,12 @@ CFArrayRef SOSCCCopyRetirementPeerInfo(CFErrorRef* error)
 
 CFArrayRef SOSCCCopyViewUnawarePeerInfo(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyViewUnawarePeerInfo, error);
@@ -796,6 +849,12 @@ CFArrayRef SOSCCCopyViewUnawarePeerInfo(CFErrorRef* error)
 
 SOSPeerInfoRef SOSCCCopyMyPeerInfo(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(SOSPeerInfoRef, ^{
         do_if_registered(soscc_CopyMyPeerInfo, error);
@@ -806,6 +865,12 @@ SOSPeerInfoRef SOSCCCopyMyPeerInfo(CFErrorRef *error)
 
 static CFArrayRef SOSCCCopyEngineState(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFArrayRef, ^{
         do_if_registered(soscc_CopyEngineState, error);
@@ -821,6 +886,11 @@ CFStringRef kSOSCCEngineStateCoderKey = CFSTR("CoderDump");
 CFStringRef kSOSCCEngineStateManifestHashKey = CFSTR("ManifestHash");
 
 void SOSCCForEachEngineStateAsStringFromArray(CFArrayRef states, void (^block)(CFStringRef oneStateString)) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return;
+    }
+
 
     CFArrayForEach(states, ^(const void *value) {
         CFDictionaryRef dict = asDictionary(value, NULL);
@@ -868,6 +938,12 @@ void SOSCCForEachEngineStateAsStringFromArray(CFArrayRef states, void (^block)(C
 }
 
 bool SOSCCForEachEngineStateAsString(CFErrorRef* error, void (^block)(CFStringRef oneStateString)) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     CFArrayRef states = SOSCCCopyEngineState(error);
     if (states == NULL)
         return false;
@@ -882,6 +958,12 @@ bool SOSCCForEachEngineStateAsString(CFErrorRef* error, void (^block)(CFStringRe
 
 bool SOSCCAcceptApplicants(CFArrayRef applicants, CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_AcceptApplicants, applicants, error);
@@ -892,7 +974,13 @@ bool SOSCCAcceptApplicants(CFArrayRef applicants, CFErrorRef* error)
 
 bool SOSCCRejectApplicants(CFArrayRef applicants, CFErrorRef *error)
 {
-    sec_trace_enter_api(CFSTR("applicants=%@"), applicants);
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
+   sec_trace_enter_api(CFSTR("applicants=%@"), applicants);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_RejectApplicants, applicants, error);
         
@@ -911,6 +999,12 @@ static CF_RETURNS_RETAINED SOSPeerInfoRef SOSSetNewPublicBackupKey(CFDataRef pub
 }
 
 SOSPeerInfoRef SOSCCCopyMyPeerWithNewDeviceRecoverySecret(CFDataRef secret, CFErrorRef *error){
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     secnotice("devRecovery", "Enter SOSCCCopyMyPeerWithNewDeviceRecoverySecret()");
     CFDataRef publicKeyData = SOSCopyDeviceBackupPublicKey(secret, error);
     secnotice("devRecovery", "SOSCopyDeviceBackupPublicKey (%@)", publicKeyData);
@@ -921,6 +1015,12 @@ SOSPeerInfoRef SOSCCCopyMyPeerWithNewDeviceRecoverySecret(CFDataRef secret, CFEr
 }
 
 bool SOSCCRegisterSingleRecoverySecret(CFDataRef aks_bag, bool forV0Only, CFErrorRef *error){
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_RegisterSingleRecoverySecret, aks_bag, forV0Only, error);
@@ -930,7 +1030,13 @@ bool SOSCCRegisterSingleRecoverySecret(CFDataRef aks_bag, bool forV0Only, CFErro
 
 
 bool SOSCCRegisterRecoveryPublicKey(CFDataRef recovery_key, CFErrorRef *error){
-    sec_trace_enter_api(NULL);
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
+   sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
         bool retval = false;
         do_if_registered(soscc_RegisterRecoveryPublicKey, recovery_key, error);
@@ -941,6 +1047,12 @@ bool SOSCCRegisterRecoveryPublicKey(CFDataRef recovery_key, CFErrorRef *error){
 }
 
 CFDataRef SOSCCCopyRecoveryPublicKey(CFErrorRef *error){
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFDataRef, ^{
         do_if_registered(soscc_CopyRecoveryPublicKey, error);
@@ -969,7 +1081,7 @@ static bool label_and_password_to_bool_error_request(enum SecXPCOperation op,
 
 static bool label_and_password_and_dsid_to_bool_error_request(enum SecXPCOperation op,
                                                      CFStringRef user_label, CFDataRef user_password,
-                                                     CFStringRef dsid, CFDataRef parentEvent, CFErrorRef* error)
+                                                     CFStringRef dsid, CFErrorRef* error)
 {
     __block bool result = false;
     
@@ -981,9 +1093,6 @@ static bool label_and_password_and_dsid_to_bool_error_request(enum SecXPCOperati
             xpc_dictionary_set_string(message, kSecXPCKeyDSID, utr8StrDSID);
         });
         xpc_dictionary_set_data(message, kSecXPCKeyUserPassword, CFDataGetBytePtr(user_password), CFDataGetLength(user_password));
-        if(parentEvent){
-            SecXPCDictionarySetData(message, kSecXPCKeySignInAnalytics, parentEvent, error);
-        }
         return true;
     }, ^bool(xpc_object_t response, __unused CFErrorRef *error) {
         result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
@@ -995,12 +1104,24 @@ static bool label_and_password_and_dsid_to_bool_error_request(enum SecXPCOperati
 
 bool SOSCCRegisterUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error)
 {
-    secnotice("circleOps", "SOSCCRegisterUserCredentials - calling SOSCCSetUserCredentials for %@\n", user_label);
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
+   secnotice("circleOps", "SOSCCRegisterUserCredentials - calling SOSCCSetUserCredentials for %@\n", user_label);
     return SOSCCSetUserCredentials(user_label, user_password, error);
 }
 
 bool SOSCCSetUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("circleOps", "SOSCCSetUserCredentials for %@\n", user_label);
        sec_trace_enter_api(CFSTR("user_label=%@"), user_label);
     sec_trace_return_bool_api(^{
@@ -1012,6 +1133,12 @@ bool SOSCCSetUserCredentials(CFStringRef user_label, CFDataRef user_password, CF
 
 bool SOSCCSetUserCredentialsAndDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("circleOps", "SOSCCSetUserCredentialsAndDSID for %@\n", user_label);
     sec_trace_enter_api(CFSTR("user_label=%@"), user_label);
     sec_trace_return_bool_api(^{
@@ -1026,30 +1153,7 @@ bool SOSCCSetUserCredentialsAndDSID(CFStringRef user_label, CFDataRef user_passw
         if(account_dsid == NULL){
             account_dsid = CFSTR("");
         }
-        return label_and_password_and_dsid_to_bool_error_request(kSecXPCOpSetUserCredentialsAndDSID, user_label, user_password, account_dsid, nil, error);
-    out:
-        return result;
-
-    }, NULL)
-}
-
-bool SOSCCSetUserCredentialsAndDSIDWithAnalytics(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error)
-{
-    secnotice("circleOps", "SOSCCSetUserCredentialsAndDSIDWithAnalytics for %@\n", user_label);
-    sec_trace_enter_api(CFSTR("user_label=%@"), user_label);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_SetUserCredentialsAndDSIDWithAnalytics, user_label, user_password, dsid, parentEvent, error);
-
-        bool result = false;
-        __block CFStringRef account_dsid = dsid;
-
-        require_action_quiet(user_label, out, SOSErrorCreate(kSOSErrorParam, error, NULL, CFSTR("user_label is nil")));
-        require_action_quiet(user_password, out, SOSErrorCreate(kSOSErrorParam, error, NULL, CFSTR("user_password is nil")));
-
-        if(account_dsid == NULL){
-            account_dsid = CFSTR("");
-        }
-        return label_and_password_and_dsid_to_bool_error_request(kSecXPCOpSetUserCredentialsAndDSIDWithAnalytics, user_label, user_password, account_dsid, parentEvent, error);
+        return label_and_password_and_dsid_to_bool_error_request(kSecXPCOpSetUserCredentialsAndDSID, user_label, user_password, account_dsid, error);
     out:
         return result;
 
@@ -1070,7 +1174,7 @@ static bool SOSCCTryUserCredentialsAndDSID_internal(CFStringRef user_label, CFDa
             account_dsid = CFSTR("");
         }
         
-        return label_and_password_and_dsid_to_bool_error_request(kSecXPCOpTryUserCredentials, user_label, user_password, account_dsid, nil, error);
+        return label_and_password_and_dsid_to_bool_error_request(kSecXPCOpTryUserCredentials, user_label, user_password, account_dsid, error);
     out:
         return result;
         
@@ -1080,6 +1184,12 @@ static bool SOSCCTryUserCredentialsAndDSID_internal(CFStringRef user_label, CFDa
 
 bool SOSCCTryUserCredentialsAndDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("sosops", "SOSCCTryUserCredentialsAndDSID!! %@\n", user_label);
     require_action_quiet(user_label, out, SOSErrorCreate(kSOSErrorParam, error, NULL, CFSTR("user_label is nil")));
     require_action_quiet(user_password, out, SOSErrorCreate(kSOSErrorParam, error, NULL, CFSTR("user_password is nil")));
@@ -1090,11 +1200,23 @@ out:
 }
 
 bool SOSCCTryUserCredentials(CFStringRef user_label, CFDataRef user_password, CFErrorRef* error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     return SOSCCTryUserCredentialsAndDSID_internal(user_label, user_password, NULL, error);
 }
 
 
 bool SOSCCCanAuthenticate(CFErrorRef* error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
            do_if_registered(soscc_CanAuthenticate, error);
@@ -1104,6 +1226,12 @@ bool SOSCCCanAuthenticate(CFErrorRef* error) {
 }
 
 bool SOSCCPurgeUserCredentials(CFErrorRef* error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
            do_if_registered(soscc_PurgeUserCredentials, error);
@@ -1113,6 +1241,12 @@ bool SOSCCPurgeUserCredentials(CFErrorRef* error) {
 }
 
 enum DepartureReason SOSCCGetLastDepartureReason(CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return kSOSDepartureReasonError;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(enum DepartureReason, ^{
            do_if_registered(soscc_GetLastDepartureReason, error);
@@ -1122,6 +1256,12 @@ enum DepartureReason SOSCCGetLastDepartureReason(CFErrorRef *error) {
 }
 
 bool SOSCCSetLastDepartureReason(enum DepartureReason reason, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
        sec_trace_enter_api(NULL);
        sec_trace_return_api(bool, ^{
                do_if_registered(soscc_SetLastDepartureReason, reason, error);
@@ -1138,6 +1278,12 @@ bool SOSCCSetLastDepartureReason(enum DepartureReason reason, CFErrorRef *error)
 }
 
 bool SOSCCProcessEnsurePeerRegistration(CFErrorRef* error){
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("updates", "enter SOSCCProcessEnsurePeerRegistration");
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
@@ -1150,6 +1296,12 @@ bool SOSCCProcessEnsurePeerRegistration(CFErrorRef* error){
 
 CFSetRef /* CFString */ SOSCCProcessSyncWithPeers(CFSetRef peers, CFSetRef backupPeers, CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFSetRef, ^{
         do_if_registered(soscc_ProcessSyncWithPeers, peers, backupPeers, error);
@@ -1161,6 +1313,12 @@ CFSetRef /* CFString */ SOSCCProcessSyncWithPeers(CFSetRef peers, CFSetRef backu
 
 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers(CFErrorRef* error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return kSyncWithAllPeersOtherFail;
+    }
+
     sec_trace_enter_api(NULL);
     sec_trace_return_api(SyncWithAllPeersReason, ^{
            do_if_registered(soscc_ProcessSyncWithAllPeers, error);
@@ -1228,6 +1386,12 @@ static int64_t name_action_to_code_request(enum SecXPCOperation op, uint16_t err
 }
 
 SOSViewResultCode SOSCCView(CFStringRef view, SOSViewActionCode actionCode, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return kSOSCCGeneralViewError;
+    }
+
     if(actionCode == kSOSCCViewQuery) {
         uint64_t circleStat = SOSGetCachedCircleBitmask();
         if(circleStat & CC_STATISVALID) {
@@ -1254,6 +1418,11 @@ SOSViewResultCode SOSCCView(CFStringRef view, SOSViewActionCode actionCode, CFEr
 
 
 bool SOSCCViewSet(CFSetRef enabledViews, CFSetRef disabledViews) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFErrorRef *error = NULL;
     __block bool result = false;
 
@@ -1273,27 +1442,6 @@ bool SOSCCViewSet(CFSetRef enabledViews, CFSetRef disabledViews) {
     }, NULL)
 }
 
-bool SOSCCViewSetWithAnalytics(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) {
-    CFErrorRef *error = NULL;
-    __block bool result = false;
-
-    sec_trace_enter_api(NULL);
-    sec_trace_return_bool_api(^{
-        do_if_registered(soscc_ViewSetWithAnalytics, enabledViews, disabledViews, parentEvent);
-        return securityd_send_sync_and_do(kSecXPCOpViewSetWithAnalytics, error, ^bool(xpc_object_t message, CFErrorRef *error) {
-            xpc_object_t enabledSetXpc = CreateXPCObjectWithCFSetRef(enabledViews, error);
-            xpc_object_t disabledSetXpc = CreateXPCObjectWithCFSetRef(disabledViews, error);
-            if (enabledSetXpc) xpc_dictionary_set_value(message, kSecXPCKeyEnabledViewsKey, enabledSetXpc);
-            if (disabledSetXpc) xpc_dictionary_set_value(message, kSecXPCKeyDisabledViewsKey, disabledSetXpc);
-            if(parentEvent) SecXPCDictionarySetData(message, kSecXPCKeySignInAnalytics, parentEvent, error);
-            return (enabledSetXpc != NULL) || (disabledSetXpc != NULL) ;
-        }, ^bool(xpc_object_t response, __unused CFErrorRef *error) {
-            result = xpc_dictionary_get_bool(response, kSecXPCKeyResult);
-            return result;
-        });
-    }, NULL)
-}
-
 static CFStringRef copyViewNames(size_t n, CFStringRef *views) {
     CFMutableStringRef retval = CFStringCreateMutable(kCFAllocatorDefault, 0);
     CFStringAppend(retval, CFSTR("|"));
@@ -1354,36 +1502,72 @@ static bool sosIsViewSetSyncing(size_t n, CFStringRef *views) {
 }
 
 bool SOSCCIsIcloudKeychainSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;  // should we lie since CKKS is syncing - or forward?
+    }
+
     CFStringRef views[] = { kSOSViewWiFi, kSOSViewAutofillPasswords, kSOSViewSafariCreditCards, kSOSViewOtherSyncable };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 bool SOSCCIsSafariSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFStringRef views[] = { kSOSViewAutofillPasswords, kSOSViewSafariCreditCards };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 bool SOSCCIsAppleTVSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFStringRef views[] = { kSOSViewAppleTV };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 bool SOSCCIsHomeKitSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFStringRef views[] = { kSOSViewHomeKit };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 bool SOSCCIsWiFiSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFStringRef views[] = { kSOSViewWiFi };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 bool SOSCCIsContinuityUnlockSyncing(void) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        return false;
+    }
+
     CFStringRef views[] = { kSOSViewContinuityUnlock };
     return sosIsViewSetSyncing(sizeof(views)/sizeof(views[0]), views);
 }
 
 SOSPeerInfoRef SOSCCCopyApplication(CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     secnotice("hsa2PB", "enter SOSCCCopyApplication applicant");
     sec_trace_enter_api(NULL);
     
@@ -1394,6 +1578,12 @@ SOSPeerInfoRef SOSCCCopyApplication(CFErrorRef *error) {
 }
 
 bool SOSCCCleanupKVSKeys(CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("cleanup-keys", "enter SOSCCCleanupKVSKeys");
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
@@ -1406,6 +1596,12 @@ bool SOSCCCleanupKVSKeys(CFErrorRef *error) {
 }
 
 CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     secnotice("hsa2PB", "enter SOSCCCopyCircleJoiningBlob approver");
     sec_trace_enter_api(NULL);
 
@@ -1420,6 +1616,12 @@ CFDataRef SOSCCCopyCircleJoiningBlob(SOSPeerInfoRef applicant, CFErrorRef *error
 }
 
 CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return NULL;
+    }
+
     secnotice("circleJoin", "enter SOSCCCopyInitialSyncData approver");
     sec_trace_enter_api(NULL);
     
@@ -1430,6 +1632,12 @@ CFDataRef SOSCCCopyInitialSyncData(SOSInitialSyncFlags flags, CFErrorRef *error)
 }
 
 bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, PiggyBackProtocolVersion version, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("hsa2PB", "enter SOSCCJoinWithCircleJoiningBlob applicant");
     sec_trace_enter_api(NULL);
     sec_trace_return_bool_api(^{
@@ -1440,6 +1648,12 @@ bool SOSCCJoinWithCircleJoiningBlob(CFDataRef joiningBlob, PiggyBackProtocolVers
 }
 
 CFBooleanRef SOSCCPeersHaveViewsEnabled(CFArrayRef viewNames, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return FALSE;
+    }
+
     secnotice("view-enabled", "enter SOSCCPeersHaveViewsEnabled");
     sec_trace_enter_api(NULL);
     sec_trace_return_api(CFBooleanRef, ^{
@@ -1450,6 +1664,12 @@ CFBooleanRef SOSCCPeersHaveViewsEnabled(CFArrayRef viewNames, CFErrorRef *error)
 }
 
 bool SOSCCMessageFromPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     secnotice("pending-check", "enter SOSCCMessageFromPeerIsPending");
 
     sec_trace_return_bool_api(^{
@@ -1461,6 +1681,12 @@ bool SOSCCMessageFromPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) {
 }
 
 bool SOSCCSendToPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return false;
+    }
+
     sec_trace_return_bool_api(^{
         do_if_registered(soscc_SOSCCSendToPeerIsPending, peer, error);
 
@@ -1505,6 +1731,12 @@ bool SOSCCSendToPeerIsPending(SOSPeerInfoRef peer, CFErrorRef *error) {
 static id<SOSControlProtocol>
 SOSCCGetStatusObject(CFErrorRef *error)
 {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(error);
+        return nil;
+    }
+
     if (gSecurityd && gSecurityd->soscc_status)
         return (__bridge id<SOSControlProtocol>)gSecurityd->soscc_status();
 
@@ -1519,6 +1751,11 @@ SOSCCGetStatusObject(CFErrorRef *error)
 
 static id<SOSControlProtocol>
 SOSCCGetSynchronousStatusObject(CFErrorRef *cferror) {
+    IF_SOS_DISABLED {
+        secdebug("circleOps", "SOS disabled for this platform");
+        setSOSDisabledError(cferror);
+        return nil;
+    }
     if (gSecurityd && gSecurityd->soscc_status)
         return (__bridge id<SOSControlProtocol>)gSecurityd->soscc_status();
     
index b174896fb48b4dd5599911755a38b9046470fb81..9fd07e974efc5107dc5194008653f7f33b494751 100644 (file)
 #include <xpc/xpc.h>
 #include <Security/SecKey.h>
 
+#if TARGET_OS_TV
+#define SOS_AVAILABLE false
+#elif TARGET_OS_WATCH
+#define SOS_AVAILABLE false
+#elif TARGET_OS_BRIDGE
+#define SOS_AVAILABLE false
+#elif TARGET_OS_IOS
+#define SOS_AVAILABLE true
+#elif TARGET_OS_OSX
+#define SOS_AVAILABLE true
+#elif TARGET_OS_SIMULATOR
+#define SOS_AVAILABLE true
+#else
+#define SOS_AVAILABLE false
+#endif
+
+#define IF_SOS_DISABLED if(!SOS_AVAILABLE)
+
 __BEGIN_DECLS
 
 // Use the kSecAttrViewHint* constants in SecItemPriv.h instead
index 109cffae352c21f0ca3e05c8157339a7ca54ccb3..4172edb30deebc4054adc25fa171636198454fa5 100644 (file)
@@ -48,7 +48,6 @@
 
 #include <corecrypto/ccder.h>
 #include <utilities/iCloudKeychainTrace.h>
-#include <utilities/SecADWrapper.h>
 
 #include "AssertMacros.h"
 
@@ -274,7 +273,7 @@ SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) {
 
     switch (SOSCoderGetExportedVersion(der, der_end)) {
         case kCoderAsOTRDataOnly:
-            der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, der_end);
+            der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, der_end);
             p->waitingForDataPacket = false;
             break;
 
@@ -285,10 +284,10 @@ SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) {
 
             require_action_quiet(sequence_end == der_end, fail, SecCFDERCreateError(kSOSErrorDecodeFailure, CFSTR("Extra data in SOS coder"), NULL, error));
 
-            der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end);
+            der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, sequence_end);
             der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end);
             if (der != sequence_end) { // optionally a pending response
-                der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end);
+                der = der_decode_data(kCFAllocatorDefault, &p->pendingResponse, error, der, sequence_end);
             }
         }
             break;
@@ -307,12 +306,12 @@ SOSCoderRef SOSCoderCreateFromData(CFDataRef exportedData, CFErrorRef *error) {
                 goto fail;
             }
 
-            der = der_decode_data(kCFAllocatorDefault, 0, &otr_data, error, der, sequence_end);
+            der = der_decode_data(kCFAllocatorDefault, &otr_data, error, der, sequence_end);
             der = ccder_decode_bool(&p->waitingForDataPacket, der, sequence_end);
             der = ccder_decode_bool(&p->lastReceivedWasOld, der, sequence_end);
-            der = der_decode_data(kCFAllocatorDefault, 0, &p->hashOfLastReceived, error, der, sequence_end);
+            der = der_decode_data(kCFAllocatorDefault, &p->hashOfLastReceived, error, der, sequence_end);
             if (der != sequence_end) { // optionally a pending response
-                der = der_decode_data(kCFAllocatorDefault, 0, &p->pendingResponse, error, der, sequence_end);
+                der = der_decode_data(kCFAllocatorDefault, &p->pendingResponse, error, der, sequence_end);
             }
         }
             break;
@@ -356,7 +355,7 @@ SOSCoderRef SOSCoderCreate(SOSPeerInfoRef peerInfo, SOSFullPeerInfoRef myPeerInf
         privateKey = SOSFullPeerInfoCopyDeviceKey(myPeerInfo, &localError);
         require_quiet(privateKey, errOut);
 
-        myRef = SecOTRFullIdentityCreateFromSecKeyRef(allocator, privateKey, &localError);
+        myRef = SecOTRFullIdentityCreateFromSecKeyRefSOS(allocator, privateKey, &localError);
         require_quiet(myRef, errOut);
         
         CFReleaseNull(privateKey);
@@ -566,7 +565,6 @@ SOSCoderStatus SOSCoderUnwrap(SOSCoderRef coder, CFDataRef codedMessage, CFMutab
                     case errSecDecode:
                         CFStringAppend(action, CFSTR("resending dh"));
                         result = SOSCoderResendDH(coder, error);
-                        SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.restartotrnegotiation"), 1);
                         break;
                     default:
                         SOSCreateErrorWithFormat(kSOSErrorEncodeFailure, (error != NULL) ? *error : NULL, error, NULL, CFSTR("%@ Cannot negotiate session (%ld)"), clientId, (long)ppstatus);
@@ -592,7 +590,6 @@ SOSCoderStatus SOSCoderUnwrap(SOSCoderRef coder, CFDataRef codedMessage, CFMutab
 
             if(!SecOTRSGetIsReadyForMessages(coder->sessRef)) {
                 CFStringAppend(action, CFSTR("not ready for data; resending DH packet"));
-                SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.restartotrnegotiation"), 1);
                 result = SOSCoderResendDH(coder, error);
             } else {
                 if (coder->waitingForDataPacket) {
index d700b69e3749e035f3f8a872f61ebe4487c7b5a5..a8296b903c6daf04db87c91102f3622de7a6645e 100644 (file)
@@ -24,6 +24,8 @@
 #import <Foundation/Foundation.h>
 #import <Foundation/NSXPCConnection.h>
 #import <objc/runtime.h>
+#import <Security/SecXPCHelper.h>
+#include <utilities/debugging.h>
 
 #import "keychain/SecureObjectSync/SOSTypes.h"
 #import "keychain/SecureObjectSync/SOSControlHelper.h"
 void
 _SOSControlSetupInterface(NSXPCInterface *interface)
 {
-    static NSMutableSet *errClasses;
+    NSSet<Class> *errClasses = [SecXPCHelper safeErrorClasses];
 
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        errClasses = [NSMutableSet set];
+    @try {
+        [interface setClasses:errClasses forSelector:@selector(userPublicKey:) argumentIndex:2 ofReply:YES];
 
-        char *classes[] = {
-            "NSURL",
-            "NSURLError",
-            "NSError"
-        };
+        [interface setClasses:errClasses forSelector:@selector(stashedCredentialPublicKey:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(assertStashedAccountCredential:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(validatedStashedAccountCredential:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(stashAccountCredential:complete:) argumentIndex:1 ofReply:YES];
 
-        for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
-            Class cls = objc_getClass(classes[n]);
-            if (cls)
-                [errClasses addObject:cls];
-        }
-    });
+        [interface setClasses:errClasses forSelector:@selector(ghostBust:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(ghostBustPeriodic:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(ghostBustTriggerTimed:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(ghostBustInfo:) argumentIndex:0 ofReply:YES];
 
-    [interface setClasses:errClasses forSelector:@selector(userPublicKey:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(iCloudIdentityStatus:) argumentIndex:1 ofReply:YES];
 
-    [interface setClasses:errClasses forSelector:@selector(stashedCredentialPublicKey:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(assertStashedAccountCredential:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(stashAccountCredential:complete:) argumentIndex:1 ofReply:YES];
-
-    [interface setClasses:errClasses forSelector:@selector(myPeerInfo:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(circleHash:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(circleJoiningBlob:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(joinCircleWithBlob:version:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(initialSyncCredentials:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(importInitialSyncCredentials:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(triggerSync:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(getWatchdogParameters:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(setWatchdogParmeters:complete:) argumentIndex:0 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(ghostBust:complete:) argumentIndex:1 ofReply:YES];
-    [interface setClasses:errClasses forSelector:@selector(triggerBackup:complete:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(myPeerInfo:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(circleHash:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(circleJoiningBlob:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(joinCircleWithBlob:version:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(initialSyncCredentials:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(importInitialSyncCredentials:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcTriggerSync:complete:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(getWatchdogParameters:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(setWatchdogParmeters:complete:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcTriggerBackup:complete:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcTriggerRingUpdate:) argumentIndex:0 ofReply:YES];
+    }
+    @catch(NSException* e) {
+        secerror("Could not configure SOSControlHelper: %@", e);
+        @throw e;
+    }
 }
index 46332efa14ac77568bf85cbb5c1899884efe4e4c..38bfa056c890e3da775438a3febe725de1c04ce3 100644 (file)
     [self.account importInitialSyncCredentials:items complete:complete];
 }
 
-- (void)triggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
+- (void)rpcTriggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete
 {
-    if (![self checkEntitlement:(__bridge NSString *)kSecEntitlementKeychainCloudCircle]) {
-        complete(false, [NSError errorWithDomain:(__bridge NSString *)kSOSErrorDomain code:kSOSEntitlementMissing userInfo:NULL]);
-        return;
-    }
-
-    [self.account triggerSync:peers complete:complete];
+    [self.account rpcTriggerSync:peers complete:complete];
 }
 
 - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete
     [self.account ghostBustInfo:complete];
 }
 
-- (void)triggerBackup:(NSArray<NSString *>* _Nullable)backupPeers complete:(void (^)(NSError *error))complete
+- (void)iCloudIdentityStatus: (void (^)(NSData *json, NSError *error))complete {
+    [self.account iCloudIdentityStatus: complete];
+}
+
+- (void)rpcTriggerBackup:(NSArray<NSString *>* _Nullable)backupPeers complete:(void (^)(NSError *error))complete
 {
-    [self.account triggerBackup:backupPeers complete:complete];
+    [self.account rpcTriggerBackup:backupPeers complete:complete];
+}
+
+- (void)rpcTriggerRingUpdate:(void (^)(NSError *))complete {
+    [self.account rpcTriggerRingUpdate:complete];
+}
+
+- (void)iCloudIdentityStatus_internal:(void (^)(NSDictionary *, NSError *))complete {
+    [self.account iCloudIdentityStatus_internal:complete];
 }
 
 
 
 - (instancetype)initSOSConnectionWithConnection:(NSXPCConnection *)connection account:(SOSAccount *)account
 {
-    self = [super initSOSClientWithAccount:account];
-    if (self) {
+    if ((self = [super initSOSClientWithAccount:account])) {
         self.connection = connection;
     }
     return self;
index 7aea444d0257300cf410f80aca05271b0a18622e..f013cb8ebfb3ce7c50088e8d3866f90db1b94886 100644 (file)
@@ -9,11 +9,11 @@
 
 #include <AssertMacros.h>
 
-#include <CommonCrypto/CommonRandomSPI.h>
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFError.h>
 #include <utilities/SecBuffer.h>
-#include <corecrypto/ccec.h>
+#import <corecrypto/ccec.h>
+#import <corecrypto/ccrng.h>
 
 
 #if 0 && defined(CCEC_RFC6637_DEBUG_KEYS)
@@ -46,7 +46,7 @@ SOSCopyECWrappedData(ccec_pub_ctx_t ec_ctx, CFDataRef data, CFErrorRef *error)
     res = ccec_rfc6637_wrap_key(ec_ctx, CFDataGetMutableBytePtr(output), CCEC_RFC6637_COMPACT_KEYS | DEBUGKEYS, kAlgorithmID,
                                 CFDataGetLength(data), CFDataGetBytePtr(data), &ccec_rfc6637_dh_curve_p256,
                                 &ccec_rfc6637_wrap_sha256_kek_aes128, (const uint8_t *)fingerprint,
-                                ccDevRandomGetRngState());
+                                ccrng(NULL));
     require_noerr_action(res, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Wrap failed with %d"), res));
 
     CFTransferRetained(result, output);
index f2a4a9dbc8e82caff485f7598bb6eca60f6abc58..d644bee030d2187846f6b7019c4f1a7249daca35 100644 (file)
@@ -50,9 +50,8 @@
 #include <utilities/iCloudKeychainTrace.h>
 #include <utilities/SecCoreCrypto.h>
 #include <utilities/SecFileLocations.h>
-#include <utilities/SecADWrapper.h>
 #include <utilities/SecTrace.h>
-
+#include "utilities/SecCoreAnalytics.h"
 
 #include <AssertMacros.h>
 #include <CoreFoundation/CoreFoundation.h>
@@ -332,6 +331,19 @@ static void SOSEngineForEachBackupPeer_locked(SOSEngineRef engine, void (^with)(
     CFRelease(peerMapCopy);
 }
 
+static void SOSEngineForBackupPeer_locked(SOSEngineRef engine, CFStringRef backupPeerID, void (^with)(SOSPeerRef peer)) {
+    struct SOSEngineWithPeerContext ewp = { .engine = engine, .with = with };
+    CFMutableDictionaryRef singleEntryMap = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
+    CFDictionaryRef peerMapCopy = CFDictionaryCreateCopy(NULL, engine->peerMap);
+    SOSPeerRef peer = (SOSPeerRef)CFDictionaryGetValue(peerMapCopy, backupPeerID);
+    if(peer != NULL) {
+        CFDictionaryAddValue(singleEntryMap, backupPeerID, peer);
+        CFDictionaryApplyFunction(singleEntryMap, SOSEngineWithBackupPeerMapEntry_locked, &ewp);
+    }
+    CFRelease(peerMapCopy);
+    CFRelease(singleEntryMap);
+}
+
 //
 // Manifest cache
 //
@@ -706,7 +718,7 @@ CFMutableDictionaryRef derStateToDictionaryCopy(CFDataRef state, CFErrorRef *err
     if (state) {
         const uint8_t *der = CFDataGetBytePtr(state);
         const uint8_t *der_end = der + CFDataGetLength(state);
-        ok = der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListMutableContainers, (CFDictionaryRef *)&stateDict, error, der, der_end);
+        ok = der = der_decode_dictionary(kCFAllocatorDefault, (CFDictionaryRef *)&stateDict, error, der, der_end);
         if (der && der != der_end) {
             ok = SOSErrorCreate(kSOSErrorDecodeFailure, error, NULL, CFSTR("trailing %td bytes at end of state"), der_end - der);
         }
@@ -773,7 +785,7 @@ static bool SOSEngineLoadCoders(SOSEngineRef engine, SOSTransactionRef txn, CFEr
     secnotice("coder", "Will force peer registration: %s",needPeerRegistration ? "yes" : "no");
 
     if (needPeerRegistration) {
-        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
+        dispatch_queue_t queue = dispatch_get_global_queue(SOS_ENGINE_PRIORITY, 0);
 
         dispatch_async(queue, ^{
             CFErrorRef eprError = NULL;
@@ -1202,22 +1214,12 @@ static bool SOSEngineUpdateChanges_locked(SOSEngineRef engine, SOSTransactionRef
                 if (deleted) {
                     bool someoneCares = SOSChangeMapperIngestChange(&cm, false, deleted);
                     if (someoneCares) {
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-                        SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.delete"), 1);
-#endif
                         mappedItemChanged = true;
                     }
                 }
                 if (inserted) {
                     bool someoneCares = SOSChangeMapperIngestChange(&cm, true, inserted);
                     if (someoneCares) {
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-                        if (deleted == NULL) {
-                            SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.add"), 1);
-                        } else {
-                            SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.update"), 1);
-                        }
-#endif
                         mappedItemChanged = true;
                     }
                     if (!someoneCares && !isData(inserted) && SecDbItemIsTombstone((SecDbItemRef)inserted) && !CFEqualSafe(SecDbItemGetValue((SecDbItemRef)inserted, &v7utomb, NULL), kCFBooleanTrue)) {
@@ -1748,6 +1750,12 @@ static void SOSEngineForEachBackupPeer(SOSEngineRef engine, void (^with)(SOSPeer
     });
 }
 
+static void SOSEngineForBackupPeer(SOSEngineRef engine, CFStringRef backupPeerID, void (^with)(SOSPeerRef peer)) {
+    SOSEngineDoOnQueue(engine, ^{
+        SOSEngineForBackupPeer_locked(engine, backupPeerID, with);
+    });
+}
+
 static const CFStringRef kSecADSecurityNewItemSyncTimeKey = CFSTR("com.apple.security.secureobjectsync.itemtime.new");
 static const CFStringRef kSecADSecurityKnownItemSyncTimeKey = CFSTR("com.apple.security.secureobjectsync.itemtime.known");
 
@@ -1764,8 +1772,8 @@ static void ReportItemSyncTime(SOSDataSourceRef ds, bool known, SOSObjectRef obj
             syncTime = now - peerModificationAbsoluteTime;
         }
 
-        SecADClientPushValueForDistributionKey(known ? kSecADSecurityKnownItemSyncTimeKey : kSecADSecurityNewItemSyncTimeKey,
-                                               SecBucket2Significant(syncTime));
+        SecCoreAnalyticsSendValue(known ? kSecADSecurityKnownItemSyncTimeKey : kSecADSecurityNewItemSyncTimeKey,
+                                  SecBucket2Significant(syncTime));
     }
     CFReleaseNull(itemModDate);
 }
@@ -2772,6 +2780,14 @@ CFArrayRef SOSEngineCopyBackupPeerNames(SOSEngineRef engine, CFErrorRef *error)
     return backupNames;
 }
 
+CFStringRef SOSEngineEnsureCopyBackupPeerForView(SOSEngineRef engine, CFStringRef backupPeerID, CFErrorRef *error) {
+    __block CFStringRef backupName = CFSTR("");
+    SOSEngineForBackupPeer(engine, backupPeerID, ^(SOSPeerRef peer) {
+        backupName = CFRetainSafe(SOSPeerGetID(peer));
+    });
+    return backupName;
+}
+
 static CFMutableDictionaryRef SOSEngineCreateStateDictionary(CFStringRef peerID, SOSManifestRef manifest, CFSetRef vns, CFStringRef coderString) {
     CFNumberRef manifestCount = CFNumberCreateWithCFIndex(kCFAllocatorDefault, SOSManifestGetCount(manifest));
     CFDataRef manifestHash = SOSManifestGetDigest(manifest, NULL);
index ea598b8baeee4c547fa1a8027a679286052a40bb..0e508d175cca2acc93bef93df8880775948397c3 100644 (file)
@@ -135,6 +135,7 @@ bool SOSEnginePeerDidConnect(SOSEngineRef engine, CFStringRef peerID, CFErrorRef
 bool SOSEngineSetPeerConfirmedManifest(SOSEngineRef engine, CFStringRef backupName,
                                        CFDataRef keybagDigest, CFDataRef manifestData, CFErrorRef *error);
 CFArrayRef SOSEngineCopyBackupPeerNames(SOSEngineRef engine, CFErrorRef *error);
+CFStringRef SOSEngineEnsureCopyBackupPeerForView(SOSEngineRef engine, CFStringRef backupPeerID, CFErrorRef *error);
 
 void logRawMessage(CFDataRef message, bool sending, uint64_t seqno);
 
index 4417dd34b64408179c64bc684efc73a49526f599..fe2771489657b300aab213533ca6c4dfb137edf9 100644 (file)
@@ -39,6 +39,7 @@ _SOSCCIsIcloudKeychainSyncing
 _SOSCCIsSafariSyncing
 _SOSCCIsWiFiSyncing
 _SOSCCJoinWithCircleJoiningBlob
+_SOSCCLoggedIntoAccount
 _SOSCCLoggedOutOfAccount
 _SOSCCMessageFromPeerIsPending
 _SOSCCPeersHaveViewsEnabled
@@ -51,21 +52,15 @@ _SOSCCRegisterSingleRecoverySecret
 _SOSCCRegisterUserCredentials
 _SOSCCRejectApplicants
 _SOSCCRemovePeersFromCircle
-_SOSCCRemovePeersFromCircleWithAnalytics
 _SOSCCRemoveThisDeviceFromCircle
-_SOSCCRemoveThisDeviceFromCircleWithAnalytics
 _SOSCCRequestToJoinCircle
-_SOSCCRequestToJoinCircleWithAnalytics
 _SOSCCRequestToJoinCircleAfterRestore
-_SOSCCRequestToJoinCircleAfterRestoreWithAnalytics
 _SOSCCResetToEmpty
-_SOSCCResetToEmptyWithAnalytics
 _SOSCCResetToOffering
 _SOSCCSendToPeerIsPending
 _SOSCCSetLastDepartureReason
 _SOSCCSetUserCredentials
 _SOSCCSetUserCredentialsAndDSID
-_SOSCCSetUserCredentialsAndDSIDWithAnalytics
 _SOSCCThisDeviceIsInCircle
 _SOSCCThisDeviceIsInCircleNonCached
 _SOSCCTryUserCredentials
@@ -73,9 +68,7 @@ _SOSCCTryUserCredentialsAndDSID
 _SOSCCValidateUserPublic
 _SOSCCView
 _SOSCCViewSet
-_SOSCCViewSetWithAnalytics
 _SOSCCWaitForInitialSync
-_SOSCCWaitForInitialSyncWithAnalytics
 _SOSCCCopyInitialSyncData
 
 _kSOSCCEngineStateCoderKey
@@ -141,6 +134,7 @@ _SOSPeerInfoGetClass
 _SOSPeerInfoGetDEREncodedSize
 _SOSPeerInfoGetPeerDeviceType
 _SOSPeerInfoGetPeerID
+_SOSPeerInfoGetSPID
 _SOSPeerInfoGetPeerName
 _SOSPeerInfoGetPeerProtocolVersion
 _SOSPeerInfoGetPermittedViews
@@ -407,6 +401,7 @@ _SOSFullPeerInfoCreateWithViews
 _SOSFullPeerInfoEncodeToDER
 _SOSFullPeerInfoGetDEREncodedSize
 _SOSFullPeerInfoPing
+_SOSFullPeerInfoSetCKKS4AllSupport
 _SOSFullPeerInfoPrivKeyExists
 _SOSFullPeerInfoPromoteToRetiredAndCopy
 _SOSFullPeerInfoPurgePersistentKey
@@ -468,6 +463,7 @@ _SOSRingKeyCreateWithName
 _SOSRingKeyCreateWithRingName
 _kSOSKVSKeyParametersKey
 _sCirclePrefix
+_sRingPrefix
 _sDebugInfoPrefix
 _sRetirementPrefix
 
@@ -489,6 +485,7 @@ _SOSCreateErrorWithFormat
 _SOSCreateErrorWithFormatAndArguments
 _SOSDateCreate
 _SOSErrorCreate
+_SOSCCCredentialQueue
 _SOSGenerateDeviceBackupFullKey
 _SOSGetBackupKeyCurveParameters
 _SOSItemsChangedCopyDescription
@@ -498,7 +495,7 @@ _SOSTransportMessageTypeIDSV2
 _SOSTransportMessageTypeKVS
 _kSOSDSIDKey
 _kSOSNoCachedValue
-
+_kSOSCountKey
 
 _SOSPeerGestaltGetAnswer
 _SOSPeerGestaltGetName
@@ -536,6 +533,7 @@ _sBackupKeyKey
 _sEscrowRecord
 _sTransportType
 _SOSGenerationCountCopyDescription
+_sCKKSForAll
 
 _kSOSHsaCrKeyDictionary
 _SOSPeerInfoCopySerialNumber
@@ -544,6 +542,8 @@ _SOSPeerInfoPackV2Data
 _SOSPeerInfoSerialNumberIsSet
 _SOSPeerInfoSetSerialNumber
 _SOSPeerInfoSetTestSerialNumber
+_SOSPeerInfoSetSupportsCKKSForAll
+_SOSPeerInfoSupportsCKKSForAll
 _SOSPeerInfoSign
 _SOSPeerInfoUpdateToV2
 _SOSPeerInfoV2DictionaryCopyDictionary
index dce3a3f8e954290a9d4a24788bc5d26db23ba3b3..05e1b1af06c30e74503cacbdc85e19692be4eada 100644 (file)
@@ -63,6 +63,7 @@ SecKeyRef SOSFullPeerInfoCopyOctagonPublicSigningKey(SOSFullPeerInfoRef fullPeer
 SecKeyRef SOSFullPeerInfoCopyOctagonPublicEncryptionKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error);
 SecKeyRef SOSFullPeerInfoCopyOctagonSigningKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error);
 SecKeyRef SOSFullPeerInfoCopyOctagonEncryptionKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error);
+bool SOSFullPeerInfoSetCKKS4AllSupport(SOSFullPeerInfoRef fullPeerInfo, bool support, CFErrorRef* error);
 
 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef peer, CFErrorRef* error);
 
index adea27880f366c513dd08c2895fadcff17820bb9..02cbbe20ddef656f5acce9554c9a621a1b3190de 100644 (file)
@@ -41,7 +41,6 @@
 #include <Security/SecFramework.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFRelease.h>
@@ -146,15 +145,17 @@ SOSFullPeerInfoRef SOSFullPeerInfoCreateWithViews(CFAllocatorRef allocator,
     fpi->peer_info = SOSPeerInfoCreateWithTransportAndViews(allocator, gestalt, backupKey,
                                                             IDSID, transportType, preferIDS,
                                                             preferIDSFragmentation, preferACKModel, initialViews,
-                                                            signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error);
+                                                            signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey,
+                                                            // All newly-created FullPeerInfos are on software that supports CKKS4All
+                                                            true,
+                                                            error);
     require_quiet(fpi->peer_info, exit);
 
     OSStatus status = SecKeyCopyPersistentRef(signingKey, &fpi->key_ref);
     require_quiet(SecError(status, error, CFSTR("Inflating persistent ref")), exit);
-    
     status = SecKeyCopyPersistentRef(octagonPeerSigningKey, &fpi->octagon_peer_signing_key_ref);
     require_quiet(SecError(status, error, CFSTR("Inflating octagon peer signing persistent ref")), exit);
-    status = SecKeyCopyPersistentRef(octagonPeerSigningKey, &fpi->octagon_peer_encryption_key_ref);
+    status = SecKeyCopyPersistentRef(octagonPeerEncryptionKey, &fpi->octagon_peer_encryption_key_ref);
     require_quiet(SecError(status, error, CFSTR("Inflating octagon peer encryption persistent ref")), exit);
 
     CFTransferRetained(result, fpi);
@@ -199,6 +200,27 @@ bool SOSFullPeerInfoUpdateOctagonEncryptionKey(SOSFullPeerInfoRef peer, SecKeyRe
     });
 }
 
+bool SOSFullPeerInfoSetCKKS4AllSupport(SOSFullPeerInfoRef fullPeerInfo, bool support, CFErrorRef* error) {
+
+    SOSPeerInfoRef peerInfo = SOSFullPeerInfoGetPeerInfo(fullPeerInfo);
+    bool supportsCKKS4All = SOSPeerInfoSupportsCKKSForAll(peerInfo);
+
+    if(supportsCKKS4All == support) {
+        // Early-exit: no change needed
+        return true;
+    }
+
+    secnotice("circleChange", "Setting CKKS4All status to '%@'", support ? @"supported" : @"not supported");
+
+    return SOSFullPeerInfoUpdate(fullPeerInfo, error, ^SOSPeerInfoRef(SOSPeerInfoRef currentPeerInfo, SecKeyRef key, CFErrorRef *blockerror) {
+        SOSPeerInfoRef newPeerInfo = SOSPeerInfoCopyWithModification(kCFAllocatorDefault, currentPeerInfo, key, blockerror,
+                                                                     ^bool(SOSPeerInfoRef peerToModify, CFErrorRef *innerblockerror) {
+            SOSPeerInfoSetSupportsCKKSForAll(peerToModify, support);
+            return true;
+        });
+        return newPeerInfo;
+    });
+}
 
 
 CFDataRef SOSPeerInfoCopyData(SOSPeerInfoRef pi, CFErrorRef *error)
@@ -271,7 +293,7 @@ SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErro
     fpi->peer_info = SOSPeerInfoCreateFromDER(allocator, error, der_p, der_end);
     require_quiet(fpi->peer_info != NULL, fail);
 
-    *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
+    *der_p = der_decode_data(allocator, &fpi->key_ref, error, *der_p, sequence_end);
     require_quiet(*der_p != NULL, fail);
     
     return fpi;
@@ -492,12 +514,14 @@ errOut:
 
 static SecKeyRef SOSFullPeerInfoCopyMatchingPrivateKey(SOSFullPeerInfoRef fpi, CFErrorRef *error) {
     SecKeyRef retval = NULL;
-
     SecKeyRef pub = SOSFullPeerInfoCopyPubKey(fpi, error);
-    require_quiet(pub, exit);
-    retval = SecKeyCopyMatchingPrivateKey(pub, error);
-exit:
-    CFReleaseNull(pub);
+    if(pub) {
+        retval = SecKeyCopyMatchingPrivateKey(pub, error);
+        if(!retval) {
+            secnotice("circleOp", "Failed to find my private key for spid %@", SOSPeerInfoGetSPID(SOSFullPeerInfoGetPeerInfo(fpi)));
+        }
+        CFReleaseNull(pub);
+    }
     return retval;
 }
 
index 5163e901475d7023a21a021fccf0d81f3c98c235..ef04e2dcf2d9deca9e40cc30dd85fe970ed0f80f 100644 (file)
@@ -124,7 +124,7 @@ SOSGenCountRef SOSGenerationCreateWithBaseline(SOSGenCountRef reference) {
 SOSGenCountRef SOSGenCountCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
                                         const uint8_t** der_p, const uint8_t *der_end) {
     SOSGenCountRef retval = NULL;
-    *der_p = der_decode_number(allocator, 0, &retval, error, *der_p, der_end);
+    *der_p = der_decode_number(allocator, &retval, error, *der_p, der_end);
     if(retval == NULL)
         retval = SOSGenerationCreate();
     return retval;
index 0460de82943d5473de8ee378433d81219208f822..8c02d3c0f35ed558a343b99b0e305ec1b9061a16 100644 (file)
 
 __BEGIN_DECLS
 
+#define SOS_ACCOUNT_PRIORITY DISPATCH_QUEUE_PRIORITY_LOW
+#define SOS_ENGINE_PRIORITY DISPATCH_QUEUE_PRIORITY_BACKGROUND
+#define SOS_TRANSPORT_PRIORITY DISPATCH_QUEUE_PRIORITY_LOW
+
 #define ENABLE_IDS 0
 
 #define kSOSPeerIDLengthMax (26)
@@ -82,12 +86,16 @@ enum {
     kSOSErrorParam              = 1045,
     kSOSErrorNotInCircle        = 1046,
     kSOSErrorKeysNeedAttention  = 1047,
+    kSOSErrorNoAccount          = 1048,
 };
 
 extern const CFStringRef SOSTransportMessageTypeIDSV2;
 extern const CFStringRef SOSTransportMessageTypeKVS;
 extern const CFStringRef kSOSDSIDKey;
 extern const SOSCCStatus kSOSNoCachedValue;
+extern const CFStringRef kSOSCountKey;
+
+dispatch_queue_t SOSCCCredentialQueue(void);
 
 // Returns false unless errorCode is 0.
 bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef descriptionString, ...);
index 35e8c151794e3e7919bc71482fb4c0adf79ad655..696387e32a0308671da144282af4bcb0e2104244 100644 (file)
@@ -47,9 +47,9 @@
 #include <utilities/der_date.h>
 
 #include <corecrypto/ccrng.h>
-#include <corecrypto/ccrng_pbkdf2_prng.h>
-
-#include <CommonCrypto/CommonRandomSPI.h>
+#include <corecrypto/ccdigest.h>
+#include <corecrypto/ccsha2.h>
+#include <corecrypto/ccpbkdf2.h>
 
 #include <os/lock.h>
 
@@ -59,6 +59,7 @@ const CFStringRef kSOSErrorDomain = CFSTR("com.apple.security.sos.error");
 const CFStringRef kSOSDSIDKey = CFSTR("AccountDSID");
 const CFStringRef SOSTransportMessageTypeIDSV2 = CFSTR("IDS2.0");
 const CFStringRef SOSTransportMessageTypeKVS = CFSTR("KVS");
+const CFStringRef kSOSCountKey = CFSTR("numberOfErrorsDeep");
 
 bool SOSErrorCreate(CFIndex errorCode, CFErrorRef *error, CFDictionaryRef formatOptions, CFStringRef format, ...)
     CF_FORMAT_FUNCTION(4, 5);
@@ -256,23 +257,29 @@ bool SOSGenerateDeviceBackupFullKey(ccec_full_ctx_t generatedKey, ccec_const_cp_
 {
     bool result = false;
     int cc_result = 0;
-    struct ccrng_pbkdf2_prng_state pbkdf2_prng;
-    const int kBackupKeyMaxBytes = 1024; // This may be a function of the cp but will be updated when we use a formally deterministic key generation.
-
-    cc_result = ccrng_pbkdf2_prng_init(&pbkdf2_prng, kBackupKeyMaxBytes,
-                                       CFDataGetLength(entropy), CFDataGetBytePtr(entropy),
-                                       sizeof(sBackupKeySalt), sBackupKeySalt,
-                                       kBackupKeyIterations);
-    require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("pbkdf rng init failed: %d"), cc_result));
 
-    cc_result = ccec_compact_generate_key(cp, (struct ccrng_state *) &pbkdf2_prng, generatedKey);
-    require_action_quiet(cc_result == 0, exit, SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("Generate key failed: %d"), cc_result));
+#define drbg_output_size 1024
+
+    uint8_t drbg_output[drbg_output_size];
+    cc_result = ccpbkdf2_hmac(ccsha256_di(), CFDataGetLength(entropy), CFDataGetBytePtr(entropy),
+                              sizeof(sBackupKeySalt), sBackupKeySalt,
+                              kBackupKeyIterations,
+                              drbg_output_size, drbg_output);
+    require_action_quiet(cc_result == 0, exit,
+                         SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("ccpbkdf2_hmac failed: %d"), cc_result));
+
+    cc_result = ccec_generate_key_deterministic(cp,
+                                                drbg_output_size,
+                                                drbg_output,
+                                                ccrng(NULL),
+                                                CCEC_GENKEY_DETERMINISTIC_SECBKP,
+                                                generatedKey);
+    require_action_quiet(cc_result == 0, exit,
+                         SOSErrorCreate(kSOSErrorProcessingFailure, error, NULL, CFSTR("ccec_generate_key_deterministic failed: %d"), cc_result));
 
     result = true;
 exit:
-    bzero(&pbkdf2_prng, sizeof(pbkdf2_prng));
     return result;
-
 }
 
 CFDataRef SOSCopyDeviceBackupPublicKey(CFDataRef entropy, CFErrorRef *error)
@@ -440,3 +447,12 @@ NSDate *SOSCreateRandomDateBetweenNowPlus(NSTimeInterval starting, NSTimeInterva
     return [[NSDate alloc] initWithTimeIntervalSinceNow:resultInterval];
 }
 
+
+dispatch_queue_t SOSCCCredentialQueue(void) {
+    static dispatch_queue_t credQueue = NULL;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        credQueue = dispatch_queue_create("com.apple.SOSCredentialsQueue", DISPATCH_QUEUE_SERIAL);
+    });
+    return credQueue;
+}
index 30fda73654e812a6a0438121ef7b789e76808847..f230261b81235af51c2583da6f59a4c4cab5d2e0 100644 (file)
@@ -54,15 +54,16 @@ SOSIntervalEvent fooEvent = [[SOSIntervalEvent alloc] initWithDefaults:account.s
 }
 
 -(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];
+    if ((self = [super init])) {
+        _defaults = defaults;
+        if(! _defaults) {
+            _defaults =  [[NSUserDefaults alloc] init];
+        }
+        _dateDescription = dateDescription;
+        _earliestDate = earliest;
+        _latestDate = latest;
+        [self schedule];
     }
-    _dateDescription = dateDescription;
-    _earliestDate = earliest;
-    _latestDate = latest;
-    [self schedule];
     return self;
 }
 
index 84afb8c91cd9aa4d7d26b09eba63c275a8b302c0..dabc69c5906d24d66101d9832d8cbf154014b52d 100644 (file)
@@ -36,6 +36,7 @@ extern const CFStringRef kSOSKVSWroteLastKeyParams;
 extern const CFStringRef sCirclePrefix;
 extern const CFStringRef sRetirementPrefix;
 extern const CFStringRef sDebugInfoPrefix;
+extern const CFStringRef sRingPrefix;
 
 SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key);
 bool SOSKVSKeyParse(SOSKVSKeyType keyType, CFStringRef key, CFStringRef *circle, CFStringRef *peerInfo, CFStringRef *ring, CFStringRef *backupName, CFStringRef *from, CFStringRef *to);
index 97ab42dbe59ed1ee5fe99e2dce98695a200c1d82..f01b48da1846195d261d02a0987e9d7bb0d40ee8 100644 (file)
@@ -443,13 +443,13 @@ bool SOSMessageAppendObject(SOSMessageRef message, CFDataRef object, CFErrorRef
     return true;
 }
 
-static CC_NONNULL_ALL
-size_t ccder_sizeof_bit_string(cc_size n, const cc_unit *s) {
+static
+size_t ccder_sizeof_bit_string(cc_size n, const cc_unit *_Nonnull s) {
     return ccder_sizeof(CCDER_BIT_STRING, ccn_sizeof(ccn_bitlen(n, s)) + 1);
 }
 
-static CC_NONNULL_ALL
-uint8_t *ccder_encode_bit_string(cc_size n, const cc_unit *s, const uint8_t *der, uint8_t *der_end) {
+static
+uint8_t *ccder_encode_bit_string(cc_size n, const cc_unit *_Nonnull s, const uint8_t *_Nonnull der, uint8_t *_Nonnull der_end) {
     size_t bits = ccn_bitlen(n, s);
     size_t out_size = ccn_sizeof(bits) + 1;
     der_end = ccder_encode_body_nocopy(out_size, der, der_end);
@@ -467,8 +467,8 @@ size_t der_sizeof_implicit_data(ccder_tag tag, CFDataRef data) {
 }
 
 
-static CC_NONNULL((3, 4))
-uint8_t *der_encode_implicit_data(ccder_tag tag, CFDataRef data, const uint8_t *der, uint8_t *der_end) {
+static
+uint8_t *der_encode_implicit_data(ccder_tag tag, CFDataRef data, const uint8_t *_Nonnull der, uint8_t *_Nonnull der_end) {
     if (!data)
         return der_end;
     return ccder_encode_implicit_raw_octet_string(tag, CFDataGetLength(data), CFDataGetBytePtr(data), der, der_end);
@@ -765,8 +765,8 @@ CFDataRef SOSMessageCreateData(SOSMessageRef message, uint64_t sequenceNumber, C
 
 // Decode BER length field.  Sets *lenp to ccber_indefinite_len if this is an indefinite length encoded object.
 // Behaves like ccder_decode_len in every other way.
-static CC_NONNULL((1, 3))
-const uint8_t *ccber_decode_len(size_t *lenp, const uint8_t *der, const uint8_t *der_end) {
+static
+const uint8_t *ccber_decode_len(size_t *_Nonnull lenp, const uint8_t *_Nullable der, const uint8_t *_Nonnull der_end) {
     if (der && der < der_end) {
         if (*der == 0x80) {
             der++;
@@ -793,8 +793,8 @@ static const uint8_t *der_decode_optional_generalizedtime(CFAbsoluteTime *at, CF
     return times_end ? times_end : der;
 }
 
-static CC_NONNULL((2, 4))
-const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag, uint64_t* r, const uint8_t *der, const uint8_t *der_end) {
+static
+const uint8_t *ccder_decode_implicit_uint64(ccder_tag expected_tag, uint64_t *_Nonnull r, const uint8_t *_Nullable der, const uint8_t *_Nonnull der_end) {
     size_t len;
     der = ccder_decode_tl(expected_tag, &len, der, der_end);
     if (der && len && (*der & 0x80) != 0x80) {
@@ -1155,7 +1155,7 @@ bool SOSMessageWithSOSObjects(SOSMessageRef message, SOSDataSourceRef dataSource
         const uint8_t *der = CFDataGetBytePtr(object);
         const uint8_t *der_end = der + CFDataGetLength(object);
         // TODO Remove intermediate plist format
-        der = der_decode_dictionary(kCFAllocatorDefault, kCFPropertyListImmutable, &plist, error, der, der_end);
+        der = der_decode_dictionary(kCFAllocatorDefault, &plist, error, der, der_end);
         if (der) {
             SOSObjectRef peersObject = SOSObjectCreateWithPropertyList(dataSource, plist, error);
             withObject(peersObject, stop);
index 0e6579b4ea8bb0bd909978acaefca600f5cd325e..e7c785161aafed6a9c9d486ff81470a21b82862b 100644 (file)
@@ -61,11 +61,15 @@ static inline SOSPeerInfoRef asSOSPeerInfo(CFTypeRef obj) {
     return isSOSPeerInfo(obj) ? (SOSPeerInfoRef) obj : NULL;
 }
 
-SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonSigningKey, SecKeyRef octagonPeerEncryptionKey, CFErrorRef* error);
+SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey,
+                                 SecKeyRef octagonSigningKey, SecKeyRef octagonPeerEncryptionKey, bool supportsCKKS4All,
+                                 CFErrorRef* error);
 
 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
                                                       CFStringRef IDSID, CFStringRef transportType, CFBooleanRef preferIDS,
-                                                      CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey, SecKeyRef octagonSigningKey, SecKeyRef octagonPeerEncryptionKey, CFErrorRef* error);
+                                                      CFBooleanRef preferFragmentation, CFBooleanRef preferAckModel, CFSetRef enabledViews, SecKeyRef signingKey,
+                                                      SecKeyRef octagonSigningKey, SecKeyRef octagonPeerEncryptionKey, bool supportsCKKS4All,
+                                                      CFErrorRef* error);
 
 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error);
 
@@ -138,6 +142,8 @@ CFIndex SOSPeerInfoGetPeerProtocolVersion(SOSPeerInfoRef peer);
 
 // Stringified ID for this peer, not human readable.
 CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef peer);
+CFStringRef SOSPeerInfoGetSPID(SOSPeerInfoRef pi);
+
 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID);
 
 CFIndex SOSPeerInfoGetVersion(SOSPeerInfoRef peer);
@@ -153,7 +159,7 @@ CFTypeRef SOSPeerGestaltGetAnswer(CFDictionaryRef gestalt, CFStringRef question)
 SecKeyRef SOSPeerInfoCopyPubKey(SOSPeerInfoRef peer, CFErrorRef *error);
 SecKeyRef SOSPeerInfoCopyOctagonSigningPublicKey(SOSPeerInfoRef peer, CFErrorRef* error);
 SecKeyRef SOSPeerInfoCopyOctagonEncryptionPublicKey(SOSPeerInfoRef peer, CFErrorRef* error);
-void SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer,  SecKeyRef octagonSigningKey,
+bool SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer,  SecKeyRef octagonSigningKey,
                                             SecKeyRef octagonEncryptionKey, CFErrorRef *error);
 CFDataRef SOSPeerInfoGetAutoAcceptInfo(SOSPeerInfoRef peer);
 
@@ -183,6 +189,9 @@ void SOSPeerInfoWithEnabledViewSet(SOSPeerInfoRef pi, void (^operation)(CFSetRef
 uint64_t SOSViewBitmaskFromSet(CFSetRef views);
 uint64_t SOSPeerInfoViewBitMask(SOSPeerInfoRef pi);
 
+bool SOSPeerInfoSupportsCKKSForAll(SOSPeerInfoRef peerInfo);
+void SOSPeerInfoSetSupportsCKKSForAll(SOSPeerInfoRef peerInfo, bool supports);
+
 bool SOSPeerInfoKVSOnly(SOSPeerInfoRef pi);
 CFStringRef SOSPeerInfoCopyTransportType(SOSPeerInfoRef peer);
 CFStringRef SOSPeerInfoCopyDeviceID(SOSPeerInfoRef peer);
index 915cc40376b2055ee4b5f0b45525232e6eff7647..f7c304eb791d2ab3c7e87291b7ab72a3b04408d0 100644 (file)
@@ -37,7 +37,6 @@
 #include <dispatch/dispatch.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFRelease.h>
@@ -98,6 +97,8 @@ CFStringRef sPreferIDSACKModel          = CFSTR("PreferIDSAckModel");
 CFStringRef sTransportType              = CFSTR("TransportType");
 CFStringRef sDeviceID                   = CFSTR("DeviceID");
 
+CFStringRef sCKKSForAll                 = CFSTR("CKKS4A");
+
 const CFStringRef peerIDLengthKey             = CFSTR("idLength");
 
 SOSPeerInfoRef SOSPeerInfoAllocate(CFAllocatorRef allocator) {
@@ -158,10 +159,9 @@ static bool SOSDescriptionHash(SOSPeerInfoRef peer, const struct ccdigest_info *
 
 #define SIGLEN 128
 static CFDataRef sosCopySignedHash(SecKeyRef privkey, const struct ccdigest_info *di, uint8_t *hbuf) {
-    OSStatus stat;
     size_t siglen = SIGLEN;
     uint8_t sig[siglen];
-    if((stat = SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen)) != 0) {
+    if(SecKeyRawSign(privkey, kSecPaddingNone, hbuf, di->output_size, sig, &siglen) != 0) {
         return NULL;
     }
     return CFDataCreate(NULL, sig, (CFIndex)siglen);
@@ -230,6 +230,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
                                                  SecKeyRef signingKey,
                                                  SecKeyRef octagonPeerSigningKey,
                                                  SecKeyRef octagonPeerEncryptionKey,
+                                                 bool supportsCKKS4All,
                                                  CFErrorRef* error,
                                                  void (^ description_modifier)(CFMutableDictionaryRef description)) {
     SOSPeerInfoRef pi = CFTypeAllocate(SOSPeerInfo, struct __OpaqueSOSPeerInfo, allocator);
@@ -257,6 +258,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
         goto exit;
     }
 
+
     if (octagonPeerSigningKey) {
         SecKeyRef octagonPeerSigningPublicKey = SecKeyCreatePublicFromPrivate(octagonPeerSigningKey);
         if (octagonPeerSigningPublicKey == NULL) {
@@ -311,6 +313,7 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
     description_modifier(pi->description);
     
     pi->peerID = SOSCopyIDOfKey(publicKey, error);
+    pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
     
     pi->verifiedAppKeyID = NULL;
     pi->verifiedResult = false;
@@ -328,6 +331,8 @@ static SOSPeerInfoRef SOSPeerInfoCreate_Internal(CFAllocatorRef allocator,
     if (backup_key != NULL) SOSPeerInfoV2DictionarySetValue(pi, sBackupKeyKey, backup_key);
     SOSPeerInfoV2DictionarySetValue(pi, sViewsKey, enabledViews);
 
+    SOSPeerInfoSetSupportsCKKSForAll(pi, supportsCKKS4All);
+
     // ================ V2 Additions End
     
     if (!SOSPeerInfoSign(signingKey, pi, error)) {
@@ -344,8 +349,14 @@ exit:
     return pi;
 }
 
-SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey, SecKeyRef octagonPeerSigningKey, SecKeyRef octagonPeerEncryptionKey, CFErrorRef* error) {
-    return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
+SOSPeerInfoRef SOSPeerInfoCreate(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key, SecKeyRef signingKey,
+                                 SecKeyRef octagonPeerSigningKey,
+                                 SecKeyRef octagonPeerEncryptionKey,
+                                 bool supportsCKKS4All,
+                                 CFErrorRef* error) {
+    return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey,
+                                      supportsCKKS4All,
+                                      error, ^(CFMutableDictionaryRef description) {});
 }
 
 SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator, CFDictionaryRef gestalt, CFDataRef backup_key,
@@ -354,14 +365,19 @@ SOSPeerInfoRef SOSPeerInfoCreateWithTransportAndViews(CFAllocatorRef allocator,
                                                       SecKeyRef signingKey,
                                                       SecKeyRef octagonPeerSigningKey,
                                                       SecKeyRef octagonPeerEncryptionKey,
+                                                      bool supportsCKKS4All,
                                                       CFErrorRef* error)
 {
-    return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey, octagonPeerSigningKey, octagonPeerEncryptionKey, error, ^(CFMutableDictionaryRef description) {});
+    return SOSPeerInfoCreate_Internal(allocator, gestalt, backup_key, IDSID, transportType, preferIDS, preferFragmentation, preferAckModel, enabledViews, signingKey,
+                                      octagonPeerSigningKey,
+                                      octagonPeerEncryptionKey,
+                                      supportsCKKS4All,
+                                      error, ^(CFMutableDictionaryRef description) {});
 }
 
 
 SOSPeerInfoRef SOSPeerInfoCreateCloudIdentity(CFAllocatorRef allocator, CFDictionaryRef gestalt, SecKeyRef signingKey, CFErrorRef* error) {
-    return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, NULL, NULL, error, ^(CFMutableDictionaryRef description) {
+    return SOSPeerInfoCreate_Internal(allocator, gestalt, NULL, NULL, NULL, NULL, NULL, NULL, NULL, signingKey, NULL, NULL, false, error, ^(CFMutableDictionaryRef description) {
         CFDictionarySetValue(description, sCloudIdentityKey, kCFBooleanTrue);
     });
 
@@ -377,6 +393,7 @@ SOSPeerInfoRef SOSPeerInfoCreateCopy(CFAllocatorRef allocator, SOSPeerInfoRef to
 
     pi->gestalt = CFDictionaryCreateCopy(allocator, toCopy->gestalt);
     pi->peerID = CFStringCreateCopy(allocator, toCopy->peerID);
+    pi->spid = CFStringCreateCopy(allocator, toCopy->spid);
     pi->verifiedAppKeyID = NULL; // The peer resulting from this will need to be re-evaluated for an application signature.
     pi->verifiedResult = false;
 
@@ -414,10 +431,10 @@ SOSPeerInfoRef SOSPeerInfoCreateCurrentCopy(CFAllocatorRef allocator, SOSPeerInf
 }
 
 
-static SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
-                                                      SecKeyRef signingKey, CFErrorRef *error,
-                                                      bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error)) {
-
+SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
+                                               SecKeyRef signingKey, CFErrorRef *error,
+                                               bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error))
+{
     SOSPeerInfoRef result = NULL;
     SOSPeerInfoRef copy = SOSPeerInfoCreateCopy(allocator, original, error);
 
@@ -507,6 +524,7 @@ SOSPeerInfoRef SOSPeerInfoCopyWithPing(CFAllocatorRef allocator, SOSPeerInfoRef
     SecKeyRef pub_key = SOSPeerInfoCopyPubKey(pi, error);
     require_quiet(pub_key, exit);
     pi->peerID = SOSCopyIDOfKey(pub_key, error);
+    pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
     require_quiet(pi->peerID, exit);
     require_action_quiet(SOSPeerInfoSign(signingKey, pi, error), exit, CFReleaseNull(pi));
 exit:
@@ -528,8 +546,9 @@ static void SOSPeerInfoDestroy(CFTypeRef aObj) {
     CFReleaseNull(pi->signature);
     CFReleaseNull(pi->gestalt);
     CFReleaseNull(pi->peerID);
-    CFReleaseNull(pi->v2Dictionary);
+    CFReleaseNull(pi->spid);
     CFReleaseNull(pi->verifiedAppKeyID);
+    CFReleaseNull(pi->v2Dictionary);
     pi->verifiedResult = false;
 }
 
@@ -609,19 +628,19 @@ static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionary
     bool selfValid  = SOSPeerInfoVerify(pi, NULL);
     bool backingUp = SOSPeerInfoHasBackupKey(pi);
     bool isKVS = SOSPeerInfoKVSOnly(pi);
+    bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(pi);
     CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
     CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
     CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
     CFReleaseNull(tmp);
     CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
-    CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
 
     // Calculate the truncated length
 
     CFStringRef objectPrefix = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions, CFSTR("PI@%p"), pi);
     
     description = CFStringCreateWithFormat(kCFAllocatorDefault, formatOptions,
-                                           CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
+                                           CFSTR("<%@: [name: %20@] [%c%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]"),
                                            objectPrefix,
                                            isKnown(SOSPeerInfoGetPeerName(pi)),
                                            '-',
@@ -631,10 +650,10 @@ static CFStringRef copyDescriptionWithFormatOptions(CFTypeRef aObj, CFDictionary
                                            boolToChars(backingUp, 'B', 'b'),
                                            boolToChars(isKVS, 'K', 'I'),
                                            '-',
-                                           isKnown(SOSPeerInfoGetPeerDeviceType(pi)),  isKnown(peerID),
+                                           boolToChars(isCKKSForAll, 'C', '_'),
+                                           isKnown(SOSPeerInfoGetPeerDeviceType(pi)),  isKnown(SOSPeerInfoGetSPID(pi)),
                                            isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
 
-    CFReleaseNull(peerID);
     CFReleaseNull(deviceID);
     CFReleaseNull(serialNum);
     CFReleaseNull(objectPrefix);
@@ -660,25 +679,25 @@ void SOSPeerInfoLogState(char *category, SOSPeerInfoRef pi, SecKeyRef pubKey, CF
     bool backingUp = SOSPeerInfoHasBackupKey(pi);
     bool isMe = CFEqualSafe(SOSPeerInfoGetPeerID(pi), myPID) == true;
     bool isKVS = SOSPeerInfoKVSOnly(pi);
+    bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(pi);
     CFStringRef osVersion = CFDictionaryGetValue(pi->gestalt, kPIOSVersionKey);
     CFStringRef tmp = SOSPeerInfoV2DictionaryCopyString(pi, sDeviceID);
     CFStringRef deviceID = CFStringCreateTruncatedCopy(tmp, 8);
     CFReleaseNull(tmp);
     CFStringRef serialNum = SOSPeerInfoCopySerialNumber(pi);
-    CFStringRef peerID = CFStringCreateTruncatedCopy(SOSPeerInfoGetPeerID(pi), 8);
 
-    secnotice(category, "PI:    [name: %-20@] [%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]", isKnown(SOSPeerInfoGetPeerName(pi)),
+    secnotice(category, "PI:    [name: %-20@] [%c%c%c%c%c%c%c%c] [type: %-20@] [spid: %8@] [os: %10@] [devid: %10@] [serial: %12@]", isKnown(SOSPeerInfoGetPeerName(pi)),
               boolToChars(isMe, 'M', 'm'),
               boolToChars(appValid, 'A', 'a'),
               boolToChars(selfValid, 'S', 's'),
               boolToChars(retired, 'R', 'r'),
               boolToChars(backingUp, 'B', 'b'),
               boolToChars(isKVS, 'K', 'I'),
+              boolToChars(isCKKSForAll, 'C', '_'),
               sigchr,
-              isKnown(SOSPeerInfoGetPeerDeviceType(pi)),  isKnown(peerID),
+              isKnown(SOSPeerInfoGetPeerDeviceType(pi)),  isKnown(SOSPeerInfoGetSPID(pi)),
               isKnown(osVersion), isKnown(deviceID), isKnown(serialNum));
 
-    CFReleaseNull(peerID);
     CFReleaseNull(deviceID);
     CFReleaseNull(serialNum);
 }
@@ -716,6 +735,10 @@ CFStringRef SOSPeerInfoGetPeerID(SOSPeerInfoRef pi) {
     return pi ? pi->peerID : NULL;
 }
 
+CFStringRef SOSPeerInfoGetSPID(SOSPeerInfoRef pi) {
+    return pi ? pi->spid : NULL;
+}
+
 bool SOSPeerInfoPeerIDEqual(SOSPeerInfoRef pi, CFStringRef myPeerID) {
     return CFEqualSafe(myPeerID, SOSPeerInfoGetPeerID(pi));
 }
@@ -780,7 +803,7 @@ static CFDataRef sosCreateDate() {
 
 static CFDateRef sosCreateCFDate(CFDataRef sosdate) {
     CFDateRef date;
-    der_decode_date(NULL, 0, &date, NULL, CFDataGetBytePtr(sosdate),
+    der_decode_date(NULL, &date, NULL, CFDataGetBytePtr(sosdate),
                     CFDataGetBytePtr(sosdate) + CFDataGetLength(sosdate));
     return date;
 }
@@ -983,9 +1006,10 @@ SOSPeerInfoRef SOSPeerInfoUpgradeSignatures(CFAllocatorRef allocator, SecKeyRef
     return retval;
 }
 
-void SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer,  SecKeyRef octagonSigningKey,
+bool SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer,  SecKeyRef octagonSigningKey,
                                SecKeyRef octagonEncryptionKey, CFErrorRef *error)
 {
+    bool ret = false;
     CFDataRef signingPublicKeyBytes = NULL;
     CFDataRef encryptionPublicKeyBytes = NULL;
 
@@ -999,9 +1023,13 @@ void SOSPeerInfoSetOctagonKeysInDescription(SOSPeerInfoRef peer,  SecKeyRef octa
     CFDictionarySetValue(peer->description, sOctagonPeerSigningPublicKeyKey, signingPublicKeyBytes);
     CFDictionarySetValue(peer->description, sOctagonPeerEncryptionPublicKeyKey, encryptionPublicKeyBytes);
 
+    ret = true;
+
 fail:
     CFReleaseNull(signingPublicKeyBytes);
     CFReleaseNull(encryptionPublicKeyBytes);
+
+    return ret;
 }
 
 
index b71e7f93d8a51fcfadbd5f3bdddfba5a643e90cf..a1bc10ff9af535567125f9c55f051b262e0b908c 100644 (file)
@@ -77,8 +77,8 @@ SOSPeerInfoRef SOSPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* er
     pi->gestalt = NULL;
     pi->version = 0; // TODO: Encode this in the DER
     *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
-    *der_p = der_decode_plist(allocator, kCFPropertyListImmutable, &pl, error, *der_p, sequence_end);
-    *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &pi->signature, error, *der_p, sequence_end);
+    *der_p = der_decode_plist(allocator, &pl, error, *der_p, sequence_end);
+    *der_p = der_decode_data(allocator, &pi->signature, error, *der_p, sequence_end);
     
     if (*der_p == NULL || *der_p != sequence_end) {
         SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Peer Info DER"), NULL, error);
@@ -134,7 +134,8 @@ SOSPeerInfoRef SOSPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* er
     
     pi->peerID = SOSCopyIDOfKey(pubKey, error);
     require_quiet(pi->peerID, fail);
-    
+    pi->spid = CFStringCreateTruncatedCopy(pi->peerID, 8);
+
     if(pi->version >= 2) SOSPeerInfoExpandV2Data(pi, error);
     
     if(!SOSPeerInfoVerify(pi, error)) {
index c216d2c03e99c475f9bf69b10ccdf219b8c6b5fd..c669ab0a71c870e972b73fb74aacdc9508885398 100644 (file)
@@ -22,6 +22,7 @@ struct __OpaqueSOSPeerInfo {
     // Cached data
     CFDictionaryRef         gestalt;
     CFStringRef             peerID;
+    CFStringRef             spid;
     CFIndex                 version;
     CFStringRef             verifiedAppKeyID;
     bool                    verifiedResult;
@@ -35,6 +36,10 @@ bool SOSPeerInfoSign(SecKeyRef privKey, SOSPeerInfoRef peer, CFErrorRef *error);
 bool SOSPeerInfoVerify(SOSPeerInfoRef peer, CFErrorRef *error);
 void SOSPeerInfoSetVersionNumber(SOSPeerInfoRef pi, int version);
 
+SOSPeerInfoRef SOSPeerInfoCopyWithModification(CFAllocatorRef allocator, SOSPeerInfoRef original,
+                                               SecKeyRef signingKey, CFErrorRef *error,
+                                               bool (^modification)(SOSPeerInfoRef peerToModify, CFErrorRef *error));
+
 extern const CFStringRef peerIDLengthKey;
 
 #endif
index d482b24836fee03bafebf14b42bf272fbfe259de..661699f86229f6398a87aba902febc800165a972 100644 (file)
@@ -30,6 +30,8 @@ extern CFStringRef sRingState;                  // Dictionary of Ring Membership
 extern CFStringRef sBackupKeyKey;
 extern CFStringRef sEscrowRecord;
 
+extern CFStringRef sCKKSForAll;
+
 bool SOSPeerInfoUpdateToV2(SOSPeerInfoRef pi, CFErrorRef *error);
 void SOSPeerInfoPackV2Data(SOSPeerInfoRef peer);
 bool SOSPeerInfoExpandV2Data(SOSPeerInfoRef pi, CFErrorRef *error);
index 84eec8a6795b86e10bd11b312c3ba64cca10f90d..d3a812fb9ef4d0d3027f09750afe30e535ea8ab5 100644 (file)
@@ -127,7 +127,7 @@ static CFMutableDictionaryRef SOSCreateDictionaryFromDER(CFDataRef v2Data, CFErr
     const uint8_t *der_p = CFDataGetBytePtr(v2Data);
     const uint8_t *der_end = CFDataGetLength(v2Data) + der_p;
     
-    der_p = der_decode_plist(NULL, kCFPropertyListImmutable, &pl, error, der_p, der_end);
+    der_p = der_decode_plist(NULL, &pl, error, der_p, der_end);
 
     if (der_p == NULL || der_p != der_end) {
         SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Format of Dictionary DER"), NULL, error);
index 87c682fec597de7c1de0608bfde5b24dd2a0aad1..f2f93a8b7be96146caece137eff87dcf5d86259a 100644 (file)
 #include "keychain/SecureObjectSync/SOSPeerOTRTimer.h"
 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
 
-#include <utilities/SecADWrapper.h>
 #include <utilities/debugging.h>
 #include <utilities/SecCFWrappers.h>
 
 #include <AssertMacros.h>
 #include "keychain/SecureObjectSync/SOSInternal.h"
 
-//AGGD
-NSString* const SecSOSAggdMaxRenegotiation   = @"com.apple.security.sos.otrrenegotiationmaxretries";
-
 static int maxRetryCount = 7; //max number of times to attempt restarting OTR negotiation
 
 bool SOSPeerOTRTimerHaveReachedMaxRetryAllowance(SOSAccount* account, NSString* peerid){
@@ -37,7 +33,6 @@ bool SOSPeerOTRTimerHaveReachedMaxRetryAllowance(SOSAccount* account, NSString*
     if(attempt && [attempt intValue] >= maxRetryCount)
     {
         reachedMax = true;
-        SecADAddValueForScalarKey((__bridge CFStringRef) SecSOSAggdMaxRenegotiation,1);
     }
     return reachedMax;
 }
index 15d756f9b77f329b8d3a128e58474f73c9c07c27..104efeba65ee273603032947c19546308abae5fa 100644 (file)
@@ -71,8 +71,7 @@
 
 -(instancetype)initWithPeer:(SOSPeerRef)peer
 {
-    self = [super initWithConfig:[self setUpConfigForPeer]];
-    if(self){
+    if ((self = [super initWithConfig:[self setUpConfigForPeer]])) {
         self.peerID = (__bridge NSString *)(SOSPeerGetID(peer));
         self.accessGroupRateLimitState = [[NSMutableDictionary alloc] init];
         self.accessGroupToTimer = [[NSMutableDictionary alloc]init];
 
 -(instancetype)initWithAccessGroup:(NSString *)accessGroup
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         _accessGroup = accessGroup;
     }
     return self;
index 0234388fa56239cd0f15a9874a821796102c84c9..5780234c3d8320f327f9d366e1e811bc7ed20f85 100644 (file)
@@ -262,7 +262,7 @@ SOSPiggyCreateDecodedTLKs(const uint8_t *der, const uint8_t *der_end)
             CFErrorRef localError = NULL;
             CFStringRef string = NULL;
 
-            choice_der = der_decode_string(NULL, 0, &string, &localError, item_der, end_item_der);
+            choice_der = der_decode_string(NULL, &string, &localError, item_der, end_item_der);
             if (choice_der == NULL || string == NULL) {
                 CFReleaseNull(string);
                 secnotice("piggy", "Failed to parse view name");
@@ -365,7 +365,7 @@ SOSPiggyBackBlobCreateFromDER(SOSGenCountRef  *retGencount,
     *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
     require_action_quiet(sequence_end != NULL, errOut,
                          SOSCreateError(kSOSErrorBadFormat, CFSTR("Bad Blob DER"), (error != NULL) ? *error : NULL, error));
-    *der_p = der_decode_number(kCFAllocatorDefault, 0, &gencount, error, *der_p, sequence_end);
+    *der_p = der_decode_number(kCFAllocatorDefault, &gencount, error, *der_p, sequence_end);
     *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);
     
index 5555949b57cd7c72c995d99c72e8a5139b6a1f6f..91abdc17789c8cd09604ff4c03db8d6bf09668e4 100644 (file)
@@ -101,10 +101,10 @@ const uint8_t* der_decode_RecoveryKeyBag(CFAllocatorRef allocator,
     der = ccder_decode_sequence_tl(&sequence_end, der, der_end);
     require_quiet(sequence_end == der_end, fail);
     
-    der = der_decode_string(kCFAllocatorDefault, kCFPropertyListImmutable, &rb->accountDSID, error, der, sequence_end);
+    der = der_decode_string(kCFAllocatorDefault, &rb->accountDSID, error, der, sequence_end);
     rb->generation = SOSGenCountCreateFromDER(kCFAllocatorDefault, error, &der, sequence_end);
     der = ccder_decode_uint64(&rb->rkbVersion, der, sequence_end);
-    der = der_decode_data(allocator, kCFPropertyListImmutable, &rb->recoveryKeyBag, error, der, sequence_end);
+    der = der_decode_data(allocator, &rb->recoveryKeyBag, error, der, sequence_end);
     
     require_quiet(SecRequirementError(der == der_end, error, CFSTR("Extra space in sequence")), fail);
     if (RecoveryKeyBag) CFTransferRetained(*RecoveryKeyBag, rb);
index 26582d44419bbf63f583e64fb9cfc8851202ac29..1c9cba4c50da6c485304fbb296cd6f1ba21bb9b8 100644 (file)
@@ -24,7 +24,6 @@
 #include <utilities/SecCFWrappers.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRingUtils.h"
 #include "SOSRingTypes.h"
index 6c0cfa21af1634782f03e79033d27e910c922367..e2fea8b833b49585aa1ec44895367328318e1df6 100644 (file)
@@ -23,7 +23,6 @@
 #include <utilities/SecCFWrappers.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRingUtils.h"
 #include "SOSRingTypes.h"
index 2218db14803a6c5b1f97bf18ff47043c82012049..110aee5352c13e8826d6246da38365e07fbf7111 100644 (file)
@@ -34,7 +34,6 @@
 #include <utilities/der_date.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRing.h"
 #include "SOSRingUtils.h"
index 66d6f70ae49ab2256771c07c17d3ec20f0a2a02f..b53f54ad4a93a0fa8a549385f6f8127850aa584a 100644 (file)
@@ -35,7 +35,6 @@
 #include <utilities/der_date.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRingUtils.h"
 
@@ -79,10 +78,10 @@ SOSRingRef SOSRingCreateFromDER(CFErrorRef* error, const uint8_t** der_p, const
 
     require_action_quiet(ring, errOut, secnotice("ring", "Unable to allocate ring"));
     *der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, *der_p, der_end);
-    *der_p = der_decode_dictionary(ALLOCATOR, kCFPropertyListImmutable, &unSignedInformation, error, *der_p, sequence_end);
-    *der_p = der_decode_dictionary(ALLOCATOR, kCFPropertyListImmutable, &signedInformation, error, *der_p, sequence_end);
-    *der_p = der_decode_dictionary(ALLOCATOR, kCFPropertyListImmutable, &signatures, error, *der_p, sequence_end);
-    *der_p = der_decode_dictionary(ALLOCATOR, kCFPropertyListImmutable, &data, error, *der_p, sequence_end);
+    *der_p = der_decode_dictionary(ALLOCATOR, &unSignedInformation, error, *der_p, sequence_end);
+    *der_p = der_decode_dictionary(ALLOCATOR, &signedInformation, error, *der_p, sequence_end);
+    *der_p = der_decode_dictionary(ALLOCATOR, &signatures, error, *der_p, sequence_end);
+    *der_p = der_decode_dictionary(ALLOCATOR, &data, error, *der_p, sequence_end);
 
     require_action_quiet(*der_p, errOut, secnotice("ring", "Unable to decode DER"));
     require_action_quiet(*der_p == der_end, errOut, secnotice("ring", "Unable to decode DER"));
index a141de6208808b523618a26483f033b3f2870627..e18ddb0aea4c818672fc6711a7410264e08d1109 100644 (file)
@@ -35,7 +35,6 @@
 #include <utilities/der_date.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRing.h"
 #include "SOSRingUtils.h"
index 3a204d6818bef2e24225d1332abd00e356916bae..e513853c69387ec8e59ccde6dd59a14f6799a53d 100644 (file)
@@ -47,7 +47,6 @@
 #include <utilities/SecCFWrappers.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRingUtils.h"
 #include "SOSRingTypes.h"
index ddff4c19b057f831bf8c9fc6049afd43059054c3..ac2ad45d87d046b34855214e38a45279dabd53f7 100644 (file)
@@ -54,7 +54,7 @@
 #include <utilities/der_date.h>
 
 #include <stdlib.h>
-#include <assert.h>
+#include <utilities/simulatecrash_assert.h>
 
 #include "SOSRing.h"
 #include "SOSRingUtils.h"
@@ -730,16 +730,18 @@ static CFStringRef CreateCommaSeparatedPeerIDs(CFSetRef peers) {
 
     __block bool addSeparator = false;
 
-    CFSetForEachPeerID(peers, ^(CFStringRef peerID) {
-        if (addSeparator) {
-            CFStringAppendCString(result, ", ", kCFStringEncodingUTF8);
-        }
-        CFStringRef spid = CFStringCreateTruncatedCopy(peerID, 8);
-        CFStringAppend(result, spid);
-        CFReleaseNull(spid);
-
-        addSeparator = true;
-    });
+    if(peers) {
+        CFSetForEachPeerID(peers, ^(CFStringRef peerID) {
+            if (addSeparator) {
+                CFStringAppendCString(result, ", ", kCFStringEncodingUTF8);
+            }
+            CFStringRef spid = CFStringCreateTruncatedCopy(peerID, 8);
+            CFStringAppend(result, spid);
+            CFReleaseNull(spid);
+
+            addSeparator = true;
+        });
+    }
 
     return result;
 }
index 32e280564e6abe12ce45a86ff79096db7c6a57e5..e070bd93ada8dbc0d3ed0831f50b9eaeef70ed2e 100644 (file)
@@ -23,7 +23,6 @@
 #include <utilities/SecCFWrappers.h>
 
 #include <stdlib.h>
-#include <assert.h>
 
 #include "SOSRingUtils.h"
 #include "SOSRingTypes.h"
index ce9a8d821f605da00453c63bb6589e255fae8a78..4bdfe17cb344bcef38f531d1ca3d6f561bdaeb3e 100644 (file)
@@ -206,7 +206,7 @@ void SOSUpdateKeyInterest(SOSAccount* account)
     secnotice("key-interests", "Updating interests done: %lu", (unsigned long)itemCount);
 
     CFStringRef uuid = SOSAccountCopyUUID(account);
-    SOSCloudKeychainUpdateKeys(keyDict, uuid, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error) {
+    SOSCloudKeychainUpdateKeys(keyDict, uuid, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef error) {
         if (error) {
             secerror("Error updating keys: %@", error);
             account.key_interests_need_updating = true;
index 49145ab143493a3c3f356bcfe3d13c6e94a141ae..d58a85e148beee90f359280c9c8c23d855bf994a 100644 (file)
@@ -12,8 +12,7 @@
 }
 -(SOSCircleStorageTransport*) initWithAccount:(SOSAccount*)acct
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.account = acct;
     }
     return self;
index 2e3a4cc5d1cb9da8cf3b43e3c759ef0cefd5d942..4e82d1162ee6fe39b662a7456036ed5a6769a642 100644 (file)
@@ -15,8 +15,7 @@
 
 -(id) init
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         SOSRegisterTransportCircle(self);
     }
     return self;
@@ -24,9 +23,7 @@
 
 -(id) initWithAccount:(SOSAccount*)acct
 {
-    self = [super init];
-    if(self)
-    {
+    if ((self = [super init])) {
         self.account = acct;
     }
     return self;
index d3237e81ca9bd225575f5946a96b72ff22a1f503..1077f63990d788858e09e8762f38a4a019b5edeb 100644 (file)
@@ -25,8 +25,7 @@ extern CFStringRef kSOSAccountDebugScope;
 
 -(id)initWithAccount:(SOSAccount*)acct andCircleName:(NSString*)name
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.pending_changes = [NSMutableDictionary dictionary];
         self.circleName = [[NSString alloc] initWithString:name];
         self.account = acct;
@@ -52,7 +51,7 @@ static bool SOSTransportCircleKVSUpdateKVS(NSDictionary *changes, CFErrorRef *er
         }
     };
     
-    SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
+    SOSCloudKeychainPutObjectsInCloud((__bridge CFDictionaryRef)(changes), dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), log_error);
     return true;
 }
 
index 84b1bf27ae910616af81c02b043182df7feda6b8..25ccd6bbbbb979df54816fce21fbc28a4464c979 100644 (file)
@@ -35,8 +35,7 @@
 
 -(id) initWithAccount:(SOSAccount*) acct
 {
-    self  = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.account = acct;
         SOSRegisterTransportKeyParameter(self);
     }
@@ -57,7 +56,7 @@ static bool SOSTransportKeyParameterKVSUpdateKVS(CFDictionaryRef changes, CFErro
         }
     };
 
-    SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
+    SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), log_error);
     return true;
 }
 
index 407c55432f35e75f59dd50fe5efbf7cfec6e3c9c..1e6b247f99c5294041499bee96c2b217509b71d8 100644 (file)
@@ -5,8 +5,8 @@
 #include "keychain/SecureObjectSync/SOSEngine.h"
 #import "keychain/SecureObjectSync/SOSPeerRateLimiter.h"
 #import "keychain/SecureObjectSync/SOSPeerOTRTimer.h"
-#include <utilities/SecADWrapper.h>
 
+#import "utilities/SecCoreAnalytics.h"
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecPLWrappers.h>
 #include "keychain/SecureObjectSync/SOSInternal.h"
@@ -29,8 +29,7 @@ static const CFStringRef kSecAccessGroupCKKS                 = CFSTR("com.apple.
 
 -(id) initWithAccount:(SOSAccount*)acct andName:(NSString*)name
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         SOSEngineRef e = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, (__bridge CFStringRef)name, NULL);
         engine = e;
         account = acct;
@@ -89,6 +88,12 @@ static const CFStringRef kSecAccessGroupCKKS                 = CFSTR("com.apple.
 bool SOSEngineHandleCodedMessage(SOSAccount* account, SOSEngineRef engine, CFStringRef peerID, CFDataRef codedMessage, CFErrorRef*error) {
     __block bool result = true;
     __block bool somethingChanged = false;
+
+    if(account && account.accountIsChanging) {
+        secnotice("engine", "SOSEngineHandleCodedMessage called before signing in to new account");
+        return true; // we want to drop sync message notifications when account is changing
+    }
+
     result &= SOSEngineWithPeerID(engine, peerID, error, ^(SOSPeerRef peer, SOSCoderRef coder, SOSDataSourceRef dataSource, SOSTransactionRef txn, bool *shouldSave) {
         CFDataRef decodedMessage = NULL;
         enum SOSCoderUnwrapStatus uwstatus = SOSPeerHandleCoderMessage(peer, coder, peerID, codedMessage, &decodedMessage, shouldSave, error);
@@ -188,8 +193,8 @@ bool SOSEngineHandleCodedMessage(SOSAccount* account, SOSEngineRef engine, CFStr
             secnotice("otrtimer","peerID: %@ current date: %@, stored date: %@", peerid, currentDate, storedDate);
             secnotice("otrtimer", "rtt: %d", rtt);
             [self SOSTransportMessageCalculateNextTimer:account rtt:rtt peerid:peerid];
-            
-            SecADClientPushValueForDistributionKey(kSecSOSMessageRTT, rtt);
+
+            [SecCoreAnalytics sendEvent:(__bridge id)kSecSOSMessageRTT event:@{SecCoreAnalyticsValue: [NSNumber numberWithUnsignedInt:rtt]}];
             [peerToTimeLastSentDict removeObjectForKey:peerid]; //remove last sent message date
             SOSAccountSetValue(account, kSOSAccountPeerLastSentTimestamp, (__bridge CFMutableDictionaryRef)peerToTimeLastSentDict, NULL);
         }
index 68af1835fb8aa4a09619c3805b8e3f20f2c3fc5b..5d785ed90419a18684373fa90eadd08181f5c957 100644 (file)
@@ -3,7 +3,6 @@
 #import "keychain/SecureObjectSync/SOSTransportMessageKVS.h"
 #include "keychain/SecureObjectSync/SOSKVSKeys.h"
 #include <utilities/SecCFWrappers.h>
-#include <utilities/SecADWrapper.h>
 #include "keychain/SecureObjectSync/SOSInternal.h"
 #include <AssertMacros.h>
 #include "keychain/SecureObjectSync/CKBridge/SOSCloudKeychainClient.h"
@@ -14,9 +13,7 @@
 
 -(id) initWithAccount:(SOSAccount*)acct andName:(NSString*)name
 {
-    self = [super init];
-    
-    if (self) {
+    if ((self = [super init])) {
         account = acct;
         circleName = [[NSString alloc]initWithString:name];
         SOSEngineRef e = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, (__bridge CFStringRef)(circleName), NULL);
@@ -83,16 +80,13 @@ fail:
 }
 
 static bool SOSTransportMessageKVSUpdateKVS(SOSMessageKVS* transport, CFDictionaryRef changes, CFErrorRef *error){
-
-    SecADAddValueForScalarKey(CFSTR("com.apple.security.sos.sendkvs"), 1);
-
     CloudKeychainReplyBlock log_error = ^(CFDictionaryRef returnedValues __unused, CFErrorRef block_error) {
         if (block_error) {
             secerror("Error putting: %@", block_error);
         }
     };
     
-    SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
+    SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), log_error);
     return true;
 }
 
index 65f2d9e645f8bf653b03227b3e742ee933e8ad5a..7c328783ecd09d5730a141be9bba695292cac800 100644 (file)
@@ -116,6 +116,8 @@ typedef NS_OPTIONS(uint32_t, SOSAccountGhostBustingOptions) {
 - (void)ghostBustPeriodic:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool busted, NSError *error))complete;
 - (void)ghostBustTriggerTimed:(SOSAccountGhostBustingOptions)options complete: (void(^)(bool ghostBusted, NSError *error))complete;
 - (void)ghostBustInfo: (void(^)(NSData *json, NSError *error))complete;
+- (void)iCloudIdentityStatus_internal: (void(^)(NSDictionary *tableSpid, NSError *error))complete;
+- (void)iCloudIdentityStatus: (void (^)(NSData *json, NSError *error))complete;
 
 - (void)myPeerInfo:(void (^)(NSData *, NSError *))complete;
 - (void)circleHash:(void (^)(NSString *, NSError *))complete;
@@ -124,12 +126,14 @@ typedef NS_OPTIONS(uint32_t, SOSAccountGhostBustingOptions) {
 - (void)initialSyncCredentials:(uint32_t)flags complete:(void (^)(NSArray *, NSError *))complete;
 - (void)importInitialSyncCredentials:(NSArray *)items complete:(void (^)(bool success, NSError *))complete;
 
-- (void)triggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete;
+- (void)rpcTriggerSync:(NSArray <NSString *> *)peers complete:(void(^)(bool success, NSError *))complete;
 
 - (void)getWatchdogParameters:(void (^)(NSDictionary* parameters, NSError* error))complete;
 - (void)setWatchdogParmeters:(NSDictionary*)parameters complete:(void (^)(NSError* error))complete;
 
-- (void)triggerBackup:(NSArray<NSString *>*)backupPeers complete:(void (^)(NSError *error))complete;
+- (void)rpcTriggerBackup:(NSArray<NSString *>*)backupPeers complete:(void (^)(NSError *error))complete;
+- (void)rpcTriggerRingUpdate:(void (^)(NSError *error))complete;
+
 @end
 #endif
 
index 5e466ae78f903d4637518c02e2d1501907a0253b..a8ab22b3599f001c1b581e27f62e533b854c1414 100644 (file)
@@ -29,7 +29,6 @@
 #include <corecrypto/ccec.h>
 #include <corecrypto/ccdigest.h>
 #include <corecrypto/ccsha2.h>
-#include <CommonCrypto/CommonRandomSPI.h>
 #include <Security/SecKey.h>
 #include <Security/SecKeyPriv.h>
 #include <Security/SecFramework.h>
@@ -197,8 +196,8 @@ CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) {
     size_t iterations = ITERATIONMIN;
     size_t keysize = 256;
 
-    if(CCRandomCopyBytes(kCCRandomDefault, salt, sizeof(salt)) != kCCSuccess) {
-        SOSCreateError(kSOSErrorProcessingFailure, CFSTR("CCRandomCopyBytes failed"), NULL, error);
+    if (SecRandomCopyBytes(NULL, sizeof(salt), salt) != 0) {
+        SOSCreateError(kSOSErrorProcessingFailure, CFSTR("SecRandomCopyBytes failed"), NULL, error);
         return NULL;
     }
 
@@ -213,7 +212,7 @@ CFDataRef SOSUserKeyCreateGenerateParameters(CFErrorRef *error) {
         CFReleaseNull(result);
 
     if (result) {
-        secnotice("circleOps", "Created new parameters: iterations %zd, keysize %zd: %@", iterations, keysize, result);
+        debugDumpUserParameters(CFSTR("SOSUserKeyCreateGenerateParameters created new parameters:"), result);
     }
 
     return result;
@@ -259,7 +258,7 @@ SecKeyRef SOSUserKeygen(CFDataRef password, CFDataRef parameters, CFErrorRef *er
     ccec_const_cp_t cp = ccec_get_cp(keysize);
     ccec_full_ctx_decl_cp(cp, tmpkey);
 
-    secnotice("circleOps", "Generating key for: iterations %zd, keysize %zd: %@", iterations, keysize, parameters);
+    debugDumpUserParameters(CFSTR("SOSUserKeygen generating key for:"), parameters);
 
     size_t drbg_output_size=128;
     uint8_t drbg_output[drbg_output_size];
@@ -297,51 +296,28 @@ void debugDumpUserParameters(CFStringRef message, CFDataRef parameters)
 
 CF_RETURNS_RETAINED CFStringRef UserParametersDescription(CFDataRef parameters){
 
-    __block CFStringRef description = NULL;
-    CFDataRef newParameters = NULL;
-    SecKeyRef newKey = NULL;
-    
-    CFErrorRef error = NULL;
-    const uint8_t *parse_end = der_decode_cloud_parameters(kCFAllocatorDefault, kSecECDSAAlgorithmID,
-                                                           &newKey, &newParameters, &error,
-                                                           CFDataGetBytePtr(parameters), CFDataGetPastEndPtr(parameters));
-
-    if (parse_end != CFDataGetPastEndPtr(parameters)){
-        secdebug("circleOps", "failed to decode cloud parameters");
-        CFReleaseNull(newParameters);
-        CFReleaseNull(newKey);
+    if(parameters == NULL) {
         return NULL;
     }
-
+    __block CFStringRef description = NULL;
     size_t saltlen = 0;
     const uint8_t *salt = NULL;
-    
     size_t iterations = 0;
     size_t keysize = 0;
     
-    const uint8_t *der = CFDataGetBytePtr(newParameters);
-    const uint8_t *der_end = der + CFDataGetLength(newParameters);
+    const uint8_t *der = CFDataGetBytePtr(parameters);
+    const uint8_t *der_end = der + CFDataGetLength(parameters);
     
     der = der_decode_pbkdf2_params(&saltlen, &salt, &iterations, &keysize, der, der_end);
-    if (der != NULL) {
+    if (der != der_end) {
         secdebug("circleOps", "failed to decode pbkdf2 params");
-        CFReleaseNull(newParameters);
-        CFReleaseNull(newKey);
         return NULL;
     }
-    
-    CFStringRef userPubKeyID = SOSCopyIDOfKeyWithLength(newKey, 8, NULL);
-    
+
     BufferPerformWithHexString(salt, 4, ^(CFStringRef saltHex) { // Only dump 4 bytes worth of salthex
-        CFDataPerformWithHexString(newParameters, ^(CFStringRef parametersHex) {
-            description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Params: iter: %zd, size: %zd, salt: %@> <keyid: %@>"), iterations, keysize, saltHex, userPubKeyID);
-        });
+        description = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<Params: iter: %zd, size: %zd, salt: %@>"), iterations, keysize, saltHex);
     });
-    
-    CFReleaseNull(newParameters);
-    CFReleaseNull(newKey);
-    CFReleaseNull(userPubKeyID);
-    
+        
     return description;
 }
 
index 4098335d39d8006742c334427f93a58f2dc45a6a..0b7856876ce273d4d655155cb7612fd3f20c871d 100644 (file)
@@ -306,6 +306,26 @@ CFSetRef SOSViewCreateSetFromBitmask(uint64_t bitmask) {
     return retval;
 }
 
+bool SOSPeerInfoSupportsCKKSForAll(SOSPeerInfoRef peerInfo) {
+    if(!peerInfo) {
+        return false;
+    }
+
+    bool ret = false;
+    CFBooleanRef value = SOSPeerInfoV2DictionaryCopyBoolean(peerInfo, sCKKSForAll);
+
+    if(value) {
+        ret = CFBooleanGetValue(value) ? true : false;
+    }
+
+    CFReleaseNull(value);
+    return ret;
+}
+
+void SOSPeerInfoSetSupportsCKKSForAll(SOSPeerInfoRef peerInfo, bool supports) {
+    return SOSPeerInfoV2DictionarySetValue(peerInfo, sCKKSForAll, supports ? kCFBooleanTrue : kCFBooleanFalse);
+}
+
 const char *SOSViewsXlateAction(SOSViewActionCode action) {
     switch(action) {
         case kSOSCCViewEnable: return "kSOSCCViewEnable";
index 9cdf7d3a5c8e67ef6998f734e7337acba2e6265c..b9d0db31f79b91287ea37d9b93b5e648e1206de3 100644 (file)
@@ -149,7 +149,8 @@ static void printPeerInfos(char *label, CFStringRef mypeerID, CFArrayRef (^copyP
             CFStringRef bufstr = CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8);
             CFStringRef pid = SOSPeerInfoGetPeerID(peer);
             CFIndex vers = SOSPeerInfoGetVersion(peer);
-            printmsg(CFSTR("%@ pid:%@ V%d OS:%@\n"), bufstr, pid, vers, osVersion ?: CFSTR(""));
+            bool isCKKSForAll = SOSPeerInfoSupportsCKKSForAll(peer);
+            printmsg(CFSTR("%@ pid:%@ V%d %@ OS:%@\n"), bufstr, pid, vers, isCKKSForAll ? CFSTR("c4a") : CFSTR("SOS"), osVersion ?: CFSTR(""));
             CFRelease(bufstr);
 
             CFReleaseNull(gestalt);
index 5cb4adc9473cfc58115896917539282125239179..e545b84ed76f70607c0974065e19d7d1f4dcfb63 100644 (file)
@@ -489,7 +489,7 @@ keychain_sync(int argc, char * const *argv)
     CFMutableArrayRef peers2remove = NULL;
     SOSLogSetOutputTo(NULL, NULL);
 
-    while ((ch = getopt_long(argc, argv, "ab:deikmorv:NCDLOP:RT:UWV05", longopts, NULL)) != -1)
+    while ((ch = getopt_long(argc, argv, "ab:deikmorv:NCDLOP:RT:UWV05", longopts, NULL)) != -1) {
         switch  (ch) {
             case 'a':
             {
@@ -635,10 +635,25 @@ keychain_sync(int argc, char * const *argv)
                 }
                 break;
             }
+            case 0:
+            {
+                if (action == SYNC_REMOVE_PEER) {
+                    CFStringRef optstr = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+                    if (peers2remove == NULL) {
+                        peers2remove = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+                    }
+                    CFArrayAppendValue(peers2remove, optstr);
+                    CFReleaseNull(optstr);
+                } else {
+                    return SHOW_USAGE_MESSAGE;
+                }
+                break;
+            }
             case '?':
             default:
                 return SHOW_USAGE_MESSAGE;
         }
+    }
 
     if (peers2remove != NULL) {
         hadError = !doRemovePeers(peers2remove, &error);
index 1930811b07c1ba3e61d94d468cc51646fa851a1e..c381e08a2fea9ce62098e130f0d9e593a2e0de67 100644 (file)
@@ -15,9 +15,9 @@ __attribute__((visibility("hidden")))
 @interface SOSAccountConfiguration : PBCodable <NSCopying>
 {
     NSMutableArray<NSString *> *_pendingBackupPeers;
-    BOOL _sbdBackup;
+    BOOL _ringUpdateFlag;
     struct {
-        int sbdBackup:1;
+        int ringUpdateFlag:1;
     } _has;
 }
 
@@ -29,8 +29,8 @@ __attribute__((visibility("hidden")))
 - (NSString *)pendingBackupPeersAtIndex:(NSUInteger)idx;
 + (Class)pendingBackupPeersType;
 
-@property (nonatomic) BOOL hasSbdBackup;
-@property (nonatomic) BOOL sbdBackup;
+@property (nonatomic) BOOL hasRingUpdateFlag;
+@property (nonatomic) BOOL ringUpdateFlag;
 
 // Performs a shallow copy into other
 - (void)copyTo:(SOSAccountConfiguration *)other;
index f394355f408a4ed6132f3d591082b6ee8ed58d21..be89bc724b441b777bfb1df53db750052fb27d54 100644 (file)
 {
     return [NSString class];
 }
+@synthesize ringUpdateFlag = _ringUpdateFlag;
+- (void)setRingUpdateFlag:(BOOL)v
+{
+    _has.ringUpdateFlag = YES;
+    _ringUpdateFlag = v;
+}
+- (void)setHasRingUpdateFlag:(BOOL)f
+{
+    _has.ringUpdateFlag = f;
+}
+- (BOOL)hasRingUpdateFlag
+{
+    return _has.ringUpdateFlag != 0;
+}
 
 - (NSString *)description
 {
     {
         [dict setObject:self->_pendingBackupPeers forKey:@"pendingBackupPeers"];
     }
+    if (self->_has.ringUpdateFlag)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_ringUpdateFlag] forKey:@"ringUpdateFlag"];
+    }
     return dict;
 }
 
@@ -79,6 +97,12 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
                 }
             }
             break;
+            case 2 /* ringUpdateFlag */:
+            {
+                self->_has.ringUpdateFlag = YES;
+                self->_ringUpdateFlag = PBReaderReadBOOL(reader);
+            }
+            break;
             default:
                 if (!PBReaderSkipValueWithTag(reader, tag, aType))
                     return NO;
@@ -101,6 +125,13 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
             PBDataWriterWriteStringField(writer, s_pendingBackupPeers, 1);
         }
     }
+    /* ringUpdateFlag */
+    {
+        if (self->_has.ringUpdateFlag)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_ringUpdateFlag, 2);
+        }
+    }
 }
 
 - (void)copyTo:(SOSAccountConfiguration *)other
@@ -114,6 +145,11 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
             [other addPendingBackupPeers:[self pendingBackupPeersAtIndex:i]];
         }
     }
+    if (self->_has.ringUpdateFlag)
+    {
+        other->_ringUpdateFlag = _ringUpdateFlag;
+        other->_has.ringUpdateFlag = YES;
+    }
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -124,6 +160,11 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
         NSString *vCopy = [v copyWithZone:zone];
         [copy addPendingBackupPeers:vCopy];
     }
+    if (self->_has.ringUpdateFlag)
+    {
+        copy->_ringUpdateFlag = _ringUpdateFlag;
+        copy->_has.ringUpdateFlag = YES;
+    }
     return copy;
 }
 
@@ -133,6 +174,8 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
     return [other isMemberOfClass:[self class]]
     &&
     ((!self->_pendingBackupPeers && !other->_pendingBackupPeers) || [self->_pendingBackupPeers isEqual:other->_pendingBackupPeers])
+    &&
+    ((self->_has.ringUpdateFlag && other->_has.ringUpdateFlag && ((self->_ringUpdateFlag && other->_ringUpdateFlag) || (!self->_ringUpdateFlag && !other->_ringUpdateFlag))) || (!self->_has.ringUpdateFlag && !other->_has.ringUpdateFlag))
     ;
 }
 
@@ -141,6 +184,8 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
     return 0
     ^
     [self->_pendingBackupPeers hash]
+    ^
+    (self->_has.ringUpdateFlag ? PBHashInt((NSUInteger)self->_ringUpdateFlag) : 0)
     ;
 }
 
@@ -150,6 +195,11 @@ BOOL SOSAccountConfigurationReadFrom(__unsafe_unretained SOSAccountConfiguration
     {
         [self addPendingBackupPeers:iter_pendingBackupPeers];
     }
+    if (other->_has.ringUpdateFlag)
+    {
+        self->_ringUpdateFlag = other->_ringUpdateFlag;
+        self->_has.ringUpdateFlag = YES;
+    }
 }
 
 @end
index 998dc16b0fcd7ea1592933e371808fc269413717..efcb1e2c831afd2b2a5d448006d3c032da6b3fb9 100644 (file)
@@ -68,7 +68,7 @@
 
     attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
     XCTAssertNotNil(attrs, "should create genp");
-    XCTAssertEqual(attrs[@"OSStatus"], @(errSecDuplicateItem), "should have duplicate item");
+    XCTAssertEqual([attrs[@"OSStatus"] integerValue], errSecDuplicateItem, "should have duplicate item");
 }
 
 
@@ -80,7 +80,7 @@
 
     attrs = [self addGenericPassword:@"delete-me" service:@"delete-me"];
     XCTAssertNotNil(attrs, "should create genp");
-    XCTAssertEqual(attrs[@"OSStatus"], @(errSecDuplicateItem), "should have duplicate item");
+    XCTAssertEqual([attrs[@"OSStatus"] integerValue], errSecDuplicateItem, "should have duplicate item");
 
     XCTAssertEqual([self moveGenericPassword:@"delete-me" service:@"delete-me"
                                   newAccount:@"delete-me2" newService:@"delete-me2"],
index 97348ac597412e405475f86649684325eb709f2c..98966270a579ec26785700e855dfc81f7fa116e4 100644 (file)
 
 @implementation SecKeyTests
 
-- (void)testSecKeyAttributesCanBeReadWithMatchingStringsAsKeys
-{
+- (void)testSecKeyAttributesCanBeReadWithMatchingStringsAsKeys {
     CFMutableDictionaryRef keyParameters = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
     CFDictionarySetValue(keyParameters, kSecAttrKeyType, kSecAttrKeyTypeECSECPrimeRandom);
     CFDictionarySetValue(keyParameters, kSecAttrKeySizeInBits, (__bridge CFNumberRef)@(384));
     CFDictionarySetValue(keyParameters, CFSTR("nleg"), kCFBooleanTrue);
     SecKeyRef secKey = SecKeyCreateRandomKey(keyParameters, nil);
     NSDictionary* attributes = (__bridge_transfer NSDictionary*)SecKeyCopyAttributes(secKey);
-    XCTAssertEqual(attributes[(__bridge NSString*)kSecAttrKeySizeInBits], attributes[@"bsiz"], @"the SecKey attributes dictionary value of 'kSecAttrKeySizeInBits' and 'bsiz' are not the same");
+    XCTAssertEqualObjects(attributes[(__bridge NSString*)kSecAttrKeySizeInBits], attributes[@"bsiz"], @"the SecKey attributes dictionary value of 'kSecAttrKeySizeInBits' and 'bsiz' are not the same");
     XCTAssertNotNil(attributes[@"bsiz"], @"the SecKey attributes dictionary value for 'bsiz' is nil");
 }
 
+- (void)testECIESDecryptBadInputData {
+    NSData *message = [@"message" dataUsingEncoding:NSUTF8StringEncoding];
+    NSError *error;
+    id privKey = CFBridgingRelease(SecKeyCreateRandomKey((CFDictionaryRef)@{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeySizeInBits: @256}, (void *)&error));
+    XCTAssertNotNil(privKey, @"key generation failed: %@", error);
+    id pubKey = CFBridgingRelease(SecKeyCopyPublicKey((SecKeyRef)privKey));
+    XCTAssertNotNil(pubKey);
+    NSData *ciphertext = CFBridgingRelease(SecKeyCreateEncryptedData((SecKeyRef)pubKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM, (CFDataRef)message, (void *)&error));
+    XCTAssertNotNil(ciphertext, @"Encryption failed: %@", error);
+    NSData *plaintext = CFBridgingRelease(SecKeyCreateDecryptedData((SecKeyRef)privKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM, (CFDataRef)ciphertext, (void *)&error));
+    XCTAssertEqualObjects(message, plaintext, @"Decryption did not provide original message");
+
+    // Strip tag from ciphertext
+    NSData *strippedCiphertext = [ciphertext subdataWithRange:NSMakeRange(0, ciphertext.length - 16)];
+    NSData *failedDecrypted = CFBridgingRelease(SecKeyCreateDecryptedData((SecKeyRef)privKey, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM, (CFDataRef)strippedCiphertext, (void *)&error));
+    XCTAssertNil(failedDecrypted, @"Decryption of malformed data did not fail");
+    XCTAssertEqual(error.code, errSecParam, @"Unexpected error code provided");
+}
+
 @end
index 34c07c65949a45515df4311f5c4e17ca6961cc55..b6a06b8d86514f3e2d856169a12be8ae00f8e185 100644 (file)
@@ -38,8 +38,16 @@ typedef struct octagon_signpost_s {
 } OctagonSignpost;
 
 #define OctagonSignpostNamePerformEscrowRecovery                        "OctagonSignpostNamePerformEscrowRecovery"
+#define OctagonSignpostNamePerformSilentEscrowRecovery                  "OctagonSignpostNamePerformSilentEscrowRecovery"
 #define OctagonSignpostNamePerformRecoveryFromSBD                       "OctagonSignpostNamePerformRecoveryFromSBD"
-#define OctagonSignpostNamePerformBottleRecovery                        "OctagonSignpostNamePerformBottleRecovery"
+
+#define OctagonSignpostNameRecoverWithCDPContext                        "OctagonSignpostNameRecoverWithCDPContext"
+#define OctagonSignpostNameRecoverSilentWithCDPContext                  "OctagonSignpostNameRecoverSilentWithCDPContext"
+#define OctagonSignpostNamePerformOctagonJoinForSilent                  "OctagonSignpostNamePerformOctagonJoinForSilent"
+#define OctagonSignpostNamePerformOctagonJoinForNonSilent               "OctagonSignpostNamePerformOctagonJoinForNonSilent"
+
+
+#define OctagonSignpostNamePerformOctagonJoin                           "OctagonSignpostNamePerformOctagonJoin"
 #define OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle    "OctagonSignpostNamePerformResetAndEstablishAfterFailedBottle"
 #define OctagonSignpostNameFetchEgoPeer                                 "OctagonSignpostNameFetchEgoPeer"
 #define OctagonSignpostNameEstablish                                    "OctagonSignpostNameEstablish"
@@ -61,11 +69,13 @@ typedef struct octagon_signpost_s {
 #define OctagonSignpostNameRequestToJoinCircle                          "OctagonSignpostNameRequestToJoinCircle"
 #define OctagonSignpostNameAccountUserKeyAvailable                      "OctagonSignpostNameAccountUserKeyAvailable"
 #define OctagonSignpostNameFindOptimalBottleIDsWithContextData          "OctagonSignpostNameFindOptimalBottleIDsWithContextData"
+#define OctagonSignpostNameFetchEscrowRecords                           "OctagonSignpostNameFetchEscrowRecords"
 #define OctagonSignpostNameFetchEscrowContents                          "OctagonSignpostNameFetchEscrowContents"
 #define OctagonSignpostNameSetNewRecoveryKeyWithData                    "OctagonSignpostNameSetNewRecoveryKeyWithData"
 #define OctagonSignpostNameRecoverOctagonUsingData                      "OctagonSignpostNameRecoverOctagonUsingData"
 #define OctagonSignpostNamePerformedCDPStateMachineRun                  "OctagonSignpostNamePerformedCDPStateMachineRun"
 #define OctagonSignpostNameWaitForOctagonUpgrade                        "OctagonSignpostNameWaitForOctagonUpgrade"
+#define OctagonSignpostNameGetAccountInfo                               "OctagonSignpostNameGetAccountInfo"
 
 #define SOSSignpostNameAssertUserCredentialsAndOptionalDSID     "SOSSignpostNameAssertUserCredentialsAndOptionalDSID"
 #define SOSSignpostNameSOSCCTryUserCredentials                  "SOSSignpostNameSOSCCTryUserCredentials"
diff --git a/keychain/SigninMetrics/SFSignInAnalytics+Internal.h b/keychain/SigninMetrics/SFSignInAnalytics+Internal.h
deleted file mode 100644 (file)
index 9801140..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#if __OBJC2__
-#ifndef SFSignInAnalytics_Internal_h
-#define SFSignInAnalytics_Internal_h
-
-#import "SFSignInAnalytics.h"
-
-@interface SFSignInAnalytics (Internal)
-@property (readonly) NSString *signin_uuid;
-@property (readonly) NSString *my_uuid;
--(instancetype) initChildWithSignInUUID:(NSString*)signin_uuid andCategory:(NSString*)category andEventName:(NSString*)eventName;
-@end
-
-@interface SFSIALoggerObject : SFAnalytics
-+ (instancetype)logger;
-- (instancetype)init NS_UNAVAILABLE;
-@end
-
-#endif /* SFSignInAnalytics+Internal_h */
-#endif
diff --git a/keychain/SigninMetrics/SFSignInAnalytics.h b/keychain/SigninMetrics/SFSignInAnalytics.h
deleted file mode 100644 (file)
index 2863a4d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#if __OBJC2__
-#ifndef SignInAnalytics_h
-#define SignInAnalytics_h
-
-#import <Foundation/Foundation.h>
-#import <Security/SFAnalytics.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface SFSignInAnalytics : NSObject <NSSecureCoding>
-
-@property (readonly) NSString* eventName;
-@property (readonly) NSString* category;
-@property (readonly) BOOL stopped;
-
-/*
- abstract: creates a new SignInAnalytics object, automatically starts a timer for this task.
- uuid: iCloud sign in transaction UUID
- category: name of client subsystem.  This will be used as the category name when logging
- eventName: name of the event we are measuring
- */
-- (instancetype _Nullable)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName;
-- (instancetype)init NS_UNAVAILABLE;
-
-/*
- abstract: creates a new SignInAnalytics that starts a timer for the subtask.
-           ideal for fine grained timing of sub events and automatically creates a dependency chain.
- eventNmae: name of the event being timed
- */
-- (SFSignInAnalytics* _Nullable)newSubTaskForEvent:(NSString*)eventName;
-
-/*
- abstract: call to log when a recoverable error occurs during sign in
- error: error that occured during iCloud Sign in
- */
-- (void)logRecoverableError:(NSError*)error;
-
-/*
- abstract: call to log when a unrecoverable error occurs during sign in
- error: error that occured during iCloud Sign in
- */
-- (void)logUnrecoverableError:(NSError*)error;
-
-/*
- abstract: call to cancel the timer object.
- */
-- (void)cancel;
-
-/*
- abstract: call to stop a timer and log the time spent.
- eventName: subsystem name
- attributes: a dictionary containing event attributes
- */
-- (void)stopWithAttributes:(NSDictionary<NSString*, id>* _Nullable)attributes;
-
-/*
- abstract: call to signal iCloud sign in has finished.
- */
-- (void)signInCompleted;
-
-@end
-NS_ASSUME_NONNULL_END
-#endif /* SignInAnalytics_h */
-#endif
diff --git a/keychain/SigninMetrics/SFSignInAnalytics.m b/keychain/SigninMetrics/SFSignInAnalytics.m
deleted file mode 100644 (file)
index 3b079c9..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#if __OBJC2__
-
-#import "SFSignInAnalytics.h"
-#import "SFSignInAnalytics+Internal.h"
-
-#import <Analytics/SFAnalytics+Signin.h>
-#import "Analytics/SFAnalyticsDefines.h"
-#import "Analytics/SFAnalyticsSQLiteStore.h"
-#import "Analytics/SFAnalytics.h"
-
-#import <os/log_private.h>
-#import <mach/mach_time.h>
-#import <utilities/SecFileLocations.h>
-#import "utilities/debugging.h"
-#import <utilities/SecCFWrappers.h>
-
-//metrics database location
-NSString* signinMetricsDatabase = @"signin_metrics";
-
-//defaults write results location
-static NSString* const SFSignInAnalyticsDumpLoggedResultsToLocation = @"/tmp/signin_results.txt";
-static NSString* const SFSignInAnalyticsPersistedEventList = @"/tmp/signin_eventlist";
-
-//analytics constants
-static NSString* const SFSignInAnalyticsAttributeRecoverableError = @"recoverableError";
-static NSString* const SFSignInAnalyticsAttributeErrorDomain = @"errorDomain";
-static NSString* const SFSignInAnalyticsAttributeErrorCode = @"errorCode";
-static NSString* const SFSignInAnalyticsAttributeErrorChain = @"errorChain";
-static NSString* const SFSignInAnalyticsAttributeParentUUID = @"parentUUID";
-static NSString* const SFSignInAnalyticsAttributeMyUUID = @"myUUID";
-static NSString* const SFSignInAnalyticsAttributeSignInUUID = @"signinUUID";
-static NSString* const SFSignInAnalyticsAttributeEventName = @"eventName";
-static NSString* const SFSignInAnalyticsAttributeSubsystemName = @"subsystemName";
-static NSString* const SFSignInAnalyticsAttributeBuiltDependencyChains = @"dependencyChains";
-static NSString* const SFSignInAnalyticsAttributeTrackerTime = @"trackerTime";
-
-@implementation SFSIALoggerObject
-+ (NSString*)databasePath {
-    return [SFSIALoggerObject defaultAnalyticsDatabasePath:signinMetricsDatabase];
-}
-
-+ (instancetype)logger
-{
-    return [super logger];
-}
-@end
-
-
-@interface SFSignInAnalytics ()
-@property (nonatomic, copy) NSString *signin_uuid;
-@property (nonatomic, copy) NSString *my_uuid;
-@property (nonatomic, copy) NSString *parent_uuid;
-@property (nonatomic, copy) NSString *category;
-@property (nonatomic, copy) NSString *eventName;
-@property (nonatomic, copy) NSString *persistencePath;
-
-@property (nonatomic, strong) NSURL *persistedEventPlist;
-@property (nonatomic, strong) NSMutableDictionary *eventDependencyList;
-@property (nonatomic, strong) NSMutableArray *builtDependencyChains;
-
-@property (nonatomic) BOOL canceled;
-@property (nonatomic) BOOL stopped;
-
-@property (nonatomic, strong) os_log_t logObject;
-
-@property (nonatomic, strong) NSNumber *measurement;
-
-@property (nonatomic, strong) dispatch_queue_t queue;
-
-@property (nonatomic, strong) SFSignInAnalytics *root;
-@property (nonatomic, strong) SFAnalyticsActivityTracker *tracker;
-
--(os_log_t) newLogForCategoryName:(NSString*) category;
--(os_log_t) logForCategoryName:(NSString*) category;
-
-@end
-
-static NSMutableDictionary *logObjects;
-static const NSString* signInLogSpace = @"com.apple.security.wiiss";
-
-@implementation SFSignInAnalytics
-
-+ (BOOL)supportsSecureCoding {
-    return YES;
-}
-
--(os_log_t) logForCategoryName:(NSString*) category
-{
-    return logObjects[category];
-}
-
--(os_log_t) newLogForCategoryName:(NSString*) category
-{
-    return os_log_create([signInLogSpace UTF8String], [category UTF8String]);
-}
-
-- (BOOL)writeDependencyList:(NSError**)error
-{
-    NSError *localError = nil;
-    if (![NSPropertyListSerialization propertyList: self.root.eventDependencyList isValidForFormat: NSPropertyListXMLFormat_v1_0]){
-        os_log_error(self.logObject, "can't save PersistentState as XML");
-        return false;
-    }
-
-    NSData *data = [NSPropertyListSerialization dataWithPropertyList: self.root.eventDependencyList
-                                                              format: NSPropertyListXMLFormat_v1_0 options: 0 error: &localError];
-    if (data == nil){
-        os_log_error(self.logObject, "error serializing PersistentState to xml: %@", localError);
-        return false;
-    }
-
-    BOOL writeStatus = [data writeToURL:self.root.persistedEventPlist options: NSDataWritingAtomic error: &localError];
-    if (!writeStatus){
-        os_log_error(self.logObject, "error writing PersistentState to file: %@", localError);
-    }
-    if(localError && error){
-        *error = localError;
-    }
-
-    return writeStatus;
-}
-
-- (instancetype)initWithSignInUUID:(NSString *)uuid category:(NSString *)category eventName:(NSString*)eventName
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = uuid;
-
-        _my_uuid = uuid;
-        _parent_uuid = uuid;
-        _eventName = eventName;
-        _category = category;
-        _root = self;
-        _canceled = NO;
-        _stopped = NO;
-        _builtDependencyChains = [NSMutableArray array];
-
-        if ([self writeResultsToTmp]) {
-            //make plist file containing uuid parent/child
-            _persistencePath = [NSString stringWithFormat:@"%@-%@.plist", SFSignInAnalyticsPersistedEventList, eventName];
-            _persistedEventPlist = [NSURL fileURLWithPath:_persistencePath isDirectory:NO];
-        }
-
-        _eventDependencyList = [NSMutableDictionary dictionary];
-        [_eventDependencyList setObject:[NSMutableArray array] forKey:_signin_uuid];
-
-        _tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
-        [_tracker start];
-
-        NSError* error = nil;
-
-        if(self.root.persistedEventPlist && ![self writeDependencyList:&error] ){
-            os_log(self.logObject, "attempting to write dependency list: %@", error);
-        }
-
-        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-
-        static dispatch_once_t onceToken;
-        dispatch_once(&onceToken, ^{
-            logObjects = [NSMutableDictionary dictionary];
-        });
-        @synchronized(logObjects){
-            if(category){
-                _logObject = [self logForCategoryName:category];
-
-                if(!_logObject){
-                    _logObject = [self newLogForCategoryName:category];
-                    [logObjects setObject:_logObject forKey:category];
-                }
-            }
-        }
-    }
-    return self;
-}
-
--(instancetype) initChildWithSignInUUID:(NSString*)uuid andCategory:(NSString*)category andEventName:(NSString*)eventName
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = uuid;
-
-        _my_uuid = uuid;
-        _parent_uuid = uuid;
-        _eventName = eventName;
-        _category = category;
-        _canceled = NO;
-    }
-    return self;
-}
-
-- (void)encodeWithCoder:(NSCoder *)coder {
-    [coder encodeObject:_signin_uuid forKey:@"UUID"];
-    [coder encodeObject:_category forKey:@"category"];
-    [coder encodeObject:_parent_uuid forKey:@"parentUUID"];
-    [coder encodeObject:_my_uuid forKey:@"myUUID"];
-    [coder encodeObject:_measurement forKey:@"measurement"];
-    [coder encodeObject:_eventName forKey:@"eventName"];
-}
-
-- (nullable instancetype)initWithCoder:(NSCoder *)decoder
-{
-    self = [super init];
-    if (self) {
-        _signin_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"UUID"];
-        _category = [decoder decodeObjectOfClass:[NSString class] forKey:@"category"];
-        _parent_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"parentUUID"];
-        _my_uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"myUUID"];
-        _measurement = [decoder decodeObjectOfClass:[NSString class] forKey:@"measurement"];
-        _eventName = [decoder decodeObjectOfClass:[NSString class] forKey:@"eventName"];
-        _queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-
-        if(_signin_uuid == nil ||
-           _category == nil ||
-           _parent_uuid == nil){
-            [decoder failWithError:[NSError errorWithDomain:@"securityd" code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Failed to decode SignInAnalytics object"}]];
-            return nil;
-        }
-    }
-    return self;
-}
-
-- (SFSignInAnalytics*)newSubTaskForEvent:(NSString*)eventName
-{
-    SFSignInAnalytics *newSubTask = [[SFSignInAnalytics alloc] initChildWithSignInUUID:self.signin_uuid andCategory:self.category andEventName:self.eventName];
-    if(newSubTask){
-        newSubTask.my_uuid = [NSUUID UUID].UUIDString;
-        newSubTask.parent_uuid = self.my_uuid;
-        newSubTask.signin_uuid = self.signin_uuid;
-
-        newSubTask.category = self.category;
-        newSubTask.eventName = [eventName copy];
-        newSubTask.root = self.root;
-        newSubTask.canceled = NO;
-        newSubTask.stopped = NO;
-
-        newSubTask.queue = dispatch_queue_create("com.apple.security.SignInAnalytics", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-        newSubTask.tracker = [[SFSIALoggerObject logger] logSystemMetricsForActivityNamed:eventName withAction:nil];
-        [newSubTask.tracker start];
-
-        @synchronized(_eventDependencyList){
-            NSMutableArray *parentEntry = [newSubTask.root.eventDependencyList objectForKey:newSubTask.parent_uuid];
-            
-            //add new subtask entry to parent event's list
-            [parentEntry addObject:newSubTask.my_uuid];
-            [newSubTask.root.eventDependencyList setObject:parentEntry forKey:newSubTask.parent_uuid];
-            
-            //create new array list for this new subtask incase it has subtasks
-            [newSubTask.root.eventDependencyList setObject:[NSMutableArray array] forKey:newSubTask.my_uuid];
-            NSError* error = nil;
-            if(self.root.persistedEventPlist && ![newSubTask writeDependencyList:&error] ){
-                os_log(self.logObject, "attempting to write dependency list: %@", error);
-            }
-        }
-    }
-
-    return newSubTask;
-}
-
-- (void)logRecoverableError:(NSError*)error
-{
-
-    if (error == nil){
-        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
-        return;
-    }
-
-    os_log_error(self.logObject, "%@", error);
-
-    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
-
-    [eventAttributes setValuesForKeysWithDictionary:@{
-                                                      SFSignInAnalyticsAttributeRecoverableError : @(YES),
-                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
-                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
-                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
-                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
-                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
-                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
-                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
-                                                      }];
-
-    [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:eventAttributes];
-
-}
-
-- (void)logUnrecoverableError:(NSError*)error
-{
-    if (error == nil){
-        os_log_error(self.logObject, "attempting to log a nil error for event:%@", self.eventName);
-        return;
-    }
-
-    os_log_error(self.logObject, "%@", error);
-
-    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
-
-    [eventAttributes setValuesForKeysWithDictionary:@{
-                                                      SFSignInAnalyticsAttributeRecoverableError : @(NO),
-                                                      SFSignInAnalyticsAttributeErrorDomain : error.domain,
-                                                      SFSignInAnalyticsAttributeErrorCode : @(error.code),
-                                                      SFSignInAnalyticsAttributeMyUUID : self.my_uuid,
-                                                      SFSignInAnalyticsAttributeParentUUID : self.parent_uuid,
-                                                      SFSignInAnalyticsAttributeSignInUUID : self.signin_uuid,
-                                                      SFSignInAnalyticsAttributeEventName : self.eventName,
-                                                      SFSignInAnalyticsAttributeSubsystemName : self.category
-                                                      }];
-
-    [[SFSIALoggerObject logger] logHardFailureForEventNamed:self.eventName withAttributes:eventAttributes];
-}
-
--(void)cancel
-{
-    dispatch_sync(self.queue, ^{
-        [self.tracker cancel];
-        self.canceled = YES;
-        os_log(self.logObject, "canceled timer for %@", self.eventName);
-    });
-}
-
-- (void)stopWithAttributes:(NSDictionary<NSString*, id>*)attributes
-{
-    dispatch_sync(self.queue, ^{
-
-        if(self.canceled || self.stopped){
-            return;
-        }
-
-        self.stopped = YES;
-
-        [self.tracker stop];
-
-        NSMutableDictionary *mutableAttributes = nil;
-
-        if(attributes){
-            mutableAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes];
-        }
-        else{
-            mutableAttributes = [NSMutableDictionary dictionary];
-        }
-        mutableAttributes[SFSignInAnalyticsAttributeMyUUID] = self.my_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeParentUUID] = self.parent_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeSignInUUID] = self.signin_uuid;
-        mutableAttributes[SFSignInAnalyticsAttributeEventName] = self.eventName;
-        mutableAttributes[SFSignInAnalyticsAttributeSubsystemName] = self.category;
-        mutableAttributes[SFSignInAnalyticsAttributeTrackerTime] = self.tracker.measurement;
-
-        [mutableAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, id obj, BOOL * stop) {
-            os_log(self.logObject, "event: %@, %@  :  %@", self.eventName, key, obj);
-        }];
-        
-        [[SFSIALoggerObject logger] logSuccessForEventNamed:self.eventName];
-        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:self.eventName withAttributes:mutableAttributes];
-    });
-}
-
--(BOOL) writeResultsToTmp {
-
-    bool shouldWriteResultsToTemp = NO;
-    CFBooleanRef toTmp = (CFBooleanRef)CFPreferencesCopyValue(CFSTR("DumpResultsToTemp"),
-                                                                CFSTR("com.apple.security"),
-                                                                kCFPreferencesAnyUser, kCFPreferencesAnyHost);
-    if(toTmp && CFGetTypeID(toTmp) == CFBooleanGetTypeID()){
-        if(toTmp == kCFBooleanFalse){
-            os_log(self.logObject, "writing results to splunk");
-            shouldWriteResultsToTemp = NO;
-        }
-        if(toTmp == kCFBooleanTrue){
-            os_log(self.logObject, "writing results to /tmp");
-            shouldWriteResultsToTemp = YES;
-        }
-    }
-
-    CFReleaseNull(toTmp);
-    return shouldWriteResultsToTemp;
-}
-
-- (void)processEventChainForUUID:(NSString*)uuid dependencyChain:(NSString*)dependencyChain
-{
-    NSString* newChain = dependencyChain;
-
-    NSArray* children = [self.root.eventDependencyList objectForKey:uuid];
-    for (NSString* child in children) {
-        newChain = [NSString stringWithFormat:@"%@, %@", dependencyChain, child];
-        [self processEventChainForUUID:child dependencyChain:newChain];
-    }
-    if([children count] == 0){
-        [self.root.builtDependencyChains addObject:newChain];
-        os_log(self.logObject, "current dependency chain list: %@", newChain);
-    }
-}
-
-- (void)signInCompleted
-{
-    //print final
-    os_log(self.logObject, "sign in complete");
-    NSError* error = nil;
-
-    //create dependency chains and log them
-    [self processEventChainForUUID:self.root.my_uuid dependencyChain:self.root.signin_uuid];
-    //write to database
-    if([self.root.builtDependencyChains count] > 0){
-        NSDictionary* eventAttributes =  @{SFSignInAnalyticsAttributeBuiltDependencyChains : self.root.builtDependencyChains};
-        [[SFSIALoggerObject logger] logSoftFailureForEventNamed:SFSignInAnalyticsAttributeBuiltDependencyChains withAttributes:eventAttributes];
-    }
-
-    if([self writeResultsToTmp]){ //writing sign in analytics to /tmp
-        os_log(self.logObject, "logging to /tmp");
-
-        NSData* eventData = [NSKeyedArchiver archivedDataWithRootObject:[[SFSIALoggerObject logger].database allEvents] requiringSecureCoding:YES error:&error];
-        if(eventData){
-            [eventData writeToFile:SFSignInAnalyticsDumpLoggedResultsToLocation options:0 error:&error];
-
-            if(error){
-                os_log_error(self.logObject, "error writing to file [%@], error:%@", SFSignInAnalyticsDumpLoggedResultsToLocation, error);
-            }else{
-                os_log(self.logObject, "successfully wrote sign in analytics to:%@", SFSignInAnalyticsDumpLoggedResultsToLocation);
-            }
-        }else{
-            os_log_error(self.logObject, "collected no data");
-        }
-
-    }else{ //writing to splunk
-        os_log(self.logObject, "logging to splunk");
-    }
-
-    if (self.persistencePath) {
-        //remove dependency list
-        BOOL removedPersistedDependencyList = [[NSFileManager defaultManager] removeItemAtPath:self.persistencePath error:&error];
-        if(!removedPersistedDependencyList || error){
-            os_log(self.logObject, "encountered error when attempting to remove persisted event list: %@", error);
-        }
-    }
-}
-
-@end
-#endif
-
diff --git a/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m b/keychain/SigninMetrics/tests/SFSignInAnalyticsTests.m
deleted file mode 100644 (file)
index b52d9b4..0000000
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#import <XCTest/XCTest.h>
-#import "keychain/SigninMetrics/SFSignInAnalytics.h"
-#import "keychain/SigninMetrics/SFSignInAnalytics+Internal.h"
-#import "keychain/ot/OTDefines.h"
-#import "SFAnalytics+Signin.h"
-#import <Security/SecureObjectSync/SOSCloudCircle.h>
-
-static NSInteger _testnum;
-static NSString* _path;
-
-@interface SFSignInAnalyticsTester : SFSignInAnalytics
--(instancetype)init;
-@end
-
-@implementation SFSignInAnalyticsTester
-
-+ (NSString*)databasePath {
-    return _path;
-}
-
--(instancetype)init
-{
-    self = [super initWithSignInUUID:[NSUUID UUID].UUIDString category:@"CoreCDP" eventName:@"signin"];
-
-    return self;
-}
-
-@end
-
-
-@interface SignInAnalyticsTests : XCTestCase
-@property (nonatomic) SFSignInAnalyticsTester *metric;
-@end
-
-@implementation SignInAnalyticsTests
-
-
-- (void)setUp {
-    [super setUp];
-    _testnum = 0;
-    self.continueAfterFailure = NO;
-    _path = [@"/tmp" stringByAppendingFormat:@"/test_%ld.db", (long)++_testnum];
-    _metric = [[SFSignInAnalyticsTester alloc] init];
-    XCTAssertNotNil(_metric, "SignInAnalyticsTester object should not be nil");
-}
-
-- (void)tearDown
-{
-    dispatch_async([SFSIALoggerObject logger].queue, ^{
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from all_events"];
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from soft_failures"];
-        [[SFSIALoggerObject logger].database executeSQL:@"delete from hard_failures"];
-    });
-
-    [[SFSIALoggerObject logger] removeState];
-    _metric = nil;
-    [super tearDown];
-}
-
-- (void)testStop
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"restore",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-    
-    [_metric stopWithAttributes:attributes];
-
-    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([results count], 2, @"should have 2 results");
-    
-}
-
-- (void)testCancel
-{
-    [_metric cancel];
-}
-
-- (void)testLogError
-{
-    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
-    [_metric logRecoverableError:error];
-    NSArray* results = [[SFSIALoggerObject logger].database softFailures];
-    XCTAssertEqual([results count], 1, @"should have 1 results");
-}
-
-- (void)testCreateNewSubtask
-{
-    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
-    XCTAssertNotNil(child, "child should be created");
-    [[SFSIALoggerObject logger] removeState];
-    child = nil;
-}
-
-
-- (void)testCreateNewSubtaskAndStop
-{
-    SFSignInAnalytics* child = [_metric newSubTaskForEvent:@"restore"];
-
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-
-    [child stopWithAttributes:attributes];
-    
-    XCTAssertNotNil(child, "child should be created");
-
-    NSArray* results = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([results count], 2, @"should have 2 results");
-
-    [[SFSIALoggerObject logger] removeState];
-    child = nil;
-}
-
-- (void)testStopAfterCancel
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-
-    [_metric cancel];
-
-    [_metric stopWithAttributes:attributes];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([allEvents count], 0, @"should have 0 things logged");
-}
-
-- (void)testStopAfterStop
-{
-    sleep(2);
-    NSDictionary *attributes = @{@"success": @YES,
-                                 @"takenFlow" : @"piggyback",
-                                 };
-    XCTAssertNotNil(attributes, "attributes dictionary should exist");
-
-    [_metric stopWithAttributes:attributes];
-
-    [_metric stopWithAttributes:attributes];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-
-    XCTAssertEqual([allEvents count], 2, @"should have 2 things logged");
-}
-
--(void)testSignInComplete
-{
-    NSDictionary* attributes = [NSDictionary dictionary];
-    [_metric stopWithAttributes:attributes];
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array should not be nil");
-    XCTAssertTrue(allEvents && [allEvents count] > 0, "array should not be nil and contain an entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    XCTAssertTrue(dependencyEntry && [dependencyEntry count] > 0, "dictionary should not be nil and contain an entry");
-
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 1, "should be one list");
-
-    XCTAssertTrue([chains containsObject:_metric.signin_uuid], "should contain 1 uuid");
-}
-
--(void)testSingleChainDependencyList
-{
-    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
-    XCTAssertNotNil(child1, "child1 should be created");
-
-    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
-    XCTAssertNotNil(child2, "child2 should be created");
-
-    SFSignInAnalytics* child3 = [child2 newSubTaskForEvent:@"backup"];
-    XCTAssertNotNil(child3, "child3 should be created");
-
-    SFSignInAnalytics* child4 = [child3 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child4, "child4 should be created");
-
-    [_metric signInCompleted];
-
-    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", child1.signin_uuid, child1.my_uuid, child2.my_uuid, child3.my_uuid, child4.my_uuid];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "should not be nil");
-    XCTAssertTrue([allEvents count] > 0, "should be events");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 1, "should be one list");
-    XCTAssertTrue([expectedChain isEqualToString:[chains objectAtIndex:0]], "chains should be the same");
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-}
-
--(void)testMultipleChildrenPerEvent
-{
-    SFSignInAnalytics* child1 = [_metric newSubTaskForEvent:@"piggyback"];
-    XCTAssertNotNil(child1, "child1 should be created");
-
-    SFSignInAnalytics* child2 = [child1 newSubTaskForEvent:@"initialsync"];
-    XCTAssertNotNil(child2, "child2 should be created");
-
-    SFSignInAnalytics* child3 = [child1 newSubTaskForEvent:@"backup"];
-    XCTAssertNotNil(child3, "child3 should be created");
-
-    SFSignInAnalytics* child4 = [child1 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child4, "child4 should be created");
-
-    SFSignInAnalytics* child5 = [child2 newSubTaskForEvent:@"processing second ring"];
-    XCTAssertNotNil(child5, "child5 should be created");
-
-    SFSignInAnalytics* child6 = [child2 newSubTaskForEvent:@"processing third ring"];
-    XCTAssertNotNil(child6, "child6 should be created");
-
-    SFSignInAnalytics* child7 = [child2 newSubTaskForEvent:@"processing fourth ring"];
-    XCTAssertNotNil(child7, "child7 should be created");
-
-    SFSignInAnalytics* child8 = [child7 newSubTaskForEvent:@"processing fifth ring"];
-    XCTAssertNotNil(child8, "child8 should be created");
-
-    SFSignInAnalytics* child9 = [child7 newSubTaskForEvent:@"processing one ring"];
-    XCTAssertNotNil(child9, "child9 should be created");
-
-    NSString *expectedChain = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
-
-    NSString *expectedChain1 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child3.my_uuid];
-
-    NSString *expectedChain2 = [NSString stringWithFormat:@"%@, %@, %@", _metric.signin_uuid, child1.my_uuid, child4.my_uuid];
-
-    NSString *expectedChain3 = [NSString stringWithFormat:@"%@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child5.my_uuid];
-
-    NSString *expectedChain4 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child8.my_uuid];
-
-    NSString *expectedChain5 = [NSString stringWithFormat:@"%@, %@, %@, %@, %@", _metric.signin_uuid, child1.my_uuid, child2.my_uuid, child7.my_uuid, child9.my_uuid];
-
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertTrue([allEvents count] > 0, "array should not be empty");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-
-    XCTAssertEqual([chains count], 6, "should be one list");
-
-    XCTAssertTrue([chains containsObject:expectedChain], "chains should contain expectedChain");
-    XCTAssertTrue([chains containsObject:expectedChain1], "chains should contain expectedChain1");
-    XCTAssertTrue([chains containsObject:expectedChain2], "chains should contain expectedChain2");
-    XCTAssertTrue([chains containsObject:expectedChain3], "chains should contain expectedChain3");
-    XCTAssertTrue([chains containsObject:expectedChain4], "chains should contain expectedChain4");
-    XCTAssertTrue([chains containsObject:expectedChain5], "chains should contain expectedChain5");
-
-    [[SFSIALoggerObject logger] removeState];
-
-    child1 = nil;
-    child2 = nil;
-    child3 = nil;
-    child4 = nil;
-    child5 = nil;
-    child6 = nil;
-    child7 = nil;
-    child8 = nil;
-    child9 = nil;
-
-}
-
--(void)testSOSCCWaitForInitialSync
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    bool worked = SOSCCWaitForInitialSyncWithAnalytics(parentData, &error);
-    XCTAssertTrue(worked, "should have worked");
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRemoveThisDeviceFromCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    bool worked = SOSCCRemoveThisDeviceFromCircleWithAnalytics(parentData, &error);
-    XCTAssertTrue(worked, "should have worked");
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRequestToJoinCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCRequestToJoinCircleWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRequestToJoinCircleAfterRestore
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCRequestToJoinCircleAfterRestoreWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCRemovePeersFromCircle
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    NSArray* peers = [NSArray array];
-    SOSCCRemovePeersFromCircleWithAnalytics((__bridge CFArrayRef)peers, parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
-
--(void)testSOSCCViewSet
-{
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    CFSetRef enabledViews = nil;
-    CFSetRef disabledViews = nil;
-    SOSCCViewSetWithAnalytics(enabledViews, disabledViews, parentData);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCSetUserCredentialsAndDSID
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    CFStringRef label = nil;
-    CFDataRef password = nil;
-    CFStringRef dsid = nil;
-    SOSCCSetUserCredentialsAndDSIDWithAnalytics(label, password, dsid, parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
--(void)testSOSCCResetToEmpty
-{
-    CFErrorRef error = nil;
-    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
-    XCTAssertNotNil(archiver, "should not be nil");
-    [_metric encodeWithCoder:archiver];
-    CFDataRef parentData = (__bridge CFDataRef)archiver.encodedData;
-    XCTAssertNotNil((__bridge NSData*)parentData, "should not be nil");
-    SOSCCResetToEmptyWithAnalytics(parentData, &error);
-
-    [_metric signInCompleted];
-
-    NSArray *allEvents = [[SFSIALoggerObject logger].database allEvents];
-    XCTAssertNotNil(allEvents, "array is not nil");
-    XCTAssertEqual([allEvents count], 1, "array should not contain 1 entry");
-
-    NSDictionary *dependencyEntry = [allEvents objectAtIndex:[allEvents count]-1];
-    NSArray *chains = [dependencyEntry objectForKey:@"dependencyChains"];
-    XCTAssertNotNil(chains, "chains is not nil");
-    XCTAssertEqual([chains count], 1, "array should not contain 1 entry");
-}
-
-- (void)testMultipleDBConnections
-{
-    NSError* error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorBottleID userInfo:@{NSLocalizedDescriptionKey: @"Failed to deserialize bottle peer"}];
-    dispatch_queue_t test_queue = dispatch_queue_create("com.apple.security.signin.tests", DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL);
-
-    for(int i = 0; i < 1000; i++){
-        SFSignInAnalytics *test1 = [_metric newSubTaskForEvent:@"connection1"];
-        SFSignInAnalytics *test2 = [_metric newSubTaskForEvent:@"connection2"];
-
-        dispatch_async(test_queue, ^{
-            [test1 logRecoverableError:error];
-        });
-        dispatch_async(test_queue, ^{
-            [test2 stopWithAttributes:nil];
-        });
-        dispatch_async(test_queue, ^{
-            [self->_metric logRecoverableError:error];
-        });
-    }
-}
-@end
index db9d9914d50a51a54e8d5a6c11f6df96e9a6dc03..b19065e842f44f20dd081b62d9ac09acfdf7d6cd 100644 (file)
@@ -67,8 +67,7 @@
 
 - (instancetype)initAsInitiator:(bool)initiator version:(KCPairingChannelContext *)peerVersionContext device:(SecRemoteDevice *)device
 {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         self.remoteVersionContext = peerVersionContext;
         self.initiator = initiator;
         self.device = device;
 
 - (void)sosCircleStatus:(void(^)(SOSCCStatus status, NSError *error))complete
 {
-    SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
+    SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
         CFErrorRef cferror = NULL;
         SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
         complete(status, (__bridge NSError *)cferror);
 
 - (void)sosCircleStatusNonCached:(void(^)(SOSCCStatus status, NSError *error))complete
 {
-    SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
+    SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), ^(CFDictionaryRef __unused returnedValues, CFErrorRef __unused sync_error) {
         CFErrorRef cferror = NULL;
         SOSCCStatus status = SOSCCThisDeviceIsInCircleNonCached(&cferror);
         complete(status, (__bridge NSError *)cferror);
index 9689ecaea15664390f231b2ab3f6b21e347c04b9..b63671b2074b392fe37dc5cbb61bc9f861c97ee3 100644 (file)
@@ -16,7 +16,6 @@ extension CDAIOSDevice {
 }
 
 final class OctagonTests: CDTTestCase {
-
     let username: String? = nil
     let password: String? = nil
     var signedIn: Bool = false
@@ -111,7 +110,6 @@ final class OctagonTests: CDTTestCase {
     }
 
     func compareCKKSZone(name zone: String, status1: NSDictionary, status2: NSDictionary) -> Bool {
-
         let zone1 = status1[zone] as! NSDictionary
         let zone2 = status2[zone] as! NSDictionary
 
@@ -136,7 +134,6 @@ final class OctagonTests: CDTTestCase {
     }
 
     func compareCKKSStatus(c1: NSDictionary, c2: NSDictionary) -> Bool {
-
         let status1 = c1["status"] as! NSDictionary
         let status2 = c2["status"] as! NSDictionary
 
@@ -165,7 +162,6 @@ final class OctagonTests: CDTTestCase {
 
     func sosApplication(_ device: CDAIOSDevice, verbose: Bool = false) throws {
         if self.password != nil {
-
             print("submitting application\n")
 
             let password = try device.executeFile(atPath: securityTool, withArguments: ["sync", "-P", self.password!])
@@ -183,7 +179,6 @@ final class OctagonTests: CDTTestCase {
 
     func sosApprove(_ device: CDAIOSDevice, verbose: Bool = false) throws {
         if self.password != nil {
-
             print("approving applications\n")
 
             let password = try device.executeFile(atPath: securityTool, withArguments: ["sync", "-P", self.password!])
index d18c8a9f35b6dd165c40c0112b65738e7cf45edc..415e5d4b96f22032cd638427cd58bb6950257fcc 100644 (file)
@@ -25,22 +25,21 @@ import Foundation
 import SecurityFoundation
 
 class BottledPeer: NSObject {
+    var escrowKeys: EscrowKeys
+    var secret: Data
+    var peerID: String
+    var bottleID: String
+    var peerKeys: OctagonSelfPeerKeys
 
-    public var escrowKeys: EscrowKeys
-    public var secret: Data
-    public var peerID: String
-    public var bottleID: String
-    public var peerKeys: OctagonSelfPeerKeys
+    var signatureUsingEscrowKey: Data
+    var signatureUsingPeerKey: Data
+    var escrowSigningPublicKey: Data
+    var escrowSigningSPKI: Data
+    var peersigningSPKI: Data
 
-    public var signatureUsingEscrowKey: Data
-    public var signatureUsingPeerKey: Data
-    public var escrowSigningPublicKey: Data
-    public var escrowSigningSPKI: Data
-    public var peersigningSPKI: Data
+    var contents: Data
 
-    public var contents: Data
-
-    public class func encryptionOperation() -> (_SFAuthenticatedEncryptionOperation) {
+    class func encryptionOperation() -> (_SFAuthenticatedEncryptionOperation) {
         let keySpecifier = _SFAESKeySpecifier.init(bitSize: TPHObjectiveC.aes256BitSize())
         return _SFAuthenticatedEncryptionOperation.init(keySpecifier: keySpecifier)
     }
@@ -48,8 +47,7 @@ class BottledPeer: NSObject {
     // 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.
-    public init (peerID: String, bottleID: String, peerSigningKey: _SFECKeyPair, peerEncryptionKey: _SFECKeyPair, bottleSalt: String) throws {
-
+    init (peerID: String, bottleID: String, peerSigningKey: _SFECKeyPair, peerEncryptionKey: _SFECKeyPair, bottleSalt: String) throws {
         let secret = try BottledPeer.makeMeSomeEntropy(requiredLength: Int(OTMasterSecretLength))
 
         self.secret = secret
@@ -130,8 +128,7 @@ class BottledPeer: NSObject {
 
     // Deserialize a bottle (data) and decrypt the contents (peer keys)
     // using the keys generated from the escrow secret, and signatures from signing keys
-    public init (contents: Data, secret: Data, bottleSalt: String, signatureUsingEscrow: Data, signatureUsingPeerKey: Data) throws {
-
+    init (contents: Data, secret: Data, bottleSalt: String, signatureUsingEscrow: Data, signatureUsingPeerKey: Data) throws {
         self.secret = secret
         self.escrowKeys = try EscrowKeys(secret: self.secret, bottleSalt: bottleSalt)
 
@@ -210,24 +207,24 @@ class BottledPeer: NSObject {
         try xso.verify(peerSigned, with: peerPublicKey)
     }
 
-    public func escrowSigningPublicKeyHash() -> String {
+    func escrowSigningPublicKeyHash() -> String {
         return TPHObjectiveC.digest(usingSha384: self.escrowSigningPublicKey)
     }
 
-    public class func signingOperation() -> (_SFEC_X962SigningOperation) {
+    class func signingOperation() -> (_SFEC_X962SigningOperation) {
         let keySpecifier = _SFECKeySpecifier.init(curve: SFEllipticCurve.nistp384)
         let digestOperation = _SFSHA384DigestOperation.init()
         return _SFEC_X962SigningOperation.init(keySpecifier: keySpecifier, digestOperation: digestOperation)
     }
 
-    public class func verifyBottleSignature(data: Data, signature: Data, pubKey: _SFECPublicKey) throws -> (Bool) {
+    class func verifyBottleSignature(data: Data, signature: Data, pubKey: _SFECPublicKey) throws -> (Bool) {
         let xso = BottledPeer.signingOperation()
         let peerSigned = _SFSignedData.init(data: data, signature: signature)
         try xso.verify(peerSigned, with: pubKey)
         return true
     }
 
-    public class func makeMeSomeEntropy(requiredLength: Int) throws -> Data {
+    class func makeMeSomeEntropy(requiredLength: Int) throws -> Data {
         let bytesPointer = UnsafeMutableRawPointer.allocate(byteCount: requiredLength, alignment: 1)
 
         if SecRandomCopyBytes(kSecRandomDefault, requiredLength, bytesPointer) != 0 {
@@ -253,7 +250,7 @@ extension BottledPeer {
 }
 
 extension BottledPeer.Error: LocalizedError {
-    public var errorDescription: String? {
+    var errorDescription: String? {
         switch self {
         case .OTErrorDeserializationFailure:
             return "Failed to deserialize bottle peer"
index 4669d72f4e7175ef70103cdba88dd18b67f6cf5e..206463d07f6482293b86e3a19344be6344f0f1cb 100644 (file)
@@ -35,14 +35,14 @@ enum EscrowKeyType: Int {
 }
 
 class EscrowKeys: NSObject {
-    public var encryptionKey: _SFECKeyPair
-    public var signingKey: _SFECKeyPair
-    public var symmetricKey: _SFAESKey
+    var encryptionKey: _SFECKeyPair
+    var signingKey: _SFECKeyPair
+    var symmetricKey: _SFAESKey
 
-    public var secret: Data
-    public var bottleSalt: String
+    var secret: Data
+    var bottleSalt: String
 
-    public init (secret: Data, bottleSalt: String) throws {
+    init (secret: Data, bottleSalt: String) throws {
         self.secret = secret
         self.bottleSalt = bottleSalt
 
@@ -86,7 +86,6 @@ class EscrowKeys: NSObject {
 
             let infoString = Array("Escrow Signing Private Key".utf8)
             info = Data(bytes: infoString, count: infoString.count)
-
         }
 
         guard let cp = ccec_cp_384() else {
@@ -122,7 +121,7 @@ class EscrowKeys: NSObject {
                         } else if keyType == EscrowKeyType.kOTEscrowKeyEncryption || keyType == EscrowKeyType.kOTEscrowKeySigning {
                             status = ccec_generate_key_deterministic(cp,
                                                                      derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!,
-                                                                     ccDRBGGetRngState(),
+                                                                     ccrng(nil),
                                                                      UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS),
                                                                      fullKey)
 
@@ -195,7 +194,6 @@ class EscrowKeys: NSObject {
     }
 
     class func storeEscrowedEncryptionKeyPair(keyData: Data, label: String) throws -> (Bool) {
-
         let query: [CFString: Any] = [
             kSecClass: kSecClassKey,
             kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
@@ -284,15 +282,15 @@ class EscrowKeys: NSObject {
             let keyTypeData = item[kSecAttrApplicationLabel as CFString] as! Data
             let keyType = String(data: keyTypeData, encoding: .utf8)!
 
-            if keyType.range(of: "Symmetric") != nil {
+            if keyType.contains("Symmetric") {
                 let keyData = item[kSecValueData as CFString] as! Data
                 let specifier = _SFAESKeySpecifier.init(bitSize: TPHObjectiveC.aes256BitSize())
                 symmetricKey = try _SFAESKey.init(data: keyData, specifier: specifier)
-            } else if keyType.range(of: "Encryption") != nil {
+            } else if keyType.contains("Encryption") {
                 let keyData = item[kSecValueData as CFString] as! Data
                 let encryptionSecKey = try EscrowKeys.createSecKey(keyData: keyData)
                 encryptionKey = _SFECKeyPair.init(secKey: encryptionSecKey)
-            } else if keyType.range(of: "Signing") != nil {
+            } else if keyType.contains("Signing") {
                 let keyData = item[kSecValueData as CFString] as! Data
                 let signingSecKey = try EscrowKeys.createSecKey(keyData: keyData)
                 signingKey = _SFECKeyPair.init(secKey: signingSecKey)
@@ -314,7 +312,7 @@ enum EscrowKeysError: Error {
 }
 
 extension EscrowKeysError: LocalizedError {
-    public var errorDescription: String? {
+    var errorDescription: String? {
         switch self {
         case .keyGeneration:
             return "Key generation failed"
@@ -331,12 +329,11 @@ extension EscrowKeysError: LocalizedError {
 }
 
 extension EscrowKeysError: CustomNSError {
-
-    public static var errorDomain: String {
+    static var errorDomain: String {
         return "com.apple.security.trustedpeers.EscrowKeys"
     }
 
-    public var errorCode: Int {
+    var errorCode: Int {
         switch self {
         case .keyGeneration:
             return 1
@@ -351,7 +348,7 @@ extension EscrowKeysError: CustomNSError {
         }
     }
 
-    public var errorUserInfo: [String: Any] {
+    var errorUserInfo: [String: Any] {
         var userInfo: [String: Any] = [:]
         if let desc = self.errorDescription {
             userInfo[NSLocalizedDescriptionKey] = desc
index 64dfe9f122a5044102f17423eb7588d27b7e136a..a414db52888412f971dad3cecaf02432923f32df 100644 (file)
 
 import Foundation
 
+extension Error {
+    func sanitizeForClientXPC() -> Error {
+        let nserror = self as NSError
+
+        // CoreData errors might have extra things in them that need removal.
+        if nserror.domain == NSCocoaErrorDomain {
+            return nserror.cleanAllButDescription()
+        }
+
+        // The docs for CKXPCSuitableError say it only returns nil if you pass it nil, but swift can't read those.
+        guard let ckCleanedError = CKXPCSuitableError(self) else {
+            return ContainerError.unknownCloudKitError
+        }
+        return ckCleanedError
+    }
+}
+
+extension NSError {
+    func cleanAllButDescription() -> NSError {
+        let userInfo: [String: AnyHashable]?
+        if let description = self.userInfo[NSLocalizedDescriptionKey] as? AnyHashable {
+            userInfo = [NSLocalizedDescriptionKey: description]
+        } else {
+            userInfo = nil
+        }
+
+        return NSError(domain: self.domain,
+                       code: self.code,
+                       userInfo: userInfo)
+    }
+}
+
 class Client: TrustedPeersHelperProtocol {
 
     let endpoint: NSXPCListenerEndpoint?
@@ -57,11 +89,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.dump { result, error in
                 self.logComplete(function: "Dumping", container: container.name, error: error)
-                reply(result, CKXPCSuitableError(error))
+                reply(result, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Dumping failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -74,11 +106,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.dumpEgoPeer { peerID, perm, stable, dyn, error in
                 self.logComplete(function: "Dumping peer", container: container.name, error: error)
-                reply(peerID, perm, stable, dyn, CKXPCSuitableError(error))
+                reply(peerID, perm, stable, dyn, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Dumping peer failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -86,7 +118,9 @@ class Client: TrustedPeersHelperProtocol {
         do {
             let containerName = ContainerName(container: container, context: context)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.trustStatus(reply: reply)
+            container.trustStatus { egoPeerStatus, error in
+                reply(egoPeerStatus, error?.sanitizeForClientXPC())
+            }
         } catch {
             os_log("Trust status failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
             reply(TrustedPeersHelperEgoPeerStatus(egoPeerID: nil,
@@ -95,7 +129,7 @@ class Client: TrustedPeersHelperProtocol {
                                                   peerCountsByMachineID: [:],
                                                   isExcluded: false,
                                                   isLocked: false),
-                  CKXPCSuitableError(error))
+                  error.sanitizeForClientXPC())
         }
     }
 
@@ -104,10 +138,12 @@ class Client: TrustedPeersHelperProtocol {
             let containerName = ContainerName(container: container, context: context)
             os_log("Fetch Trust State for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.fetchTrustState(reply: reply)
+            container.fetchTrustState { peerState, peerList, error in
+                reply(peerState, peerList, error?.sanitizeForClientXPC())
+            }
         } catch {
             os_log("Fetch Trust State failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -118,10 +154,10 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.reset(resetReason: resetReason) { error in
                 self.logComplete(function: "Resetting", container: container.name, error: error)
-                reply(CKXPCSuitableError(error)) }
+                reply(error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Resetting failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -132,11 +168,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.localReset { error in
                 self.logComplete(function: "Local reset", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Local reset failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -151,11 +187,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.setAllowedMachineIDs(allowedMachineIDs, honorIDMSListChanges: honorIDMSListChanges) { differences, error in
                 self.logComplete(function: "Setting allowed machineIDs", container: container.name, error: error)
-                reply(differences, CKXPCSuitableError(error))
+                reply(differences, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Setting allowed machineIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(false, CKXPCSuitableError(error))
+            reply(false, error.sanitizeForClientXPC())
         }
     }
 
@@ -169,11 +205,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.addAllow(machineIDs) { error in
                 self.logComplete(function: "Adding allowed machineIDs", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Adding allowed machineID failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -187,11 +223,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.removeAllow(machineIDs) { error in
                 self.logComplete(function: "Removing allowed machineIDs", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Removing allowed machineID failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -202,11 +238,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.fetchAllowedMachineIDs { mids, error in
                 self.logComplete(function: "Fetched allowed machineIDs", container: container.name, error: error)
-                reply(mids, CKXPCSuitableError(error))
+                reply(mids, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Fetching allowed machineIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -216,11 +252,11 @@ class Client: TrustedPeersHelperProtocol {
             os_log("retrieving epoch for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.getEgoEpoch { epoch, error in
-                reply(epoch, CKXPCSuitableError(error))
+                reply(epoch, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Epoch retrieval failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(0, CKXPCSuitableError(error))
+            reply(0, error.sanitizeForClientXPC())
         }
     }
 
@@ -232,13 +268,14 @@ class Client: TrustedPeersHelperProtocol {
                  bottleID: String,
                  modelID: String,
                  deviceName: String?,
-                 serialNumber: String,
+                 serialNumber: String?,
                  osVersion: String,
                  policyVersion: TPPolicyVersion?,
                  policySecrets: [String: Data]?,
+                 syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus,
                  signingPrivKeyPersistentRef: Data?,
                  encPrivKeyPersistentRef: Data?,
-                 reply: @escaping (String?, Data?, Data?, Data?, Data?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                 reply: @escaping (String?, Data?, Data?, Data?, Data?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Preparing new identity for %{public}@", log: tplogDebug, type: .default, containerName.description)
@@ -253,14 +290,15 @@ class Client: TrustedPeersHelperProtocol {
                               osVersion: osVersion,
                               policyVersion: policyVersion,
                               policySecrets: policySecrets,
+                              syncUserControllableViews: syncUserControllableViews,
                               signingPrivateKeyPersistentRef: signingPrivKeyPersistentRef,
-                              encryptionPrivateKeyPersistentRef: encPrivKeyPersistentRef) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, views, policy, error in
+                              encryptionPrivateKeyPersistentRef: encPrivKeyPersistentRef) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, policy, error in
                                 self.logComplete(function: "Prepare", container: container.name, error: error)
-                                reply(peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, views, policy, CKXPCSuitableError(error))
+                                reply(peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, policy, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Prepare failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, nil, nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -269,19 +307,19 @@ class Client: TrustedPeersHelperProtocol {
                    ckksKeys: [CKKSKeychainBackedKeySet],
                    tlkShares: [CKKSTLKShare],
                    preapprovedKeys: [Data]?,
-                   reply: @escaping (String?, [CKRecord]?, Error?) -> Void) {
+                   reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Establishing %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.establish(ckksKeys: ckksKeys,
                                 tlkShares: tlkShares,
-                                preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, error in
+                                preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
                                     self.logComplete(function: "Establishing", container: container.name, error: error)
-                                    reply(peerID, keyHierarchyRecords, CKXPCSuitableError(error)) }
+                                    reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Establishing failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -305,27 +343,27 @@ class Client: TrustedPeersHelperProtocol {
                             stableInfoSig: stableInfoSig,
                             ckksKeys: ckksKeys) { voucher, voucherSig, error in
                                 self.logComplete(function: "Vouching", container: container.name, error: error)
-                                reply(voucher, voucherSig, CKXPCSuitableError(error)) }
+                                reply(voucher, voucherSig, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Vouching failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
         }
     }
 
     func preflightVouchWithBottle(withContainer container: String,
                                   context: String,
                                   bottleID: String,
-                                  reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                                  reply: @escaping (String?, TPSyncingPolicy?, Bool, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Preflight Vouch With Bottle %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.preflightVouchWithBottle(bottleID: bottleID) { peerID, viewSet, policy, error in
+            container.preflightVouchWithBottle(bottleID: bottleID) { peerID, policy, refetched, error in
                 self.logComplete(function: "Preflight Vouch With Bottle", container: container.name, error: error)
-                reply(peerID, viewSet, policy, CKXPCSuitableError(error)) }
+                reply(peerID, policy, refetched, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Preflighting Vouch With Bottle failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, false, error.sanitizeForClientXPC())
         }
     }
 
@@ -342,28 +380,28 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.vouchWithBottle(bottleID: bottleID, entropy: entropy, bottleSalt: bottleSalt, tlkShares: tlkShares) { voucher, voucherSig, uniqueTLKsRecovered, totalTLKSharesRecovered, error in
                 self.logComplete(function: "Vouching With Bottle", container: container.name, error: error)
-                reply(voucher, voucherSig, uniqueTLKsRecovered, totalTLKSharesRecovered, CKXPCSuitableError(error)) }
+                reply(voucher, voucherSig, uniqueTLKsRecovered, totalTLKSharesRecovered, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Vouching with Bottle failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, 0, 0, CKXPCSuitableError(error))
+            reply(nil, nil, 0, 0, error.sanitizeForClientXPC())
         }
     }
 
     func preflightVouchWithRecoveryKey(withContainer container: String,
-                                  context: String,
-                                  recoveryKey: String,
-                                  salt: String,
-                                  reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                                       context: String,
+                                       recoveryKey: String,
+                                       salt: String,
+                                       reply: @escaping (String?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Preflight Vouch With RecoveryKey %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.preflightVouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt) { rkID, viewSet, policy, error in
+            container.preflightVouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt) { rkID, policy, error in
                 self.logComplete(function: "Preflight Vouch With RecoveryKey", container: container.name, error: error)
-                reply(rkID, viewSet, policy, CKXPCSuitableError(error)) }
+                reply(rkID, policy, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Preflighting Vouch With RecoveryKey failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -379,10 +417,10 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.vouchWithRecoveryKey(recoveryKey: recoveryKey, salt: salt, tlkShares: tlkShares) { voucher, voucherSig, error in
                 self.logComplete(function: "Vouching With Recovery Key", container: container.name, error: error)
-                reply(voucher, voucherSig, CKXPCSuitableError(error)) }
+                reply(voucher, voucherSig, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("Vouching with Recovery Key failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -392,8 +430,8 @@ class Client: TrustedPeersHelperProtocol {
               voucherSig: Data,
               ckksKeys: [CKKSKeychainBackedKeySet],
               tlkShares: [CKKSTLKShare],
-              preapprovedKeys: [Data],
-              reply: @escaping (String?, [CKRecord]?, Set<String>?, TPPolicy?, Error?) -> Void) {
+              preapprovedKeys: [Data]?,
+              reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Joining %{public}@", log: tplogDebug, type: .default, containerName.description)
@@ -402,27 +440,27 @@ class Client: TrustedPeersHelperProtocol {
                            voucherSig: voucherSig,
                            ckksKeys: ckksKeys,
                            tlkShares: tlkShares,
-                           preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, views, policy, error in
-                            reply(peerID, keyHierarchyRecords, views, policy, CKXPCSuitableError(error))
-
+                           preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
+                            reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Joining failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
     func preflightPreapprovedJoin(withContainer container: String,
                                   context: String,
+                                  preapprovedKeys: [Data]?,
                                   reply: @escaping (Bool, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Attempting to preflight a preapproved join for %{public}@", 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(preapprovedKeys: preapprovedKeys) { success, error in reply(success, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("preflightPreapprovedJoin failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(false, CKXPCSuitableError(error))
+            reply(false, error.sanitizeForClientXPC())
         }
     }
 
@@ -430,19 +468,19 @@ class Client: TrustedPeersHelperProtocol {
                                 context: String,
                                 ckksKeys: [CKKSKeychainBackedKeySet],
                                 tlkShares: [CKKSTLKShare],
-                                preapprovedKeys: [Data],
-                                reply: @escaping (String?, [CKRecord]?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                                preapprovedKeys: [Data]?,
+                                reply: @escaping (String?, [CKRecord]?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Attempting a preapproved join for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.preapprovedJoin(ckksKeys: ckksKeys,
                                       tlkShares: tlkShares,
-                                      preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, viewSet, policy, error in
-                                        reply(peerID, keyHierarchyRecords, viewSet, policy, CKXPCSuitableError(error)) }
+                                      preapprovedKeys: preapprovedKeys) { peerID, keyHierarchyRecords, policy, error in
+                                        reply(peerID, keyHierarchyRecords, policy, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("attemptPreapprovedJoin failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -453,19 +491,38 @@ class Client: TrustedPeersHelperProtocol {
                 osVersion: String?,
                 policyVersion: NSNumber?,
                 policySecrets: [String: Data]?,
-                reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
+                syncUserControllableViews: NSNumber?,
+                reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Updating %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
+
+            let syncUserControllableSetting: TPPBPeerStableInfo_UserControllableViewStatus?
+            if let value = syncUserControllableViews?.int32Value {
+                switch value {
+                case TPPBPeerStableInfo_UserControllableViewStatus.ENABLED.rawValue:
+                    syncUserControllableSetting = .ENABLED
+                case TPPBPeerStableInfo_UserControllableViewStatus.DISABLED.rawValue:
+                    syncUserControllableSetting = .DISABLED
+                case TPPBPeerStableInfo_UserControllableViewStatus.FOLLOWING.rawValue:
+                    syncUserControllableSetting = .FOLLOWING
+                default:
+                    throw ContainerError.unknownSyncUserControllableViewsValue(value: value)
+                }
+            } else {
+                syncUserControllableSetting = nil
+            }
+
             container.update(deviceName: deviceName,
                              serialNumber: serialNumber,
                              osVersion: osVersion,
                              policyVersion: policyVersion?.uint64Value,
-                             policySecrets: policySecrets) { state, error in reply(state, CKXPCSuitableError(error)) }
+                             policySecrets: policySecrets,
+                             syncUserControllableViews: syncUserControllableSetting) { state, policy, error in reply(state, policy, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("update failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -477,10 +534,10 @@ class Client: TrustedPeersHelperProtocol {
             let containerName = ContainerName(container: container, context: context)
             os_log("setPreapprovedKeysWithContainer %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.set(preapprovedKeys: preapprovedKeys) { state, error in reply(state, CKXPCSuitableError(error)) }
+            container.set(preapprovedKeys: preapprovedKeys) { state, error in reply(state, error?.sanitizeForClientXPC()) }
         } catch {
             os_log("setPreapprovedKeysWithContainer failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -494,11 +551,12 @@ class Client: TrustedPeersHelperProtocol {
             os_log("Updating TLKs for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.updateTLKs(ckksKeys: ckksKeys,
-                                 tlkShares: tlkShares,
-                                 reply: reply)
+                                 tlkShares: tlkShares) { records, error in
+                reply(records, error?.sanitizeForClientXPC())
+            }
         } catch {
             os_log("updateTLKs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -510,11 +568,11 @@ class Client: TrustedPeersHelperProtocol {
             os_log("Departing %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.departByDistrustingSelf { error in
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("departByDistrustingSelf failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -527,11 +585,11 @@ class Client: TrustedPeersHelperProtocol {
             os_log("Distrusting %{public}@ in %{public}@", log: tplogDebug, type: .default, peerIDs, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.distrust(peerIDs: peerIDs) { error in
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("distrustPeerIDs failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -541,11 +599,24 @@ class Client: TrustedPeersHelperProtocol {
             os_log("fetchViableBottles in %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.fetchViableBottles { sortedBottleIDs, partialBottleIDs, error in
-                reply(sortedBottleIDs, partialBottleIDs, CKXPCSuitableError(error))
+                reply(sortedBottleIDs, partialBottleIDs, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("fetchViableBottles failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, error.sanitizeForClientXPC())
+        }
+    }
+
+    func fetchViableEscrowRecords(withContainer container: String, context: String, forceFetch: Bool, reply: @escaping ([Data]?, Error?) -> Void) {
+        do {
+            let containerName = ContainerName(container: container, context: context)
+            os_log("fetchViableEscrowRecords in %@", log: tplogDebug, type: .default, containerName.description)
+            let container = try self.containerMap.findOrCreate(name: containerName)
+            container.fetchEscrowRecords(forceFetch: forceFetch) { recordDatas, error in
+                reply(recordDatas, error?.sanitizeForClientXPC())
+            }
+        } catch {
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -555,27 +626,28 @@ class Client: TrustedPeersHelperProtocol {
             os_log("fetchEscrowContents in %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.fetchEscrowContents { entropy, bottleID, signingPublicKey, error in
-                reply(entropy, bottleID, signingPublicKey, CKXPCSuitableError(error))
+                reply(entropy, bottleID, signingPublicKey, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("fetchEscrowContents failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, nil, CKXPCSuitableError(error))
+            reply(nil, nil, nil, error.sanitizeForClientXPC())
         }
     }
 
     func fetchCurrentPolicy(withContainer container: String,
                             context: String,
-                            reply: @escaping (Set<String>?, TPPolicy?, Error?) -> Void) {
+                            modelIDOverride: String?,
+                            reply: @escaping (TPSyncingPolicy?, TPPBPeerStableInfo_UserControllableViewStatus, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("Fetching policy+views for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.fetchCurrentPolicy { viewList, policy, error in
-                reply(viewList, policy, CKXPCSuitableError(error))
+            container.fetchCurrentPolicy(modelIDOverride: modelIDOverride) { policy, peersOpinion, error in
+                reply(policy, peersOpinion, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("fetchCurrentPolicy failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, nil, CKXPCSuitableError(error))
+            reply(nil, .UNKNOWN, error.sanitizeForClientXPC())
         }
     }
 
@@ -588,11 +660,11 @@ class Client: TrustedPeersHelperProtocol {
             os_log("Fetching policy documents %{public}@ with versions: %{public}@", log: tplogDebug, type: .default, containerName.description, versions)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.fetchPolicyDocuments(versions: versions) { entries, error in
-                reply(entries, CKXPCSuitableError(error))
+                reply(entries, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("fetchPolicyDocuments failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -604,26 +676,31 @@ class Client: TrustedPeersHelperProtocol {
             let request = ValidatePeersRequest()
             container.validatePeers(request: request) { result, error in
                 self.logComplete(function: "validatePeers", container: container.name, error: error)
-                reply(result, CKXPCSuitableError(error))
+                reply(result, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("ValidatePeers failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
-    func setRecoveryKeyWithContainer(_ container: String, context: String, recoveryKey: String, salt: String, ckksKeys: [CKKSKeychainBackedKeySet], reply: @escaping (Error?) -> Void) {
+    func setRecoveryKeyWithContainer(_ container: String,
+                                     context: String,
+                                     recoveryKey: String,
+                                     salt: String,
+                                     ckksKeys: [CKKSKeychainBackedKeySet],
+                                     reply: @escaping ([CKRecord]?, Error?) -> Void) {
         do {
             let containerName = ContainerName(container: container, context: context)
             os_log("SetRecoveryKey for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
-            container.setRecoveryKey(recoveryKey: recoveryKey, salt: salt, ckksKeys: ckksKeys) { error in
+            container.setRecoveryKey(recoveryKey: recoveryKey, salt: salt, ckksKeys: ckksKeys) { records, error in
                 self.logComplete(function: "setRecoveryKey", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(records, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("SetRecoveryKey failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
         }
     }
 
@@ -637,11 +714,11 @@ class Client: TrustedPeersHelperProtocol {
             }
             container.reportHealth(request: request) { error in
                 self.logComplete(function: "reportHealth", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("ReportHealth failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -652,11 +729,11 @@ class Client: TrustedPeersHelperProtocol {
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.pushHealthInquiry { error in
                 self.logComplete(function: "pushHealthInquiry", container: container.name, error: error)
-                reply(CKXPCSuitableError(error))
+                reply(error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("PushHealthInquiry failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(CKXPCSuitableError(error))
+            reply(error.sanitizeForClientXPC())
         }
     }
 
@@ -666,26 +743,38 @@ class Client: TrustedPeersHelperProtocol {
             os_log("Health Check! requiring escrow check? %d for %{public}@", log: tplogDebug, type: .default, requiresEscrowCheck, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.requestHealthCheck(requiresEscrowCheck: requiresEscrowCheck) { postRepair, postEscrow, postReset, leaveTrust, error in
-                reply(postRepair, postEscrow, postReset, leaveTrust, CKXPCSuitableError(error))
+                reply(postRepair, postEscrow, postReset, leaveTrust, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("Health Check! failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(false, false, false, false, CKXPCSuitableError(error))
+            reply(false, false, false, false, error.sanitizeForClientXPC())
         }
     }
 
     func getSupportAppInfo(withContainer container: String, context: String, reply: @escaping (Data?, Error?) -> Void) {
-                do {
+        do {
             let containerName = ContainerName(container: container, context: context)
-            os_log("getSupportInfo %d for %{public}@", log: tplogDebug, type: .default, containerName.description)
+            os_log("getSupportAppInfo for %{public}@", log: tplogDebug, type: .default, containerName.description)
             let container = try self.containerMap.findOrCreate(name: containerName)
             container.getSupportAppInfo { info, error in
-                reply(info, CKXPCSuitableError(error))
+                reply(info, error?.sanitizeForClientXPC())
             }
         } catch {
             os_log("getSupportInfo failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
-            reply(nil, CKXPCSuitableError(error))
+            reply(nil, error.sanitizeForClientXPC())
+        }
+    }
+    func removeEscrowCache(withContainer container: String, context: String, reply: @escaping (Error?) -> Void) {
+        do {
+            let containerName = ContainerName(container: container, context: context)
+            os_log("removeEscrowCache for %{public}@", log: tplogDebug, type: .default, containerName.description)
+            let container = try self.containerMap.findOrCreate(name: containerName)
+            container.removeEscrowCache { error in
+                reply(error?.sanitizeForClientXPC())
+            }
+        } catch {
+            os_log("removeEscrowCache failed for (%{public}@, %{public}@): %{public}@", log: tplogDebug, type: .default, container, context, error as CVarArg)
+            reply(error.sanitizeForClientXPC())
         }
-
     }
 }
index ad1e321b9c9d6299e45aea1edd26eb7a73aabe22..cd3b61e71dda5a6ff60589706e693ffa148a296a 100644 (file)
@@ -22,6 +22,7 @@
  */
 
 import CloudKitCode
+import CloudKitCodeProtobuf
 import CoreData
 import Foundation
 import os
@@ -30,9 +31,14 @@ import SecurityFoundation
 
 let tplogDebug = OSLog(subsystem: "com.apple.security.trustedpeers", category: "debug")
 let tplogTrace = OSLog(subsystem: "com.apple.security.trustedpeers", category: "trace")
-
 let egoIdentitiesAccessGroup = "com.apple.security.egoIdentities"
 
+enum Viability {
+    case full
+    case partial
+    case none
+}
+
 extension ResetReason {
     static func from(cuttlefishResetReason: CuttlefishResetReason) -> ResetReason {
         switch cuttlefishResetReason {
@@ -51,7 +57,7 @@ extension ResetReason {
         case .testGenerated:
             return ResetReason.testGenerated
         @unknown default:
-            fatalError()
+            fatalError("unknown reset reason: \(cuttlefishResetReason)")
         }
     }
 }
@@ -100,6 +106,9 @@ public enum ContainerError: Error {
     case unknownSecurityFoundationError
     case failedToSerializeData
     case unknownInternalError
+    case unknownSyncUserControllableViewsValue(value: Int32)
+    case noPeersPreapprovedBySelf
+    case peerRegisteredButNotStored(String)
 }
 
 extension ContainerError: LocalizedError {
@@ -191,12 +200,17 @@ extension ContainerError: LocalizedError {
             return "Failed to encode protobuf data"
         case .unknownInternalError:
             return "Internal code failed, but didn't return error"
+        case .unknownSyncUserControllableViewsValue(value: let value):
+            return "Unknown syncUserControllableViews number: \(value)"
+        case .noPeersPreapprovedBySelf:
+            return "No peers preapproved by the local peer"
+        case .peerRegisteredButNotStored(let s):
+            return "Peer \(s) not found in database"
         }
     }
 }
 
 extension ContainerError: CustomNSError {
-
     public static var errorDomain: String {
         return "com.apple.security.trustedpeers.container"
     }
@@ -291,6 +305,12 @@ extension ContainerError: CustomNSError {
             return 44
         case .unknownInternalError:
             return 45
+        case .unknownSyncUserControllableViewsValue:
+            return 46
+        case .noPeersPreapprovedBySelf:
+            return 47
+        case .peerRegisteredButNotStored:
+            return 48
         }
     }
 
@@ -326,7 +346,6 @@ internal func traceError(_ error: Error?) -> String {
 }
 
 func saveSecret(_ secret: Data, label: String) throws {
-
     let query: [CFString: Any] = [
         kSecClass: kSecClassInternetPassword,
         kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
@@ -545,12 +564,19 @@ func makeTLKShares(ckksTLKs: [CKKSKeychainBackedKey]?, asPeer: CKKSSelfPeer, toP
                 throw error
             }
         }
-    }.compactMap { $0 }
+    }
+    .compactMap { $0 }
 }
 
 @discardableResult
 func extract(tlkShares: [CKKSTLKShare], peer: OctagonSelfPeerKeys, model: TPModel) -> (Int64, Int64) {
     os_log("Attempting to recover %d TLK shares for peer %{public}@", log: tplogDebug, type: .default, tlkShares.count, peer.peerID)
+
+    return extract(tlkShares: tlkShares, peer: peer, sponsorPeerID: nil, model: model)
+}
+
+@discardableResult
+func extract(tlkShares: [CKKSTLKShare], peer: OctagonSelfPeerKeys, sponsorPeerID: String?, model: TPModel) -> (Int64, Int64) {
     var tlksRecovered: Set<String> = Set()
     var sharesRecovered: Int64 = 0
 
@@ -563,7 +589,7 @@ func extract(tlkShares: [CKKSTLKShare], peer: OctagonSelfPeerKeys, model: TPMode
         do {
             var trustedPeers: [AnyHashable] = [peer]
 
-            if let egoPeer = model.peer(withID: peer.peerID) {
+            if let egoPeer = model.peer(withID: sponsorPeerID ?? peer.peerID) {
                 egoPeer.trustedPeerIDs.forEach { trustedPeerID in
                     if let peer = model.peer(withID: trustedPeerID) {
                         let peerObj = CKKSActualPeer(peerID: trustedPeerID,
@@ -601,6 +627,7 @@ struct ContainerState {
     var peers: [String: TPPeer] = [:]
     var vouchers: [TPVoucher] = []
     var bottles = Set<BottleMO>()
+    var escrowRecords = Set<EscrowRecordMO>()
     var recoverySigningKey: Data?
     var recoveryEncryptionKey: Data?
 }
@@ -611,11 +638,13 @@ internal struct StableChanges {
     let osVersion: String?
     let policyVersion: UInt64?
     let policySecrets: [String: Data]?
+    let setSyncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus?
 }
 
 // CoreData doesn't handle creating an identical model from an identical URL. Help it out.
 private var nsObjectModels: [URL: NSManagedObjectModel] = [:]
 private let nsObjectModelsQueue = DispatchQueue(label: "com.apple.security.TrustedPeersHelper.nsObjectModels")
+
 func getOrMakeModel(url: URL) -> NSManagedObjectModel {
     return nsObjectModelsQueue.sync {
         if let model = nsObjectModels[url] {
@@ -649,7 +678,7 @@ extension ContainerMO {
     func egoStableInfo() -> TPPeerStableInfo? {
         guard let egoStableData = self.egoPeerStableInfo,
             let egoStableSig = self.egoPeerStableInfoSig else {
-            return nil
+                return nil
         }
 
         return TPPeerStableInfo(data: egoStableData, sig: egoStableSig)
@@ -678,12 +707,20 @@ class Container: NSObject {
     // that queue.
     internal let moc: NSManagedObjectContext
 
+    // To facilitate CoreData tear down, we need to keep the PersistentContainer around.
+    internal let persistentContainer: NSPersistentContainer
+
     // Rather than Container having its own dispatch queue, we use moc's queue
     // to synchronise access to our own state as well. So the following instance
     // variables must only be accessed within blocks executed by calling
     // moc.perform() or moc.performAndWait().
     internal var containerMO: ContainerMO
     internal var model: TPModel
+    internal var escrowCacheTimeout: TimeInterval
+
+    // Used in tests only. Set when an identity is prepared using a policy version override
+    internal var policyVersionOverride: TPPolicyVersion?
+
     /**
      Construct a Container.
 
@@ -704,17 +741,17 @@ class Container: NSObject {
         // Set up Core Data stack
         let url = Bundle(for: type(of: self)).url(forResource: "TrustedPeersHelper", withExtension: "momd")!
         let mom = getOrMakeModel(url: url)
-        let persistentContainer = NSPersistentContainer(name: "TrustedPeersHelper", managedObjectModel: mom)
-        persistentContainer.persistentStoreDescriptions = [persistentStoreDescription]
+        self.persistentContainer = NSPersistentContainer(name: "TrustedPeersHelper", managedObjectModel: mom)
+        self.persistentContainer.persistentStoreDescriptions = [persistentStoreDescription]
 
-        persistentContainer.loadPersistentStores { _, error in
+        self.persistentContainer.loadPersistentStores { _, error in
             initError = error
         }
         if let initError = initError {
             throw initError
         }
 
-        let moc = persistentContainer.newBackgroundContext()
+        let moc = self.persistentContainer.newBackgroundContext()
         moc.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump
 
         moc.performAndWait {
@@ -734,6 +771,9 @@ class Container: NSObject {
                 Container.onqueueUpgradeMachineIDSetToModel(container: containerMO!, moc: moc)
                 Container.onqueueUpgradeMachineIDSetToUseStatus(container: containerMO!, moc: moc)
 
+                //remove duplicate vouchers on all the peers
+                Container.onqueueRemoveDuplicateVouchersPerPeer(container: containerMO!, moc: moc)
+
                 model = Container.loadModel(from: containerMO!)
                 Container.ensureEgoConsistency(from: containerMO!, model: model!)
                 try moc.save()
@@ -751,9 +791,23 @@ class Container: NSObject {
         self.containerMO = containerMO!
         self.cuttlefish = cuttlefish
         self.model = model!
+        self.escrowCacheTimeout = 60.0 * 15.0 //15 minutes
         super.init()
     }
 
+    func deletePersistentStore() throws {
+        // Call this to entirely destroy the persistent store.
+        // This container should not be used after this event.
+
+        try self.persistentContainer.persistentStoreDescriptions.forEach { storeDescription in
+            if let url = storeDescription.url {
+                try self.moc.persistentStoreCoordinator?.destroyPersistentStore(at: url,
+                                                                                ofType: storeDescription.type,
+                                                                                options: [:])
+            }
+        }
+    }
+
     // Must be on containerMO's moc queue to call this
     internal static func loadModel(from containerMO: ContainerMO) -> TPModel {
         // Populate model from persistent store
@@ -804,9 +858,12 @@ class Container: NSObject {
             }
         }
 
-        if let recoveryKeySigningSPKI = containerMO.recoveryKeySigningSPKI,
-            let recoveryKeyEncyryptionSPKI = containerMO.recoveryKeyEncryptionSPKI {
-            model.setRecoveryKeys(TPRecoveryKeyPair(signingSPKI: recoveryKeySigningSPKI, encryptionSPKI: recoveryKeyEncyryptionSPKI))
+        os_log("loadModel: loaded %{public}d vouchers", log: tplogDebug, type: .default, model.allVouchers().count)
+
+        // Note: the containerMO objects are misnamed; they are key data, and not SPKI.
+        if let recoveryKeySigningKeyData = containerMO.recoveryKeySigningSPKI,
+            let recoveryKeyEncyryptionKeyData = containerMO.recoveryKeyEncryptionSPKI {
+            model.setRecoveryKeys(TPRecoveryKeyPair(signingKeyData: recoveryKeySigningKeyData, encryptionKeyData: recoveryKeyEncyryptionKeyData))
         } else {
             // If the ego peer has an RK set, tell the model to use that one
             // This is a hack to work around TPH databases which don't have the RK set on the container due to previously running old software
@@ -814,7 +871,7 @@ class Container: NSObject {
                 egoStableInfo.recoverySigningPublicKey.count > 0,
                 egoStableInfo.recoveryEncryptionPublicKey.count > 0 {
                 os_log("loadModel: recovery key not set in model, but is set on ego peer", log: tplogDebug, type: .default)
-                model.setRecoveryKeys(TPRecoveryKeyPair(signingSPKI: egoStableInfo.recoverySigningPublicKey, encryptionSPKI: egoStableInfo.recoveryEncryptionPublicKey))
+                model.setRecoveryKeys(TPRecoveryKeyPair(signingKeyData: egoStableInfo.recoverySigningPublicKey, encryptionKeyData: egoStableInfo.recoveryEncryptionPublicKey))
             }
         }
 
@@ -872,7 +929,6 @@ class Container: NSObject {
             containerMO.egoPeerStableInfo = modelStableInfo.data
             containerMO.egoPeerStableInfoSig = modelStableInfo.sig
         }
-
     }
 
     static func dictionaryRepresentation(bottle: BottleMO) -> [String: Any] {
@@ -961,7 +1017,6 @@ class Container: NSObject {
                 reply(egoStatus, nil)
                 return
             }
-
         } else {
             // With no ego peer ID, either return 'excluded' if there are extant peers, or 'unknown' to signal no peers at all
             if self.model.allPeerIDs().isEmpty {
@@ -1002,7 +1057,7 @@ class Container: NSObject {
         self.moc.performAndWait {
             // Knowledge of your peer status only exists if you know about other peers. If you haven't fetched, fetch.
             if self.containerMO.changeToken == nil {
-                self.fetchAndPersistChanges { fetchError in
+                self.onqueueFetchAndPersistChanges { fetchError in
                     guard fetchError == nil else {
                         if let error = fetchError {
                             os_log("Unable to fetch changes, trust status is unknown: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
@@ -1037,9 +1092,8 @@ class Container: NSObject {
 
         self.moc.performAndWait {
             if let egoPeerID = self.containerMO.egoPeerID,
-               let egoPermData = self.containerMO.egoPeerPermanentInfo,
-               let egoPermSig = self.containerMO.egoPeerPermanentInfoSig {
-
+                let egoPermData = self.containerMO.egoPeerPermanentInfo,
+                let egoPermSig = self.containerMO.egoPeerPermanentInfoSig {
                 let keyFactory = TPECPublicKeyFactory()
                 guard let permanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
                     os_log("fetchTrustState failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
@@ -1075,6 +1129,21 @@ class Container: NSObject {
                             os_log("No peer for trusted ID %{public}@", log: tplogDebug, type: .default, trustedPeerID)
                         }
                     }
+
+                    if let stableInfo = egoPeer.stableInfo, stableInfo.recoveryEncryptionPublicKey.count > 0, stableInfo.recoverySigningPublicKey.count > 0 {
+                        let recoveryKeyPair = TPRecoveryKeyPair(stableInfo: stableInfo)
+
+                        do {
+                            // The RK should have all views. So, claim that it should have all views that this peer has.
+                            let rkViews = try self.model.getViewsForPeer(egoPeer.permanentInfo,
+                                                                          stableInfo: egoPeer.stableInfo)
+
+                            tphPeers.append(try RecoveryKey.asPeer(recoveryKeys: recoveryKeyPair,
+                                                                   viewList: rkViews))
+                        } catch {
+                            os_log("Unable to add RK as a trusted peer: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
+                        }
+                    }
                 } else {
                     os_log("No ego peer in model; no trusted peers", log: tplogDebug, type: .default)
                 }
@@ -1094,8 +1163,8 @@ class Container: NSObject {
             os_log("dump complete: %{public}@",
                    log: tplogTrace, type: .info, traceError($1))
             reply($0, $1)
-       }
-       self.moc.performAndWait {
+        }
+        self.moc.performAndWait {
             var d: [AnyHashable: Any] = [:]
 
             if let egoPeerID = self.containerMO.egoPeerID {
@@ -1131,11 +1200,11 @@ class Container: NSObject {
     }
 
     func dumpEgoPeer(reply: @escaping (String?, TPPeerPermanentInfo?, TPPeerStableInfo?, TPPeerDynamicInfo?, Error?) -> Void) {
-       let reply: (String?, TPPeerPermanentInfo?, TPPeerStableInfo?, TPPeerDynamicInfo?, Error?) -> Void = {
-           os_log("dumpEgoPeer complete: %{public}@", log: tplogTrace, type: .info, traceError($4))
-           reply($0, $1, $2, $3, $4)
-       }
-       self.moc.performAndWait {
+        let reply: (String?, TPPeerPermanentInfo?, TPPeerStableInfo?, TPPeerDynamicInfo?, Error?) -> Void = {
+            os_log("dumpEgoPeer complete: %{public}@", log: tplogTrace, type: .info, traceError($4))
+            reply($0, $1, $2, $3, $4)
+        }
+        self.moc.performAndWait {
             guard let egoPeerID = self.containerMO.egoPeerID else {
                 reply(nil, nil, nil, nil, ContainerError.noPreparedIdentity)
                 return
@@ -1159,7 +1228,6 @@ class Container: NSObject {
         }
 
         self.cuttlefish.validatePeers(request) { response, error in
-            os_log("ValidatePeers(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
             guard let response = response, error == nil else {
                 os_log("validatePeers failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                 reply(nil, error ?? ContainerError.cloudkitResponseMissing)
@@ -1188,7 +1256,6 @@ class Container: NSObject {
                 $0.resetReason = resetReason
             }
             self.cuttlefish.reset(request) { response, error in
-                os_log("Reset(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                 guard let response = response, error == nil else {
                     os_log("reset failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                     reply(error ?? ContainerError.cloudkitResponseMissing)
@@ -1257,19 +1324,20 @@ class Container: NSObject {
                  bottleID: String,
                  modelID: String,
                  deviceName: String?,
-                 serialNumber: String,
+                 serialNumber: String?,
                  osVersion: String,
                  policyVersion: TPPolicyVersion?,
                  policySecrets: [String: Data]?,
+                 syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus,
                  signingPrivateKeyPersistentRef: Data?,
                  encryptionPrivateKeyPersistentRef: Data?,
-                 reply: @escaping (String?, Data?, Data?, Data?, Data?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                 reply: @escaping (String?, Data?, Data?, Data?, Data?, TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, Data?, Data?, Data?, Data?, Set<String>?, TPPolicy?, Error?) -> Void = {
+        let reply: (String?, Data?, Data?, Data?, Data?, TPSyncingPolicy?, Error?) -> Void = {
             os_log("prepare complete peerID: %{public}@ %{public}@",
-                   log: tplogTrace, type: .info, ($0 ?? "NULL") as CVarArg, traceError($7))
+                   log: tplogTrace, type: .info, ($0 ?? "NULL") as CVarArg, traceError($6))
             self.semaphore.signal()
-            reply($0, $1, $2, $3, $4, $5, $6, $7)
+            reply($0, $1, $2, $3, $4, $5, $6)
         }
 
         // Create a new peer identity with random keys, and store the keys in keychain
@@ -1287,9 +1355,8 @@ class Container: NSObject {
                                                     signing: signingKeyPair,
                                                     encryptionKeyPair: encryptionKeyPair,
                                                     peerIDHashAlgo: TPHashAlgo.SHA256)
-
         } catch {
-            reply(nil, nil, nil, nil, nil, nil, nil, error)
+            reply(nil, nil, nil, nil, nil, nil, error)
             return
         }
 
@@ -1306,47 +1373,55 @@ class Container: NSObject {
             _ = try saveSecret(bottle.secret, label: peerID)
         } catch {
             os_log("bottle creation failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-            reply(nil, nil, nil, nil, nil, nil, nil, error)
+            reply(nil, nil, nil, nil, nil, nil, error)
             return
         }
 
         saveEgoKeyPair(signingKeyPair, identifier: signingKeyIdentifier(peerID: peerID)) { success, error in
             guard success else {
                 os_log("Unable to save signing key: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                reply(nil, nil, nil, nil, nil, nil, nil, error ?? ContainerError.failedToStoreIdentity)
+                reply(nil, nil, nil, nil, nil, nil, error ?? ContainerError.failedToStoreIdentity)
                 return
             }
             saveEgoKeyPair(encryptionKeyPair, identifier: encryptionKeyIdentifier(peerID: peerID)) { success, error in
                 guard success else {
                     os_log("Unable to save encryption key: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                    reply(nil, nil, nil, nil, nil, nil, nil, error ?? ContainerError.failedToStoreIdentity)
+                    reply(nil, nil, nil, nil, nil, nil, error ?? ContainerError.failedToStoreIdentity)
                     return
                 }
 
-                let policyVersion = policyVersion ?? prevailingPolicyVersion
-                self.fetchPolicyDocumentWithSemaphore(version: policyVersion) { policyDoc, policyFetchError in
+                let actualPolicyVersion = policyVersion ?? prevailingPolicyVersion
+                self.fetchPolicyDocumentWithSemaphore(version: actualPolicyVersion) { policyDoc, policyFetchError in
                     guard let policyDoc = policyDoc, policyFetchError == nil else {
                         os_log("Unable to fetch policy: %{public}@", log: tplogDebug, type: .default, (policyFetchError as CVarArg?) ?? "error missing")
-                        reply(nil, nil, nil, nil, nil, nil, nil, error ?? ContainerError.unknownInternalError)
+                        reply(nil, nil, nil, nil, nil, nil, error ?? ContainerError.unknownInternalError)
                         return
                     }
 
+                    if policyVersion != nil {
+                        self.policyVersionOverride = policyDoc.version
+                    }
+
                     // Save the prepared identity as containerMO.egoPeer* and its bottle
                     self.moc.performAndWait {
                         do {
-
-                            let stableInfo = TPPeerStableInfo(clock: 1,
-                                                              frozenPolicyVersion: frozenPolicyVersion,
-                                                              flexiblePolicyVersion: policyDoc.version,
-                                                              policySecrets: policySecrets,
-                                                              deviceName: deviceName,
-                                                              serialNumber: serialNumber,
-                                                              osVersion: osVersion,
-                                                              signing: signingKeyPair,
-                                                              recoverySigningPubKey: nil,
-                                                              recoveryEncryptionPubKey: nil,
-                                                              error: nil)
-
+                            // Note: the client chooses for syncUserControllableViews here.
+                            // if they pass in UNKNOWN, we'll fix it later at join time, following the peers we trust.
+                            let syncUserViews = syncUserControllableViews.sanitizeForPlatform(permanentInfo: permanentInfo)
+
+                            let useFrozenPolicyVersion = policyDoc.version.versionNumber >= frozenPolicyVersion.versionNumber
+
+                            let stableInfo = try TPPeerStableInfo(clock: 1,
+                                                                  frozenPolicyVersion: useFrozenPolicyVersion ? frozenPolicyVersion : policyDoc.version,
+                                                                  flexiblePolicyVersion: useFrozenPolicyVersion ? policyDoc.version : nil,
+                                                                  policySecrets: policySecrets,
+                                                                  syncUserControllableViews: syncUserViews,
+                                                                  deviceName: deviceName,
+                                                                  serialNumber: serialNumber,
+                                                                  osVersion: osVersion,
+                                                                  signing: signingKeyPair,
+                                                                  recoverySigningPubKey: nil,
+                                                                  recoveryEncryptionPubKey: nil)
                             self.containerMO.egoPeerID = permanentInfo.peerID
                             self.containerMO.egoPeerPermanentInfo = permanentInfo.data
                             self.containerMO.egoPeerPermanentInfoSig = permanentInfo.sig
@@ -1363,14 +1438,14 @@ class Container: NSObject {
 
                             self.containerMO.addToBottles(bottleMO)
 
-                            let (syncingViews, policy) = try self.policyAndViewsFor(permanentInfo: permanentInfo, stableInfo: stableInfo)
+                            let syncingPolicy = try self.syncingPolicyFor(modelID: permanentInfo.modelID, stableInfo: stableInfo)
 
                             try self.moc.save()
 
-                            reply(permanentInfo.peerID, permanentInfo.data, permanentInfo.sig, stableInfo.data, stableInfo.sig, syncingViews, policy, nil)
+                            reply(permanentInfo.peerID, permanentInfo.data, permanentInfo.sig, stableInfo.data, stableInfo.sig, syncingPolicy, nil)
                         } catch {
                             os_log("Unable to save identity: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                            reply(nil, nil, nil, nil, nil, nil, nil, error)
+                            reply(nil, nil, nil, nil, nil, nil, error)
                         }
                     }
                 }
@@ -1399,22 +1474,21 @@ class Container: NSObject {
     func establish(ckksKeys: [CKKSKeychainBackedKeySet],
                    tlkShares: [CKKSTLKShare],
                    preapprovedKeys: [Data]?,
-                   reply: @escaping (String?, [CKRecord], Error?) -> Void) {
+                   reply: @escaping (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, [CKRecord], Error?) -> Void = {
+        let reply: (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void = {
             os_log("establish complete peer: %{public}@ %{public}@",
-                   log: tplogTrace, type: .default, ($0 ?? "NULL") as CVarArg, traceError($2))
+                   log: tplogTrace, type: .default, ($0 ?? "NULL") as CVarArg, traceError($3))
             self.semaphore.signal()
-            reply($0, $1, $2)
+            reply($0, $1, $2, $3)
         }
 
         self.moc.performAndWait {
             self.onqueueEstablish(ckksKeys: ckksKeys,
                                   tlkShares: tlkShares,
-                                  preapprovedKeys: preapprovedKeys,
-                                  reply: { peerID, ckrecords, _, _, error in
-                                    reply(peerID, ckrecords, error)
-            })
+                                  preapprovedKeys: preapprovedKeys) { peerID, ckrecords, syncingPolicy, error in
+                                    reply(peerID, ckrecords, syncingPolicy, error)
+            }
         }
     }
 
@@ -1427,63 +1501,63 @@ class Container: NSObject {
 
     func fetchAfterEstablish(ckksKeys: [CKKSKeychainBackedKeySet],
                              tlkShares: [CKKSTLKShare],
-                             reply: @escaping (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void) {
+                             reply: @escaping (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void) {
         self.moc.performAndWait {
             do {
                 try self.deleteLocalCloudKitData()
             } catch {
                 os_log("fetchAfterEstablish failed to reset local data: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                reply(nil, [], nil, nil, error)
+                reply(nil, [], nil, error)
                 return
             }
             self.onqueueFetchAndPersistChanges { error in
                 guard error == nil else {
                     os_log("fetchAfterEstablish failed to fetch changes: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                    reply(nil, [], nil, nil, error)
+                    reply(nil, [], nil, error)
                     return
                 }
 
                 self.moc.performAndWait {
                     guard let egoPeerID = self.containerMO.egoPeerID,
-                          let egoPermData = self.containerMO.egoPeerPermanentInfo,
-                          let egoPermSig = self.containerMO.egoPeerPermanentInfoSig,
-                          let egoStableData = self.containerMO.egoPeerStableInfo,
-                          let egoStableSig = self.containerMO.egoPeerStableInfoSig
-                    else {
-                        os_log("fetchAfterEstablish: failed to fetch egoPeerID", log: tplogDebug, type: .default)
-                        reply(nil, [], nil, nil, ContainerError.noPreparedIdentity)
-                        return
+                        let egoPermData = self.containerMO.egoPeerPermanentInfo,
+                        let egoPermSig = self.containerMO.egoPeerPermanentInfoSig,
+                        let egoStableData = self.containerMO.egoPeerStableInfo,
+                        let egoStableSig = self.containerMO.egoPeerStableInfoSig
+                        else {
+                            os_log("fetchAfterEstablish: failed to fetch egoPeerID", log: tplogDebug, type: .default)
+                            reply(nil, [], nil, ContainerError.noPreparedIdentity)
+                            return
                     }
                     guard self.model.hasPeer(withID: egoPeerID) else {
                         os_log("fetchAfterEstablish: did not find peer %{public}@ in model", log: tplogDebug, type: .default, egoPeerID)
-                        reply(nil, [], nil, nil, ContainerError.invalidPeerID)
+                        reply(nil, [], nil, ContainerError.invalidPeerID)
                         return
                     }
                     let keyFactory = TPECPublicKeyFactory()
                     guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-                        reply(nil, [], nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                        reply(nil, [], nil, ContainerError.invalidPermanentInfoOrSig)
                         return
                     }
                     guard let selfStableInfo = TPPeerStableInfo(data: egoStableData, sig: egoStableSig) else {
                         os_log("cannot create TPPeerStableInfo", log: tplogDebug, type: .default)
-                        reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+                        reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
                         return
                     }
                     self.onqueueUpdateTLKs(ckksKeys: ckksKeys, tlkShares: tlkShares) { ckrecords, error in
                         guard error == nil else {
                             os_log("fetchAfterEstablish failed to update TLKs: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                             return
                         }
 
                         do {
-                            let (syncingViews, policy) = try self.policyAndViewsFor(permanentInfo: selfPermanentInfo,
-                                                                                    stableInfo: selfStableInfo)
+                            let syncingPolicy = try self.syncingPolicyFor(modelID: selfPermanentInfo.modelID,
+                                                                          stableInfo: selfStableInfo)
                             os_log("fetchAfterEstablish succeeded", log: tplogDebug, type: .default)
-                            reply(egoPeerID, ckrecords ?? [], syncingViews, policy, nil)
+                            reply(egoPeerID, ckrecords ?? [], syncingPolicy, nil)
                         } catch {
                             os_log("fetchAfterEstablish failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg))
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                         }
                     }
                 }
@@ -1494,7 +1568,7 @@ class Container: NSObject {
     func onqueueEstablish(ckksKeys: [CKKSKeychainBackedKeySet],
                           tlkShares: [CKKSTLKShare],
                           preapprovedKeys: [Data]?,
-                          reply: @escaping (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void) {
+                          reply: @escaping (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void) {
         // Fetch ego peer identity from local storage.
         guard let egoPeerID = self.containerMO.egoPeerID,
             let egoPermData = self.containerMO.egoPeerPermanentInfo,
@@ -1502,31 +1576,31 @@ class Container: NSObject {
             let egoStableData = self.containerMO.egoPeerStableInfo,
             let egoStableSig = self.containerMO.egoPeerStableInfoSig
             else {
-                reply(nil, [], nil, nil, ContainerError.noPreparedIdentity)
+                reply(nil, [], nil, ContainerError.noPreparedIdentity)
                 return
         }
 
         let keyFactory = TPECPublicKeyFactory()
         guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-            reply(nil, [], nil, nil, ContainerError.invalidPermanentInfoOrSig)
+            reply(nil, [], nil, ContainerError.invalidPermanentInfoOrSig)
             return
         }
         guard let selfStableInfo = TPPeerStableInfo(data: egoStableData, sig: egoStableSig) else {
             os_log("cannot create TPPeerStableInfo", log: tplogDebug, type: .default)
-            reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+            reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
             return
         }
         guard self.onqueueMachineIDAllowedByIDMS(machineID: selfPermanentInfo.machineID) else {
             os_log("establish: self machineID %{public}@ not on list", log: tplogDebug, type: .debug, selfPermanentInfo.machineID)
             self.onqueueTTRUntrusted()
-            reply(nil, [], nil, nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
+            reply(nil, [], nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
             return
         }
 
         loadEgoKeys(peerID: egoPeerID) { egoPeerKeys, error in
-             guard let egoPeerKeys = egoPeerKeys else {
+            guard let egoPeerKeys = egoPeerKeys else {
                 os_log("Don't have my own peer keys; can't establish: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                reply(nil, [], nil, nil, error)
+                reply(nil, [], nil, error)
                 return
             }
             self.moc.performAndWait {
@@ -1539,40 +1613,39 @@ class Container: NSObject {
                     allTLKShares = octagonShares + sosShares
                 } catch {
                     os_log("Unable to make TLKShares for self: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                    reply(nil, [], nil, nil, error)
+                    reply(nil, [], nil, error)
                     return
                 }
 
-                let dynamicInfo: TPPeerDynamicInfo
+                let peer: Peer
+                let newDynamicInfo: TPPeerDynamicInfo
                 do {
-                    dynamicInfo = try self.model.dynamicInfo(forJoiningPeerID: egoPeerID,
-                                                             peerPermanentInfo: selfPermanentInfo,
-                                                             peerStableInfo: selfStableInfo,
-                                                             sponsorID: nil,
-                                                             preapprovedKeys: preapprovedKeys,
-                                                             signing: egoPeerKeys.signingKey,
-                                                             currentMachineIDs: self.onqueueCurrentMIDList())
-
-                    os_log("dynamic info: %{public}@", log: tplogDebug, type: .default, dynamicInfo)
+                    (peer, newDynamicInfo) = try self.onqueuePreparePeerForJoining(egoPeerID: egoPeerID,
+                                                                                   peerPermanentInfo: selfPermanentInfo,
+                                                                                   stableInfo: selfStableInfo,
+                                                                                   sponsorID: nil,
+                                                                                   preapprovedKeys: preapprovedKeys,
+                                                                                   vouchers: [],
+                                                                                   egoPeerKeys: egoPeerKeys)
+
+                    os_log("dynamic info: %{public}@", log: tplogDebug, type: .default, newDynamicInfo)
                 } catch {
-                    reply(nil, [], nil, nil, error)
+                    os_log("Unable to create peer for joining: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                    reply(nil, [], nil, error)
                     return
                 }
 
-                let peer = Peer.with {
-                    $0.peerID = egoPeerID
-                    $0.permanentInfoAndSig.peerPermanentInfo = egoPermData
-                    $0.permanentInfoAndSig.sig = egoPermSig
-                    $0.stableInfoAndSig.peerStableInfo = egoStableData
-                    $0.stableInfoAndSig.sig = egoStableSig
-                    $0.dynamicInfoAndSig = SignedPeerDynamicInfo(dynamicInfo)
+                guard let newPeerStableInfo = peer.stableInfoAndSig.toStableInfo() else {
+                    os_log("Unable to create new peer stable info for joining", log: tplogDebug, type: .default)
+                    reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
+                    return
                 }
 
                 let bottle: Bottle
                 do {
                     bottle = try self.assembleBottle(egoPeerID: egoPeerID)
                 } catch {
-                    reply(nil, [], nil, nil, error)
+                    reply(nil, [], nil, error)
                     return
                 }
                 os_log("Beginning establish for peer %{public}@", log: tplogDebug, type: .default, egoPeerID)
@@ -1599,7 +1672,6 @@ class Container: NSObject {
                     $0.tlkShares = allTLKShares
                 }
                 self.cuttlefish.establish(request) { response, error in
-                    os_log("Establish(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                     os_log("Establish: viewKeys: %{public}@", String(describing: viewKeys))
                     guard let response = response, error == nil else {
                         switch error {
@@ -1609,7 +1681,7 @@ class Container: NSObject {
                             return
                         default:
                             os_log("establish failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                            reply(nil, [], nil, nil, error ?? ContainerError.cloudkitResponseMissing)
+                            reply(nil, [], nil, error ?? ContainerError.cloudkitResponseMissing)
                             return
                         }
                     }
@@ -1623,8 +1695,8 @@ class Container: NSObject {
                     let keyHierarchyRecords = response.zoneKeyHierarchyRecords.compactMap { CKRecord($0) }
 
                     do {
-                        let (syncingViews, policy) = try self.policyAndViewsFor(permanentInfo: selfPermanentInfo,
-                                                                                stableInfo: selfStableInfo)
+                        let syncingPolicy = try self.syncingPolicyFor(modelID: selfPermanentInfo.modelID,
+                                                                      stableInfo: newPeerStableInfo)
 
                         try self.persist(changes: response.changes)
 
@@ -1635,33 +1707,33 @@ class Container: NSObject {
                                 guard fetchError == nil else {
                                     // 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: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "no error")
-                                    reply(nil, keyHierarchyRecords, nil, nil, fetchError)
+                                    reply(nil, keyHierarchyRecords, nil, fetchError)
                                     return
                                 }
 
                                 os_log("fetch-after-establish succeeded", log: tplogDebug, type: .default)
-                                reply(egoPeerID, keyHierarchyRecords, nil, nil, nil)
+                                reply(egoPeerID, keyHierarchyRecords, syncingPolicy, nil)
                             }
                             return
                         }
 
                         os_log("establish succeeded", log: tplogDebug, type: .default)
-                        reply(egoPeerID, keyHierarchyRecords, syncingViews, policy, nil)
+                        reply(egoPeerID, keyHierarchyRecords, syncingPolicy, nil)
                     } catch {
                         os_log("establish handling failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg))
-                        reply(nil, keyHierarchyRecords, nil, nil, error)
+                        reply(nil, keyHierarchyRecords, nil, error)
                     }
                 }
             }
         }
     }
 
-    func setRecoveryKey(recoveryKey: String, salt: String, ckksKeys: [CKKSKeychainBackedKeySet], reply: @escaping (Error?) -> Void) {
+    func setRecoveryKey(recoveryKey: String, salt: String, ckksKeys: [CKKSKeychainBackedKeySet], reply: @escaping ([CKRecord]?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (Error?) -> Void = {
-            os_log("setRecoveryKey complete: %{public}@", log: tplogTrace, type: .info, traceError($0))
+        let reply: ([CKRecord]?, Error?) -> Void = {
+            os_log("setRecoveryKey complete: %{public}@", log: tplogTrace, type: .info, traceError($1))
             self.semaphore.signal()
-            reply($0)
+            reply($0, $1)
         }
 
         os_log("beginning a setRecoveryKey", log: tplogDebug, type: .default)
@@ -1669,7 +1741,7 @@ class Container: NSObject {
         self.moc.performAndWait {
             guard let egoPeerID = self.containerMO.egoPeerID else {
                 os_log("no prepared identity, cannot set recovery key", log: tplogDebug, type: .default)
-                reply(ContainerError.noPreparedIdentity)
+                reply(nil, ContainerError.noPreparedIdentity)
                 return
             }
 
@@ -1678,7 +1750,7 @@ class Container: NSObject {
                 recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
             } catch {
                 os_log("failed to create recovery keys: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                reply(ContainerError.failedToCreateRecoveryKey)
+                reply(nil, ContainerError.failedToCreateRecoveryKey)
                 return
             }
 
@@ -1690,40 +1762,40 @@ class Container: NSObject {
 
             guard let stableInfoData = self.containerMO.egoPeerStableInfo else {
                 os_log("stableInfo does not exist", log: tplogDebug, type: .default)
-                reply(ContainerError.nonMember)
+                reply(nil, ContainerError.nonMember)
                 return
             }
             guard let stableInfoSig = self.containerMO.egoPeerStableInfoSig else {
                 os_log("stableInfoSig does not exist", log: tplogDebug, type: .default)
-                reply(ContainerError.nonMember)
+                reply(nil, ContainerError.nonMember)
                 return
             }
             guard let permInfoData = self.containerMO.egoPeerPermanentInfo else {
                 os_log("permanentInfo does not exist", log: tplogDebug, type: .default)
-                reply(ContainerError.nonMember)
+                reply(nil, ContainerError.nonMember)
                 return
             }
             guard let permInfoSig = self.containerMO.egoPeerPermanentInfoSig else {
                 os_log("permInfoSig does not exist", log: tplogDebug, type: .default)
-                reply(ContainerError.nonMember)
+                reply(nil, ContainerError.nonMember)
                 return
             }
             guard let stableInfo = TPPeerStableInfo(data: stableInfoData, sig: stableInfoSig) else {
                 os_log("cannot create TPPeerStableInfo", log: tplogDebug, type: .default)
-                reply(ContainerError.invalidStableInfoOrSig)
+                reply(nil, ContainerError.invalidStableInfoOrSig)
                 return
             }
             let keyFactory = TPECPublicKeyFactory()
             guard let permanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: permInfoData, sig: permInfoSig, keyFactory: keyFactory) else {
                 os_log("cannot create TPPeerPermanentInfo", log: tplogDebug, type: .default)
-                reply(ContainerError.invalidStableInfoOrSig)
+                reply(nil, ContainerError.invalidStableInfoOrSig)
                 return
             }
 
             loadEgoKeyPair(identifier: signingKeyIdentifier(peerID: egoPeerID)) { signingKeyPair, error in
                 guard let signingKeyPair = signingKeyPair else {
                     os_log("handle: no signing key pair: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                    reply(error)
+                    reply(nil, error)
                     return
                 }
                 self.moc.performAndWait {
@@ -1736,17 +1808,17 @@ class Container: NSObject {
                         let policyVersion = stableInfo.bestPolicyVersion()
                         let policyDoc = try self.getPolicyDoc(policyVersion.versionNumber)
 
-                        let updatedStableInfo = TPPeerStableInfo(clock: stableInfo.clock + 1,
-                                                                 frozenPolicyVersion: frozenPolicyVersion,
-                                                                 flexiblePolicyVersion: policyDoc.version,
-                                                                 policySecrets: stableInfo.policySecrets,
-                                                                 deviceName: stableInfo.deviceName,
-                                                                 serialNumber: stableInfo.serialNumber,
-                                                                 osVersion: stableInfo.osVersion,
-                                                                 signing: signingKeyPair,
-                                                                 recoverySigningPubKey: signingPublicKey,
-                                                                 recoveryEncryptionPubKey: encryptionPublicKey,
-                                                                 error: nil)
+                        let updatedStableInfo = try TPPeerStableInfo(clock: stableInfo.clock + 1,
+                                                                     frozenPolicyVersion: frozenPolicyVersion,
+                                                                     flexiblePolicyVersion: policyDoc.version,
+                                                                     policySecrets: stableInfo.policySecrets,
+                                                                     syncUserControllableViews: stableInfo.syncUserControllableViews,
+                                                                     deviceName: stableInfo.deviceName,
+                                                                     serialNumber: stableInfo.serialNumber,
+                                                                     osVersion: stableInfo.osVersion,
+                                                                     signing: signingKeyPair,
+                                                                     recoverySigningPubKey: signingPublicKey,
+                                                                     recoveryEncryptionPubKey: encryptionPublicKey)
                         let signedStableInfo = SignedPeerStableInfo(updatedStableInfo)
 
                         let request = SetRecoveryKeyRequest.with {
@@ -1759,10 +1831,9 @@ class Container: NSObject {
                         }
 
                         self.cuttlefish.setRecoveryKey(request) { response, error in
-                            os_log("SetRecoveryKey(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                             guard let response = response, error == nil else {
                                 os_log("setRecoveryKey failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                                reply(error ?? ContainerError.cloudkitResponseMissing)
+                                reply(nil, error ?? ContainerError.cloudkitResponseMissing)
                                 return
                             }
 
@@ -1773,142 +1844,23 @@ class Container: NSObject {
                                     try self.onQueuePersist(changes: response.changes)
 
                                     os_log("setRecoveryKey succeeded", log: tplogDebug, type: .default)
-                                    reply(nil)
+
+                                    let keyHierarchyRecords = response.zoneKeyHierarchyRecords.compactMap { CKRecord($0) }
+                                    reply(keyHierarchyRecords, nil)
                                 } catch {
                                     os_log("setRecoveryKey handling failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg))
-                                    reply(error)
+                                    reply(nil, error)
                                 }
                             }
                         }
                     } catch {
-                        reply(error)
+                        reply(nil, error)
                     }
                 }
             }
         }
     }
 
-    func currentSetContainerBottleID(bottleMOs: Set<BottleMO>, bottleID: String) -> (Bool) {
-        let bmos = bottleMOs.filter {
-            $0.bottleID == bottleID
-        }
-        return !bmos.isEmpty
-    }
-
-    func onqueueFindBottle(bottleID: String, reply: @escaping (BottleMO?, Error?) -> Void) {
-
-        var bmo: BottleMO?
-        var bottles: Set<BottleMO> = []
-        var shouldPerformFetch = false
-
-        if let containerBottles = self.containerMO.bottles as? Set<BottleMO> {
-            if self.currentSetContainerBottleID(bottleMOs: containerBottles, bottleID: bottleID) == false {
-                shouldPerformFetch = true
-            } else {
-                bottles = containerBottles
-            }
-        } else {
-            shouldPerformFetch = true
-        }
-
-        if shouldPerformFetch == true {
-            self.fetchViableBottlesWithSemaphore { _, _, error in
-                guard error == nil else {
-                    os_log("fetchViableBottles failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                    reply(nil, error)
-                    return
-                }
-
-                guard let newBottles = self.containerMO.bottles as? Set<BottleMO> else {
-                    os_log("no bottles on container: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                    reply(nil, ContainerError.noBottlesPresent)
-                    return
-                }
-
-                guard self.currentSetContainerBottleID(bottleMOs: newBottles, bottleID: bottleID) == true else {
-                    reply(nil, ContainerError.noBottlesForEscrowRecordID)
-                    return
-                }
-
-                os_log("onqueueFindBottle found bottle: %{public}@", log: tplogDebug, type: .default, newBottles)
-
-                bottles = newBottles.filter {
-                    $0.bottleID == bottleID
-                }
-                if bottles.count > 1 {
-                    reply(nil, ContainerError.tooManyBottlesForPeer)
-                    return
-                }
-                bmo = bottles.removeFirst()
-                reply(bmo, nil)
-            }
-        } else {
-            var filteredBottles = bottles.filter {
-                $0.bottleID == bottleID
-            }
-            if filteredBottles.count > 1 {
-                reply(nil, ContainerError.tooManyBottlesForPeer)
-                return
-            }
-            bmo = filteredBottles.removeFirst()
-            reply(bmo, nil)
-        }
-    }
-
-    func onqueueRecoverBottle(managedBottle: BottleMO, entropy: Data, bottleSalt: String) throws -> BottledPeer {
-        guard let bottledContents = managedBottle.contents else {
-            throw ContainerError.bottleDoesNotContainContents
-        }
-        guard let signatureUsingEscrowKey = managedBottle.signatureUsingEscrowKey else {
-            throw ContainerError.bottleDoesNotContainEscrowKeySignature
-        }
-
-        guard let signatureUsingPeerKey = managedBottle.signatureUsingPeerKey else {
-            throw ContainerError.bottleDoesNotContainerPeerKeySignature
-        }
-        guard let sponsorPeerID = managedBottle.peerID else {
-            throw ContainerError.bottleDoesNotContainPeerID
-        }
-
-        //verify bottle signature using peer
-        do {
-            guard let sponsorPeer = self.model.peer(withID: sponsorPeerID) else {
-                os_log("recover bottle: Unable to find peer that created the bottle", log: tplogDebug, type: .default)
-                throw ContainerError.bottleCreatingPeerNotFound
-            }
-            guard let signingKey: _SFECPublicKey = sponsorPeer.permanentInfo.signingPubKey as? _SFECPublicKey else {
-                os_log("recover bottle: Unable to create a sponsor public key", log: tplogDebug, type: .default)
-                throw ContainerError.signatureVerificationFailed
-            }
-
-            _ = try BottledPeer.verifyBottleSignature(data: bottledContents, signature: signatureUsingPeerKey, pubKey: signingKey)
-        } catch {
-            os_log("Verification of bottled signature failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-            throw ContainerError.failedToCreateBottledPeer
-        }
-
-        do {
-            return try BottledPeer(contents: bottledContents,
-                                   secret: entropy,
-                                   bottleSalt: bottleSalt,
-                                   signatureUsingEscrow: signatureUsingEscrowKey,
-                                   signatureUsingPeerKey: signatureUsingPeerKey)
-        } catch {
-            os_log("Creation of Bottled Peer failed with bottle salt: %@,\nAttempting with empty bottle salt", bottleSalt)
-
-            do {
-                return try BottledPeer(contents: bottledContents,
-                                       secret: entropy,
-                                       bottleSalt: "",
-                                       signatureUsingEscrow: signatureUsingEscrowKey,
-                                       signatureUsingPeerKey: signatureUsingPeerKey)
-            } catch {
-                os_log("Creation of Bottled Peer failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                throw ContainerError.failedToCreateBottledPeer
-            }
-        }
-    }
-
     func vouchWithBottle(bottleID: String,
                          entropy: Data,
                          bottleSalt: String,
@@ -1922,148 +1874,137 @@ class Container: NSObject {
             reply($0, $1, $2, $3, $4)
         }
 
-        self.fetchAndPersistChangesIfNeeded { error in
-            guard error == nil else {
-                os_log("vouchWithBottle unable to fetch changes: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
+        // A preflight should have been successful before calling this function. So, we can assume that all required data is stored locally.
+
+        self.moc.performAndWait {
+            let bmo: BottleMO
+
+            do {
+                (bmo, _, _) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
+            } catch {
+                os_log("vouchWithBottle failed preflight: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
                 reply(nil, nil, 0, 0, error)
                 return
             }
 
-            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: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
-                        reply(nil, nil, 0, 0, error)
-                        return
-                    }
-
-                    guard let bmo: BottleMO = returnedBMO else {
-                        os_log("vouchWithBottle bottle is nil: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
-                        reply(nil, nil, 0, 0, error)
-                        return
-                    }
-
-                    guard let bottledContents = bmo.contents else {
-                        reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainContents)
-                        return
-                    }
-                    guard let signatureUsingEscrowKey = bmo.signatureUsingEscrowKey else {
-                        reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainEscrowKeySignature)
-                        return
-                    }
-
-                    guard let signatureUsingPeerKey = bmo.signatureUsingPeerKey else {
-                        reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainerPeerKeySignature)
-                        return
-                    }
-                    guard let sponsorPeerID = bmo.peerID else {
-                        reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainPeerID)
-                        return
-                    }
+            guard let bottledContents = bmo.contents else {
+                reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainContents)
+                return
+            }
+            guard let signatureUsingEscrowKey = bmo.signatureUsingEscrowKey else {
+                reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainEscrowKeySignature)
+                return
+            }
 
-                    //verify bottle signature using peer
-                    do {
-                        guard let sponsorPeer = self.model.peer(withID: sponsorPeerID) else {
-                            os_log("vouchWithBottle: Unable to find peer that created the bottle", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.bottleCreatingPeerNotFound)
-                            return
-                        }
-                        guard let signingKey: _SFECPublicKey = sponsorPeer.permanentInfo.signingPubKey as? _SFECPublicKey else {
-                            os_log("vouchWithBottle: Unable to create a sponsor public key", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.signatureVerificationFailed)
-                            return
-                        }
+            guard let signatureUsingPeerKey = bmo.signatureUsingPeerKey else {
+                reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainerPeerKeySignature)
+                return
+            }
+            guard let sponsorPeerID = bmo.peerID else {
+                reply(nil, nil, 0, 0, ContainerError.bottleDoesNotContainPeerID)
+                return
+            }
 
-                        _ = try BottledPeer.verifyBottleSignature(data: bottledContents, signature: signatureUsingPeerKey, pubKey: signingKey)
-                    } catch {
-                        os_log("vouchWithBottle: Verification of bottled signature failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                        reply(nil, nil, 0, 0, ContainerError.failedToCreateBottledPeer)
-                        return
-                    }
+            //verify bottle signature using peer
+            do {
+                guard let sponsorPeer = self.model.peer(withID: sponsorPeerID) else {
+                    os_log("vouchWithBottle: Unable to find peer that created the bottle", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.bottleCreatingPeerNotFound)
+                    return
+                }
+                guard let signingKey: _SFECPublicKey = sponsorPeer.permanentInfo.signingPubKey as? _SFECPublicKey else {
+                    os_log("vouchWithBottle: Unable to create a sponsor public key", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.signatureVerificationFailed)
+                    return
+                }
 
-                    //create bottled peer
-                    let bottledPeer: BottledPeer
-                    do {
-                        bottledPeer = try BottledPeer(contents: bottledContents,
-                                                      secret: entropy,
-                                                      bottleSalt: bottleSalt,
-                                                      signatureUsingEscrow: signatureUsingEscrowKey,
-                                                      signatureUsingPeerKey: signatureUsingPeerKey)
-                    } catch {
-                        os_log("Creation of Bottled Peer failed with bottle salt: %@,\nAttempting with empty bottle salt", bottleSalt)
+                _ = try BottledPeer.verifyBottleSignature(data: bottledContents, signature: signatureUsingPeerKey, pubKey: signingKey)
+            } catch {
+                os_log("vouchWithBottle: Verification of bottled signature failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                reply(nil, nil, 0, 0, ContainerError.failedToCreateBottledPeer)
+                return
+            }
 
-                        do {
-                            bottledPeer = try BottledPeer(contents: bottledContents,
-                                                          secret: entropy,
-                                                          bottleSalt: "",
-                                                          signatureUsingEscrow: signatureUsingEscrowKey,
-                                                          signatureUsingPeerKey: signatureUsingPeerKey)
-                        } catch {
+            //create bottled peer
+            let bottledPeer: BottledPeer
+            do {
+                bottledPeer = try BottledPeer(contents: bottledContents,
+                                              secret: entropy,
+                                              bottleSalt: bottleSalt,
+                                              signatureUsingEscrow: signatureUsingEscrowKey,
+                                              signatureUsingPeerKey: signatureUsingPeerKey)
+            } catch {
+                os_log("Creation of Bottled Peer failed with bottle salt: %@,\nAttempting with empty bottle salt", bottleSalt)
 
-                            os_log("Creation of Bottled Peer failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                            reply(nil, nil, 0, 0, ContainerError.failedToCreateBottledPeer)
-                            return
-                        }
-                    }
+                do {
+                    bottledPeer = try BottledPeer(contents: bottledContents,
+                                                  secret: entropy,
+                                                  bottleSalt: "",
+                                                  signatureUsingEscrow: signatureUsingEscrowKey,
+                                                  signatureUsingPeerKey: signatureUsingPeerKey)
+                } catch {
+                    os_log("Creation of Bottled Peer failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                    reply(nil, nil, 0, 0, ContainerError.failedToCreateBottledPeer)
+                    return
+                }
+            }
 
-                    os_log("Have a bottle for peer %{public}@", log: tplogDebug, type: .default, bottledPeer.peerID)
+            os_log("Have a bottle for peer %{public}@", log: tplogDebug, type: .default, bottledPeer.peerID)
 
-                    // Extract any TLKs we have been given
-                    let (uniqueTLKsRecovered, totalSharesRecovered) = extract(tlkShares: tlkShares, peer: bottledPeer.peerKeys, model: self.model)
+            // Extract any TLKs we have been given
+            let (uniqueTLKsRecovered, totalSharesRecovered) = extract(tlkShares: tlkShares, peer: bottledPeer.peerKeys, model: self.model)
 
-                    self.moc.performAndWait {
-                        // I must have an ego identity in order to vouch using bottle
-                        guard let egoPeerID = self.containerMO.egoPeerID else {
-                            os_log("As a nonmember, can't vouch for someone else", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.nonMember)
-                            return
-                        }
-                        guard let permanentInfo = self.containerMO.egoPeerPermanentInfo else {
-                            os_log("permanentInfo does not exist", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.nonMember)
-                            return
-                        }
-                        guard let permanentInfoSig = self.containerMO.egoPeerPermanentInfoSig else {
-                            os_log("permanentInfoSig does not exist", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.nonMember)
-                            return
-                        }
-                        guard let stableInfo = self.containerMO.egoPeerStableInfo else {
-                            os_log("stableInfo does not exist", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.nonMember)
-                            return
-                        }
-                        guard let stableInfoSig = self.containerMO.egoPeerStableInfoSig else {
-                            os_log("stableInfoSig does not exist", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.nonMember)
-                            return
-                        }
-                        let keyFactory = TPECPublicKeyFactory()
-                        guard let beneficiaryPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: permanentInfo, sig: permanentInfoSig, keyFactory: keyFactory) else {
-                            os_log("Invalid permenent info or signature; can't vouch for them", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.invalidPermanentInfoOrSig)
-                            return
-                        }
-                        guard let beneficiaryStableInfo = TPPeerStableInfo(data: stableInfo, sig: stableInfoSig) else {
-                            os_log("Invalid stableinfo or signature; van't vouch for them", log: tplogDebug, type: .default)
-                            reply(nil, nil, 0, 0, ContainerError.invalidStableInfoOrSig)
-                            return
-                        }
+            self.moc.performAndWait {
+                // I must have an ego identity in order to vouch using bottle
+                guard let egoPeerID = self.containerMO.egoPeerID else {
+                    os_log("As a nonmember, can't vouch for someone else", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.nonMember)
+                    return
+                }
+                guard let permanentInfo = self.containerMO.egoPeerPermanentInfo else {
+                    os_log("permanentInfo does not exist", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.nonMember)
+                    return
+                }
+                guard let permanentInfoSig = self.containerMO.egoPeerPermanentInfoSig else {
+                    os_log("permanentInfoSig does not exist", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.nonMember)
+                    return
+                }
+                guard let stableInfo = self.containerMO.egoPeerStableInfo else {
+                    os_log("stableInfo does not exist", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.nonMember)
+                    return
+                }
+                guard let stableInfoSig = self.containerMO.egoPeerStableInfoSig else {
+                    os_log("stableInfoSig does not exist", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.nonMember)
+                    return
+                }
+                let keyFactory = TPECPublicKeyFactory()
+                guard let beneficiaryPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: permanentInfo, sig: permanentInfoSig, keyFactory: keyFactory) else {
+                    os_log("Invalid permenent info or signature; can't vouch for them", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.invalidPermanentInfoOrSig)
+                    return
+                }
+                guard let beneficiaryStableInfo = TPPeerStableInfo(data: stableInfo, sig: stableInfoSig) else {
+                    os_log("Invalid stableinfo or signature; van't vouch for them", log: tplogDebug, type: .default)
+                    reply(nil, nil, 0, 0, ContainerError.invalidStableInfoOrSig)
+                    return
+                }
 
-                        do {
-                            let voucher = try self.model.createVoucher(forCandidate: beneficiaryPermanentInfo,
-                                                                       stableInfo: beneficiaryStableInfo,
-                                                                       withSponsorID: sponsorPeerID,
-                                                                       reason: TPVoucherReason.restore,
-                                                                       signing: bottledPeer.peerKeys.signingKey)
-                            reply(voucher.data, voucher.sig, uniqueTLKsRecovered, totalSharesRecovered, nil)
-                            return
-                        } catch {
-                            os_log("Error creating voucher with bottle: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                            reply(nil, nil, 0, 0, error)
-                            return
-                        }
-                    }
+                do {
+                    let voucher = try self.model.createVoucher(forCandidate: beneficiaryPermanentInfo,
+                                                               stableInfo: beneficiaryStableInfo,
+                                                               withSponsorID: sponsorPeerID,
+                                                               reason: TPVoucherReason.restore,
+                                                               signing: bottledPeer.peerKeys.signingKey)
+                    reply(voucher.data, voucher.sig, uniqueTLKsRecovered, totalSharesRecovered, nil)
+                    return
+                } catch {
+                    os_log("Error creating voucher with bottle: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                    reply(nil, nil, 0, 0, error)
+                    return
                 }
             }
         }
@@ -2132,8 +2073,6 @@ class Container: NSObject {
                 return
             }
 
-            extract(tlkShares: tlkShares, peer: recoveryKeys.peerKeys, model: self.model)
-
             let signingPublicKey: Data = recoveryKeys.peerKeys.signingKey.publicKey.keyData
             let encryptionPublicKey: Data = recoveryKeys.peerKeys.encryptionKey.publicKey.keyData
 
@@ -2147,12 +2086,16 @@ class Container: NSObject {
             }
 
             //find matching peer containing recovery keys
-            guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingSPKI: signingPublicKey, encryptionSPKI: encryptionPublicKey)) else {
+            guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingKeyData: signingPublicKey, encryptionKeyData: encryptionPublicKey)) else {
                 os_log("Untrusted recovery key set", log: tplogDebug, type: .default)
                 reply(nil, nil, ContainerError.untrustedRecoveryKeys)
                 return
             }
 
+            // We're going to end up trusting every peer that the sponsor peer trusts.
+            // We might as well trust all TLKShares from those peers at this point.
+            extract(tlkShares: tlkShares, peer: recoveryKeys.peerKeys, sponsorPeerID: sponsorPeerID, model: self.model)
+
             do {
                 let voucher = try self.model.createVoucher(forCandidate: beneficiaryPermanentInfo,
                                                            stableInfo: beneficiaryStableInfo,
@@ -2340,7 +2283,6 @@ class Container: NSObject {
 
     func onqueueDistrust(peerIDs: Set<String>,
                          reply: @escaping (Error?) -> Void) {
-
         guard let egoPeerID = self.containerMO.egoPeerID else {
             os_log("No dynamic info for self?", log: tplogDebug, type: .default)
             reply(ContainerError.noPreparedIdentity)
@@ -2363,7 +2305,6 @@ class Container: NSObject {
                                                                              preapprovedKeys: nil,
                                                                              signing: signingKeyPair,
                                                                              currentMachineIDs: self.onqueueCurrentMIDList())
-
                 } catch {
                     os_log("Error preparing dynamic info: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "nil")
                     reply(error)
@@ -2379,7 +2320,6 @@ class Container: NSObject {
                     $0.dynamicInfoAndSig = signedDynamicInfo
                 }
                 self.cuttlefish.updateTrust(request) { response, error in
-                    os_log("UpdateTrust(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                     guard let response = response, error == nil else {
                         os_log("updateTrust failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                         reply(error ?? ContainerError.cloudkitResponseMissing)
@@ -2421,8 +2361,12 @@ class Container: NSObject {
                 return
             }
 
-            var bmoSet = bottles.filter { $0.peerID == egoPeerID }
-            let bmo = bmoSet.removeFirst()
+            guard let bmo = bottles.filter({ $0.peerID == egoPeerID }).first else {
+                os_log("fetchEscrowContents no bottle matches peerID", log: tplogDebug, type: .default)
+                reply(nil, nil, nil, ContainerError.noBottleForPeer)
+                return
+            }
+
             let bottleID = bmo.bottleID
             var entropy: Data
 
@@ -2459,35 +2403,157 @@ class Container: NSObject {
         self.fetchViableBottlesWithSemaphore(reply: reply)
     }
 
-    func onqueueCachedBottlesContainEgoPeerBottle(cachedBottles: TPCachedViableBottles) -> Bool {
-        guard let egoPeerID = self.containerMO.egoPeerID else {
-            os_log("bottleForEgoPeer: No identity.", log: tplogDebug, type: .default)
-            return false
+    func handleFetchViableBottlesResponseWithSemaphore(response: FetchViableBottlesResponse?) {
+        guard let escrowPairs = response?.viableBottles else {
+            os_log("fetchViableBottles returned no viable bottles", log: tplogDebug, type: .default)
+            return
+        }
+
+        var partialPairs: [EscrowPair] = []
+        if let partial = response?.partialBottles {
+            partialPairs = partial
+        } else {
+            os_log("fetchViableBottles returned no partially viable bottles, but that's ok", log: tplogDebug, type: .default)
         }
-        guard let bottles: Set<BottleMO> = self.containerMO.bottles as? Set<BottleMO>  else {
-            os_log("bottleForEgoPeer: No Bottles.", log: tplogDebug, type: .default)
-            return false
+
+        var legacyEscrowInformations: [EscrowInformation] = []
+        if let legacy = response?.legacyRecords {
+            legacyEscrowInformations = legacy
+        } else {
+            os_log("fetchViableBottles returned no legacy escrow records", log: tplogDebug, type: .default)
+        }
+
+        escrowPairs.forEach { pair in
+            let bottle = pair.bottle
+            let record = pair.record
+            if pair.hasRecord {
+                // Save this escrow record only if we don't already have it
+                if let existingRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
+                    let matchingRecords: Set<EscrowRecordMO> = existingRecords.filter { existing in existing.label == record.label
+                        && existing.escrowMetadata?.bottleID == record.escrowInformationMetadata.bottleID }
+                    if !matchingRecords.isEmpty {
+                        os_log("fetchViableBottles already knows about record, re-adding entry", log: tplogDebug, type: .default, record.label)
+                        self.containerMO.removeFromFullyViableEscrowRecords(matchingRecords as NSSet)
+                    }
+                    self.setEscrowRecord(record: record, viability: .full)
+                }
+            }
+            // Save this bottle only if we don't already have it
+            if let existingBottles = self.containerMO.bottles as? Set<BottleMO> {
+                let matchingBottles: Set<BottleMO> = existingBottles.filter { existing in
+                    existing.peerID == bottle.peerID &&
+                        existing.bottleID == bottle.bottleID &&
+                        existing.escrowedSigningSPKI == bottle.escrowedSigningSpki &&
+                        existing.signatureUsingEscrowKey == bottle.signatureUsingEscrowKey &&
+                        existing.signatureUsingPeerKey == bottle.signatureUsingPeerKey &&
+                        existing.contents == bottle.contents
+                }
+                if !matchingBottles.isEmpty {
+                    os_log("fetchViableBottles already knows about bottle", log: tplogDebug, type: .default, bottle.bottleID)
+                    return
+                }
+            }
+
+            let bmo = BottleMO(context: self.moc)
+            bmo.peerID = bottle.peerID
+            bmo.bottleID = bottle.bottleID
+            bmo.escrowedSigningSPKI = bottle.escrowedSigningSpki
+            bmo.signatureUsingEscrowKey = bottle.signatureUsingEscrowKey
+            bmo.signatureUsingPeerKey = bottle.signatureUsingPeerKey
+            bmo.contents = bottle.contents
+
+            os_log("fetchViableBottles saving new bottle: %{public}@", log: tplogDebug, type: .default, bmo)
+            self.containerMO.addToBottles(bmo)
         }
-        var matchesCached: Bool = false
-        for bottle in bottles {
-            guard let bottleID: String = bottle.bottleID else {
-                continue
+
+        partialPairs.forEach { pair in
+            let bottle = pair.bottle
+
+            let record = pair.record
+            // Save this escrow record only if we don't already have it
+            if pair.hasRecord {
+                if let existingRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
+                    let matchingRecords: Set<EscrowRecordMO> = existingRecords.filter { existing in existing.label == record.label
+                        && existing.escrowMetadata?.bottleID == record.escrowInformationMetadata.bottleID }
+                    if !matchingRecords.isEmpty {
+                        os_log("fetchViableBottles already knows about record, re-adding entry", log: tplogDebug, type: .default, record.label)
+                        self.containerMO.removeFromPartiallyViableEscrowRecords(matchingRecords as NSSet)
+                    }
+                    self.setEscrowRecord(record: record, viability: Viability.partial)
+                }
             }
-            if bottle.peerID == egoPeerID && (cachedBottles.viableBottles.contains(bottleID) || cachedBottles.partialBottles.contains(bottleID)) {
-                matchesCached = true
-                break
+
+            // Save this bottle only if we don't already have it
+            if let existingBottles = self.containerMO.bottles as? Set<BottleMO> {
+                let matchingBottles: Set<BottleMO> = existingBottles.filter { existing in
+                    existing.peerID == bottle.peerID &&
+                        existing.bottleID == bottle.bottleID &&
+                        existing.escrowedSigningSPKI == bottle.escrowedSigningSpki &&
+                        existing.signatureUsingEscrowKey == bottle.signatureUsingEscrowKey &&
+                        existing.signatureUsingPeerKey == bottle.signatureUsingPeerKey &&
+                        existing.contents == bottle.contents
+                }
+                if !matchingBottles.isEmpty {
+                    os_log("fetchViableBottles already knows about bottle", log: tplogDebug, type: .default, bottle.bottleID)
+                    return
+                }
+            }
+
+            let bmo = BottleMO(context: self.moc)
+            bmo.peerID = bottle.peerID
+            bmo.bottleID = bottle.bottleID
+            bmo.escrowedSigningSPKI = bottle.escrowedSigningSpki
+            bmo.signatureUsingEscrowKey = bottle.signatureUsingEscrowKey
+            bmo.signatureUsingPeerKey = bottle.signatureUsingPeerKey
+            bmo.contents = bottle.contents
+
+            os_log("fetchViableBottles saving new bottle: %{public}@", log: tplogDebug, type: .default, bmo)
+            self.containerMO.addToBottles(bmo)
+        }
+        legacyEscrowInformations.forEach { record in
+            // Save this escrow record only if we don't already have it
+            if let existingRecords = self.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO> {
+                let matchingRecords: Set<EscrowRecordMO> = existingRecords.filter { existing in existing.label == record.label }
+                if !matchingRecords.isEmpty {
+                    os_log("fetchViableBottles already knows about legacy record %@, re-adding entry", log: tplogDebug, type: .default, record.label)
+                    self.containerMO.removeFromLegacyEscrowRecords(matchingRecords as NSSet)
+                }
+                if record.label.hasSuffix(".double") {
+                    os_log("ignoring double enrollment record %@", record.label)
+                } else {
+                    self.setEscrowRecord(record: record, viability: Viability.none)
+                }
             }
         }
-        return matchesCached
     }
 
     func fetchViableBottlesWithSemaphore(reply: @escaping ([String]?, [String]?, Error?) -> Void) {
         os_log("beginning a fetchViableBottles", log: tplogDebug, type: .default)
 
-        let cachedBottles: TPCachedViableBottles = self.model.currentCachedViableBottlesSet()
         self.moc.performAndWait {
-            if self.onqueueCachedBottlesContainEgoPeerBottle(cachedBottles: cachedBottles)
-                && (!cachedBottles.viableBottles.isEmpty || !cachedBottles.partialBottles.isEmpty) {
+            var cachedBottles = TPCachedViableBottles(viableBottles: [], partialBottles: [])
+
+            if OctagonIsOptimizationEnabled() {
+                if let lastDate = self.containerMO.escrowFetchDate {
+                    if Date() < lastDate.addingTimeInterval(escrowCacheTimeout) {
+                        os_log("escrow cache still valid", log: tplogDebug, type: .default)
+                        cachedBottles = onqueueCachedBottlesFromEscrowRecords()
+                    } else {
+                        os_log("escrow cache no longer valid", log: tplogDebug, type: .default)
+                        if let records = self.containerMO.fullyViableEscrowRecords {
+                            self.containerMO.removeFromFullyViableEscrowRecords(records)
+                        }
+                        if let records = self.containerMO.partiallyViableEscrowRecords {
+                            self.containerMO.removeFromPartiallyViableEscrowRecords(records)
+                        }
+                        self.containerMO.escrowFetchDate = nil
+                    }
+                }
+            } else {
+                cachedBottles = self.model.currentCachedViableBottlesSet()
+            }
+
+            if !cachedBottles.viableBottles.isEmpty || !cachedBottles.partialBottles.isEmpty {
                 os_log("returning from fetchViableBottles, using cached bottles", log: tplogDebug, type: .default)
                 reply(cachedBottles.viableBottles, cachedBottles.partialBottles, nil)
                 return
@@ -2501,7 +2567,6 @@ class Container: NSObject {
                 }
 
                 self.moc.performAndWait {
-
                     guard let escrowPairs = response?.viableBottles else {
                         os_log("fetchViableBottles returned no viable bottles", log: tplogDebug, type: .default)
                         reply([], [], nil)
@@ -2521,87 +2586,138 @@ class Container: NSObject {
                     let partialBottleIDs = partialPairs.compactMap { $0.bottle.bottleID }
                     os_log("fetchViableBottles returned partial bottles: %{public}@", log: tplogDebug, type: .default, partialBottleIDs)
 
-                    escrowPairs.forEach { pair in
-                        let bottle = pair.bottle
-
-                        // Save this bottle only if we don't already have it
-                        if let existingBottles = self.containerMO.bottles as? Set<BottleMO> {
-                            let matchingBottles: Set<BottleMO> = existingBottles.filter { existing in
-                                existing.peerID == bottle.peerID &&
-                                    existing.bottleID == bottle.bottleID &&
-                                    existing.escrowedSigningSPKI == bottle.escrowedSigningSpki &&
-                                    existing.signatureUsingEscrowKey == bottle.signatureUsingEscrowKey &&
-                                    existing.signatureUsingPeerKey == bottle.signatureUsingPeerKey &&
-                                    existing.contents == bottle.contents
-                            }
-                            if !matchingBottles.isEmpty {
-                                os_log("fetchViableBottles already knows about bottle", log: tplogDebug, type: .default, bottle.bottleID)
-                                return
-                            }
-                        }
-
-                        let bmo = BottleMO(context: self.moc)
-                        bmo.peerID = bottle.peerID
-                        bmo.bottleID = bottle.bottleID
-                        bmo.escrowedSigningSPKI = bottle.escrowedSigningSpki
-                        bmo.signatureUsingEscrowKey = bottle.signatureUsingEscrowKey
-                        bmo.signatureUsingPeerKey = bottle.signatureUsingPeerKey
-                        bmo.contents = bottle.contents
-
-                        os_log("fetchViableBottles saving new bottle: %{public}@", log: tplogDebug, type: .default, bmo)
-                        self.containerMO.addToBottles(bmo)
-                    }
-
-                    partialPairs.forEach { pair in
-                        let bottle = pair.bottle
-
-                        // Save this bottle only if we don't already have it
-                        if let existingBottles = self.containerMO.bottles as? Set<BottleMO> {
-                            let matchingBottles: Set<BottleMO> = existingBottles.filter { existing in
-                                existing.peerID == bottle.peerID &&
-                                    existing.bottleID == bottle.bottleID &&
-                                    existing.escrowedSigningSPKI == bottle.escrowedSigningSpki &&
-                                    existing.signatureUsingEscrowKey == bottle.signatureUsingEscrowKey &&
-                                    existing.signatureUsingPeerKey == bottle.signatureUsingPeerKey &&
-                                    existing.contents == bottle.contents
-                            }
-                            if !matchingBottles.isEmpty {
-                                os_log("fetchViableBottles already knows about bottle", log: tplogDebug, type: .default, bottle.bottleID)
-                                return
-                            }
-                        }
-
-                        let bmo = BottleMO(context: self.moc)
-                        bmo.peerID = bottle.peerID
-                        bmo.bottleID = bottle.bottleID
-                        bmo.escrowedSigningSPKI = bottle.escrowedSigningSpki
-                        bmo.signatureUsingEscrowKey = bottle.signatureUsingEscrowKey
-                        bmo.signatureUsingPeerKey = bottle.signatureUsingPeerKey
-                        bmo.contents = bottle.contents
-
-                        os_log("fetchViableBottles saving new bottle: %{public}@", log: tplogDebug, type: .default, bmo)
-                        self.containerMO.addToBottles(bmo)
-                    }
+                    self.handleFetchViableBottlesResponseWithSemaphore(response: response)
 
                     do {
                         try self.moc.save()
                         os_log("fetchViableBottles saved bottles", log: tplogDebug, type: .default)
                         let cached = TPCachedViableBottles(viableBottles: viableBottleIDs, partialBottles: partialBottleIDs)
                         self.model.setViableBottles(cached)
+                        self.containerMO.escrowFetchDate = Date()
                         reply(viableBottleIDs, partialBottleIDs, nil)
                     } catch {
                         os_log("fetchViableBottles unable to save bottles: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                         reply(nil, nil, error)
                     }
+                }
+            }
+        }
+    }
+
+    func removeEscrowCache(reply: @escaping (Error?) -> Void) {
+        os_log("beginning a removeEscrowCache", log: tplogDebug, type: .default)
+
+        self.semaphore.wait()
+        let reply: (Error?) -> Void = {
+            os_log("removeEscrowCache complete %{public}@", log: tplogTrace, type: .info, traceError($0))
+            self.semaphore.signal()
+            reply($0)
+        }
+
+        self.moc.performAndWait {
+            self.onQueueRemoveEscrowCache()
+            reply(nil)
+        }
+    }
+
+    private func onQueueRemoveEscrowCache() {
+        if let records = self.containerMO.fullyViableEscrowRecords {
+            self.containerMO.removeFromFullyViableEscrowRecords(records)
+        }
+        if let records = self.containerMO.partiallyViableEscrowRecords {
+            self.containerMO.removeFromPartiallyViableEscrowRecords(records)
+        }
+        if let records = self.containerMO.legacyEscrowRecords {
+            self.containerMO.removeFromLegacyEscrowRecords(records)
+        }
+        self.containerMO.escrowFetchDate = nil
+    }
+
+    func fetchEscrowRecordsWithSemaphore(forceFetch: Bool, reply: @escaping ([Data]?, Error?) -> Void) {
+        os_log("beginning a fetchEscrowRecords", log: tplogDebug, type: .default)
+
+        self.moc.performAndWait {
+            var cachedRecords: [OTEscrowRecord] = []
+
+            if forceFetch == false {
+                os_log("fetchEscrowRecords: force fetch flag is off", log: tplogDebug, type: .default)
+                if let lastDate = self.containerMO.escrowFetchDate {
+                    if Date() < lastDate.addingTimeInterval(escrowCacheTimeout) {
+                        os_log("escrow cache still valid", log: tplogDebug, type: .default)
+                        cachedRecords = onqueueCachedEscrowRecords()
+                    } else {
+                        os_log("escrow cache no longer valid", log: tplogDebug, type: .default)
+                        self.onQueueRemoveEscrowCache()
+                    }
+                }
+            } else {
+                os_log("fetchEscrowRecords: force fetch flag is on, removing escrow cache", log: tplogDebug, type: .default)
+                self.onQueueRemoveEscrowCache()
+            }
+
+            if !cachedRecords.isEmpty {
+                os_log("returning from fetchEscrowRecords, using cached escrow records", log: tplogDebug, type: .default)
+                let recordData: [Data] = cachedRecords.map { $0.data }
+                reply(recordData, nil)
+                return
+            }
+
+            self.cuttlefish.fetchViableBottles { response, error in
+                guard error == nil else {
+                    os_log("fetchViableBottles failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
+                    reply(nil, error)
+                    return
+                }
+
+                self.moc.performAndWait {
+                    guard response?.viableBottles != nil else {
+                        os_log("fetchViableBottles returned no viable bottles", log: tplogDebug, type: .default)
+                        reply([], nil)
+                        return
+                    }
 
+                    self.handleFetchViableBottlesResponseWithSemaphore(response: response)
+                }
+
+                do {
+                    try self.moc.save()
+                    os_log("fetchViableBottles saved bottles and records", log: tplogDebug, type: .default)
+                    self.containerMO.escrowFetchDate = Date()
+
+                    var allEscrowRecordData: [Data] = []
+                    if let fullyViableRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
+                        for record in fullyViableRecords {
+                            if let r = self.escrowRecordMOToEscrowRecords(record: record, viability: .full) {
+                                allEscrowRecordData.append(r.data)
+                            }
+                        }
+                    }
+                    if let partiallyViableRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
+                        for record in partiallyViableRecords {
+                            if let r = self.escrowRecordMOToEscrowRecords(record: record, viability: .partial) {
+                                allEscrowRecordData.append(r.data)
+                            }
+                        }
+                    }
+                    if let legacyRecords = self.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO> {
+                        for record in legacyRecords {
+                            if let r = self.escrowRecordMOToEscrowRecords(record: record, viability: .none) {
+                                allEscrowRecordData.append(r.data)
+                            }
+                        }
+                    }
+                    reply(allEscrowRecordData, nil)
+                } catch {
+                    os_log("fetchViableBottles unable to save bottles and records: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
+                    reply(nil, error)
                 }
             }
         }
     }
 
-    func fetchCurrentPolicy(reply: @escaping (Set<String>?, TPPolicy?, Error?) -> Void) {
+    func fetchCurrentPolicy(modelIDOverride: String?, reply: @escaping (TPSyncingPolicy?, TPPBPeerStableInfo_UserControllableViewStatus, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (Set<String>?, TPPolicy?, Error?) -> Void = {
+        let reply: (TPSyncingPolicy?, TPPBPeerStableInfo_UserControllableViewStatus, Error?) -> Void = {
             os_log("fetchCurrentPolicy complete: %{public}@", log: tplogTrace, type: .info, traceError($2))
             self.semaphore.signal()
             reply($0, $1, $2)
@@ -2613,46 +2729,88 @@ class Container: NSObject {
                 let egoPermSig = self.containerMO.egoPeerPermanentInfoSig,
                 let stableInfoData = self.containerMO.egoPeerStableInfo,
                 let stableInfoSig = self.containerMO.egoPeerStableInfoSig else {
-                    os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
-                    reply(nil, nil, ContainerError.noPreparedIdentity)
+                os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
+                // This is technically an error, but we also need to know the prevailing syncing policy at CloudKit signin time, not just after we've started to join
+
+                guard let modelID = modelIDOverride else {
+                    os_log("no model ID override; returning error", log: tplogDebug, type: .default)
+                    reply(nil, .UNKNOWN, ContainerError.noPreparedIdentity)
                     return
+                }
+
+                guard let policyDocument = self.model.policy(withVersion: prevailingPolicyVersion.versionNumber) else {
+                    os_log("prevailing policy is missing?", log: tplogDebug, type: .default)
+                    reply(nil, .UNKNOWN, ContainerError.noPreparedIdentity)
+                    return
+                }
+
+                do {
+                    let prevailingPolicy = try policyDocument.policy(withSecrets: [:], decrypter: Decrypter())
+                    let syncingPolicy = try prevailingPolicy.syncingPolicy(forModel: modelID, syncUserControllableViews: .UNKNOWN)
+
+                    os_log("returning a policy for model ID %{public}@", log: tplogDebug, type: .default, modelID)
+                    reply(syncingPolicy, .UNKNOWN, nil)
+                    return
+                } catch {
+                    os_log("fetchCurrentPolicy failed to prevailing policy: %{public}@", log: tplogDebug, type: .error)
+                    reply(nil, .UNKNOWN, ContainerError.noPreparedIdentity)
+                    return
+                }
             }
 
             let keyFactory = TPECPublicKeyFactory()
             guard let permanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
                 os_log("fetchCurrentPolicy failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
-                reply(nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                reply(nil, .UNKNOWN, ContainerError.invalidPermanentInfoOrSig)
                 return
             }
             guard let stableInfo = TPPeerStableInfo(data: stableInfoData, sig: stableInfoSig) else {
                 os_log("fetchCurrentPolicy failed to create TPPeerStableInfo", log: tplogDebug, type: .error)
-                reply(nil, nil, ContainerError.invalidStableInfoOrSig)
+                reply(nil, .UNKNOWN, ContainerError.invalidStableInfoOrSig)
                 return
             }
 
             do {
-                let (views, policy) = try self.policyAndViewsFor(permanentInfo: permanentInfo, stableInfo: stableInfo)
-                reply(views, policy, nil)
+                let syncingPolicy = try self.syncingPolicyFor(modelID: modelIDOverride ?? permanentInfo.modelID, stableInfo: stableInfo)
+
+                guard let peer = self.model.peer(withID: permanentInfo.peerID), let dynamicInfo = peer.dynamicInfo else {
+                    os_log("fetchCurrentPolicy with no dynamic info", log: tplogDebug, type: .error)
+                    reply(syncingPolicy, .UNKNOWN, nil)
+                    return
+                }
+
+                // Note: we specifically do not want to sanitize this value for the platform: returning FOLLOWING here isn't that helpful
+                let peersUserViewSyncability = self.model.userViewSyncabilityConsensusAmongTrustedPeers(dynamicInfo)
+                reply(syncingPolicy, peersUserViewSyncability, nil)
                 return
             } catch {
-                os_log("TPPolicyDocument failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                reply(nil, nil, error)
+                os_log("Fetching the syncing policy failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                reply(nil, .UNKNOWN, error)
                 return
             }
         }
     }
 
-    func policyAndViewsFor(permanentInfo: TPPeerPermanentInfo, stableInfo: TPPeerStableInfo) throws -> (Set<String>, TPPolicy) {
-        let policyVersion = stableInfo.bestPolicyVersion()
-        guard let policyDocument = self.model.policy(withVersion: policyVersion.versionNumber) else {
-            os_log("current policy is missing?", log: tplogDebug, type: .default)
-            throw ContainerError.unknownPolicyVersion(policyVersion.versionNumber)
+    func syncingPolicyFor(modelID: String, stableInfo: TPPeerStableInfo) throws -> TPSyncingPolicy {
+        let bestPolicyVersion : TPPolicyVersion
+
+        let peerPolicyVersion = stableInfo.bestPolicyVersion()
+        if peerPolicyVersion.versionNumber < frozenPolicyVersion.versionNumber {
+            // This peer was from before CKKS4All, and we shouldn't listen to them when it comes to Syncing Policies
+            bestPolicyVersion = prevailingPolicyVersion
+            os_log("Ignoring policy version from pre-CKKS4All peer", log: tplogDebug, type: .default)
+
+        } else {
+            bestPolicyVersion = peerPolicyVersion
         }
 
-        let policy = try policyDocument.policy(withSecrets: stableInfo.policySecrets, decrypter: Decrypter())
-        let views = try policy.views(forModel: permanentInfo.modelID)
+        guard let policyDocument = self.model.policy(withVersion: bestPolicyVersion.versionNumber) else {
+            os_log("best policy is missing?", log: tplogDebug, type: .default)
+            throw ContainerError.unknownPolicyVersion(prevailingPolicyVersion.versionNumber)
+        }
 
-        return (views, policy)
+        let policy = try policyDocument.policy(withSecrets: stableInfo.policySecrets, decrypter: Decrypter())
+        return try policy.syncingPolicy(forModel: modelID, syncUserControllableViews: stableInfo.syncUserControllableViews)
     }
 
     // All-or-nothing: return an error in case full list cannot be returned.
@@ -2714,7 +2872,6 @@ class Container: NSObject {
         }
 
         self.cuttlefish.fetchPolicyDocuments(request) { response, error in
-            os_log("FetchPolicyDocuments(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
             guard let response = response, error == nil else {
                 os_log("FetchPolicyDocuments failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                 reply(nil, error ?? ContainerError.cloudkitResponseMissing)
@@ -2732,7 +2889,7 @@ class Container: NSObject {
                         return
                     }
 
-                    guard let expectedVersion = (remaining.filter { $0.versionNumber == doc.version.versionNumber }.first) else {
+                    guard let expectedVersion = (remaining.first { $0.versionNumber == doc.version.versionNumber }) else {
                         os_log("Received a policy version we didn't request: %d", log: tplogDebug, type: .default, doc.version.versionNumber)
                         reply(nil, ContainerError.policyDocumentDoesNotValidate)
                         return
@@ -2800,10 +2957,13 @@ class Container: NSObject {
         }
         vouchers?.forEach { voucher in
             self.model.register(voucher)
-            let voucherMO = VoucherMO(context: self.moc)
-            voucherMO.voucherInfo = voucher.data
-            voucherMO.voucherInfoSig = voucher.sig
-            peer.addToVouchers(voucherMO)
+
+            if (peer.vouchers as? Set<TPVoucher> ?? Set()).filter({ $0.data == voucher.data && $0.sig == voucher.sig }).isEmpty {
+                let voucherMO = VoucherMO(context: self.moc)
+                voucherMO.voucherInfo = voucher.data
+                voucherMO.voucherInfoSig = voucher.sig
+                peer.addToVouchers(voucherMO)
+            }
         }
         return peer
     }
@@ -2841,7 +3001,6 @@ class Container: NSObject {
                 }
 
                 peerShares += viewPeerShares
-
             } catch {
                 os_log("Unable to create TLKShares for keyset %@: %{public}@", log: tplogDebug, type: .default, String(describing: keyset), error as CVarArg)
             }
@@ -2865,8 +3024,30 @@ class Container: NSObject {
                                                      signing: egoPeerKeys.signingKey,
                                                      currentMachineIDs: self.onqueueCurrentMIDList())
 
-        let newStableInfo = try self.createNewStableInfoIfNeeded(stableChanges: nil,
-                                                                 egoPeerID: egoPeerID,
+        let userViewSyncability: TPPBPeerStableInfo_UserControllableViewStatus?
+        if [.ENABLED, .DISABLED].contains(stableInfo.syncUserControllableViews) {
+            // No change!
+            userViewSyncability = nil
+        } else {
+            let newUserViewSyncability: TPPBPeerStableInfo_UserControllableViewStatus
+
+            if peerPermanentInfo.modelID.hasPrefix("AppleTV") ||
+                peerPermanentInfo.modelID.hasPrefix("AudioAccessory") ||
+                peerPermanentInfo.modelID.hasPrefix("Watch") {
+                // Watches, TVs, and AudioAccessories always join as FOLLOWING.
+                newUserViewSyncability = .FOLLOWING
+            } else {
+                // All other platforms select what the other devices say to do
+                newUserViewSyncability = self.model.userViewSyncabilityConsensusAmongTrustedPeers(dynamicInfo)
+            }
+
+            os_log("join: setting 'user view sync' control as: %{public}@", log: tplogDebug, type: .default,
+                   TPPBPeerStableInfo_UserControllableViewStatusAsString(newUserViewSyncability))
+            userViewSyncability = newUserViewSyncability
+        }
+
+        let newStableInfo = try self.createNewStableInfoIfNeeded(stableChanges: StableChanges.change(viewStatus: userViewSyncability),
+                                                                 permanentInfo: peerPermanentInfo,
                                                                  existingStableInfo: stableInfo,
                                                                  dynamicInfo: dynamicInfo,
                                                                  signingKeyPair: egoPeerKeys.signingKey)
@@ -2887,17 +3068,17 @@ class Container: NSObject {
               ckksKeys: [CKKSKeychainBackedKeySet],
               tlkShares: [CKKSTLKShare],
               preapprovedKeys: [Data]?,
-              reply: @escaping (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void) {
+              reply: @escaping (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void = {
-            os_log("join complete: %{public}@", log: tplogTrace, type: .info, traceError($4))
+        let reply: (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void = {
+            os_log("join complete: %{public}@", log: tplogTrace, type: .info, traceError($3))
             self.semaphore.signal()
-            reply($0, $1, $2, $3, $4)
+            reply($0, $1, $2, $3)
         }
 
         self.fetchAndPersistChanges { error in
             guard error == nil else {
-                reply(nil, [], nil, nil, error)
+                reply(nil, [], nil, error)
                 return
             }
 
@@ -2910,11 +3091,11 @@ class Container: NSObject {
 
                 self.moc.performAndWait {
                     guard let voucher = TPVoucher(infoWith: voucherData, sig: voucherSig) else {
-                        reply(nil, [], nil, nil, ContainerError.invalidVoucherOrSig)
+                        reply(nil, [], nil, ContainerError.invalidVoucherOrSig)
                         return
                     }
                     guard let sponsor = self.model.peer(withID: voucher.sponsorID) else {
-                        reply(nil, [], nil, nil, ContainerError.sponsorNotRegistered(voucher.sponsorID))
+                        reply(nil, [], nil, ContainerError.sponsorNotRegistered(voucher.sponsorID))
                         return
                     }
 
@@ -2925,30 +3106,30 @@ class Container: NSObject {
                         let egoStableData = self.containerMO.egoPeerStableInfo,
                         let egoStableSig = self.containerMO.egoPeerStableInfoSig
                         else {
-                            reply(nil, [], nil, nil, ContainerError.noPreparedIdentity)
+                            reply(nil, [], nil, ContainerError.noPreparedIdentity)
                             return
                     }
 
                     let keyFactory = TPECPublicKeyFactory()
                     guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-                        reply(nil, [], nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                        reply(nil, [], nil, ContainerError.invalidPermanentInfoOrSig)
                         return
                     }
                     guard let selfStableInfo = TPPeerStableInfo(data: egoStableData, sig: egoStableSig) else {
-                        reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+                        reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
                         return
                     }
                     guard self.onqueueMachineIDAllowedByIDMS(machineID: selfPermanentInfo.machineID) else {
                         os_log("join: self machineID %{public}@ not on list", log: tplogDebug, type: .debug, selfPermanentInfo.machineID)
                         self.onqueueTTRUntrusted()
-                        reply(nil, [], nil, nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
+                        reply(nil, [], nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
                         return
                     }
 
                     loadEgoKeys(peerID: egoPeerID) { egoPeerKeys, error in
                         guard let egoPeerKeys = egoPeerKeys else {
                             os_log("Don't have my own peer keys; can't join: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                             return
                         }
                         self.moc.performAndWait {
@@ -2967,13 +3148,13 @@ class Container: NSObject {
                                                                                                egoPeerKeys: egoPeerKeys)
                             } catch {
                                 os_log("Unable to create peer for joining: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                                reply(nil, [], nil, nil, error)
+                                reply(nil, [], nil, error)
                                 return
                             }
 
                             guard let peerStableInfo = peer.stableInfoAndSig.toStableInfo() else {
-                                os_log("Unable to create new peer stable new for joining", log: tplogDebug, type: .default)
-                                reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+                                os_log("Unable to create new peer stable info for joining", log: tplogDebug, type: .default)
+                                reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
                                 return
                             }
 
@@ -2987,7 +3168,7 @@ class Container: NSObject {
                                                                                             epoch: Int(selfPermanentInfo.epoch))
                             } catch {
                                 os_log("Unable to process keys before joining: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                                reply(nil, [], nil, nil, error)
+                                reply(nil, [], nil, error)
                                 return
                             }
 
@@ -2997,7 +3178,7 @@ class Container: NSObject {
                                                                  withSponsorID: sponsor.peerID)
                             } catch {
                                 os_log("Error checking introduction: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                                reply(nil, [], nil, nil, error)
+                                reply(nil, [], nil, error)
                                 return
                             }
 
@@ -3005,7 +3186,7 @@ class Container: NSObject {
                             do {
                                 bottle = try self.assembleBottle(egoPeerID: egoPeerID)
                             } catch {
-                                reply(nil, [], nil, nil, error)
+                                reply(nil, [], nil, error)
                                 return
                             }
 
@@ -3037,10 +3218,9 @@ class Container: NSObject {
                                 $0.viewKeys = viewKeys
                             }
                             self.cuttlefish.joinWithVoucher(request) { response, error in
-                                os_log("JoinWithVoucher(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                                 guard let response = response, error == nil else {
                                     os_log("joinWithVoucher failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                                    reply(nil, [], nil, nil, error ?? ContainerError.cloudkitResponseMissing)
+                                    reply(nil, [], nil, error ?? ContainerError.cloudkitResponseMissing)
                                     return
                                 }
 
@@ -3049,17 +3229,17 @@ class Container: NSObject {
                                         self.containerMO.egoPeerStableInfo = peer.stableInfoAndSig.peerStableInfo
                                         self.containerMO.egoPeerStableInfoSig = peer.stableInfoAndSig.sig
 
-                                        let (syncingViews, policy) = try self.policyAndViewsFor(permanentInfo: selfPermanentInfo,
-                                                                                                stableInfo: peerStableInfo)
+                                        let syncingPolicy = try self.syncingPolicyFor(modelID: selfPermanentInfo.modelID,
+                                                                                      stableInfo: peerStableInfo)
 
                                         try self.onQueuePersist(changes: response.changes)
                                         os_log("JoinWithVoucher succeeded", log: tplogDebug)
 
                                         let keyHierarchyRecords = response.zoneKeyHierarchyRecords.compactMap { CKRecord($0) }
-                                        reply(egoPeerID, keyHierarchyRecords, syncingViews, policy, nil)
+                                        reply(egoPeerID, keyHierarchyRecords, syncingPolicy, nil)
                                     } catch {
                                         os_log("JoinWithVoucher failed: %{public}@", log: tplogDebug, String(describing: error))
-                                        reply(nil, [], nil, nil, error)
+                                        reply(nil, [], nil, error)
                                     }
                                 }
                             }
@@ -3135,8 +3315,6 @@ class Container: NSObject {
         }
 
         self.cuttlefish.getSupportAppInfo { response, error in
-            os_log("getSupportAppInfo(): %{public}@, error: %{public}@", log: tplogDebug,
-                   "(\(String(describing: response))", "\(String(describing: error))")
             guard let response = response, error == nil else {
                 os_log("getSupportAppInfo failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
                 reply(nil, error ?? ContainerError.cloudkitResponseMissing)
@@ -3150,10 +3328,10 @@ class Container: NSObject {
 
             reply(data, nil)
         }
-
     }
 
-    func preflightPreapprovedJoin(reply: @escaping (Bool, Error?) -> Void) {
+    func preflightPreapprovedJoin(preapprovedKeys: [Data]?,
+                                  reply: @escaping (Bool, Error?) -> Void) {
         self.semaphore.wait()
         let reply: (Bool, Error?) -> Void = {
             os_log("preflightPreapprovedJoin complete: %{public}@", log: tplogTrace, type: .info, traceError($1))
@@ -3205,6 +3383,16 @@ class Container: NSObject {
                     return
                 }
 
+                let keysApprovingPeers = preapprovedKeys?.filter { key in
+                    self.model.hasPotentiallyTrustedPeer(withSigningKey: key)
+                }
+
+                guard (keysApprovingPeers?.count ?? 0) > 0 else {
+                    os_log("preflightPreapprovedJoin: no reciprocal trust for existing peers", log: tplogDebug, type: .debug)
+                    reply(false, ContainerError.noPeersPreapprovedBySelf)
+                    return
+                }
+
                 reply(true, nil)
             }
         }
@@ -3213,18 +3401,18 @@ class Container: NSObject {
     func preapprovedJoin(ckksKeys: [CKKSKeychainBackedKeySet],
                          tlkShares: [CKKSTLKShare],
                          preapprovedKeys: [Data]?,
-                         reply: @escaping (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void) {
+                         reply: @escaping (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, [CKRecord], Set<String>?, TPPolicy?, Error?) -> Void = {
-            os_log("preapprovedJoin complete: %{public}@", log: tplogTrace, type: .info, traceError($4))
+        let reply: (String?, [CKRecord], TPSyncingPolicy?, Error?) -> Void = {
+            os_log("preapprovedJoin complete: %{public}@", log: tplogTrace, type: .info, traceError($3))
             self.semaphore.signal()
-            reply($0, $1, $2, $3, $4)
+            reply($0, $1, $2, $3)
         }
 
         self.fetchAndPersistChangesIfNeeded { error in
             guard error == nil else {
                 os_log("preapprovedJoin unable to fetch changes: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
-                reply(nil, [], nil, nil, error)
+                reply(nil, [], nil, error)
                 return
             }
             self.moc.performAndWait {
@@ -3233,10 +3421,11 @@ class Container: NSObject {
                 // That's up to the caller.
                 if self.model.allPeerIDs().isEmpty {
                     os_log("preapprovedJoin but no existing peers, attempting establish", log: tplogDebug, type: .debug)
+
                     self.onqueueEstablish(ckksKeys: ckksKeys,
-                        tlkShares: tlkShares,
-                        preapprovedKeys: preapprovedKeys,
-                        reply: reply)
+                                          tlkShares: tlkShares,
+                                          preapprovedKeys: preapprovedKeys,
+                                          reply: reply)
                     return
                 }
 
@@ -3248,41 +3437,40 @@ class Container: NSObject {
                     let egoStableSig = self.containerMO.egoPeerStableInfoSig
                     else {
                         os_log("preapprovedJoin: no prepared identity", log: tplogDebug, type: .debug)
-                        reply(nil, [], nil, nil, ContainerError.noPreparedIdentity)
+                        reply(nil, [], nil, ContainerError.noPreparedIdentity)
                         return
                 }
 
                 let keyFactory = TPECPublicKeyFactory()
                 guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-                    reply(nil, [], nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                    reply(nil, [], nil, ContainerError.invalidPermanentInfoOrSig)
                     return
                 }
                 guard let selfStableInfo = TPPeerStableInfo(data: egoStableData, sig: egoStableSig) else {
-                    reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+                    reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
                     return
                 }
 
                 guard self.onqueueMachineIDAllowedByIDMS(machineID: selfPermanentInfo.machineID) else {
                     os_log("preapprovedJoin: self machineID %{public}@ (me) not on list", log: tplogDebug, type: .debug, selfPermanentInfo.machineID)
                     self.onqueueTTRUntrusted()
-                    reply(nil, [], nil, nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
+                    reply(nil, [], nil, ContainerError.preparedIdentityNotOnAllowedList(selfPermanentInfo.machineID))
                     return
                 }
                 loadEgoKeys(peerID: egoPeerID) { egoPeerKeys, error in
                     guard let egoPeerKeys = egoPeerKeys else {
                         os_log("preapprovedJoin: Don't have my own keys: can't join", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                        reply(nil, [], nil, nil, error)
+                        reply(nil, [], nil, error)
                         return
                     }
 
                     guard self.model.hasPotentiallyTrustedPeerPreapprovingKey(egoPeerKeys.signingKey.publicKey().spki()) else {
                         os_log("preapprovedJoin: no peers preapprove our key", log: tplogDebug, type: .debug)
-                        reply(nil, [], nil, nil, ContainerError.noPeersPreapprovePreparedIdentity)
+                        reply(nil, [], nil, ContainerError.noPeersPreapprovePreparedIdentity)
                         return
                     }
 
                     self.moc.performAndWait {
-
                         let peer: Peer
                         let newDynamicInfo: TPPeerDynamicInfo
                         do {
@@ -3295,13 +3483,13 @@ class Container: NSObject {
                                                                                            egoPeerKeys: egoPeerKeys)
                         } catch {
                             os_log("Unable to create peer for joining: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                             return
                         }
 
                         guard let peerStableInfo = peer.stableInfoAndSig.toStableInfo() else {
-                            os_log("Unable to create new peer stable new for joining", log: tplogDebug, type: .default)
-                            reply(nil, [], nil, nil, ContainerError.invalidStableInfoOrSig)
+                            os_log("Unable to create new peer stable info for joining", log: tplogDebug, type: .default)
+                            reply(nil, [], nil, ContainerError.invalidStableInfoOrSig)
                             return
                         }
 
@@ -3309,13 +3497,13 @@ class Container: NSObject {
                         let viewKeys: [ViewKeys]
                         do {
                             (viewKeys, allTLKShares) = try self.makeSharesForNewKeySets(ckksKeys: ckksKeys,
-                                                                                   tlkShares: tlkShares,
-                                                                                   egoPeerKeys: egoPeerKeys,
-                                                                                   egoPeerDynamicInfo: newDynamicInfo,
-                                                                                   epoch: Int(selfPermanentInfo.epoch))
+                                                                                        tlkShares: tlkShares,
+                                                                                        egoPeerKeys: egoPeerKeys,
+                                                                                        egoPeerDynamicInfo: newDynamicInfo,
+                                                                                        epoch: Int(selfPermanentInfo.epoch))
                         } catch {
                             os_log("Unable to process keys before joining: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                             return
                         }
 
@@ -3323,7 +3511,7 @@ class Container: NSObject {
                         do {
                             bottle = try self.assembleBottle(egoPeerID: egoPeerID)
                         } catch {
-                            reply(nil, [], nil, nil, error)
+                            reply(nil, [], nil, error)
                             return
                         }
 
@@ -3355,10 +3543,9 @@ class Container: NSObject {
                             $0.viewKeys = viewKeys
                         }
                         self.cuttlefish.joinWithVoucher(request) { response, error in
-                            os_log("preapprovedJoin(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
                             guard let response = response, error == nil else {
                                 os_log("preapprovedJoin failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                                reply(nil, [], nil, nil, error ?? ContainerError.cloudkitResponseMissing)
+                                reply(nil, [], nil, error ?? ContainerError.cloudkitResponseMissing)
                                 return
                             }
 
@@ -3367,17 +3554,17 @@ class Container: NSObject {
                                     self.containerMO.egoPeerStableInfo = peer.stableInfoAndSig.peerStableInfo
                                     self.containerMO.egoPeerStableInfoSig = peer.stableInfoAndSig.sig
 
-                                    let (syncingViews, policy) = try self.policyAndViewsFor(permanentInfo: selfPermanentInfo,
-                                                                                            stableInfo: peerStableInfo)
+                                    let syncingPolicy = try self.syncingPolicyFor(modelID: selfPermanentInfo.modelID,
+                                                                                  stableInfo: peerStableInfo)
 
                                     try self.onQueuePersist(changes: response.changes)
                                     os_log("preapprovedJoin succeeded", log: tplogDebug)
 
                                     let keyHierarchyRecords = response.zoneKeyHierarchyRecords.compactMap { CKRecord($0) }
-                                    reply(egoPeerID, keyHierarchyRecords, syncingViews, policy, nil)
+                                    reply(egoPeerID, keyHierarchyRecords, syncingPolicy, nil)
                                 } catch {
                                     os_log("preapprovedJoin failed: %{public}@", log: tplogDebug, String(describing: error))
-                                    reply(nil, [], nil, nil, error)
+                                    reply(nil, [], nil, error)
                                 }
                             }
                         }
@@ -3392,12 +3579,13 @@ class Container: NSObject {
                 osVersion: String?,
                 policyVersion: UInt64?,
                 policySecrets: [String: Data]?,
-                reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
+                syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus?,
+                reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (TrustedPeersHelperPeerState?, Error?) -> Void = {
-            os_log("update complete: %{public}@", log: tplogTrace, type: .info, traceError($1))
+        let reply: (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void = {
+            os_log("update complete: %{public}@", log: tplogTrace, type: .info, traceError($2))
             self.semaphore.signal()
-            reply($0, $1)
+            reply($0, $1, $2)
         }
 
         // Get (and save) the latest from cuttlefish
@@ -3405,7 +3593,8 @@ class Container: NSObject {
                                           serialNumber: serialNumber,
                                           osVersion: osVersion,
                                           policyVersion: policyVersion,
-                                          policySecrets: policySecrets)
+                                          policySecrets: policySecrets,
+                                          setSyncUserControllableViews: syncUserControllableViews)
         self.fetchChangesAndUpdateTrustIfNeeded(stableChanges: stableChanges, reply: reply)
     }
 
@@ -3455,7 +3644,9 @@ class Container: NSObject {
                         os_log("setPreapprovedKeys: no change; nothing to do.", log: tplogDebug, type: .default)
 
                         // Calling this will fill in the peer status
-                        self.updateTrustIfNeeded(reply: reply)
+                        self.updateTrustIfNeeded { status, _, error in
+                            reply(status, error)
+                        }
                         return
                     }
 
@@ -3466,7 +3657,7 @@ class Container: NSObject {
                         $0.dynamicInfoAndSig = SignedPeerDynamicInfo(dynamicInfo)
                     }
 
-                    self.perform(updateTrust: request) { state, error in
+                    self.perform(updateTrust: request) { state, _, error in
                         guard error == nil else {
                             os_log("setPreapprovedKeys: failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg? ?? "no error")
                             reply(state, error)
@@ -3496,11 +3687,11 @@ class Container: NSObject {
         self.moc.performAndWait {
             self.onqueueUpdateTLKs(ckksKeys: ckksKeys, tlkShares: tlkShares, reply: reply)
         }
-   }
+    }
 
-   func onqueueUpdateTLKs(ckksKeys: [CKKSKeychainBackedKeySet],
-                          tlkShares: [CKKSTLKShare],
-                          reply: @escaping ([CKRecord]?, Error?) -> Void) {
+    func onqueueUpdateTLKs(ckksKeys: [CKKSKeychainBackedKeySet],
+                           tlkShares: [CKKSTLKShare],
+                           reply: @escaping ([CKRecord]?, Error?) -> Void) {
         guard let egoPeerID = self.containerMO.egoPeerID,
             let egoPermData = self.containerMO.egoPeerPermanentInfo,
             let egoPermSig = self.containerMO.egoPeerPermanentInfoSig
@@ -3518,7 +3709,7 @@ class Container: NSObject {
 
         loadEgoKeys(peerID: egoPeerID) { egoPeerKeys, error in
             guard let egoPeerKeys = egoPeerKeys else {
-                os_log("Don't have my own peer keys; can't upload new TLKs: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
+                os_log("Don't have my own peer keys; can't upload new TLKs: %@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "error missing")
                 reply(nil, error)
                 return
             }
@@ -3551,8 +3742,6 @@ class Container: NSObject {
                 }
 
                 self.cuttlefish.updateTrust(request) { response, error in
-                    os_log("UpdateTrust(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
-
                     guard error == nil else {
                         reply(nil, error)
                         return
@@ -3584,6 +3773,18 @@ class Container: NSObject {
                 }
             }
 
+            if self.containerMO.fullyViableEscrowRecords != nil {
+                self.containerMO.fullyViableEscrowRecords!.forEach { record in
+                    state.escrowRecords.insert(record as! EscrowRecordMO)
+                }
+            }
+
+            if self.containerMO.partiallyViableEscrowRecords != nil {
+                self.containerMO.partiallyViableEscrowRecords!.forEach { record in
+                    state.escrowRecords.insert(record as! EscrowRecordMO)
+                }
+            }
+
             self.model.allPeers().forEach { peer in
                 state.peers[peer.peerID] = peer
             }
@@ -3603,7 +3804,7 @@ class Container: NSObject {
         }
     }
 
-    private func fetchAndPersistChanges(reply: @escaping (Error?) -> Void) {
+    func fetchAndPersistChanges(reply: @escaping (Error?) -> Void) {
         self.moc.performAndWait {
             self.onqueueFetchAndPersistChanges(reply: reply)
         }
@@ -3616,7 +3817,6 @@ class Container: NSObject {
         os_log("Fetching with change token: %{public}@", log: tplogDebug, type: .default, !request.changeToken.isEmpty ? request.changeToken : "empty")
 
         self.cuttlefish.fetchChanges(request) { response, error in
-            os_log("FetchChanges(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
             guard let response = response, error == nil else {
                 switch error {
                 case CuttlefishErrorMatcher(code: CuttlefishErrorCode.changeTokenExpired):
@@ -3693,11 +3893,11 @@ class Container: NSObject {
     // (i.e. after reply is invoked).
     internal func fetchChangesAndUpdateTrustIfNeeded(stableChanges: StableChanges? = nil,
                                                      peerChanges: Bool = false,
-                                                     reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
+                                                     reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
         self.fetchAndPersistChanges { error in
             if let error = error {
                 os_log("fetchChangesAndUpdateTrustIfNeeded: fetching failed: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                reply(nil, error)
+                reply(nil, nil, error)
                 return
             }
 
@@ -3716,18 +3916,22 @@ class Container: NSObject {
     // (i.e. after reply is invoked).
     private func updateTrustIfNeeded(stableChanges: StableChanges? = nil,
                                      peerChanges: Bool = false,
-                                     reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
+                                     reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
         self.moc.performAndWait {
             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: peerChanges, unknownMachineIDs: false, osVersion: nil), nil)
+                reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: peerChanges, unknownMachineIDs: false, osVersion: nil),
+                      nil,
+                      nil)
                 return
             }
             loadEgoKeyPair(identifier: signingKeyIdentifier(peerID: egoPeerID)) { signingKeyPair, error in
                 guard let signingKeyPair = signingKeyPair else {
                     os_log("updateTrustIfNeeded: no signing key pair: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                    reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: peerChanges, unknownMachineIDs: false, osVersion: nil), error)
+                    reply(TrustedPeersHelperPeerState(peerID: nil, isPreapproved: false, status: .unknown, memberChanges: peerChanges, unknownMachineIDs: false, osVersion: nil),
+                          nil,
+                          error)
                     return
                 }
                 guard let currentSelfInModel = self.model.peer(withID: egoPeerID) else {
@@ -3740,6 +3944,7 @@ class Container: NSObject {
                                                       memberChanges: peerChanges,
                                                       unknownMachineIDs: false,
                                                       osVersion: nil),
+                          nil,
                           nil)
                     return
                 }
@@ -3755,7 +3960,6 @@ class Container: NSObject {
                         let dynamicInfo: TPPeerDynamicInfo
                         var stableInfo: TPPeerStableInfo?
                         do {
-
                             // FIXME We should be able to calculate the contents of dynamicInfo without the signingKeyPair,
                             // and then only load the key if it has changed and we need to sign a new one. This would also
                             // help make our detection of change immune from non-canonical serialization of dynamicInfo.
@@ -3767,7 +3971,7 @@ class Container: NSObject {
                                                                                      currentMachineIDs: self.onqueueCurrentMIDList())
 
                             stableInfo = try self.createNewStableInfoIfNeeded(stableChanges: stableChanges,
-                                                                              egoPeerID: egoPeerID,
+                                                                              permanentInfo: currentSelfInModel.permanentInfo,
                                                                               existingStableInfo: currentSelfInModel.stableInfo,
                                                                               dynamicInfo: dynamicInfo,
                                                                               signingKeyPair: signingKeyPair)
@@ -3779,6 +3983,7 @@ class Container: NSObject {
                                                               memberChanges: peerChanges,
                                                               unknownMachineIDs: false,
                                                               osVersion: nil),
+                                  nil,
                                   error)
                             return
                         }
@@ -3798,12 +4003,25 @@ class Container: NSObject {
                                 os_log("updateTrustIfNeeded: unable to remove untrusted MachineIDs: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
                             }
 
+                            let syncingPolicy: TPSyncingPolicy?
+                            do {
+                                if let peer = self.model.peer(withID: egoPeerID), let stableInfo = peer.stableInfo {
+                                    syncingPolicy = try self.syncingPolicyFor(modelID: peer.permanentInfo.modelID, stableInfo: stableInfo)
+                                } else {
+                                    syncingPolicy = nil
+                                }
+                            } catch {
+                                os_log("updateTrustIfNeeded: unable to compute a new syncing policy: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
+                                syncingPolicy = nil
+                            }
+
                             reply(TrustedPeersHelperPeerState(peerID: egoPeerID,
                                                               isPreapproved: false,
                                                               status: self.model.statusOfPeer(withID: egoPeerID),
                                                               memberChanges: peerChanges,
                                                               unknownMachineIDs: self.onqueueFullIDMSListWouldBeHelpful(),
                                                               osVersion: peer?.stableInfo?.osVersion),
+                                  syncingPolicy,
                                   nil)
                             return
                         }
@@ -3811,7 +4029,7 @@ class Container: NSObject {
                         let havePeerChanges = peerChanges || self.haveTrustMemberChanges(newDynamicInfo: dynamicInfo, oldDynamicInfo: peer?.dynamicInfo)
 
                         let signedDynamicInfo = SignedPeerDynamicInfo(dynamicInfo)
-                            os_log("updateTrustIfNeeded: attempting updateTrust for %{public}@ with: %{public}@", log: tplogDebug, type: .default, egoPeerID, dynamicInfo)
+                        os_log("updateTrustIfNeeded: attempting updateTrust for %{public}@ with: %{public}@", log: tplogDebug, type: .default, egoPeerID, dynamicInfo)
                         var request = UpdateTrustRequest.with {
                             $0.changeToken = self.containerMO.changeToken ?? ""
                             $0.peerID = egoPeerID
@@ -3831,13 +4049,11 @@ class Container: NSObject {
     private func perform(updateTrust request: UpdateTrustRequest,
                          stableChanges: StableChanges? = nil,
                          peerChanges: Bool = false,
-                         reply: @escaping (TrustedPeersHelperPeerState?, Error?) -> Void) {
-
+                         reply: @escaping (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) -> Void) {
         self.cuttlefish.updateTrust(request) { response, error in
-            os_log("UpdateTrust(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
             guard let response = response, error == nil else {
                 os_log("UpdateTrust failed: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "no error")
-                reply(nil, error ?? ContainerError.cloudkitResponseMissing)
+                reply(nil, nil, error ?? ContainerError.cloudkitResponseMissing)
                 return
             }
 
@@ -3845,7 +4061,7 @@ class Container: NSObject {
                 try self.persist(changes: response.changes)
             } catch {
                 os_log("UpdateTrust failed: %{public}@", log: tplogDebug, String(describing: error))
-                reply(nil, error)
+                reply(nil, nil, error)
                 return
             }
 
@@ -3892,15 +4108,14 @@ class Container: NSObject {
 
         if !changes.differences.isEmpty {
             self.model.clearViableBottles()
+            os_log("escrow cache and viable bottles are no longer valid", log: tplogDebug, type: .default)
+            self.onQueueRemoveEscrowCache()
         }
 
         try changes.differences.forEach { peerDifference in
             if let operation = peerDifference.operation {
                 switch operation {
-                case .add(let peer):
-                    try self.addOrUpdate(peer: peer)
-
-                case .update(let peer):
+                case .add(let peer), .update(let peer):
                     try self.addOrUpdate(peer: peer)
                     // Update containerMO ego data if it has changed.
                     if peer.peerID == self.containerMO.egoPeerID {
@@ -3939,12 +4154,25 @@ class Container: NSObject {
             peerRequest.predicate = NSPredicate(format: "container == %@", self.containerMO)
             try self.moc.execute(NSBatchDeleteRequest(fetchRequest: peerRequest))
 
-            let bottleRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Bottle")
-            bottleRequest.predicate = NSPredicate(format: "container == %@", self.containerMO)
-            try self.moc.execute(NSBatchDeleteRequest(fetchRequest: bottleRequest))
+            // If we have an ego peer ID, keep the bottle associated with it
+            if let peerID = self.containerMO.egoPeerID, let bottles = self.containerMO.bottles {
+                let nonPeerBottles = NSSet(array: bottles.filter {
+                    switch $0 {
+                    case let bottleMO as BottleMO:
+                        return bottleMO.peerID != peerID
+                    default:
+                        return false
+                    }
+                })
+                self.containerMO.removeFromBottles(nonPeerBottles as NSSet)
+            } else {
+                let bottleRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Bottle")
+                bottleRequest.predicate = NSPredicate(format: "container == %@", self.containerMO)
+                try self.moc.execute(NSBatchDeleteRequest(fetchRequest: bottleRequest))
+                self.containerMO.bottles = nil
+            }
 
             self.containerMO.peers = nil
-            self.containerMO.bottles = nil
             self.containerMO.changeToken = nil
             self.containerMO.moreChanges = false
 
@@ -3961,7 +4189,7 @@ class Container: NSObject {
     // Must be on moc queue to call this.
     private func addOrUpdate(signingKey: Data, encryptionKey: Data) {
         self.model.setRecoveryKeys(
-            TPRecoveryKeyPair(signingSPKI: signingKey, encryptionSPKI: encryptionKey))
+            TPRecoveryKeyPair(signingKeyData: signingKey, encryptionKeyData: encryptionKey))
 
         self.containerMO.recoveryKeySigningSPKI = signingKey
         self.containerMO.recoveryKeyEncryptionSPKI = encryptionKey
@@ -3989,7 +4217,9 @@ class Container: NSObject {
         } else {
             // Update:
             // The assertion here is that every peer registered in model is also present in containerMO
-            let peerMO = try self.fetchPeerMO(peerID: peer.peerID)!
+            guard let peerMO = try self.fetchPeerMO(peerID: peer.peerID) else {
+                throw ContainerError.peerRegisteredButNotStored(peer.peerID)
+            }
 
             if let stableInfo = peer.stableInfoAndSig.toStableInfo() {
                 try self.model.update(stableInfo, forPeerWithID: peer.peerID)
@@ -4010,10 +4240,12 @@ class Container: NSObject {
             peer.vouchers.forEach {
                 if let voucher = TPVoucher(infoWith: $0.voucher, sig: $0.sig) {
                     self.model.register(voucher)
-                    let voucherMO = VoucherMO(context: self.moc)
-                    voucherMO.voucherInfo = voucher.data
-                    voucherMO.voucherInfoSig = voucher.sig
-                    peerMO.addToVouchers(voucherMO)
+                    if peer.vouchers.filter({ $0.voucher == voucher.data && $0.sig == voucher.sig }).isEmpty {
+                        let voucherMO = VoucherMO(context: self.moc)
+                        voucherMO.voucherInfo = voucher.data
+                        voucherMO.voucherInfoSig = voucher.sig
+                        peerMO.addToVouchers(voucherMO)
+                    }
                 }
             }
         }
@@ -4041,7 +4273,7 @@ class Container: NSObject {
 
     // Must be on moc queue to call this.
     private func createNewStableInfoIfNeeded(stableChanges: StableChanges?,
-                                             egoPeerID: String,
+                                             permanentInfo: TPPeerPermanentInfo,
                                              existingStableInfo: TPPeerStableInfo?,
                                              dynamicInfo: TPPeerDynamicInfo,
                                              signingKeyPair: _SFECKeyPair) throws -> TPPeerStableInfo? {
@@ -4050,41 +4282,53 @@ class Container: NSObject {
         }
 
         let policyOfPeers = try? self.model.policy(forPeerIDs: dynamicInfo.includedPeerIDs,
-                                                   candidatePeerID: egoPeerID,
+                                                   candidatePeerID: permanentInfo.peerID,
                                                    candidateStableInfo: existingStableInfo)
 
         // Pick the best version of:
         //   1. The policy version asked for by the client
-        //   2. The max of our existing policyVersion, the highest policy used by our trusted peers, and the compile-time prevailing policy version
+        //   2. The policy override set on this object (tests only)
+        //   3. The max of our existing policyVersion, the highest policy used by our trusted peers, and the compile-time prevailing policy version
         let optimalPolicyVersionNumber = stableChanges?.policyVersion ??
-                        max(existingStableInfo?.bestPolicyVersion().versionNumber ?? prevailingPolicyVersion.versionNumber,
-                        policyOfPeers?.version.versionNumber ?? prevailingPolicyVersion.versionNumber,
-                        prevailingPolicyVersion.versionNumber)
+                self.policyVersionOverride?.versionNumber ??
+                max(existingStableInfo?.bestPolicyVersion().versionNumber ?? prevailingPolicyVersion.versionNumber,
+                    policyOfPeers?.version.versionNumber ?? prevailingPolicyVersion.versionNumber,
+                    prevailingPolicyVersion.versionNumber)
 
         // Determine which recovery key we'd like to be using, given our current idea of who to trust
         let optimalRecoveryKey = self.model.bestRecoveryKey(for: existingStableInfo, dynamicInfo: dynamicInfo)
 
+        let intendedSyncUserControllableViews = stableChanges?.setSyncUserControllableViews?.sanitizeForPlatform(permanentInfo: permanentInfo)
+
         if noChange(stableChanges?.deviceName, existingStableInfo?.deviceName) &&
             noChange(stableChanges?.serialNumber, existingStableInfo?.serialNumber) &&
             noChange(stableChanges?.osVersion, existingStableInfo?.osVersion) &&
             noChange(optimalPolicyVersionNumber, existingStableInfo?.bestPolicyVersion().versionNumber) &&
             noChange(stableChanges?.policySecrets, existingStableInfo?.policySecrets) &&
-            noChange(optimalRecoveryKey?.signingSPKI, existingStableInfo?.recoverySigningPublicKey) &&
-            noChange(optimalRecoveryKey?.encryptionSPKI, existingStableInfo?.recoveryEncryptionPublicKey) {
+            noChange(optimalRecoveryKey?.signingKeyData, existingStableInfo?.recoverySigningPublicKey) &&
+            noChange(optimalRecoveryKey?.encryptionKeyData, existingStableInfo?.recoveryEncryptionPublicKey) &&
+            noChange(intendedSyncUserControllableViews, existingStableInfo?.syncUserControllableViews) {
             return nil
         }
 
+        // If a test has asked a policy version before we froze this policy, then don't set a flexible version--it's trying to build a peer from before the policy was frozen
         let optimalPolicyVersion = try self.getPolicyDoc(optimalPolicyVersionNumber).version
+        let useFrozenPolicyVersion = optimalPolicyVersion.versionNumber >= frozenPolicyVersion.versionNumber
+
+        if let intendedSyncUserControllableViews = intendedSyncUserControllableViews {
+            os_log("Intending to set user-controllable views to %{public}@", log: tplogTrace, type: .info, TPPBPeerStableInfo_UserControllableViewStatusAsString(intendedSyncUserControllableViews))
+        }
 
-        return try self.model.createStableInfo(withFrozenPolicyVersion: frozenPolicyVersion,
-                                               flexiblePolicyVersion: optimalPolicyVersion,
+        return try self.model.createStableInfo(withFrozenPolicyVersion: useFrozenPolicyVersion ? frozenPolicyVersion : optimalPolicyVersion,
+                                               flexiblePolicyVersion: useFrozenPolicyVersion ? optimalPolicyVersion : nil,
                                                policySecrets: stableChanges?.policySecrets ?? existingStableInfo?.policySecrets,
+                                               syncUserControllableViews: intendedSyncUserControllableViews ?? existingStableInfo?.syncUserControllableViews ?? .UNKNOWN,
                                                deviceName: stableChanges?.deviceName ?? existingStableInfo?.deviceName ?? "",
                                                serialNumber: stableChanges?.serialNumber ?? existingStableInfo?.serialNumber ?? "",
                                                osVersion: stableChanges?.osVersion ?? existingStableInfo?.osVersion ?? "",
                                                signing: signingKeyPair,
-                                               recoverySigningPubKey: optimalRecoveryKey?.signingSPKI,
-                                               recoveryEncryptionPubKey: optimalRecoveryKey?.encryptionSPKI)
+                                               recoverySigningPubKey: optimalRecoveryKey?.signingKeyData,
+                                               recoveryEncryptionPubKey: optimalRecoveryKey?.encryptionKeyData)
     }
 
     private func assembleBottle(egoPeerID: String) throws -> Bottle {
@@ -4097,7 +4341,9 @@ class Container: NSObject {
         if let count = bottleMOs?.count {
             if count > 1 {
                 throw ContainerError.tooManyBottlesForPeer
+                // swiftlint:disable empty_count
             } else if count == 0 {
+                // swiftlint:enable empty_count
                 throw ContainerError.noBottleForPeer
             }
         } else {
@@ -4160,8 +4406,7 @@ class Container: NSObject {
         }
 
         self.moc.performAndWait {
-            self.cuttlefish.reportHealth(updatedRequest) { response, error in
-                os_log("reportHealth(%{public}@): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: request))", "\(String(describing: response))", "\(String(describing: error))")
+            self.cuttlefish.reportHealth(updatedRequest) { _, error in
                 guard error == nil else {
                     reply(error)
                     return
@@ -4180,8 +4425,7 @@ class Container: NSObject {
         }
 
         self.moc.performAndWait {
-            self.cuttlefish.pushHealthInquiry(PushHealthInquiryRequest()) { response, error in
-                os_log("pushHealthInquiry(): %{public}@, error: %{public}@", log: tplogDebug, "\(String(describing: response))", "\(String(describing: error))")
+            self.cuttlefish.pushHealthInquiry(PushHealthInquiryRequest()) { _, error in
                 guard error == nil else {
                     reply(error)
                     return
index 73a8fdfa89491dbddc609a33a5f16c1cb6bac01a..7f6e03c5605f31630bde162b0e9671694c3daffc 100644 (file)
@@ -47,7 +47,7 @@ func ~= (pattern: CKInternalErrorMatcher, value: Error?) -> Bool {
         return false
     }
     return error.domain == CKErrorDomain && error.code == pattern.code &&
-           underlyingError.domain == CKInternalErrorDomain && underlyingError.code == pattern.internalCode
+        underlyingError.domain == CKInternalErrorDomain && underlyingError.code == pattern.internalCode
 }
 
 struct CKErrorMatcher {
@@ -83,7 +83,7 @@ public class RetryingInvocable: CloudKitCode.Invocable {
         self.underlyingInvocable = retry
     }
 
-   public class func retryableError(error: Error?) -> Bool {
+    public class func retryableError(error: Error?) -> Bool {
         switch error {
         case NSURLErrorMatcher(code: NSURLErrorTimedOut):
             return true
@@ -120,34 +120,33 @@ public class RetryingInvocable: CloudKitCode.Invocable {
         deadline: Date,
         minimumDelay: TimeInterval,
         completion: @escaping (ResponseType?, Error?) -> Void) {
-
         self.underlyingInvocable.invoke(function: function,
                                         request: request) { (response: ResponseType?, error: Error?) in
-            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,
-                           function,
-                           "\(String(describing: error))",
-                           "\(String(describing: now))",
-                           "\(String(describing: deadline))")
-                    self.invokeRetry(function: function,
-                                     request: request,
-                                     deadline: deadline,
-                                     minimumDelay: minimumDelay,
-                                     completion: completion)
-                    return
-                }
-            }
-            completion(response, 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,
+                                                           function,
+                                                           "\(String(describing: error))",
+                                                        "\(String(describing: now))",
+                                                        "\(String(describing: deadline))")
+                                                    self.invokeRetry(function: function,
+                                                                     request: request,
+                                                                     deadline: deadline,
+                                                                     minimumDelay: minimumDelay,
+                                                                     completion: completion)
+                                                    return
+                                                }
+                                            }
+                                            completion(response, error)
         }
     }
 }
@@ -172,10 +171,8 @@ public class MyCodeConnection: CloudKitCode.Invocable {
     public func invoke<RequestType: Message, ResponseType: Message>(
         function: String, request: RequestType,
         completion: @escaping (ResponseType?, Error?) -> Void) {
-
         // Hack to fool CloudKit, real solution is tracked in <rdar://problem/49086080>
         self.queue.async {
-
             let operation = CodeOperation<RequestType, ResponseType>(
                 service: self.serviceName,
                 functionName: function,
@@ -213,8 +210,7 @@ public class MyCodeConnection: CloudKitCode.Invocable {
             operation.configuration.discretionaryNetworkBehavior = .nonDiscretionary
             operation.configuration.automaticallyRetryNetworkFailures = false
             operation.configuration.isCloudKitSupportOperation = true
-
-            operation.configuration.sourceApplicationBundleIdentifier = CuttlefishPushTopicBundleIdentifier
+            operation.configuration.setApplicationBundleIdentifierOverride(CuttlefishPushTopicBundleIdentifier)
 
             let database = self.container.database(with: self.databaseScope)
 
@@ -234,7 +230,7 @@ class CKCodeCuttlefishInvocableCreator: ContainerNameToCuttlefishInvocable {
 
         // Cuttlefish is using its own push topic.
         // To register for this push topic, we need to issue CK operations with a specific bundle identifier
-        ckContainer.sourceApplicationBundleIdentifier = CuttlefishPushTopicBundleIdentifier
+        ckContainer.options.setApplicationBundleIdentifierOverride(CuttlefishPushTopicBundleIdentifier)
 
         let ckDatabase = ckContainer.privateCloudDatabase
         return MyCodeConnection(service: "Cuttlefish", container: ckContainer,
@@ -262,7 +258,6 @@ class ContainerMap {
             if let container = self.containers[name] {
                 return container
             } else {
-
                 // Set up Core Data stack
                 let persistentStoreURL = ContainerMap.urlForPersistentStore(name: name)
                 let description = NSPersistentStoreDescription(url: persistentStoreURL)
@@ -291,4 +286,12 @@ class ContainerMap {
             self.containers.removeAll()
         }
     }
+
+    func deleteAllPersistentStores() throws {
+        try queue.sync {
+            try self.containers.forEach {
+                try $0.value.deletePersistentStore()
+            }
+        }
+    }
 }
index ff281daed11a79da4c14a237d20193028d37854f..e9908f5be95a8e688395798df7bce6931ea80b9e 100644 (file)
@@ -2,80 +2,105 @@ import CoreData
 import Foundation
 
 extension Container {
+    func onMOCQueueFindBottle(bottleID: String) throws -> (BottleMO) {
+        guard let containerBottles = self.containerMO.bottles as? Set<BottleMO> else {
+            throw ContainerError.noBottlesPresent
+        }
+
+        let bottles = containerBottles.filter { $0.bottleID == bottleID }
+
+        guard let bottle = bottles.first else {
+            throw ContainerError.noBottlesForEscrowRecordID
+        }
+
+        return bottle
+    }
+
     func preflightVouchWithBottle(bottleID: String,
-                                  reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                                  reply: @escaping (String?, TPSyncingPolicy?, Bool, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, Set<String>?, TPPolicy?, Error?) -> Void = {
+        let reply: (String?, TPSyncingPolicy?, Bool, Error?) -> Void = {
             os_log("preflightVouchWithBottle complete: %{public}@",
                    log: tplogTrace, type: .info, traceError($3))
             self.semaphore.signal()
             reply($0, $1, $2, $3)
         }
 
-        self.fetchAndPersistChangesIfNeeded { fetchError in
-            guard fetchError == nil else {
-                os_log("preflightVouchWithBottle unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
-                reply(nil, nil, nil, fetchError)
-                return
-            }
+        self.moc.performAndWait {
+            do {
+                let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
+                reply(peerID, syncingPolicy, false, nil)
+            } catch {
+                os_log("preflightVouchWithBottle failed; forcing refetch and retrying: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
 
-            // Ensure we have all policy versions claimed by peers, including our sponsor
-            let allPolicyVersions = self.model.allPolicyVersions()
-            self.fetchPolicyDocumentsWithSemaphore(versions: allPolicyVersions) { _, fetchPolicyDocumentsError in
-                guard fetchPolicyDocumentsError == nil else {
-                    os_log("preflightVouchWithBottle unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
-                    reply(nil, nil, nil, fetchPolicyDocumentsError)
-                    return
-                }
-
-                self.moc.performAndWait {
-                    guard let egoPeerID = self.containerMO.egoPeerID,
-                        let egoPermData = self.containerMO.egoPeerPermanentInfo,
-                        let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
-                            os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
-                            reply(nil, nil, nil, ContainerError.noPreparedIdentity)
-                            return
-                    }
-
-                    let keyFactory = TPECPublicKeyFactory()
-                    guard let egoPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-                        os_log("fetchCurrentPolicy failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
-                        reply(nil, nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                self.fetchAndPersistChanges { fetchError in
+                    guard fetchError == nil else {
+                        os_log("preflightVouchWithBottle unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
+                        reply(nil, nil, true, fetchError)
                         return
                     }
 
-                    self.onqueueFindBottle(bottleID: bottleID) { bottleMO, error in
-                        guard let bottleMO = bottleMO else {
-                            os_log("preflightVouchWithBottle found no bottle: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
-                            reply(nil, nil, nil, error)
-                            return
-                        }
-
-                        guard let sponsorPeer = self.model.peer(withID: bottleMO.peerID ?? "") else {
-                            os_log("preflightVouchWithBottle found no peer to match bottle", log: tplogDebug, type: .default)
-                            reply(nil, nil, nil, ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given"))
-                            return
-                        }
-
-                        guard let sponsorPeerStableInfo = sponsorPeer.stableInfo else {
-                            os_log("preflightVouchWithBottle sponsor peer has no stable info", log: tplogDebug, type: .default)
-                            reply(nil, nil, nil, ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given"))
+                    // Ensure we have all policy versions claimed by peers, including our sponsor
+                    let allPolicyVersions = self.model.allPolicyVersions()
+                    self.fetchPolicyDocumentsWithSemaphore(versions: allPolicyVersions) { _, fetchPolicyDocumentsError in
+                        guard fetchPolicyDocumentsError == nil else {
+                            os_log("preflightVouchWithBottle unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
+                            reply(nil, nil, true, fetchPolicyDocumentsError)
                             return
                         }
 
-                        do {
-                            // We need to extract the syncing policy that the remote peer would have used (if they were the type of device that we are)
-                            // So, figure out their policy version...
-                            let (views, policy) = try self.policyAndViewsFor(permanentInfo: egoPermanentInfo, stableInfo: sponsorPeerStableInfo)
+                        self.fetchViableBottlesWithSemaphore { _, _, fetchBottlesError in
+                            guard fetchBottlesError == nil else {
+                                os_log("preflightVouchWithBottle unable to fetch viable bottles: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
+                                reply(nil, nil, true, fetchBottlesError)
+                                return
+                            }
 
-                            reply(bottleMO.peerID, views, policy, nil)
-                        } catch {
-                            os_log("preflightVouchWithBottle failed to fetch policy: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
-                            reply(nil, nil, nil, error)
+                            // and try again:
+                            self.moc.performAndWait {
+                                do {
+                                    let (_, peerID, syncingPolicy) = try self.onMOCQueuePerformPreflight(bottleID: bottleID)
+                                    reply(peerID, syncingPolicy, true, nil)
+                                } catch {
+                                    os_log("preflightVouchWithBottle failed after refetches; failing: %{public}@", log: tplogDebug, type: .default, (error as CVarArg?) ?? "")
+                                    reply(nil, nil, true, error)
+                                }
+                            }
                         }
                     }
                 }
             }
         }
     }
+
+    func onMOCQueuePerformPreflight(bottleID: String) throws -> (BottleMO, String, TPSyncingPolicy) {
+        guard let egoPeerID = self.containerMO.egoPeerID,
+              let egoPermData = self.containerMO.egoPeerPermanentInfo,
+              let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
+            os_log("fetchCurrentPolicy failed to find ego peer information", log: tplogDebug, type: .error)
+            throw ContainerError.noPreparedIdentity
+        }
+
+        let keyFactory = TPECPublicKeyFactory()
+        guard let egoPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
+            os_log("fetchCurrentPolicy failed to create TPPeerPermanentInfo", log: tplogDebug, type: .error)
+            throw ContainerError.invalidPermanentInfoOrSig
+        }
+
+        let bottleMO = try self.onMOCQueueFindBottle(bottleID: bottleID)
+
+        guard let sponsorPeer = self.model.peer(withID: bottleMO.peerID ?? "") else {
+            os_log("preflightVouchWithBottle found no peer to match bottle", log: tplogDebug, type: .default)
+            throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
+        }
+
+        guard let sponsorPeerStableInfo = sponsorPeer.stableInfo else {
+            os_log("preflightVouchWithBottle sponsor peer has no stable info", log: tplogDebug, type: .default)
+            throw ContainerError.sponsorNotRegistered(bottleMO.peerID ?? "no peer ID given")
+        }
+
+        // We need to extract the syncing policy that the remote peer would have used (if they were the type of device that we are)
+        let policy = try self.syncingPolicyFor(modelID: egoPermanentInfo.modelID, stableInfo: sponsorPeerStableInfo)
+        return (bottleMO, sponsorPeer.peerID, policy)
+    }
 }
diff --git a/keychain/TrustedPeersHelper/Container_EscrowRecords.swift b/keychain/TrustedPeersHelper/Container_EscrowRecords.swift
new file mode 100644 (file)
index 0000000..89bdc20
--- /dev/null
@@ -0,0 +1,202 @@
+import CoreData
+import Foundation
+
+extension Container {
+
+    func onqueueCachedRecordsContainEgoPeerBottle(cachedRecords: [OTEscrowRecord]) -> Bool {
+        guard let egoPeerID = self.containerMO.egoPeerID else {
+            os_log("onqueueCachedRecordsContainEgoPeerBottle: No identity.", log: tplogDebug, type: .default)
+            return false
+        }
+        guard let bottles: Set<BottleMO> = self.containerMO.bottles as? Set<BottleMO>  else {
+            os_log("onqueueCachedRecordsContainEgoPeerBottle: No Bottles.", log: tplogDebug, type: .default)
+            return false
+        }
+        var matchesCached: Bool = false
+        for bottle in bottles {
+            guard let bottleID: String = bottle.bottleID else {
+                continue
+            }
+            if bottle.peerID == egoPeerID && (cachedRecords.compactMap { $0.escrowInformationMetadata.bottleId }).contains(bottleID) {
+                matchesCached = true
+                break
+            }
+        }
+        return matchesCached
+    }
+
+    func escrowRecordMOToEscrowRecords(record: EscrowRecordMO, viability: Viability) -> OTEscrowRecord? {
+        let escrowRecord = OTEscrowRecord()
+        let escrowRecordMetadata = OTEscrowRecordMetadata()
+        let clientMetadata = OTEscrowRecordMetadataClientMetadata()
+
+        if let e = escrowRecord {
+            if let creationDate = record.creationDate {
+                e.creationDate = UInt64(creationDate.timeIntervalSince1970)
+            }
+            e.label = record.label ?? ""
+            e.remainingAttempts = UInt64(record.remainingAttempts)
+            e.silentAttemptAllowed = UInt64(record.silentAttemptAllowed)
+            e.recordStatus = record.recordStatus == 0 ? .RECORD_STATUS_VALID : .RECORD_STATUS_INVALID
+
+            switch viability {
+            case .full:
+                e.recordViability = .RECORD_VIABILITY_FULLY_VIABLE
+            case .partial:
+                e.recordViability = .RECORD_VIABILITY_PARTIALLY_VIABLE
+            case .none:
+                e.recordViability = .RECORD_VIABILITY_LEGACY
+            }
+
+            switch record.sosViability {
+            case 0:
+                e.viabilityStatus = .SOS_VIABLE_UNKNOWN
+            case 1:
+                e.viabilityStatus = .SOS_VIABLE
+            case 2:
+                e.viabilityStatus = .SOS_NOT_VIABLE
+            default:
+                e.viabilityStatus = .SOS_VIABLE_UNKNOWN
+            }
+
+            if let metadata = escrowRecordMetadata {
+                if let m = record.escrowMetadata {
+                    metadata.backupKeybagDigest = m.backupKeybagDigest ?? Data()
+                    if let timestamp = m.secureBackupTimestamp {
+                        metadata.secureBackupTimestamp = UInt64(timestamp.timeIntervalSince1970)
+                    }
+                    metadata.secureBackupUsesMultipleIcscs = UInt64(m.secureBackupUsesMultipleiCSCS)
+                    metadata.bottleId = m.bottleID ?? ""
+                    metadata.escrowedSpki = m.escrowedSPKI ?? Data()
+                    metadata.peerInfo = m.peerInfo ?? Data()
+                    metadata.serial = m.serial ?? ""
+                    if let cmToFill = clientMetadata {
+                        if let cm = m.clientMetadata {
+                            cmToFill.deviceMid = cm.deviceMid ?? ""
+                            cmToFill.deviceColor = cm.deviceColor ?? ""
+                            cmToFill.deviceModel = cm.deviceModel ?? ""
+                            cmToFill.deviceName = cm.deviceName ?? ""
+                            cmToFill.devicePlatform = UInt64(cm.devicePlatform)
+                            cmToFill.deviceModelClass = cm.deviceModelClass ?? ""
+                            cmToFill.deviceModelVersion = cm.deviceModelVersion ?? ""
+                            cmToFill.deviceEnclosureColor = cm.deviceEnclosureColor ?? ""
+                            if let timestamp = cm.secureBackupMetadataTimestamp {
+                                cmToFill.secureBackupMetadataTimestamp = UInt64(timestamp.timeIntervalSince1970)
+                            }
+                            cmToFill.secureBackupUsesComplexPassphrase = UInt64(cm.secureBackupUsesComplexPassphrase)
+                            cmToFill.secureBackupUsesNumericPassphrase = UInt64(cm.secureBackupUsesNumericPassphrase)
+                            cmToFill.secureBackupNumericPassphraseLength = UInt64(cm.secureBackupNumericPassphraseLength)
+                        }
+                    }
+                    metadata.clientMetadata = clientMetadata
+                }
+                e.escrowInformationMetadata = metadata
+            }
+        }
+
+        return escrowRecord
+    }
+
+    func setEscrowRecord(record: EscrowInformation, viability: Viability) {
+        let escrowRecordMO = EscrowRecordMO(context: self.moc)
+        escrowRecordMO.label = record.label
+        escrowRecordMO.creationDate = record.creationDate.date
+        escrowRecordMO.remainingAttempts = Int64(record.remainingAttempts)
+        escrowRecordMO.silentAttemptAllowed = Int64(record.silentAttemptAllowed)
+        escrowRecordMO.recordStatus = Int64(record.recordStatus.rawValue)
+        escrowRecordMO.sosViability = Int64(record.viabilityStatus.rawValue)
+        
+        let escrowRecordMetadataMO = EscrowMetadataMO(context: self.moc)
+        escrowRecordMetadataMO.backupKeybagDigest = record.escrowInformationMetadata.backupKeybagDigest
+        escrowRecordMetadataMO.secureBackupUsesMultipleiCSCS = Int64(record.escrowInformationMetadata.secureBackupUsesMultipleIcscs)
+        escrowRecordMetadataMO.bottleID = record.escrowInformationMetadata.bottleID
+        escrowRecordMetadataMO.secureBackupTimestamp = record.escrowInformationMetadata.secureBackupTimestamp.date
+        escrowRecordMetadataMO.escrowedSPKI = record.escrowInformationMetadata.escrowedSpki
+        escrowRecordMetadataMO.peerInfo = record.escrowInformationMetadata.peerInfo
+        escrowRecordMetadataMO.serial = record.escrowInformationMetadata.serial
+        escrowRecordMO.escrowMetadata = escrowRecordMetadataMO
+
+        let escrowRecordClientMetadataMO = EscrowClientMetadataMO(context: self.moc)
+        escrowRecordClientMetadataMO.secureBackupMetadataTimestamp = record.escrowInformationMetadata.clientMetadata.secureBackupMetadataTimestamp.date
+        escrowRecordClientMetadataMO.secureBackupNumericPassphraseLength = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupNumericPassphraseLength)
+        escrowRecordClientMetadataMO.secureBackupUsesComplexPassphrase = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupUsesComplexPassphrase)
+        escrowRecordClientMetadataMO.secureBackupUsesNumericPassphrase = Int64(record.escrowInformationMetadata.clientMetadata.secureBackupUsesNumericPassphrase)
+        escrowRecordClientMetadataMO.deviceColor = record.escrowInformationMetadata.clientMetadata.deviceColor
+        escrowRecordClientMetadataMO.deviceEnclosureColor = record.escrowInformationMetadata.clientMetadata.deviceEnclosureColor
+        escrowRecordClientMetadataMO.deviceMid = record.escrowInformationMetadata.clientMetadata.deviceMid
+        escrowRecordClientMetadataMO.deviceModel = record.escrowInformationMetadata.clientMetadata.deviceModel
+        escrowRecordClientMetadataMO.deviceModelClass = record.escrowInformationMetadata.clientMetadata.deviceModelClass
+        escrowRecordClientMetadataMO.deviceModelVersion = record.escrowInformationMetadata.clientMetadata.deviceModelVersion
+        escrowRecordClientMetadataMO.deviceName = record.escrowInformationMetadata.clientMetadata.deviceName
+        escrowRecordClientMetadataMO.devicePlatform = Int64(record.escrowInformationMetadata.clientMetadata.devicePlatform)
+
+        escrowRecordMetadataMO.clientMetadata = escrowRecordClientMetadataMO
+
+        os_log("setEscrowRecord saving new escrow record: %@", log: tplogDebug, type: .default, escrowRecordMO)
+        switch viability {
+        case .full:
+            self.containerMO.addToFullyViableEscrowRecords(escrowRecordMO)
+            break
+        case .partial:
+            self.containerMO.addToPartiallyViableEscrowRecords(escrowRecordMO)
+            break
+        case .none:
+            self.containerMO.addToLegacyEscrowRecords(escrowRecordMO)
+            break
+        }
+    }
+
+    func onqueueCachedBottlesFromEscrowRecords() -> (TPCachedViableBottles) {
+        var viableRecords: [String] = []
+        var partiallyViableRecords: [String] = []
+
+        if let fullyViableEscrowRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
+            viableRecords = fullyViableEscrowRecords.compactMap { $0.escrowMetadata?.bottleID }
+        }
+        if let partiallyViableEscrowRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
+            partiallyViableRecords = partiallyViableEscrowRecords.compactMap { $0.escrowMetadata?.bottleID }
+        }
+        return TPCachedViableBottles(viableBottles: viableRecords, partialBottles: partiallyViableRecords)
+    }
+
+    func onqueueCachedEscrowRecords() -> ([OTEscrowRecord]) {
+        var escrowRecords: [OTEscrowRecord] = []
+
+        if let fullyViableEscrowRecords = self.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO> {
+            for record in fullyViableEscrowRecords {
+                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .full)
+                if let r = convertedRecord {
+                    escrowRecords.append(r)
+                }
+            }
+        }
+        if let partiallyViableEscrowRecords = self.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO> {
+            for record in partiallyViableEscrowRecords {
+                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .partial)
+                if let r = convertedRecord {
+                    escrowRecords.append(r)
+                }
+            }
+        }
+        if let legacyEscrowRecords = self.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO> {
+            for record in legacyEscrowRecords {
+                let convertedRecord = escrowRecordMOToEscrowRecords(record: record, viability: .none)
+                if let r = convertedRecord {
+                    escrowRecords.append(r)
+                }
+            }
+        }
+        return escrowRecords
+    }
+
+    func fetchEscrowRecords(forceFetch: Bool, reply: @escaping ([Data]?, Error?) -> Void) {
+        self.semaphore.wait()
+        let reply: ([Data]?, Error?) -> Void = {
+            os_log("fetchEscrowRecords complete: %@", log: tplogTrace, type: .info, traceError($1))
+            self.semaphore.signal()
+            reply($0, $1)
+        }
+
+        self.fetchEscrowRecordsWithSemaphore(forceFetch: forceFetch, reply: reply)
+    }
+}
index 19e76cbb217145d3b79545ab6c71323129a6e11e..b684c77ea4df5b989075a19b15456928de1f4593 100644 (file)
@@ -57,7 +57,7 @@ extension Container {
 
         // Once we run this upgrade, we will set the allowed bool to false, since it's unused.
         // Therefore, if we have a single record with "allowed" set, we haven't run the upgrade.
-        let runUpgrade = !knownMachineMOs.filter { $0.allowed }.isEmpty
+        let runUpgrade = knownMachineMOs.contains { $0.allowed }
         if runUpgrade {
             knownMachineMOs.forEach { mo in
                 if mo.allowed {
@@ -132,7 +132,6 @@ extension Container {
                                 machine.modified = Date()
                                 os_log("Newly distrusted machine ID: %{public}@", log: tplogDebug, type: .default, String(describing: machine.machineID))
                                 differences = true
-
                             } else {
                                 if machine.modifiedInPast(hours: cutoffHours) {
                                     os_log("Allowed-but-unseen machine ID isn't on full list, last modified %{public}@, ignoring: %{public}@", log: tplogDebug, type: .default, machine.modifiedDate(), String(describing: machine.machineID))
@@ -143,7 +142,6 @@ extension Container {
                                     differences = true
                                 }
                             }
-
                         } else if machine.status == TPMachineIDStatus.unknown.rawValue {
                             if machine.modifiedInPast(hours: cutoffHours) {
                                 os_log("Unknown machine ID last modified %{public}@; leaving unknown: %{public}@", log: tplogDebug, type: .default, machine.modifiedDate(), String(describing: machine.machineID))
@@ -235,7 +233,6 @@ extension Container {
                                 os_log("Continue to trust machine ID: %{public}@", log: tplogDebug, type: .default, String(describing: machine.machineID))
                             }
                         }
-
                     } else {
                         let machine = MachineMO(context: self.moc)
                         machine.machineID = machineID
@@ -285,7 +282,6 @@ extension Container {
                                 os_log("Now suspicious of machine ID: %{public}@", log: tplogDebug, type: .default, String(describing: machine.machineID))
                             }
                         }
-
                     } else {
                         let machine = MachineMO(context: self.moc)
                         machine.machineID = machineID
diff --git a/keychain/TrustedPeersHelper/Container_Peers.swift b/keychain/TrustedPeersHelper/Container_Peers.swift
new file mode 100644 (file)
index 0000000..4c9903e
--- /dev/null
@@ -0,0 +1,42 @@
+import CloudKitCode
+import CloudKitCodeProtobuf
+import CoreData
+import Foundation
+import os
+import Security
+import SecurityFoundation
+
+extension Container {
+    internal static func removingDuplicates(vouchers: Set<VoucherMO>) -> Set<VoucherMO> {
+        var unique: Set<VoucherMO> = Set()
+
+        for voucher in vouchers {
+            if !unique.contains(voucher) {
+                unique.insert(voucher)
+            }
+        }
+        return unique
+    }
+
+    internal static func onqueueRemoveDuplicateVouchersPerPeer(container: ContainerMO, moc: NSManagedObjectContext) {
+        var peersWithUniqueSetOfVouchers: Set<PeerMO> = Set()
+        let peers = container.peers as? Set<PeerMO> ?? Set()
+        for peer in peers {
+            let vouchers = peer.vouchers as? Set<VoucherMO> ?? Set()
+            let uniqueSet = Container.removingDuplicates(vouchers: vouchers)
+            for voucher in vouchers {
+                peer.removeFromVouchers(voucher)
+            }
+            for voucher in uniqueSet {
+                peer.addToVouchers(voucher)
+            }
+            peersWithUniqueSetOfVouchers.insert(peer)
+        }
+        for peer in peers {
+            container.removeFromPeers(peer)
+        }
+        for peer in peersWithUniqueSetOfVouchers {
+            container.addToPeers(peer)
+        }
+    }
+}
index 165764a9083025810f296be4256f34b2e0746905..0d7fe8280deb5df9ab1bfee72da09186bcb69dd6 100644 (file)
@@ -4,19 +4,19 @@ import Foundation
 extension Container {
     func preflightVouchWithRecoveryKey(recoveryKey: String,
                                        salt: String,
-                                       reply: @escaping (String?, Set<String>?, TPPolicy?, Error?) -> Void) {
+                                       reply: @escaping (String?, TPSyncingPolicy?, Error?) -> Void) {
         self.semaphore.wait()
-        let reply: (String?, Set<String>?, TPPolicy?, Error?) -> Void = {
+        let reply: (String?, TPSyncingPolicy?, Error?) -> Void = {
             os_log("preflightRecoveryKey complete: %{public}@",
-                   log: tplogTrace, type: .info, traceError($3))
+                   log: tplogTrace, type: .info, traceError($2))
             self.semaphore.signal()
-            reply($0, $1, $2, $3)
+            reply($0, $1, $2)
         }
 
         self.fetchAndPersistChangesIfNeeded { fetchError in
             guard fetchError == nil else {
                 os_log("preflightRecoveryKey unable to fetch current peers: %{public}@", log: tplogDebug, type: .default, (fetchError as CVarArg?) ?? "")
-                reply(nil, nil, nil, fetchError)
+                reply(nil, nil, fetchError)
                 return
             }
 
@@ -24,7 +24,7 @@ extension Container {
             self.fetchPolicyDocumentsWithSemaphore(versions: self.model.allPolicyVersions()) { _, fetchPolicyDocumentsError in
                 guard fetchPolicyDocumentsError == nil else {
                     os_log("preflightRecoveryKey unable to fetch policy documents: %{public}@", log: tplogDebug, type: .default, (fetchPolicyDocumentsError as CVarArg?) ?? "no error")
-                    reply(nil, nil, nil, fetchPolicyDocumentsError)
+                    reply(nil, nil, fetchPolicyDocumentsError)
                     return
                 }
 
@@ -32,14 +32,14 @@ extension Container {
                     guard let egoPeerID = self.containerMO.egoPeerID,
                         let egoPermData = self.containerMO.egoPeerPermanentInfo,
                         let egoPermSig = self.containerMO.egoPeerPermanentInfoSig else {
-                        os_log("preflightRecoveryKey: no ego peer ID", log: tplogDebug, type: .default)
-                        reply(nil, nil, nil, ContainerError.noPreparedIdentity)
-                        return
+                            os_log("preflightRecoveryKey: no ego peer ID", log: tplogDebug, type: .default)
+                            reply(nil, nil, ContainerError.noPreparedIdentity)
+                            return
                     }
 
                     let keyFactory = TPECPublicKeyFactory()
                     guard let selfPermanentInfo = TPPeerPermanentInfo(peerID: egoPeerID, data: egoPermData, sig: egoPermSig, keyFactory: keyFactory) else {
-                        reply(nil, nil, nil, ContainerError.invalidPermanentInfoOrSig)
+                        reply(nil, nil, ContainerError.invalidPermanentInfoOrSig)
                         return
                     }
 
@@ -48,27 +48,27 @@ extension Container {
                         recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
                     } catch {
                         os_log("preflightRecoveryKey: failed to create recovery keys: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                        reply(nil, nil, nil, ContainerError.failedToCreateRecoveryKey)
+                        reply(nil, nil, ContainerError.failedToCreateRecoveryKey)
                         return
                     }
 
                     // Dear model: if i were to use this recovery key, what peers would I end up using?
                     guard self.model.isRecoveryKeyEnrolled() else {
                         os_log("preflightRecoveryKey: recovery Key is not enrolled", log: tplogDebug, type: .default)
-                        reply(nil, nil, nil, ContainerError.recoveryKeysNotEnrolled)
+                        reply(nil, nil, ContainerError.recoveryKeysNotEnrolled)
                         return
                     }
 
-                    guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingSPKI: recoveryKeys.peerKeys.signingKey.publicKey.keyData,
-                                                                                                        encryptionSPKI: recoveryKeys.peerKeys.encryptionKey.publicKey.keyData)) else {
+                    guard let sponsorPeerID = self.model.peerIDThatTrustsRecoveryKeys(TPRecoveryKeyPair(signingKeyData: recoveryKeys.peerKeys.signingKey.publicKey.keyData,
+                                                                                                        encryptionKeyData: recoveryKeys.peerKeys.encryptionKey.publicKey.keyData)) else {
                                                                                                             os_log("preflightRecoveryKey Untrusted recovery key set", log: tplogDebug, type: .default)
-                                                                                                            reply(nil, nil, nil, ContainerError.untrustedRecoveryKeys)
+                                                                                                            reply(nil, nil, ContainerError.untrustedRecoveryKeys)
                                                                                                             return
                     }
 
                     guard let sponsor = self.model.peer(withID: sponsorPeerID) else {
                         os_log("preflightRecoveryKey Failed to find peer with ID", log: tplogDebug, type: .default)
-                        reply(nil, nil, nil, ContainerError.sponsorNotRegistered(sponsorPeerID))
+                        reply(nil, nil, ContainerError.sponsorNotRegistered(sponsorPeerID))
                         return
                     }
 
@@ -76,12 +76,13 @@ extension Container {
                         let bestPolicy = try self.model.policy(forPeerIDs: sponsor.dynamicInfo?.includedPeerIDs ?? [sponsor.peerID],
                                                                candidatePeerID: egoPeerID,
                                                                candidateStableInfo: sponsor.stableInfo)
+                        let syncingPolicy = try bestPolicy.syncingPolicy(forModel: selfPermanentInfo.modelID,
+                                                                         syncUserControllableViews: sponsor.stableInfo?.syncUserControllableViews ?? .UNKNOWN)
 
-                        let views = try bestPolicy.views(forModel: selfPermanentInfo.modelID)
-                        reply(recoveryKeys.peerKeys.peerID, views, bestPolicy, nil)
+                        reply(recoveryKeys.peerKeys.peerID, syncingPolicy, nil)
                     } catch {
                         os_log("preflightRecoveryKey: error fetching policy: %{public}@", log: tplogDebug, type: .default, error as CVarArg)
-                        reply(nil, nil, nil, error)
+                        reply(nil, nil, error)
                         return
                     }
                 }
diff --git a/keychain/TrustedPeersHelper/Container_UserSync.swift b/keychain/TrustedPeersHelper/Container_UserSync.swift
new file mode 100644 (file)
index 0000000..498f4a7
--- /dev/null
@@ -0,0 +1,41 @@
+import Foundation
+
+// Apple TVs and watches have no UI to enable or disable this status.
+// So, help them out by ignoring all efforts.
+extension TPPBPeerStableInfo_UserControllableViewStatus {
+    func sanitizeForPlatform(permanentInfo: TPPeerPermanentInfo) -> TPPBPeerStableInfo_UserControllableViewStatus {
+        // Unknown is the unknown for any platform
+        if self == .UNKNOWN {
+            return .UNKNOWN
+        }
+
+        if permanentInfo.modelID.hasPrefix("AppleTV") ||
+            permanentInfo.modelID.hasPrefix("AudioAccessory") {
+            // Apple TVs, and HomePods don't have UI to set this bit. So, they should always sync the
+            // user-controlled views to which they have access.
+            //
+            // Some watches don't have UI to set the bit, but some do.
+            //
+            // Note that we want this sanitization behavior to be baked into the local OS, which is what owns
+            // the UI software, and not in the Policy, which can change.
+            return .FOLLOWING
+        } else {
+            // All other platforms can choose their own fate
+            return self
+        }
+    }
+}
+
+extension StableChanges {
+    static func change(viewStatus: TPPBPeerStableInfo_UserControllableViewStatus?) -> StableChanges? {
+        if viewStatus == nil {
+            return nil
+        }
+        return StableChanges(deviceName: nil,
+                             serialNumber: nil,
+                             osVersion: nil,
+                             policyVersion: nil,
+                             policySecrets: nil,
+                             setSyncUserControllableViews: viewStatus)
+    }
+}
index 535ef221ec1397e70f8ee8792d114cef101a2219..8014ccbb4d8d5c5b19137be143e1ea0c99d29678 100644 (file)
@@ -29,7 +29,7 @@ class OctagonSelfPeerKeys: NSObject, CKKSSelfPeer {
         self.publicSigningKey = signingKey.publicKey as? _SFECPublicKey
 
         guard let encryptionVerificationKey = self.publicEncryptionKey,
-              let signingVerificationKey = self.publicSigningKey else {
+            let signingVerificationKey = self.publicSigningKey else {
                 throw OctagonSelfPeerKeysError.noPublicKeys
         }
 
index ce1c3eef9350c84414451148f8ac8009b4693fff..df6e00a9e82d9b316fa9bd8826b4659d5037e09b 100644 (file)
@@ -29,14 +29,13 @@ struct RawPolicy {
     let plaintextPolicy: TPPolicyDocument
 }
 
-let prevailingPolicyVersion = TPPolicyVersion(version: 6, hash: "SHA256:L2Px1aYyR1tgChe8dIyTBSmCHCWEFJirZ3ELMFXz2PY=")
+let prevailingPolicyVersion = TPPolicyVersion(version: 7, hash: "SHA256:dL8Qujqzprhp6FdH5GzNMtPlnZtLWMwfiiF7aykr8WU=")
 
 // Some peers don't know how to handle new policies when pairing. If we're pairing with one of those,
 // we must prepare our identity using this policy.
 let frozenPolicyVersion = TPPolicyVersion(version: 5, hash: "SHA256:O/ECQlWhvNlLmlDNh2+nal/yekUC87bXpV3k+6kznSo=")
 
 func builtInPolicyDocuments() -> [TPPolicyDocument] {
-
     // swiftlint:disable force_try
     // These bytes are generated by tppolicy
     let rawPolicies = [
@@ -64,6 +63,8 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                     ],
                                                    redactions: [:],
                                                    keyViewMapping: [],
+                                                   userControllableViewList: [],
+                                                   piggybackViews: [],
                                                    hashAlgo: .SHA256)
         ),
 
@@ -92,6 +93,8 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                     ],
                                                    redactions: [:],
                                                    keyViewMapping: [],
+                                                   userControllableViewList: [],
+                                                   piggybackViews: [],
                                                    hashAlgo: .SHA256)
         ),
 
@@ -208,6 +211,8 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                 TPPBPolicyKeyViewMapping(view: "Backstop",
                                                                          matchingRule: TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^com.apple.cfnetwork$")),
                                              ],
+                                             userControllableViewList: [],
+                                             piggybackViews: [],
                                              hashAlgo: .SHA256)
             ),
         RawPolicy(version: TPPolicyVersion(version: 4, hash: "SHA256:Tjdu5QrWGvKWMx7k3VWFrEWSsBDPZAwCql9ybDkvFs8="),
@@ -318,6 +323,8 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                         TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^WatchMigration$"),
                                                     ])),
                                              ],
+                                             userControllableViewList: [],
+                                             piggybackViews: [],
                                              hashAlgo: .SHA256)
             ),
 
@@ -435,6 +442,8 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                             TPPBPolicyKeyViewMapping(view: "Backstop", matchingRule:
                                                                 TPDictionaryMatchingRule.trueMatch()),
                     ],
+                    userControllableViewList: [],
+                    piggybackViews: [],
                                                          hashAlgo: .SHA256)
         ),
 
@@ -552,8 +561,135 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
                                                             TPPBPolicyKeyViewMapping(view: "Backstop", matchingRule:
                                                                 TPDictionaryMatchingRule.trueMatch()),
                     ],
+                    userControllableViewList: [],
+                    piggybackViews: [],
+                                                         hashAlgo: .SHA256)
+    ),
+        RawPolicy(version: TPPolicyVersion(version: 7, hash: "SHA256:dL8Qujqzprhp6FdH5GzNMtPlnZtLWMwfiiF7aykr8WU="),
+                  policyData: "CAcSDgoGaVBob25lEgRmdWxsEgwKBGlQYWQSBGZ1bGwSDAoEaVBvZBIEZnVsbBILCgNNYWMSBGZ1bGwSDAoEaU1hYxIEZnVsbBINCgdBcHBsZVRWEgJ0dhIOCgVXYXRjaBIFd2F0Y2gSFwoOQXVkaW9BY2Nlc3NvcnkSBWF1ZGlvGh4KBEhvbWUSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aJAoVUHJvdGVjdGVkQ2xvdWRTdG9yYWdlEgRmdWxsEgV3YXRjaBoYCglQYXNzd29yZHMSBGZ1bGwSBXdhdGNoGh8KEFNlY3VyZU9iamVjdFN5bmMSBGZ1bGwSBXdhdGNoGh4KBFdpRmkSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aGgoLQ3JlZGl0Q2FyZHMSBGZ1bGwSBXdhdGNoGhcKCEFwcGxlUGF5EgRmdWxsEgV3YXRjaBoVCgZIZWFsdGgSBGZ1bGwSBXdhdGNoGhkKCkF1dG9VbmxvY2sSBGZ1bGwSBXdhdGNoGi0KE0xpbWl0ZWRQZWVyc0FsbG93ZWQSBGZ1bGwSBXdhdGNoEgJ0dhIFYXVkaW8aHAoNRGV2aWNlUGFpcmluZxIEZnVsbBIFd2F0Y2gaFgoHTWFuYXRlZRIEZnVsbBIFd2F0Y2gaFQoGRW5ncmFtEgRmdWxsEgV3YXRjaBoXCghCYWNrc3RvcBIEZnVsbBIFd2F0Y2gaGwoMQXBwbGljYXRpb25zEgRmdWxsEgV3YXRjaCITCgRmdWxsEgRmdWxsEgV3YXRjaCIVCgJ0dhIEZnVsbBIFd2F0Y2gSAnR2IhQKBXdhdGNoEgRmdWxsEgV3YXRjaCIbCgVhdWRpbxIEZnVsbBIFd2F0Y2gSBWF1ZGlvMiIKFgAEIhICBHZ3aHQKCl5BcHBsZVBheSQSCEFwcGxlUGF5MiYKGAAEIhQCBHZ3aHQKDF5BdXRvVW5sb2NrJBIKQXV0b1VubG9jazIeChQABCIQAgR2d2h0CgheRW5ncmFtJBIGRW5ncmFtMh4KFAAEIhACBHZ3aHQKCF5IZWFsdGgkEgZIZWFsdGgyGgoSAAQiDgIEdndodAoGXkhvbWUkEgRIb21lMiAKFQAEIhECBHZ3aHQKCV5NYW5hdGVlJBIHTWFuYXRlZTI4CiEABCIdAgR2d2h0ChVeTGltaXRlZFBlZXJzQWxsb3dlZCQSE0xpbWl0ZWRQZWVyc0FsbG93ZWQyXQpQAAISHgAEIhoCBHZ3aHQKEl5Db250aW51aXR5VW5sb2NrJBIVAAQiEQIEdndodAoJXkhvbWVLaXQkEhUABCIRAgR2d2h0CgleQXBwbGVUViQSCU5vdFN5bmNlZDIrChsABCIXAgRhZ3JwCg9eWzAtOUEtWl17MTB9XC4SDEFwcGxpY2F0aW9uczLKAQq1AQACEjYAAQoTAAQiDwIFY2xhc3MKBl5nZW5wJAodAAQiGQIEYWdycAoRXmNvbVwuYXBwbGVcLnNiZCQSQAABChMABCIPAgVjbGFzcwoGXmtleXMkCicABCIjAgRhZ3JwChteY29tXC5hcHBsZVwuc2VjdXJpdHlcLnNvcyQSGQAEIhUCBHZ3aHQKDV5CYWNrdXBCYWdWMCQSHAAEIhgCBHZ3aHQKEF5pQ2xvdWRJZGVudGl0eSQSEFNlY3VyZU9iamVjdFN5bmMyYwpbAAISEgAEIg4CBHZ3aHQKBl5XaUZpJBJDAAEKEwAEIg8CBWNsYXNzCgZeZ2VucCQKEwAEIg8CBGFncnAKB15hcHBsZSQKFQAEIhECBHN2Y2UKCV5BaXJQb3J0JBIEV2lGaTKdAwqDAwACEhgABCIUAgR2d2h0CgxeUENTLUJhY2t1cCQSGgAEIhYCBHZ3aHQKDl5QQ1MtQ2xvdWRLaXQkEhgABCIUAgR2d2h0CgxeUENTLUVzY3JvdyQSFQAEIhECBHZ3aHQKCV5QQ1MtRkRFJBIaAAQiFgIEdndodAoOXlBDUy1GZWxkc3BhciQSGgAEIhYCBHZ3aHQKDl5QQ1MtTWFpbERyb3AkEhoABCIWAgR2d2h0Cg5eUENTLU1haWxkcm9wJBIbAAQiFwIEdndodAoPXlBDUy1NYXN0ZXJLZXkkEhcABCITAgR2d2h0CgteUENTLU5vdGVzJBIYAAQiFAIEdndodAoMXlBDUy1QaG90b3MkEhkABCIVAgR2d2h0Cg1eUENTLVNoYXJpbmckEh4ABCIaAgR2d2h0ChJeUENTLWlDbG91ZEJhY2t1cCQSHQAEIhkCBHZ3aHQKEV5QQ1MtaUNsb3VkRHJpdmUkEhoABCIWAgR2d2h0Cg5eUENTLWlNZXNzYWdlJBIVUHJvdGVjdGVkQ2xvdWRTdG9yYWdlMj0KLgAEIioCBGFncnAKIl5jb21cLmFwcGxlXC5zYWZhcmlcLmNyZWRpdC1jYXJkcyQSC0NyZWRpdENhcmRzMjAKIwAEIh8CBGFncnAKF15jb21cLmFwcGxlXC5jZm5ldHdvcmskEglQYXNzd29yZHMybQpcAAISHgAEIhoCBHZ3aHQKEl5BY2Nlc3NvcnlQYWlyaW5nJBIaAAQiFgIEdndodAoOXk5hbm9SZWdpc3RyeSQSHAAEIhgCBHZ3aHQKEF5XYXRjaE1pZ3JhdGlvbiQSDURldmljZVBhaXJpbmcyDgoCAAYSCEJhY2tzdG9w",
+                  plaintextPolicy: try! TPPolicyDocument(version: 7,
+                                                         modelToCategory: [
+                                                            ["prefix": "iPhone", "category": "full"],
+                                                            ["prefix": "iPad", "category": "full"],
+                                                            ["prefix": "iPod", "category": "full"],
+                                                            ["prefix": "Mac", "category": "full"],
+                                                            ["prefix": "iMac", "category": "full"],
+                                                            ["prefix": "AppleTV", "category": "tv"],
+                                                            ["prefix": "Watch", "category": "watch"],
+                                                            ["prefix": "AudioAccessory", "category": "audio"],
+                    ],
+                                                         categoriesByView: [
+                                                            "AutoUnlock": ["full", "watch"],
+                                                            "ApplePay": ["full", "watch"],
+                                                            "Backstop": ["full", "watch"],
+                                                            "Engram": ["full", "watch"],
+                                                            "Health": ["full", "watch"],
+                                                            "Home": ["full", "watch", "tv", "audio"],
+                                                            "LimitedPeersAllowed": ["full", "watch", "tv", "audio"],
+                                                            "Manatee": ["full", "watch"],
+                                                            "Applications": ["full", "watch"],
+                                                            "SecureObjectSync": ["full", "watch"],
+                                                            "WiFi": ["full", "watch", "tv", "audio"],
+                                                            "ProtectedCloudStorage": ["full", "watch"],
+                                                            "CreditCards": ["full", "watch"],
+                                                            "Passwords": ["full", "watch"],
+                                                            "DevicePairing": ["full", "watch"],
+                    ],
+                                                         introducersByCategory: [
+                                                            "full": ["full", "watch"],
+                                                            "watch": ["full", "watch"],
+                                                            "tv": ["full", "watch", "tv"],
+                                                            "audio": ["full", "watch", "audio"],
+                    ],
+                                                         redactions: [:],
+                                                         keyViewMapping: [
+                                                            TPPBPolicyKeyViewMapping(view: "ApplePay", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^ApplePay$")),
+                                                            TPPBPolicyKeyViewMapping(view: "AutoUnlock", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^AutoUnlock$")),
+                                                            TPPBPolicyKeyViewMapping(view: "Engram", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^Engram$")),
+                                                            TPPBPolicyKeyViewMapping(view: "Health", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^Health$")),
+                                                            TPPBPolicyKeyViewMapping(view: "Home", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^Home$")),
+                                                            TPPBPolicyKeyViewMapping(view: "Manatee", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^Manatee$")),
+                                                            TPPBPolicyKeyViewMapping(view: "LimitedPeersAllowed", matchingRule: TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^LimitedPeersAllowed$")),
+
+                                                            // These items will not be synced by Octagon
+                                                            TPPBPolicyKeyViewMapping(view: "NotSynced", matchingRule:
+                                                                TPDictionaryMatchingRule.orMatch([
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^ContinuityUnlock$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^HomeKit$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^AppleTV$"),
+                                                                ])),
+
+                                                            TPPBPolicyKeyViewMapping(view: "Applications", matchingRule:
+                                                                TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^[0-9A-Z]{10}\\.")),
+
+                                                            TPPBPolicyKeyViewMapping(view: "SecureObjectSync", matchingRule:
+                                                                TPDictionaryMatchingRule.orMatch([
+                                                                    TPDictionaryMatchingRule.andMatch([
+                                                                        TPDictionaryMatchingRule.fieldMatch("class", fieldRegex: "^genp$"),
+                                                                        TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^com\\.apple\\.sbd$"),
+                                                                    ]),
+                                                                    TPDictionaryMatchingRule.andMatch([
+                                                                        TPDictionaryMatchingRule.fieldMatch("class", fieldRegex: "^keys$"),
+                                                                        TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^com\\.apple\\.security\\.sos$"),
+                                                                    ]),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^BackupBagV0$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^iCloudIdentity$"),
+                                                                ])),
+
+                                                            TPPBPolicyKeyViewMapping(view: "WiFi", matchingRule:
+                                                                TPDictionaryMatchingRule.orMatch([
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^WiFi$"),
+                                                                    TPDictionaryMatchingRule.andMatch([
+                                                                        TPDictionaryMatchingRule.fieldMatch("class", fieldRegex: "^genp$"),
+                                                                        TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^apple$"),
+                                                                        TPDictionaryMatchingRule.fieldMatch("svce", fieldRegex: "^AirPort$"),
+                                                                    ]),
+                                                                ])),
+
+                                                            TPPBPolicyKeyViewMapping(view: "ProtectedCloudStorage", matchingRule:
+                                                                TPDictionaryMatchingRule.orMatch([
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Backup$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-CloudKit$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Escrow$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-FDE$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Feldspar$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-MailDrop$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Maildrop$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-MasterKey$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Notes$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Photos$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-Sharing$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-iCloudBackup$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-iCloudDrive$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^PCS-iMessage$"),
+                                                                ])),
+
+                                                            TPPBPolicyKeyViewMapping(view: "CreditCards",
+                                                                                     matchingRule: TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^com\\.apple\\.safari\\.credit-cards$")),
+
+                                                            TPPBPolicyKeyViewMapping(view: "Passwords",
+                                                                                     matchingRule: TPDictionaryMatchingRule.fieldMatch("agrp", fieldRegex: "^com\\.apple\\.cfnetwork$")),
+
+                                                            TPPBPolicyKeyViewMapping(view: "DevicePairing", matchingRule:
+                                                                TPDictionaryMatchingRule.orMatch([
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^AccessoryPairing$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^NanoRegistry$"),
+                                                                    TPDictionaryMatchingRule.fieldMatch("vwht", fieldRegex: "^WatchMigration$"),
+                                                                ])),
+
+                                                            TPPBPolicyKeyViewMapping(view: "Backstop", matchingRule:
+                                                                TPDictionaryMatchingRule.trueMatch()),
+                    ],
+                    userControllableViewList: [],
+                    piggybackViews: [],
                                                          hashAlgo: .SHA256)
         ),
+
+        // Note to you, the next person to add a policy:
+        // We added user_controllable_views to the policy proto after creating v7. Pushing a new policy just to fill
+        // in that section seemed unnecessary. When you create v8, please fill it in. See the hacky v7 patch in TPPolicy.m.
+        // We added views_to_piggyback to the policy proto after creating v7 as well.
+
             ]
     // swiftlint:enable force_try
 
@@ -563,7 +699,7 @@ func builtInPolicyDocuments() -> [TPPolicyDocument] {
         let data = Data(base64Encoded: raw.policyData)!
         let doc = TPPolicyDocument.policyDoc(withHash: raw.version.policyHash, data: data)!
 
-        if(!doc.isEqual(to: raw.plaintextPolicy)) {
+        if !doc.isEqual(to: raw.plaintextPolicy) {
             let bodyData = raw.plaintextPolicy.protobuf
             let bodyBase64 = bodyData.base64EncodedString()
             let hash = TPHashBuilder.hash(with: .SHA256, of: bodyData)
index 5499b200bca7feb5ae8cd0e62f96ac8d9e4f18ed..f300de1916d98804596f1c4400d3f831743c2055 100644 (file)
@@ -33,13 +33,13 @@ enum RecoveryKeyType: Int {
 }
 
 class RecoveryKeySet: NSObject {
-    public var encryptionKey: _SFECKeyPair
-    public var signingKey: _SFECKeyPair
+    var encryptionKey: _SFECKeyPair
+    var signingKey: _SFECKeyPair
 
-    public var secret: Data
-    public var recoverySalt: String
+    var secret: Data
+    var recoverySalt: String
 
-    public init (secret: Data, recoverySalt: String) throws {
+    init (secret: Data, recoverySalt: String) throws {
         self.secret = secret
         self.recoverySalt = recoverySalt
 
@@ -49,7 +49,9 @@ class RecoveryKeySet: NSObject {
         let signingKeyData = try RecoveryKeySet.generateRecoveryKey(keyType: RecoveryKeyType.kOTRecoveryKeySigning, masterSecret: secret, recoverySalt: recoverySalt)
         self.signingKey = _SFECKeyPair.init(secKey: try RecoveryKeySet.createSecKey(keyData: signingKeyData))
 
-        let RecoverySigningPubKeyHash = try RecoveryKeySet.hashRecoveryedSigningPublicKey(keyData: self.signingKey.publicKey().spki())
+        // Note: this uses the SPKI hash, and not the key data hash
+        // So, this will not match the RK's peer ID
+        let RecoverySigningPubKeyHash = RecoveryKeySet.hashRecoveryedSigningPublicKey(keyData: self.signingKey.publicKey().spki())
         _ = try RecoveryKeySet.storeRecoveryedSigningKeyPair(keyData: self.signingKey.keyData, label: RecoverySigningPubKeyHash)
         _ = try RecoveryKeySet.storeRecoveryedEncryptionKeyPair(keyData: self.encryptionKey.keyData, label: RecoverySigningPubKeyHash)
     }
@@ -76,7 +78,6 @@ class RecoveryKeySet: NSObject {
 
             let infoString = Array("Recovery Signing Private Key".utf8)
             info = Data(bytes: infoString, count: infoString.count)
-
         }
 
         guard let cp = ccec_cp_384() else {
@@ -109,7 +110,7 @@ class RecoveryKeySet: NSObject {
                         if keyType == RecoveryKeyType.kOTRecoveryKeyEncryption || keyType == RecoveryKeyType.kOTRecoveryKeySigning {
                             status = ccec_generate_key_deterministic(cp,
                                                                      derivedKeyBytes.count, derivedKeyBytes.bindMemory(to: UInt8.self).baseAddress!,
-                                                                     ccDRBGGetRngState(),
+                                                                     ccrng(nil),
                                                                      UInt32(CCEC_GENKEY_DETERMINISTIC_FIPS),
                                                                      fullKey)
 
@@ -167,7 +168,7 @@ class RecoveryKeySet: NSObject {
         return result
     }
 
-    class func hashRecoveryedSigningPublicKey(keyData: Data) throws -> (String) {
+    class func hashRecoveryedSigningPublicKey(keyData: Data) -> (String) {
         let di = ccsha384_di()
         var result = Data(count: TPHObjectiveC.ccsha384_diSize())
 
@@ -183,7 +184,6 @@ class RecoveryKeySet: NSObject {
     }
 
     class func storeRecoveryedEncryptionKeyPair(keyData: Data, label: String) throws -> (Bool) {
-
         let query: [CFString: Any] = [
             kSecClass: kSecClassKey,
             kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked,
@@ -257,11 +257,11 @@ class RecoveryKeySet: NSObject {
             let keyTypeData = item[kSecAttrApplicationLabel as CFString] as! Data
             let keyType = String(data: keyTypeData, encoding: .utf8)!
 
-            if keyType.range(of: "Encryption") != nil {
+            if keyType.contains("Encryption") {
                 let keyData = item[kSecValueData as CFString] as! Data
                 let encryptionSecKey = try RecoveryKeySet.createSecKey(keyData: keyData)
                 encryptionKey = _SFECKeyPair.init(secKey: encryptionSecKey)
-            } else if keyType.range(of: "Signing") != nil {
+            } else if keyType.contains("Signing") {
                 let keyData = item[kSecValueData as CFString] as! Data
                 let signingSecKey = try RecoveryKeySet.createSecKey(keyData: keyData)
                 signingKey = _SFECKeyPair.init(secKey: signingSecKey)
@@ -300,7 +300,6 @@ extension RecoveryKeySetError: LocalizedError {
 }
 
 extension RecoveryKeySetError: CustomNSError {
-
     public static var errorDomain: String {
         return "com.apple.security.trustedpeers.RecoveryKeySetError"
     }
index 35cd9b3f99d815d726f8eecffe2314083889da16..373a256d1d63137210ef8fb1642673a81e1b301f 100644 (file)
@@ -25,20 +25,38 @@ import Foundation
 import SecurityFoundation
 
 class RecoveryKey: NSObject {
-    public var recoveryKeys: RecoveryKeySet
-    public var secret: Data
+    internal var recoveryKeys: RecoveryKeySet
+    internal var secret: Data
 
-    public var peerKeys: OctagonSelfPeerKeys
+    internal var peerKeys: OctagonSelfPeerKeys
 
-    public init(recoveryKeyString: String, recoverySalt: String) throws {
+    internal init(recoveryKeyString: String, recoverySalt: String) throws {
         self.secret = Data(bytes: Array(recoveryKeyString.utf8), count: recoveryKeyString.utf8.count)
         self.recoveryKeys = try RecoveryKeySet(secret: self.secret, recoverySalt: recoverySalt)
 
-        let hash = try RecoveryKeySet.hashRecoveryedSigningPublicKey(keyData: self.recoveryKeys.signingKey.publicKey.keyData)
-        let peerID = "RK-" + hash
+        let peerID = RecoveryKey.PeerID(signingPublicKeyData: self.recoveryKeys.signingKey.publicKey.keyData)
 
         try self.peerKeys = OctagonSelfPeerKeys(peerID: peerID, signingKey: self.recoveryKeys.signingKey, encryptionKey: self.recoveryKeys.encryptionKey)
     }
+
+    static func PeerID(signingPublicKeyData: Data) -> String {
+        let hash = RecoveryKeySet.hashRecoveryedSigningPublicKey(keyData: signingPublicKeyData)
+        let peerID = "RK-" + hash
+
+        return peerID
+    }
+
+    static func spki(publicKeyData: Data) throws -> Data {
+        let key = try _SFECPublicKey(data: publicKeyData, specifier: _SFECKeySpecifier(curve: SFEllipticCurve.nistp384))
+        return key.encodeSubjectPublicKeyInfo()
+    }
+
+    public static func asPeer(recoveryKeys: TPRecoveryKeyPair, viewList: Set<String>) throws -> TrustedPeersHelperPeer {
+        return TrustedPeersHelperPeer(peerID: self.PeerID(signingPublicKeyData: recoveryKeys.signingKeyData),
+                                      signingSPKI: try self.spki(publicKeyData: recoveryKeys.signingKeyData),
+                                      encryptionSPKI: try self.spki(publicKeyData: recoveryKeys.encryptionKeyData),
+                                      viewList: viewList)
+    }
 }
 
 extension RecoveryKey {
index 5254fe766436c253fdd25ace6490e3d926eed193..51128fa0f523dd9f5681a1edf69a802719473ada 100644 (file)
@@ -6,7 +6,7 @@
 #import <SecurityFoundation/SFKey.h>
 #import <SecurityFoundation/SFKey_Private.h>
 #import <corecrypto/ccsha2.h>
-#import <CommonCrypto/CommonRandomSPI.h>
+#import <corecrypto/ccrng.h>
 
 @implementation TPHObjectiveC : NSObject
 
index a633cef55b9782c6734e0f50b088b75cd242f6af..38ec749f89439cd8f700374a788a42341734ed1b 100644 (file)
 
 #import "keychain/ot/OTConstants.h"
 #import "keychain/ot/OTDefines.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecord.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h"
+
 #import "keychain/TrustedPeersHelper/TPHObjcTranslation.h"
 #import "keychain/TrustedPeersHelper/proto/generated_source/OTBottleContents.h"
 #import "keychain/TrustedPeersHelper/proto/generated_source/OTBottle.h"
 #import <corecrypto/cchkdf.h>
 #import <corecrypto/ccsha2.h>
 #import <corecrypto/ccec.h>
+#import <corecrypto/ccrng.h>
 
-#import <CommonCrypto/CommonRandomSPI.h>
 #import <Security/SecCFAllocator.h>
 #include <Security/SecRecoveryKey.h>
+
+#if TARGET_OS_OSX
+#include <sandbox.h>
+#endif
index 6947f3d51da9c5cee13ee8ecfc16ba0f0e856136..539efa037aa704fb4db0a4b80a865706f046347a 100644 (file)
@@ -24,6 +24,8 @@
        <true/>
        <key>com.apple.private.cloudkit.systemService</key>
        <true/>
+       <key>com.apple.private.cloudkit.spi</key>
+       <true/>
        <key>com.apple.private.cloudkit.supportservice</key>
        <true/>
        <key>com.apple.private.cloudkit.prefix</key>
        </array>
        <key>com.apple.symptom_diagnostics.report</key>
        <true/>
+       <key>seatbelt-profiles</key>
+       <array>
+               <string>temporary-sandbox</string>
+       </array>
+       <key>com.apple.security.ts.cloudkit-client</key>
+       <true/>
+       <key>com.apple.security.exception.files.absolute-path.read-write</key>
+       <array>
+               <string>/private/var/Keychains/</string>
+       </array>
+       <key>com.apple.security.exception.mach-lookup.global-name</key>
+       <array>
+               <string>com.apple.securityd</string>
+               <string>com.apple.security.sfkeychainserver</string>
+       </array>
+       <key>com.apple.security.exception.shared-preference.read-write</key>
+       <array>
+               <string>com.apple.TrustedPeersHelper</string>
+       </array>
 </dict>
 </plist>
index 83d8766c0dc8d42c737c88d8184031e90847be25..8160123b10496dfe0c375ff2d863f4f56ba430dd 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17026" systemVersion="19E219" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
+<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17162" systemVersion="20A2347" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
     <entity name="Bottle" representedClassName="BottleMO" syncable="YES" codeGenerationType="class">
         <attribute name="bottleID" optional="YES" attributeType="String"/>
         <attribute name="contents" optional="YES" attributeType="Binary"/>
         <attribute name="egoPeerPermanentInfoSig" optional="YES" attributeType="Binary"/>
         <attribute name="egoPeerStableInfo" optional="YES" attributeType="Binary"/>
         <attribute name="egoPeerStableInfoSig" optional="YES" attributeType="Binary"/>
+        <attribute name="escrowFetchDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="honorIDMSListChanges" optional="YES" attributeType="String" defaultValueString="UNKNOWN"/>
         <attribute name="moreChanges" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
         <attribute name="name" optional="YES" attributeType="String"/>
         <attribute name="recoveryKeyEncryptionSPKI" optional="YES" attributeType="Binary"/>
         <attribute name="recoveryKeySigningSPKI" optional="YES" attributeType="Binary"/>
         <relationship name="bottles" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Bottle" inverseName="container" inverseEntity="Bottle"/>
+        <relationship name="fullyViableEscrowRecords" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="EscrowRecord" inverseName="fullyViableEscrowRecords" inverseEntity="EscrowRecord"/>
+        <relationship name="legacyEscrowRecords" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="EscrowRecord" inverseName="legacyEscrowRecords" inverseEntity="EscrowRecord"/>
         <relationship name="machines" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Machine" inverseName="container" inverseEntity="Machine"/>
+        <relationship name="partiallyViableEscrowRecords" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="EscrowRecord" inverseName="partiallyViableEscrowRecords" inverseEntity="EscrowRecord"/>
         <relationship name="peers" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Peer" inverseName="container" inverseEntity="Peer"/>
         <relationship name="policies" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="Policy" inverseName="container" inverseEntity="Policy"/>
     </entity>
+    <entity name="EscrowClientMetadata" representedClassName="EscrowClientMetadataMO" syncable="YES" codeGenerationType="class">
+        <attribute name="deviceColor" optional="YES" attributeType="String"/>
+        <attribute name="deviceEnclosureColor" optional="YES" attributeType="String"/>
+        <attribute name="deviceMid" optional="YES" attributeType="String"/>
+        <attribute name="deviceModel" optional="YES" attributeType="String"/>
+        <attribute name="deviceModelClass" optional="YES" attributeType="String"/>
+        <attribute name="deviceModelVersion" optional="YES" attributeType="String"/>
+        <attribute name="deviceName" optional="YES" attributeType="String"/>
+        <attribute name="devicePlatform" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="secureBackupMetadataTimestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="secureBackupNumericPassphraseLength" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="secureBackupUsesComplexPassphrase" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="secureBackupUsesNumericPassphrase" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <relationship name="escrowMetadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="EscrowMetadata" inverseName="clientMetadata" inverseEntity="EscrowMetadata"/>
+    </entity>
+    <entity name="EscrowMetadata" representedClassName="EscrowMetadataMO" syncable="YES" codeGenerationType="class">
+        <attribute name="backupKeybagDigest" optional="YES" attributeType="Binary"/>
+        <attribute name="bottleID" optional="YES" attributeType="String"/>
+        <attribute name="escrowedSPKI" optional="YES" attributeType="Binary"/>
+        <attribute name="peerInfo" optional="YES" attributeType="Binary"/>
+        <attribute name="secureBackupTimestamp" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="secureBackupUsesMultipleiCSCS" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="serial" optional="YES" attributeType="String"/>
+        <relationship name="clientMetadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="EscrowClientMetadata" inverseName="escrowMetadata" inverseEntity="EscrowClientMetadata"/>
+        <relationship name="escrowRecord" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="EscrowRecord" inverseName="escrowMetadata" inverseEntity="EscrowRecord"/>
+    </entity>
+    <entity name="EscrowRecord" representedClassName="EscrowRecordMO" syncable="YES" codeGenerationType="class">
+        <attribute name="creationDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="label" optional="YES" attributeType="String"/>
+        <attribute name="recordStatus" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="remainingAttempts" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="silentAttemptAllowed" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <attribute name="sosViability" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
+        <relationship name="escrowMetadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="EscrowMetadata" inverseName="escrowRecord" inverseEntity="EscrowMetadata"/>
+        <relationship name="fullyViableEscrowRecords" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Container" inverseName="fullyViableEscrowRecords" inverseEntity="Container"/>
+        <relationship name="legacyEscrowRecords" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Container" inverseName="legacyEscrowRecords" inverseEntity="Container"/>
+        <relationship name="partiallyViableEscrowRecords" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Container" inverseName="partiallyViableEscrowRecords" inverseEntity="Container"/>
+    </entity>
     <entity name="Machine" representedClassName="MachineMO" syncable="YES" codeGenerationType="class">
         <attribute name="allowed" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
         <attribute name="machineID" optional="YES" attributeType="String"/>
     </entity>
     <elements>
         <element name="Bottle" positionX="-549" positionY="-234" width="128" height="150"/>
-        <element name="Container" positionX="-758" positionY="-261" width="128" height="268"/>
+        <element name="Container" positionX="-758" positionY="-261" width="128" height="343"/>
+        <element name="EscrowClientMetadata" positionX="-513" positionY="-198" width="128" height="238"/>
+        <element name="EscrowMetadata" positionX="-522" positionY="-207" width="128" height="178"/>
+        <element name="EscrowRecord" positionX="-549" positionY="-234" width="128" height="179"/>
         <element name="Machine" positionX="-549" positionY="-234" width="128" height="133"/>
         <element name="Peer" positionX="-414" positionY="-387" width="128" height="210"/>
         <element name="Policy" positionX="-414" positionY="54" width="128" height="105"/>
         <element name="RecoveryVoucher" positionX="-65" positionY="-297" width="128" height="105"/>
         <element name="Voucher" positionX="-65" positionY="-171" width="128" height="90"/>
     </elements>
-</model>
+</model>
\ No newline at end of file
index 0f37bed20f8510afabe30b86985894c73dc56069..145eee7838def817e316d11bc2ea133b95b9fdfb 100644 (file)
@@ -23,6 +23,7 @@
 
 #import <Foundation/Foundation.h>
 #import <TrustedPeers/TrustedPeers.h>
+#import <objc/runtime.h>
 
 #import "keychain/ckks/CKKSKeychainBackedKey.h"
 #import "keychain/ckks/CKKSTLKShare.h"
@@ -158,11 +159,12 @@ NS_ASSUME_NONNULL_BEGIN
                   bottleSalt:(NSString *)bottleSalt
                     bottleID:(NSString *)bottleID
                      modelID:(NSString *)modelID
-                  deviceName:(nullable NSString*)deviceName
-                serialNumber:(NSString *)serialNumber
+                  deviceName:(nullable NSString *)deviceName
+                serialNumber:(nullable NSString *)serialNumber
                    osVersion:(NSString *)osVersion
                policyVersion:(nullable TPPolicyVersion *)policyVersion
                policySecrets:(nullable NSDictionary<NSString*,NSData*> *)policySecrets
+   syncUserControllableViews:(TPPBPeerStableInfo_UserControllableViewStatus)syncUserControllableViews
  signingPrivKeyPersistentRef:(nullable NSData *)spkPr
      encPrivKeyPersistentRef:(nullable NSData*)epkPr
                        reply:(void (^)(NSString * _Nullable peerID,
@@ -170,8 +172,7 @@ NS_ASSUME_NONNULL_BEGIN
                                        NSData * _Nullable permanentInfoSig,
                                        NSData * _Nullable stableInfo,
                                        NSData * _Nullable stableInfoSig,
-                                       NSSet<NSString*>* _Nullable syncingViewList,
-                                       TPPolicy* _Nullable syncingPolicy,
+                                       TPSyncingPolicy* _Nullable syncingPolicy,
                                        NSError * _Nullable error))reply;
 
 // If there already are existing CKKSViews, please pass in their key sets anyway.
@@ -183,6 +184,7 @@ NS_ASSUME_NONNULL_BEGIN
                preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                          reply:(void (^)(NSString * _Nullable peerID,
                                          NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                         TPSyncingPolicy* _Nullable syncingPolicy,
                                          NSError * _Nullable error))reply;
 
 // Returns a voucher for the given peer ID using our own identity
@@ -202,12 +204,13 @@ NS_ASSUME_NONNULL_BEGIN
 // Preflighting a vouch will return the peer ID associated with the bottle you will be recovering, as well as
 // the syncing policy used by that peer, and,
 // You can then use that peer ID to filter the tlkshares provided to vouchWithBottle.
+// If TPH had to refetch anything from the network, it will report that fact as refetchNeeded.
 - (void)preflightVouchWithBottleWithContainer:(NSString *)container
                                       context:(NSString *)context
                                      bottleID:(NSString*)bottleID
                                         reply:(void (^)(NSString* _Nullable peerID,
-                                                        NSSet<NSString*>* _Nullable peerSyncingViewList,
-                                                        TPPolicy * _Nullable peerSyncingPolicy,
+                                                        TPSyncingPolicy* _Nullable syncingPolicy,
+                                                        BOOL refetchWasNeeded,
                                                         NSError * _Nullable error))reply;
 
 // Returns a voucher for our own identity, created by the identity inside this bottle
@@ -230,8 +233,7 @@ NS_ASSUME_NONNULL_BEGIN
                                        recoveryKey:(NSString*)recoveryKey
                                               salt:(NSString*)salt
                                              reply:(void (^)(NSString* _Nullable recoveryKeyID,
-                                                             NSSet<NSString*>* _Nullable peerSyncingViewList,
-                                                             TPPolicy * _Nullable peerSyncingPolicy,
+                                                             TPSyncingPolicy* _Nullable syncingPolicy,
                                                              NSError * _Nullable error))reply;
 
 // Returns a voucher for our own identity, using recovery key
@@ -253,20 +255,21 @@ NS_ASSUME_NONNULL_BEGIN
                voucherSig:(NSData *)voucherSig
                  ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)viewKeySets
                 tlkShares:(NSArray<CKKSTLKShare*> *)tlkShares
-          preapprovedKeys:(NSArray<NSData*> *)preapprovedKeys
+          preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                     reply:(void (^)(NSString * _Nullable peerID,
                                     NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
-                                    NSSet<NSString*>* _Nullable syncingViewList,
-                                    TPPolicy* _Nullable syncingPolicy,
+                                    TPSyncingPolicy* _Nullable syncingPolicy,
                                     NSError * _Nullable error))reply;
 
 // Preflighting a preapproved join suggests whether or not you expect to succeed in an immediate preapprovedJoin() call
 // This only inspects the Octagon model, and ignores the trusted device list, so that you can preflight the preapprovedJoin()
 // before fetching that list.
-// This will return YES if there are no existing peers, or if the existing peers preapprove your prepared identity.
+// This will return YES if there are no existing peers, or if the existing peers preapprove your prepared identity, and
+//   you are intending to trust at least one preapproving peer (so that you don't stomp all over everyone else at join time).
 // This will return NO otherwise.
 - (void)preflightPreapprovedJoinWithContainer:(NSString *)container
                                       context:(NSString *)context
+                              preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                                         reply:(void (^)(BOOL launchOkay,
                                                         NSError * _Nullable error))reply;
 
@@ -276,14 +279,14 @@ NS_ASSUME_NONNULL_BEGIN
                                     context:(NSString *)context
                                    ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)ckksKeys
                                   tlkShares:(NSArray<CKKSTLKShare*> *)tlkShares
-                            preapprovedKeys:(NSArray<NSData*> *)preapprovedKeys
+                            preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                                       reply:(void (^)(NSString * _Nullable peerID,
                                                       NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
-                                                      NSSet<NSString*>* _Nullable syncingViewList,
-                                                      TPPolicy* _Nullable syncingPolicy,
+                                                      TPSyncingPolicy* _Nullable syncingPolicy,
                                                       NSError * _Nullable error))reply;
 
 // TODO: if the new policy causes someone to lose access to a view, how should this API work?
+// syncUserControllableViews should contain the raw value of the TPPBPeerStableInfo_UserControllableViewStatus enum, or be nil
 - (void)updateWithContainer:(NSString *)container
                     context:(NSString *)context
                  deviceName:(nullable NSString *)deviceName
@@ -291,7 +294,10 @@ NS_ASSUME_NONNULL_BEGIN
                   osVersion:(nullable NSString *)osVersion
               policyVersion:(nullable NSNumber *)policyVersion
               policySecrets:(nullable NSDictionary<NSString*,NSData*> *)policySecrets
-                      reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState, NSError * _Nullable error))reply;
+  syncUserControllableViews:(nullable NSNumber *)syncUserControllableViews
+                      reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState,
+                                      TPSyncingPolicy* _Nullable syncingPolicy,
+                                      NSError * _Nullable error))reply;
 
 - (void)setPreapprovedKeysWithContainer:(NSString *)container
                                 context:(NSString *)context
@@ -309,6 +315,11 @@ NS_ASSUME_NONNULL_BEGIN
                                 context:(NSString *)context
                                   reply:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs, NSArray<NSString*>* _Nullable sortedPartialBottleIDs, NSError* _Nullable error))reply;
 
+- (void)fetchViableEscrowRecordsWithContainer:(NSString *)container
+                                      context:(NSString *)context
+                                   forceFetch:(BOOL)forceFetch
+                                        reply:(void (^)(NSArray<NSData*>* _Nullable records, NSError* _Nullable error))reply;
+
 - (void)fetchEscrowContentsWithContainer:(NSString *)container
                                  context:(NSString *)context
                                    reply:(void (^)(NSData* _Nullable entropy,
@@ -323,10 +334,14 @@ NS_ASSUME_NONNULL_BEGIN
                                                     NSError * _Nullable error))reply;
 
 // Fetch the policy and view list for current peer.
+// Note: userControllableViewStatusOfPeers is not our current peer's view of the world, but rather what
+// our peers believe.
+// If there is no prepared ego peer, the returned policy will be for a device with modelIDOverride
 - (void)fetchCurrentPolicyWithContainer:(NSString*)container
                                 context:(NSString*)context
-                                  reply:(void (^)(NSSet<NSString*>* _Nullable syncingViewList,
-                                                  TPPolicy * _Nullable syncingPolicy,
+                        modelIDOverride:(NSString* _Nullable)modelID
+                                  reply:(void (^)(TPSyncingPolicy* _Nullable syncingPolicy,
+                                                  TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers,
                                                   NSError * _Nullable error))reply;
 
 - (void)validatePeersWithContainer:(NSString *)container
@@ -346,7 +361,8 @@ NS_ASSUME_NONNULL_BEGIN
                         recoveryKey:(NSString *)recoveryKey
                                salt:(NSString *)salt
                            ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)ckksKeys
-                              reply:(void (^)(NSError* _Nullable error))reply;
+                              reply:(void (^)(NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                              NSError* _Nullable error))reply;
 
 - (void)reportHealthWithContainer:(NSString *)container
                           context:(NSString *)context
@@ -367,6 +383,10 @@ NS_ASSUME_NONNULL_BEGIN
                                context:(NSString *)context
                                  reply:(void (^)(NSData * _Nullable, NSError * _Nullable))reply;
 
+- (void)removeEscrowCacheWithContainer:(NSString *)container
+                               context:(NSString *)context
+                                 reply:(void (^)(NSError * _Nullable))reply;
+
 @end
 
 /*
index fb2f1557e1c331a54c1da269a496b85019ca8a4c..fb31466cc520c549f9aabbe96e12cd8e43d3d577 100644 (file)
@@ -6,6 +6,7 @@
 #import "utilities/debugging.h"
 #import <CloudKit/CloudKit.h>
 #import <CloudKit/CloudKit_Private.h>
+#import <Security/SecXPCHelper.h>
 #endif
 
 NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
@@ -16,29 +17,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         errClasses = [NSMutableSet setWithSet:CKAcceptableValueClasses()];
-
-        char *classes[] = {
-            "CKPrettyError",
-            "CKRecordID",
-            "NSArray",
-            "NSData",
-            "NSDate",
-            "NSDictionary",
-            "NSError",
-            "NSNull",
-            "NSNumber",
-            "NSOrderedSet",
-            "NSSet",
-            "NSString",
-            "NSURL",
-        };
-
-        for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
-            Class cls = objc_getClass(classes[n]);
-            if (cls) {
-                [errClasses addObject:cls];
-            }
-        }
+        [errClasses unionSet:[SecXPCHelper safeErrorClasses]];
     });
 
     @try {
@@ -50,6 +29,45 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
 
         NSSet* arrayOfTrustedPeersHelperPeer = [NSSet setWithArray:@[[NSArray class], [TrustedPeersHelperPeer class]]];
 
+        [interface setClasses:errClasses forSelector:@selector(dumpWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(departByDistrustingSelfWithContainer:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(distrustPeerIDsWithContainer:context:peerIDs:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(trustStatusWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(resetWithContainer:context:resetReason:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(localResetWithContainer:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(setAllowedMachineIDsWithContainer:context:allowedMachineIDs:honorIDMSListChanges:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(addAllowedMachineIDsWithContainer:context:machineIDs:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(removeAllowedMachineIDsWithContainer:context:machineIDs:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchAllowedMachineIDsWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchEgoEpochWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(prepareWithContainer:context:epoch:machineID:bottleSalt:bottleID:modelID:deviceName:serialNumber:osVersion:policyVersion:policySecrets:syncUserControllableViews:signingPrivKeyPersistentRef:encPrivKeyPersistentRef:reply:) argumentIndex:6 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(establishWithContainer:context:ckksKeys:tlkShares:preapprovedKeys:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(vouchWithContainer:context:peerID:permanentInfo:permanentInfoSig:stableInfo:stableInfoSig:ckksKeys:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(preflightVouchWithBottleWithContainer:context:bottleID:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(vouchWithBottleWithContainer:context:bottleID:entropy:bottleSalt:tlkShares:reply:) argumentIndex:4 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(preflightVouchWithRecoveryKeyWithContainer:context:recoveryKey:salt:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(vouchWithRecoveryKeyWithContainer:context:recoveryKey:salt:tlkShares:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(joinWithContainer:context:voucherData:voucherSig:ckksKeys:tlkShares:preapprovedKeys:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(preflightPreapprovedJoinWithContainer:context:preapprovedKeys:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(attemptPreapprovedJoinWithContainer:context:ckksKeys:tlkShares:preapprovedKeys:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(updateWithContainer:context:deviceName:serialNumber:osVersion:policyVersion:policySecrets:syncUserControllableViews:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(setPreapprovedKeysWithContainer:context:preapprovedKeys:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(updateTLKsWithContainer:context:ckksKeys:tlkShares:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchViableBottlesWithContainer:context:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchViableEscrowRecordsWithContainer:context:forceFetch:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchEscrowContentsWithContainer:context:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchPolicyDocumentsWithContainer:context:versions:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchCurrentPolicyWithContainer:context:modelIDOverride:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(validatePeersWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchTrustStateWithContainer:context:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(setRecoveryKeyWithContainer:context:recoveryKey:salt:ckksKeys:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(reportHealthWithContainer:context:stateMachineState:trustState:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(pushHealthInquiryWithContainer:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(requestHealthCheckWithContainer:context:requiresEscrowCheck:reply:) argumentIndex:4 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(getSupportAppInfoWithContainer:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(removeEscrowCacheWithContainer:context:reply:) argumentIndex:0 ofReply:YES];
+
+
         [interface setClasses:arrayOfStrings   forSelector:@selector(addAllowedMachineIDsWithContainer:context:machineIDs:reply:) argumentIndex:2 ofReply:NO];
         [interface setClasses:arrayOfStrings   forSelector:@selector(removeAllowedMachineIDsWithContainer:context:machineIDs:reply:) argumentIndex:2 ofReply:NO];
 
@@ -88,6 +106,12 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
                                                                    salt:
                                                                    ckksKeys:
                                                                    reply:) argumentIndex:4 ofReply:NO];
+        [interface setClasses:arrayOfCKRecords forSelector:@selector(setRecoveryKeyWithContainer:
+                                                                     context:
+                                                                     recoveryKey:
+                                                                     salt:
+                                                                     ckksKeys:
+                                                                     reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:arrayOfTLKShares forSelector:@selector(vouchWithRecoveryKeyWithContainer:
                                                                      context:
                                                                      recoveryKey:
@@ -95,10 +119,6 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
                                                                      tlkShares:
                                                                      reply:) argumentIndex:4 ofReply:NO];
 
-        [interface setClasses:[NSSet setWithObject:[TPPolicy class]] forSelector:@selector(fetchCurrentPolicyWithContainer:
-                                                                                           context:
-                                                                                           reply:) argumentIndex:1 ofReply:YES];
-
         [interface setClasses:trustedPeersHelperPeerState forSelector:@selector(updateWithContainer:
                                                                                 context:
                                                                                 deviceName:
@@ -106,6 +126,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
                                                                                 osVersion:
                                                                                 policyVersion:
                                                                                 policySecrets:
+                                                                                syncUserControllableViews:
                                                                                 reply:) argumentIndex:0 ofReply:YES];
 
         [interface setClasses:trustedPeersHelperPeerState   forSelector:@selector(fetchTrustStateWithContainer:
@@ -133,9 +154,7 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
     }
     @catch(NSException* e) {
         secerror("TrustedPeersHelperSetupProtocol failed, continuing, but you might crash later: %@", e);
-#if DEBUG
         @throw e;
-#endif
     }
 #endif
 
@@ -164,10 +183,10 @@ NSXPCInterface* TrustedPeersHelperSetupProtocol(NSXPCInterface* interface)
 
 - (NSString*)description
 {
-    return [NSString stringWithFormat:@"<TPHPeerState: %@ preapproved:%d status:%lld memberChanges: %@ unk. mIDs: %@ osVersion: %@>",
+    return [NSString stringWithFormat:@"<TPHPeerState: %@ preapproved:%d status:%@ memberChanges: %@ unk. mIDs: %@ osVersion: %@>",
             self.peerID,
             self.identityIsPreapproved,
-            (int64_t)self.peerStatus,
+            TPPeerStatusToString(self.peerStatus),
             self.memberChanges ? @"YES" : @"NO",
             self.unknownMachineIDsPresent ? @"YES" : @"NO",
             self.osVersion?:@"unknown"];
diff --git a/keychain/TrustedPeersHelper/com.apple.TrustedPeersHelper.sb b/keychain/TrustedPeersHelper/com.apple.TrustedPeersHelper.sb
new file mode 100644 (file)
index 0000000..a3d85d5
--- /dev/null
@@ -0,0 +1,41 @@
+(version 1)
+
+(define (home-subpath home-relative-subpath)
+    (subpath (string-append (param "HOME") home-relative-subpath)))
+
+(deny default)
+(deny file-map-executable iokit-get-properties process-info* nvram*)
+(deny dynamic-code-generation)
+
+(deny mach-priv-host-port)
+(import "system.sb")
+(import "com.apple.corefoundation.sb")
+(corefoundation)
+
+(allow distributed-notification-post)
+
+(allow process-info* (target self))
+(allow process-info-codesignature)
+
+(allow file-read-metadata)
+
+(allow file-read* file-write*
+    (home-subpath "/Library/Keychains/"))
+
+(allow mach-lookup
+    (global-name "com.apple.cloudd")
+    (global-name "com.apple.apsd")
+    (global-name "com.apple.securityd.xpc")
+    (global-name "com.apple.security.sfkeychainserver")
+    (global-name "com.apple.SecurityServer")
+    (global-name "com.apple.lsd.mapdb")
+)
+
+(allow user-preference-read
+    (preference-domain "kCFPreferencesAnyApplication")
+)
+
+(allow file-read* file-write*
+    (subpath "/private/var/db/mds/")
+    (subpath "/Library/Keychains/")
+)
index 9bfa5fb666d17d0897158c518473aa867b590487..3f98b40d40d2e78b6c43b7828fd1f7288db546e7 100644 (file)
@@ -59,11 +59,42 @@ class ServiceDelegate: NSObject, NSXPCListenerDelegate {
     }
 }
 
+#if os(macOS)
+public func withArrayOfCStrings<R>(
+    _ args: [String],
+    _ body: ([UnsafePointer<CChar>?]) -> R
+) -> R {
+    var mutableCStrings = args.map { strdup($0) }
+    mutableCStrings.append(nil)
+
+    let cStrings = mutableCStrings.map { UnsafePointer($0) }
+
+    defer {
+        mutableCStrings.forEach { free($0) }
+    }
+    return body(cStrings)
+}
+
+withArrayOfCStrings(["HOME", NSHomeDirectory()]) { parameters in
+    var sandboxErrors: UnsafeMutablePointer<CChar>?
+
+    let rc = sandbox_init_with_parameters("com.apple.TrustedPeersHelper", UInt64(SANDBOX_NAMED), parameters, &sandboxErrors)
+    guard rc == 0 else {
+        let printableMessage = sandboxErrors.map { String(cString: $0 ) }
+        os_log("Unable to enter sandbox. Error code:%d message: %@", log: tplogDebug, type: .default, rc, printableMessage ?? "no printable message")
+        sandbox_free_error(sandboxErrors)
+        abort()
+    }
+    os_log("Sandbox entered", log: tplogDebug, type: .default)
+}
+#endif
+
 os_log("Starting up", log: tplogDebug, type: .default)
 
 ValueTransformer.setValueTransformer(SetValueTransformer(), forName: SetValueTransformer.name)
 
 let delegate = ServiceDelegate()
 let listener = NSXPCListener.service()
+
 listener.delegate = delegate
 listener.resume()
index 926ae2d016f5d582be1423e8d307809dac76fd1f..0afee1065637dcc6bca39a68d10bb45ca82ca2a6 100644 (file)
@@ -5,7 +5,6 @@
 #import <Foundation/Foundation.h>
 #import <ProtocolBuffer/PBCodable.h>
 
-@class OTPrivateKey;
 @class OTPrivateKey;
 
 #ifdef __cplusplus
index 9ddd0d113986ba6f3ff19d2baa95efc65b8d9f66..f8391d9b2cefdd508c55478414abe230db3ac8c3 100644 (file)
@@ -1,3 +1,4 @@
 disabled_rules:
     - force_cast
     - force_try
+    - implicitly_unwrapped_optional
index 655bfdf8cab1bde89a6a3874315d47a7736d1246..1b325f35a216b866c1f77ae00491035550f3ef10 100644 (file)
@@ -8,7 +8,6 @@
 import XCTest
 
 extension Container {
-
     func dumpSync(test: XCTestCase) -> ([AnyHashable: Any]?, Error?) {
         let expectation = XCTestExpectation(description: "dump replied")
         var reta: [AnyHashable: Any]?, reterr: Error?
@@ -54,13 +53,13 @@ extension Container {
                      osVersion: String = "123",
                      policyVersion: TPPolicyVersion? = nil,
                      policySecrets: [String: Data]? = nil,
+                     syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus = .UNKNOWN,
                      signingPrivateKeyPersistentRef: Data? = nil,
                      encryptionPrivateKeyPersistentRef: Data? = nil
-        ) -> (String?, Data?, Data?, Data?, Data?, Set<String>?, TPPolicy?, Error?) {
+    ) -> (String?, Data?, Data?, Data?, Data?, TPSyncingPolicy?, Error?) {
         let expectation = XCTestExpectation(description: "prepare replied")
         var reta: String?, retb: Data?, retc: Data?, retd: Data?, rete: Data?, reterr: Error?
-        var retviews: Set<String>?
-        var retpolicy: TPPolicy?
+        var retpolicy: TPSyncingPolicy?
         self.prepare(epoch: epoch,
                      machineID: machineID,
                      bottleSalt: bottleSalt,
@@ -71,39 +70,41 @@ extension Container {
                      osVersion: osVersion,
                      policyVersion: policyVersion,
                      policySecrets: policySecrets,
+                     syncUserControllableViews: syncUserControllableViews,
                      signingPrivateKeyPersistentRef: signingPrivateKeyPersistentRef,
                      encryptionPrivateKeyPersistentRef: encryptionPrivateKeyPersistentRef
-        ) { a, b, c, d, e, f, g, err in
+        ) { a, b, c, d, e, f, err in
             reta = a
             retb = b
             retc = c
             retd = d
             rete = e
-            retviews = f
-            retpolicy = g
+            retpolicy = f
             reterr = err
             expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reta, retb, retc, retd, rete, retviews, retpolicy, reterr)
+        return (reta, retb, retc, retd, rete, retpolicy, reterr)
     }
 
     func establishSync(test: XCTestCase,
                        ckksKeys: [CKKSKeychainBackedKeySet],
                        tlkShares: [CKKSTLKShare],
-                       preapprovedKeys: [Data]?) -> (String?, [CKRecord], Error?) {
+                       preapprovedKeys: [Data]?) -> (String?, [CKRecord], TPSyncingPolicy?, Error?) {
         let expectation = XCTestExpectation(description: "prepare replied")
         var reta: String?, retkhr: [CKRecord]?, reterr: Error?
+        var retpolicy: TPSyncingPolicy?
         self.establish(ckksKeys: ckksKeys,
                        tlkShares: tlkShares,
-                       preapprovedKeys: preapprovedKeys) { a, khr, err in
+                       preapprovedKeys: preapprovedKeys) { a, khr, policy, err in
                         reta = a
                         retkhr = khr
+                        retpolicy = policy
                         reterr = err
                         expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reta, retkhr!, reterr)
+        return (reta, retkhr!, retpolicy, reterr)
     }
 
     func vouchSync(test: XCTestCase,
@@ -130,19 +131,20 @@ extension Container {
         return (reta, retb, reterr)
     }
 
-    func preflightVouchWithBottleSync(test: XCTestCase, bottleID: String) -> (String?, Set<String>?, TPPolicy?, Error?) {
+    func preflightVouchWithBottleSync(test: XCTestCase, bottleID: String) -> (String?, TPSyncingPolicy?, Bool, Error?) {
         let expectation = XCTestExpectation(description: "preflightVouchWithBottle replied")
         var reta: String?, reterr: Error?
-        var retviews: Set<String>?, retpolicy: TPPolicy?
-        self.preflightVouchWithBottle(bottleID: bottleID) { a, views, policy, err in
+        var retrefetched: Bool = false
+        var retpolicy: TPSyncingPolicy?
+        self.preflightVouchWithBottle(bottleID: bottleID) { a, policy, refetched, err in
             reta = a
-            retviews = views
             retpolicy = policy
+            retrefetched = refetched
             reterr = err
             expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reta, retviews, retpolicy, reterr)
+        return (reta, retpolicy, retrefetched, reterr)
     }
 
     func vouchWithBottleSync(test: XCTestCase, b: String, entropy: Data, bottleSalt: String, tlkShares: [CKKSTLKShare]) -> (Data?, Data?, Int64, Int64, Error?) {
@@ -165,70 +167,71 @@ extension Container {
                   voucherSig: Data,
                   ckksKeys: [CKKSKeychainBackedKeySet],
                   tlkShares: [CKKSTLKShare],
-                  preapprovedKeys: [Data]? = nil) -> (String?, [CKRecord]?, Set<String>?, TPPolicy?, Error?) {
+                  preapprovedKeys: [Data]? = nil) -> (String?, [CKRecord]?, TPSyncingPolicy?, Error?) {
         let expectation = XCTestExpectation(description: "join replied")
         var reta: String?, retkhr: [CKRecord]?, reterr: Error?
-        var retviews: Set<String>?, retpolicy: TPPolicy?
+        var retpolicy: TPSyncingPolicy?
         self.join(voucherData: voucherData,
                   voucherSig: voucherSig,
                   ckksKeys: ckksKeys,
                   tlkShares: tlkShares,
-                  preapprovedKeys: preapprovedKeys) { a, khr, views, policy, err in
+                  preapprovedKeys: preapprovedKeys) { a, khr, policy, err in
                     reta = a
                     retkhr = khr
-                    retviews = views
                     retpolicy = policy
                     reterr = err
                     expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reta, retkhr, retviews, retpolicy, reterr)
+        return (reta, retkhr, retpolicy, reterr)
     }
 
     func preapprovedJoinSync(test: XCTestCase,
                              ckksKeys: [CKKSKeychainBackedKeySet],
                              tlkShares: [CKKSTLKShare],
-                             preapprovedKeys: [Data]? = nil) -> (String?, [CKRecord]?, Set<String>?, TPPolicy?, Error?) {
+                             preapprovedKeys: [Data]? = nil) -> (String?, [CKRecord]?, TPSyncingPolicy?, Error?) {
         let expectation = XCTestExpectation(description: "preapprovedjoin replied")
         var reta: String?
         var retkhr: [CKRecord]?
-        var retviews: Set<String>?
-        var retpolicy: TPPolicy?
+        var retpolicy: TPSyncingPolicy?
         var reterr: Error?
         self.preapprovedJoin(ckksKeys: ckksKeys,
                              tlkShares: tlkShares,
-                             preapprovedKeys: preapprovedKeys) { a, khr, views, policy, err in
+                             preapprovedKeys: preapprovedKeys) { a, khr, policy, err in
                                 reta = a
                                 retkhr = khr
-                                retviews = views
                                 retpolicy = policy
                                 reterr = err
                                 expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reta, retkhr, retviews, retpolicy, reterr)
+        return (reta, retkhr, retpolicy, reterr)
     }
 
     func updateSync(test: XCTestCase,
                     deviceName: String? = nil,
-                    serialNumner: String? = nil,
+                    serialNumber: String? = nil,
                     osVersion: String? = nil,
                     policyVersion: UInt64? = nil,
-                    policySecrets: [String: Data]? = nil) -> (TrustedPeersHelperPeerState?, Error?) {
+                    policySecrets: [String: Data]? = nil,
+                    syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus? = nil) -> (TrustedPeersHelperPeerState?, TPSyncingPolicy?, Error?) {
         let expectation = XCTestExpectation(description: "update replied")
         var reterr: Error?
         var retstate: TrustedPeersHelperPeerState?
+        var retpolicy: TPSyncingPolicy?
         self.update(deviceName: deviceName,
-                    serialNumber: serialNumner,
+                    serialNumber: serialNumber,
                     osVersion: osVersion,
                     policyVersion: policyVersion,
-                    policySecrets: policySecrets) { state, err in
+                    policySecrets: policySecrets,
+                    syncUserControllableViews: syncUserControllableViews) { state, policy, err in
                         retstate = state
+                        retpolicy = policy
                         reterr = err
                         expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (retstate, reterr)
+        return (retstate, retpolicy, reterr)
     }
 
     func setAllowedMachineIDsSync(test: XCTestCase, allowedMachineIDs: Set<String>, accountIsDemo: Bool, listDifference: Bool = true) -> (Error?) {
@@ -318,21 +321,22 @@ extension Container {
         do {
             secret = try loadSecret(label: label)
         } catch {
-
         }
         return secret
     }
 
-    func setRecoveryKeySync(test: XCTestCase, recoveryKey: String, recoverySalt: String, ckksKeys: [CKKSKeychainBackedKeySet]) -> (Error?) {
+    func setRecoveryKeySync(test: XCTestCase, recoveryKey: String, recoverySalt: String, ckksKeys: [CKKSKeychainBackedKeySet]) -> ([CKRecord]?, Error?) {
         let expectation = XCTestExpectation(description: "setRecoveryKey replied")
+        var retrecords: [CKRecord]?
         var reterr: Error?
 
-        self.setRecoveryKey(recoveryKey: recoveryKey, salt: recoverySalt, ckksKeys: ckksKeys) { error in
+        self.setRecoveryKey(recoveryKey: recoveryKey, salt: recoverySalt, ckksKeys: ckksKeys) { records, error in
+            retrecords = records
             reterr = error
             expectation.fulfill()
         }
         test.wait(for: [expectation], timeout: 10.0)
-        return (reterr)
+        return (retrecords, reterr)
     }
 
     func fetchViableBottlesSync(test: XCTestCase) -> ([String]?, [String]?, Error?) {
@@ -381,6 +385,20 @@ extension Container {
         return (reta, reterr)
     }
 
+    func fetchCurrentPolicySync(test: XCTestCase) -> (TPSyncingPolicy?, TPPBPeerStableInfo_UserControllableViewStatus, Error?) {
+        let expectation = XCTestExpectation(description: "fetchCurrentPolicy replied")
+        var reta: TPSyncingPolicy?, reterr: Error?
+        var retOp: TPPBPeerStableInfo_UserControllableViewStatus = .UNKNOWN
+        self.fetchCurrentPolicy(modelIDOverride: nil) { a, peerOpinion, err in
+            reta = a
+            retOp = peerOpinion
+            reterr = err
+            expectation.fulfill()
+        }
+        test.wait(for: [expectation], timeout: 10.0)
+        return (reta, retOp, reterr)
+    }
+
     func fetchEscrowContentsSync(test: XCTestCase) -> (Data?, String?, Data?, Error?) {
         let expectation = XCTestExpectation(description: "fetchEscrowContents replied")
         var retentropy: Data?
index 23267a012df547dd3028458aa653894ae9568019..4236b8c338712556b596061a9a0ed4cf220973e0 100644 (file)
@@ -6,14 +6,9 @@
 //
 
 import CloudKitCode
+import CloudKitCodeProtobuf
 import Foundation
 
-enum FakeCuttlefishError: Error {
-    case notEmpty
-    case unknownChangeToken
-    case unknownPeerID
-}
-
 enum FakeCuttlefishOpinion {
     case trusts
     case trustsByPreapproval
@@ -70,6 +65,7 @@ struct FakeCuttlefishAssertion: CustomStringConvertible {
 class FakeCuttlefishNotify: NSObject {
     let pushes: (Data) -> Void
     let containerName: String
+
     @objc
     init(_ containerName: String, pushes: @escaping (Data) -> Void) {
         self.containerName = containerName
@@ -77,7 +73,7 @@ class FakeCuttlefishNotify: NSObject {
     }
 
     @objc
-    public func notify(_ function: String) throws {
+    func notify(_ function: String) throws {
         let notification: [String: [String: Any]] = [
             "aps": ["content-available": 1],
             "cf": [
@@ -168,12 +164,12 @@ extension TLKShare {
 }
 
 class FakeCuttlefishServer: CuttlefishAPIAsync {
-
     struct State {
         var peersByID: [String: Peer] = [:]
         var recoverySigningPubKey: Data?
         var recoveryEncryptionPubKey: Data?
         var bottles: [Bottle] = []
+        var escrowRecords: [EscrowInformation] = []
 
         var viewKeys: [CKRecordZone.ID: ViewKeys] = [:]
         var tlkShares: [CKRecordZone.ID: [TLKShare]] = [:]
@@ -194,6 +190,9 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
     // @property (nullable) NSMutableDictionary<CKRecordZoneID*, ZoneKeys*>* keys;
     var ckksZoneKeys: NSMutableDictionary
 
+    var injectLegacyEscrowRecords: Bool = false
+    var includeEscrowRecords: Bool = true
+
     var nextFetchErrors: [Error] = []
     var fetchViableBottlesError: [Error] = []
     var nextJoinErrors: [Error] = []
@@ -205,6 +204,9 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
     var returnLeaveTrustResponse: Bool = false
     var returnRepairErrorResponse: Error?
     var fetchChangesCalledCount: Int = 0
+    var fetchChangesReturnEmptyResponse: Bool = false
+
+    var fetchViableBottlesEscrowRecordCacheTimeout: TimeInterval = 2.0
 
     var nextEstablishReturnsMoreChanges: Bool = false
 
@@ -282,7 +284,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
                 }
             }
             snapshot.peersByID.forEach { (key: String, _: Peer) in
-                if nil == self.state.peersByID[key] {
+                if self.state.peersByID[key] == nil {
                     changes.differences.append(PeerDifference.with {
                         $0.remove = Peer.with {
                             $0.peerID = key
@@ -297,7 +299,6 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
             if self.state.recoveryEncryptionPubKey != snapshot.recoveryEncryptionPubKey {
                 changes.recoveryEncryptionPubKey = self.state.recoveryEncryptionPubKey ?? Data()
             }
-
         }
     }
 
@@ -410,7 +411,6 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
                 let record = share.fakeRecord(zoneID: rzid)
                 fakeZone.add(toZone: record)
                 allRecords.append(record)
-
             } else {
                 print("Received an unexpected zone id: \(rzid)")
             }
@@ -422,7 +422,7 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
     func establish(_ request: EstablishRequest, completion: @escaping (EstablishResponse?, Error?) -> Void) {
         print("FakeCuttlefish: establish called")
         if !self.state.peersByID.isEmpty {
-            completion(nil, FakeCuttlefishError.notEmpty)
+            completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .establishFailed))
         }
 
         // Before performing write, check if we should error
@@ -442,6 +442,38 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
 
         self.state.peersByID[request.peer.peerID] = request.peer
         self.state.bottles.append(request.bottle)
+        let escrowInformation = EscrowInformation.with {
+            $0.label = "com.apple.icdp.record." + request.bottle.bottleID
+            $0.creationDate = Google_Protobuf_Timestamp(date: Date())
+            $0.remainingAttempts = 10
+            $0.silentAttemptAllowed = 1
+            $0.recordStatus = .valid
+            let e = EscrowInformation.Metadata.with {
+                $0.backupKeybagDigest = Data()
+                $0.secureBackupUsesMultipleIcscs = 1
+                $0.secureBackupTimestamp = Google_Protobuf_Timestamp(date: Date())
+                $0.peerInfo = Data()
+                $0.bottleID = request.bottle.bottleID
+                $0.escrowedSpki = request.bottle.escrowedSigningSpki
+                let cm = EscrowInformation.Metadata.ClientMetadata.with {
+                    $0.deviceColor = "#202020"
+                    $0.deviceEnclosureColor = "#020202"
+                    $0.deviceModel = "model"
+                    $0.deviceModelClass = "modelClass"
+                    $0.deviceModelVersion = "modelVersion"
+                    $0.deviceMid = "mid"
+                    $0.deviceName = "my device"
+                    $0.devicePlatform = 1
+                    $0.secureBackupNumericPassphraseLength = 6
+                    $0.secureBackupMetadataTimestamp = Google_Protobuf_Timestamp(date: Date())
+                    $0.secureBackupUsesNumericPassphrase = 1
+                    $0.secureBackupUsesComplexPassphrase = 1
+                }
+                $0.clientMetadata = cm
+            }
+            $0.escrowInformationMetadata = e
+        }
+        self.state.escrowRecords.append(escrowInformation)
 
         var keyRecords: [CKRecord] = []
         keyRecords.append(contentsOf: store(viewKeys: request.viewKeys))
@@ -490,12 +522,43 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
         }
 
         guard let snapshot = self.snapshotsByChangeToken[request.changeToken] else {
-            completion(nil, FakeCuttlefishError.unknownChangeToken)
+            completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
             return
         }
         self.state.peersByID[request.peer.peerID] = request.peer
         self.state.bottles.append(request.bottle)
-
+        let escrowInformation = EscrowInformation.with {
+            $0.label = "com.apple.icdp.record." + request.bottle.bottleID
+            $0.creationDate = Google_Protobuf_Timestamp(date: Date())
+            $0.remainingAttempts = 10
+            $0.silentAttemptAllowed = 1
+            $0.recordStatus = .valid
+            let e = EscrowInformation.Metadata.with {
+                $0.backupKeybagDigest = Data()
+                $0.secureBackupUsesMultipleIcscs = 1
+                $0.secureBackupTimestamp = Google_Protobuf_Timestamp(date: Date())
+                $0.peerInfo = Data()
+                $0.bottleID = request.bottle.bottleID
+                $0.escrowedSpki = request.bottle.escrowedSigningSpki
+                let cm = EscrowInformation.Metadata.ClientMetadata.with {
+                    $0.deviceColor = "#202020"
+                    $0.deviceEnclosureColor = "#020202"
+                    $0.deviceModel = "model"
+                    $0.deviceModelClass = "modelClass"
+                    $0.deviceModelVersion = "modelVersion"
+                    $0.deviceMid = "mid"
+                    $0.deviceName = "my device"
+                    $0.devicePlatform = 1
+                    $0.secureBackupNumericPassphraseLength = 6
+                    $0.secureBackupMetadataTimestamp = Google_Protobuf_Timestamp(date: Date())
+                    $0.secureBackupUsesNumericPassphrase = 1
+                    $0.secureBackupUsesComplexPassphrase = 1
+                }
+                $0.clientMetadata = cm
+            }
+            $0.escrowInformationMetadata = e
+        }
+        self.state.escrowRecords.append(escrowInformation)
         var keyRecords: [CKRecord] = []
         keyRecords.append(contentsOf: store(viewKeys: request.viewKeys))
         keyRecords.append(contentsOf: store(tlkShares: request.tlkShares))
@@ -520,11 +583,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
         }
 
         guard let snapshot = self.snapshotsByChangeToken[request.changeToken] else {
-            completion(nil, FakeCuttlefishError.unknownChangeToken)
+            completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
             return
         }
         guard var peer = self.state.peersByID[request.peerID] else {
-            completion(nil, FakeCuttlefishError.unknownPeerID)
+            completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .updateTrustPeerNotFound))
             return
         }
         if request.hasStableInfoAndSig {
@@ -580,15 +643,21 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
         }
 
         guard let snapshot = self.snapshotsByChangeToken[request.changeToken] else {
-            completion(nil, FakeCuttlefishError.unknownChangeToken)
+            completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
             return
         }
         self.state.recoverySigningPubKey = request.recoverySigningPubKey
         self.state.recoveryEncryptionPubKey = request.recoveryEncryptionPubKey
         self.state.peersByID[request.peerID]?.stableInfoAndSig = request.stableInfoAndSig
+
+        var keyRecords: [CKRecord] = []
+        //keyRecords.append(contentsOf: store(viewKeys: request.viewKeys))
+        keyRecords.append(contentsOf: store(tlkShares: request.tlkShares))
+
         self.makeSnapshot()
         completion(SetRecoveryKeyResponse.with {
             $0.changes = self.changesSince(snapshot: snapshot)
+            $0.zoneKeyHierarchyRecords = keyRecords.map { try! CloudKitCode.Ckcode_RecordTransport($0) }
         }, nil)
         self.pushNotify("setRecoveryKey")
     }
@@ -604,6 +673,10 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
                 completion(nil, possibleError)
                 return
             }
+            if fetchChangesReturnEmptyResponse == true {
+                completion(FetchChangesResponse(), nil)
+                return
+            }
         }
 
         if let injectedError = self.nextFetchErrors.first {
@@ -614,11 +687,11 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
         }
 
         let snapshot: State
-        if request.changeToken == "" {
+        if request.changeToken.isEmpty {
             snapshot = State()
         } else {
             guard let s = self.snapshotsByChangeToken[request.changeToken] else {
-                completion(nil, FakeCuttlefishError.unknownChangeToken)
+                completion(nil, FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
                 return
             }
             snapshot = s
@@ -648,14 +721,29 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
             return
         }
 
+        var legacy: [EscrowInformation] = []
+        if self.injectLegacyEscrowRecords {
+            print("FakeCuttlefish: fetchViableBottles injecting legacy records")
+            let record = EscrowInformation.with {
+                $0.label = "fake-label"
+            }
+            legacy.append(record)
+        }
         let bottles = self.state.bottles.filter { $0.bottleID != fetchViableBottlesDontReturnBottleWithID }
+
         completion(FetchViableBottlesResponse.with {
             $0.viableBottles = bottles.compactMap { bottle in
                 EscrowPair.with {
                     $0.escrowRecordID = bottle.bottleID
                     $0.bottle = bottle
+                    if self.includeEscrowRecords {
+                        $0.record = self.state.escrowRecords.first { $0.escrowInformationMetadata.bottleID == bottle.bottleID } ?? EscrowInformation()
+                    }
                 }
             }
+            if self.injectLegacyEscrowRecords {
+                $0.legacyRecords = legacy
+            }
         }, nil)
     }
 
@@ -754,6 +842,10 @@ class FakeCuttlefishServer: CuttlefishAPIAsync {
     func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) {
         completion(GetSupportAppInfoResponse(), nil)
     }
+
+    func fetchSosiCloudIdentity(_: FetchSOSiCloudIdentityRequest, completion: @escaping (FetchSOSiCloudIdentityResponse?, Error?) -> Void) {
+        completion(FetchSOSiCloudIdentityResponse(), nil)
+    }
 }
 
 extension FakeCuttlefishServer: CloudKitCode.Invocable {
index 8289a40e72c175389b8198c45e34efaade23f85b..083d98beb694901207df645f12301b1bb29c40f7 100644 (file)
@@ -21,7 +21,6 @@ enum Handler {
 }
 
 class MockCuttlefishAPIAsyncClient: CuttlefishAPIAsync {
-
     var handlers: [Handler] = []
     var index: Int = 0
 
@@ -164,7 +163,6 @@ class MockCuttlefishAPIAsyncClient: CuttlefishAPIAsync {
     }
     func getRepairAction(_: GetRepairActionRequest, completion: @escaping (GetRepairActionResponse?, Error?) -> Void) {
         completion(GetRepairActionResponse(), nil)
-
     }
     func getSupportAppInfo(_: GetSupportAppInfoRequest, completion: @escaping (GetSupportAppInfoResponse?, Error?) -> Void) {
         completion(GetSupportAppInfoResponse(), nil)
@@ -172,4 +170,7 @@ class MockCuttlefishAPIAsyncClient: CuttlefishAPIAsync {
     func getClubCertificates(_: GetClubCertificatesRequest, completion: @escaping (GetClubCertificatesResponse?, Error?) -> Void) {
         completion(GetClubCertificatesResponse(), nil)
     }
+    func fetchSosiCloudIdentity(_: FetchSOSiCloudIdentityRequest, completion: @escaping (FetchSOSiCloudIdentityResponse?, Error?) -> Void) {
+        completion(FetchSOSiCloudIdentityResponse(), nil)
+    }
 }
index fc2d9223c873e1494b8d4b75af4ae2d0c942d9a2..9753ef8dd5ae650e0198a99a008625a62c88a5e0 100644 (file)
@@ -19,5 +19,6 @@
 #import <SecurityFoundation/SFKey_Private.h>
 
 #import "keychain/TrustedPeersHelper/TrustedPeersHelper-Bridging-Header.h"
+#import "keychain/securityd/SecItemDataSource.h"
 
 #import "keychain/ckks/tests/MockCloudKit.h"
index c5f2b3f766198b5cbce28b824de734e3e275fb1b..1ed9145c2b033b77c1220b0ab04ca0da000f3778 100644 (file)
@@ -5,6 +5,7 @@
 //  Created by Ben Williamson on 5/1/18.
 //
 
+import CloudKitCodeProtobuf
 import CoreData
 import XCTest
 
@@ -21,7 +22,6 @@ let recovery_signingKey_384 = Data(base64Encoded: "BK5nrmP6oitJHtGV2Josk5cUKnG3p
 let recovery_encryptionKey_384 = Data(base64Encoded: "BKkZpYHTbMi2yrWFo+ErM3HbcYJCngPuWDYoVUD7egKkmiHFvv1Bsk0j/Dcj3xTR12vj5QOpZQV3GzE5estf75BV+EZz1cjUUSi/MysfpKsqEbwYrhIEkmeyMGr7CVWQWRLR2LnoihnQajvWi1LmO0AoDl3+LzVgTJBjjDQ5ANyw0Yv1EgOgBvZsLA9UTN4oAg==")
 
 class TrustedPeersHelperUnitTests: XCTestCase {
-
     var tmpPath: String!
     var tmpURL: URL!
     var cuttlefish: FakeCuttlefishServer!
@@ -46,7 +46,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         cuttlefish = FakeCuttlefishServer(nil, ckZones: [:], ckksZoneKeys: [:])
 
         // Make a new fake keychain
-        tmpPath = String(format: "/tmp/%@-%X", testName, arc4random())
+        tmpPath = String(format: "/tmp/%@-%X", testName, Int.random(in: 0..<1000000))
         tmpURL = URL(fileURLWithPath: tmpPath, isDirectory: true)
         do {
             try FileManager.default.createDirectory(atPath: String(format: "%@/Library/Keychains", tmpPath), withIntermediateDirectories: true, attributes: nil)
@@ -72,6 +72,23 @@ class TrustedPeersHelperUnitTests: XCTestCase {
     override func tearDown() {
         // Put teardown code here. This method is called after the invocation of each test method in the class.
         cuttlefish = nil
+
+        if let nskeychainDir : NSURL = SecCopyHomeURL(), let keychainDir : URL = nskeychainDir as URL? {
+            SecItemDataSourceFactoryReleaseAll()
+            SecKeychainDbForceClose()
+            SecKeychainDbReset(nil)
+
+            // Only perform the destructive step if the url matches what we expect!
+            let testName = self.name.components(separatedBy: CharacterSet(charactersIn: " ]"))[1]
+            if keychainDir.path.hasPrefix("/tmp/" + testName) {
+                do {
+                    try FileManager.default.removeItem(at: keychainDir)
+                } catch {
+                    print("Failed to remove keychain directory: \(error)")
+                }
+            }
+        }
+
         super.tearDown()
     }
 
@@ -164,15 +181,24 @@ class TrustedPeersHelperUnitTests: XCTestCase {
                    contextID: String,
                    allowedMachineIDs: Set<String> = Set(["aaa", "bbb", "ccc"]),
                    accountIsDemo: Bool,
+                   modelID: String = "iPhone1,1",
+                   syncUserControllableViews: TPPBPeerStableInfo_UserControllableViewStatus = .UNKNOWN,
                    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: allowedMachineIDs, accountIsDemo: accountIsDemo, listDifference: !allowedMachineIDs.isEmpty), "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")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self,
+                                                                                              epoch: 1,
+                                                                                              machineID: "aaa",
+                                                                                              bottleSalt: "123456789",
+                                                                                              bottleID: UUID().uuidString,
+                                                                                              modelID: modelID,
+                                                                                              syncUserControllableViews: syncUserControllableViews)
+
         do {
             let state = container.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == peerID }, "should have a bottle for peer")
             let secret = container.loadSecretSync(test: self, label: peerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -192,7 +218,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             }
         }
 
-        let (peerID2, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+        let (peerID2, _, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
         XCTAssertNil(error2)
         XCTAssertNotNil(peerID2)
 
@@ -203,24 +229,97 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
     func testEstablishWithReload() throws {
         let description = tmpStoreDescription(name: "container.db")
-        let (_, peerID) = try establish(reload: true, store: description)
+        let (container, peerID) = try establish(reload: true, store: description)
 
         assertTLKShareFor(peerID: peerID, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+        // With no other input, the syncing policy should say to sync user views
+        let (policy, _, policyError) = container.fetchCurrentPolicySync(test: self)
+        XCTAssertNil(policyError, "Should be no error fetching aPolicy")
+        XCTAssertNotNil(policy, "Should have a syncing policy")
+        XCTAssertEqual(policy?.syncUserControllableViews, .DISABLED, "Peer should not desire to sync user controllable views (as the client didn't have any input)")
     }
 
     func testEstablishNoReload() throws {
         let description = tmpStoreDescription(name: "container.db")
-        _ = try establish(reload: false, store: description)
+        let (container, peerID) = try establish(reload: false, store: description)
+
+        assertTLKShareFor(peerID: peerID, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+        // With no other input, the syncing policy should say to sync user views
+        let (policy, _, policyError) = container.fetchCurrentPolicySync(test: self)
+        XCTAssertNil(policyError, "Should be no error fetching aPolicy")
+        XCTAssertNotNil(policy, "Should have a syncing policy")
+        XCTAssertEqual(policy?.syncUserControllableViews, .DISABLED, "Peer should not desire to sync user controllable views (as the client didn't have any input)")
+    }
+
+    func testEstablishWithUserSyncableViews() throws {
+        let description = tmpStoreDescription(name: "container.db")
+
+        let (container, peerID) = try self.establish(reload: false,
+                                                     contextID: OTDefaultContext,
+                                                     accountIsDemo: false,
+                                                     syncUserControllableViews: .ENABLED,
+                                                     store: description)
+
+        assertTLKShareFor(peerID: peerID, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+        //The syncing policy should say not to sync user views
+        let (policy, _, policyError) = container.fetchCurrentPolicySync(test: self)
+        XCTAssertNil(policyError, "Should be no error fetching aPolicy")
+        XCTAssertNotNil(policy, "Should have a syncing policy")
+
+        XCTAssertEqual(policy?.syncUserControllableViews, .ENABLED, "Peer should desire to sync user controllable views (per request)")
+    }
+
+    func testEstablishWithoutUserSyncableViews() throws {
+        let description = tmpStoreDescription(name: "container.db")
+
+        let (container, peerID) = try self.establish(reload: false,
+                                                     contextID: OTDefaultContext,
+                                                     accountIsDemo: false,
+                                                     syncUserControllableViews: .DISABLED,
+                                                     store: description)
+
+        assertTLKShareFor(peerID: peerID, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+        //The syncing policy should say not to sync user views
+        let (policy, _, policyError) = container.fetchCurrentPolicySync(test: self)
+        XCTAssertNil(policyError, "Should be no error fetching aPolicy")
+        XCTAssertNotNil(policy, "Should have a syncing policy")
+
+        XCTAssertEqual(policy?.syncUserControllableViews, .DISABLED, "Peer should not desire to sync user controllable views (per request)")
+    }
+
+    func testEstablishWithoutUserSyncableViewsOnWatch() throws {
+        let description = tmpStoreDescription(name: "container.db")
+
+        // Watches will listen to the input here. If we set FOLLOWING, it should remain FOLLOWING (as some watches don't have UI to change this value)
+        let (container, peerID) = try self.establish(reload: false,
+                                                     contextID: OTDefaultContext,
+                                                     accountIsDemo: false,
+                                                     modelID: "Watch1,1",
+                                                     syncUserControllableViews: .FOLLOWING,
+                                                     store: description)
+
+        assertTLKShareFor(peerID: peerID, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+        //The syncing policy should say not to sync user views
+        let (policy, _, policyError) = container.fetchCurrentPolicySync(test: self)
+        XCTAssertNil(policyError, "Should be no error fetching aPolicy")
+        XCTAssertNotNil(policy, "Should have a syncing policy")
+
+        XCTAssertEqual(policy?.syncUserControllableViews, .FOLLOWING, "Peer should desire to sync user controllable views (ignoring the request)")
     }
 
     func testEstablishNotOnAllowListErrors() throws {
         let description = tmpStoreDescription(name: "container.db")
         let container = try Container(name: ContainerName(container: "test", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish)
 
-        let (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = container.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == peerID }, "should have a bottle for peer")
             let secret = container.loadSecretSync(test: self, label: peerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -235,7 +334,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         // Now set up a machine ID list that positively does not have our peer
         XCTAssertNil(container.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["aaa"], accountIsDemo: false), "should be able to set allowed machine IDs")
 
-        let (peerID3, _, error3) = container.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+        let (peerID3, _, _, error3) = container.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
         XCTAssertNotNil(peerID3, "Should get a peer when you establish a now allow-listed peer")
         XCTAssertNil(error3, "Should not get an error when you establish a now allow-listed peer")
     }
@@ -253,7 +352,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: accountIsDemo, listDifference: !machineIDs.isEmpty), "Should be able to set machine IDs")
 
         print("preparing \(containerID)")
-        let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error) =
+        let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error) =
             c.prepareSync(test: self, epoch: 1, machineID: machineID, bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         XCTAssertNil(error)
         XCTAssertNotNil(peerID)
@@ -282,11 +381,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: peerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("\(containerID) joins")
-            let (joinedPeerID, _, _, _, joinError) = c.joinSync(test: self,
-                                                                voucherData: voucherData!,
-                                                                voucherSig: voucherSig!,
-                                                                ckksKeys: [],
-                                                                tlkShares: [])
+            let (joinedPeerID, _, _, joinError) = c.joinSync(test: self,
+                                                             voucherData: voucherData!,
+                                                             voucherSig: voucherSig!,
+                                                             ckksKeys: [],
+                                                             tlkShares: [])
             XCTAssertNil(joinError)
             XCTAssertEqual(joinedPeerID, peerID!)
         }
@@ -306,15 +405,15 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerC.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aViewList, aPolicy, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aPolicy, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
-        XCTAssertNotNil(aViewList, "Should have a view list coming back from a successful prepare")
-        XCTAssertNotNil(aPolicy, "Should have a policy coming back from a successful prepare")
+        XCTAssertNotNil(aPolicy, "Should have a syncing policy coming back from a successful prepare")
         XCTAssertEqual(aPolicy?.version, prevailingPolicyVersion, "Policy coming back from prepare() should be prevailing policy version")
+        XCTAssertEqual(aPolicy?.syncUserControllableViews, .UNKNOWN, "Policy coming back from prepare() should not have an opinion on views")
 
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -326,17 +425,25 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
 
+        do {
+            // With no other input, the syncing policy should say to sync user views
+            let (aPolicy, _, aPolicyError) = containerA.fetchCurrentPolicySync(test: self)
+            XCTAssertNil(aPolicyError, "Should be no error fetching aPolicy")
+            XCTAssertNotNil(aPolicy, "Should have a syncing policy")
+            XCTAssertEqual(aPolicy?.syncUserControllableViews, .DISABLED, "Peer should desire to not sync user controllable views (as the client didn't have any input)")
+        }
+
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _, error2) =
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -392,13 +499,16 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self,
-                                                               voucherData: voucherData!,
-                                                               voucherSig: voucherSig!,
-                                                               ckksKeys: [],
-                                                               tlkShares: [])
+            let (peerID, _, bPolicy, error) = containerB.joinSync(test: self,
+                                                                  voucherData: voucherData!,
+                                                                  voucherSig: voucherSig!,
+                                                                  ckksKeys: [],
+                                                                  tlkShares: [])
             XCTAssertNil(error)
             XCTAssertEqual(peerID, bPeerID!)
+
+            XCTAssertNotNil(bPolicy, "Should have a syncing policy")
+            XCTAssertEqual(bPolicy?.syncUserControllableViews, .DISABLED, "Peer should desire to not sync user controllable views (following A's lead)")
         }
 
         _ = containerA.dumpSync(test: self)
@@ -406,11 +516,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerC.dumpSync(test: self)
 
         print("preparing C")
-        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, _, error4) =
+        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, error4) =
             containerC.prepareSync(test: self, epoch: 1, machineID: "ccc", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerC.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == cPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == cPeerID }, "should have a bottle for peer")
             let secret = containerC.loadSecretSync(test: self, label: cPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -444,14 +554,17 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: cPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("C joins")
-            let (peerID, _, _, _, error2) = containerC.joinSync(test: self,
-                                                                voucherData: voucherData!,
-                                                                voucherSig: voucherSig!,
-                                                                ckksKeys: [self.manateeKeySet, provisionalEngramKeySet],
-                                                                tlkShares: [])
+            let (peerID, _, cPolicy, error2) = containerC.joinSync(test: self,
+                                                                   voucherData: voucherData!,
+                                                                   voucherSig: voucherSig!,
+                                                                   ckksKeys: [self.manateeKeySet, provisionalEngramKeySet],
+                                                                   tlkShares: [])
             XCTAssertNil(error2)
             XCTAssertEqual(peerID, cPeerID!)
 
+            XCTAssertNotNil(cPolicy, "Should have a syncing policy")
+            XCTAssertEqual(cPolicy?.syncUserControllableViews, .DISABLED, "Peer should desire to not sync user controllable views (following A and B's lead)")
+
             assertTLKShareFor(peerID: cPeerID!, keyUUID: provisionalEngramKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Engram"))
             assertTLKShareFor(peerID: aPeerID!, keyUUID: provisionalEngramKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Engram"))
             assertTLKShareFor(peerID: bPeerID!, keyUUID: provisionalEngramKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Engram"))
@@ -459,7 +572,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("A updates")
         do {
-            let (_, error) = containerA.updateSync(test: self)
+            let (_, _, error) = containerA.updateSync(test: self)
             XCTAssertNil(error)
         }
 
@@ -474,15 +587,130 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerC.dumpSync(test: self)
     }
 
+    func testJoinWithEnabledUserControllableViews() throws {
+        let description = tmpStoreDescription(name: "container.db")
+        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", "ccc"])
+        XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
+        XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
+
+        print("preparing A")
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aPolicy, error) =
+            containerA.prepareSync(test: self,
+                                   epoch: 1,
+                                   machineID: "aaa",
+                                   bottleSalt: "123456789",
+                                   bottleID: UUID().uuidString,
+                                   modelID: "iPhone1,1",
+                                   syncUserControllableViews: .ENABLED)
+        XCTAssertNotNil(aPolicy, "Should have a syncing policy coming back from a successful prepare")
+        XCTAssertEqual(aPolicy?.version, prevailingPolicyVersion, "Policy coming back from prepare() should be prevailing policy version")
+        XCTAssertEqual(aPolicy?.syncUserControllableViews, .ENABLED, "Policy coming back from prepare() should already have an opinion of user view syncing")
+
+        XCTAssertNil(error)
+        XCTAssertNotNil(aPeerID)
+        XCTAssertNotNil(aPermanentInfo)
+        XCTAssertNotNil(aPermanentInfoSig)
+
+        print("establishing A")
+        do {
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            XCTAssertNil(error)
+            XCTAssertNotNil(peerID)
+        }
+
+        do {
+            let (aPolicy, _, aPolicyError) = containerA.fetchCurrentPolicySync(test: self)
+            XCTAssertNil(aPolicyError, "Should be no error fetching aPolicy")
+            XCTAssertNotNil(aPolicy, "Should have a syncing policy")
+            XCTAssertEqual(aPolicy?.syncUserControllableViews, .ENABLED, "Peer should desire to sync user controllable views (as per request)")
+        }
+
+        print("preparing B")
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, error2) =
+            containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        do {
+            let state = containerB.getStateSync(test: self)
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
+            let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
+            XCTAssertNotNil(secret, "secret should not be nil")
+            XCTAssertNil(error, "error should be nil")
+        }
+        XCTAssertNil(error2)
+        XCTAssertNotNil(bPeerID)
+        XCTAssertNotNil(bPermanentInfo)
+        XCTAssertNotNil(bPermanentInfoSig)
+
+        do {
+            assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+            print("A vouches for B, but doesn't provide any TLKShares")
+            let (_, _, errorVouchingWithoutTLKs) =
+                containerA.vouchSync(test: self,
+                                     peerID: bPeerID!,
+                                     permanentInfo: bPermanentInfo!,
+                                     permanentInfoSig: bPermanentInfoSig!,
+                                     stableInfo: bStableInfo!,
+                                     stableInfoSig: bStableInfoSig!,
+                                     ckksKeys: [])
+            XCTAssertNil(errorVouchingWithoutTLKs, "Should be no error vouching without uploading TLKShares")
+            assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+            print("A vouches for B, but doesn't only has provisional TLKs at the time")
+            let provisionalManateeKeySet = try self.makeFakeKeyHierarchy(zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+            provisionalManateeKeySet.newUpload = true
+
+            let (_, _, errorVouchingWithProvisionalTLKs) =
+                containerA.vouchSync(test: self,
+                                     peerID: bPeerID!,
+                                     permanentInfo: bPermanentInfo!,
+                                     permanentInfoSig: bPermanentInfoSig!,
+                                     stableInfo: bStableInfo!,
+                                     stableInfoSig: bStableInfoSig!,
+                                     ckksKeys: [provisionalManateeKeySet])
+            XCTAssertNil(errorVouchingWithProvisionalTLKs, "Should be no error vouching without uploading TLKShares for a non-existent key")
+            assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+            print("A vouches for B")
+            let (voucherData, voucherSig, error3) =
+                containerA.vouchSync(test: self,
+                                     peerID: bPeerID!,
+                                     permanentInfo: bPermanentInfo!,
+                                     permanentInfoSig: bPermanentInfoSig!,
+                                     stableInfo: bStableInfo!,
+                                     stableInfoSig: bStableInfoSig!,
+                                     ckksKeys: [self.manateeKeySet])
+            XCTAssertNil(error3)
+            XCTAssertNotNil(voucherData)
+            XCTAssertNotNil(voucherSig)
+
+            // As part of the vouch, A should have uploaded a tlkshare for B
+            assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+            print("B joins")
+            let (peerID, _, bPolicy, error) = containerB.joinSync(test: self,
+                                                                  voucherData: voucherData!,
+                                                                  voucherSig: voucherSig!,
+                                                                  ckksKeys: [],
+                                                                  tlkShares: [])
+            XCTAssertNil(error)
+            XCTAssertEqual(peerID, bPeerID!)
+
+            XCTAssertNotNil(bPolicy, "Should have a syncing policy")
+            XCTAssertEqual(bPolicy?.syncUserControllableViews, .ENABLED, "Peer should desire to sync user controllable views (following A's lead)")
+        }
+    }
+
     func testJoinWithoutAllowListErrors() throws {
         let description = tmpStoreDescription(name: "container.db")
         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 (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == peerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: peerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -494,16 +722,16 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: ["aaa"], accountIsDemo: false), "should be able to set allowed machine IDs")
 
-        let (peerID2, _, error2) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+        let (peerID2, _, _, error2) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
         XCTAssertNotNil(peerID2, "Should get a peer when you establish a now allow-listed peer")
         XCTAssertNil(error2, "Should not get an error when you establish a now allow-listed peer")
 
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _, errorPrepareB) =
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, errorPrepareB) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == peerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: peerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -530,11 +758,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             XCTAssertNotNil(voucherSig, "Should have a signature from A")
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self,
-                                                               voucherData: voucherData!,
-                                                               voucherSig: voucherSig!,
-                                                               ckksKeys: [],
-                                                               tlkShares: [])
+            let (peerID, _, _, error) = containerB.joinSync(test: self,
+                                                            voucherData: voucherData!,
+                                                            voucherSig: voucherSig!,
+                                                            ckksKeys: [],
+                                                            tlkShares: [])
             XCTAssertNotNil(error, "Should have an error joining with an unapproved machine ID")
             XCTAssertNil(peerID, "Should not receive a peer ID joining with an unapproved machine ID")
         }
@@ -548,10 +776,10 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -564,7 +792,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         print("establishing A")
         do {
             assertNoTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
             assertTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
@@ -591,10 +819,10 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let machineIDs = Set(["aaa"])
         XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -619,6 +847,8 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             let error = containerA.localResetSync(test: self)
             XCTAssertNil(error, "local-reset shouldn't error")
+            let peers = containerA.containerMO.peers as! Set<PeerMO>
+            XCTAssertEqual(peers.count, 0, "peers should be empty ")
         }
         do {
             let (dict, error) = containerA.dumpSync(test: self)
@@ -645,24 +875,24 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerC.setAllowedMachineIDsSync(test: self, allowedMachineIDs: Set(["aaa", "bbb", "ccc"]), accountIsDemo: false))
 
         print("preparing")
-        let (peerID, _, _, _, _, _, _, _) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, _, _, _, _, _, _) = containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == peerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: peerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
         }
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _, _) = containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _) = containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
         }
-        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, _, _) = containerC.prepareSync(test: self, epoch: 1, machineID: "ccc", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, _) = containerC.prepareSync(test: self, epoch: 1, machineID: "ccc", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerC.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == cPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == cPeerID }, "should have a bottle for peer")
             let secret = containerC.loadSecretSync(test: self, label: cPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
         }
@@ -747,7 +977,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
     // TODO: need a real configurable mock cuttlefish
     func testFetchPolicyDocuments() throws {
-
         // 1 is known locally via builtin, 3 is not but is known to cuttlefish
 
         let missingTuple = TPPolicyVersion(version: 900, hash: "not a hash")
@@ -808,7 +1037,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
     }
 
     func testEscrowKeys() throws {
-
         XCTAssertThrowsError(try EscrowKeys.retrieveEscrowKeysFromKeychain(label: "hash"), "retrieveEscrowKeysFromKeychain should throw error")
         XCTAssertThrowsError(try EscrowKeys.findEscrowKeysForLabel(label: "hash"), "findEscrowKeysForLabel should throw error")
 
@@ -843,7 +1071,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
     }
 
     func testEscrowKeyTestVectors() {
-
         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)
@@ -911,11 +1138,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
 
             bottleA = state.bottles.removeFirst()
 
@@ -930,14 +1157,14 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         print("establishing A")
         do {
             assertNoTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
             assertTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -947,11 +1174,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -961,10 +1188,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B prepares to join via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNotNil(views, "Should have a set of views to restore")
             XCTAssertNotNil(policy, "Should have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: [])
@@ -977,7 +1203,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            let (peerID, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
             XCTAssertNil(error)
             XCTAssertEqual(peerID, bPeerID!)
 
@@ -998,11 +1224,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
 
             bottleA = state.bottles.removeFirst()
 
@@ -1017,14 +1243,14 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         print("establishing A")
         do {
             assertNoTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
             assertTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1034,11 +1260,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1048,10 +1274,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B prepares to join via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNotNil(views, "Should have a set of views to restore")
             XCTAssertNotNil(policy, "Should have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: [])
@@ -1064,7 +1289,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            let (peerID, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
             XCTAssertNil(error)
             XCTAssertEqual(peerID, bPeerID!)
 
@@ -1084,11 +1309,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1100,13 +1325,13 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1116,11 +1341,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1130,10 +1355,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B joins via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: "wrong escrow record")
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNil(views, "Should not have a set of views to restore")
             XCTAssertNil(policy, "Should not have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: "wrong escrow record", entropy: entropy, bottleSalt: "123456789", tlkShares: [])
@@ -1156,11 +1380,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1172,13 +1396,13 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1186,11 +1410,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         }
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             bottleB = state.bottles.removeFirst()
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1201,10 +1425,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B joins via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleB.bottleID!)
+            let (bottlePeerID, policy, _, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleB.bottleID!)
             XCTAssertNotNil(errorPreflight, "Should be an error preflighting bottle that doesn't correspond to a peer")
             XCTAssertNil(bottlePeerID, "Should have no peer for invalid bottle")
-            XCTAssertNil(views, "Should not have a set of views to restore")
             XCTAssertNil(policy, "Should not have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleB.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: [])
@@ -1227,11 +1450,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             bottleA = state.bottles.removeFirst()
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1244,13 +1467,13 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1260,11 +1483,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1274,10 +1497,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B joins via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNotNil(views, "Should have a set of views to restore")
             XCTAssertNotNil(policy, "Should have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "987654321", tlkShares: [])
@@ -1299,11 +1521,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             bottleA = state.bottles.removeFirst()
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1316,13 +1538,13 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1331,11 +1553,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1345,10 +1567,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B joins via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNotNil(views, "Should have a set of views to restore")
             XCTAssertNotNil(policy, "Should have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: Data(count: Int(OTMasterSecretLength)), bottleSalt: "123456789", tlkShares: [])
@@ -1371,11 +1592,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             bottleA = state.bottles.removeFirst()
@@ -1389,24 +1610,24 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
         }
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1418,10 +1639,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
             self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNil(views, "Should not have a set of views to restore")
             XCTAssertNil(policy, "Should not have a policy")
 
             self.cuttlefish.fetchViableBottlesError.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
@@ -1438,29 +1658,37 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let description = tmpStoreDescription(name: "container.db")
         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 containerC = try Container(name: ContainerName(container: "c", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish)
 
-        let machineIDs = Set(["aaa", "bbb"])
+        let machineIDs = Set(["aaa", "bbb", "ccc"])
         XCTAssertNil(containerA.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
+        XCTAssertNil(containerC.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aViewList, aPolicy, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aPolicy, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         XCTAssertNil(error)
         XCTAssertNotNil(aPeerID)
         XCTAssertNotNil(aPermanentInfo)
         XCTAssertNotNil(aPermanentInfoSig)
 
-        XCTAssertNotNil(aViewList, "Should have a view list coming back from a successful prepare")
         XCTAssertNotNil(aPolicy, "Should have a policy coming back from a successful prepare")
         XCTAssertEqual(aPolicy?.version, prevailingPolicyVersion, "Policy coming back from prepare() should be prevailing policy version")
+        XCTAssertEqual(aPolicy?.syncUserControllableViews, .UNKNOWN, "Policy shouldn't yet know whether we want to sync user views")
 
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, _, _, _, _, error2) =
-            containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, _, _, _, error2) =
+            containerB.prepareSync(test: self,
+                                   epoch: 1,
+                                   machineID: "bbb",
+                                   bottleSalt: "123456789",
+                                   bottleID: UUID().uuidString,
+                                   modelID: "iPhone1,1",
+                                   syncUserControllableViews: .DISABLED)
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1470,34 +1698,96 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNotNil(bPermanentInfo)
         XCTAssertNotNil(bPermanentInfoSig)
 
-        // Now, A establishes preapproving B
+        print("preparing C")
+        let (cPeerID, cPermanentInfo, cPermanentInfoSig, _, _, _, cPrepareError) =
+            containerC.prepareSync(test: self,
+                                   epoch: 1,
+                                   machineID: "ccc",
+                                   bottleSalt: "123456789",
+                                   bottleID: UUID().uuidString,
+                                   modelID: "iPhone1,1",
+                                   syncUserControllableViews: .ENABLED)
+        do {
+            let state = containerC.getStateSync(test: self)
+            XCTAssertTrue(state.bottles.contains { $0.peerID == cPeerID }, "should have a bottle for peer")
+            let secret = containerC.loadSecretSync(test: self, label: cPeerID!)
+            XCTAssertNotNil(secret, "secret should not be nil")
+            XCTAssertNil(error, "error should be nil")
+        }
+        XCTAssertNil(cPrepareError)
+        XCTAssertNotNil(cPeerID)
+        XCTAssertNotNil(cPermanentInfo)
+        XCTAssertNotNil(cPermanentInfoSig)
+
+        // Now, A establishes preapproving B & C
         // Note: secd is responsible for passing in TLKShares to these preapproved keys in sosTLKShares
 
+        let aPermanentInfoParsed = TPPeerPermanentInfo(peerID: aPeerID!, data: aPermanentInfo!, sig: aPermanentInfoSig!, keyFactory: TPECPublicKeyFactory())
+        XCTAssertNotNil(aPermanentInfoParsed, "Should have parsed A's permanent info")
+
         let bPermanentInfoParsed = TPPeerPermanentInfo(peerID: bPeerID!, data: bPermanentInfo!, sig: bPermanentInfoSig!, keyFactory: TPECPublicKeyFactory())
         XCTAssertNotNil(bPermanentInfoParsed, "Should have parsed B's permanent info")
 
+        let cPermanentInfoParsed = TPPeerPermanentInfo(peerID: cPeerID!, data: cPermanentInfo!, sig: cPermanentInfoSig!, keyFactory: TPECPublicKeyFactory())
+        XCTAssertNotNil(cPermanentInfoParsed, "Should have parsed C's permanent info")
+
+        print(bPermanentInfoParsed!.signingPubKey.spki().base64EncodedString())
+        print(cPermanentInfoParsed!.signingPubKey.spki().base64EncodedString())
+
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [bPermanentInfoParsed!.signingPubKey.spki()])
+            let (peerID, _, _, error) = containerA.establishSync(test: self,
+                                                                 ckksKeys: [self.manateeKeySet],
+                                                                 tlkShares: [],
+                                                                 preapprovedKeys: [bPermanentInfoParsed!.signingPubKey.spki(),
+                                                                                   cPermanentInfoParsed!.signingPubKey.spki(), ])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
+
+            let (aPolicy, _, aPolicyError) = containerA.fetchCurrentPolicySync(test: self)
+            XCTAssertNil(aPolicyError, "Should be no error fetching aPolicy")
+            XCTAssertNotNil(aPolicy, "Should have a syncing policy")
+            XCTAssertEqual(aPolicy?.syncUserControllableViews, .DISABLED, "A should desire to not ync user controllable views (as the client didn't have any input)")
         }
 
         do {
             assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins by preapproval, and uploads all TLKShares that it has")
-            let (bJoinedPeerID, _, views, policy, bJoinedError) = containerB.preapprovedJoinSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            let (bJoinedPeerID, _, bPolicy, bJoinedError) = containerB.preapprovedJoinSync(test: self,
+                                                                                          ckksKeys: [self.manateeKeySet],
+                                                                                          tlkShares: [],
+                                                                                          preapprovedKeys: [aPermanentInfoParsed!.signingPubKey.spki(),
+                                                                                                            cPermanentInfoParsed!.signingPubKey.spki(), ])
             XCTAssertNil(bJoinedError, "Should be no error joining by preapproval")
             XCTAssertNotNil(bJoinedPeerID, "Should have a peer ID out of join")
-            XCTAssertNotNil(views, "should have a list of views to use")
-            XCTAssertNotNil(policy, "Should have a policy back from preapprovedjoin")
+            XCTAssertNotNil(bPolicy, "Should have a policy back from preapprovedjoin")
+            XCTAssertEqual(bPolicy?.syncUserControllableViews, .DISABLED, "Policy should say not to sync user controllable views")
 
             assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
         }
 
+        do {
+            assertNoTLKShareFor(peerID: cPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+            print("B joins by preapproval, and uploads all TLKShares that it has")
+            let (cJoinedPeerID, _, cPolicy, cJoinedError) = containerC.preapprovedJoinSync(test: self,
+                                                                                          ckksKeys: [self.manateeKeySet],
+                                                                                          tlkShares: [],
+                                                                                          preapprovedKeys: [aPermanentInfoParsed!.signingPubKey.spki(),
+                                                                                                            bPermanentInfoParsed!.signingPubKey.spki(), ])
+            XCTAssertNil(cJoinedError, "Should be no error joining by preapproval")
+            XCTAssertNotNil(cJoinedPeerID, "Should have a peer ID out of join")
+            XCTAssertEqual(cPeerID, cJoinedPeerID, "PeerID after joining should match")
+            XCTAssertNotNil(cPolicy, "Should have a policy back from preapprovedjoin")
+            XCTAssertEqual(cPolicy?.syncUserControllableViews, .ENABLED, "Policy should say to sync user controllable views")
+
+            assertTLKShareFor(peerID: cPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+        }
+
         _ = containerA.dumpSync(test: self)
         _ = containerB.dumpSync(test: self)
+        _ = containerC.dumpSync(test: self)
     }
 
     func testDepart() throws {
@@ -1524,7 +1814,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
                                               machineIDs: ["aaa", "bbb", "ccc"], accountIsDemo: false,
                                               store: store)
 
-        let (_, cUpdateError) = c.updateSync(test: self)
+        let (_, _, cUpdateError) = c.updateSync(test: self)
         XCTAssertNil(cUpdateError, "Should be able to update first container")
         assertTrusts(context: c, peerIDs: [peerID1, peerID2, peerID3])
 
@@ -1540,11 +1830,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         assertDistrusts(context: c, peerIDs: [peerID2, peerID3])
 
         // peers should accept their fates
-        let (_, c2UpdateError) = c2.updateSync(test: self)
+        let (_, _, c2UpdateError) = c2.updateSync(test: self)
         XCTAssertNil(c2UpdateError, "Should be able to update second container")
         assertDistrusts(context: c2, peerIDs: [peerID2])
 
-        let (_, c3UpdateError) = c3.updateSync(test: self)
+        let (_, _, c3UpdateError) = c3.updateSync(test: self)
         XCTAssertNil(c3UpdateError, "Should be able to update third container")
         assertDistrusts(context: c3, peerIDs: [peerID3])
     }
@@ -1558,7 +1848,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         // And the first container fetches again, which should succeed
         self.cuttlefish.nextFetchErrors.append(FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .changeTokenExpired))
-        let (_, updateError) = c.updateSync(test: self)
+        let (_, _, updateError) = c.updateSync(test: self)
         XCTAssertNil(updateError, "Update should have succeeded")
 
         // and c's model should only include peerID2
@@ -1618,7 +1908,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             XCTAssertNotNil(deserializedBottle, "deserializedBottle should not be nil")
 
             XCTAssertEqual(deserializedBottle.contents, bottle.contents, "bottle data should be equal")
-
         } catch {
             XCTFail("error testing bottles \(error)")
         }
@@ -1636,12 +1925,14 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             let state = c.getStateSync(test: self)
             XCTAssertEqual(state.bottles.count, 1, "first container should have a bottle for peer")
+            XCTAssertEqual(state.escrowRecords.count, 1, "first container should have an escrow record for peer")
         }
 
         let c2 = try Container(name: ContainerName(container: "test", context: "newcomer"), persistentStoreDescription: store, cuttlefish: self.cuttlefish)
         do {
             let state = c2.getStateSync(test: self)
             XCTAssertEqual(state.bottles.count, 0, "before fetch, second container should not have any stored bottles")
+            XCTAssertEqual(state.escrowRecords.count, 0, "before fetch, second container should not have any escrow records")
         }
 
         let (c2bottles, _, c2FetchError) = c2.fetchViableBottlesSync(test: self)
@@ -1652,6 +1943,128 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             let state = c2.getStateSync(test: self)
             XCTAssertEqual(state.bottles.count, 1, "after fetch, second container should have one stored bottles")
+            XCTAssertEqual(state.escrowRecords.count, 1, "after fetch, second container should have one escrow record")
+        }
+    }
+
+    func testFetchBottlesAfterCacheExpires() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        var bottleA: BottleMO
+        var entropy: Data
+        let description = tmpStoreDescription(name: "container.db")
+        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, accountIsDemo: false))
+        XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
+
+        print("preparing A")
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
+            containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        do {
+            var state = containerA.getStateSync(test: self)
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
+
+            bottleA = state.bottles.removeFirst()
+
+            let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
+            XCTAssertNotNil(secret, "secret should not be nil")
+            XCTAssertNil(error, "error should be nil")
+        }
+        XCTAssertNotNil(aPeerID)
+        XCTAssertNotNil(aPermanentInfo)
+        XCTAssertNotNil(aPermanentInfoSig)
+
+        print("establishing A")
+        do {
+            assertNoTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            XCTAssertNil(error)
+            XCTAssertNotNil(peerID)
+            assertTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+        }
+        do {
+            let state = containerA.getStateSync(test: self)
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
+            let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
+            entropy = secret!
+            XCTAssertNotNil(secret, "secret should not be nil")
+            XCTAssertNil(error, "error should be nil")
+        }
+
+        let (bottles, _, fetchError) = containerA.fetchViableBottlesSync(test: self)
+        XCTAssertNil(fetchError, "should be no error fetching viable bottles")
+        XCTAssertNotNil(bottles, "should have fetched some bottles")
+        XCTAssertEqual(bottles!.count, 1, "should have fetched one bottle")
+
+        do {
+            let state = containerA.getStateSync(test: self)
+            XCTAssertEqual(state.bottles.count, 1, "first container should have a bottle for peer")
+            XCTAssertEqual(state.escrowRecords.count, 1, "first container should have an escrow record for peer")
+        }
+
+        //have another peer join
+        _ = containerB.updateSync(test: self)
+
+        print("preparing B")
+        let (bPeerID, _, _, _, _, _, error2) =
+            containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        do {
+            let state = containerB.getStateSync(test: self)
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
+            let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
+            XCTAssertNotNil(secret, "secret should not be nil")
+            XCTAssertNil(error, "error should be nil")
+        }
+        XCTAssertNil(error2)
+
+        do {
+            print("B prepares to join via bottle")
+
+            let (bottlePeerID, policy, _, 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")
+            XCTAssertNotNil(policy, "Should have a policy")
+
+            let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: [])
+
+            XCTAssertNil(error3)
+            XCTAssertNotNil(voucherData)
+            XCTAssertNotNil(voucherSig)
+
+            // Before B joins, there should be no TLKShares for B
+            assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+
+            print("B joins")
+            let (peerID, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            XCTAssertNil(error)
+            XCTAssertEqual(peerID, bPeerID!)
+
+            // But afterward, it has one!
+            assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
+        }
+
+        //now fetch bottles and we should get the cached version
+        let (_, _, _) = containerA.fetchViableBottlesSync(test: self)
+        do {
+            let state = containerA.getStateSync(test: self)
+            XCTAssertEqual(state.bottles.count, 1, "first container should have a bottle for peer")
+            XCTAssertEqual(state.escrowRecords.count, 1, "first container should have an escrow record for peer")
+        }
+
+        sleep(2)
+
+        //now fetch bottles again after the cache expired
+        containerA.escrowCacheTimeout = 2.0
+
+        let (_, _, _) = containerA.fetchViableBottlesSync(test: self)
+        do {
+            let state = containerA.getStateSync(test: self)
+            XCTAssertEqual(state.bottles.count, 2, "container A should have 2 bottles")
+            XCTAssertEqual(state.escrowRecords.count, 2, "container A should have 2 escrow records")
         }
     }
 
@@ -1711,18 +2124,18 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let store = tmpStoreDescription(name: "container.db")
 
         let c = try Container(name: ContainerName(container: "c", context: "context"),
-                                 persistentStoreDescription: store,
-                                 cuttlefish: self.cuttlefish)
+                              persistentStoreDescription: store,
+                              cuttlefish: self.cuttlefish)
 
         let machineIDs = Set(["aaa", "bbb", "ccc"])
         XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing peer A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             c.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = c.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = c.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1734,14 +2147,14 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = c.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
+            let (peerID, _, _, error) = c.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         let recoveryKey = SecRKCreateRecoveryKeyString(nil)
         XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
 
-        let (setRecoveryError) = c.setRecoveryKeySync(test: self, recoveryKey: recoveryKey!, recoverySalt: "altDSID", ckksKeys: [])
+        let (_, setRecoveryError) = c.setRecoveryKeySync(test: self, recoveryKey: recoveryKey!, recoverySalt: "altDSID", ckksKeys: [])
         XCTAssertNil(setRecoveryError, "error should be nil")
     }
 
@@ -1774,11 +2187,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(c.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing peer A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             c.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = c.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = c.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1790,15 +2203,15 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = c.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
+            let (peerID, _, _, error) = c.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
         let (repairAccount, repairEscrow, resetOctagon, leaveTrust, healthError) = c.requestHealthCheckSync(requiresEscrowCheck: true, test: self)
-        XCTAssertEqual(repairAccount, false, "")
-        XCTAssertEqual(repairEscrow, false, "")
-        XCTAssertEqual(resetOctagon, false, "")
-        XCTAssertEqual(leaveTrust, false, "")
+        XCTAssertFalse(repairAccount, "")
+        XCTAssertFalse(repairEscrow, "")
+        XCTAssertFalse(resetOctagon, "")
+        XCTAssertFalse(leaveTrust, "")
         XCTAssertNil(healthError)
     }
 
@@ -1814,11 +2227,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             var state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
 
             bottleA = state.bottles.removeFirst()
 
@@ -1833,14 +2246,14 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         print("establishing A")
         do {
             assertNoTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
             assertTLKShareFor(peerID: aPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
         }
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             entropy = secret!
             XCTAssertNotNil(secret, "secret should not be nil")
@@ -1850,11 +2263,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerB.updateSync(test: self)
 
         print("preparing B")
-        let (bPeerID, _, _, _, _, _, _, error2) =
+        let (bPeerID, _, _, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1864,10 +2277,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             print("B prepares to join via bottle")
 
-            let (bottlePeerID, views, policy, errorPreflight) = containerB.preflightVouchWithBottleSync(test: self, bottleID: bottleA.bottleID!)
+            let (bottlePeerID, policy, _, 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")
-            XCTAssertNotNil(views, "Should have a set of views to restore")
             XCTAssertNotNil(policy, "Should have a policy")
 
             let (voucherData, voucherSig, _, _, error3) = containerB.vouchWithBottleSync(test: self, b: bottleA.bottleID!, entropy: entropy, bottleSalt: "123456789", tlkShares: [])
@@ -1882,9 +2294,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
-            XCTAssertNotNil(error)
-            XCTAssertNil(peerID)
+            let (peerID, _, _, error) = containerB.joinSync(test: self, voucherData: voucherData!, voucherSig: voucherSig!, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            XCTAssertNil(error, "Should be no error joining with a fetch error")
+            XCTAssertNotNil(peerID, "Should have a peer ID")
         }
     }
 
@@ -1898,11 +2310,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertNil(containerB.setAllowedMachineIDsSync(test: self, allowedMachineIDs: machineIDs, accountIsDemo: false))
 
         print("preparing peer A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, aStableInfo, aStableInfoSig, _, _, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, aStableInfo, aStableInfoSig, _, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerA.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == aPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == aPeerID }, "should have a bottle for peer")
             let secret = containerA.loadSecretSync(test: self, label: aPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1916,17 +2328,17 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: nil)
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
 
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _, error2) =
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
-            XCTAssertFalse( state.bottles.filter { $0.peerID == bPeerID } .isEmpty, "should have a bottle for peer")
+            XCTAssertTrue(state.bottles.contains { $0.peerID == bPeerID }, "should have a bottle for peer")
             let secret = containerB.loadSecretSync(test: self, label: bPeerID!)
             XCTAssertNotNil(secret, "secret should not be nil")
             XCTAssertNil(error, "error should be nil")
@@ -1982,23 +2394,23 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self,
-                                                               voucherData: voucherData!,
-                                                               voucherSig: voucherSig!,
-                                                               ckksKeys: [],
-                                                               tlkShares: [])
+            let (peerID, _, _, error) = containerB.joinSync(test: self,
+                                                            voucherData: voucherData!,
+                                                            voucherSig: voucherSig!,
+                                                            ckksKeys: [],
+                                                            tlkShares: [])
             XCTAssertNil(error)
             XCTAssertEqual(peerID, bPeerID!)
         }
 
         print("A updates")
         do {
-            let (_, error) = containerA.updateSync(test: self)
+            let (_, _, error) = containerA.updateSync(test: self)
             XCTAssertNil(error)
         }
         print("B updates")
         do {
-            let (_, error) = containerB.updateSync(test: self)
+            let (_, _, error) = containerB.updateSync(test: self)
             XCTAssertNil(error)
         }
 
@@ -2009,17 +2421,17 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let recoveryKey = SecRKCreateRecoveryKeyString(nil)
         XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
 
-        let (setRecoveryError) = containerB.setRecoveryKeySync(test: self, recoveryKey: recoveryKey!, recoverySalt: "altDSID", ckksKeys: [])
+        let (_, setRecoveryError) = containerB.setRecoveryKeySync(test: self, recoveryKey: recoveryKey!, recoverySalt: "altDSID", ckksKeys: [])
         XCTAssertNil(setRecoveryError, "error should be nil")
 
         print("A updates")
         do {
-            let (_, error) = containerA.updateSync(test: self)
+            let (_, _, error) = containerA.updateSync(test: self)
             XCTAssertNil(error)
         }
         print("B updates")
         do {
-            let (_, error) = containerB.updateSync(test: self)
+            let (_, _, error) = containerB.updateSync(test: self)
             XCTAssertNil(error)
         }
 
@@ -2040,7 +2452,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
             let recoveryEncryptionPublicKey: Data? = stableInfo!["recovery_encryption_public_key"] as! Data?
             XCTAssertNil(recoveryEncryptionPublicKey, "recoveryEncryptionPublicKey should be nil")
-
         }
     }
 
@@ -2050,7 +2461,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
                 unknownMachineIDs: Set<String> = Set(),
                 persistentStore: NSPersistentStoreDescription,
                 cuttlefish: FakeCuttlefishServer) throws {
-
         let midList = container.onqueueCurrentMIDList()
         XCTAssertEqual(midList.machineIDs(in: .allowed), allowedMachineIDs, "List of allowed machine IDs should match")
         XCTAssertEqual(midList.machineIDs(in: .disallowed), disallowedMachineIDs, "List of disallowed machine IDs should match")
@@ -2073,7 +2483,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let description = tmpStoreDescription(name: "container.db")
         let container = try Container(name: ContainerName(container: "test", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish)
 
-        let (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
 
         XCTAssertNil(error)
         XCTAssertNotNil(peerID)
@@ -2120,17 +2530,17 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set")
 
         // A update() before establish() doesn't change the list, since it isn't actually changing anything
-        let (_, updateError) = container.updateSync(test: self)
+        let (_, _, updateError) = container.updateSync(test: self)
         XCTAssertNil(updateError, "Should not be an error updating the container without first establishing")
         try self.assert(container: container, allowedMachineIDs: Set(["xxx", "mmm", "aaa"]), disallowedMachineIDs: Set(["zzz", "kkk", "bbb", "ccc", "fff"]), persistentStore: description, cuttlefish: self.cuttlefish)
 
-        let (_, _, establishError) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+        let (_, _, _, establishError) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
         XCTAssertNil(establishError, "Should be able to establish() with no error")
         try self.assert(container: container, allowedMachineIDs: Set(["xxx", "mmm", "aaa"]), disallowedMachineIDs: Set(["zzz", "kkk", "bbb", "ccc", "fff"]), persistentStore: description, cuttlefish: self.cuttlefish)
         XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set")
 
         // But a successful update() does remove all disallowed machine IDs, as they're no longer relevant
-        let (_, updateError2) = container.updateSync(test: self)
+        let (_, _, updateError2) = container.updateSync(test: self)
         XCTAssertNil(updateError2, "Should not be an error updating the container after establishing")
         try self.assert(container: container, allowedMachineIDs: Set(["xxx", "mmm", "aaa"]), disallowedMachineIDs: Set([]), persistentStore: description, cuttlefish: self.cuttlefish)
         XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set")
@@ -2225,7 +2635,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         // Now TPH boots up with a preexisting model
         let container = try Container(name: containerName, persistentStoreDescription: description, cuttlefish: cuttlefish)
 
-        let (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
 
         XCTAssertNil(error)
         XCTAssertNotNil(peerID)
@@ -2346,6 +2756,109 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertFalse(container.onqueueFullIDMSListWouldBeHelpful(), "Container shouldn't think it could use an IDMS list set")
     }
 
+    func testDuplicateVouchersWhenRegisteringOnModel() throws {
+        let store = tmpStoreDescription(name: "container.db")
+        let (c, peerID1) = try establish(reload: false, store: store)
+
+        let (c2, peerID2) = try joinByVoucher(sponsor: c,
+                                              containerID: "second",
+                                              machineID: "bbb",
+                                              machineIDs: ["aaa", "bbb"], accountIsDemo: false,
+                                              store: store)
+
+        let (_, _, cUpdateError) = c.updateSync(test: self)
+        XCTAssertNil(cUpdateError, "Should be able to update first container")
+        assertTrusts(context: c, peerIDs: [peerID1, peerID2])
+
+        let (_, _, c2UpdateError) = c2.updateSync(test: self)
+        XCTAssertNil(c2UpdateError, "Should be able to update second container")
+        assertTrusts(context: c2, peerIDs: [peerID1, peerID2])
+
+        //attempt to register a bunch of vouchers it likely already has
+        for voucher in c2.model.allVouchers() {
+            c.model.register(voucher)
+        }
+        XCTAssertEqual(c.model.allVouchers().count, 1, "voucher count should be 1")
+        XCTAssertEqual(c2.model.allVouchers().count, 1, "voucher count should be 1")
+    }
+
+    func testDuplicateVouchersOnload() throws {
+        let description = tmpStoreDescription(name: "container.db")
+
+        let store = tmpStoreDescription(name: "container.db")
+        let (c, peerID1) = try establish(reload: false, store: store)
+
+        let (c2, peerID2) = try joinByVoucher(sponsor: c,
+                                              containerID: "second",
+                                              machineID: "bbb",
+                                              machineIDs: ["aaa", "bbb", "ccc"], accountIsDemo: false,
+                                              store: store)
+
+        let (c3, peerID3) = try joinByVoucher(sponsor: c,
+                                              containerID: "third",
+                                              machineID: "ccc",
+                                              machineIDs: ["aaa", "bbb", "ccc"], accountIsDemo: false,
+                                              store: store)
+
+        let (_, _, cUpdateError) = c.updateSync(test: self)
+        XCTAssertNil(cUpdateError, "Should be able to update first container")
+
+        let (_, _, cUpdateError2) = c2.updateSync(test: self)
+        XCTAssertNil(cUpdateError2, "Should be able to update first container")
+        let (_, _, cUpdateError3) = c3.updateSync(test: self)
+        XCTAssertNil(cUpdateError3, "Should be able to update first container")
+        let (_, _, _) = c.updateSync(test: self)
+
+        assertTrusts(context: c, peerIDs: [peerID1, peerID2, peerID3])
+
+        var vouchers: [VoucherMO] = Array()
+
+        let c1Peers = c.containerMO.peers as! Set<PeerMO>
+        for peer in c1Peers {
+            for voucher in peer.vouchers! {
+                let vouch = voucher as! VoucherMO
+                vouchers.append(vouch)
+            }
+        }
+        for peer in c1Peers {
+            for voucher in peer.vouchers! {
+                let vouch = voucher as! VoucherMO
+                vouchers.append(vouch)
+            }
+        }
+
+        for peer in c1Peers {
+            for voucher in peer.vouchers! {
+                let vouch = voucher as! VoucherMO
+                vouchers.append(vouch)
+            }
+        }
+
+        //reload container
+        XCTAssertEqual(vouchers.count, 6, "should have 6 vouchers")
+
+        c.moc.performAndWait {
+            let containerMO = ContainerMO(context: c.moc)
+            do {
+
+                for peer in containerMO.peers as! Set<PeerMO> {
+                    for vouch in vouchers {
+                        peer.addToVouchers(vouch)
+                    }
+                }
+            }
+            XCTAssertNoThrow(try! c.moc.save())
+        }
+
+        //reload container
+        do {
+            let container = try Container(name: c.name, persistentStoreDescription: description, cuttlefish: cuttlefish)
+            XCTAssertEqual(container.model.allVouchers().count, 2, "voucher count should be 2")
+        } catch {
+            XCTFail("Creating container errored: \(error)")
+        }
+    }
+
     func testMachineIDListSetDisallowedOldUnknownMachineIDs() throws {
         let description = tmpStoreDescription(name: "container.db")
         var (container, peerID1) = try establish(reload: false, contextID: OTDefaultContext, allowedMachineIDs: Set(["aaa"]), accountIsDemo: false, store: description)
@@ -2364,7 +2877,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
                                                   store: description)
 
         // And the first container accepts the join...
-        let (_, cUpdateError) = container.updateSync(test: self)
+        let (_, _, cUpdateError) = container.updateSync(test: self)
         XCTAssertNil(cUpdateError, "Should be able to update first container")
         assertTrusts(context: container, peerIDs: [peerID1, peerID3])
 
@@ -2393,7 +2906,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             container = try Container(name: ContainerName(container: "test", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish)
             XCTAssertEqual(container.containerMO.honorIDMSListChanges, "YES", "honorIDMSListChanges should be YES")
-
         } catch {
             XCTFail("Creating container errored: \(error)")
         }
@@ -2431,7 +2943,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
                                                   store: description)
 
         // And the first container accepts the join...
-        let (_, cUpdateError) = container.updateSync(test: self)
+        let (_, _, cUpdateError) = container.updateSync(test: self)
         XCTAssertNil(cUpdateError, "Should be able to update first container")
         assertTrusts(context: container, peerIDs: [peerID1, peerID2])
 
@@ -2459,7 +2971,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         c2.containerMO.honorIDMSListChanges = "NO"
 
         // And the first container accepts the join...
-        let (_, cUpdateError) = container.updateSync(test: self)
+        let (_, _, cUpdateError) = container.updateSync(test: self)
         XCTAssertNil(cUpdateError, "Should be able to update first container")
         assertTrusts(context: container, peerIDs: [peerID1, peerID2])
 
@@ -2470,7 +2982,6 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             container = try Container(name: ContainerName(container: "test", context: OTDefaultContext), persistentStoreDescription: description, cuttlefish: cuttlefish)
             XCTAssertEqual(container.containerMO.honorIDMSListChanges, "NO", "honorIDMSListChanges should be NO")
-
         } catch {
             XCTFail("Creating container errored: \(error)")
         }
@@ -2484,11 +2995,10 @@ class TrustedPeersHelperUnitTests: XCTestCase {
     }
 
     func testContainerAndModelConsistency() throws {
-
         let preTestContainerName = ContainerName(container: "testToCreatePrepareData", context: "context")
         let description = tmpStoreDescription(name: "container.db")
         let containerTest = try Container(name: preTestContainerName, persistentStoreDescription: description, cuttlefish: cuttlefish)
-        let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error) = containerTest.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error) = containerTest.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         XCTAssertNil(error)
         XCTAssertNotNil(peerID)
         XCTAssertNotNil(permanentInfo)
@@ -2519,17 +3029,18 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             let containerEgoStableInfo = TPPeerStableInfo(data: stableInfo!, sig: stableInfoSig!)
             do {
                 let peerKeys: OctagonSelfPeerKeys = try loadEgoKeysSync(peerID: containerMO.egoPeerID!)
-                let info3 = TPPeerStableInfo(clock: containerEgoStableInfo!.clock + 2,
-                                             frozenPolicyVersion: containerEgoStableInfo!.frozenPolicyVersion,
-                                             flexiblePolicyVersion: containerEgoStableInfo!.flexiblePolicyVersion!,
-                                                               policySecrets: containerEgoStableInfo!.policySecrets,
-                                                               deviceName: containerEgoStableInfo!.deviceName,
-                                                               serialNumber: containerEgoStableInfo!.serialNumber,
-                                                               osVersion: containerEgoStableInfo!.osVersion,
-                                                               signing: peerKeys.signingKey,
-                                                               recoverySigningPubKey: containerEgoStableInfo!.recoverySigningPublicKey,
-                                                               recoveryEncryptionPubKey: containerEgoStableInfo!.recoveryEncryptionPublicKey,
-                                                               error: nil)
+                let newClock = containerEgoStableInfo!.clock + 2
+                let info3 = try TPPeerStableInfo(clock: newClock,
+                                                 frozenPolicyVersion: containerEgoStableInfo!.frozenPolicyVersion,
+                                                 flexiblePolicyVersion: containerEgoStableInfo!.flexiblePolicyVersion!,
+                                                 policySecrets: containerEgoStableInfo!.policySecrets,
+                                                 syncUserControllableViews: containerEgoStableInfo!.syncUserControllableViews,
+                                                 deviceName: containerEgoStableInfo!.deviceName,
+                                                 serialNumber: containerEgoStableInfo!.serialNumber,
+                                                 osVersion: containerEgoStableInfo!.osVersion,
+                                                 signing: peerKeys.signingKey,
+                                                 recoverySigningPubKey: containerEgoStableInfo!.recoverySigningPublicKey,
+                                                 recoveryEncryptionPubKey: containerEgoStableInfo!.recoveryEncryptionPublicKey)
 
                 //setting the containerMO's ego stable info to an old clock
                 containerMO.egoPeerStableInfo = containerEgoStableInfo!.data
@@ -2603,7 +3114,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         var container = try Container(name: ContainerName(container: "test", context: contextID), persistentStoreDescription: description, cuttlefish: cuttlefish)
         XCTAssertEqual(container.containerMO.honorIDMSListChanges, "UNKNOWN", "honorIDMSListChanges should be unknown")
 
-        let (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = container.getStateSync(test: self)
             XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
@@ -2624,7 +3135,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             XCTFail("Creating container errored: \(error)")
         }
 
-        let (peerID2, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+        let (peerID2, _, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
         XCTAssertNil(error2)
         XCTAssertNotNil(peerID2)
 
@@ -2643,9 +3154,8 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertEqual(containerC.containerMO.honorIDMSListChanges, "UNKNOWN", "honorIDMSListChanges should be unknown")
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aViewList, aPolicy, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aPolicy, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
-        XCTAssertNotNil(aViewList, "Should have a view list coming back from a successful prepare")
         XCTAssertNotNil(aPolicy, "Should have a policy coming back from a successful prepare")
         XCTAssertEqual(aPolicy?.version, prevailingPolicyVersion, "Policy coming back from prepare() should be prevailing policy version")
 
@@ -2663,13 +3173,13 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [], tlkShares: [], preapprovedKeys: [])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
 
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, _, error2) =
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, bStableInfo, bStableInfoSig, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
@@ -2729,11 +3239,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins")
-            let (peerID, _, _, _, error) = containerB.joinSync(test: self,
-                                                               voucherData: voucherData!,
-                                                               voucherSig: voucherSig!,
-                                                               ckksKeys: [],
-                                                               tlkShares: [])
+            let (peerID, _, _, error) = containerB.joinSync(test: self,
+                                                            voucherData: voucherData!,
+                                                            voucherSig: voucherSig!,
+                                                            ckksKeys: [],
+                                                            tlkShares: [])
             XCTAssertNil(error)
             XCTAssertEqual(peerID, bPeerID!)
         }
@@ -2743,7 +3253,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         _ = containerC.dumpSync(test: self)
 
         print("preparing C")
-        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, _, error4) =
+        let (cPeerID, cPermanentInfo, cPermanentInfoSig, cStableInfo, cStableInfoSig, _, error4) =
             containerC.prepareSync(test: self, epoch: 1, machineID: "ccc", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerC.getStateSync(test: self)
@@ -2781,11 +3291,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertTLKShareFor(peerID: cPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("C joins")
-            let (peerID, _, _, _, error2) = containerC.joinSync(test: self,
-                                                                voucherData: voucherData!,
-                                                                voucherSig: voucherSig!,
-                                                                ckksKeys: [self.manateeKeySet, provisionalEngramKeySet],
-                                                                tlkShares: [])
+            let (peerID, _, _, error2) = containerC.joinSync(test: self,
+                                                             voucherData: voucherData!,
+                                                             voucherSig: voucherSig!,
+                                                             ckksKeys: [self.manateeKeySet, provisionalEngramKeySet],
+                                                             tlkShares: [])
             XCTAssertNil(error2)
             XCTAssertEqual(peerID, cPeerID!)
 
@@ -2796,7 +3306,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("A updates")
         do {
-            let (_, error) = containerA.updateSync(test: self)
+            let (_, _, error) = containerA.updateSync(test: self)
             XCTAssertNil(error)
         }
 
@@ -2824,19 +3334,18 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         XCTAssertEqual(containerB.containerMO.honorIDMSListChanges, "UNKNOWN", "honorIDMSListChanges should be unknown")
 
         print("preparing A")
-        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aViewList, aPolicy, error) =
+        let (aPeerID, aPermanentInfo, aPermanentInfoSig, _, _, aPolicy, error) =
             containerA.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         XCTAssertNil(error)
         XCTAssertNotNil(aPeerID)
         XCTAssertNotNil(aPermanentInfo)
         XCTAssertNotNil(aPermanentInfoSig)
 
-        XCTAssertNotNil(aViewList, "Should have a view list coming back from a successful prepare")
         XCTAssertNotNil(aPolicy, "Should have a policy coming back from a successful prepare")
         XCTAssertEqual(aPolicy?.version, prevailingPolicyVersion, "Policy coming back from prepare() should be prevailing policy version")
 
         print("preparing B")
-        let (bPeerID, bPermanentInfo, bPermanentInfoSig, _, _, _, _, error2) =
+        let (bPeerID, bPermanentInfo, bPermanentInfoSig, _, _, _, error2) =
             containerB.prepareSync(test: self, epoch: 1, machineID: "bbb", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = containerB.getStateSync(test: self)
@@ -2858,7 +3367,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
 
         print("establishing A")
         do {
-            let (peerID, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [bPermanentInfoParsed!.signingPubKey.spki()])
+            let (peerID, _, _, error) = containerA.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [bPermanentInfoParsed!.signingPubKey.spki()])
             XCTAssertNil(error)
             XCTAssertNotNil(peerID)
         }
@@ -2867,10 +3376,9 @@ class TrustedPeersHelperUnitTests: XCTestCase {
             assertNoTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
 
             print("B joins by preapproval, and uploads all TLKShares that it has")
-            let (bJoinedPeerID, _, views, policy, bJoinedError) = containerB.preapprovedJoinSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [])
+            let (bJoinedPeerID, _, policy, bJoinedError) = containerB.preapprovedJoinSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [])
             XCTAssertNil(bJoinedError, "Should be no error joining by preapproval")
             XCTAssertNotNil(bJoinedPeerID, "Should have a peer ID out of join")
-            XCTAssertNotNil(views, "should have a list of views to use")
             XCTAssertNotNil(policy, "Should have a policy back from preapprovedjoin")
 
             assertTLKShareFor(peerID: bPeerID!, keyUUID: self.manateeKeySet.tlk.uuid, zoneID: CKRecordZone.ID(zoneName: "Manatee"))
@@ -2888,7 +3396,7 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         let contextID = "contextID"
         var container = try Container(name: ContainerName(container: "test", context: contextID), persistentStoreDescription: store, cuttlefish: cuttlefish)
 
-        let (peerID, permanentInfo, permanentInfoSig, _, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
+        let (peerID, permanentInfo, permanentInfoSig, _, _, _, error) = container.prepareSync(test: self, epoch: 1, machineID: "aaa", bottleSalt: "123456789", bottleID: UUID().uuidString, modelID: "iPhone1,1")
         do {
             let state = container.getStateSync(test: self)
             XCTAssertFalse( state.bottles.filter { $0.peerID == peerID } .isEmpty, "should have a bottle for peer")
@@ -2908,12 +3416,11 @@ class TrustedPeersHelperUnitTests: XCTestCase {
         do {
             container = try Container(name: ContainerName(container: "test", context: contextID), persistentStoreDescription: store, cuttlefish: cuttlefish)
             XCTAssertEqual(container.containerMO.honorIDMSListChanges, "UNKNOWN", "honorIDMSListChanges should be unknown")
-
         } catch {
             XCTFail("Creating container errored: \(error)")
         }
 
-        let (peerID2, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
+        let (peerID2, _, _, error2) = container.establishSync(test: self, ckksKeys: [self.manateeKeySet], tlkShares: [], preapprovedKeys: [])
         XCTAssertNil(error2)
         XCTAssertNotNil(peerID2)
 
index f40e458d21a3d79a3a9d9f43ca9ee2dd38ccc343..7f1493b13631912063ee2c3f18e6a247da8cf0fc 100644 (file)
@@ -54,8 +54,7 @@
 }
 
 - (instancetype)initWithCoder:(NSCoder *)coder {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         NSMutableSet *attributeClasses = [[[self class] supportedAttributeClasses] mutableCopy];
         [attributeClasses addObject:[NSDictionary class]];
 
index 5aa7ef4c833ee17d18334ed2d0f416478645ebf5..cabdc1c719b218059cc94e4edf819b3adbca6b07 100644 (file)
@@ -23,7 +23,7 @@
 
 #import <os/transaction_private.h>
 #import <Foundation/Foundation.h>
-#import <CFNetwork/CFURLConnection.h>
+#import <CFNetwork/CFNetworkPriv.h>
 #import <Accounts/Accounts.h>
 #import <Accounts/Accounts_Private.h>
 #import <AppleAccount/ACAccount+AppleAccount.h>
@@ -42,6 +42,8 @@
 #import "keychain/analytics/C2Metric/SECC2MPDeviceInfo.h"
 #import <utilities/SecCoreAnalytics.h>
 
+#import <utilities/simulatecrash_assert.h>
+
 
 
 @interface SecMetrics () <NSURLSessionDelegate>
diff --git a/keychain/behavior/SFBehavior.h b/keychain/behavior/SFBehavior.h
deleted file mode 100644 (file)
index 69fc256..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#if __OBJC2__
-
-#import <Foundation/Foundation.h>
-
-typedef NS_ENUM(uint32_t, SFBehaviorRamping) {
-    SFBehaviorRampingDisabled = 0,      /* must not be enabled */
-    SFBehaviorRampingEnabled = 1,       /* unconditionally enabled */
-    SFBehaviorRampingPromoted = 2,      /* should be promoted by application */
-    SFBehaviorRampingVisible = 3,       /* allowed to enabled */
-};
-
-@interface SFBehavior : NSObject
-
-+ (SFBehavior *)behaviorFamily:(NSString *)family;
-- (instancetype)init NS_UNAVAILABLE;
-
-/*
- * Ramping control controlled by CloudKit and configuration
- *
- *   Return the current ramping state, can be called as often as clients want, state is cached
- *   and fetched in background (returning SFBehaviorRampingDisabled) until server changes the value.
- *
- *   Ramping always go from Disable -> Visiable -> Promoted -> Enabled, can can skip over steps in-between.
- *
- *   The feature can also go from { Visiable, Promoted, Enabled } -> Disabled if the feature is disabled
- *
- *   Passing in force will for fetching the value from the server and bypass all caching, this will
- *   take its sweet time, so don't block UI on this operation, using force is not recommended.
- */
-- (SFBehaviorRamping)ramping:(NSString *)feature force:(bool)force;
-
-/*
- *  This feature is assumed to be enabled unless disabled by configuration.
- */
-- (bool)featureEnabled:(NSString *)feature;
-/*
- * This feature is assumed to be disabled unless enabled by configuration.
- */
-- (bool)featureDisabled:(NSString *)feature;
-
-/*
- * Fetch configuration values that might be changed from server configuration
- */
-- (NSNumber *)configurationNumber:(NSString *)configuration defaultValue:(NSNumber *)defaultValue;
-- (NSString *)configurationString:(NSString *)configuration defaultValue:(NSString *)defaultValue;
-
-@end
-
-#endif
diff --git a/keychain/behavior/SFBehavior.m b/keychain/behavior/SFBehavior.m
deleted file mode 100644 (file)
index cd46021..0000000
+++ /dev/null
@@ -1,140 +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 "SFBehavior.h"
-#import <dispatch/dispatch.h>
-
-#if __OBJC2__
-
-@interface SFBehavior ()
-@property NSString *family;
-@property NSXPCConnection *connection;
-- (instancetype)initBehaviorFamily:(NSString *)family connection:(NSXPCConnection *)connection;
-@end
-
-@protocol SFBehaviorProtocol <NSObject>
-- (void)ramping:(NSString *)feature family:(NSString*)family complete:(void (^)(SFBehaviorRamping))complete;
-- (void)feature:(NSString *)feature family:(NSString*)family defaultValue:(bool)defaultValue complete:(void (^)(bool))complete;
-
-- (void)configNumber:(NSString *)configuration family:(NSString*)family complete:(void (^)(NSNumber *))complete;
-- (void)configString:(NSString *)configuration family:(NSString*)family complete:(void (^)(NSString *))complete;
-@end
-
-
-@implementation SFBehavior
-
-+ (SFBehavior *)behaviorFamily:(NSString *)family
-{
-    static dispatch_once_t onceToken = 0;
-    static NSMutableDictionary<NSString *, SFBehavior *> *behaviors;
-    static NSXPCConnection *connection = NULL;
-    dispatch_once(&onceToken, ^{
-        behaviors = [NSMutableDictionary dictionary];
-        connection = [[NSXPCConnection alloc] initWithMachServiceName:@"com.apple.security.behavior" options:NSXPCConnectionPrivileged];
-
-        connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(SFBehaviorProtocol)];
-        [connection resume];
-    });
-
-    SFBehavior *behavior = nil;
-    @synchronized (behaviors) {
-        behavior = behaviors[family];
-        if (behavior == NULL) {
-            behavior = [[SFBehavior alloc] initBehaviorFamily:family connection:connection];
-            behaviors[family] = behavior;
-        }
-    }
-
-    return behavior;
-}
-
-- (instancetype)initBehaviorFamily:(NSString *)family connection:(NSXPCConnection *)connection
-{
-    self = [super init];
-    if (self) {
-        _family = family;
-        _connection = connection;
-    }
-    return self;
-}
-
-- (SFBehaviorRamping)ramping:(NSString *)feature force:(bool)force
-{
-    __block SFBehaviorRamping _ramping = SFBehaviorRampingDisabled;
-    [[_connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
-    }] ramping:feature family:_family complete:^(SFBehaviorRamping ramping) {
-        _ramping = ramping;
-    }];
-    return _ramping;
-}
-
-- (bool)feature:(NSString *)feature defaultValue:(bool)defaultValue
-{
-    __block bool enabled = defaultValue;
-
-    [[_connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
-    }] feature:feature family:_family defaultValue:defaultValue complete:^(bool returnFeature) {
-        enabled = returnFeature;
-    }];
-    return enabled;
-
-}
-
-- (bool)featureEnabled:(NSString *)feature
-{
-    return [self feature:feature defaultValue:true];
-}
-
-- (bool)featureDisabled:(NSString *)feature
-{
-    return ![self feature:feature defaultValue:false];
-}
-
-- (NSNumber *)configurationNumber:(NSString *)configuration defaultValue:(NSNumber *)defaultValue
-{
-    __block NSNumber *_number = defaultValue;
-
-    [[_connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
-    }] configNumber:configuration family:_family complete:^(NSNumber *number) {
-        if (number)
-            _number = number;
-    }];
-    return _number;
-}
-
-- (NSString *)configurationString:(NSString *)configuration defaultValue:(NSString *)defaultValue
-{
-    __block NSString *_string = defaultValue;
-
-    [[_connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
-    }] configString:configuration family:_family complete:^(NSString *string) {
-        if (string)
-            _string = string;
-    }];
-    return _string;
-}
-
-@end
-
-#endif /* __OBJC2__ */
-
index 50070ebc5780493bf6a841f98230e970d8c71fe2..8cf2723939b8c7e5e07a94b3c53130ea5454dd81 100644 (file)
 
 #ifdef __OBJC__
 #import <Foundation/Foundation.h>
-NS_ASSUME_NONNULL_BEGIN
-#else
+#import "keychain/ot/OctagonStateMachine.h"
+#endif /* __OBJC__ */
+
 CF_ASSUME_NONNULL_BEGIN
-#endif
 
 #ifdef __OBJC__
 
@@ -62,6 +62,7 @@ extern CKKSItemState* const SecCKKSStateInFlight;
 extern CKKSItemState* const SecCKKSStateReencrypt;
 extern CKKSItemState* const SecCKKSStateError;
 extern CKKSItemState* const SecCKKSStateDeleted;  // meta-state: please delete this item!
+extern CKKSItemState* const SecCKKSStateMismatchedView; // This item was for a different view at processing time. Held pending a policy refresh.
 
 /* Processed States */
 @protocol SecCKKSProcessedState <NSObject>
@@ -157,9 +158,16 @@ extern NSString* const SecCKRecordManifestLeafDERKey;
 extern NSString* const SecCKRecordManifestLeafDigestKey;
 
 /* Zone Key Hierarchy States */
+#if OCTAGON
+typedef OctagonState CKKSZoneKeyState;
+#else
+// This is here to allow for building with Octagon off
 @protocol SecCKKSZoneKeyState <NSObject>
 @end
 typedef NSString<SecCKKSZoneKeyState> CKKSZoneKeyState;
+#endif
+
+extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForCloudKitAccountStatus;
 
 // CKKS is currently logged out
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateLoggedOut;
@@ -170,17 +178,28 @@ extern CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing;
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized;
 // CKKSZone has informed us that zone setup did not work. Try again soon!
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateZoneCreationFailed;
+
+// Everything is likely ready. Double-check.
+extern CKKSZoneKeyState* const SecCKKSZoneKeyStateBecomeReady;
 // Everything is ready and waiting for input.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateReady;
+
 // We're presumably ready, but we'd like to do one or two more checks after we unlock.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateReadyPendingUnlock;
 
+// A key hierarchy fetch will now begin
+extern CKKSZoneKeyState* const SecCKKSZoneKeyStateBeginFetch;
+
 // We're currently refetching the zone
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateFetch;
 // A Fetch has just been completed which includes some new keys to process
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateFetchComplete;
 // We'd really like a full refetch.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateNeedFullRefetch;
+
+// The TLK doesn't appear to be present. Determine what to to next!
+extern CKKSZoneKeyState* const SecCKKSZoneKeyStateTLKMissing;
+
 // We've received a wrapped TLK, but we don't have its contents yet. Wait until they arrive.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK;
 
@@ -191,8 +210,11 @@ extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLKUpload;
 
 // We've received a wrapped TLK, but we can't process it until the keybag unlocks. Wait until then.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock;
+// Some operation has noticed that trust is lost. Will enter WaitForTrust.
+extern CKKSZoneKeyState* const SecCKKSZoneKeyStateLoseTrust;
 // We've done some CK ops, but are waiting for the trust system to tell us to continue
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTrust;
+
 // Things are unhealthy, but we're not sure entirely why.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy;
 // Something has gone horribly wrong with the current key pointers.
@@ -215,8 +237,6 @@ extern CKKSZoneKeyState* const SecCKKSZoneKeyStateResettingLocalData;
 
 // Fatal error. Will not proceed unless fixed from outside class.
 extern CKKSZoneKeyState* const SecCKKSZoneKeyStateError;
-// This CKKS instance has been cancelled.
-extern CKKSZoneKeyState* const SecCKKSZoneKeyStateCancelled;
 
 // If you absolutely need to numberify one of the above constants, here's your maps.
 NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void);
@@ -226,7 +246,7 @@ CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber);
 
 // Use this to determine if CKKS believes the current state is "transient": that is, should resolve itself with further local processing
 // or 'nontransient': further local processing won't progress. Either we're ready, or waiting for the user to unlock, or a remote device to do something.
-bool CKKSKeyStateTransient(CKKSZoneKeyState* state);
+NSSet<CKKSZoneKeyState*>* CKKSKeyStateNonTransientStates(void);
 
 /* Hide Item Length */
 extern const NSUInteger SecCKKSItemPaddingBlockSize;
@@ -298,6 +318,9 @@ void SecCKKSTestSetDisableSOS(bool set);
 bool SecCKKSTestDisableKeyNotifications(void);
 void SecCKKSTestSetDisableKeyNotifications(bool set);
 
+bool SecCKKSTestSkipScan(void);
+bool SecCKKSSetTestSkipScan(bool value);
+
 // TODO: handle errors better
 typedef CF_ENUM(CFIndex, CKKSErrorCode) {
     CKKSNotInitialized = 9,
@@ -337,6 +360,11 @@ typedef CF_ENUM(CFIndex, CKKSErrorCode) {
     CKKSKeysMissing = 53,
 
     CKKSCircularKeyReference = 54,
+
+    CKKSErrorViewIsPaused = 55,
+    CKKSErrorPolicyNotLoaded = 56,
+
+    CKKSErrorUnexpectedNil = 57,
 };
 
 typedef CF_ENUM(CFIndex, CKKSResultDescriptionErrorCode) {
@@ -384,6 +412,8 @@ typedef CF_ENUM(CFIndex, CKKSServerExtensionErrorCode) {
     //CKKSServerInvalidCurrentItem = 17,
 };
 
+#if __OBJC__
+
 #define SecTranslateError(nserrorptr, cferror)             \
     if(nserrorptr) {                                       \
         *nserrorptr = (__bridge_transfer NSError*)cferror; \
@@ -391,62 +421,38 @@ typedef CF_ENUM(CFIndex, CKKSServerExtensionErrorCode) {
         CFReleaseNull(cferror);                            \
     }
 
+extern os_log_t CKKSLogObject(NSString* scope, NSString* _Nullable zoneName);
+
 // Very similar to the secerror, secnotice, and secinfo macros in debugging.h, but add zoneNames
-#define ckkserrorwithzonename(scope, zoneName, format, ...)                                                             \
-    {                                                                                                                   \
-        os_log(secLogObjForScope("SecError"), scope "-%@: " format, (zoneName ? zoneName : @"unknown"), ##__VA_ARGS__); \
-    }
-#define ckksnoticewithzonename(scope, zoneName, format, ...)                                                                         \
-    {                                                                                                                                \
-        os_log(secLogObjForCFScope((__bridge CFStringRef)[@(scope "-") stringByAppendingString:(zoneName ? zoneName : @"unknown")]), \
-               format,                                                                                                               \
-               ##__VA_ARGS__);                                                                                                       \
-    }
-#define ckksinfowithzonename(scope, zoneName, format, ...)                                                                                 \
-    {                                                                                                                                      \
-        os_log_debug(secLogObjForCFScope((__bridge CFStringRef)[@(scope "-") stringByAppendingString:(zoneName ? zoneName : @"unknown")]), \
-                     format,                                                                                                               \
-                     ##__VA_ARGS__);                                                                                                       \
-    }
+#define ckkserrorwithzonename(scope, zoneName, format, ...) \
+{ \
+    os_log_with_type(CKKSLogObject(@scope, zoneName),       \
+                    OS_LOG_TYPE_ERROR,                      \
+                    format,                                 \
+                    ##__VA_ARGS__);                         \
+}
 
-#define ckkserror(scope, zoneNameHaver, format, ...)             \
-    {                                                            \
-        NSString* znh = zoneNameHaver.zoneName;                  \
-        ckkserrorwithzonename(scope, znh, format, ##__VA_ARGS__) \
-    }
-#define ckksnotice(scope, zoneNameHaver, format, ...)             \
-    {                                                             \
-        NSString* znh = zoneNameHaver.zoneName;                   \
-        ckksnoticewithzonename(scope, znh, format, ##__VA_ARGS__) \
-    }
-#define ckksinfo(scope, zoneNameHaver, format, ...)             \
-    {                                                           \
-        NSString* znh = zoneNameHaver.zoneName;                 \
-        ckksinfowithzonename(scope, znh, format, ##__VA_ARGS__) \
-    }
+#define ckkserror(scope, zoneNameBearer, format, ...) \
+    ckkserrorwithzonename(scope, zoneNameBearer.zoneName, format, ##__VA_ARGS__)
 
-#undef ckksdebug
-#if !defined(NDEBUG)
-#define ckksdebugwithzonename(scope, zoneName, format, ...)                                                                                \
-    {                                                                                                                                      \
-        os_log_debug(secLogObjForCFScope((__bridge CFStringRef)[@(scope "-") stringByAppendingString:(zoneName ? zoneName : @"unknown")]), \
-                     format,                                                                                                               \
-                     ##__VA_ARGS__);                                                                                                       \
-    }
-#define ckksdebug(scope, zoneNameHaver, format, ...)             \
-    {                                                            \
-        NSString* znh = zoneNameHaver.zoneName;                  \
-        ckksdebugwithzonename(scope, znh, format, ##__VA_ARGS__) \
-    }
-#else
-#define ckksdebug(scope, ...) /* nothing */
-#endif
+#define ckkserror_global(scope, format, ...) \
+    ckkserrorwithzonename(scope, nil, format, ##__VA_ARGS__)
+
+#define ckksnotice(scope, zoneNameBearer, format, ...) \
+    os_log(CKKSLogObject(@scope, zoneNameBearer.zoneName), format, ##__VA_ARGS__)
+
+#define ckksnotice_global(scope, format, ...) \
+    os_log(CKKSLogObject(@scope, nil), format, ##__VA_ARGS__)
+
+#define ckksinfo(scope, zoneNameBearer, format, ...) \
+    os_log_debug(CKKSLogObject(@scope, zoneNameBearer.zoneName), format, ##__VA_ARGS__)
+
+#define ckksinfo_global(scope, format, ...) \
+    os_log_debug(CKKSLogObject(@scope, nil), format, ##__VA_ARGS__)
+
+#endif // __OBJC__
 
-#ifdef __OBJC__
-NS_ASSUME_NONNULL_END
-#else
 CF_ASSUME_NONNULL_END
-#endif
 
 #endif /* CKKS_h */
 
index 3b35e8380ee4e81d4d952c2c108c303579b0d70b..31ce6d7a26bff38e4155247d4adc1c980443f9b8 100644 (file)
@@ -27,7 +27,6 @@
 #import <CloudKit/CloudKit.h>
 #endif
 
-#include <utilities/debugging.h>
 #include "keychain/securityd/SecItemServer.h"
 #include <Security/SecItemPriv.h>
 
@@ -38,6 +37,7 @@
 #import "keychain/ckks/CKKSKey.h"
 
 #import "keychain/ot/OTManager.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
 
 NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void) {
     static NSDictionary<CKKSZoneKeyState*, NSNumber*>* map = nil;
@@ -46,7 +46,7 @@ NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void) {
         map = @{
           SecCKKSZoneKeyStateReady:              @0U,
           SecCKKSZoneKeyStateError:              @1U,
-          SecCKKSZoneKeyStateCancelled:          @2U,
+          //SecCKKSZoneKeyStateCancelled:          @2U,
 
           SecCKKSZoneKeyStateInitializing:       @3U,
           SecCKKSZoneKeyStateInitialized:        @4U,
@@ -70,6 +70,11 @@ NSDictionary<CKKSZoneKeyState*, NSNumber*>* CKKSZoneKeyStateMap(void) {
           SecCKKSZoneKeyStateWaitForTLKUpload:   @22U,
           SecCKKSZoneKeyStateWaitForTLKCreation: @23U,
           SecCKKSZoneKeyStateProcess:            @24U,
+          SecCKKSZoneKeyStateBecomeReady:        @25U,
+          SecCKKSZoneKeyStateLoseTrust:          @26U,
+          SecCKKSZoneKeyStateTLKMissing:         @27U,
+          SecCKKSZoneKeyStateWaitForCloudKitAccountStatus:@28U,
+          SecCKKSZoneKeyStateBeginFetch:         @29U,
         };
     });
     return map;
@@ -106,18 +111,27 @@ CKKSZoneKeyState* CKKSZoneKeyRecover(NSNumber* stateNumber) {
     return SecCKKSZoneKeyStateError;
 }
 
-bool CKKSKeyStateTransient(CKKSZoneKeyState* state) {
-    // Easier to compare against a blacklist of end states
-    bool nontransient = [state isEqualToString:SecCKKSZoneKeyStateReady] ||
-        [state isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock] ||
-        [state isEqualToString:SecCKKSZoneKeyStateWaitForTrust] ||
-        [state isEqualToString:SecCKKSZoneKeyStateWaitForTLK] ||
-        [state isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation] ||
-        [state isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload] ||
-        [state isEqualToString:SecCKKSZoneKeyStateWaitForUnlock] ||
-        [state isEqualToString:SecCKKSZoneKeyStateError] ||
-        [state isEqualToString:SecCKKSZoneKeyStateCancelled];
-    return !nontransient;
+NSSet<CKKSZoneKeyState*>* CKKSKeyStateNonTransientStates()
+{
+    static NSSet<CKKSZoneKeyState*>* states = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        states = [NSSet setWithArray:@[
+             SecCKKSZoneKeyStateReady,
+             SecCKKSZoneKeyStateReadyPendingUnlock,
+             SecCKKSZoneKeyStateWaitForTrust,
+             SecCKKSZoneKeyStateWaitForTLK,
+             SecCKKSZoneKeyStateWaitForTLKCreation,
+             SecCKKSZoneKeyStateWaitForTLKUpload,
+             SecCKKSZoneKeyStateWaitForUnlock,
+             SecCKKSZoneKeyStateError,
+             SecCKKSZoneKeyStateLoggedOut,
+#if OCTAGON
+             OctagonStateMachineHalted,
+#endif
+        ]];
+    });
+    return states;
 }
 
 #if OCTAGON
@@ -128,7 +142,7 @@ static bool testCKKS = false;
 bool SecCKKSIsEnabled(void) {
     if([CKDatabase class] == nil) {
         // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
-        secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS (on pain of crash).");
+        ckkserror_global("ckks", "CloudKit.framework appears to not be linked. Cannot enable CKKS (on pain of crash).");
         return false;
     }
 
@@ -158,7 +172,7 @@ bool SecCKKSTestsEnabled(void) {
 bool SecCKKSTestsEnable(void) {
     if([CKDatabase class] == nil) {
         // CloudKit is not linked. We cannot bring CKKS up; disable it with prejudice.
-        secerror("CKKS: CloudKit.framework appears to not be linked. Cannot enable CKKS testing.");
+        ckkserror_global("ckks", "CloudKit.framework appears to not be linked. Cannot enable CKKS testing.");
         testCKKS = false;
         return false;
     }
@@ -210,7 +224,7 @@ bool SecCKKSReduceRateLimiting(void) {
         [defaults registerDefaults: @{key: CKKSReduceRateLimiting ? @YES : @NO}];
 
         CKKSReduceRateLimiting = !![defaults boolForKey:@"reduce-rate-limiting"];
-        secnotice("ckks", "reduce-rate-limiting is %@", CKKSReduceRateLimiting ? @"on" : @"off");
+        ckksnotice_global("ratelimit", "reduce-rate-limiting is %@", CKKSReduceRateLimiting ? @"on" : @"off");
     });
 
     return CKKSReduceRateLimiting;
@@ -219,7 +233,7 @@ bool SecCKKSReduceRateLimiting(void) {
 bool SecCKKSSetReduceRateLimiting(bool value) {
     (void) SecCKKSReduceRateLimiting(); // Call this once to read the defaults write
     CKKSReduceRateLimiting = value;
-    secnotice("ckks", "reduce-rate-limiting is now %@", CKKSReduceRateLimiting ? @"on" : @"off");
+    ckksnotice_global("ratelimit", "reduce-rate-limiting is now %@", CKKSReduceRateLimiting ? @"on" : @"off");
     return CKKSReduceRateLimiting;
 }
 
@@ -234,7 +248,7 @@ bool SecCKKSShareTLKs(void) {
         [defaults registerDefaults: @{@"tlksharing": CKKSShareTLKs ? @YES : @NO}];
 
         CKKSShareTLKs = !![defaults boolForKey:@"tlksharing"];
-        secnotice("ckksshare", "TLK sharing is %@", CKKSShareTLKs ? @"on" : @"off");
+        ckksnotice_global("ckksshare", "TLK sharing is %@", CKKSShareTLKs ? @"on" : @"off");
     });
 
     return CKKSShareTLKs;
@@ -278,16 +292,26 @@ void SecCKKSTestSetDisableKeyNotifications(bool set) {
     CKKSDisableKeyNotifications = set;
 }
 
+static bool CKKSSkipScan = false;
+bool SecCKKSTestSkipScan(void) {
+    return CKKSSkipScan;
+}
+bool SecCKKSSetTestSkipScan(bool value) {
+    CKKSSkipScan = value;
+    return CKKSSkipScan;
+}
+
 void SecCKKSTestResetFlags(void) {
     SecCKKSTestSetDisableAutomaticUUID(false);
     SecCKKSTestSetDisableSOS(false);
     SecCKKSTestSetDisableKeyNotifications(false);
+    SecCKKSSetTestSkipScan(false);
 }
 
 #else /* NO OCTAGON */
 
 bool SecCKKSIsEnabled(void) {
-    secerror("CKKS was disabled at compile time.");
+    ckkserror_global("ckks", "CKKS was disabled at compile time.");
     return false;
 }
 
@@ -323,7 +347,7 @@ void SecCKKSInitialize(SecDbRef db) {
         if(!SecCKKSTestsEnabled()) {
             static dispatch_once_t onceToken;
             dispatch_once(&onceToken, ^{
-                [OctagonAPSReceiver receiverForEnvironment:APSEnvironmentProduction namedDelegatePort:SecCKKSAPSNamedPort apsConnectionClass:[APSConnection class]];
+                [[OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort apsConnectionClass:[APSConnection class]] registerForEnvironment:APSEnvironmentProduction];
             });
         }
     }
@@ -338,7 +362,7 @@ void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase,
 
     // Ignore our own changes, otherwise we'd infinite-loop.
     if(source == kSecDbCKKSTransaction) {
-        secinfo("ckks", "Ignoring kSecDbCKKSTransaction notification");
+        ckksinfo_global("ckks", "Ignoring kSecDbCKKSTransaction notification");
         return;
     }
 
@@ -349,7 +373,7 @@ void SecCKKSNotifyBlock(SecDbConnectionRef dbconn, SecDbTransactionPhase phase,
         SecDbEventTranslateComponents(r, (CFTypeRef*) &deleted, (CFTypeRef*) &added);
 
         if(!added && !deleted) {
-            secerror("CKKS: SecDbEvent gave us garbage: %@", r);
+            ckkserror_global("ckks", "SecDbEvent gave us garbage: %@", r);
             return;
         }
 
@@ -380,12 +404,12 @@ void CKKSRegisterSyncStatusCallback(CFStringRef cfuuid, SecBoolCFErrorCallback c
 void SecCKKSPerformLocalResync() {
 #if OCTAGON
     if(SecCKKSIsEnabled()) {
-        secnotice("ckks", "Local keychain was reset; performing local resync");
+        ckksnotice_global("reset", "Local keychain was reset; performing local resync");
         [[CKKSViewManager manager] rpcResyncLocal:nil reply:^(NSError *result) {
             if(result) {
-                secnotice("ckks", "Local keychain reset resync finished with an error: %@", result);
+                ckksnotice_global("reset", "Local keychain reset resync finished with an error: %@", result);
             } else {
-                secnotice("ckks", "Local keychain reset resync finished successfully");
+                ckksnotice_global("reset", "Local keychain reset resync finished successfully");
             }
         }];
     }
index e83a8a24e96b39638b92ce44cc8e0822de5f46c1..ef2179676df764a5fc6ecc7ffcfd8d10dc031ced 100644 (file)
@@ -83,6 +83,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status);
 @end
 @protocol CKKSCloudKitAccountStateTrackingProvider <NSObject>
 - (dispatch_semaphore_t)registerForNotificationsOfCloudKitAccountStatusChange:(id<CKKSCloudKitAccountStateListener>)listener;
+- (BOOL)notifyCKAccountStatusChangeAndWait:(dispatch_time_t)timeout;
 @end
 
 #pragma mark -- Tracker
index 05900dc0576f39a8b6dbc3e48e8439987a0f289e..8db458f711fa33f1986e6e6ba4a969f2cb66ccf8 100644 (file)
@@ -24,7 +24,6 @@
 #if OCTAGON
 
 #include <dispatch/dispatch.h>
-#include <utilities/debugging.h>
 #include <Security/SecureObjectSync/SOSCloudCircle.h>
 #include <Security/SecureObjectSync/SOSCloudCircleInternal.h>
 #include "keychain/SecureObjectSync/SOSInternal.h"
@@ -100,7 +99,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         _hsa2iCloudAccountInitialized = [[CKKSCondition alloc] init];
 
         id<CKKSNSNotificationCenter> notificationCenter = [self.nsnotificationCenterClass defaultCenter];
-        secinfo("ckksaccount", "Registering with notification center %@", notificationCenter);
+        ckksinfo_global("ckksaccount", "Registering with notification center %@", notificationCenter);
         [notificationCenter addObserver:self selector:@selector(notifyCKAccountStatusChange:) name:CKAccountChangedNotification object:NULL];
 
         WEAKIFY(self);
@@ -178,15 +177,15 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
             dispatch_queue_t objQueue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
             [self.ckChangeListeners setObject:listener forKey: objQueue];
 
-            secinfo("ckksaccount-ck", "adding a new listener: %@", listener);
+            ckksinfo_global("ckksaccount-ck", "adding a new listener: %@", listener);
 
             // If we know the current account status, let this listener know
             if(self.firstCKAccountFetch) {
-                secinfo("ckksaccount-ck", "notifying new listener %@ of current state %@", listener, self.currentCKAccountInfo);
+                ckksinfo_global("ckksaccount-ck", "notifying new listener %@ of current state %@", listener, self.currentCKAccountInfo);
 
                 dispatch_group_t g = dispatch_group_create();
                 if(!g) {
-                    secnotice("ckksaccount-ck", "Unable to get dispatch group.");
+                    ckkserror_global("ckksaccount-ck", "Unable to get dispatch group.");
                     dispatch_semaphore_signal(finishedSema);
                     return;
                 }
@@ -217,14 +216,14 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         STRONGIFY(self);
 
         if(error) {
-            secerror("ckksaccount: error getting account info: %@", error);
+            ckkserror_global("ckksaccount", "error getting account info: %@", error);
             dispatch_semaphore_signal(finishedSema);
             return;
         }
 
         dispatch_sync(self.queue, ^{
             self.firstCKAccountFetch = true;
-            secnotice("ckksaccount", "received CK Account info: %@", ckAccountInfo);
+            ckksnotice_global("ckksaccount", "received CK Account info: %@", ckAccountInfo);
             [self _onqueueUpdateAccountState:ckAccountInfo deliveredSemaphore:finishedSema];
         });
     }];
@@ -242,7 +241,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         [self.container fetchCurrentDeviceIDWithCompletionHandler:^(NSString* deviceID, NSError* ckerror) {
             STRONGIFY(self);
             if(!self) {
-                secerror("ckksaccount: Received fetchCurrentDeviceIDWithCompletionHandler callback with null AccountStateTracker");
+                ckkserror_global("ckksaccount", "Received fetchCurrentDeviceIDWithCompletionHandler callback with null AccountStateTracker");
                 return;
             }
 
@@ -250,14 +249,14 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
             dispatch_async(self.queue, ^{
                 STRONGIFY(self);
                 if(self.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) {
-                    secnotice("ckksaccount", "CloudKit deviceID is: %@ %@", deviceID, ckerror);
+                    ckksnotice_global("ckksaccount", "CloudKit deviceID is: %@ %@", deviceID, ckerror);
 
                     self.ckdeviceID = deviceID;
                     self.ckdeviceIDError = ckerror;
                     [self.ckdeviceIDInitialized fulfill];
                 } else {
                     // Logged out! No ckdeviceid.
-                    secerror("ckksaccount: Logged back out but still received a fetchCurrentDeviceIDWithCompletionHandler callback");
+                    ckkserror_global("ckksaccount", "Logged back out but still received a fetchCurrentDeviceIDWithCompletionHandler callback");
 
                     self.ckdeviceID = nil;
                     self.ckdeviceIDError = nil;
@@ -279,7 +278,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
     SOSAccountStatus* sosstatus = [CKKSAccountStateTracker getCircleStatus];
     dispatch_sync(self.queue, ^{
         if(self.currentCircleStatus == nil || ![self.currentCircleStatus isEqual:sosstatus]) {
-            secnotice("ckksaccount", "moving to circle status: %@", sosstatus);
+            ckksnotice_global("ckksaccount", "moving to circle status: %@", sosstatus);
             self.currentCircleStatus = sosstatus;
 
             if (sosstatus.status == kSOSCCInCircle) {
@@ -315,7 +314,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         [CKKSAccountStateTracker fetchCirclePeerID:^(NSString* peerID, NSError* error) {
             STRONGIFY(self);
             if(!self) {
-                secerror("ckksaccount: Received fetchCirclePeerID callback with null AccountStateTracker");
+                ckkserror_global("ckksaccount", "Received fetchCirclePeerID callback with null AccountStateTracker");
                 return;
             }
 
@@ -323,13 +322,13 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
                 STRONGIFY(self);
 
                 if(self.currentCircleStatus && self.currentCircleStatus.status == kSOSCCInCircle) {
-                    secnotice("ckksaccount", "Circle peerID is: %@ %@", peerID, error);
+                    ckksnotice_global("ckksaccount", "Circle peerID is: %@ %@", peerID, error);
                     // Still in circle. Proceed.
                     self.accountCirclePeerID = peerID;
                     self.accountCirclePeerIDError = error;
                     [self.accountCirclePeerIDInitialized fulfill];
                 } else {
-                    secerror("ckksaccount: Out of circle but still received a fetchCirclePeerID callback");
+                    ckkserror_global("ckksaccount", "Out of circle but still received a fetchCirclePeerID callback");
                     // Not in-circle. Throw away circle id.
                     self.accountCirclePeerID = nil;
                     self.accountCirclePeerIDError = nil;
@@ -339,7 +338,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         }];
     } else {
         // Not in-circle, reset circle ID
-        secnotice("ckksaccount", "out of circle(%@): resetting peer ID", sosstatus);
+        ckksnotice_global("ckksaccount", "out of circle(%@): resetting peer ID", sosstatus);
         self.accountCirclePeerID = nil;
         self.accountCirclePeerIDError = nil;
         self.accountCirclePeerIDInitialized = [[CKKSCondition alloc] init];
@@ -356,7 +355,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
 
     dispatch_group_t g = dispatch_group_create();
     if(!g) {
-        secnotice("ckksaccount", "Unable to get dispatch group.");
+        ckksnotice_global("ckksaccount", "Unable to get dispatch group.");
         dispatch_semaphore_signal(finishedSema);
         return;
     }
@@ -376,13 +375,13 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
 
     if([self.currentCKAccountInfo isEqual: ckAccountInfo]) {
         // no-op.
-        secinfo("ckksaccount", "received another notification of CK Account State %@", ckAccountInfo);
+        ckksinfo_global("ckksaccount", "received another notification of CK Account State %@", ckAccountInfo);
         return;
     }
 
     if((self.currentCKAccountInfo == nil && ckAccountInfo != nil) ||
        !(self.currentCKAccountInfo == ckAccountInfo || [self.currentCKAccountInfo isEqual: ckAccountInfo])) {
-        secnotice("ckksaccount", "moving to CK Account info: %@", ckAccountInfo);
+        ckksnotice_global("ckksaccount", "moving to CK Account info: %@", ckAccountInfo);
         CKAccountInfo* oldAccountInfo = self.currentCKAccountInfo;
         self.currentCKAccountInfo = ckAccountInfo;
         [self.ckAccountInfoInitialized fulfill];
@@ -424,8 +423,13 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
     }
 }
 
+- (BOOL)notifyCKAccountStatusChangeAndWait:(dispatch_time_t)timeout
+{
+    return dispatch_semaphore_wait([self notifyCKAccountStatusChange:nil], dispatch_time(DISPATCH_TIME_NOW, timeout)) == 0;
+}
+
 -(void)notifyCKAccountStatusChangeAndWaitForSignal {
-    dispatch_semaphore_wait([self notifyCKAccountStatusChange: nil], DISPATCH_TIME_FOREVER);
+    [self notifyCKAccountStatusChangeAndWait:DISPATCH_TIME_FOREVER];
 }
 
 -(void)notifyCircleStatusChangeAndWaitForSignal {
@@ -436,7 +440,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
 
     dispatch_group_t g = dispatch_group_create();
     if(!g) {
-        secnotice("ckksaccount", "Unable to get dispatch group.");
+        ckksnotice_global("ckksaccount", "Unable to get dispatch group.");
         return nil;
     }
 
@@ -448,12 +452,12 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
         while ((dq = [enumerator nextObject])) {
             id<CKKSCloudKitAccountStateListener> listener = [self.ckChangeListeners objectForKey: dq];
 
-            secinfo("ckksaccountblock", "Starting blocking for listener %@", listener);
+            ckksinfo_global("ckksaccountblock", "Starting blocking for listener %@", listener);
             WEAKIFY(listener);
             dispatch_group_async(g, dq, ^{
                 STRONGIFY(listener);
                 // Do nothing in particular. It's just important that this block runs.
-                secinfo("ckksaccountblock", "Done blocking for listener %@", listener);
+                ckksinfo_global("ckksaccountblock", "Done blocking for listener %@", listener);
             });
         }
     });
@@ -467,7 +471,7 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
 
     SOSCCStatus status = SOSCCThisDeviceIsInCircle(&cferror);
     if(cferror) {
-        secerror("ckksaccount: error getting circle status: %@", cferror);
+        ckkserror_global("ckksaccount", "error getting circle status: %@", cferror);
         return [[SOSAccountStatus alloc] init:kSOSCCError error:CFBridgingRelease(cferror)];
     }
 
@@ -503,10 +507,10 @@ NSString* CKKSAccountStatusToString(CKKSAccountStatus status)
 
                                         dispatch_sync(self.queue, ^{
                                             if(error) {
-                                                secerror("ckksaccount: error getting octagon status: %@", error);
+                                                ckkserror_global("ckksaccount", "error getting octagon status: %@", error);
                                                 self.octagonStatus = [[OTCliqueStatusWrapper alloc] initWithStatus:CliqueStatusError];
                                             } else {
-                                                secnotice("ckksaccount", "Caching octagon status as (%@, %@)", OTCliqueStatusToString(status), peerID);
+                                                ckksnotice_global("ckksaccount", "Caching octagon status as (%@, %@)", OTCliqueStatusToString(status), peerID);
                                                 self.octagonStatus = [[OTCliqueStatusWrapper alloc] initWithStatus:status];
                                             }
 
index b90f425261d3b8cc58c9985797ac1eb0787be3c4..357a032c96eb1b999211b296dc20a03edf3d1347 100644 (file)
@@ -43,6 +43,7 @@ extern NSString* const OctagonAnalyticIcloudAccountState;
 extern NSString* const OctagonAnalyticCDPBitStatus;
 extern NSString* const OctagonAnalyticsTrustState;
 extern NSString* const OctagonAnalyticsAttemptedJoin;
+extern NSString* const OctagonAnalyticsUserControllableViewsSyncing;
 extern NSString* const OctagonAnalyticsLastHealthCheck;
 extern NSString* const OctagonAnalyticsSOSStatus;
 extern NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin;
@@ -73,8 +74,6 @@ extern NSString* const OctagonAnalyticsBottledTotalTLKSharesRecovered;
 extern NSString* const OctagonAnalyticsBottledUniqueTLKsWithSharesCount;
 extern NSString* const OctagonAnalyticsBottledTLKUniqueViewCount;
 
-@class CKKSKeychainView;
-
 @protocol CKKSAnalyticsFailableEvent <NSObject>
 @end
 typedef NSString<CKKSAnalyticsFailableEvent> CKKSAnalyticsFailableEvent;
@@ -211,17 +210,12 @@ extern CKKSAnalyticsActivity* const OctagonSOSAdapterUpdateKeys;
 
 + (instancetype)logger;
 
-- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view;
+- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)viewName;
 - (void)logRecoverableError:(NSError*)error
                    forEvent:(CKKSAnalyticsFailableEvent*)event
-                     inView:(CKKSKeychainView*)view
+                   zoneName:(NSString*)viewName
              withAttributes:(NSDictionary*)attributes;
 
-- (void)logRecoverableError:(NSError*)error
-                   forEvent:(CKKSAnalyticsFailableEvent*)event
-                   zoneName:(NSString*)zoneName
-             withAttributes:(NSDictionary *)attributes;
-
 - (void)logRecoverableError:(NSError*)error
                    forEvent:(CKKSAnalyticsFailableEvent*)event
              withAttributes:(NSDictionary *)attributes;
@@ -232,21 +226,21 @@ extern CKKSAnalyticsActivity* const OctagonSOSAdapterUpdateKeys;
 
 - (void)logUnrecoverableError:(NSError*)error
                      forEvent:(CKKSAnalyticsFailableEvent*)event
-                       inView:(CKKSKeychainView*)view
+                     zoneName:(NSString*)viewName
                withAttributes:(NSDictionary*)attributes;
 
 - (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event;
-- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view;
+- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event zoneName:(NSString*)zoneName;
 
-- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key inView:(CKKSKeychainView *)view;
-- (NSDate *)datePropertyForKey:(NSString *)key inView:(CKKSKeychainView *)view;
+- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key zoneName:(NSString*)zoneName;
+- (NSDate *)datePropertyForKey:(NSString *)key zoneName:(NSString*)zoneName;
 
 @end
 
 @interface CKKSAnalytics (UnitTesting)
 
 - (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event
-                              inView:(CKKSKeychainView*)view;
+                            zoneName:(NSString*)zoneName;
 - (NSDictionary *)errorChain:(NSError *)error
                        depth:(NSUInteger)depth;
 - (NSDictionary *)createErrorAttributes:(NSError *)error
index 6547366d6c8f2b48d3a664fce7836ba7240ff09a..dcc6b61c1bbb0a27e4430cf7f1461aea0196d662 100644 (file)
@@ -53,6 +53,7 @@ NSString* const OctagonAnalyticCDPBitStatus = @"OACDPStatus";
 
 NSString* const OctagonAnalyticsTrustState = @"OATrust";
 NSString* const OctagonAnalyticsAttemptedJoin = @"OAAttemptedJoin";
+NSString* const OctagonAnalyticsUserControllableViewsSyncing = @"OAUserViewsSyncing";
 NSString* const OctagonAnalyticsLastHealthCheck = @"OAHealthCheck";
 NSString* const OctagonAnalyticsSOSStatus = @"OASOSStatus";
 NSString* const OctagonAnalyticsDateOfLastPreflightPreapprovedJoin = @"OALastPPJ";
@@ -221,10 +222,10 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
     return [super logger];
 }
 
-- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
+- (void)logSuccessForEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)zoneName
 {
-    [self logSuccessForEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
-    [self setDateProperty:[NSDate date] forKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
+    [self logSuccessForEventNamed:[NSString stringWithFormat:@"%@-%@", zoneName, event]];
+    [self setDateProperty:[NSDate date] forKey:[NSString stringWithFormat:@"last_success_%@-%@", zoneName, event]];
 }
 
 - (bool)isCKPartialError:(NSError *)error
@@ -297,7 +298,10 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
     return eventAttributes;
 }
 
-- (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)zoneName withAttributes:(NSDictionary *)attributes
+- (void)logRecoverableError:(NSError*)error
+                   forEvent:(CKKSAnalyticsFailableEvent*)event
+                   zoneName:(NSString*)zoneName
+             withAttributes:(NSDictionary *)attributes
 {
     if (error == nil){
         return;
@@ -346,32 +350,10 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
     [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
 }
 
-- (void)logRecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
-{
-    if (error == nil){
-        return;
-    }
-    NSMutableDictionary* eventAttributes = [NSMutableDictionary dictionary];
-
-    /* Don't allow caller to overwrite our attributes, lets merge them first */
-    if (attributes) {
-        [eventAttributes setValuesForKeysWithDictionary:attributes];
-    }
-
-    [eventAttributes setValuesForKeysWithDictionary:@{
-        CKKSAnalyticsAttributeRecoverableError : @(YES),
-        CKKSAnalyticsAttributeZoneName : view.zoneName,
-        CKKSAnalyticsAttributeErrorDomain : error.domain,
-        CKKSAnalyticsAttributeErrorCode : @(error.code)
-    }];
-
-    eventAttributes[CKKSAnalyticsAttributeErrorChain] = [self errorChain:error.userInfo[NSUnderlyingErrorKey] depth:0];
-    [self addCKPartialError:eventAttributes error:error depth:0];
-
-    [super logSoftFailureForEventNamed:event withAttributes:eventAttributes];
-}
-
-- (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view withAttributes:(NSDictionary *)attributes
+- (void)logUnrecoverableError:(NSError*)error
+                     forEvent:(CKKSAnalyticsFailableEvent*)event
+                     zoneName:(NSString*)zoneName
+               withAttributes:(NSDictionary *)attributes
 {
     if (error == nil){
         return;
@@ -386,7 +368,7 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
 
     [eventAttributes setValuesForKeysWithDictionary:@{
         CKKSAnalyticsAttributeRecoverableError : @(NO),
-        CKKSAnalyticsAttributeZoneName : view.zoneName,
+        CKKSAnalyticsAttributeZoneName : zoneName,
         CKKSAnalyticsAttributeErrorDomain : error.domain,
         CKKSAnalyticsAttributeErrorCode : @(error.code)
     }];
@@ -394,7 +376,9 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
     [self logHardFailureForEventNamed:event withAttributes:eventAttributes];
 }
 
-- (void)logUnrecoverableError:(NSError*)error forEvent:(CKKSAnalyticsFailableEvent*)event withAttributes:(NSDictionary *)attributes
+- (void)logUnrecoverableError:(NSError*)error
+                     forEvent:(CKKSAnalyticsFailableEvent*)event
+               withAttributes:(NSDictionary *)attributes
 {
     if (error == nil){
         return;
@@ -423,23 +407,23 @@ CKKSAnalyticsActivity* const OctagonActivityRemoveFriendsInClique = (CKKSAnalyti
 {
     [self noteEventNamed:event];
 }
-- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event inView:(CKKSKeychainView*)view
+- (void)noteEvent:(CKKSAnalyticsSignpostEvent*)event zoneName:(NSString*)zoneName
 {
-    [self noteEventNamed:[NSString stringWithFormat:@"%@-%@", view.zoneName, event]];
+    [self noteEventNamed:[NSString stringWithFormat:@"%@-%@", zoneName, event]];
 }
 
-- (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event inView:(CKKSKeychainView*)view
+- (NSDate*)dateOfLastSuccessForEvent:(CKKSAnalyticsFailableEvent*)event zoneName:(NSString*)zoneName
 {
-    return [self datePropertyForKey:[NSString stringWithFormat:@"last_success_%@-%@", view.zoneName, event]];
+    return [self datePropertyForKey:[NSString stringWithFormat:@"last_success_%@-%@", zoneName, event]];
 }
 
-- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key inView:(CKKSKeychainView *)view
+- (void)setDateProperty:(NSDate*)date forKey:(NSString*)key zoneName:(NSString*)zoneName
 {
-    [self setDateProperty:date forKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
+    [self setDateProperty:date forKey:[NSString stringWithFormat:@"%@-%@", key, zoneName]];
 }
-- (NSDate *)datePropertyForKey:(NSString *)key inView:(CKKSKeychainView *)view
+- (NSDate *)datePropertyForKey:(NSString *)key zoneName:(NSString*)zoneName
 {
-    return [self datePropertyForKey:[NSString stringWithFormat:@"%@-%@", key, view.zoneName]];
+    return [self datePropertyForKey:[NSString stringWithFormat:@"%@-%@", key, zoneName]];
 }
 
 @end
diff --git a/keychain/ckks/CKKSCheckKeyHierarchyOperation.h b/keychain/ckks/CKKSCheckKeyHierarchyOperation.h
new file mode 100644 (file)
index 0000000..0ed2769
--- /dev/null
@@ -0,0 +1,23 @@
+
+#import <Foundation/Foundation.h>
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CKKSCheckKeyHierarchyOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ckks/CKKSCheckKeyHierarchyOperation.m b/keychain/ckks/CKKSCheckKeyHierarchyOperation.m
new file mode 100644 (file)
index 0000000..874969c
--- /dev/null
@@ -0,0 +1,198 @@
+
+#if OCTAGON
+
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ckks/CKKSCheckKeyHierarchyOperation.h"
+#import "keychain/ckks/CKKSMirrorEntry.h"
+#import "keychain/ot/OTDefines.h"
+#import "utilities/SecTrace.h"
+
+@implementation CKKSCheckKeyHierarchyOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if(self = [super init]) {
+        _deps = dependencies;
+
+        _intendedState = intendedState;
+        _nextState = errorState;
+    }
+    return self;
+}
+
+- (void)main {
+    NSArray<CKKSPeerProviderState*>* currentTrustStates = [self.deps currentTrustStates];
+
+    __block CKKSCurrentKeySet* set = nil;
+
+    [self.deps.databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
+        set = [CKKSCurrentKeySet loadForZone:self.deps.zoneID];
+    }];
+
+    // Drop off the sql queue: we can do the rest of this function with what we've already loaded
+
+    if(set.error && !([set.error.domain isEqual: @"securityd"] && set.error.code == errSecItemNotFound)) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error examining existing key hierarchy: %@", set.error);
+    }
+
+    if(!set.currentTLKPointer && !set.currentClassAPointer && !set.currentClassCPointer) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error examining existing key hierarchy (missing all CKPs, likely no hierarchy exists): %@", set);
+        self.nextState = SecCKKSZoneKeyStateWaitForTLKCreation;
+        return;
+    }
+
+    // Check keyset
+    if(!set.tlk || !set.classA || !set.classC) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error examining existing key hierarchy (missing at least one key): %@", set);
+        self.error = set.error;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    }
+
+    NSError* localerror = nil;
+    bool probablyOkIfUnlocked = false;
+
+    // keychain being locked is not a fatal error here
+    [set.tlk loadKeyMaterialFromKeychain:&localerror];
+    if(localerror && ![self.deps.lockStateTracker isLockedError:localerror]) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error loading TLK(%@): %@", set.tlk, localerror);
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    } else if(localerror) {
+        ckkserror("ckkskey", self.deps.zoneID, "Soft error loading TLK(%@), maybe locked: %@", set.tlk, localerror);
+        probablyOkIfUnlocked = true;
+    }
+    localerror = nil;
+
+    // keychain being locked is not a fatal error here
+    [set.classA loadKeyMaterialFromKeychain:&localerror];
+    if(localerror && ![self.deps.lockStateTracker isLockedError:localerror]) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error loading classA key(%@): %@", set.classA, localerror);
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    } else if(localerror) {
+        ckkserror("ckkskey", self.deps.zoneID, "Soft error loading classA key(%@), maybe locked: %@", set.classA, localerror);
+        probablyOkIfUnlocked = true;
+    }
+    localerror = nil;
+
+    // keychain being locked is a fatal error here, since this is class C
+    [set.classC loadKeyMaterialFromKeychain:&localerror];
+    if(localerror) {
+        ckkserror("ckkskey", self.deps.zoneID, "Error loading classC(%@): %@", set.classC, localerror);
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    }
+
+    // Check that the classA and classC keys point to the current TLK
+    if(![set.classA.parentKeyUUID isEqualToString: set.tlk.uuid]) {
+        localerror = [NSError errorWithDomain:CKKSServerExtensionErrorDomain
+                                         code:CKKSServerUnexpectedSyncKeyInChain
+                                     userInfo:@{
+                                                NSLocalizedDescriptionKey: @"Current class A key does not wrap to current TLK",
+                                               }];
+        ckkserror("ckkskey", self.deps.zoneID, "Key hierarchy unhealthy: %@", localerror);
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    }
+    if(![set.classC.parentKeyUUID isEqualToString: set.tlk.uuid]) {
+        localerror = [NSError errorWithDomain:CKKSServerExtensionErrorDomain
+                                         code:CKKSServerUnexpectedSyncKeyInChain
+                                     userInfo:@{
+                                                NSLocalizedDescriptionKey: @"Current class C key does not wrap to current TLK",
+                                               }];
+        ckkserror("ckkskey", self.deps.zoneID, "Key hierarchy unhealthy: %@", localerror);
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    }
+
+    // Now that we're pretty sure we have the keys, are they shared appropriately?
+    // We need trust in order to proceed here
+    if(currentTrustStates.count == 0u) {
+        ckkserror("ckkskey", self.deps.zoneID, "Can't check TLKShares due to missing trust states");
+        [self.deps provideKeySet:set];
+        self.nextState = SecCKKSZoneKeyStateLoseTrust;
+        return;
+    }
+
+    // If we've reached this point, we have a workable keyset. Let's provide it to all waiters.
+    [self.deps provideKeySet:set];
+
+    if(probablyOkIfUnlocked) {
+        ckkserror("ckkskey", self.deps.zoneID, "Can't check TLKShares due to lock state");
+        [self.deps provideKeySet:set];
+        self.nextState = SecCKKSZoneKeyStateReadyPendingUnlock;
+        return;
+    }
+
+    // Check that every trusted peer has at least one TLK share
+    // If any trust state check works, don't error out
+    bool anyTrustStateSucceeded = false;
+    for(CKKSPeerProviderState* trustState in currentTrustStates) {
+        NSSet<id<CKKSPeer>>* missingShares = [trustState findPeersMissingTLKSharesFor:set
+                                                                                error:&localerror];
+
+        if(localerror && [self.deps.lockStateTracker isLockedError:localerror]) {
+            ckkserror("ckkskey", self.deps.zoneID, "Couldn't find missing TLK shares due to lock state: %@", localerror);
+            continue;
+
+        } else if(([localerror.domain isEqualToString:TrustedPeersHelperErrorDomain] && localerror.code == TrustedPeersHelperErrorNoPreparedIdentity) ||
+                  ([localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSLackingTrust) ||
+                  ([localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSNoPeersAvailable)) {
+            ckkserror("ckkskey", self.deps.zoneID, "Couldn't find missing TLK shares due some trust issue: %@", localerror);
+
+            if(trustState.essential) {
+                ckkserror("ckkskey", self.deps.zoneID, "Trust state is considered essential; entering waitfortrust: %@", trustState);
+
+                // Octagon can reinform us when it thinks we should start again
+                self.nextState = SecCKKSZoneKeyStateLoseTrust;
+
+                return;
+            } else {
+                ckkserror("ckkskey", self.deps.zoneID, "Peer provider is considered nonessential; ignoring error: %@", trustState);
+                continue;
+            }
+
+        } else if(localerror) {
+            ckkserror("ckkskey", self.deps.zoneID, "Error finding missing TLK shares: %@", localerror);
+            continue;
+        }
+
+        if(!missingShares || missingShares.count != 0u) {
+            ckksnotice("ckksshare", self.deps.zoneID, "TLK (%@) is not shared correctly for trust state %@, but we believe AKS is locked", set.tlk, trustState.peerProviderID);
+
+            self.error = [NSError errorWithDomain:CKKSErrorDomain
+                                             code:CKKSMissingTLKShare
+                                      description:[NSString stringWithFormat:@"Missing shares for %lu peers", (unsigned long)missingShares.count]];
+            self.nextState = SecCKKSZoneKeyStateHealTLKShares;
+            return;
+        } else {
+            ckksnotice("ckksshare", self.deps.zoneID, "TLK (%@) is shared correctly for trust state %@", set.tlk, trustState.peerProviderID);
+        }
+
+        anyTrustStateSucceeded |= true;
+    }
+
+    if(!anyTrustStateSucceeded) {
+        self.error = localerror;
+        self.nextState = SecCKKSZoneKeyStateError;
+
+        return;
+    }
+
+    // Got to the bottom? Cool! All keys are present and accounted for.
+    self.nextState = SecCKKSZoneKeyStateReady;
+}
+
+@end
+
+#endif // OCTAGON
index f680d81b19923613610a4ca013d8c138b3b1c1c5..60c3ce967532ec784debec95d9595b652173a270 100644 (file)
@@ -16,6 +16,7 @@ CKKSItemState* const SecCKKSStateInFlight = (CKKSItemState*) @"inflight";
 CKKSItemState* const SecCKKSStateReencrypt = (CKKSItemState*) @"reencrypt";
 CKKSItemState* const SecCKKSStateError = (CKKSItemState*) @"error";
 CKKSItemState* const SecCKKSStateDeleted = (CKKSItemState*) @"deleted";
+CKKSItemState* const SecCKKSStateMismatchedView = (CKKSItemState*) @"mismatched_view";
 
 CKKSProcessedState* const SecCKKSProcessedStateLocal = (CKKSProcessedState*) @"local";
 CKKSProcessedState* const SecCKKSProcessedStateRemote = (CKKSProcessedState*) @"remote";
@@ -87,21 +88,27 @@ NSString* const SecCKRecordManifestLeafType = @"manifest_leaf";
 NSString* const SecCKRecordManifestLeafDERKey = @"der";
 NSString* const SecCKRecordManifestLeafDigestKey = @"digest";
 
+CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForCloudKitAccountStatus = (CKKSZoneKeyState*)@"wait_for_ck_account_status";
+
 CKKSZoneKeyState* const SecCKKSZoneKeyStateReady = (CKKSZoneKeyState*) @"ready";
+CKKSZoneKeyState* const SecCKKSZoneKeyStateBecomeReady = (CKKSZoneKeyState*) @"become_ready";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateReadyPendingUnlock = (CKKSZoneKeyState*) @"readypendingunlock";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateError = (CKKSZoneKeyState*) @"error";
-CKKSZoneKeyState* const SecCKKSZoneKeyStateCancelled = (CKKSZoneKeyState*) @"cancelled";
 
 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitializing = (CKKSZoneKeyState*) @"initializing";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateInitialized = (CKKSZoneKeyState*) @"initialized";
+CKKSZoneKeyState* const SecCKKSZoneKeyStateBeginFetch = (CKKSZoneKeyState*) @"begin_fetch";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateFetch = (CKKSZoneKeyState*) @"fetching";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateFetchComplete = (CKKSZoneKeyState*) @"fetchcomplete";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateNeedFullRefetch = (CKKSZoneKeyState*) @"needrefetch";
+
+CKKSZoneKeyState* const SecCKKSZoneKeyStateTLKMissing = (CKKSZoneKeyState*) @"tlkmissing";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLK = (CKKSZoneKeyState*) @"waitfortlk";
 
 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLKCreation = (CKKSZoneKeyState*) @"waitfortlkcreation";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTLKUpload = (CKKSZoneKeyState*) @"waitfortlkupload";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForUnlock = (CKKSZoneKeyState*) @"waitforunlock";
+CKKSZoneKeyState* const SecCKKSZoneKeyStateLoseTrust = (CKKSZoneKeyState*) @"lose_trust";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateWaitForTrust = (CKKSZoneKeyState*) @"waitfortrust";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateUnhealthy = (CKKSZoneKeyState*) @"unhealthy";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateBadCurrentPointers = (CKKSZoneKeyState*) @"badcurrentpointers";
@@ -113,7 +120,7 @@ CKKSZoneKeyState* const SecCKKSZoneKeyStateResettingZone = (CKKSZoneKeyState*) @
 CKKSZoneKeyState* const SecCKKSZoneKeyStateResettingLocalData = (CKKSZoneKeyState*) @"resetlocal";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateLoggedOut = (CKKSZoneKeyState*) @"loggedout";
 CKKSZoneKeyState* const SecCKKSZoneKeyStateZoneCreationFailed = (CKKSZoneKeyState*) @"zonecreationfailed";
-CKKSZoneKeyState* const SecCKKSZoneKeyStateProcess = (CKKSZoneKeyState*) @"process";
+CKKSZoneKeyState* const SecCKKSZoneKeyStateProcess = (CKKSZoneKeyState*) @"process_key_hierarchy";
 
 NSString* const CKKSErrorDomain = @"CKKSErrorDomain";
 NSString* const CKKSServerExtensionErrorDomain = @"CKKSServerExtensionErrorDomain";
index 7a071d0aff86cdf5a8edbe2b5dc9f3de16665887..92ddf33091110e435242b2377a1eb16064204377 100644 (file)
@@ -34,6 +34,7 @@ typedef NS_ENUM(NSUInteger, CKKSKnownBadState) {
     CKKSKnownStateTLKsMissing = 1,   // CKKS doesn't have the TLKs: your operation will likely not succeed
     CKKSKnownStateWaitForUnlock = 2, // CKKS has some important things to do, but the device is locked. Your operation will likely not succeed
     CKKSKnownStateWaitForOctagon = 3, // CKKS has important things to do, but Octagon hasn't done them yet. Your operation will likely not succeed
+    CKKSKnownStateNoCloudKitAccount = 4, // The device isn't signed into CloudKit. Your operation will likely not succeed
 };
 
 @interface CKKSControl : NSObject
@@ -49,6 +50,7 @@ typedef NS_ENUM(NSUInteger, CKKSKnownBadState) {
                 reply:(void (^)(NSArray<NSDictionary*>* _Nullable result, NSError* _Nullable error))reply;
 - (void)rpcResetLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
 - (void)rpcResetCloudKit:(NSString* _Nullable)viewName reason:(NSString *)reason reply:(void (^)(NSError* _Nullable error))reply;
+- (void)rpcResyncLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
 - (void)rpcResync:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
 - (void)rpcFetchAndProcessChanges:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
 - (void)rpcFetchAndProcessClassAChanges:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply;
index f4d75de75ebc2451b1bf7df7a71d350d172135a8..fc09adc740d57da1e4333181df8397af49f730c9 100644 (file)
@@ -31,8 +31,7 @@
 #import "keychain/ckks/CKKSControl.h"
 #import "keychain/ckks/CKKSControlProtocol.h"
 #import "keychain/ckks/CKKSControlServer.h"
-
-#include <security_utilities/debugging.h>
+#import "utilities/debugging.h"
 
 @interface CKKSControl ()
 @property (readwrite,assign) BOOL synchronous;
     return self;
 }
 
+- (void)dealloc {
+    [self.connection invalidate];
+}
+
 - (id<CKKSControlProtocol>)objectProxyWithErrorHandler:(void(^)(NSError * _Nonnull error))failureHandler
 {
     if (self.synchronous) {
@@ -78,6 +81,7 @@
 
 
 - (void)rpcResetLocal:(NSString*)viewName reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a local reset for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcResetLocal:viewName reply:^(NSError* error){
@@ -86,6 +90,7 @@
 }
 
 - (void)rpcResetCloudKit:(NSString*)viewName reason:(NSString *)reason reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a CloudKit reset for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcResetCloudKit:viewName reason:reason reply:^(NSError* error){
     }];
 }
 
-
+- (void)rpcResyncLocal:(NSString* _Nullable)viewName reply:(void (^)(NSError* _Nullable error))reply
+{
+    secnotice("ckkscontrol", "Requesting a local resync for view %@", viewName);
+    [[self objectProxyWithErrorHandler:^(NSError* error) {
+        reply(error);
+    }] rpcResyncLocal:viewName reply:^(NSError* error){
+        reply(error);
+    }];
+}
 - (void)rpcResync:(NSString*)viewName reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a resync for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcResync:viewName reply:^(NSError* error){
     }];
 }
 - (void)rpcFetchAndProcessChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a fetch for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcFetchAndProcessChanges:viewName reply:^(NSError* error){
     }];
 }
 - (void)rpcFetchAndProcessClassAChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a fetch(classA) for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcFetchAndProcessClassAChanges:viewName reply:^(NSError* error){
     }];
 }
 - (void)rpcPushOutgoingChanges:(NSString*)viewName reply:(void(^)(NSError* error))reply {
+    secnotice("ckkscontrol", "Requesting a push for view %@", viewName);
     [[self objectProxyWithErrorHandler:^(NSError* error) {
         reply(error);
     }] rpcPushOutgoingChanges:viewName reply:^(NSError* error){
         bool tlkMissing = false;
         bool waitForUnlock = false;
         bool waitForOctagon = false;
+        bool noAccount = false;
 
         CKKSKnownBadState response = CKKSKnownStatePossiblyGood;
 
             }
 
             if([keystate isEqualToString:@"waitfortlkcreation"] ||
-               [keystate isEqualToString:@"waitfortlkupload"]) {
+               [keystate isEqualToString:@"waitfortlkupload"] ||
+               [keystate isEqualToString:@"waitfortrust"]) {
                 waitForOctagon = true;
             }
+
+            if([keystate isEqualToString:@"loggedout"]) {
+                noAccount = true;
+            }
         }
 
-        response = (tlkMissing ? CKKSKnownStateTLKsMissing :
-                   (waitForUnlock ? CKKSKnownStateWaitForUnlock :
-                    (waitForOctagon ? CKKSKnownStateWaitForOctagon :
-                    CKKSKnownStatePossiblyGood)));
+        response = (noAccount ? CKKSKnownStateNoCloudKitAccount :
+                    (tlkMissing ? CKKSKnownStateTLKsMissing :
+                     (waitForUnlock ? CKKSKnownStateWaitForUnlock :
+                      (waitForOctagon ? CKKSKnownStateWaitForOctagon :
+                       CKKSKnownStatePossiblyGood))));
 
         reply(response);
     }];
index d96fae7b2eb3cc1605a248b90c2572937956ccbf..1775d8908744399e809de4d26e8feb8c1e9cea2b 100644 (file)
@@ -25,7 +25,7 @@
 
 @protocol CKKSControlProtocol <NSObject>
 - (void)performanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *))reply;
-- (void)rpcResetLocal:    (NSString*)viewName reply: (void(^)(NSError* result)) reply;
+- (void)rpcResetLocal: (NSString*)viewName reply: (void(^)(NSError* result)) reply;
 
 /**
  * Reset CloudKit zone with a caller provided reason, the reason will be logged in the operation group
index 648b8253296baae73c4feb00733c4955ac1b45ba..4109183baf5e600750898b9d162a98ecae546b5f 100644 (file)
 #if OCTAGON
 #import <CloudKit/CloudKit.h>
 #import <CloudKit/CloudKit_Private.h>
-#import <utilities/debugging.h>
+#import <objc/runtime.h>
+#import "utilities/debugging.h"
 #include <dlfcn.h>
+#import <Security/SecXPCHelper.h>
 
 // Weak-link CloudKit, until we can get ckksctl out of base system
 static void *cloudKit = NULL;
@@ -67,48 +69,26 @@ NSXPCInterface* CKKSSetupControlProtocol(NSXPCInterface* interface) {
         __typeof(CKAcceptableValueClasses) *soft_CKAcceptableValueClasses = NULL;
         getCloudKitSymbol((void **)&soft_CKAcceptableValueClasses, "CKAcceptableValueClasses");
         errClasses = [NSMutableSet setWithSet:soft_CKAcceptableValueClasses()];
-
-        char *classes[] = {
-            "CKPrettyError",
-            "CKRecordID",
-            "NSArray",
-            "NSData",
-            "NSDate",
-            "NSDictionary",
-            "NSError",
-            "NSNull",
-            "NSNumber",
-            "NSOrderedSet",
-            "NSSet",
-            "NSString",
-            "NSURL",
-        };
-
-        for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
-            Class cls = objc_getClass(classes[n]);
-            if (cls) {
-                [errClasses addObject:cls];
-            }
-        }
+        [errClasses unionSet:[SecXPCHelper safeErrorClasses]];
     });
 
     @try {
-        [interface setClasses:errClasses forSelector:@selector(rpcResetCloudKit:reason:reply:)                argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcResetLocal:reply:)                   argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcResetCloudKit:reason:reply:)         argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcResync:reply:)                       argumentIndex:0 ofReply:YES];
-        [interface setClasses:errClasses forSelector:@selector(rpcStatus:reply:)                       argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcResyncLocal:reply:)                  argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcStatus:reply:)                       argumentIndex:1 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcFastStatus:reply:)                   argumentIndex:1 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcFetchAndProcessChanges:reply:)       argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcFetchAndProcessClassAChanges:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcPushOutgoingChanges:reply:)          argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(rpcGetCKDeviceIDWithReply:)             argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(rpcCKMetric:attributes:reply:)          argumentIndex:0 ofReply:YES];
     }
 
     @catch(NSException* e) {
         secerror("CKKSSetupControlProtocol failed, continuing, but you might crash later: %@", e);
-#if DEBUG
         @throw e;
-#endif
     }
 #endif
 
index fecffc4c4bb2a340f8f74e54bea9c9d8c4e54425..a76d72eeb6a6ee900cd4620ce0b0eee0714a24b9 100644 (file)
 #if OCTAGON
     NSNumber *num = [newConnection valueForEntitlement:(__bridge NSString *)kSecEntitlementPrivateCKKS];
     if (![num isKindOfClass:[NSNumber class]] || ![num boolValue]) {
-        secerror("ckks: Client pid: %d doesn't have entitlement: %@",
+        ckkserror_global("ckks", "Client pid: %d doesn't have entitlement: %@",
                 [newConnection processIdentifier], kSecEntitlementPrivateCKKS);
         return NO;
     }
 
     // In the future, we should consider vending a proxy object that can return a nicer error.
     if (!SecCKKSIsEnabled()) {
-        secerror("ckks: Client pid: %d attempted to use CKKS, but CKKS is not enabled.",
+        ckkserror_global("ckks", "Client pid: %d attempted to use CKKS, but CKKS is not enabled.",
                 newConnection.processIdentifier);
         return NO;
     }
diff --git a/keychain/ckks/CKKSCreateCKZoneOperation.h b/keychain/ckks/CKKSCreateCKZoneOperation.h
new file mode 100644 (file)
index 0000000..8e9473f
--- /dev/null
@@ -0,0 +1,23 @@
+
+#import <Foundation/Foundation.h>
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CKKSCreateCKZoneOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ckks/CKKSCreateCKZoneOperation.m b/keychain/ckks/CKKSCreateCKZoneOperation.m
new file mode 100644 (file)
index 0000000..3edc2c3
--- /dev/null
@@ -0,0 +1,121 @@
+#if OCTAGON
+
+#import <CloudKit/CloudKit.h>
+#import <CloudKit/CloudKit_Private.h>
+
+#import "keychain/ckks/CKKSCreateCKZoneOperation.h"
+#import "keychain/ckks/CKKSZoneStateEntry.h"
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ot/ObjCImprovements.h"
+#import "keychain/ot/OTDefines.h"
+
+@implementation CKKSCreateCKZoneOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if(self = [super init]) {
+        _deps = dependencies;
+
+        _intendedState = intendedState;
+        _nextState = errorState;
+    }
+    return self;
+}
+
+- (void)groupStart
+{
+    __block CKKSZoneStateEntry* ckseOriginal = nil;
+    [self.deps.databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
+        ckseOriginal = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
+    }];
+
+    if(ckseOriginal.ckzonecreated && ckseOriginal.ckzonesubscribed) {
+        ckksinfo("ckkskey", self.deps.zoneID, "Zone is already created and subscribed");
+        self.nextState = self.intendedState;
+        return;
+    }
+
+    ckksnotice("ckkszone", self.deps.zoneID, "Asking to create and subscribe to CloudKit zone '%@'", self.deps.zoneID.zoneName);
+    CKRecordZone* zone = [[CKRecordZone alloc] initWithZoneID:self.deps.zoneID];
+    CKKSZoneModifyOperations* zoneOps = [self.deps.zoneModifier createZone:zone];
+
+    WEAKIFY(self);
+
+    CKKSResultOperation* handleModificationsOperation = [CKKSResultOperation named:@"handle-modification" withBlock:^{
+        STRONGIFY(self);
+        BOOL zoneCreated = NO;
+        BOOL zoneSubscribed = NO;
+        if([zoneOps.savedRecordZones containsObject:zone]) {
+            ckksinfo("ckkszone", self.deps.zoneID, "Successfully created '%@'", self.deps.zoneID);
+            zoneCreated = YES;
+        } else {
+            ckkserror("ckkszone", self.deps.zoneID, "Failed to create '%@'", self.deps.zoneID);
+        }
+
+        bool createdSubscription = false;
+        for(CKSubscription* subscription in zoneOps.savedSubscriptions) {
+            if([subscription.subscriptionID isEqual:[@"zone:" stringByAppendingString: self.deps.zoneID.zoneName]]) {
+                zoneSubscribed = true;
+                break;
+            }
+        }
+
+        if(createdSubscription) {
+            ckksinfo("ckkszone", self.deps.zoneID, "Successfully subscribed '%@'", self.deps.zoneID);
+            zoneSubscribed = YES;
+        } else {
+            ckkserror("ckkszone", self.deps.zoneID, "Failed to subscribe to '%@'", self.deps.zoneID);
+        }
+
+        [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            ckksnotice("ckkszone", self.deps.zoneID, "Zone setup progress: created:%d %@ subscribed:%d %@",
+                       zoneCreated,
+                       zoneOps.zoneModificationOperation.error,
+                       zoneSubscribed,
+                       zoneOps.zoneSubscriptionOperation.error);
+
+            NSError* error = nil;
+            CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
+            ckse.ckzonecreated = zoneCreated;
+            ckse.ckzonesubscribed = zoneSubscribed;
+
+            // Although, if the zone subscribed error says there's no zone, mark down that there's no zone
+            if(zoneOps.zoneSubscriptionOperation.error &&
+               [zoneOps.zoneSubscriptionOperation.error.domain isEqualToString:CKErrorDomain] && zoneOps.zoneSubscriptionOperation.error.code == CKErrorPartialFailure) {
+                NSError* subscriptionError = zoneOps.zoneSubscriptionOperation.error.userInfo[CKPartialErrorsByItemIDKey][self.deps.zoneID];
+                if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) {
+
+                    ckkserror("ckks", self.deps.zoneID, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", zoneOps.zoneSubscriptionOperation.error);
+                    ckse.ckzonecreated = false;
+                }
+            }
+
+            [ckse saveToDatabase:&error];
+            if(error) {
+                ckkserror("ckks", self.deps.zoneID, "couldn't save zone creation status for %@: %@", self.deps.zoneID, error);
+            }
+
+            if(!zoneCreated || !zoneSubscribed) {
+                // Go into 'zonecreationfailed'
+                self.nextState = SecCKKSZoneKeyStateZoneCreationFailed;
+                self.error = zoneOps.zoneModificationOperation.error ?: zoneOps.zoneSubscriptionOperation.error;
+            } else {
+                self.nextState = self.intendedState;
+            }
+
+            return CKKSDatabaseTransactionCommit;
+        }];
+    }];
+
+    [handleModificationsOperation addNullableDependency:zoneOps.zoneModificationOperation];
+    [handleModificationsOperation addNullableDependency:zoneOps.zoneSubscriptionOperation];
+    [self runBeforeGroupFinished:handleModificationsOperation];
+}
+
+@end
+
+#endif // OCTAGON
index 78a935ad56344bc4b6b34aa185d6941aece028a7..d0c74c1291930c3aa742cae1523329046f6affd2 100644 (file)
@@ -39,7 +39,7 @@
         _currentKeyUUID = currentKeyUUID;
 
         if(self.currentKeyUUID == nil) {
-            secerror("ckkscurrentkey: created a CKKSCurrentKey with a nil currentKeyUUID. Why?");
+            ckkserror_global("currentkey", "created a CKKSCurrentKey with a nil currentKeyUUID. Why?");
         }
     }
     return self;
     self.currentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName;
 
     if(self.currentKeyUUID == nil) {
-        secerror("ckkscurrentkey: No current key UUID in record! How/why? %@", record);
+        ckkserror_global("currentkey", "No current key UUID in record! How/why? %@", record);
     }
 }
 
diff --git a/keychain/ckks/CKKSDeleteCKZoneOperation.h b/keychain/ckks/CKKSDeleteCKZoneOperation.h
new file mode 100644 (file)
index 0000000..bb7a540
--- /dev/null
@@ -0,0 +1,22 @@
+#import <Foundation/Foundation.h>
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CKKSDeleteCKZoneOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ckks/CKKSDeleteCKZoneOperation.m b/keychain/ckks/CKKSDeleteCKZoneOperation.m
new file mode 100644 (file)
index 0000000..e2b5aa7
--- /dev/null
@@ -0,0 +1,101 @@
+
+
+#if OCTAGON
+
+#import <CloudKit/CloudKit.h>
+#import <CloudKit/CloudKit_Private.h>
+
+#import "keychain/ckks/CKKSDeleteCKZoneOperation.h"
+#import "keychain/ckks/CKKSZoneStateEntry.h"
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ot/ObjCImprovements.h"
+#import "keychain/ot/OTDefines.h"
+
+@implementation CKKSDeleteCKZoneOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if(self = [super init]) {
+        _deps = dependencies;
+
+        _intendedState = intendedState;
+        _nextState = errorState;
+    }
+    return self;
+}
+
+- (void)groupStart
+{
+
+    ckksnotice("ckkszone", self.deps.zoneID, "Deleting CloudKit zone '%@'", self.deps.zoneID);
+    CKKSZoneModifyOperations* zoneOps = [self.deps.zoneModifier deleteZone:self.deps.zoneID];
+
+
+    WEAKIFY(self);
+
+    CKKSResultOperation* handleModificationsOperation = [CKKSResultOperation named:@"handle-modification" withBlock:^{
+        STRONGIFY(self);
+
+        bool fatalError = false;
+
+        NSError* operationError = zoneOps.zoneModificationOperation.error;
+        bool removed = [zoneOps.deletedRecordZoneIDs containsObject:self.deps.zoneID];
+
+        if(!removed && operationError) {
+            // Okay, but if this error is either 'ZoneNotFound' or 'UserDeletedZone', that's fine by us: the zone is deleted.
+            NSDictionary* partialErrors = operationError.userInfo[CKPartialErrorsByItemIDKey];
+            if([operationError.domain isEqualToString:CKErrorDomain] && operationError.code == CKErrorPartialFailure && partialErrors) {
+                for(CKRecordZoneID* errorZoneID in partialErrors.allKeys) {
+                    NSError* errorZone = partialErrors[errorZoneID];
+
+                    if(errorZone && [errorZone.domain isEqualToString:CKErrorDomain] &&
+                       (errorZone.code == CKErrorZoneNotFound || errorZone.code == CKErrorUserDeletedZone)) {
+                        ckksnotice("ckkszone", self.deps.zoneID, "Attempted to delete zone %@, but it's already missing. This is okay: %@", errorZoneID, errorZone);
+                    } else {
+                        fatalError = true;
+                    }
+                }
+
+            } else {
+                fatalError = true;
+            }
+
+            ckksnotice("ckkszone", self.deps.zoneID, "deletion of record zone %@ completed with error: %@", self.deps.zoneID, operationError);
+
+            if(fatalError) {
+                // Early-exit
+                self.error = operationError;
+                return;
+            }
+        }
+
+        ckksnotice("ckkszone", self.deps.zoneID, "deletion of record zone %@ completed successfully", self.deps.zoneID);
+
+        [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            NSError* error = nil;
+            CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
+            ckse.ckzonecreated = NO;
+            ckse.ckzonesubscribed = NO;
+
+            [ckse saveToDatabase:&error];
+            if(error) {
+                ckkserror("ckks", self.deps.zoneID, "couldn't save zone creation status for %@: %@", self.deps.zoneID, error);
+            }
+
+            self.nextState = self.intendedState;
+            return CKKSDatabaseTransactionCommit;
+        }];
+    }];
+
+    [handleModificationsOperation addNullableDependency:zoneOps.zoneModificationOperation];
+    [handleModificationsOperation addNullableDependency:zoneOps.zoneSubscriptionOperation];
+    [self runBeforeGroupFinished:handleModificationsOperation];
+}
+
+@end
+
+#endif // OCTAGON
index 557de53c63415ca2f8b64eb6a749fcd7f60a9ec1..b19013e63c08946f84e19932032ebb94c831fdd4 100644 (file)
         case (uint32_t)kSOSCCError: // And, if by some miracle, you end up with -1 as a uint32_t, accept that too
             return kSOSCCError;
         default:
-            secerror("ckks: %d is not an SOSCCStatus?", n);
+            ckkserror_global("ckks", "%d is not an SOSCCStatus?", n);
             return kSOSCCError;
     }
 }
         case (uint32_t)kSOSCCErrorPositive: // Use the magic number
             return [[OTCliqueStatusWrapper alloc] initWithStatus:CliqueStatusError];
         default:
-            secerror("ckks: %d is not an OTCliqueStatus?", n);
+            ckkserror_global("ckks", "%d is not an OTCliqueStatus?", n);
             return [[OTCliqueStatusWrapper alloc] initWithStatus:CliqueStatusError];;
     }
 }
index 9a03e9762a001442a10f75913fd6da8334fa970b..7212cf975da651f04b94ebc928e67a54cfa4435f 100644 (file)
             if(!self.forceResync) {
                 if (self.changeTokens[clientZoneID]) {
                     options.previousServerChangeToken = self.changeTokens[clientZoneID];
-                    secnotice("ckksfetch", "Using cached change token for %@: %@", clientZoneID, self.changeTokens[clientZoneID]);
+                    ckksnotice_global("ckksfetch", "Using cached change token for %@: %@", clientZoneID, self.changeTokens[clientZoneID]);
                 } else {
                     options.previousServerChangeToken = clientPreference.changeToken;
                 }
     if(self.fetchedZoneIDs.count == 0) {
         // No clients actually want to fetch right now, so quit
         self.error = [NSError errorWithDomain:CKKSErrorDomain code:CKKSNoFetchesRequested description:@"No clients want a fetch right now"];
-        secnotice("ckksfetch", "Cancelling fetch: %@", self.error);
+        ckksnotice_global("ckksfetch", "Cancelling fetch: %@", self.error);
         return;
     }
 
     //    networkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
     //}
 
-    secnotice("ckksfetch", "Beginning fetch with discretionary network (%d): %@", (int)networkBehavior, self.allClientOptions);
+    ckksnotice_global("ckksfetch", "Beginning fetch with discretionary network (%d): %@", (int)networkBehavior, self.allClientOptions);
     self.fetchRecordZoneChangesOperation = [[self.fetchRecordZoneChangesOperationClass alloc] initWithRecordZoneIDs:self.fetchedZoneIDs
                                                                                               configurationsByRecordZoneID:self.allClientOptions];
 
     self.fetchRecordZoneChangesOperation.configuration.discretionaryNetworkBehavior = networkBehavior;
     self.fetchRecordZoneChangesOperation.configuration.isCloudKitSupportOperation = YES;
     self.fetchRecordZoneChangesOperation.group = self.ckoperationGroup;
-    secnotice("ckksfetch", "Operation group is %@", self.ckoperationGroup);
+    ckksnotice_global("ckksfetch", "Operation group is %@", self.ckoperationGroup);
 
     self.fetchRecordZoneChangesOperation.recordChangedBlock = ^(CKRecord *record) {
         STRONGIFY(self);
-        secinfo("ckksfetch", "CloudKit notification: record changed(%@): %@", [record recordType], record);
+        ckksinfo_global("ckksfetch", "CloudKit notification: record changed(%@): %@", [record recordType], record);
 
         // Add this to the modifications, and remove it from the deletions
         self.modifications[record.recordID] = record;
 
     self.fetchRecordZoneChangesOperation.recordWithIDWasDeletedBlock = ^(CKRecordID *recordID, NSString *recordType) {
         STRONGIFY(self);
-        secinfo("ckksfetch", "CloudKit notification: deleted record(%@): %@", recordType, recordID);
+        ckksinfo_global("ckksfetch", "CloudKit notification: deleted record(%@): %@", recordType, recordID);
 
         // Add to the deletions, and remove any pending modifications
         [self.modifications removeObjectForKey: recordID];
     self.fetchRecordZoneChangesOperation.recordZoneChangeTokensUpdatedBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData) {
         STRONGIFY(self);
 
-        secinfo("ckksfetch", "Received a new server change token (via block) for %@: %@ %@", recordZoneID, serverChangeToken, clientChangeTokenData);
+        ckksinfo_global("ckksfetch", "Received a new server change token (via block) for %@: %@ %@", recordZoneID, serverChangeToken, clientChangeTokenData);
         self.changeTokens[recordZoneID] = serverChangeToken;
     };
 
     self.fetchRecordZoneChangesOperation.recordZoneFetchCompletionBlock = ^(CKRecordZoneID *recordZoneID, CKServerChangeToken *serverChangeToken, NSData *clientChangeTokenData, BOOL moreComing, NSError * recordZoneError) {
         STRONGIFY(self);
 
-        secnotice("ckksfetch", "Received a new server change token for %@: %@ %@", recordZoneID, serverChangeToken, clientChangeTokenData);
+        ckksinfo_global("ckksfetch", "Received a new server change token for %@: %@ %@", recordZoneID, serverChangeToken, clientChangeTokenData);
         self.changeTokens[recordZoneID] = serverChangeToken;
         self.allClientOptions[recordZoneID].previousServerChangeToken = serverChangeToken;
 
         self.moreComing |= moreComing;
         if(moreComing) {
-            secnotice("ckksfetch", "more changes pending for %@, will start a new fetch at change token %@", recordZoneID, self.changeTokens[recordZoneID]);
+            ckksnotice_global("ckksfetch", "more changes pending for %@, will start a new fetch at change token %@", recordZoneID, self.changeTokens[recordZoneID]);
         }
 
-        ckksnotice("ckksfetch", recordZoneID, "Record zone fetch complete: changeToken=%@ clientChangeTokenData=%@ moreComing=%@ error=%@", serverChangeToken, clientChangeTokenData,
-                   moreComing ? @"YES" : @"NO",
-                   recordZoneError);
+        ckksinfo("ckksfetch", recordZoneID, "Record zone fetch complete: changeToken=%@ clientChangeTokenData=%@ moreComing=%@ error=%@", serverChangeToken, clientChangeTokenData,
+                 moreComing ? @"YES" : @"NO",
+                 recordZoneError);
 
         [self sendChangesToClient:recordZoneID moreComing:moreComing];
     };
     self.fetchRecordZoneChangesOperation.fetchRecordZoneChangesCompletionBlock = ^(NSError * _Nullable operationError) {
         STRONGIFY(self);
         if(!self) {
-            secerror("ckksfetch: received callback for released object");
+            ckkserror_global("ckksfetch", "received callback for released object");
             return;
         }
 
         // 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])) {
-            secnotice("ckksfetch", "Must issue another fetch (with potential error %@)", operationError);
+            ckksnotice_global("ckksfetch", "Must issue another fetch (with potential error %@)", operationError);
             self.moreComing = false;
             [self performFetch];
             return;
             self.error = operationError;
         }
 
-        secnotice("ckksfetch", "Record zone changes fetch complete: error=%@", operationError);
+        ckksnotice_global("ckksfetcher", "Record zone changes fetch complete: error=%@", operationError);
 
         [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventFetchAllChanges
                                       count:self.fetchedItems];
 
         for(CKRecordZoneNotification* rz in self.apnsPushes) {
             if(rz.ckksPushTracingEnabled) {
-                secnotice("ckksfetch", "Submitting post-fetch CKEventMetric due to notification %@", rz);
+                ckksnotice_global("ckksfetch", "Submitting post-fetch CKEventMetric due to notification %@", rz);
 
                 // Schedule submitting this metric on another operation, so hopefully CK will have marked this fetch as done by the time that fires?
                 CKEventMetric *metric = [[CKEventMetric alloc] initWithEventName:@"APNSPushMetrics"];
 
                 CKKSResultOperation* launchMetricOp = [CKKSResultOperation named:@"submit-metric" withBlock:^{
                     if(![metric associateWithCompletedOperation:rzcOperation]) {
-                        secerror("ckksfetch: Couldn't associate metric with operation: %@ %@", metric, rzcOperation);
+                        ckkserror_global("ckksfetch", "Couldn't associate metric with operation: %@ %@", metric, rzcOperation);
                     }
                     [container submitEventMetric:metric];
                     [[SecMetrics managerObject] submitEvent:metric2];
-                    secnotice("ckksfetch", "Metric submitted: %@", metric);
+                    ckksnotice_global("ckksfetch", "Metric submitted: %@", metric);
                 }];
                 [launchMetricOp addSuccessDependency:self.fetchCompletedOperation];
 
 {
     id<CKKSChangeFetcherClient> client = self.clientMap[recordZoneID];
     if(!client) {
-        secerror("ckksfetch: no client registered for %@, so why did we get any data?", recordZoneID);
+        ckkserror_global("ckksfetch", "no client registered for %@, so why did we get any data?", recordZoneID);
         return;
     }
 
 
     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);
+    ckksnotice("ckksfetch", recordZoneID, "Delivering fetched changes: changed=%lu deleted=%lu moreComing=%lu resync=%u changeToken=%@",
+               (unsigned long)zoneModifications.count, (unsigned long)zoneDeletions.count, (unsigned long)moreComing, resync, self.changeTokens[recordZoneID]);
 
     // Tell the client about these changes!
     [client changesFetched:zoneModifications
index 98e48dd7cbcd967d1503ae4b2f4ea888a277856b..d64fba89c1d7db40dd8f5a55cfc3dd30780c5f29 100644 (file)
@@ -40,11 +40,12 @@ typedef NS_ENUM(NSUInteger, CKKSFixup) {
     CKKSFixupFetchTLKShares,
     CKKSFixupLocalReload,
     CKKSFixupResaveDeviceStateEntries,
+    CKKSFixupDeleteAllCKKSTombstones,
 };
-#define CKKSCurrentFixupNumber (CKKSFixupResaveDeviceStateEntries)
+#define CKKSCurrentFixupNumber (CKKSFixupDeleteAllCKKSTombstones)
 
 @interface CKKSFixups : NSObject
-+(CKKSGroupOperation*)fixup:(CKKSFixup)lastfixup for:(CKKSKeychainView*)keychainView;
++(nullable CKKSGroupOperation*)fixup:(CKKSFixup)lastfixup for:(CKKSKeychainView*)keychainView;
 @end
 
 // Fixup declarations. You probably don't need to look at these
@@ -61,6 +62,7 @@ typedef NS_ENUM(NSUInteger, CKKSFixup) {
 @interface CKKSFixupLocalReloadOperation : CKKSGroupOperation
 @property (weak) CKKSKeychainView* ckks;
 - (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)keychainView
+                             fixupNumber:(CKKSFixup)fixupNumber
                         ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
 @end
 
index 927cf56e44eb5e8790133594ddbce4a0af1643ee..44f2ef5a0c2976a20a665c9689277baa3e1f5d9a 100644 (file)
@@ -31,7 +31,7 @@
 #import "keychain/ot/ObjCImprovements.h"
 
 @implementation CKKSFixups
-+(CKKSGroupOperation*)fixup:(CKKSFixup)lastfixup for:(CKKSKeychainView*)keychainView
++(nullable CKKSGroupOperation*)fixup:(CKKSFixup)lastfixup for:(CKKSKeychainView*)keychainView
 {
     if(lastfixup == CKKSCurrentFixupNumber) {
         return nil;
@@ -61,6 +61,7 @@
 
     if(lastfixup < CKKSFixupLocalReload) {
         CKKSResultOperation* localSync = [[CKKSFixupLocalReloadOperation alloc] initWithCKKSKeychainView:keychainView
+                                                                                             fixupNumber:CKKSFixupLocalReload
                                                                                         ckoperationGroup:fixupCKGroup];
         [localSync addNullableSuccessDependency:previousOp];
         [fixups runBeforeGroupFinished:localSync];
         previousOp = resave;
     }
 
+    if(lastfixup < CKKSFixupDeleteAllCKKSTombstones) {
+        CKKSResultOperation* localSync = [[CKKSFixupLocalReloadOperation alloc] initWithCKKSKeychainView:keychainView
+                                                                                             fixupNumber:CKKSFixupDeleteAllCKKSTombstones
+                                                                                        ckoperationGroup:fixupCKGroup];
+        [localSync addNullableSuccessDependency:previousOp];
+        [fixups runBeforeGroupFinished:localSync];
+        previousOp = localSync;
+    }
+
     (void)previousOp;
     return fixups;
 }
         return;
     }
 
-    [ckks dispatchSyncWithAccountKeys:^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
 
         NSArray<CKKSCurrentItemPointer*>* cips = [CKKSCurrentItemPointer allInZone: ckks.zoneID error:&error];
         if(error) {
             ckkserror("ckksfixup", ckks, "Couldn't fetch current item pointers: %@", error);
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         NSMutableSet<CKRecordID*>* recordIDs = [NSMutableSet set];
 
         WEAKIFY(self);
         NSBlockOperation* doneOp = [NSBlockOperation named:@"fetch-records-operation-complete" withBlock:^{}];
-        id<CKKSFetchRecordsOperation> fetch = [[ckks.cloudKitClassDependencies.fetchRecordsOperationClass alloc] initWithRecordIDs: [recordIDs allObjects]];
+        CKDatabaseOperation<CKKSFetchRecordsOperation>* fetch = [[ckks.cloudKitClassDependencies.fetchRecordsOperationClass alloc] initWithRecordIDs: [recordIDs allObjects]];
         fetch.fetchRecordsCompletionBlock = ^(NSDictionary<CKRecordID *,CKRecord *> * _Nullable recordsByRecordID, NSError * _Nullable error) {
             STRONGIFY(self);
             CKKSKeychainView* strongCKKS = self.ckks;
 
-            [strongCKKS dispatchSync:^bool{
+            [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 if(error) {
                     ckkserror("ckksfixup", strongCKKS, "Finished record fetch with error: %@", error);
 
                 }
 
                 [self runBeforeGroupFinished:doneOp];
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
         };
         [ckks.database addOperation: fetch];
         [self dependOnBeforeGroupFinished:fetch];
         [self dependOnBeforeGroupFinished:doneOp];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 @end
         return;
     }
 
-    [ckks dispatchSyncWithAccountKeys:^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         WEAKIFY(self);
         NSBlockOperation* doneOp = [NSBlockOperation named:@"fetch-records-operation-complete" withBlock:^{}];
 
         NSPredicate *yes = [NSPredicate predicateWithValue:YES];
         CKQuery *query = [[CKQuery alloc] initWithRecordType:SecCKRecordTLKShareType predicate:yes];
 
-        id<CKKSQueryOperation> fetch = [[ckks.cloudKitClassDependencies.queryOperationClass alloc] initWithQuery:query];
+        CKDatabaseOperation<CKKSQueryOperation>* fetch = [[ckks.cloudKitClassDependencies.queryOperationClass alloc] initWithQuery:query];
         fetch.zoneID = ckks.zoneID;
         fetch.desiredKeys = nil;
 
         fetch.recordFetchedBlock = ^(CKRecord * _Nonnull record) {
             STRONGIFY(self);
             CKKSKeychainView* strongCKKS = self.ckks;
-            [strongCKKS dispatchSync:^bool{
+            [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 ckksnotice("ckksfixup", strongCKKS, "Recieved tlk share record from query: %@", record);
 
                 [strongCKKS _onqueueCKRecordChanged:record resync:true];
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
         };
 
             STRONGIFY(self);
             CKKSKeychainView* strongCKKS = self.ckks;
 
-            [strongCKKS dispatchSync:^bool{
+            [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 if(error) {
                     ckkserror("ckksfixup", strongCKKS, "Couldn't fetch all TLKShare records: %@", error);
                     self.error = error;
-                    return false;
+                    return CKKSDatabaseTransactionRollback;
                 }
 
                 ckksnotice("ckksfixup", strongCKKS, "Successfully fetched TLKShare records (%@)", cursor);
                 } else {
                     ckksnotice("ckksfixup", strongCKKS, "Updated zone fixup state to CKKSFixupFetchTLKShares");
                 }
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
             [self runBeforeGroupFinished:doneOp];
         };
         [self dependOnBeforeGroupFinished:fetch];
         [self dependOnBeforeGroupFinished:doneOp];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 @end
 
 @interface CKKSFixupLocalReloadOperation ()
 @property CKOperationGroup* group;
+@property CKKSFixup fixupNumber;
 @end
 
 // In <rdar://problem/35540228> Server Generated CloudKit "Manatee Identity Lost"
 // items could be deleted from the local keychain after CKKS believed they were already synced, and therefore wouldn't resync
 // Perform a local resync operation
+//
+// In <rdar://problem/60650208> CKKS: adjust UUID and tombstone handling
+// some CKKS participants uploaded entries with tomb=1 to CKKS
+// Performing a local reload operation should find and delete those entries
 @implementation CKKSFixupLocalReloadOperation
 - (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)keychainView
+                             fixupNumber:(CKKSFixup)fixupNumber
                         ckoperationGroup:(CKOperationGroup *)ckoperationGroup
 {
     if((self = [super init])) {
         _ckks = keychainView;
+        _fixupNumber = fixupNumber;
         _group = ckoperationGroup;
     }
     return self;
 }
 
 - (NSString*)description {
-    return [NSString stringWithFormat:@"<CKKSFixup:LocalReload (%@)>", self.ckks];
+    return [NSString stringWithFormat:@"<CKKSFixup:LocalReload (%d)(%@)>", (int)self.fixupNumber, self.ckks];
 }
 - (void)groupStart {
     CKKSKeychainView* ckks = self.ckks;
     CKKSResultOperation* cleanup = [CKKSResultOperation named:@"local-reload-cleanup" withBlock:^{
         STRONGIFY(self);
         __strong __typeof(self.ckks) strongCKKS = self.ckks;
-        [strongCKKS dispatchSync:^bool{
+        [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
             if(reload.error) {
                 ckkserror("ckksfixup", strongCKKS, "Couldn't perform a reload: %@", reload.error);
                 self.error = reload.error;
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
-            ckksnotice("ckksfixup", strongCKKS, "Successfully performed a reload fixup");
+            ckksnotice("ckksfixup", strongCKKS, "Successfully performed a reload fixup. New fixup number is %d",
+                       (int)self.fixupNumber);
 
             NSError* localerror = nil;
             CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:strongCKKS.zoneName error:&localerror];
-            ckse.lastFixup = CKKSFixupLocalReload;
+            ckse.lastFixup = self.fixupNumber;
             [ckse saveToDatabase:&localerror];
             if(localerror) {
                 ckkserror("ckksfixup", strongCKKS, "Couldn't save CKKSZoneStateEntry(%@): %@", ckse, localerror);
             } else {
                 ckksnotice("ckksfixup", strongCKKS, "Updated zone fixup state to CKKSFixupLocalReload");
             }
-            return true;
+            return CKKSDatabaseTransactionCommit;
         }];
     }];
     [cleanup addNullableDependency:reload];
     }
 
     // This operation simply loads all CDSEs, remakes them from their CKRecord, and resaves them
-    [ckks dispatchSync:^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         NSArray<CKKSDeviceStateEntry*>* cdses = [CKKSDeviceStateEntry allInZone:ckks.zoneID
                                                                           error:&error];
         if(error) {
             ckkserror("ckksfixup", ckks, "Unable to fetch all CDSEs: %@", error);
             self.error = error;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         for(CKKSDeviceStateEntry* cdse in cdses) {
                 if(error) {
                     ckkserror("ckksfixup", ckks, "Unable to save CDSE: %@", error);
                     self.error = error;
-                    return false;
+                    return CKKSDatabaseTransactionRollback;
                 }
             } else {
                 ckksnotice("ckksfixup", ckks, "Saved CDSE has no stored record: %@", cdse);
         if(localerror) {
             ckkserror("ckksfixup", ckks, "Couldn't save CKKSZoneStateEntry(%@): %@", ckse, localerror);
             self.error = localerror;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         ckksnotice("ckksfixup", ckks, "Updated zone fixup state to CKKSFixupResaveDeviceStateEntries");
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
index d85e9fad0c1f5f748efb925f585bde3b137a3751..bc984f44d90f664e4c2a3609fed6c2569ca0e6b6 100644 (file)
@@ -25,7 +25,7 @@
 
 #import "CKKSGroupOperation.h"
 #import "keychain/ot/ObjCImprovements.h"
-#include <utilities/debugging.h>
+#import "keychain/ckks/CKKS.h"
 
 @interface CKKSGroupOperation()
 @property bool fillInError;
         _startOperation = [NSBlockOperation blockOperationWithBlock:^{
             STRONGIFY(self);
             if(!self) {
-                secerror("ckks: received callback for released object");
+                ckkserror_global("ckks", "received callback for released object");
                 return;
             }
 
             if(![self allDependentsSuccessful]) {
-                secdebug("ckksgroup", "Not running due to some failed dependent: %@", self.error);
+                ckksinfo_global("ckksgroup", "Not running due to some failed dependent: %@", self.error);
                 [self cancel];
                 return;
             }
@@ -71,7 +71,7 @@
         _finishOperation = [NSBlockOperation blockOperationWithBlock:^{
             STRONGIFY(self);
             if(!self) {
-                secerror("ckks: received callback for released object");
+                ckkserror_global("ckks", "received callback for released object");
                 return;
             }
 
 }
 
 - (NSString*)description {
-    if(self.isFinished) {
+
+    static __thread unsigned __descriptionRecursion = 0;
+    NSString* state = [self operationStateString];
+    NSString *desc = NULL;
+
+    __descriptionRecursion++;
+
+    if(__descriptionRecursion > 10) {
+        desc = [NSString stringWithFormat: @"<%@: %@ recursion>", [self selfname], state];
+
+    } else if(self.isFinished) {
         if(self.error) {
-            return [NSString stringWithFormat: @"<%@: %@ %@ - %@>", [self selfname],
-                    [self operationStateString],
+            desc = [NSString stringWithFormat: @"<%@: %@ %@ - %@>", [self selfname],
+                    state,
                     self.finishDate,
                     self.error];
         } else {
-            return [NSString stringWithFormat: @"<%@: %@ %@>", [self selfname],
-                    [self operationStateString],
+            desc = [NSString stringWithFormat: @"<%@: %@ %@>", [self selfname],
+                    state,
                     self.finishDate];
         }
-    }
+    } else {
 
-    NSMutableArray* ops = [self.operationQueue.operations mutableCopy];
+        NSString* opsString = nil;
 
-    [ops removeObject: self.finishOperation];
+        if (self.operationQueue.operationCount + self.finishOperation.dependencies.count > 20) {
+            opsString = @"Potentially more than 20 operations";
+        } else {
+            NSMutableArray* ops = [self.operationQueue.operations mutableCopy];
+
+            [ops removeObject: self.finishOperation];
+
+            // Any extra dependencies from the finish operation should be considered part of this group
+            for(NSOperation* finishDep in self.finishOperation.dependencies) {
+                if (ops.count > 20) {
+                    opsString = @"Potentially more than 20 operations";
+                    break;
+                }
+                if(finishDep != self.startOperation && (NSNotFound == [ops indexOfObject: finishDep])) {
+                    [ops addObject: finishDep];
+                }
+            }
+            if (opsString == nil) {
+                opsString = [ops componentsJoinedByString:@", "];
+            }
+        }
 
-    // Any extra dependencies from the finish operation should be considered part of this group
-    for(NSOperation* finishDep in self.finishOperation.dependencies) {
-        if(finishDep != self.startOperation && (NSNotFound == [ops indexOfObject: finishDep])) {
-            [ops addObject: finishDep];
+        if(self.error) {
+            desc = [NSString stringWithFormat: @"<%@: %@ [%@] error:%@>", [self selfname], state, opsString, self.error];
+        } else {
+            desc = [NSString stringWithFormat: @"<%@: %@ [%@]%@>", [self selfname], state, opsString, [self pendingDependenciesString:@" dep:"]];
         }
     }
+    __descriptionRecursion--;
 
-    NSString* opsString = [ops componentsJoinedByString:@", "];
-
-    if(self.error) {
-        return [NSString stringWithFormat: @"<%@: %@ [%@] error:%@>", [self selfname], [self operationStateString], opsString, self.error];
-    } else {
-        return [NSString stringWithFormat: @"<%@: %@ [%@]%@>", [self selfname], [self operationStateString], opsString, [self pendingDependenciesString:@" dep:"]];
-    }
+    return desc;
 }
 
 - (NSString*)debugDescription {
 
     if([self isCancelled]) {
         // Cancelled operations can't add anything.
-        secnotice("ckksgroup", "Can't add operation dependency to cancelled group");
+        ckksnotice_global("ckksgroup", "Can't add operation dependency to cancelled group");
         return;
     }
 
index 2e30b8c302e176918278ef7a04c6d9964b1841fa..7fbbb63edb389ed1f9418a58d11badc49e935b49 100644 (file)
@@ -23,6 +23,8 @@
 
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
 
 #if OCTAGON
 
@@ -30,12 +32,16 @@ NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 
-@interface CKKSHealKeyHierarchyOperation : CKKSGroupOperation
+@interface CKKSHealKeyHierarchyOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
+@property OctagonState* nextState;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
-
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
 @end
 
 NS_ASSUME_NONNULL_END
index 21351856b0b778fc9ed0dd7df8fefb35d6b0e3f6..69720cb73156e100099455cb009753adf050d932 100644 (file)
@@ -28,6 +28,7 @@
 #import "CKKSGroupOperation.h"
 #import "CKKSAnalytics.h"
 #import "keychain/ckks/CloudKitCategories.h"
+#import "keychain/ckks/CKKSHealTLKSharesOperation.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #import "keychain/ot/ObjCImprovements.h"
 
 
 @interface CKKSHealKeyHierarchyOperation ()
 @property NSBlockOperation* cloudkitModifyOperationFinished;
-@property CKOperationGroup* ckoperationGroup;
 @end
 
 @implementation CKKSHealKeyHierarchyOperation
+@synthesize intendedState = _intendedState;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
-    if(self = [super init]) {
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if((self = [super init])) {
+        _deps = dependencies;
         _ckks = ckks;
-        _ckoperationGroup = ckoperationGroup;
+
+        _intendedState = intendedState;
+        _nextState = errorState;
     }
     return self;
 }
         return;
     }
 
+    NSArray<CKKSPeerProviderState*>* currentTrustStates = self.deps.currentTrustStates;
+
     // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety.
-    [ckks dispatchSyncWithAccountKeys: ^bool{
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
             ckksnotice("ckksheal", ckks, "CKKSHealKeyHierarchyOperation cancelled, quitting");
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         NSError* error = nil;
             // If we haven't done one yet, initiate a refetch of everything from cloudkit, and write down that we did so
             if(!ckks.keyStateMachineRefetched) {
                 ckksnotice("ckksheal", ckks, "Have current key pointers, but no keys. This is exceptional; requesting full refetch");
-                [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateNeedFullRefetch withError:nil];
-                return true;
+                self.nextState = SecCKKSZoneKeyStateNeedFullRefetch;
+                return CKKSDatabaseTransactionCommit;
             }
         }
 
                     newTLK = topKey;
                 } else if(![newTLK.uuid isEqualToString: topKey.uuid]) {
                     ckkserror("ckksheal", ckks, "key hierarchy has split: there's two top keys. Currently we don't handle this situation.");
-                    [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: [NSError errorWithDomain:CKKSErrorDomain
-                                                                                                                         code:CKKSSplitKeyHierarchy
-                                                                                                                     userInfo:@{NSLocalizedDescriptionKey:
-                                                                                                                                    [NSString stringWithFormat:@"Key hierarchy has split: %@ and %@ are roots", newTLK, topKey]}]];
-                    return true;
+                    self.error = [NSError errorWithDomain:CKKSErrorDomain
+                                                     code:CKKSSplitKeyHierarchy
+                                              description:[NSString stringWithFormat:@"Key hierarchy has split: %@ and %@ are roots", newTLK, topKey]];
+                    self.nextState = SecCKKSZoneKeyStateError;
+                    return CKKSDatabaseTransactionCommit;
                 }
             }
 
             if(!newTLK) {
                 // We don't have any TLKs lying around, but we're supposed to heal the key hierarchy. This isn't any good; let's wait for TLK creation.
                 ckkserror("ckksheal", ckks, "No possible TLK found. Waiting for creation.");
-                [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForTLKCreation withError:nil];
-                return true;
+                self.nextState = SecCKKSZoneKeyStateWaitForTLKCreation;
+                return CKKSDatabaseTransactionCommit;
             }
 
-            if(![ckks _onqueueWithAccountKeysCheckTLK: newTLK error: &error]) {
-                // Was this error "I've never seen that TLK before in my life"? If so, enter the "wait for TLK sync" state.
-                if(error && [error.domain isEqualToString: @"securityd"] && error.code == errSecItemNotFound) {
-                    ckksnotice("ckksheal", ckks, "Received a TLK which we don't have in the local keychain(%@). Entering waitfortlk.", newTLK);
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForTLK withError:nil];
-                    return true;
-                } else if(error && [ckks.lockStateTracker isLockedError:error]) {
-                    ckksnotice("ckkskey", ckks, "Received a TLK(%@), but keybag appears to be locked. Entering WaitForUnlock.", newTLK);
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForUnlock withError:nil];
-                    return true;
+            if(![newTLK validTLK:&error]) {
+                // Something has gone horribly wrong. Enter error state.
+                ckkserror("ckkskey", ckks, "CKKS claims %@ is not a valid TLK: %@", newTLK, error);
+                self.error = [NSError errorWithDomain:CKKSErrorDomain code:CKKSInvalidTLK description:@"Invalid TLK from CloudKit (during heal)" underlying:error];
+                self.nextState = SecCKKSZoneKeyStateError;
+                return CKKSDatabaseTransactionCommit;
+            }
 
+            // This key is our proposed TLK.
+            if(![newTLK tlkMaterialPresentOrRecoverableViaTLKShare:currentTrustStates
+                                                          error:&error]) {
+                // TLK is valid, but not present locally
+                if(error && [self.deps.lockStateTracker isLockedError:error]) {
+                    ckksnotice("ckkskey", ckks, "Received a TLK(%@), but keybag appears to be locked. Entering a waiting state.", newTLK);
+                    self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
                 } else {
-                    // Otherwise, something has gone horribly wrong. enter error state.
-                    ckkserror("ckksheal", ckks, "CKKS claims %@ is not a valid TLK: %@", newTLK, error);
-                    NSError* newError = [NSError errorWithDomain:CKKSErrorDomain code:CKKSInvalidTLK description:@"Invalid TLK from CloudKit (during heal)" underlying:error];
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:newError];
-                    return true;
+                    ckksnotice("ckkskey", ckks, "Received a TLK(%@) which we don't have in the local keychain: %@", newTLK, error);
+                    self.error = error;
+                    self.nextState = SecCKKSZoneKeyStateTLKMissing;
                 }
+                return CKKSDatabaseTransactionCommit;
             }
 
             // We have our new TLK.
 
                 if(error && [ckks.lockStateTracker isLockedError:error]) {
                     ckksnotice("ckksheal", ckks, "Couldn't create a new class A key, but keybag appears to be locked. Entering waitforunlock.");
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForUnlock withError:error];
-                    return true;
+                    self.error = error;
+                    self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+                    return CKKSDatabaseTransactionCommit;
                 } else if(error) {
                     ckkserror("ckksheal", ckks, "couldn't create new classA key: %@", error);
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error];
-                    return true;
+                    self.error = error;
+                    self.nextState = SecCKKSZoneKeyStateError;
+                    return CKKSDatabaseTransactionCommit;
                 }
 
                 keyset.classA = newClassAKey;
 
                 if(error && [ckks.lockStateTracker isLockedError:error]) {
                     ckksnotice("ckksheal", ckks, "Couldn't create a new class C key, but keybag appears to be locked. Entering waitforunlock.");
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForUnlock withError:error];
-                    return true;
+                    self.error = error;
+                    self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+                    return CKKSDatabaseTransactionCommit;
                 } else if(error) {
                     ckkserror("ckksheal", ckks, "couldn't create new class C key: %@", error);
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error];
-                    return true;
+                    self.error = error;
+                    self.nextState = SecCKKSZoneKeyStateError;
+                    return CKKSDatabaseTransactionCommit;
                 }
 
                 keyset.classC = newClassCKey;
             }
 
             // We've selected a new TLK. Compute any TLKShares that should go along with it.
-            NSSet<CKKSTLKShareRecord*>* tlkShares = [ckks _onqueueCreateMissingKeyShares:keyset.tlk
-                                                                             error:&error];
+            NSSet<CKKSTLKShareRecord*>* tlkShares = [CKKSHealTLKSharesOperation createMissingKeyShares:keyset
+                                                                                           trustStates:currentTrustStates
+                                                                                                 error:&error];
             if(error) {
                 ckkserror("ckksshare", ckks, "Unable to create TLK shares for new tlk: %@", error);
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             for(CKKSTLKShareRecord* share in tlkShares) {
             modifyRecordsOp.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
             modifyRecordsOp.configuration.isCloudKitSupportOperation = YES;
 
-            modifyRecordsOp.group = self.ckoperationGroup;
-            ckksnotice("ckksheal", ckks, "Operation group is %@", self.ckoperationGroup);
+            modifyRecordsOp.group = self.deps.ckoperationGroup;
+            ckksnotice("ckksheal", ckks, "Operation group is %@", self.deps.ckoperationGroup);
 
             modifyRecordsOp.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) {
                 STRONGIFY(self);
                 STRONGIFY(self);
                 CKKSKeychainView* strongCKKS = self.ckks;
                 if(!self) {
-                    secerror("ckks: received callback for released object");
+                    ckkserror_global("ckks", "received callback for released object");
                     return;
                 }
 
                 ckksnotice("ckksheal", strongCKKS, "Completed Key Heal CloudKit operation with error: %@", error);
 
-                [strongCKKS dispatchSyncWithAccountKeys: ^bool{
+                [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                     if(error == nil) {
-                        [[CKKSAnalytics logger] logSuccessForEvent:CKKSEventProcessHealKeyHierarchy inView:ckks];
+                        [[CKKSAnalytics logger] logSuccessForEvent:CKKSEventProcessHealKeyHierarchy zoneName:ckks.zoneName];
                         // Success. Persist the keys to the CKKS database.
 
                         // Save the new CKRecords to the before persisting to database
 
                         if(localerror != nil) {
                             ckkserror("ckksheal", strongCKKS, "couldn't save new key hierarchy to database; this is very bad: %@", localerror);
-                            [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: localerror];
-                            return false;
+                            self.error = localerror;
+                            self.nextState = SecCKKSZoneKeyStateError;
+                            return CKKSDatabaseTransactionRollback;
                         } else {
                             // Everything is groovy. HOWEVER, we might still not have processed the keys. Ask for that!
-                            [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateProcess withError: nil];
+                            self.nextState = SecCKKSZoneKeyStateProcess;
                         }
                     } else {
                         // ERROR. This isn't a total-failure error state, but one that should kick off a healing process.
-                        [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:CKKSEventProcessHealKeyHierarchy inView:ckks withAttributes:NULL];
+                        [[CKKSAnalytics logger] logUnrecoverableError:error forEvent:CKKSEventProcessHealKeyHierarchy zoneName:ckks.zoneName withAttributes:NULL];
                         ckkserror("ckksheal", strongCKKS, "couldn't save new key hierarchy to CloudKit: %@", error);
                         [strongCKKS _onqueueCKWriteFailed:error attemptedRecordsChanged:attemptedRecords];
-                        [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateNewTLKsFailed withError: nil];
+
+                        self.nextState = SecCKKSZoneKeyStateNewTLKsFailed;
                     }
-                    return true;
+                    return CKKSDatabaseTransactionCommit;
                 }];
 
                 // Notify that we're done
         }
 
         // Check if CKKS can recover this TLK.
-        bool haveTLK = [ckks _onqueueWithAccountKeysCheckTLK:keyset.tlk error:&error];
-        if(error && [ckks.lockStateTracker isLockedError:error]) {
-            ckksnotice("ckkskey", ckks, "Failed to load TLK from keychain, keybag is locked. Entering waitforunlock: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForUnlock withError:nil];
-            return false;
-        } else if(error && [error.domain isEqualToString: @"securityd"] && error.code == errSecItemNotFound) {
-            ckkserror("ckksheal", ckks, "CKKS couldn't find TLK, triggering move to wait state: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateWaitForTLK withError: nil];
 
-        } else if(!haveTLK) {
-            ckkserror("ckksheal", ckks, "CKKS errored examining TLK, triggering move to bad state: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error];
-            return false;
+        if(![keyset.tlk validTLK:&error]) {
+            // Something has gone horribly wrong. Enter error state.
+            ckkserror("ckkskey", ckks, "CKKS claims %@ is not a valid TLK: %@", keyset.tlk, error);
+            self.error = [NSError errorWithDomain:CKKSErrorDomain code:CKKSInvalidTLK description:@"Invalid TLK from CloudKit (during heal)" underlying:error];
+            self.nextState = SecCKKSZoneKeyStateError;
+            return CKKSDatabaseTransactionCommit;
+        }
+
+        // This key is our proposed TLK.
+        if(![keyset.tlk tlkMaterialPresentOrRecoverableViaTLKShare:currentTrustStates
+                                                             error:&error]) {
+            // TLK is valid, but not present locally
+            if(error && [self.deps.lockStateTracker isLockedError:error]) {
+                ckksnotice("ckkskey", ckks, "Received a TLK(%@), but keybag appears to be locked. Entering a waiting state.", keyset.tlk);
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+            } else {
+                ckksnotice("ckkskey", ckks, "Received a TLK(%@) which we don't have in the local keychain: %@", keyset.tlk, error);
+                self.error = error;
+                self.nextState = SecCKKSZoneKeyStateTLKMissing;
+            }
+            return CKKSDatabaseTransactionCommit;
         }
 
         if(![self ensureKeyPresent:keyset.tlk]) {
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         if(![self ensureKeyPresent:keyset.classA]) {
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         if(![self ensureKeyPresent:keyset.classC]) {
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Seems good to us. Check if we're ready?
-        [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil];
+        self.nextState = self.intendedState;
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
         error = nil;
         [key unwrapViaKeyHierarchy: &error];
         if(error) {
+            if([ckks.lockStateTracker isLockedError:error]) {
+                ckkserror("ckksheal", ckks, "Couldn't unwrap key(%@) using key hierarchy due to the lock state: %@", key, error);
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+                self.error = error;
+                return false;
+            }
             ckkserror("ckksheal", ckks, "Couldn't unwrap key(%@) using key hierarchy. Keys are broken, quitting: %@", key, error);
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
+            self.error = error;
+            self.nextState = SecCKKSZoneKeyStateError;
             self.error = error;
             return false;
         }
         [key saveKeyMaterialToKeychain:&error];
         if(error) {
+            if([ckks.lockStateTracker isLockedError:error]) {
+                ckkserror("ckksheal", ckks, "Couldn't save key(%@) to keychain due to the lock state: %@", key, error);
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+                self.error = error;
+                return false;
+            }
             ckkserror("ckksheal", ckks, "Couldn't save key(%@) to keychain: %@", key, error);
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
             self.error = error;
+            self.nextState = SecCKKSZoneKeyStateError;
             return false;
         }
     }
index 9dc61050371aa611c78617b87c59a86f802d9af2..910cd9172ca09fcf2e1d577c1cb40069dd48c740 100644 (file)
 
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ckks/CKKSCurrentKeyPointer.h"
+#import "keychain/ot/OctagonStateMachine.h"
 
 #if OCTAGON
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
+@class CKKSOperationDependencies;
 
-@interface CKKSHealTLKSharesOperation : CKKSGroupOperation
+@interface CKKSHealTLKSharesOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
+- (instancetype)initWithOperationDependencies:(CKKSOperationDependencies*)operationDependencies
+                                         ckks:(CKKSKeychainView*)ckks;
+
+
+// For this keyset, who doesn't yet have a CKKSTLKShare for its TLK, shared to their current Octagon keys?
+// Note that we really want a record sharing the TLK to ourselves, so this function might return
+// a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
+// If you pass in a non-empty set in afterUploading, those records will be included in the calculation.
++ (NSSet<CKKSTLKShareRecord*>* _Nullable)createMissingKeyShares:(CKKSCurrentKeySet*)keyset
+                                                    trustStates:(NSArray<CKKSPeerProviderState*>*)trustStates
+                                                          error:(NSError* __autoreleasing*)errore;
 @end
 
 NS_ASSUME_NONNULL_END
index a407f46619a970713591d27fd5a5125f30f49e8b..bd303afd18395b4503b1f91640c5c0fa1cc7a049 100644 (file)
 
 @interface CKKSHealTLKSharesOperation ()
 @property NSBlockOperation* cloudkitModifyOperationFinished;
-@property CKOperationGroup* ckoperationGroup;
 @end
 
 @implementation CKKSHealTLKSharesOperation
+@synthesize intendedState = _intendedState;
+@synthesize nextState = _nextState;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
+
+- (instancetype)initWithOperationDependencies:(CKKSOperationDependencies*)operationDependencies
+                                         ckks:(CKKSKeychainView*)ckks
+{
     if(self = [super init]) {
         _ckks = ckks;
-        _ckoperationGroup = ckoperationGroup;
+        _deps = operationDependencies;
+
+        _nextState = SecCKKSZoneKeyStateHealTLKSharesFailed;
+        _intendedState = SecCKKSZoneKeyStateBecomeReady;
     }
     return self;
 }
 
     WEAKIFY(self);
 
-    CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksshare", ckks, "no CKKS object");
+    if(self.cancelled) {
+        ckksnotice("ckksshare", self.deps.zoneID, "CKKSHealTLKSharesOperation cancelled, quitting");
         return;
     }
 
-    if(self.cancelled) {
-        ckksnotice("ckksshare", ckks, "CKKSHealTLKSharesOperation cancelled, quitting");
+    NSArray<CKKSPeerProviderState*>* trustStates = [self.deps currentTrustStates];
+
+    NSError* error = nil;
+    __block CKKSCurrentKeySet* keyset = nil;
+
+    [self.deps.databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
+        keyset = [CKKSCurrentKeySet loadForZone:self.deps.zoneID];
+    }];
+
+    if(keyset.error) {
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        self.error = keyset.error;
+        ckkserror("ckksshare", self.deps.zoneID, "couldn't load current keys: can't fix TLK shares");
         return;
+    } else {
+        ckksnotice("ckksshare", self.deps.zoneID, "Key set is %@", keyset);
     }
 
-    [ckks dispatchSyncWithAccountKeys: ^bool{
-        if(self.cancelled) {
-            ckksnotice("ckksshare", ckks, "CKKSHealTLKSharesOperation cancelled, quitting");
-            return false;
+    [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventTLKShareProcessing zone:self.deps.zoneID.zoneName];
+
+    // Okay! Perform the checks.
+    if(![keyset.tlk loadKeyMaterialFromKeychain:&error] || error) {
+        // Well, that's no good. We can't share a TLK we don't have.
+        if([self.deps.lockStateTracker isLockedError: error]) {
+            ckkserror("ckksshare", self.deps.zoneID, "Keychain is locked: can't fix shares yet: %@", error);
+            self.nextState = SecCKKSZoneKeyStateBecomeReady;
+        } else {
+            ckkserror("ckksshare", self.deps.zoneID, "couldn't load current tlk from keychain: %@", error);
+            self.nextState = SecCKKSZoneKeyStateUnhealthy;
         }
+        return;
+    }
+
+    NSSet<CKKSTLKShareRecord*>* newShares = [CKKSHealTLKSharesOperation createMissingKeyShares:keyset
+                                                                                   trustStates:trustStates
+                                                                                         error:&error];
+    if(error) {
+        ckkserror("ckksshare", self.deps.zoneID, "Unable to create shares: %@", error);
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
+        return;
+    }
+
+    if(newShares.count == 0u) {
+        ckksnotice("ckksshare", self.deps.zoneID, "Don't believe we need to change any TLKShares, stopping");
+        self.nextState = self.intendedState;
+        return;
+    }
+
+    keyset.pendingTLKShares = [newShares allObjects];
 
-        NSError* error = nil;
+    // Let's double-check: if we upload these TLKShares, will the world be right?
+    BOOL newSharesSufficient = [CKKSHealTLKSharesOperation areNewSharesSufficient:keyset
+                                                                      trustStates:trustStates
+                                                                            error:&error];
+    if(!newSharesSufficient || error) {
+        ckksnotice("ckksshare", self.deps.zoneID, "New shares won't resolve the share issue; erroring to avoid infinite loops");
+        self.nextState = SecCKKSZoneKeyStateError;
+        return;
+    }
+
+    // Fire up our CloudKit operation!
+
+    NSMutableArray<CKRecord *>* recordsToSave = [[NSMutableArray alloc] init];
+    NSMutableArray<CKRecordID *>* recordIDsToDelete = [[NSMutableArray alloc] init];
+    NSMutableDictionary<CKRecordID*, CKRecord*>* attemptedRecords = [[NSMutableDictionary alloc] init];
+
+    ckksnotice("ckksshare", self.deps.zoneID, "Uploading %d new TLKShares", (unsigned int)newShares.count);
+    for(CKKSTLKShareRecord* share in newShares) {
+        ckksnotice("ckksshare", self.deps.zoneID, "Uploading TLKShare to %@ (as %@)", share.share.receiverPeerID, share.senderPeerID);
+
+        CKRecord* record = [share CKRecordWithZoneID:self.deps.zoneID];
+        [recordsToSave addObject: record];
+        attemptedRecords[record.recordID] = record;
+    }
+
+    // Use the spare operation trick to wait for the CKModifyRecordsOperation to complete
+    self.cloudkitModifyOperationFinished = [NSBlockOperation named:@"heal-tlkshares-modify-operation-finished" withBlock:^{}];
+    [self dependOnBeforeGroupFinished: self.cloudkitModifyOperationFinished];
+
+    // Get the CloudKit operation ready...
+    CKModifyRecordsOperation* modifyRecordsOp = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave
+                                                                                      recordIDsToDelete:recordIDsToDelete];
+    modifyRecordsOp.atomic = YES;
+    modifyRecordsOp.longLived = NO;
+
+    // very important: get the TLKShares off-device ASAP
+    modifyRecordsOp.configuration.automaticallyRetryNetworkFailures = NO;
+    modifyRecordsOp.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
+    modifyRecordsOp.configuration.isCloudKitSupportOperation = YES;
 
-        CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:ckks.zoneID];
+    modifyRecordsOp.group = self.deps.ckoperationGroup;
+    ckksnotice("ckksshare", self.deps.zoneID, "Operation group is %@", self.deps.ckoperationGroup);
 
-        if(keyset.error) {
-            self.error = keyset.error;
-            ckkserror("ckksshare", ckks, "couldn't load current keys: can't fix TLK shares");
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateUnhealthy withError:nil];
-            return true;
+    modifyRecordsOp.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) {
+        STRONGIFY(self);
+
+        // These should all fail or succeed as one. Do the hard work in the records completion block.
+        if(!error) {
+            ckksnotice("ckksshare", self.deps.zoneID, "Successfully completed upload for record %@", record.recordID.recordName);
         } else {
-            ckksnotice("ckksshare", ckks, "Key set is %@", keyset);
+            ckkserror("ckksshare",  self.deps.zoneID, "error on row: %@ %@", record.recordID, error);
         }
+    };
+
+    modifyRecordsOp.modifyRecordsCompletionBlock = ^(NSArray<CKRecord *> *savedRecords, NSArray<CKRecordID *> *deletedRecordIDs, NSError *error) {
+        STRONGIFY(self);
+
+        CKKSKeychainView* strongCKKS = self.ckks;
+
+        [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            if(error == nil) {
+                // Success. Persist the records to the CKKS database
+                ckksnotice("ckksshare",  self.deps.zoneID, "Completed TLK Share heal operation with success");
+                NSError* localerror = nil;
+
+                // Save the new CKRecords to the database
+                for(CKRecord* record in savedRecords) {
+                    CKKSTLKShareRecord* savedShare = [[CKKSTLKShareRecord alloc] initWithCKRecord:record];
+                    bool saved = [savedShare saveToDatabase:&localerror];
+
+                    if(!saved || localerror != nil) {
+                        // erroring means we were unable to save the new TLKShare records to the database. This will cause us to try to reupload them. Fail.
+                        // No recovery from this, really...
+                        ckkserror("ckksshare", self.deps.zoneID, "Couldn't save new TLKShare record to database: %@", localerror);
+                        self.error = localerror;
+                        self.nextState = SecCKKSZoneKeyStateError;
+                        return CKKSDatabaseTransactionCommit;
+
+                    } else {
+                        ckksnotice("ckksshare", self.deps.zoneID, "Successfully completed upload for %@", savedShare);
+                    }
+                }
 
-        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventTLKShareProcessing zone:ckks.zoneName];
-
-        // Okay! Perform the checks.
-        if(![keyset.tlk loadKeyMaterialFromKeychain:&error] || error) {
-            // Well, that's no good. We can't share a TLK we don't have.
-            if([ckks.lockStateTracker isLockedError: error]) {
-                ckkserror("ckksshare", ckks, "Keychain is locked: can't fix shares yet: %@", error);
-                [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateReadyPendingUnlock withError:nil];
+                // Successfully sharing TLKs means we're now in ready!
+                self.nextState = SecCKKSZoneKeyStateBecomeReady;
             } else {
-                // TODO go to waitfortlk
-                ckkserror("ckksshare", ckks, "couldn't load current tlk from keychain: %@", error);
-                [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateUnhealthy withError:nil];
+                ckkserror("ckksshare", self.deps.zoneID, "Completed TLK Share heal operation with error: %@", error);
+                [strongCKKS _onqueueCKWriteFailed:error attemptedRecordsChanged:attemptedRecords];
+                // Send the key state machine into tlksharesfailed
+                self.nextState = SecCKKSZoneKeyStateHealTLKSharesFailed;
             }
-            return true;
-        }
+            return CKKSDatabaseTransactionCommit;
+        }];
 
-        NSSet<CKKSTLKShareRecord*>* newShares = [ckks _onqueueCreateMissingKeyShares:keyset.tlk
-                                                                         error:&error];
-        if(error) {
-            ckkserror("ckksshare", ckks, "Unable to create shares: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateUnhealthy withError:nil];
-            return false;
-        }
+        // Notify that we're done
+        [self.operationQueue addOperation: self.cloudkitModifyOperationFinished];
+    };
+
+    [self.ckks.database addOperation:modifyRecordsOp];
+}
 
-        if(newShares.count == 0u) {
-            ckksnotice("ckksshare", ckks, "Don't believe we need to change any TLKShares, stopping");
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateReady withError:nil];
-            return true;
+- (void)cancel {
+    [self.cloudkitModifyOperationFinished cancel];
+    [super cancel];
+}
+
++ (BOOL)areNewSharesSufficient:(CKKSCurrentKeySet*)keyset
+                   trustStates:(NSArray<CKKSPeerProviderState*>*)trustStates
+                         error:(NSError* __autoreleasing*)error
+{
+    for(CKKSPeerProviderState* trustState in trustStates) {
+        NSError* localError = nil;
+        NSSet<id<CKKSPeer>>* peersMissingShares = [trustState findPeersMissingTLKSharesFor:keyset
+                                                                                     error:&localError];
+        if(peersMissingShares == nil || localError) {
+            if(trustState.essential) {
+                if(error) {
+                    *error = localError;
+                }
+                return NO;
+            } else {
+                ckksnotice("ckksshare", keyset.tlk, "Failed to find peers for nonessential system: %@", trustState);
+                // Not a hard failure.
+            }
         }
 
-        // Let's double-check: if we upload these TLKShares, will the world be right?
-        BOOL newSharesSufficient = [ckks _onqueueAreNewSharesSufficient:newShares
-                                                             currentTLK:keyset.tlk
-                                                                  error:&error];
-        if(!newSharesSufficient || error) {
-            ckksnotice("ckksshare", ckks, "New shares won't resolve the share issue; erroring to avoid infinite loops");
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error];
-            return true;
+        if(peersMissingShares.count > 0) {
+            ckksnotice("ckksshare", keyset.tlk, "New share set is missing shares for peers: %@", peersMissingShares);
+            return NO;
         }
+    }
 
-        // Fire up our CloudKit operation!
+    return YES;
+}
 
-        NSMutableArray<CKRecord *>* recordsToSave = [[NSMutableArray alloc] init];
-        NSMutableArray<CKRecordID *>* recordIDsToDelete = [[NSMutableArray alloc] init];
-        NSMutableDictionary<CKRecordID*, CKRecord*>* attemptedRecords = [[NSMutableDictionary alloc] init];
 
-        for(CKKSTLKShareRecord* share in newShares) {
-            CKRecord* record = [share CKRecordWithZoneID:ckks.zoneID];
-            [recordsToSave addObject: record];
-            attemptedRecords[record.recordID] = record;
-        }
++ (NSSet<CKKSTLKShareRecord*>* _Nullable)createMissingKeyShares:(CKKSCurrentKeySet*)keyset
+                                                    trustStates:(NSArray<CKKSPeerProviderState*>*)trustStates
+                                                          error:(NSError* __autoreleasing*)error
+{
+    NSError* localerror = nil;
+    NSSet<CKKSTLKShareRecord*>* newShares = nil;
 
-        // Use the spare operation trick to wait for the CKModifyRecordsOperation to complete
-        self.cloudkitModifyOperationFinished = [NSBlockOperation named:@"heal-tlkshares-modify-operation-finished" withBlock:^{}];
-        [self dependOnBeforeGroupFinished: self.cloudkitModifyOperationFinished];
+    // If any one of our trust states succeed, this function doesn't have an error
+    for(CKKSPeerProviderState* trustState in trustStates) {
+        NSError* stateError = nil;
 
+        NSSet<CKKSTLKShareRecord*>* newTrustShares = [self createMissingKeyShares:keyset
+                                                                            peers:trustState
+                                                                            error:&stateError];
 
-        // Get the CloudKit operation ready...
-        CKModifyRecordsOperation* modifyRecordsOp = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave
-                                                                                          recordIDsToDelete:recordIDsToDelete];
-        modifyRecordsOp.atomic = YES;
-        modifyRecordsOp.longLived = NO;
 
-        // very important: get the TLKShares off-device ASAP
-        modifyRecordsOp.configuration.automaticallyRetryNetworkFailures = NO;
-        modifyRecordsOp.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
-        modifyRecordsOp.configuration.isCloudKitSupportOperation = YES;
+        if(newTrustShares && !stateError) {
+            newShares = newShares ? [newShares setByAddingObjectsFromSet:newTrustShares] : newTrustShares;
+        } else {
+            ckksnotice("ckksshare", keyset.tlk, "Unable to create shares for trust set %@: %@", trustState, stateError);
+            if(localerror == nil) {
+                localerror = stateError;
+            }
+        }
+    }
 
-        modifyRecordsOp.group = self.ckoperationGroup;
-        ckksnotice("ckksshare", ckks, "Operation group is %@", self.ckoperationGroup);
+    // Only report an error if none of the trust states were able to succeed
+    if(newShares) {
+        return newShares;
+    } else {
+        if(error && localerror) {
+            *error = localerror;
+        }
+        return nil;
+    }
+}
 
-        modifyRecordsOp.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) {
-            STRONGIFY(self);
-            CKKSKeychainView* blockCKKS = self.ckks;
++ (NSSet<CKKSTLKShareRecord*>*)createMissingKeyShares:(CKKSCurrentKeySet*)keyset
+                                                peers:(CKKSPeerProviderState*)trustState
+                                                error:(NSError* __autoreleasing*)error
+{
+    NSError* localerror = nil;
+    if(![keyset.tlk ensureKeyLoaded:&localerror]) {
+        ckkserror("ckksshare", keyset.tlk, "TLK not loaded; cannot make shares for peers: %@", localerror);
+        if(error) {
+            *error = localerror;
+        }
+        return nil;
+    }
 
-            // These should all fail or succeed as one. Do the hard work in the records completion block.
-            if(!error) {
-                ckksnotice("ckksshare", blockCKKS, "Successfully completed upload for record %@", record.recordID.recordName);
-            } else {
-                ckkserror("ckksshare", blockCKKS, "error on row: %@ %@", record.recordID, error);
-            }
-        };
-
-        modifyRecordsOp.modifyRecordsCompletionBlock = ^(NSArray<CKRecord *> *savedRecords, NSArray<CKRecordID *> *deletedRecordIDs, NSError *error) {
-            STRONGIFY(self);
-            CKKSKeychainView* strongCKKS = self.ckks;
-            if(!self) {
-                secerror("ckks: received callback for released object");
-                return;
-            }
+    NSSet<id<CKKSPeer>>* remainingPeers = [trustState findPeersMissingTLKSharesFor:keyset
+                                                                             error:&localerror];
+    if(!remainingPeers) {
+        ckkserror("ckksshare", keyset.tlk, "Unable to find peers missing TLKShares: %@", localerror);
+        if(error) {
+            *error = localerror;
+        }
+        return nil;
+    }
 
-            [strongCKKS dispatchSyncWithAccountKeys: ^bool {
-                if(error == nil) {
-                    // Success. Persist the records to the CKKS database
-                    ckksnotice("ckksshare", strongCKKS, "Completed TLK Share heal operation with success");
-                    NSError* localerror = nil;
-
-                    // Save the new CKRecords to the database
-                    for(CKRecord* record in savedRecords) {
-                        CKKSTLKShareRecord* savedShare = [[CKKSTLKShareRecord alloc] initWithCKRecord:record];
-                        bool saved = [savedShare saveToDatabase:&localerror];
-
-                        if(!saved || localerror != nil) {
-                            // erroring means we were unable to save the new TLKShare records to the database. This will cause us to try to reupload them. Fail.
-                            // No recovery from this, really...
-                            ckkserror("ckksshare", strongCKKS, "Couldn't save new TLKShare record to database: %@", localerror);
-                            [strongCKKS _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError: localerror];
-                            return true;
-
-                        } else {
-                            ckksnotice("ckksshare", strongCKKS, "Successfully completed upload for %@", savedShare);
-                        }
-                    }
+    NSMutableSet<CKKSTLKShareRecord*>* newShares = [NSMutableSet set];
 
-                    // Successfully sharing TLKs means we're now in ready!
-                    [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateReady withError: nil];
-                } else {
-                    ckkserror("ckksshare", strongCKKS, "Completed TLK Share heal operation with error: %@", error);
-                    [strongCKKS _onqueueCKWriteFailed:error attemptedRecordsChanged:attemptedRecords];
-                    // Send the key state machine into tlksharesfailed
-                    [strongCKKS _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateHealTLKSharesFailed withError: nil];
-                }
-                return true;
-            }];
+    for(id<CKKSPeer> peer in remainingPeers) {
+        if(!peer.publicEncryptionKey) {
+            ckksnotice("ckksshare", keyset.tlk, "No need to make TLK for %@; they don't have any encryption keys", peer);
+            continue;
+        }
 
-            // Notify that we're done
-            [self.operationQueue addOperation: self.cloudkitModifyOperationFinished];
-        };
+        // Create a share for this peer.
+        ckksnotice("ckksshare", keyset.tlk, "Creating share of %@ as %@ for %@", keyset.tlk, trustState.currentSelfPeers.currentSelf, peer);
+        CKKSTLKShareRecord* newShare = [CKKSTLKShareRecord share:keyset.tlk
+                                                              as:trustState.currentSelfPeers.currentSelf
+                                                              to:peer
+                                                           epoch:-1
+                                                        poisoned:0
+                                                           error:&localerror];
+
+        if(localerror) {
+            ckkserror("ckksshare", keyset.tlk, "Couldn't create new share for %@: %@", peer, localerror);
+            if(error) {
+                *error = localerror;
+            }
+            return nil;
+        }
 
-        [ckks.database addOperation: modifyRecordsOp];
-        return true;
-    }];
-}
+        [newShares addObject: newShare];
+    }
 
-- (void)cancel {
-    [self.cloudkitModifyOperationFinished cancel];
-    [super cancel];
+    return newShares;
 }
 
 @end;
index 8d425b21a6035260be15b4c54c6e6fe8d92890e3..64e36437a73b5881d27c03b9f7e0f218190988e1 100644 (file)
@@ -46,8 +46,9 @@ NS_ASSUME_NONNULL_BEGIN
 + (instancetype _Nullable)tryFromDatabase:(NSString*)uuid zoneID:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
 
 + (NSArray<CKKSIncomingQueueEntry*>* _Nullable)fetch:(ssize_t)n
-                                      startingAtUUID:(NSString*)uuid
+                                      startingAtUUID:(NSString* _Nullable)uuid
                                                state:(NSString*)state
+                                              action:(NSString* _Nullable)action
                                               zoneID:(CKRecordZoneID*)zoneID
                                                error:(NSError* __autoreleasing*)error;
 
index 0aa1311107a5c13ef1cc35ed6f6867002eead0b5..4e3e51fd1d6c5c20d4a51d23a9a9b56bcf96cab7 100644 (file)
 + (NSArray<CKKSIncomingQueueEntry*>*)fetch:(ssize_t)n
                             startingAtUUID:(NSString*)uuid
                                      state:(NSString*)state
+                                    action:(NSString* _Nullable)action
                                     zoneID:(CKRecordZoneID*)zoneID
                                      error: (NSError * __autoreleasing *) error {
     NSMutableDictionary* whereDict = [@{@"state": CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} mutableCopy];
+    whereDict[@"action"] = action;
     if(uuid) {
         whereDict[@"UUID"] = [CKKSSQLWhereValue op:CKKSSQLWhereComparatorGreaterThan value:uuid];
     }
index 8b8972854273d08bcb25d4d532df5f00cbccd9c7..1dd4102356d7a3a9793a2dcbfcada825eed83110 100644 (file)
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSGroupOperation.h"
 #if OCTAGON
+
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 @class CKKSItem;
 
-@interface CKKSIncomingQueueOperation : CKKSResultOperation
+@interface CKKSIncomingQueueOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 // Set this to true if this instance of CKKSIncomingQueueOperation
 // should error if it can't process class A items due to the keychain being locked.
 @property bool errorOnClassAFailure;
 
+// Set this to true if you're pretty sure that the policy set on the CKKS object
+// should be considered authoritative, and items that do not match this policy should
+// be moved.
+@property bool handleMismatchedViewItems;
+
 @property size_t successfulItemsProcessed;
 @property size_t errorItemsProcessed;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks errorOnClassAFailure:(bool)errorOnClassAFailure;
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intending
+                          errorState:(OctagonState*)errorState
+                errorOnClassAFailure:(bool)errorOnClassAFailure
+               handleMismatchedViewItems:(bool)handleMismatchedViewItems;
 
 // Use this to turn a CKKS item into a keychain dictionary suitable for keychain insertion
 + (NSDictionary* _Nullable)decryptCKKSItemToAttributes:(CKKSItem*)item error:(NSError**)error;
index e5c96b49d46fb5b9fc86f3911ad0fd54cd0fcd0f..b025a03c65048cb0df91d1df1f582f2b3e0a5a68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2016-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#import "CKKSKeychainView.h"
-#import "CKKSIncomingQueueOperation.h"
-#import "CKKSIncomingQueueEntry.h"
-#import "CKKSItemEncrypter.h"
-#import "CKKSOutgoingQueueEntry.h"
-#import "CKKSKey.h"
-#import "CKKSManifest.h"
-#import "CKKSAnalytics.h"
-#import "CKKSPowerCollection.h"
+#import "keychain/analytics/CKKSPowerCollection.h"
+#import "keychain/ckks/CKKSAnalytics.h"
 #import "keychain/ckks/CKKSCurrentItemPointer.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSIncomingQueueOperation.h"
+#import "keychain/ckks/CKKSItemEncrypter.h"
+#import "keychain/ckks/CKKSKey.h"
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CKKSStates.h"
+#import "keychain/ckks/CKKSViewManager.h"
+#import "keychain/ckks/CloudKitCategories.h"
 #import "keychain/ot/ObjCImprovements.h"
 
 #include "keychain/securityd/SecItemServer.h"
 #include "keychain/securityd/SecItemDb.h"
 #include <Security/SecItemPriv.h>
 
-#include <utilities/SecADWrapper.h>
 #import <utilities/SecCoreAnalytics.h>
 
 #if OCTAGON
 @property bool newOutgoingEntries;
 @property bool pendingClassAEntries;
 @property bool missingKey;
+
+@property NSMutableSet<NSString*>* viewsToScan;
 @end
 
 @implementation CKKSIncomingQueueOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks errorOnClassAFailure:(bool)errorOnClassAFailure {
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intending
+                          errorState:(OctagonState*)errorState
+                errorOnClassAFailure:(bool)errorOnClassAFailure
+               handleMismatchedViewItems:(bool)handleMismatchedViewItems
+{
     if(self = [super init]) {
+        _deps = dependencies;
         _ckks = ckks;
 
+        _intendedState = intending;
+        _nextState = errorState;
+
         // Can't process unless we have a reasonable key hierarchy.
         if(ckks.keyStateReadyDependency) {
             [self addDependency: ckks.keyStateReadyDependency];
         _errorOnClassAFailure = errorOnClassAFailure;
         _pendingClassAEntries = false;
 
-        [self linearDependencies:ckks.incomingQueueOperations];
-
-        if ([CKKSManifest shouldSyncManifests]) {
-            WEAKIFY(self);
-            CKKSResultOperation* updateManifestOperation = [CKKSResultOperation operationWithBlock:^{
-                STRONGIFY(self);
-                CKKSKeychainView* strongCKKS = self.ckks;
-                __block NSError* error = nil;
-                if (!strongCKKS || !self) {
-                    ckkserror("ckksincoming", strongCKKS, "update manifest operation fired for released object");
-                    return;
-                }
+        _handleMismatchedViewItems = handleMismatchedViewItems;
 
-                [strongCKKS dispatchSyncWithAccountKeys:^bool{
-                    strongCKKS.latestManifest = [CKKSManifest latestTrustedManifestForZone:strongCKKS.zoneName error:&error];
-                    if (error) {
-                        self.error = error;
-                        ckkserror("ckksincoming", strongCKKS, "failed to get latest manifest: %@", error);
-                        return false;
-                    }
-                    else {
-                        return true;
-                    }
-                }];
-            }];
-            updateManifestOperation.name = @"update-manifest-operation";
+        _viewsToScan = [NSMutableSet set];
 
-            [ckks scheduleOperation:updateManifestOperation];
-            [self addSuccessDependency:updateManifestOperation];
-        }
+        [self linearDependencies:ckks.incomingQueueOperations];
     }
     return self;
 }
 
-- (bool)processNewCurrentItemPointers:(NSArray<CKKSCurrentItemPointer*>*)queueEntries withManifest:(CKKSManifest*)manifest egoManifest:(CKKSEgoManifest*)egoManifest
+- (bool)processNewCurrentItemPointers:(NSArray<CKKSCurrentItemPointer*>*)queueEntries
 {
-    CKKSKeychainView* ckks = self.ckks;
-
     NSError* error = nil;
     for(CKKSCurrentItemPointer* p in queueEntries) {
         @autoreleasepool {
-            if ([CKKSManifest shouldSyncManifests]) {
-                if (![manifest validateCurrentItem:p withError:&error]) {
-                    ckkserror("ckksincoming", ckks, "Unable to validate current item pointer (%@) against manifest (%@)", p, manifest);
-                    if ([CKKSManifest shouldEnforceManifests]) {
-                        return false;
-                    }
-                }
-            }
-
             p.state = SecCKKSProcessedStateLocal;
 
             [p saveToDatabase:&error];
-            ckksnotice("ckkspointer", ckks, "Saving new current item pointer: %@", p);
+            ckksnotice("ckkspointer", self.deps.zoneID, "Saving new current item pointer: %@", p);
             if(error) {
-                ckkserror("ckksincoming", ckks, "Error saving new current item pointer: %@ %@", error, p);
+                ckkserror("ckksincoming", self.deps.zoneID, "Error saving new current item pointer: %@ %@", error, p);
             }
-
-            // Schedule a view change notification
-            [ckks.notifyViewChangedScheduler trigger];
         }
     }
 
     if(queueEntries.count > 0) {
-        // Schedule a view change notification
-        [ckks.notifyViewChangedScheduler trigger];
+        [self.deps.notifyViewChangedScheduler trigger];
     }
 
     return (error == nil);
 }
 
-- (bool)processQueueEntries:(NSArray<CKKSIncomingQueueEntry*>*)queueEntries withManifest:(CKKSManifest*)manifest egoManifest:(CKKSEgoManifest*)egoManifest
+- (bool)processQueueEntries:(NSArray<CKKSIncomingQueueEntry*>*)queueEntries
 {
     CKKSKeychainView* ckks = self.ckks;
+    dispatch_assert_queue(ckks.queue);
 
     NSMutableArray* newOrChangedRecords = [[NSMutableArray alloc] init];
     NSMutableArray* deletedRecordIDs = [[NSMutableArray alloc] init];
 
     for(id entry in queueEntries) {
         @autoreleasepool {
-            if(self.cancelled) {
-                ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
-                return false;
-            }
-
             NSError* error = nil;
 
             CKKSIncomingQueueEntry* iqe = (CKKSIncomingQueueEntry*) entry;
-            ckksnotice("ckksincoming", ckks, "ready to process an incoming queue entry: %@ %@ %@", iqe, iqe.uuid, iqe.action);
+            ckksnotice("ckksincoming", self.deps.zoneID, "ready to process an incoming queue entry: %@ %@ %@", iqe, iqe.uuid, iqe.action);
 
             // Note that we currently unencrypt the item before deleting it, instead of just deleting it
             // This finds the class, which is necessary for the deletion process. We could just try to delete
             NSDictionary* attributes = [CKKSIncomingQueueOperation decryptCKKSItemToAttributes:iqe.item error:&error];
 
             if(!attributes || error) {
-                if([ckks.lockStateTracker isLockedError:error]) {
+                if([self.deps.lockStateTracker isLockedError:error]) {
                     NSError* localerror = nil;
-                    ckkserror("ckksincoming", ckks, "Keychain is locked; can't decrypt IQE %@", iqe);
-                    CKKSKey* key = [CKKSKey tryFromDatabase:iqe.item.parentKeyUUID zoneID:ckks.zoneID error:&localerror];
+                    ckkserror("ckksincoming", self.deps.zoneID, "Keychain is locked; can't decrypt IQE %@", iqe);
+                    CKKSKey* key = [CKKSKey tryFromDatabase:iqe.item.parentKeyUUID zoneID:self.deps.zoneID error:&localerror];
                     if(localerror || ([key.keyclass isEqualToString:SecCKKSKeyClassA] && self.errorOnClassAFailure)) {
                         self.error = error;
                     }
                     }
 
                 } else if ([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) {
-                    ckkserror("ckksincoming", ckks, "Coudn't find key in keychain; will attempt to poke key hierarchy: %@", error)
+                    ckkserror("ckksincoming", self.deps.zoneID, "Coudn't find key in keychain; will attempt to poke key hierarchy: %@", error)
                     self.missingKey = true;
+                    self.error = error;
 
                 } else {
-                    ckkserror("ckksincoming", ckks, "Couldn't decrypt IQE %@ for some reason: %@", iqe, error);
+                    ckkserror("ckksincoming", self.deps.zoneID, "Couldn't decrypt IQE %@ for some reason: %@", iqe, error);
                     self.error = error;
                 }
                 self.errorItemsProcessed += 1;
                 self.error = [NSError errorWithDomain:@"securityd"
                                                  code:errSecInternalError
                                              userInfo:@{NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Item did not have a reasonable class: %@", classStr]}];
-                ckkserror("ckksincoming", ckks, "Synced item seems wrong: %@", self.error);
+                ckkserror("ckksincoming", self.deps.zoneID, "Synced item seems wrong: %@", self.error);
                 self.errorItemsProcessed += 1;
                 continue;
             }
             const SecDbClass * classP = !classStr ? NULL : kc_class_with_name((__bridge CFStringRef) classStr);
 
             if(!classP) {
-                ckkserror("ckksincoming", ckks, "unknown class in object: %@ %@", classStr, iqe);
+                ckkserror("ckksincoming", self.deps.zoneID, "unknown class in object: %@ %@", classStr, iqe);
                 iqe.state = SecCKKSStateError;
                 [iqe saveToDatabase:&error];
                 if(error) {
-                    ckkserror("ckksincoming", ckks, "Couldn't save errored IQE to database: %@", error);
+                    ckkserror("ckksincoming", self.deps.zoneID, "Couldn't save errored IQE to database: %@", error);
                     self.error = error;
                 }
                 self.errorItemsProcessed += 1;
                 continue;
             }
 
-            if([iqe.action isEqualToString: SecCKKSActionAdd] || [iqe.action isEqualToString: SecCKKSActionModify]) {
-                BOOL requireManifestValidation = [CKKSManifest shouldEnforceManifests];
-                BOOL manifestValidatesItem = [manifest validateItem:iqe.item withError:&error];
-
-                if (!requireManifestValidation || manifestValidatesItem) {
-                    [self _onqueueHandleIQEChange: iqe attributes:attributes class:classP];
-                    [newOrChangedRecords addObject:[iqe.item CKRecordWithZoneID:ckks.zoneID]];
-                }
-                else {
-                    ckkserror("ckksincoming", ckks, "could not validate incoming item against manifest with error: %@", error);
-                    if (![self _onqueueUpdateIQE:iqe withState:SecCKKSStateUnauthenticated error:&error]) {
-                        ckkserror("ckksincoming", ckks, "failed to save incoming item back to database in unauthenticated state with error: %@", error);
-                        return false;
-                    }
-                    self.errorItemsProcessed += 1;
-                    continue;
-                }
-            } else if ([iqe.action isEqualToString: SecCKKSActionDelete]) {
-                BOOL requireManifestValidation = [CKKSManifest shouldEnforceManifests];
-                BOOL manifestValidatesDelete = ![manifest itemUUIDExistsInManifest:iqe.uuid];
-            
-                if (!requireManifestValidation || manifestValidatesDelete) {
-                    // if the item does not exist in the latest manifest, we're good to delete it
-                    [self _onqueueHandleIQEDelete: iqe class:classP];
-                    [deletedRecordIDs addObject:[[CKRecordID alloc] initWithRecordName:iqe.uuid zoneID:ckks.zoneID]];
-                }
-                else {
-                    // if the item DOES exist in the manifest, we can't trust the deletion
-                    ckkserror("ckksincoming", ckks, "could not validate incoming item deletion against manifest");
-                    if (![self _onqueueUpdateIQE:iqe withState:SecCKKSStateUnauthenticated error:&error]) {
-                        ckkserror("ckksincoming", ckks, "failed to save incoming item deletion back to database in unauthenticated state with error: %@", error);
+            NSString* intendedView = [self.deps.syncingPolicy mapDictionaryToView:attributes];
+            if(![self.deps.zoneID.zoneName isEqualToString:intendedView]) {
+                if(self.handleMismatchedViewItems) {
+                    [self _onqueueHandleMismatchedViewItem:iqe
+                                                secDbClass:classP
+                                                attributes:attributes
+                                              intendedView:intendedView];
+                } else {
+                    ckksnotice("ckksincoming", ckks, "Received an item (%@), but our current policy claims it should be in view %@", iqe.uuid, intendedView);
 
+                    [self _onqueueUpdateIQE:iqe withState:SecCKKSStateMismatchedView error:&error];
+                    if(error) {
+                        ckkserror("ckksincoming", ckks, "Couldn't save mismatched IQE to database: %@", error);
                         self.errorItemsProcessed += 1;
-                        return false;
+                        self.error = error;
                     }
+
+                    [ckks receivedItemForWrongView];
                 }
+                continue;
+            }
+
+            if([iqe.action isEqualToString: SecCKKSActionAdd] || [iqe.action isEqualToString: SecCKKSActionModify]) {
+                [self _onqueueHandleIQEChange:iqe
+                                   attributes:attributes
+                                        class:classP
+                            sortedForThisView:YES];
+                [newOrChangedRecords addObject:[iqe.item CKRecordWithZoneID:self.deps.zoneID]];
+
+            } else if ([iqe.action isEqualToString: SecCKKSActionDelete]) {
+                [self _onqueueHandleIQEDelete: iqe class:classP];
+                [deletedRecordIDs addObject:[[CKRecordID alloc] initWithRecordName:iqe.uuid zoneID:self.deps.zoneID]];
             }
         }
     }
 
     if(newOrChangedRecords.count > 0 || deletedRecordIDs > 0) {
         // Schedule a view change notification
-        [ckks.notifyViewChangedScheduler trigger];
+        [self.deps.notifyViewChangedScheduler trigger];
     }
 
     if(self.missingKey) {
-        [ckks.pokeKeyStateMachineScheduler trigger];
+        // TODO: will be removed when the IncomingQueueOperation is part of the state machine
+        [ckks.stateMachine _onqueuePokeStateMachine];
+        self.nextState = SecCKKSZoneKeyStateUnhealthy;
     }
 
-    if ([CKKSManifest shouldSyncManifests]) {
-        [egoManifest updateWithNewOrChangedRecords:newOrChangedRecords deletedRecordIDs:deletedRecordIDs];
-    }
     return true;
 }
 
+- (void)_onqueueHandleMismatchedViewItem:(CKKSIncomingQueueEntry*)iqe
+                              secDbClass:(const SecDbClass*)secDbClass
+                              attributes:(NSDictionary*)attributes
+                            intendedView:(NSString* _Nullable)intendedView
+{
+    ckksnotice("ckksincoming", self.deps.zoneID, "Received an item (%@), which should be in view %@", iqe.uuid, intendedView);
+
+    // Here's the plan:
+    //
+    // If this is an add or a modify, we will execute the modification _if we do not currently have this item_.
+    // Then, ask the view that should handle this item to scan.
+    //
+    // When, we will leave the CloudKit record in the existing 'wrong' view.
+    // This will allow garbage to collect, but should prevent item loss in complicated multi-device scenarios.
+    //
+    // If this is a deletion, then we will inspect the other zone's current on-disk state. If it knows about the item,
+    // we will ignore the deletion from this view. Otherwise, we will proceed with the deletion.
+    // Note that the deletion approach already ensures that the UUID of the deleted item matches the UUID of the CKRecord.
+    // This protects against an item being in multiple views, and deleted from only one.
+
+    if([iqe.action isEqualToString:SecCKKSActionAdd] || [iqe.action isEqualToString:SecCKKSActionModify]) {
+        CFErrorRef cferror = NULL;
+        SecDbItemRef item = SecDbItemCreateWithAttributes(NULL, secDbClass, (__bridge CFDictionaryRef) attributes, KEYBAG_DEVICE, &cferror);
+
+        if(!item || cferror) {
+            ckkserror("ckksincoming", self.deps.zoneID, "Unable to create SecDbItemRef from IQE: %@", cferror);
+            return;
+        }
+
+        [self _onqueueHandleIQEChange:iqe item:item sortedForThisView:NO];
+        [self.viewsToScan addObject:intendedView];
+
+        CFReleaseNull(item);
+
+    } else if ([iqe.action isEqualToString:SecCKKSActionDelete]) {
+        NSError* loadError = nil;
+
+        CKRecordZoneID* otherZoneID = [[CKRecordZoneID alloc] initWithZoneName:intendedView ownerName:CKCurrentUserDefaultName];
+        CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:iqe.uuid zoneID:otherZoneID error:&loadError];
+
+        if(!ckme || loadError) {
+            ckksnotice("ckksincoming", self.deps.zoneID, "Unable to load CKKSMirrorEntry from database* %@", loadError);
+            return;
+        }
+
+        if(ckme) {
+            ckksnotice("ckksincoming", self.deps.zoneID, "Other view (%@) already knows about this item, dropping incoming queue entry: %@", intendedView, ckme);
+            NSError* saveError = nil;
+            [iqe deleteFromDatabase:&saveError];
+            if(saveError) {
+                ckkserror("ckksincoming", self.deps.zoneID, "Unable to delete IQE: %@", saveError);
+            }
+
+        } else {
+            ckksnotice("ckksincoming", self.deps.zoneID, "Other view (%@) does not know about this item; processing delete for %@", intendedView, iqe);
+            [self _onqueueHandleIQEDelete:iqe class:secDbClass];
+        }
+
+    } else {
+        // We don't recognize this action. Do nothing.
+    }
+}
+
 + (NSDictionary* _Nullable)decryptCKKSItemToAttributes:(CKKSItem*)item error:(NSError**)error
 {
     NSMutableDictionary* attributes = [[CKKSItemEncrypter decryptItemToDictionary:item error:error] mutableCopy];
     return true;
 }
 
-- (void) main {
-    // Synchronous, on some thread. Get back on the CKKS queue for thread-safety.
+- (void)main
+{
     CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksincoming", ckks, "no CKKS object");
+
+    if(!ckks.itemSyncingEnabled) {
+        ckkserror("ckksincoming", self.deps.zoneID, "Item syncing for this view is disabled");
+        self.nextState = self.intendedState;
         return;
     }
 
     self.completionBlock = ^(void) {
         STRONGIFY(self);
         if (!self) {
-            ckkserror("ckksincoming", ckks, "received callback for released object");
+            ckkserror("ckksincoming", self.deps.zoneID, "received callback for released object");
             return;
         }
 
         CKKSAnalytics* logger = [CKKSAnalytics logger];
 
         if (!self.error) {
-            [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:ckks];
+            [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassC zoneName:self.deps.zoneID.zoneName];
+
             if (!self.pendingClassAEntries) {
-                [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassA inView:ckks];
+                [logger logSuccessForEvent:CKKSEventProcessIncomingQueueClassA zoneName:self.deps.zoneID.zoneName];
             }
         } else {
             [logger logRecoverableError:self.error
                                forEvent:self.errorOnClassAFailure ? CKKSEventProcessIncomingQueueClassA : CKKSEventProcessIncomingQueueClassC
-                                 inView:ckks
+                               zoneName:self.deps.zoneID.zoneName
                          withAttributes:NULL];
         }
     };
 
-    __block bool errored = false;
-    [ckks dispatchSync: ^bool{
-        if(self.cancelled) {
-            ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
-            return false;
-        }
-        ckks.lastIncomingQueueOperation = self;
+    ckksnotice("ckksincoming", self.deps.zoneID, "Processing incoming queue");
 
-        ckksnotice("ckksincoming", ckks, "Processing incoming queue");
+    // First, process all item deletions.
+    // Then, process all modifications and additions.
+    // Therefore, if there's both a delete and a re-add of a single Primary Key item in the queue,
+    // we should end up with the item still existing in tthe keychain afterward.
+    // But, since we're dropping off the queue inbetween, we might accidentally tell our clients that
+    // their item doesn't exist. Fixing that would take quite a bit of complexity and memory.
 
-        if ([CKKSManifest shouldSyncManifests]) {
-            if (!ckks.latestManifest) {
-                // Until we can make manifests in our unit tests, we can't abort here
-                ckkserror("ckksincoming", ckks, "no manifest in ckks");
-            }
-            if (!ckks.egoManifest) {
-                ckkserror("ckksincoming", ckks, "no ego manifest in ckks");
-            }
-        }
-
-        bool ok = true; // Should commit transaction?
-        __block NSError* error = nil;
+    BOOL success = [self loadAndProcessEntriesWithActionFilter:SecCKKSActionDelete];
+    if(!success) {
+        ckksnotice("ckksincoming", self.deps.zoneID, "Early-exiting from IncomingQueueOperation (after processing deletes): %@", self.error);
+        return;
+    }
 
-        if ([CKKSManifest shouldSyncManifests]) {
-            NSInteger unauthenticatedItemCount = [CKKSIncomingQueueEntry countByState:SecCKKSStateUnauthenticated zone:ckks.zoneID error:&error];
-            if (error || unauthenticatedItemCount < 0) {
-                ckkserror("ckksincoming", ckks, "Error fetching incoming queue state counts: %@", error);
-                self.error = error;
-                return false;
-            }
+    success = [self loadAndProcessEntriesWithActionFilter:nil];
+    if(!success) {
+        ckksnotice("ckksincoming", self.deps.zoneID, "Early-exiting from IncomingQueueOperation (after processing all incoming entries): %@", self.error);
+        return;
+    }
 
-            // take any existing unauthenticated entries and put them back in the new state
-            NSArray<CKKSIncomingQueueEntry*>* unauthenticatedEntries = nil;
-            NSString* lastMaxUUID = nil;
-            NSInteger numEntriesProcessed = 0;
-            while (numEntriesProcessed < unauthenticatedItemCount &&  (unauthenticatedEntries == nil || unauthenticatedEntries.count == SecCKKSIncomingQueueItemsAtOnce)) {
-                if(self.cancelled) {
-                    ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
-                    return false;
-                }
+    ckksnotice("ckksincoming", self.deps.zoneID, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
 
-                unauthenticatedEntries = [CKKSIncomingQueueEntry fetch:SecCKKSIncomingQueueItemsAtOnce
-                                                        startingAtUUID:lastMaxUUID
-                                                                 state:SecCKKSStateUnauthenticated
-                                                                zoneID:ckks.zoneID
-                                                                 error:&error];
-                if (error) {
-                    ckkserror("ckksincoming", ckks, "Error fetching unauthenticated queue records: %@", error);
-                    self.error = error;
-                    return false;
-                }
-
-                if (unauthenticatedEntries.count == 0) {
-                    ckksinfo("ckksincoming", ckks, "No unauthenticated entries in incoming queue to process");
-                    break;
-                }
+    if(![self fixMismatchedViewItems]) {
+        ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation due to failure fixing mismatched items");
+        return;
+    }
 
-                for (CKKSIncomingQueueEntry* unauthenticatedEntry in unauthenticatedEntries) {
-                    if (![self _onqueueUpdateIQE:unauthenticatedEntry withState:SecCKKSStateNew error:&error]) {
-                        ckkserror("ckksincoming", ckks, "Error saving unauthenticated entry back to new state: %@", error);
-                        self.error = error;
-                        return false;
-                    }
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        NSError* error = nil;
 
-                    lastMaxUUID = ([lastMaxUUID compare:unauthenticatedEntry.uuid] == NSOrderedDescending) ? lastMaxUUID : unauthenticatedEntry.uuid;
-                }
+        NSArray<CKKSCurrentItemPointer*>* newCIPs = [CKKSCurrentItemPointer remoteItemPointers:self.deps.zoneID error:&error];
+        if(error || !newCIPs) {
+            ckkserror("ckksincoming", self.deps.zoneID, "Could not load remote item pointers: %@", error);
+        } else {
+            if (![self processNewCurrentItemPointers:newCIPs]) {
+                return CKKSDatabaseTransactionRollback;
             }
+            ckksnotice("ckksincoming", self.deps.zoneID, "Processed %lu items in CIP queue", (unsigned long)newCIPs.count);
         }
-        errored = !ok;
-        return ok;
+
+        return CKKSDatabaseTransactionCommit;
     }];
 
-    if(errored) {
-        ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
-        return;
+    if(self.newOutgoingEntries) {
+        //[self.deps.flagHandler handleFlag:CKKSFlagProcessOutgoingQueue];
+        [ckks processOutgoingQueue:[CKOperationGroup CKKSGroupWithName:@"incoming-queue-response"]];
+    }
+
+    if(self.pendingClassAEntries) {
+        [ckks processIncomingQueueAfterNextUnlock];
+        //OctagonPendingFlag* whenUnlocked = [[OctagonPendingFlag alloc] initWithFlag:CKKSFlagProcessIncomingQueue
+        //                                                                 conditions:OctagonPendingConditionsDeviceUnlocked];
+        //[self.deps.flagHandler handlePendingFlag:whenUnlocked];
+    }
+
+    for(NSString* viewName in self.viewsToScan) {
+        CKKSKeychainView* view = [[CKKSViewManager manager] findView:viewName];
+        ckksnotice("ckksincoming", ckks, "Requesting scan for %@ (%@)", view, viewName);
+        [view scanLocalItems:@"policy-mismatch"];
     }
 
+    self.nextState = self.intendedState;
+}
+
+- (BOOL)loadAndProcessEntriesWithActionFilter:(NSString* _Nullable)actionFilter
+{
+    __block bool errored = false;
+
     // Now for the tricky bit: take and drop the account queue for each batch of queue entries
     // This is for peak memory concerns, but also to allow keychain API clients to make changes while we're processing many items
     // Note that IncomingQueueOperations are no longer transactional: they can partially succeed. This might make them harder to reason about.
     __block NSUInteger lastCount = SecCKKSIncomingQueueItemsAtOnce;
     __block NSString* lastMaxUUID = nil;
 
+    id<CKKSDatabaseProviderProtocol> databaseProvider = self.deps.databaseProvider;
+
     while(lastCount == SecCKKSIncomingQueueItemsAtOnce) {
-        [ckks dispatchSync: ^bool{
+        [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
             NSArray<CKKSIncomingQueueEntry*> * queueEntries = nil;
             if(self.cancelled) {
-                ckksnotice("ckksincoming", ckks, "CKKSIncomingQueueOperation cancelled, quitting");
+                ckksnotice("ckksincoming", self.deps.zoneID, "CKKSIncomingQueueOperation cancelled, quitting");
                 errored = true;
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             NSError* error = nil;
 
-            queueEntries = [CKKSIncomingQueueEntry fetch: SecCKKSIncomingQueueItemsAtOnce
+            queueEntries = [CKKSIncomingQueueEntry fetch:SecCKKSIncomingQueueItemsAtOnce
                                           startingAtUUID:lastMaxUUID
                                                    state:SecCKKSStateNew
-                                                  zoneID:ckks.zoneID
-                                                   error: &error];
+                                                  action:actionFilter
+                                                  zoneID:self.deps.zoneID
+                                                   error:&error];
 
             if(error != nil) {
-                ckkserror("ckksincoming", ckks, "Error fetching incoming queue records: %@", error);
+                ckkserror("ckksincoming", self.deps.zoneID, "Error fetching incoming queue records: %@", error);
                 self.error = error;
-                errored = true;
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             lastCount = queueEntries.count;
 
             if([queueEntries count] == 0) {
                 // Nothing to do! exit.
-                ckksnotice("ckksincoming", ckks, "Nothing in incoming queue to process");
-                return true;
+                ckksinfo("ckksincoming", self.deps.zoneID, "Nothing in incoming queue to process (filter: %@)", actionFilter);
+                return CKKSDatabaseTransactionCommit;
             }
 
-            [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventOutgoingQueue zone:ckks.zoneName count:[queueEntries count]];
+            [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventIncommingQueue zone:self.deps.zoneID.zoneName count:[queueEntries count]];
 
-            if (![self processQueueEntries:queueEntries withManifest:ckks.latestManifest egoManifest:ckks.egoManifest]) {
-                ckksnotice("ckksincoming", ckks, "processQueueEntries didn't complete successfully");
+            if (![self processQueueEntries:queueEntries]) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "processQueueEntries didn't complete successfully");
                 errored = true;
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             // Find the highest UUID for the next fetch.
             for(CKKSIncomingQueueEntry* iqe in queueEntries) {
                 lastMaxUUID = ([lastMaxUUID compare:iqe.uuid] == NSOrderedDescending) ? lastMaxUUID : iqe.uuid;
-            };
-            return true;
+            }
+
+            return CKKSDatabaseTransactionCommit;
         }];
 
         if(errored) {
-            ckksnotice("ckksincoming", ckks, "Early-exiting from IncomingQueueOperation");
-            return;
+            ckksnotice("ckksincoming", self.deps.zoneID, "Early-exiting from IncomingQueueOperation");
+            return false;
         }
     }
 
-    ckksnotice("ckksincoming", ckks, "Processed %lu items in incoming queue (%lu errors)", (unsigned long)self.successfulItemsProcessed, (unsigned long)self.errorItemsProcessed);
+    return true;
+}
+- (BOOL)fixMismatchedViewItems
+{
+    if(!self.handleMismatchedViewItems) {
+        return YES;
+    }
 
-    [ckks dispatchSync: ^bool{
-        NSError* error = nil;
+    ckksnotice("ckksincoming", self.deps.zoneID, "Handling policy-mismatched items");
+    __block NSUInteger lastCount = SecCKKSIncomingQueueItemsAtOnce;
+    __block NSString* lastMaxUUID = nil;
+    __block BOOL errored = NO;
 
-        NSArray<CKKSCurrentItemPointer*>* newCIPs = [CKKSCurrentItemPointer remoteItemPointers:ckks.zoneID error:&error];
-        if(error || !newCIPs) {
-            ckkserror("ckksincoming", ckks, "Could not load remote item pointers: %@", error);
-        } else {
-            if (![self processNewCurrentItemPointers:newCIPs withManifest:ckks.latestManifest egoManifest:ckks.egoManifest]) {
-                return false;
+    id<CKKSDatabaseProviderProtocol> databaseProvider = self.deps.databaseProvider;
+
+    while(lastCount == SecCKKSIncomingQueueItemsAtOnce) {
+        [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            NSError* error = nil;
+            NSArray<CKKSIncomingQueueEntry*>* queueEntries = [CKKSIncomingQueueEntry fetch:SecCKKSIncomingQueueItemsAtOnce
+                                                                            startingAtUUID:lastMaxUUID
+                                                                                     state:SecCKKSStateMismatchedView
+                                                                                    action:nil
+                                                                                    zoneID:self.deps.zoneID
+                                                                                     error:&error];
+            if(error) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "Cannot fetch mismatched view items");
+                self.error = error;
+                errored = true;
+                return CKKSDatabaseTransactionRollback;
             }
-            ckksnotice("ckksincoming", ckks, "Processed %lu items in CIP queue", (unsigned long)newCIPs.count);
-        }
 
-        if(self.newOutgoingEntries) {
-            // No operation group
-            [ckks processOutgoingQueue:nil];
-        }
+            lastCount = queueEntries.count;
 
-        if(self.pendingClassAEntries) {
-            [self.ckks processIncomingQueueAfterNextUnlock];
-        }
+            if(queueEntries.count == 0) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "No mismatched view items");
+                return CKKSDatabaseTransactionCommit;
+            }
 
-        return true;
-    }];
-}
+            ckksnotice("ckksincoming", self.deps.zoneID, "Inspecting %lu mismatched items", (unsigned long)queueEntries.count);
 
-- (void)_onqueueHandleIQEChange: (CKKSIncomingQueueEntry*) iqe attributes:(NSDictionary*)attributes class:(const SecDbClass *)classP {
-    CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksincoming", ckks, "no CKKS object");
-        return;
+            if (![self processQueueEntries:queueEntries]) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "processQueueEntries didn't complete successfully");
+                errored = true;
+                return CKKSDatabaseTransactionRollback;
+            }
+
+            for(CKKSIncomingQueueEntry* iqe in queueEntries) {
+                lastMaxUUID = ([lastMaxUUID compare:iqe.uuid] == NSOrderedDescending) ? lastMaxUUID : iqe.uuid;
+            }
+
+            return CKKSDatabaseTransactionCommit;
+        }];
     }
 
-    dispatch_assert_queue(ckks.queue);
+    return !errored;
+}
+
+- (void)_onqueueHandleIQEChange:(CKKSIncomingQueueEntry*)iqe
+                     attributes:(NSDictionary*)attributes
+                          class:(const SecDbClass *)classP
+              sortedForThisView:(BOOL)sortedForThisView
+{
+    __block CFErrorRef cferror = NULL;
+    SecDbItemRef item = SecDbItemCreateWithAttributes(NULL, classP, (__bridge CFDictionaryRef) attributes, KEYBAG_DEVICE, &cferror);
 
+     if(!item || cferror) {
+         ckkserror("ckksincoming", self.deps.zoneID, "Unable to make SecDbItemRef out of attributes: %@", cferror);
+         return;
+     }
+     CFReleaseNull(cferror);
+
+     [self _onqueueHandleIQEChange:iqe
+                              item:item
+                 sortedForThisView:sortedForThisView];
+
+    CFReleaseNull(item);
+}
+
+- (void)_onqueueHandleIQEChange:(CKKSIncomingQueueEntry*)iqe
+                           item:(SecDbItemRef)item
+              sortedForThisView:(BOOL)sortedForThisView
+{
     bool ok = false;
     __block CFErrorRef cferror = NULL;
     __block NSError* error = NULL;
 
-    SecDbItemRef item = SecDbItemCreateWithAttributes(NULL, classP, (__bridge CFDictionaryRef) attributes, KEYBAG_DEVICE, &cferror);
+    if(SecDbItemIsTombstone(item)) {
+        ckkserror("ckksincoming", self.deps.zoneID, "Rejecting a tombstone item addition from CKKS(%@): %@", iqe.uuid, item);
+
+        NSError* error = nil;
+        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry withItem:item action:SecCKKSActionDelete zoneID:self.deps.zoneID error:&error];
+        [oqe saveToDatabase:&error];
+
+        if(error) {
+            ckkserror("ckksincoming", self.deps.zoneID, "Unable to save new deletion OQE: %@", error);
+        } else {
+            [iqe deleteFromDatabase: &error];
+            if(error) {
+                ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete CKKSIncomingQueueEntry: %@", error);
+                self.error = error;
+                self.errorItemsProcessed += 1;
+            } else {
+                self.successfulItemsProcessed += 1;
+            }
+        }
+        self.newOutgoingEntries = true;
+
+        return;
+    }
 
     __block NSDate* moddate = (__bridge NSDate*) CFDictionaryGetValue(item->attributes, kSecAttrModificationDate);
 
     ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt){
         bool replaceok = SecDbItemInsertOrReplace(item, dbt, &cferror, ^(SecDbItemRef olditem, SecDbItemRef *replace) {
-            // If the UUIDs do not match, then select the item with the 'lower' UUID, and tell CKKS to
+            // If the UUIDs do not match, then check to be sure that the local item is known to CKKS. If not, accept the cloud value.
+            // Otherwise, when the UUIDs do not match, then select the item with the 'lower' UUID, and tell CKKS to
             //   delete the item with the 'higher' UUID.
             // Otherwise, the cloud wins.
 
-            SecADAddValueForScalarKey((__bridge CFStringRef) SecCKKSAggdPrimaryKeyConflict,1);
+            [SecCoreAnalytics sendEvent:SecCKKSAggdPrimaryKeyConflict event:@{SecCoreAnalyticsValue: @1}];
 
             // Note that SecDbItemInsertOrReplace CFReleases any replace pointer it's given, so, be careful
 
             if(!CFDictionaryContainsKey(olditem->attributes, kSecAttrUUID)) {
                 // No UUID -> no good.
-                ckksnotice("ckksincoming", ckks, "Replacing item (it doesn't have a UUID) for %@", iqe.uuid);
+                ckksnotice("ckksincoming", self.deps.zoneID, "Replacing item (it doesn't have a UUID) for %@", iqe.uuid);
                 if(replace) {
                     *replace = CFRetainSafe(item);
                 }
                 return;
             }
 
+            // If this item arrived in what we believe to be the wrong view, drop the modification entirely.
+            if(!sortedForThisView) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "Primary key conflict; dropping CK item (arriving from wrong view) %@", item);
+                return;
+            }
+
             CFStringRef itemUUID    = CFDictionaryGetValue(item->attributes,    kSecAttrUUID);
             CFStringRef olditemUUID = CFDictionaryGetValue(olditem->attributes, kSecAttrUUID);
 
+            // Is the old item already somewhere in CKKS?
+            NSError* ckmeError = nil;
+            CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:(__bridge NSString*)olditemUUID
+                                                              zoneID:self.deps.zoneID
+                                                               error:&ckmeError];
+
+            if(ckmeError) {
+                ckksnotice("ckksincoming", self.deps.zoneID, "Unable to fetch ckme: %@", ckmeError);
+                // We'll just have to assume that there is a CKME, and let the comparison analysis below win
+            }
+
             CFComparisonResult compare = CFStringCompare(itemUUID, olditemUUID, 0);
             CKKSOutgoingQueueEntry* oqe = nil;
-            if (compare == kCFCompareGreaterThan) {
+            if (compare == kCFCompareGreaterThan && (ckme || ckmeError)) {
                 // olditem wins; don't change olditem; delete item
-                ckksnotice("ckksincoming", ckks, "Primary key conflict; dropping CK item %@", item);
-                oqe = [CKKSOutgoingQueueEntry withItem:item action:SecCKKSActionDelete ckks:ckks error:&error];
+                ckksnotice("ckksincoming", self.deps.zoneID, "Primary key conflict; dropping CK item %@", item);
+                oqe = [CKKSOutgoingQueueEntry withItem:item action:SecCKKSActionDelete zoneID:self.deps.zoneID error:&error];
                 [oqe saveToDatabase: &error];
                 self.newOutgoingEntries = true;
                 moddate = nil;
             } else {
-                // item wins
-                ckksnotice("ckksincoming", ckks, "Primary key conflict; replacing %@ with CK item %@", olditem, item);
+                // item wins, either due to the UUID winning or the item not being in CKKS yet
+                ckksnotice("ckksincoming", self.deps.zoneID, "Primary key conflict; replacing %@%@ with CK item %@",
+                           ckme ? @"" : @"non-onboarded", olditem, item);
                 if(replace) {
                     *replace = CFRetainSafe(item);
                     moddate = (__bridge NSDate*) CFDictionaryGetValue(item->attributes, kSecAttrModificationDate);
                 }
                 // delete olditem if UUID differs (same UUID is the normal update case)
                 if (compare != kCFCompareEqualTo) {
-                    oqe = [CKKSOutgoingQueueEntry withItem:olditem action:SecCKKSActionDelete ckks:ckks error:&error];
+                    oqe = [CKKSOutgoingQueueEntry withItem:olditem action:SecCKKSActionDelete zoneID:self.deps.zoneID error:&error];
                     [oqe saveToDatabase: &error];
                     self.newOutgoingEntries = true;
                 }
         return replaceok;
     });
 
-    CFReleaseNull(item);
-
     if(cferror) {
-        ckkserror("ckksincoming", ckks, "couldn't process item from IncomingQueue: %@", cferror);
+        ckkserror("ckksincoming", self.deps.zoneID, "couldn't process item from IncomingQueue: %@", cferror);
         SecTranslateError(&error, cferror);
         self.error = error;
 
         iqe.state = SecCKKSStateError;
         [iqe saveToDatabase:&error];
         if(error) {
-            ckkserror("ckksincoming", ckks, "Couldn't save errored IQE to database: %@", error);
+            ckkserror("ckksincoming", self.deps.zoneID, "Couldn't save errored IQE to database: %@", error);
             self.error = error;
         }
         return;
     }
 
     if(error) {
-        ckkserror("ckksincoming", ckks, "Couldn't handle IQE, but why?: %@", error);
+        ckkserror("ckksincoming", self.deps.zoneID, "Couldn't handle IQE, but why?: %@", error);
         self.error = error;
         return;
     }
 
     if(ok) {
-        ckksinfo("ckksincoming", ckks, "Correctly processed an IQE; deleting");
+        ckksinfo("ckksincoming", self.deps.zoneID, "Correctly processed an IQE; deleting");
         [iqe deleteFromDatabase: &error];
 
         if(error) {
-            ckkserror("ckksincoming", ckks, "couldn't delete CKKSIncomingQueueEntry: %@", error);
+            ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete CKKSIncomingQueueEntry: %@", error);
             self.error = error;
             self.errorItemsProcessed += 1;
         } else {
         if(moddate) {
             // Log the number of ms it took to propagate this change
             uint64_t delayInMS = [[NSDate date] timeIntervalSinceDate:moddate] * 1000;
-            [SecCoreAnalytics sendEvent:@"com.apple.ckks.item.propagation" event:@{
+            [SecCoreAnalytics sendEvent:@"com.apple.self.deps.item.propagation" event:@{
                 @"time" : @(delayInMS)
             }];
 
         }
 
     } else {
-        ckksnotice("ckksincoming", ckks, "IQE not correctly processed, but why? %@ %@", error, cferror);
+        ckksnotice("ckksincoming", self.deps.zoneID, "IQE not correctly processed, but why? %@ %@", error, cferror);
         self.error = error;
 
         iqe.state = SecCKKSStateError;
         [iqe saveToDatabase:&error];
         if(error) {
-            ckkserror("ckksincoming", ckks, "Couldn't save errored IQE to database: %@", error);
+            ckkserror("ckksincoming", self.deps.zoneID, "Couldn't save errored IQE to database: %@", error);
             self.error = error;
         }
 
 }
 
 - (void)_onqueueHandleIQEDelete: (CKKSIncomingQueueEntry*) iqe class:(const SecDbClass *)classP {
-    CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksincoming", ckks, "no CKKS object");
-        return;
-    }
-
-    dispatch_assert_queue(ckks.queue);
-
     bool ok = false;
     __block CFErrorRef cferror = NULL;
     NSError* error = NULL;
     NSDictionary* queryAttributes = @{(__bridge NSString*) kSecClass: (__bridge NSString*) classP->name,
                                       (__bridge NSString*) kSecAttrUUID: iqe.uuid,
                                       (__bridge NSString*) kSecAttrSynchronizable: @(YES)};
-    ckksnotice("ckksincoming", ckks, "trying to delete with query: %@", queryAttributes);
-    Query *q = query_create_with_limit( (__bridge CFDictionaryRef) queryAttributes, NULL, kSecMatchUnlimited, &cferror);
+    ckksnotice("ckksincoming", self.deps.zoneID, "trying to delete with query: %@", queryAttributes);
+    Query *q = query_create_with_limit( (__bridge CFDictionaryRef) queryAttributes, NULL, kSecMatchUnlimited, NULL, &cferror);
+    q->q_tombstone_use_mdat_from_item = true;
 
     if(cferror) {
-        ckkserror("ckksincoming", ckks, "couldn't create query: %@", cferror);
+        ckkserror("ckksincoming", self.deps.zoneID, "couldn't create query: %@", cferror);
         SecTranslateError(&error, cferror);
         self.error = error;
         return;
 
     if(cferror) {
         if(CFErrorGetCode(cferror) == errSecItemNotFound) {
-            ckkserror("ckksincoming", ckks, "couldn't delete item (as it's already gone); this is okay: %@", cferror);
+            ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete item (as it's already gone); this is okay: %@", cferror);
             ok = true;
             CFReleaseNull(cferror);
         } else {
-            ckkserror("ckksincoming", ckks, "couldn't delete item: %@", cferror);
+            ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete item: %@", cferror);
             SecTranslateError(&error, cferror);
             self.error = error;
             query_destroy(q, NULL);
     ok = query_notify_and_destroy(q, ok, &cferror);
 
     if(cferror) {
-        ckkserror("ckksincoming", ckks, "couldn't delete query: %@", cferror);
+        ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete query: %@", cferror);
         SecTranslateError(&error, cferror);
         self.error = error;
         return;
     }
 
     if(ok) {
-        ckksnotice("ckksincoming", ckks, "Correctly processed an IQE; deleting");
+        ckksnotice("ckksincoming", self.deps.zoneID, "Correctly processed an IQE; deleting");
         [iqe deleteFromDatabase: &error];
 
         if(error) {
-            ckkserror("ckksincoming", ckks, "couldn't delete CKKSIncomingQueueEntry: %@", error);
+            ckkserror("ckksincoming", self.deps.zoneID, "couldn't delete CKKSIncomingQueueEntry: %@", error);
             self.error = error;
             self.errorItemsProcessed += 1;
         } else {
             self.successfulItemsProcessed += 1;
         }
     } else {
-        ckkserror("ckksincoming", ckks, "IQE not correctly processed, but why? %@ %@", error, cferror);
+        ckkserror("ckksincoming", self.deps.zoneID, "IQE not correctly processed, but why? %@ %@", error, cferror);
         self.error = error;
         self.errorItemsProcessed += 1;
     }
index 445d4898fba314b242261a87aff447fae7f03a4a..688d7eca1dbe436deca6850a4de6a6c010a83b46 100644 (file)
@@ -178,7 +178,17 @@ plaintextPCSServiceIdentifier: (NSNumber*) pcsServiceIdentifier
     _uuid = [[record recordID] recordName];
     self.parentKeyUUID = [record[SecCKRecordParentKeyRefKey] recordID].recordName;
     self.encitem = record[SecCKRecordDataKey];
-    self.wrappedkey = [[CKKSWrappedAESSIVKey alloc] initWithBase64: record[SecCKRecordWrappedKeyKey]];
+
+    // If wrapped key is nil, this is a bad record. We've seen this at least once, though, and so need to be resilient to it.
+    // Passing nil here will cause a crash, so pass all zeroes.
+    NSString* wrappedKey = record[SecCKRecordWrappedKeyKey];
+    if(wrappedKey) {
+        self.wrappedkey = [[CKKSWrappedAESSIVKey alloc] initWithBase64:wrappedKey];
+    } else {
+        ckkserror("ckksitem", record.recordID.zoneID, "Corrupt item recieved with no wrapped key");
+        self.wrappedkey = [CKKSWrappedAESSIVKey zeroedKey];
+    }
+
     self.generationCount = [record[SecCKRecordGenerationCountKey] unsignedIntegerValue];
     self.encver = [record[SecCKRecordEncryptionVersionKey] unsignedIntegerValue];
 
@@ -228,27 +238,27 @@ plaintextPCSServiceIdentifier: (NSNumber*) pcsServiceIdentifier
     // Note that since all of those things are included as authenticated data into the AES-SIV ciphertext, we could just
     // compare that. However, check 'em all.
     if(![record.recordID.recordName isEqualToString: self.uuid]) {
-        secinfo("ckksitem", "UUID does not match");
+        ckksinfo_global("ckksitem", "UUID does not match");
         return false;
     }
 
     if(![[record[SecCKRecordParentKeyRefKey] recordID].recordName isEqualToString: self.parentKeyUUID]) {
-        secinfo("ckksitem", "wrapping key reference does not match");
+        ckksinfo_global("ckksitem", "wrapping key reference does not match");
         return false;
     }
 
     if(![record[SecCKRecordGenerationCountKey] isEqual: [NSNumber numberWithInteger:self.generationCount]]) {
-        secinfo("ckksitem", "SecCKRecordGenerationCountKey does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordGenerationCountKey does not match");
         return false;
     }
 
     if(![record[SecCKRecordWrappedKeyKey] isEqual: [self.wrappedkey base64WrappedKey]]) {
-        secinfo("ckksitem", "SecCKRecordWrappedKeyKey does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordWrappedKeyKey does not match");
         return false;
     }
 
     if(![record[SecCKRecordDataKey] isEqual: self.encitem]) {
-        secinfo("ckksitem", "SecCKRecordDataKey does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordDataKey does not match");
         return false;
     }
 
@@ -256,19 +266,19 @@ plaintextPCSServiceIdentifier: (NSNumber*) pcsServiceIdentifier
     // Why is obj-c nullable equality so difficult?
     if(!((record[SecCKRecordPCSServiceIdentifier] == nil && self.plaintextPCSServiceIdentifier == nil) ||
           [record[SecCKRecordPCSServiceIdentifier] isEqual: self.plaintextPCSServiceIdentifier])) {
-        secinfo("ckksitem", "SecCKRecordPCSServiceIdentifier does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordPCSServiceIdentifier does not match");
         return false;
     }
 
     if(!((record[SecCKRecordPCSPublicKey] == nil && self.plaintextPCSPublicKey == nil) ||
           [record[SecCKRecordPCSPublicKey] isEqual: self.plaintextPCSPublicKey])) {
-        secinfo("ckksitem", "SecCKRecordPCSPublicKey does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordPCSPublicKey does not match");
         return false;
     }
 
     if(!((record[SecCKRecordPCSPublicIdentity] == nil && self.plaintextPCSPublicIdentity == nil) ||
           [record[SecCKRecordPCSPublicIdentity] isEqual: self.plaintextPCSPublicIdentity])) {
-        secinfo("ckksitem", "SecCKRecordPCSPublicIdentity does not match");
+        ckksinfo_global("ckksitem", "SecCKRecordPCSPublicIdentity does not match");
         return false;
     }
 
index 90810ceff193478ad2dbf36baf1faf4b19c1daec..a487b2b9c782a4310531eca91ecf04c47b2cfc52 100644 (file)
@@ -88,7 +88,7 @@
     if(olditem) {
         NSMutableDictionary* oldDictionary = [[CKKSItemEncrypter decryptItemToDictionary: olditem error:error] mutableCopy];
         if(!oldDictionary) {
-            secerror("Couldn't decrypt old CKMirror entry: %@", (error ? *error : @"null error passed in"));
+            ckkserror("ckme", olditem.zoneID, "Couldn't decrypt old CKMirror entry: %@", (error ? *error : @"null error passed in"));
             return nil;
         }
 
 
     NSDictionary* result = [self decryptDictionary: item.encitem key:itemkey authenticatedData:authenticatedData error:error];
     if(!result) {
-        secwarning("ckks: couldn't decrypt item %@", *error);
+        ckkserror("item", item.zoneID, "ckks: couldn't decrypt item %@", *error);
     }
     return result;
 }
                                                       code:1
                                                   userInfo:@{NSLocalizedDescriptionKey:
                                                                  [NSString stringWithFormat:@"Unrecognized encryption version: %lu", (unsigned long)item.encver]}];
-            secerror("decryptItemToDictionary %@", localError);
+            ckkserror("item", item.zoneID, "decryptItemToDictionary failed: %@", localError);
             if (error) {
                 *error = localError;
             }
index 766e547988d879d94b440ef88184166c8c3179b5..a651da13018c77201dda2ec2a1426bab5400807a 100644 (file)
@@ -34,6 +34,8 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+@class CKKSPeerProviderState;
+
 @interface CKKSKey : CKKSCKRecordHolder
 @property CKKSKeychainBackedKey* keycore;
 
@@ -47,6 +49,8 @@ NS_ASSUME_NONNULL_BEGIN
 @property (copy) CKKSProcessedState* state;
 @property bool currentkey;
 
+@property (readonly) NSString* zoneName;
+
 // Fetches and attempts to unwrap this key for use
 + (instancetype _Nullable)loadKeyWithUUID:(NSString*)uuid zoneID:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
 
@@ -78,7 +82,19 @@ NS_ASSUME_NONNULL_BEGIN
                                     error:(NSError* __autoreleasing*)error;
 
 
+// Returns false if this key is not a valid TLK for any reason.
+- (BOOL)validTLK:(NSError**)error;
+
+// First, attempts to load the key from the keychain. If it isn't present, this will
+// load the TLKShares for this key from the database, then attempts to use them to unwrap this key.
+// If no TLKShares are trusted, returns an error.
+- (BOOL)tlkMaterialPresentOrRecoverableViaTLKShare:(NSArray<CKKSPeerProviderState*>*)trustStates
+                                             error:(NSError**)error;
+
 + (instancetype _Nullable)fromDatabase:(NSString*)uuid zoneID:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
++ (instancetype _Nullable)fromDatabaseAnyState:(NSString*)uuid
+                                        zoneID:(CKRecordZoneID*)zoneID
+                                         error:(NSError* __autoreleasing*)error;
 + (instancetype _Nullable)tryFromDatabase:(NSString*)uuid zoneID:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
 + (instancetype _Nullable)tryFromDatabaseAnyState:(NSString*)uuid zoneID:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
 
index 4f497ee0a2cd7b977db79458946f501e537bc3ee..fe5b22c8dcf5bf5738baa527a7b888e6f984b00d 100644 (file)
@@ -27,6 +27,7 @@
 #import "CKKSKeychainView.h"
 #import "CKKSCurrentKeyPointer.h"
 #import "CKKSKey.h"
+#import "keychain/ckks/CKKSPeerProvider.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #include "keychain/securityd/SecItemSchema.h"
 #include <Security/SecItem.h>
@@ -41,7 +42,8 @@
 @implementation CKKSKey
 
 - (instancetype)init {
-    self = [super init];
+    if ((self = [super init])) {
+    }
     return self;
 }
 
     return self.keycore.uuid;
 }
 
+- (NSString*)zoneName
+{
+    return self.keycore.zoneID.zoneName;
+}
+
 - (void)setUuid:(NSString *)uuid
 {
     self.keycore.uuid = uuid;
 
         // Check for circular references.
         if([seenUUID containsObject:key.uuid]) {
-            *error = [NSError errorWithDomain:CKKSErrorDomain
-                                         code:CKKSCircularKeyReference
-                                  description:@"Circular reference in key hierarchy"];
+            if (error) {
+                *error = [NSError errorWithDomain:CKKSErrorDomain
+                                             code:CKKSCircularKeyReference
+                                      description:@"Circular reference in key hierarchy"];
+            }
             return nil;
         }
 
         // Attempt to save this new key, but don't error if it fails
         NSError* resaveError = nil;
         if(![self saveKeyMaterialToKeychain:&resaveError] || resaveError) {
-            secerror("ckkskey: Resaving missing key failed, continuing: %@", resaveError);
+            ckkserror("ckkskey", self.zoneID, "Resaving missing key failed, continuing: %@", resaveError);
         }
 
         return self.aessivkey;
     return self.aessivkey;
 }
 
+- (BOOL)unwrapViaTLKSharesTrustedBy:(NSArray<CKKSPeerProviderState*>*)trustStates
+                              error:(NSError**)error
+{
+    NSError* localerror = nil;
+
+    if(trustStates.count == 0u) {
+        if(error) {
+            *error = [NSError errorWithDomain:CKKSErrorDomain
+                                         code:CKKSLackingTrust
+                                  description:@"No current trust states; can't unwrap TLK"];
+        }
+        return NO;
+    }
+
+    NSArray<CKKSTLKShareRecord*>* possibleShares = [CKKSTLKShareRecord allForUUID:self.uuid
+                                                                           zoneID:self.zoneID
+                                                                            error:&localerror];
+
+    if(!possibleShares || localerror) {
+        ckkserror("ckksshare", self, "Unable to load TLK shares for TLK(%@): %@", self, localerror);
+        if(error) {
+            *error = localerror;
+        }
+        return NO;
+    }
+
+    NSError* lastTrustStateError = nil;
+    for(CKKSPeerProviderState* trustState in trustStates) {
+        BOOL extracted = [trustState unwrapKey:self
+                                    fromShares:possibleShares
+                                         error:&localerror];
+
+        if(!extracted || localerror) {
+            ckkserror("ckksshare", self, "Failed to recover tlk (%@) from trust state (%@): %@", self.uuid, trustState, localerror);
+            lastTrustStateError = localerror;
+            localerror = nil;
+        } else {
+            ckkserror("ckksshare", self, "Recovered tlk (%@) from trust state (%@)", self.uuid, trustState);
+            return YES;
+        }
+    }
+
+    // Because there's at least one trustState, then either we returned the TLK above, or we filled in lastTrustStateError.
+    if(error) {
+        *error = lastTrustStateError;
+    }
+
+    return NO;
+}
+
+- (BOOL)validTLK:(NSError**)error
+{
+    if(![self wrapsSelf]) {
+        NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain
+                                                  code:CKKSKeyNotSelfWrapped
+                                           description:[NSString stringWithFormat:@"Potential TLK %@ doesn't wrap itself: %@",
+                                                        self,
+                                                        self.parentKeyUUID]
+                                            underlying:NULL];
+        ckkserror("ckksshare", self, "Error with TLK: %@", localerror);
+        if (error) {
+            *error = localerror;
+        }
+        return NO;
+    }
+
+    return YES;
+}
+
+- (BOOL)tlkMaterialPresentOrRecoverableViaTLKShare:(NSArray<CKKSPeerProviderState*>*)trustStates
+                                             error:(NSError**)error
+{
+    // If we have the key material, then this TLK is considered valid.
+    NSError* loadError = nil;
+    CKKSAESSIVKey* loadedKey = [self ensureKeyLoaded:&loadError];
+    if(!loadedKey || loadError) {
+        if(loadError.code == errSecInteractionNotAllowed) {
+            ckkserror("ckksshare", self, "Unable to load key due to lock state: %@", loadError);
+            if(error) {
+                *error = loadError;
+            }
+
+            return NO;
+        }
+
+        ckkserror("ckksshare", self, "Do not yet have this key in the keychain: %@", loadError);
+        // Fall through to attempt to recover the TLK via shares below
+    } else {
+        bool result = [self trySelfWrappedKeyCandidate:loadedKey error:&loadError];
+        if(result) {
+            // We have a key, and it can decrypt itself.
+            return YES;
+        } else {
+            ckkserror("ckksshare", self, "Some key is present, but the key is not self-wrapped: %@", loadError);
+            // Key seems broken. Fall through.
+        }
+    }
+
+    NSError* localerror = nil;
+    BOOL success = [self unwrapViaTLKSharesTrustedBy:trustStates
+                                               error:&localerror];
+
+    if(!success || localerror) {
+        ckkserror("ckksshare", self, "Failed to unwrap tlk(%@) via shares: %@", self.uuid, localerror);
+        if(error) {
+            *error = localerror;
+        }
+        return NO;
+    }
+
+    success = [self saveKeyMaterialToKeychain:true error:&localerror];
+
+    if(!success || localerror) {
+        ckkserror("ckksshare", self, "Errored saving TLK to keychain: %@", localerror);
+
+        if(error) {
+            *error = localerror;
+            return NO;
+        }
+    }
+
+    return YES;
+}
+
 - (bool)trySelfWrappedKeyCandidate:(CKKSAESSIVKey*)candidate error:(NSError * __autoreleasing *) error {
     return [self.keycore trySelfWrappedKeyCandidate:candidate error:error];
 }
     }
 
     if(![record.recordID.recordName isEqualToString: self.uuid]) {
-        secinfo("ckkskey", "UUID does not match");
+        ckksinfo_global("ckkskey", "UUID does not match");
         return false;
     }
 
     // For the parent key ref, ensure that if it's nil, we wrap ourself
     if(record[SecCKRecordParentKeyRefKey] == nil) {
         if(![self wrapsSelf]) {
-            secinfo("ckkskey", "wrapping key reference (self-wrapped) does not match");
+            ckksinfo_global("ckkskey", "wrapping key reference (self-wrapped) does not match");
             return false;
         }
 
     } else {
         if(![[[record[SecCKRecordParentKeyRefKey] recordID] recordName] isEqualToString: self.parentKeyUUID]) {
-            secinfo("ckkskey", "wrapping key reference (non-self-wrapped) does not match");
+            ckksinfo_global("ckkskey", "wrapping key reference (non-self-wrapped) does not match");
             return false;
         }
     }
 
     if(![record[SecCKRecordKeyClassKey] isEqual: self.keyclass]) {
-        secinfo("ckkskey", "key class does not match");
+        ckksinfo_global("ckkskey", "key class does not match");
         return false;
     }
 
     if(![record[SecCKRecordWrappedKeyKey] isEqual: [self.wrappedkey base64WrappedKey]]) {
-        secinfo("ckkskey", "wrapped key does not match");
+        ckksinfo_global("ckkskey", "wrapped key does not match");
         return false;
     }
 
index 8552ee420f3cf64c9aa021ef2b9b9fb203cf6287..eca829c69628c2704cb1f0599384561e8be26240 100644 (file)
@@ -31,7 +31,7 @@
         NSError* error = nil;
         [self wrapUnder:self error:&error];
         if(error != nil) {
-            secerror("CKKSKeychainBackedKey: Couldn't self-wrap key: %@", error);
+            ckkserror_global("ckkskey", "Couldn't self-wrap key: %@", error);
             return nil;
         }
     }
@@ -55,7 +55,7 @@
         NSError* error = nil;
         [self wrapUnder:wrappingKey error:&error];
         if(error != nil) {
-            secerror("CKKSKeychainBackedKey: Couldn't wrap key with key: %@", error);
+            ckkserror_global("ckkskey", "Couldn't wrap key with key: %@", error);
             return nil;
         }
     }
             error:(NSError* __autoreleasing*)error
 {
     NSError* localError = nil;
-    self.wrappedkey = [wrappingKey wrapAESKey:self.aessivkey error:&localError];
-    if(self.wrappedkey == nil) {
-        secerror("CKKSKeychainBackedKey: couldn't wrap key: %@", localError);
+    CKKSWrappedAESSIVKey* wrappedKey = [wrappingKey wrapAESKey:self.aessivkey error:&localError];
+    if (wrappedKey == nil) {
+        ckkserror_global("ckkskey", "couldn't wrap key: %@", localError);
         if(error) {
             *error = localError;
         }
+        return false;
     } else {
+        self.wrappedkey = wrappedKey;
         self.parentKeyUUID = wrappingKey.uuid;
     }
-    return (self.wrappedkey != nil);
+    return true;
 }
 
 - (bool)unwrapSelfWithAESKey:(CKKSAESSIVKey*)unwrappingKey
         [CKKSKeychainBackedKey setKeyMaterialInKeychain:query error:&localError];
 
         if(stashError) {
-            secerror("CKKSKeychainBackedKey: Couldn't stash %@ to keychain: %@", self, stashError);
+            ckkserror_global("ckkskey", "Couldn't stash %@ to keychain: %@", self, stashError);
         }
     }
 
 
         result = [self queryKeyMaterialInKeychain:query error:&localError];
         if(localError == nil) {
-            secnotice("CKKSKeychainBackedKey", "loaded a piggy TLK (%@)", key.uuid);
+            ckksnotice_global("ckkskey", "loaded a piggy TLK (%@)", key.uuid);
 
             if(resavePtr) {
                 *resavePtr = true;
 
         result = [self queryKeyMaterialInKeychain:query error:&localError];
         if(localError == nil) {
-            secnotice("CKKSKeychainBackedKey", "loaded a stashed TLK (%@)", key.uuid);
+            ckksnotice_global("ckkskey", "loaded a stashed TLK (%@)", key.uuid);
 
             if(resavePtr) {
                 *resavePtr = true;
     NSMutableData* keymaterial =
         [[NSMutableData alloc] initWithBase64EncodedData:b64keymaterial options:0];
     if(!keymaterial) {
-        secnotice("CKKSKeychainBackedKey", "Unable to unbase64 key: %@", self);
+        ckkserror_global("ckkskey",  "Unable to unbase64 key: %@", self);
         if(error) {
             *error = [NSError
                 errorWithDomain:CKKSErrorDomain
     self.aessivkey = key;
 
     if(resave) {
-        secnotice("CKKSKeychainBackedKey", "Resaving %@ as per request", self);
+        ckksnotice_global("ckkskey", "Resaving %@ as per request", self);
         NSError* resaveError = nil;
         [self saveKeyMaterialToKeychain:&resaveError];
         if(resaveError) {
-            secnotice("CKKSKeychainBackedKey", "Resaving %@ failed: %@", self, resaveError);
+            ckksnotice_global("ckkskey", "Resaving %@ failed: %@", self, resaveError);
         }
     }
 
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder*)decoder
 {
-    self = [super init];
-    if(self) {
+    if ((self = [super init])) {
         _uuid = [decoder decodeObjectOfClass:[NSString class] forKey:@"uuid"];
         _parentKeyUUID =
             [decoder decodeObjectOfClass:[NSString class] forKey:@"parentKeyUUID"];
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder*)decoder
 {
-    self = [super init];
-    if(self) {
+    if ((self = [super init])) {
         _tlk = [decoder decodeObjectOfClass:[CKKSKeychainBackedKey class] forKey:@"tlk"];
         _classA = [decoder decodeObjectOfClass:[CKKSKeychainBackedKey class] forKey:@"classA"];
         _classC = [decoder decodeObjectOfClass:[CKKSKeychainBackedKey class] forKey:@"classC"];
index 5e090e1bb228091d967d13dd2dacfcab75f5a676..7ed70543d749954c3d289661788288d04648be39 100644 (file)
@@ -31,6 +31,9 @@
 #import "keychain/ckks/CKKSReachabilityTracker.h"
 #import "keychain/ckks/CloudKitDependencies.h"
 
+#import "keychain/ot/OctagonFlags.h"
+#import "keychain/ot/OctagonStateMachine.h"
+
 #include "keychain/securityd/SecDbItem.h"
 #include <utilities/SecDb.h>
 
 #import "keychain/ckks/CKKSScanLocalItemsOperation.h"
 #import "keychain/ckks/CKKSTLKShareRecord.h"
 #import "keychain/ckks/CKKSUpdateDeviceStateOperation.h"
-#import "keychain/ckks/CKKSZone.h"
 #import "keychain/ckks/CKKSZoneModifier.h"
 #import "keychain/ckks/CKKSZoneChangeFetcher.h"
 #import "keychain/ckks/CKKSSynchronizeOperation.h"
 #import "keychain/ckks/CKKSLocalSynchronizeOperation.h"
 #import "keychain/ckks/CKKSProvideKeySetOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/trust/TrustedPeers/TPSyncingPolicy.h"
 
 #include "CKKS.h"
 
@@ -64,34 +68,41 @@ NS_ASSUME_NONNULL_BEGIN
 @class CKKSAESSIVKey;
 @class CKKSSynchronizeOperation;
 @class CKKSRateLimiter;
-@class CKKSManifest;
-@class CKKSEgoManifest;
 @class CKKSOutgoingQueueEntry;
 @class CKKSZoneChangeFetcher;
 @class CKKSCurrentKeySet;
 
-@interface CKKSKeychainView : CKKSZone <CKKSZoneUpdateReceiver,
+@interface CKKSKeychainView : NSObject <CKKSCloudKitAccountStateListener,
                                         CKKSChangeFetcherClient,
-                                        CKKSPeerUpdateListener>
-{
-    CKKSZoneKeyState* _keyHierarchyState;
-}
+                                        CKKSPeerUpdateListener,
+                                        CKKSDatabaseProviderProtocol,
+                                        OctagonStateMachineEngine>
+
+@property (readonly) NSString* zoneName;
+@property CKKSAccountStatus accountStatus;
+@property (readonly) CKContainer* container;
+@property (readonly) CKDatabase* database;
+@property (weak) CKKSAccountStateTracker* accountTracker;
+@property (weak) CKKSReachabilityTracker* reachabilityTracker;
+@property (readonly) CKKSCloudKitClassDependencies* cloudKitClassDependencies;
+@property (readonly) dispatch_queue_t queue;
+
+@property (readonly) CKRecordZoneID* zoneID;
 
 @property CKKSCondition* loggedIn;
 @property CKKSCondition* loggedOut;
 @property CKKSCondition* accountStateKnown;
 
 @property CKKSAccountStatus trustStatus;
-@property (nullable) CKKSResultOperation* trustDependency;
 
 @property (nullable) CKKSLaunchSequence *launch;
 
 @property CKKSLockStateTracker* lockStateTracker;
 
-@property CKKSZoneKeyState* keyHierarchyState;
-@property (nullable) NSError* keyHierarchyError;
-@property (nullable) CKOperationGroup* keyHierarchyOperationGroup;
-@property (nullable) NSOperation* keyStateMachineOperation;
+// Is this view currently syncing keychain modifications?
+@property (readonly) BOOL itemSyncingEnabled;
+
+@property (readonly) OctagonStateMachine* stateMachine;
 
 // 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.
@@ -100,27 +111,15 @@ NS_ASSUME_NONNULL_BEGIN
 // 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;
 
-// Wait for the key state to become 'nontransient': no pending operation is expected to advance it (at least until intervention)
-@property (nullable) CKKSResultOperation* keyStateNonTransientDependency;
-
-// True if we believe there's any items in the keychain which haven't been brought up in CKKS yet
-@property bool droppedItems;
-
-@property (readonly) NSString* lastActiveTLKUUID;
-
 // Full of condition variables, if you'd like to try to wait until the key hierarchy is in some state
-@property NSMutableDictionary<CKKSZoneKeyState*, CKKSCondition*>* keyHierarchyConditions;
+@property (readonly) NSDictionary<CKKSZoneKeyState*, CKKSCondition*>* keyHierarchyConditions;
 
 @property CKKSZoneChangeFetcher* zoneChangeFetcher;
 
-@property (weak) CKKSNearFutureScheduler* savedTLKNotifier;
-
 @property (nullable) CKKSNearFutureScheduler* suggestTLKUpload;
-
+@property (nullable) CKKSNearFutureScheduler* requestPolicyCheck;
 
 /* Used for debugging: just what happened last time we ran this? */
 @property CKKSIncomingQueueOperation* lastIncomingQueueOperation;
@@ -128,7 +127,6 @@ NS_ASSUME_NONNULL_BEGIN
 @property CKKSOutgoingQueueOperation* lastOutgoingQueueOperation;
 @property CKKSProcessReceivedKeysOperation* lastProcessReceivedKeysOperation;
 @property CKKSReencryptOutgoingItemsOperation* lastReencryptOutgoingItemsOperation;
-@property CKKSScanLocalItemsOperation* lastScanLocalItemsOperation;
 @property CKKSSynchronizeOperation* lastSynchronizeOperation;
 @property CKKSResultOperation* lastFixupOperation;
 
@@ -139,23 +137,16 @@ NS_ASSUME_NONNULL_BEGIN
 @property NSOperation* holdLocalSynchronizeOperation;
 @property CKKSResultOperation* holdFixupOperation;
 
+/* Used for testing */
+@property BOOL initiatedLocalScan;
+
 /* Trigger this to tell the whole machine that this view has changed */
 @property CKKSNearFutureScheduler* notifyViewChangedScheduler;
 
 /* Trigger this to tell the whole machine that this view is more ready then before */
 @property CKKSNearFutureScheduler* notifyViewReadyScheduler;
 
-/* trigger this to request key state machine poking */
-@property CKKSNearFutureScheduler* pokeKeyStateMachineScheduler;
-
-// The current list of peer providers. If empty, CKKS will consider itself untrusted, and halt operation
-@property (readonly) NSArray<id<CKKSPeerProvider>>* currentPeerProviders;
-
-// These are available when you're in a dispatchSyncWithAccountKeys call, but at no other time
-// These must be pre-fetched before you get on the CKKS queue, otherwise we end up with CKKS<->SQLite<->SOSAccountQueue deadlocks
-
-// They will be in a parallel array with currentPeerProviders above
-@property (readonly) NSArray<CKKSPeerProviderState*>* currentTrustStates;
+@property (readonly) CKKSOperationDependencies* operationDependencies;
 
 - (instancetype)initWithContainer:(CKContainer*)container
                          zoneName:(NSString*)zoneName
@@ -168,10 +159,29 @@ NS_ASSUME_NONNULL_BEGIN
         cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies;
 
 /* Trust state management */
+
+// suggestTLKUpload and requestPolicyCheck are essentially callbacks to request certain procedures from the view owner.
+// When suggestTLKUpload is triggered, the CKKS view believes it has some new TLKs that need uploading, and Octagon should take care of them.
+// When requestPolicyCheck is triggered, the CKKS view would like Octagon to perform a live check on which syncing policy is in effect,
+//  successfully retrieving all peer's opinions, and would like -setCurrentSyncingPolicy to be called with the updated policy (even if it is
+//  unchanged.)
 - (void)beginTrustedOperation:(NSArray<id<CKKSPeerProvider>>*)peerProviders
-             suggestTLKUpload:(CKKSNearFutureScheduler*)suggestTLKUpload;
+             suggestTLKUpload:(CKKSNearFutureScheduler*)suggestTLKUpload
+           requestPolicyCheck:(CKKSNearFutureScheduler*)requestPolicyCheck;
+
 - (void)endTrustedOperation;
 
+/* CloudKit account management */
+
+- (void)beginCloudKitOperation;
+
+// If this policy indicates that this view should not sync, this view will no longer sync keychain items,
+// but it will continue to particpate in TLK sharing.
+// If policyIsFresh is set, any items discovered that do not match this policy will be moved.
+- (void)setCurrentSyncingPolicy:(TPSyncingPolicy*)syncingPolicy policyIsFresh:(BOOL)policyIsFresh;
+
+- (void)receivedItemForWrongView;
+
 /* Synchronous operations */
 
 - (void)handleKeychainEventDbConnection:(SecDbConnectionRef)dbconn
@@ -195,27 +205,23 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (bool)outgoingQueueEmpty:(NSError* __autoreleasing*)error;
 
-- (CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*)findKeySet;
+- (CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*)findKeySet:(BOOL)refetchBeforeReturningKeySet;
 - (void)receiveTLKUploadRecords:(NSArray<CKRecord*>*)records;
 
-- (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing;
+// Returns true if this zone would like a new TLK to be uploaded
+- (BOOL)requiresTLKUpload;
+
 - (void)waitForKeyHierarchyReadiness;
 - (void)cancelAllOperations;
 
-- (CKKSKey* _Nullable)keyForItem:(SecDbItemRef)item error:(NSError* __autoreleasing*)error;
-
-- (bool)_onqueueWithAccountKeysCheckTLK:(CKKSKey*)proposedTLK error:(NSError* __autoreleasing*)error;
-
-- (BOOL)otherDevicesReportHavingTLKs:(CKKSCurrentKeySet*)keyset;
-
 /* Asynchronous kickoffs */
 
 - (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup* _Nullable)ckoperationGroup;
 - (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation* _Nullable)after
                                         ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup;
-- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after
+- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation* _Nullable)after
                                            requiredDelay:(uint64_t)requiredDelay
-                                        ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
+                                        ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup;
 
 - (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA;
 - (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA after:(CKKSResultOperation* _Nullable)after;
@@ -237,8 +243,6 @@ NS_ASSUME_NONNULL_BEGIN
 - (CKKSSynchronizeOperation*)resyncWithCloud;
 - (CKKSLocalSynchronizeOperation*)resyncLocal;
 
-- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because;
-
 - (CKKSResultOperation*)resetLocalData;
 - (CKKSResultOperation*)resetCloudKitZone:(CKOperationGroup*)operationGroup;
 
@@ -248,20 +252,11 @@ NS_ASSUME_NONNULL_BEGIN
 // For our serial queue to work with how handleKeychainEventDbConnection is called from the main thread,
 // every block on our queue must have a SecDBConnectionRef available to it before it begins on the queue.
 // Use these helper methods to make sure those exist.
-- (void)dispatchSync:(bool (^)(void))block;
-- (void)dispatchSyncWithAccountKeys:(bool (^)(void))block;
+- (void)dispatchSyncWithSQLTransaction:(CKKSDatabaseTransactionResult (^)(void))block;
+- (void)dispatchSyncWithReadOnlySQLTransaction:(void (^)(void))block;
 
 /* Synchronous operations which must be called from inside a dispatchAsyncWithAccountKeys or dispatchSync block */
 
-// Call this to request the key hierarchy state machine to fetch new updates
-- (void)_onqueueKeyStateMachineRequestFetch;
-
-// Call this to request the key hierarchy state machine to reprocess
-- (void)_onqueueKeyStateMachineRequestProcess;
-
-// Call this from a key hierarchy operation to move the state machine, and record the results of the last move.
-- (void)_onqueueAdvanceKeyStateMachineToState:(CKKSZoneKeyState* _Nullable)state withError:(NSError* _Nullable)error;
-
 // Since we might have people interested in the state transitions of objects, please do those transitions via these methods
 - (bool)_onqueueChangeOutgoingQueueEntry:(CKKSOutgoingQueueEntry*)oqe
                                  toState:(NSString*)state
@@ -279,24 +274,6 @@ NS_ASSUME_NONNULL_BEGIN
 - (bool)_onqueueCKRecordChanged:(CKRecord*)record resync:(bool)resync;
 - (bool)_onqueueCKRecordDeleted:(CKRecordID*)recordID recordType:(NSString*)recordType resync:(bool)resync;
 
-// For this key, who doesn't yet have a CKKSTLKShare for it, shared to their current Octagon keys?
-// Note that we really want a record sharing the TLK to ourselves, so this function might return
-// a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
-// If you pass in a non-empty set in afterUploading, those records will be included in the calculation.
-- (NSSet<id<CKKSPeer>>*)_onqueueFindPeers:(CKKSPeerProviderState*)trustState
-                             missingShare:(CKKSKey*)key
-                           afterUploading:(NSSet<CKKSTLKShareRecord*>* _Nullable)newShares
-                                    error:(NSError* __autoreleasing*)error;
-
-- (BOOL)_onqueueAreNewSharesSufficient:(NSSet<CKKSTLKShareRecord*>*)newShares
-                            currentTLK:(CKKSKey*)key
-                                 error:(NSError* __autoreleasing*)error;
-
-// For this key, share it to all trusted peers who don't have it yet
-- (NSSet<CKKSTLKShareRecord*>* _Nullable)_onqueueCreateMissingKeyShares:(CKKSKey*)key error:(NSError* __autoreleasing*)error;
-
-- (bool)_onqueueUpdateLatestManifestWithError:(NSError**)error;
-
 - (CKKSDeviceStateEntry* _Nullable)_onqueueCurrentDeviceStateEntry:(NSError* __autoreleasing*)error;
 
 // Please don't use these unless you're an Operation in this package
@@ -304,11 +281,34 @@ NS_ASSUME_NONNULL_BEGIN
 @property NSHashTable<CKKSOutgoingQueueOperation*>* outgoingQueueOperations;
 
 @property NSHashTable<CKKSScanLocalItemsOperation*>* scanLocalItemsOperations;
-@property CKKSScanLocalItemsOperation* initialScanOperation;
 
 // Returns the current state of this view, fastStatus is the same, but as name promise, no expensive calculations
 - (NSDictionary<NSString*, NSString*>*)status;
 - (NSDictionary<NSString*, NSString*>*)fastStatus;
+
+- (void)xpc24HrNotification;
+
+// NSOperation Helpers
+- (void)scheduleOperation:(NSOperation*)op;
+@end
+
+@interface CKKSKeychainView (Testing)
+
+// Call this to just nudge the state machine (without a request)
+// This is used internally, but you should only call it if you're a test.
+- (void)_onqueuePokeKeyStateMachine;
+
+/* NSOperation helpers */
+- (void)cancelAllOperations;
+- (void)waitUntilAllOperationsAreFinished;
+- (void)waitForOperationsOfClass:(Class)operationClass;
+
+- (void)waitForFetchAndIncomingQueueProcessing;
+
+- (void)halt;
+
+- (void)handleCKLogout;
+
 @end
 
 NS_ASSUME_NONNULL_END
index 6a9589a1e874d811af28bbfb5cab45d6d6129fd6..16be35cfdde300867fa79e2bc002d1ee69ebac52 100644 (file)
@@ -32,6 +32,7 @@
 #endif
 
 #import "CKKS.h"
+#import "keychain/ckks/CKKSStates.h"
 #import "OctagonAPSReceiver.h"
 #import "CKKSIncomingQueueEntry.h"
 #import "CKKSOutgoingQueueEntry.h"
@@ -43,9 +44,8 @@
 #import "CKKSIncomingQueueOperation.h"
 #import "CKKSNewTLKOperation.h"
 #import "CKKSProcessReceivedKeysOperation.h"
-#import "CKKSZone.h"
 #import "CKKSFetchAllRecordZoneChangesOperation.h"
-#import "CKKSHealKeyHierarchyOperation.h"
+#import "keychain/ckks/CKKSHealKeyHierarchyOperation.h"
 #import "CKKSReencryptOutgoingItemsOperation.h"
 #import "CKKSScanLocalItemsOperation.h"
 #import "CKKSSynchronizeOperation.h"
@@ -59,6 +59,8 @@
 #import "keychain/ckks/CKKSDeviceStateEntry.h"
 #import "keychain/ckks/CKKSNearFutureScheduler.h"
 #import "keychain/ckks/CKKSCurrentItemPointer.h"
+#import "keychain/ckks/CKKSCreateCKZoneOperation.h"
+#import "keychain/ckks/CKKSDeleteCKZoneOperation.h"
 #import "keychain/ckks/CKKSUpdateCurrentItemPointerOperation.h"
 #import "keychain/ckks/CKKSUpdateDeviceStateOperation.h"
 #import "keychain/ckks/CKKSNotifier.h"
 #import "keychain/ckks/CKKSHealTLKSharesOperation.h"
 #import "keychain/ckks/CKKSLocalSynchronizeOperation.h"
 #import "keychain/ckks/CKKSPeerProvider.h"
+#import "keychain/ckks/CKKSCheckKeyHierarchyOperation.h"
+#import "keychain/ckks/CKKSViewManager.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 
+#import "keychain/ckks/CKKSLocalResetOperation.h"
+
 #import "keychain/ot/OTConstants.h"
 #import "keychain/ot/OTDefines.h"
 #import "keychain/ot/OctagonCKKSPeerAdapter.h"
 #include "keychain/securityd/SecItemDb.h"
 #include "keychain/securityd/SecItemSchema.h"
 #include "keychain/securityd/SecItemServer.h"
-#include <utilities/debugging.h>
 #include <Security/SecItemPriv.h>
 #include "keychain/SecureObjectSync/SOSAccountTransaction.h"
-#include <utilities/SecADWrapper.h>
 #include <utilities/SecPLWrappers.h>
 #include <os/transaction_private.h>
 
+#import "keychain/trust/TrustedPeers/TPSyncingPolicy.h"
+#import <Security/SecItemInternal.h>
+
 #if OCTAGON
 
 @interface CKKSKeychainView()
-@property bool keyStateFetchRequested;
-@property bool keyStateProcessRequested;
-@property bool trustedPeersSetChanged;
-
-@property bool keyStateCloudKitDeleteRequested;
-@property NSHashTable<CKKSResultOperation*>* cloudkitDeleteZoneOperations;
-
-@property bool keyStateLocalResetRequested;
-@property NSHashTable<CKKSResultOperation*>* localResetOperations;
-
-@property bool tlkCreationRequested;
-@property NSHashTable<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* keysetProviderOperations;
-
-
-@property (atomic) NSString *activeTLK;
 
 @property (readonly) Class<CKKSNotifier> notifierClass;
 
 // Scratch space for resyncs
 @property (nullable) NSMutableSet<NSString*>* resyncRecordsSeen;
 
+
+
+@property NSOperationQueue* operationQueue;
+@property CKKSResultOperation* accountLoggedInDependency;
+@property BOOL halted;
+
 // Make these readwrite
-@property NSArray<id<CKKSPeerProvider>>* currentPeerProviders;
 @property NSArray<CKKSPeerProviderState*>* currentTrustStates;
 
+@property NSMutableSet<CKKSFetchBecause*>* currentFetchReasons;
 @end
 #endif
 
         cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies
 {
 
-    if(self = [super initWithContainer:container
-                              zoneName:zoneName
-                        accountTracker:accountTracker
-                   reachabilityTracker:reachabilityTracker
-                          zoneModifier:zoneModifier
-             cloudKitClassDependencies:cloudKitClassDependencies]) {
+    if((self = [super init])) {
         WEAKIFY(self);
 
+        _container = container;
+        _zoneName = zoneName;
+        _accountTracker = accountTracker;
+        _reachabilityTracker = reachabilityTracker;
+        _cloudKitClassDependencies = cloudKitClassDependencies;
+
+        _halted = NO;
+
+        _database = [_container privateCloudDatabase];
+        _zoneID = [[CKRecordZoneID alloc] initWithZoneName:zoneName ownerName:CKCurrentUserDefaultName];
+
+        _accountStatus = CKKSAccountStatusUnknown;
+        _accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in."];
+
+        _queue = dispatch_queue_create([[NSString stringWithFormat:@"CKKSQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+        _operationQueue = [[NSOperationQueue alloc] init];
+
+
         _loggedIn = [[CKKSCondition alloc] init];
         _loggedOut = [[CKKSCondition alloc] init];
         _accountStateKnown = [[CKKSCondition alloc] init];
 
+        _initiatedLocalScan = NO;
+
         _trustStatus = CKKSAccountStatusUnknown;
-        _trustDependency = [CKKSResultOperation named:@"wait-for-trust" withBlock:^{}];
 
         _incomingQueueOperations = [NSHashTable weakObjectsHashTable];
         _outgoingQueueOperations = [NSHashTable weakObjectsHashTable];
         _scanLocalItemsOperations = [NSHashTable weakObjectsHashTable];
-        _cloudkitDeleteZoneOperations = [NSHashTable weakObjectsHashTable];
-        _localResetOperations = [NSHashTable weakObjectsHashTable];
-        _keysetProviderOperations = [NSHashTable weakObjectsHashTable];
 
-        _currentPeerProviders = @[];
         _currentTrustStates = @[];
 
+        _currentFetchReasons = [NSMutableSet set];
+
         _launch = [[CKKSLaunchSequence alloc] initWithRocketName:@"com.apple.security.ckks.launch"];
         [_launch addAttribute:@"view" value:zoneName];
 
                                                                    block:^{
                                                                        STRONGIFY(self);
                                                                        [self.notifierClass post:[NSString stringWithFormat:@"com.apple.security.view-change.%@", self.zoneName]];
+                                                                       [self.notifierClass post:[NSString stringWithUTF8String:kSecServerKeychainChangedNotification]];
+
 
                                                                        // Ugly, but: the Manatee and Engram views need to send a fake 'PCS' view change.
                                                                        // TODO: make this data-driven somehow
 
 
         _lockStateTracker = lockStateTracker;
-        _savedTLKNotifier = savedTLKNotifier;
-
-        _keyHierarchyConditions = [[NSMutableDictionary alloc] init];
-        [CKKSZoneKeyStateMap() enumerateKeysAndObjectsUsingBlock:^(CKKSZoneKeyState * _Nonnull key, NSNumber * _Nonnull obj, BOOL * _Nonnull stop) {
-            [self.keyHierarchyConditions setObject: [[CKKSCondition alloc] init] forKey:key];
-        }];
-
-        // Use the keyHierarchyState setter to modify the zone key state map
-        self.keyHierarchyState = SecCKKSZoneKeyStateLoggedOut;
 
-        _keyHierarchyError = nil;
-        _keyHierarchyOperationGroup = nil;
-        _keyStateMachineOperation = nil;
-        _keyStateFetchRequested = false;
-        _keyStateProcessRequested = false;
-        _tlkCreationRequested = false;
+        _stateMachine = [[OctagonStateMachine alloc] initWithName:[NSString stringWithFormat:@"ckks-%@", self.zoneName]
+                                                           states:[NSSet setWithArray:[CKKSZoneKeyStateMap() allKeys]]
+                                                            flags:CKKSAllStateFlags()
+                                                     initialState:SecCKKSZoneKeyStateWaitForCloudKitAccountStatus
+                                                            queue:self.queue
+                                                      stateEngine:self
+                                                 lockStateTracker:lockStateTracker];
+        [_stateMachine startOperation];
 
         _waitingQueue = [[NSOperationQueue alloc] init];
         _waitingQueue.maxConcurrentOperationCount = 5;
 
-        _keyStateReadyDependency = [self createKeyStateReadyDependency: @"Key state has become ready for the first time." ckoperationGroup:[CKOperationGroup CKKSGroupWithName:@"initial-key-state-ready-scan"]];
-
-        _keyStateNonTransientDependency = [self createKeyStateNontransientDependency];
+        _keyStateReadyDependency = [self createKeyStateReadyDependency: @"Key state has become ready for the first time."];
 
         dispatch_time_t initialOutgoingQueueDelay = SecCKKSReduceRateLimiting() ? NSEC_PER_MSEC * 200 : NSEC_PER_SEC * 1;
         dispatch_time_t continuingOutgoingQueueDelay = SecCKKSReduceRateLimiting() ? NSEC_PER_MSEC * 200 : NSEC_PER_SEC * 30;
                                                                dependencyDescriptionCode:CKKSResultDescriptionPendingOutgoingQueueScheduling
                                                                                    block:^{}];
 
-
-        dispatch_time_t initialKeyHierachyPokeDelay = SecCKKSReduceRateLimiting() ? NSEC_PER_MSEC * 100 : NSEC_PER_MSEC * 500;
-        dispatch_time_t continuingKeyHierachyPokeDelay = SecCKKSReduceRateLimiting() ? NSEC_PER_MSEC * 200 : NSEC_PER_SEC * 5;
-        _pokeKeyStateMachineScheduler = [[CKKSNearFutureScheduler alloc] initWithName:[NSString stringWithFormat: @"%@-reprocess-scheduler", self.zoneName]
-                                                                         initialDelay:initialKeyHierachyPokeDelay
-                                                                      continuingDelay:continuingKeyHierachyPokeDelay
-                                                                     keepProcessAlive:true
-                                                            dependencyDescriptionCode:CKKSResultDescriptionPendingKeyHierachyPokeScheduling
-                                                                                     block:^{
-                                                                                         STRONGIFY(self);
-                                                                                         [self dispatchSyncWithAccountKeys: ^bool{
-                                                                                             STRONGIFY(self);
-
-                                                                                             [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-                                                                                             return true;
-                                                                                         }];
-                                                                                     }];
+        _operationDependencies = [[CKKSOperationDependencies alloc] initWithZoneID:self.zoneID
+                                                                      zoneModifier:zoneModifier
+                                                                  ckoperationGroup:nil
+                                                                       flagHandler:_stateMachine
+                                                                    launchSequence:_launch
+                                                                  lockStateTracker:_lockStateTracker
+                                                               reachabilityTracker:reachabilityTracker
+                                                                     peerProviders:@[]
+                                                                  databaseProvider:self
+                                                        notifyViewChangedScheduler:_notifyViewChangedScheduler
+                                                                  savedTLKNotifier:savedTLKNotifier];
     }
     return self;
 }
 }
 
 - (CKKSZoneKeyState*)keyHierarchyState {
-    return _keyHierarchyState;
-}
-
-- (void)setKeyHierarchyState:(CKKSZoneKeyState *)keyHierarchyState {
-    if((keyHierarchyState == nil && _keyHierarchyState == nil) || ([keyHierarchyState isEqualToString:_keyHierarchyState])) {
-        // No change, do nothing.
-    } else {
-        // Fixup the condition variables as part of setting this state
-        if(_keyHierarchyState) {
-            self.keyHierarchyConditions[_keyHierarchyState] = [[CKKSCondition alloc] init];
-        }
-
-        _keyHierarchyState = keyHierarchyState;
-
-        if(keyHierarchyState) {
-            [self.keyHierarchyConditions[keyHierarchyState] fulfill];
-        }
-    }
+    return self.stateMachine.currentState;
 }
 
-- (NSString *)lastActiveTLKUUID
+- (NSMutableDictionary<CKKSZoneKeyState*, CKKSCondition*>*)keyHierarchyConditions
 {
-    return self.activeTLK;
-}
-
-- (void)_onqueueResetSetup:(CKKSZoneKeyState*)newState resetMessage:(NSString*)resetMessage ckoperationGroup:(CKOperationGroup*)group {
-    [super resetSetup];
-
-    self.keyHierarchyState = newState;
-    self.keyHierarchyError = nil;
-
-    [self.keyStateMachineOperation cancel];
-    self.keyStateMachineOperation = nil;
-
-    self.keyStateFetchRequested = false;
-    self.keyStateProcessRequested = false;
-
-    self.keyHierarchyOperationGroup = group;
-
-    [self ensureKeyStateReadyDependency:resetMessage];
-
-    NSOperation* oldKSNTD = self.keyStateNonTransientDependency;
-    self.keyStateNonTransientDependency = [self createKeyStateNontransientDependency];
-    if(oldKSNTD) {
-        [oldKSNTD addDependency:self.keyStateNonTransientDependency];
-        [self.waitingQueue addOperation:oldKSNTD];
-    }
+    return self.stateMachine.stateConditions;
 }
 
 - (void)ensureKeyStateReadyDependency:(NSString*)resetMessage {
     NSOperation* oldKSRD = self.keyStateReadyDependency;
-    self.keyStateReadyDependency = [self createKeyStateReadyDependency:resetMessage ckoperationGroup:self.keyHierarchyOperationGroup];
+    self.keyStateReadyDependency = [self createKeyStateReadyDependency:resetMessage];
     if(oldKSRD) {
         [oldKSRD addDependency:self.keyStateReadyDependency];
         [self.waitingQueue addOperation:oldKSRD];
     }
 }
 
-- (CKKSResultOperation*)createPendingInitializationOperation {
-
+- (CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)performInitializedOperation
+{
     WEAKIFY(self);
-    CKKSResultOperation* initializationOp = [CKKSGroupOperation named:@"view-initialization" withBlockTakingSelf:^(CKKSGroupOperation * _Nonnull strongOp) {
+    return [OctagonStateTransitionOperation named:@"ckks-initialized-operation"
+                                        intending:SecCKKSZoneKeyStateBecomeReady
+                                       errorState:SecCKKSZoneKeyStateError
+                              withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
         STRONGIFY(self);
+        [self dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            CKKSOutgoingQueueOperation* outgoingOperation = nil;
+            CKKSIncomingQueueOperation* initialProcess = nil;
+            CKKSScanLocalItemsOperation* initialScan = nil;
 
-        __block CKKSResultOperation* zoneCreationOperation = nil;
-        [self dispatchSync:^bool {
-            CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName];
-            zoneCreationOperation = [self handleCKLogin:ckse.ckzonecreated zoneSubscribed:ckse.ckzonesubscribed];
-            return true;
-        }];
-
-        CKKSResultOperation* viewInitializationOperation = [CKKSResultOperation named:@"view-initialization" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull strongInternalOp) {
-            STRONGIFY(self);
-            if(!self) {
-                ckkserror("ckks", self, "received callback for released object");
-                return;
-            }
-
-            [self dispatchSyncWithAccountKeys: ^bool {
-                ckksnotice("ckks", self, "Zone setup progress: %@ %d %@ %d %@",
-                           [CKKSAccountStateTracker stringFromAccountStatus:self.accountStatus],
-                           self.zoneCreated, self.zoneCreatedError, self.zoneSubscribed, self.zoneSubscribedError);
-
-                NSError* error = nil;
-                CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName];
-                ckse.ckzonecreated = self.zoneCreated;
-                ckse.ckzonesubscribed = self.zoneSubscribed;
-
-                // Although, if the zone subscribed error says there's no zone, mark down that there's no zone
-                if(self.zoneSubscribedError &&
-                   [self.zoneSubscribedError.domain isEqualToString:CKErrorDomain] && self.zoneSubscribedError.code == CKErrorPartialFailure) {
-                    NSError* subscriptionError = self.zoneSubscribedError.userInfo[CKPartialErrorsByItemIDKey][self.zoneID];
-                    if(subscriptionError && [subscriptionError.domain isEqualToString:CKErrorDomain] && subscriptionError.code == CKErrorZoneNotFound) {
-
-                        ckkserror("ckks", self, "zone subscription error appears to say the zone doesn't exist, fixing status: %@", self.zoneSubscribedError);
-                        ckse.ckzonecreated = false;
-                    }
-                }
-
-                [ckse saveToDatabase: &error];
-                if(error) {
-                    ckkserror("ckks", self, "couldn't save zone creation status for %@: %@", self.zoneName, error);
-                }
-
-                if(!self.zoneCreated || !self.zoneSubscribed) {
-                    // Go into 'zonecreationfailed'
-                    strongInternalOp.error = self.zoneCreatedError ? self.zoneCreatedError : self.zoneSubscribedError;
-                    [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateZoneCreationFailed withError:strongInternalOp.error];
-
-                    return true;
-                } else {
-                    [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateInitialized withError:nil];
-                }
+            CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName];
 
-                return true;
-            }];
-        }];
+            // Check if we believe we've synced this zone before.
+            if(ckse.changeToken == nil) {
+                self.operationDependencies.ckoperationGroup = [CKOperationGroup CKKSGroupWithName:@"initial-setup"];
 
-        [viewInitializationOperation addDependency:zoneCreationOperation];
-        [strongOp runBeforeGroupFinished:viewInitializationOperation];
-    }];
+                ckksnotice("ckks", self, "No existing change token; going to try to match local items with CloudKit ones.");
 
-    return initializationOp;
-}
+                // Onboard this keychain: there's likely items in it that we haven't synced yet.
+                // But, there might be items in The Cloud that correspond to these items, with UUIDs that we don't know yet.
+                // First, fetch all remote items.
 
-- (void)_onqueuePerformKeyStateInitialized:(CKKSZoneStateEntry*)ckse {
-    CKKSOutgoingQueueOperation* outgoingOperation = nil;
-    NSOperation* initialProcess = nil;
+                [self.currentFetchReasons addObject:CKKSFetchBecauseInitialStart];
+                op.nextState = SecCKKSZoneKeyStateBeginFetch;
 
-    // Check if we believe we've synced this zone before.
-    if(ckse.changeToken == nil) {
-        self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"initial-setup"];
+                // Next, try to process them (replacing local entries). This will wait for the key state to be ready.
+                initialProcess = [self processIncomingQueue:true after:nil];
 
-        ckksnotice("ckks", self, "No existing change token; going to try to match local items with CloudKit ones.");
+                // If all that succeeds, iterate through all keychain items and find the ones which need to be uploaded
+                initialScan = [self scanLocalItems:@"initial-scan-operation"
+                                  ckoperationGroup:self.operationDependencies.ckoperationGroup
+                                             after:initialProcess];
 
-        // Onboard this keychain: there's likely items in it that we haven't synced yet.
-        // But, there might be items in The Cloud that correspond to these items, with UUIDs that we don't know yet.
-        // First, fetch all remote items.
-        CKKSResultOperation* fetch = [self.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseInitialStart];
-        fetch.name = @"initial-fetch";
+            } else {
+                // Likely a restart of securityd!
+
+                // Are there any fixups to run first?
+                self.lastFixupOperation = [CKKSFixups fixup:ckse.lastFixup for:self];
+                if(self.lastFixupOperation) {
+                    ckksnotice("ckksfixup", self, "We have a fixup to perform: %@", self.lastFixupOperation);
+                    [self scheduleOperation:self.lastFixupOperation];
+                    op.nextState = SecCKKSZoneKeyStateWaitForFixupOperation;
+                    return CKKSDatabaseTransactionCommit;
+                }
 
-        // Next, try to process them (replacing local entries)
-        initialProcess = [self processIncomingQueue:true after:fetch];
-        initialProcess.name = @"initial-process-incoming-queue";
+                // First off, are there any in-flight queue entries? If so, put them back into New.
+                // If they're truly in-flight, we'll "conflict" with ourselves, but that should be fine.
+                NSError* error = nil;
+                [self _onqueueResetAllInflightOQE:&error];
+                if(error) {
+                    ckkserror("ckks", self, "Couldn't reset in-flight OQEs, bad behavior ahead: %@", error);
+                }
 
-        // If all that succeeds, iterate through all keychain items and find the ones which need to be uploaded
-        self.initialScanOperation = [self scanLocalItems:@"initial-scan-operation"
-                                        ckoperationGroup:self.keyHierarchyOperationGroup
-                                                   after:initialProcess];
+                // Are there any entries waiting for reencryption? If so, set the flag.
+                error = nil;
+                NSArray<CKKSOutgoingQueueEntry*>* reencryptOQEs = [CKKSOutgoingQueueEntry allInState:SecCKKSStateReencrypt
+                                                                                              zoneID:self.zoneID
+                                                                                               error:&error];
+                if(error) {
+                    ckkserror("ckks", self, "Couldn't load reencrypt OQEs, bad behavior ahead: %@", error);
+                }
+                if(reencryptOQEs.count > 0) {
+                    [self.stateMachine _onqueueHandleFlag:CKKSFlagItemReencryptionNeeded];
+                }
 
-    } else {
-        // Likely a restart of securityd!
+                self.operationDependencies.ckoperationGroup = [CKOperationGroup CKKSGroupWithName:@"restart-setup"];
 
-        // First off, are there any in-flight queue entries? If so, put them back into New.
-        // If they're truly in-flight, we'll "conflict" with ourselves, but that should be fine.
-        NSError* error = nil;
-        [self _onqueueResetAllInflightOQE:&error];
-        if(error) {
-            ckkserror("ckks", self, "Couldn't reset in-flight OQEs, bad behavior ahead: %@", error);
-        }
+                // 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.
 
-        // Are there any fixups to run first?
-        self.lastFixupOperation = [CKKSFixups fixup:ckse.lastFixup for:self];
-        if(self.lastFixupOperation) {
-            ckksnotice("ckksfixup", self, "We have a fixup to perform: %@", self.lastFixupOperation);
-            [self scheduleOperation:self.lastFixupOperation];
-        }
+                NSDate* now = [NSDate date];
+                NSDateComponents* offset = [[NSDateComponents alloc] init];
+                [offset setHour:-24];
+                NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0];
 
-        self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"restart-setup"];
+                if(ckse.lastFetchTime == nil ||
+                   [ckse.lastFetchTime compare: deadline] == NSOrderedAscending ||
+                   ckse.moreRecordsInCloudKit) {
 
-        if ([CKKSManifest shouldSyncManifests]) {
-            self.egoManifest = [CKKSEgoManifest tryCurrentEgoManifestForZone:self.zoneName];
-        }
+                    op.nextState = SecCKKSZoneKeyStateBeginFetch;
 
-        // 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.
+                } else {
+                    // Check if we have an existing key hierarchy in keyset
+                    CKKSCurrentKeySet* 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: %@", keyset.error);
+                    }
 
-        NSDate* now = [NSDate date];
-        NSDateComponents* offset = [[NSDateComponents alloc] init];
-        [offset setHour:-24];
-        NSDate* deadline = [[NSCalendar currentCalendar] dateByAddingComponents:offset toDate:now options:0];
+                    if(keyset.tlk && keyset.classA && keyset.classC && !keyset.error) {
+                        // This is likely a restart of securityd, and we think we're ready. Double check.
+                        op.nextState = SecCKKSZoneKeyStateBecomeReady;
 
-        if(ckse.lastFetchTime == nil ||
-           [ckse.lastFetchTime compare: deadline] == NSOrderedAscending ||
-           ckse.moreRecordsInCloudKit) {
-            initialProcess = [self fetchAndProcessCKChanges:CKKSFetchBecauseSecuritydRestart after:self.lastFixupOperation];
+                    } else {
+                        ckksnotice("ckkskey", self, "No existing key hierarchy for %@. Check if there's one in CloudKit...", self.zoneID.zoneName);
+                        op.nextState = SecCKKSZoneKeyStateBeginFetch;
+                    }
+                }
 
-            // Also, kick off a scan local items: it'll find any out-of-sync issues in the local keychain
-            self.initialScanOperation = [self scanLocalItems:@"24-hr-scan-operation"
-                                                ckoperationGroup:self.keyHierarchyOperationGroup
-                                                       after:initialProcess];
-        } else {
-            initialProcess = [self processIncomingQueue:false after:self.lastFixupOperation];
-        }
+                if(ckse.lastLocalKeychainScanTime == nil || [ckse.lastLocalKeychainScanTime compare:deadline] == NSOrderedAscending) {
+                    // TODO handle with a state flow
+                    ckksnotice("ckksscan", self, "CKKS scan last occurred at %@; beginning a new one", ckse.lastLocalKeychainScanTime);
+                    initialScan = [self scanLocalItems:ckse.lastLocalKeychainScanTime == nil ? @"initial-scan-operation" : @"24-hr-scan-operation"
+                                      ckoperationGroup:self.operationDependencies.ckoperationGroup
+                                                 after:nil];
+                }
 
-        if([CKKSManifest shouldSyncManifests]) {
-            if (!self.egoManifest && !self.initialScanOperation) {
-                ckksnotice("ckksmanifest", self, "No ego manifest on restart; rescanning");
-                self.initialScanOperation = [self scanLocalItems:@"initial-scan-operation"
-                                                ckoperationGroup:self.keyHierarchyOperationGroup
-                                                           after:initialProcess];
+                // Process outgoing queue after re-start
+                outgoingOperation = [self processOutgoingQueueAfter:nil ckoperationGroup:self.operationDependencies.ckoperationGroup];
             }
-        }
-
-        // Process outgoing queue after re-start
-        outgoingOperation = [self processOutgoingQueueAfter:self.lastFixupOperation ckoperationGroup:self.keyHierarchyOperationGroup];
-    }
-
-    /*
-     * Launch time is determined by when the zone have:
-     *  1. keystate have become ready
-     *  2. scan local items (if needed)
-     *  3. processed all outgoing item (if needed)
-     */
-
-    WEAKIFY(self);
-    NSBlockOperation *seemReady = [NSBlockOperation named:[NSString stringWithFormat:@"seemsReadyForSyncing-%@", self.zoneName] withBlock:^void{
-        STRONGIFY(self);
-        NSError *error = nil;
-        ckksnotice("launch", self, "Launch complete");
-        NSNumber *zoneSize = [CKKSMirrorEntry counts:self.zoneID error:&error];
-        if (zoneSize) {
-            zoneSize = @(SecBucket1Significant([zoneSize longValue]));
-            [self.launch addAttribute:@"zonesize" value:zoneSize];
-        }
-        [self.launch launch];
-
-        /*
-         * Since we think we are ready, signal to CK that its to check for PCS identities again, and create the
-         * since before we completed this operation, we would probably have failed with a timeout because
-         * we where busy downloading items from CloudKit and then processing them.
-         */
-        [self.notifyViewReadyScheduler trigger];
-    }];
-
-    [seemReady addNullableDependency:self.keyStateReadyDependency];
-    [seemReady addNullableDependency:outgoingOperation];
-    [seemReady addNullableDependency:self.initialScanOperation];
-    [seemReady addNullableDependency:initialProcess];
-
-    [self scheduleOperation: seemReady];
-}
-
-- (bool)_onqueueResetLocalData: (NSError * __autoreleasing *) error {
-    dispatch_assert_queue(self.queue);
-
-    NSError* localerror = nil;
-    bool setError = false; // Ugly, but this is the only way to return the first error given
-
-    CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state: self.zoneName];
-    ckse.ckzonecreated = false;
-    ckse.ckzonesubscribed = false; // I'm actually not sure about this: can you be subscribed to a non-existent zone?
-    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;
-        }
-    }
-
-    [CKKSMirrorEntry deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSMirrorEntry: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSOutgoingQueueEntry deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSOutgoingQueueEntry: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSIncomingQueueEntry deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSIncomingQueueEntry: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSKey deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSKey: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
 
-    [CKKSTLKShareRecord deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSTLKShare: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSCurrentKeyPointer deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSCurrentKeyPointer: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSCurrentItemPointer deleteAll:self.zoneID error: &localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSCurrentItemPointer: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    [CKKSDeviceStateEntry deleteAll:self.zoneID error:&localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "couldn't delete all CKKSDeviceStateEntry: %@", localerror);
-        if(error && !setError) {
-            *error = localerror; setError = true;
-        }
-    }
-
-    return (localerror == nil && !setError);
-}
+            /*
+             * Launch time is determined by when the zone have:
+             *  1. keystate have become ready
+             *  2. scan local items (if needed)
+             *  3. processed all outgoing item (if needed)
+             * TODO: this should move, once queue processing becomes part of the state machine
+             */
 
-- (CKKSResultOperation*)createPendingResetLocalDataOperation {
-    @synchronized(self.localResetOperations) {
-        CKKSResultOperation* pendingResetLocalOperation = (CKKSResultOperation*) [self findFirstPendingOperation:self.localResetOperations];
-        if(!pendingResetLocalOperation) {
             WEAKIFY(self);
-            pendingResetLocalOperation = [CKKSResultOperation named:@"reset-local" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull strongOp) {
+            NSBlockOperation *seemReady = [NSBlockOperation named:[NSString stringWithFormat:@"seemsReadyForSyncing-%@", self.zoneName] withBlock:^void{
                 STRONGIFY(self);
-                __block NSError* error = nil;
-
-                [self dispatchSync: ^bool{
-                    [self _onqueueResetLocalData: &error];
-                    return true;
-                }];
-
-                strongOp.error = error;
-            }];
-            [pendingResetLocalOperation linearDependencies:self.localResetOperations];
-        }
-        return pendingResetLocalOperation;
-    }
-}
-
-- (CKKSResultOperation*)resetLocalData {
-    // Not overly thread-safe, but a single read is okay
-    CKKSAccountStatus accountStatus = self.accountStatus;
-    ckksnotice("ckksreset", self, "Requesting local data reset");
-
-    // If we're currently signed in, the reset operation will be handled by the CKKS key state machine, and a reset should end up in 'ready'
-    if(accountStatus == CKKSAccountStatusAvailable) {
-        WEAKIFY(self);
-        CKKSGroupOperation* resetOperationGroup = [CKKSGroupOperation named:@"local-reset" withBlockTakingSelf:^(CKKSGroupOperation *strongOp) {
-            STRONGIFY(self);
-
-            __block CKKSResultOperation* resetOperation = nil;
-
-            [self dispatchSyncWithAccountKeys:^bool {
-                self.keyStateLocalResetRequested = true;
-                resetOperation = [self createPendingResetLocalDataOperation];
-                [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-                return true;
+                NSError *error = nil;
+                ckksnotice("launch", self, "Launch complete");
+                NSNumber *zoneSize = [CKKSMirrorEntry counts:self.zoneID error:&error];
+                if (zoneSize) {
+                    zoneSize = @(SecBucket1Significant([zoneSize longValue]));
+                    [self.launch addAttribute:@"zonesize" value:zoneSize];
+                }
+                [self.launch launch];
+
+                /*
+                 * Since we think we are ready, signal to CK that its to check for PCS identities again, and create the
+                 * since before we completed this operation, we would probably have failed with a timeout because
+                 * we where busy downloading items from CloudKit and then processing them.
+                 */
+                [self.notifyViewReadyScheduler trigger];
             }];
 
-            [strongOp dependOnBeforeGroupFinished:resetOperation];
-        }];
-        [self scheduleOperationWithoutDependencies:resetOperationGroup];
-
-        CKKSGroupOperation* viewReset = [CKKSGroupOperation named:@"local-data-reset" withBlockTakingSelf:^(CKKSGroupOperation *strongOp) {
-            STRONGIFY(self);
-            // Now that the local reset finished, wait for the key hierarchy state machine to churn
-            ckksnotice("ckksreset", self, "waiting for key hierarchy to become nontransient (after local reset)");
-            CKKSResultOperation* waitOp = [CKKSResultOperation named:@"waiting-for-local-reset" withBlock:^{}];
-            [waitOp timeout: 60*NSEC_PER_SEC];
-            [waitOp addNullableDependency:self.keyStateNonTransientDependency];
-
-            [strongOp runBeforeGroupFinished:waitOp];
-        }];
-        [viewReset addSuccessDependency:resetOperationGroup];
-
-        [self scheduleOperationWithoutDependencies:viewReset];
-        return viewReset;
-    } else {
-        // Since we're logged out, we must run the reset ourselves
-        WEAKIFY(self);
-        CKKSResultOperation* pendingResetLocalOperation = [CKKSResultOperation named:@"reset-local"
-                                                                 withBlockTakingSelf:^(CKKSResultOperation * _Nonnull strongOp) {
-            STRONGIFY(self);
-            __block NSError* error = nil;
-
-            [self dispatchSync: ^bool{
-                [self _onqueueResetLocalData: &error];
-                return true;
-            }];
+            [seemReady addNullableDependency:self.keyStateReadyDependency];
+            [seemReady addNullableDependency:outgoingOperation];
+            [seemReady addNullableDependency:initialScan];
+            [seemReady addNullableDependency:initialProcess];
+            [self scheduleOperation:seemReady];
 
-            strongOp.error = error;
+            return CKKSDatabaseTransactionCommit;
         }];
-        [self scheduleOperationWithoutDependencies:pendingResetLocalOperation];
-        return pendingResetLocalOperation;
-    }
+    }];
 }
 
-- (CKKSResultOperation*)createPendingDeleteZoneOperation:(CKOperationGroup*)operationGroup {
-    @synchronized(self.cloudkitDeleteZoneOperations) {
-        CKKSResultOperation* pendingDeleteOperation = (CKKSResultOperation*) [self findFirstPendingOperation:self.cloudkitDeleteZoneOperations];
-        if(!pendingDeleteOperation) {
-            pendingDeleteOperation = [self deleteCloudKitZoneOperation:operationGroup];
-            [pendingDeleteOperation linearDependencies:self.cloudkitDeleteZoneOperations];
-        }
-        return pendingDeleteOperation;
-    }
-}
+- (CKKSResultOperation*)resetLocalData {
+    ckksnotice("ckksreset", self, "Requesting local data reset");
 
-- (CKKSResultOperation*)resetCloudKitZone:(CKOperationGroup*)operationGroup {
+    return [self.stateMachine doWatchedStateMachineRPC:@"ckks-local-reset"
+                                   sourceStates:[NSSet setWithArray:@[
+                                       // TODO: possibly every state?
+                                       SecCKKSZoneKeyStateReady,
+                                       SecCKKSZoneKeyStateWaitForTLK,
+                                       SecCKKSZoneKeyStateWaitForTrust,
+                                       SecCKKSZoneKeyStateWaitForTLKUpload,
+                                       SecCKKSZoneKeyStateLoggedOut,
+                                   ]]
+                                           path:[OctagonStateTransitionPath pathFromDictionary:@{
+                                               SecCKKSZoneKeyStateResettingLocalData: @{
+                                                   SecCKKSZoneKeyStateInitializing: @{
+                                                       SecCKKSZoneKeyStateInitialized: [OctagonStateTransitionPathStep success],
+                                                       SecCKKSZoneKeyStateLoggedOut: [OctagonStateTransitionPathStep success],
+                                                   }
+                                               }
+                                           }]
+                                                 reply:^(NSError * _Nonnull error) {}];
+}
+
+- (CKKSResultOperation*)resetCloudKitZone:(CKOperationGroup*)operationGroup
+{
     [self.accountStateKnown wait:(SecCKKSTestsEnabled() ? 1*NSEC_PER_SEC : 10*NSEC_PER_SEC)];
 
     // Not overly thread-safe, but a single read is okay
         return errorOp;
     }
 
-    // Actually running the delete operation will be handled by the CKKS key state machine
     ckksnotice("ckksreset", self, "Requesting reset of CK zone (logged in)");
-    
-    __block CKKSResultOperation* deleteOperation = nil;
-    [self dispatchSyncWithAccountKeys:^bool {
-        self.keyStateCloudKitDeleteRequested = true;
-        deleteOperation = [self createPendingDeleteZoneOperation:operationGroup];
-        [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-        return true;
-    }];
-
-    WEAKIFY(self);
-    CKKSGroupOperation* viewReset = [CKKSGroupOperation named:[NSString stringWithFormat:@"cloudkit-view-reset-%@", self.zoneName]
-                                          withBlockTakingSelf:^(CKKSGroupOperation *strongOp) {
-        STRONGIFY(self);
-        // Now that the delete finished, wait for the key hierarchy state machine
-        ckksnotice("ckksreset", self, "waiting for key hierarchy to become nontransient (after cloudkit reset)");
-        CKKSResultOperation* waitOp = [CKKSResultOperation named:@"waiting-for-reset" withBlock:^{}];
-        [waitOp timeout: 60*NSEC_PER_SEC];
-        [waitOp addNullableDependency:self.keyStateNonTransientDependency];
-
-        [strongOp runBeforeGroupFinished:waitOp];
-    }];
-
-    [viewReset timeout:30*NSEC_PER_SEC];
-    [viewReset addDependency:deleteOperation];
-    [self.waitingQueue addOperation:viewReset];
-
-    return viewReset;
-}
 
-- (void)_onqueueKeyStateMachineRequestFetch {
-    dispatch_assert_queue(self.queue);
-
-    // We're going to set this flag, then nudge the key state machine.
-    // If it was idle, then it should launch a fetch. If there was an active process, this flag will stay high
-    // and the fetch will be launched later.
-
-    self.keyStateFetchRequested = true;
-    [self _onqueueAdvanceKeyStateMachineToState: nil withError: nil];
+    NSDictionary* localResetPath = @{
+        SecCKKSZoneKeyStateInitializing: @{
+            SecCKKSZoneKeyStateInitialized: [OctagonStateTransitionPathStep success],
+            SecCKKSZoneKeyStateLoggedOut: [OctagonStateTransitionPathStep success],
+        },
+    };
+
+    // If the zone delete doesn't work, try it up to two more times
+
+    return [self.stateMachine doWatchedStateMachineRPC:@"ckks-cloud-reset"
+                                          sourceStates:[NSSet setWithArray:@[
+                                              // TODO: possibly every state?
+                                              SecCKKSZoneKeyStateReady,
+                                              SecCKKSZoneKeyStateInitialized,
+                                              SecCKKSZoneKeyStateFetchComplete,
+                                              SecCKKSZoneKeyStateWaitForTLK,
+                                              SecCKKSZoneKeyStateWaitForTrust,
+                                              SecCKKSZoneKeyStateWaitForTLKUpload,
+                                              SecCKKSZoneKeyStateLoggedOut,
+                                          ]]
+                                                  path:[OctagonStateTransitionPath pathFromDictionary:@{
+                                                      SecCKKSZoneKeyStateResettingZone: @{
+                                                          SecCKKSZoneKeyStateResettingLocalData: localResetPath,
+                                                          SecCKKSZoneKeyStateResettingZone: @{
+                                                              SecCKKSZoneKeyStateResettingLocalData: localResetPath,
+                                                              SecCKKSZoneKeyStateResettingZone: @{
+                                                                 SecCKKSZoneKeyStateResettingLocalData: localResetPath,
+                                                              }
+                                                          }
+                                                      }
+                                                  }]
+                                                 reply:^(NSError * _Nonnull error) {}];
 }
 
 - (void)keyStateMachineRequestProcess {
-    // Since bools are atomic, we don't need to get on-queue here
-    // Just set the flag high and hope
-    self.keyStateProcessRequested = true;
-    [self.pokeKeyStateMachineScheduler trigger];
-}
-
-- (void)_onqueueKeyStateMachineRequestProcess {
-    dispatch_assert_queue(self.queue);
-
-    // Set the request flag, then nudge the key state machine.
-    // If it was idle, then it should launch a process. If there was an active process, this flag will stay high
-    // and the process will be launched later.
-
-    self.keyStateProcessRequested = true;
-    [self _onqueueAdvanceKeyStateMachineToState: nil withError: nil];
+    [self.stateMachine handleFlag:CKKSFlagKeyStateProcessRequested];
 }
 
-- (CKKSResultOperation*)createKeyStateReadyDependency:(NSString*)message ckoperationGroup:(CKOperationGroup*)group {
+- (CKKSResultOperation*)createKeyStateReadyDependency:(NSString*)message {
     WEAKIFY(self);
     CKKSResultOperation* keyStateReadyDependency = [CKKSResultOperation operationWithBlock:^{
         STRONGIFY(self);
-        if(!self) {
-            return;
-        }
-        ckksnotice("ckkskey", self, "%@", message);
-
-        [self dispatchSync:^bool {
-            if(self.droppedItems) {
-                // While we weren't in 'ready', keychain modifications might have come in and were dropped on the floor. Find them!
-                ckksnotice("ckkskey", self, "Launching scan operation for missed items");
-                [self scanLocalItems:@"ready-again-scan" ckoperationGroup:group after:nil];
-            }
-            return true;
-        }];
+        ckksnotice("ckkskey", self, "CKKS became ready: %@", message);
     }];
     keyStateReadyDependency.name = [NSString stringWithFormat: @"%@-key-state-ready", self.zoneName];
     keyStateReadyDependency.descriptionErrorCode = CKKSResultDescriptionPendingKeyReady;
     return keyStateReadyDependency;
 }
 
-- (CKKSResultOperation*)createKeyStateNontransientDependency {
-    WEAKIFY(self);
-    return [CKKSResultOperation named:[NSString stringWithFormat: @"%@-key-state-nontransient", self.zoneName] withBlock:^{
-        STRONGIFY(self);
-        ckksnotice("ckkskey", self, "Key state is now non-transient");
-    }];
+- (void)_onqueuePokeKeyStateMachine
+{
+    dispatch_assert_queue(self.queue);
+    [self.stateMachine _onqueuePokeStateMachine];
 }
 
-// The operations suggested by this state machine should call _onqueueAdvanceKeyStateMachineToState once they are complete.
-// At no other time should keyHierarchyState be modified.
-
-// Note that this function cannot rely on doing any database work; it might get rolled back, especially in an error state
-- (void)_onqueueAdvanceKeyStateMachineToState: (CKKSZoneKeyState*) state withError: (NSError*) error {
+- (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueNextStateMachineTransition:(OctagonState*)currentState
+                                                                                                        flags:(OctagonFlags*)flags
+                                                                                                 pendingFlags:(id<OctagonStateOnqueuePendingFlagHandler>)pendingFlagHandler
+{
     dispatch_assert_queue(self.queue);
-    WEAKIFY(self);
 
     // Resetting back to 'loggedout' takes all precedence.
-    if([state isEqual:SecCKKSZoneKeyStateLoggedOut]) {
-        ckksnotice("ckkskey", self, "Resetting the key hierarchy state machine back to '%@'", state);
+    if([flags _onqueueContains:CKKSFlagCloudKitLoggedOut]) {
+        [flags _onqueueRemoveFlag:CKKSFlagCloudKitLoggedOut];
+        ckksnotice("ckkskey", self, "CK account is not present");
 
-        [self _onqueueResetSetup:SecCKKSZoneKeyStateLoggedOut
-                    resetMessage:@"Key state has become ready for the first time (after reset)."
-                ckoperationGroup:[CKOperationGroup CKKSGroupWithName:@"key-state-after-logout"]];
+        [self ensureKeyStateReadyDependency:@"cloudkit-account-not-present"];
+        return [[CKKSLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                       intendedState:SecCKKSZoneKeyStateLoggedOut
+                                                          errorState:SecCKKSZoneKeyStateError];
+    }
 
-        [self _onqueueHandleKeyStateNonTransientDependency:nil];
-        self.launch = nil;
-        return;
+    if([flags _onqueueContains:CKKSFlagCloudKitZoneMissing]) {
+        [flags _onqueueRemoveFlag:CKKSFlagCloudKitZoneMissing];
+
+        [self ensureKeyStateReadyDependency:@"cloudkit-zone-missing"];
+        // The zone is gone! Let's reset our local state, which will feed into recreating the zone
+        return [OctagonStateTransitionOperation named:@"ck-zone-missing"
+                                             entering:SecCKKSZoneKeyStateResettingLocalData];
     }
 
-    [self.launch addEvent:state];
+    if([flags _onqueueContains:CKKSFlagChangeTokenExpired]) {
+        [flags _onqueueRemoveFlag:CKKSFlagChangeTokenExpired];
 
-    // Resetting back to 'initialized' also takes precedence
-    if([state isEqual:SecCKKSZoneKeyStateInitializing]) {
-        ckksnotice("ckkskey", self, "Resetting the key hierarchy state machine back to '%@'", state);
+        [self ensureKeyStateReadyDependency:@"cloudkit-change-token-expired"];
+        // Our change token is invalid! We'll have to refetch the world, so let's delete everything locally.
+        return [OctagonStateTransitionOperation named:@"ck-token-expired"
+                                             entering:SecCKKSZoneKeyStateResettingLocalData];
+    }
 
-        [self _onqueueResetSetup:SecCKKSZoneKeyStateInitializing
-                    resetMessage:@"Key state has become ready for the first time (after re-initializing)."
-                ckoperationGroup:[CKOperationGroup CKKSGroupWithName:@"key-state-reset-to-initializing"]];
+    if([currentState isEqualToString:SecCKKSZoneKeyStateLoggedOut]) {
+        if([flags _onqueueContains:CKKSFlagCloudKitLoggedIn] || self.accountStatus == CKKSAccountStatusAvailable) {
+            [flags _onqueueRemoveFlag:CKKSFlagCloudKitLoggedIn];
 
-        // Begin initialization, but rate-limit it
-        self.keyStateMachineOperation = [self createPendingInitializationOperation];
-        [self.keyStateMachineOperation addNullableDependency:self.zoneModifier.cloudkitRetryAfter.operationDependency];
-        [self.zoneModifier.cloudkitRetryAfter trigger];
-        [self scheduleOperation:self.keyStateMachineOperation];
+            ckksnotice("ckkskey", self, "CloudKit account now present");
+            return [OctagonStateTransitionOperation named:@"ck-sign-in"
+                                                 entering:SecCKKSZoneKeyStateInitializing];
+        }
 
-        [self _onqueueHandleKeyStateNonTransientDependency:nil];
-        return;
+        if([flags _onqueueContains:CKKSFlag24hrNotification]) {
+            [flags _onqueueRemoveFlag:CKKSFlag24hrNotification];
+        }
+        return nil;
     }
 
-    // Resetting to 'waitfortrust' also takes precedence
-    if([state isEqualToString:SecCKKSZoneKeyStateWaitForTrust]) {
-        if([self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateLoggedOut]) {
-            ckksnotice("ckks", self, "Asked to waitfortrust, but we're already in loggedout. Ignoring...");
-            return;
+    if([currentState isEqualToString: SecCKKSZoneKeyStateWaitForCloudKitAccountStatus]) {
+        if([flags _onqueueContains:CKKSFlagCloudKitLoggedIn] || self.accountStatus == CKKSAccountStatusAvailable) {
+            [flags _onqueueRemoveFlag:CKKSFlagCloudKitLoggedIn];
+
+            ckksnotice("ckkskey", self, "CloudKit account now present");
+            return [OctagonStateTransitionOperation named:@"ck-sign-in"
+                                                 entering:SecCKKSZoneKeyStateInitializing];
         }
 
-        ckksnotice("ckks", self, "Entering waitfortrust");
-        self.keyHierarchyState = SecCKKSZoneKeyStateWaitForTrust;
-        self.keyHierarchyError = nil;
-        self.keyStateMachineOperation = nil;
+        if([flags _onqueueContains:CKKSFlagCloudKitLoggedOut]) {
+            [flags _onqueueRemoveFlag:CKKSFlagCloudKitLoggedOut];
+            ckksnotice("ckkskey", self, "No account available");
 
-        [self ensureKeyStateReadyDependency:@"Key state has become ready for the first time (after lacking trust)."];
+            return [[CKKSLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                           intendedState:SecCKKSZoneKeyStateLoggedOut
+                                                              errorState:SecCKKSZoneKeyStateError];
+        }
+        return nil;
+    }
 
-        if(self.trustStatus == CKKSAccountStatusAvailable) {
-            // Note: we go to initialized here, since to enter waitfortrust CKKS has already gone through initializing
-            // initialized should refetch only if needed.
-            ckksnotice("ckks", self, "CKKS is trusted, moving to initialized");
-            self.keyStateMachineOperation = [self operationToEnterState:SecCKKSZoneKeyStateInitialized
-                                                          keyStateError:nil
-                                                                  named:@"re-enter initialized"];
-            [self scheduleOperation:self.keyStateMachineOperation];
+    [self.launch addEvent:currentState];
+
+    if([currentState isEqual:SecCKKSZoneKeyStateInitializing]) {
+        if(self.accountStatus == CKKSAccountStatusNoAccount) {
+            ckksnotice("ckkskey", self, "CloudKit account is missing. Departing!");
+            return [[CKKSLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                           intendedState:SecCKKSZoneKeyStateLoggedOut
+                                                              errorState:SecCKKSZoneKeyStateError];
         }
 
-        // In wait for trust, we might have a keyset. Who knows!
-        CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
-        [self _onqueueHandleKeyStateNonTransientDependency:keyset];
+        // Begin zone creation, but rate-limit it
+        CKKSCreateCKZoneOperation* pendingInitializeOp = [[CKKSCreateCKZoneOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                                   intendedState:SecCKKSZoneKeyStateInitialized
+                                                                                                      errorState:SecCKKSZoneKeyStateZoneCreationFailed];
+        [pendingInitializeOp addNullableDependency:self.operationDependencies.zoneModifier.cloudkitRetryAfter.operationDependency];
+        [self.operationDependencies.zoneModifier.cloudkitRetryAfter trigger];
 
-        return;
+        return pendingInitializeOp;
     }
 
-    // Cancels and error states take precedence
-    if([self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateError] ||
-       [self.keyHierarchyState isEqualToString: SecCKKSZoneKeyStateCancelled] ||
-       self.keyHierarchyError != nil) {
-        // Error state: nowhere to go. Early-exit.
-        ckkserror("ckkskey", self, "Asked to advance state machine from non-exit state %@ (to %@): %@", self.keyHierarchyState, state, self.keyHierarchyError);
-        return;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateWaitForFixupOperation]) {
+        // TODO: fixup operations should become part of the state machine
+        ckksnotice("ckkskey", self, "Waiting for the fixup operation: %@", self.lastFixupOperation);
+        OctagonStateTransitionOperation* op = [OctagonStateTransitionOperation named:@"wait-for-fixup" entering:SecCKKSZoneKeyStateInitialized];
+        [op addNullableDependency:self.lastFixupOperation];
+        return op;
     }
 
-    if([state isEqual: SecCKKSZoneKeyStateError]) {
-        // But wait! Is this a "we're locked" error?
-        if(error && [self.lockStateTracker isLockedError:error]) {
-            ckkserror("ckkskey", self, "advised of 'keychain locked' error, ignoring: coming from state (%@): %@", self.keyHierarchyState, error);
-            // After the next unlock, fake that we received the last zone transition
-            CKKSZoneKeyState* lastState = self.keyHierarchyState;
-            self.keyStateMachineOperation = [NSBlockOperation named:@"key-state-after-unlock" withBlock:^{
-                STRONGIFY(self);
-                if(!self) {
-                    return;
-                }
-                [self dispatchSyncWithAccountKeys:^bool{
-                    [self _onqueueAdvanceKeyStateMachineToState:lastState withError:nil];
-                    return true;
-                }];
-            }];
-            state = nil;
-
-            self.keyHierarchyState = SecCKKSZoneKeyStateWaitForUnlock;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateInitialized]) {
+        // We're initialized and CloudKit is ready. If we're trusted, see what needs done. Otherwise, wait.
+        return [self performInitializedOperation];
+    }
 
-            [self.keyStateMachineOperation addNullableDependency:self.lockStateTracker.unlockDependency];
-            [self scheduleOperation:self.keyStateMachineOperation];
+    // In error? You probably aren't getting out.
+    if([currentState isEqualToString:SecCKKSZoneKeyStateError]) {
+        if([flags _onqueueContains:CKKSFlagCloudKitLoggedIn]) {
+            [flags _onqueueRemoveFlag:CKKSFlagCloudKitLoggedIn];
 
-            [self _onqueueHandleKeyStateNonTransientDependency:nil];
-            return;
+            // Worth one last shot. Reset everything locally, and try again.
+            return [[CKKSLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                           intendedState:SecCKKSZoneKeyStateInitializing
+                                                              errorState:SecCKKSZoneKeyStateError];
+        }
 
-        } else {
-            // Error state: record the error and exit early
-            ckkserror("ckkskey", self, "advised of error: coming from state (%@): %@", self.keyHierarchyState, error);
+        ckkserror("ckkskey", self, "Staying in error state %@", currentState);
+        return nil;
+    }
 
-            [[CKKSAnalytics logger] logUnrecoverableError:error
-                                                 forEvent:CKKSEventStateError
-                                                   inView:self
-                                           withAttributes:@{ @"previousKeyHierarchyState" : self.keyHierarchyState }];
+    if([currentState isEqualToString:SecCKKSZoneKeyStateResettingZone]) {
+        ckksnotice("ckkskey", self, "Deleting the CloudKit Zone");
 
+        [self ensureKeyStateReadyDependency:@"ck-zone-reset"];
+        return [[CKKSDeleteCKZoneOperation alloc] initWithDependencies:self.operationDependencies
+                                                         intendedState:SecCKKSZoneKeyStateResettingLocalData
+                                                            errorState:SecCKKSZoneKeyStateResettingZone];
+    }
 
-            self.keyHierarchyState = SecCKKSZoneKeyStateError;
-            self.keyHierarchyError = error;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateResettingLocalData]) {
+        ckksnotice("ckkskey", self, "Resetting local data");
 
-            [self _onqueueHandleKeyStateNonTransientDependency:nil];
-            return;
-        }
+        [self ensureKeyStateReadyDependency:@"local-data-reset"];
+        return [[CKKSLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                       intendedState:SecCKKSZoneKeyStateInitializing
+                                                          errorState:SecCKKSZoneKeyStateError];
     }
 
-    if([state isEqual: SecCKKSZoneKeyStateCancelled]) {
-        ckkserror("ckkskey", self, "advised of cancel: coming from state (%@): %@", self.keyHierarchyState, error);
-        self.keyHierarchyState = SecCKKSZoneKeyStateCancelled;
-        self.keyHierarchyError = error;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateZoneCreationFailed]) {
+        //Prepare to go back into initializing, as soon as the cloudkitRetryAfter is happy
+        OctagonStateTransitionOperation* op = [OctagonStateTransitionOperation named:@"recover-from-cloudkit-failure" entering:SecCKKSZoneKeyStateInitializing];
 
-        // Cancel the key ready dependency. Strictly Speaking, this will cause errors down the line, but we're in a cancel state: those operations should be canceled anyway.
-        self.keyHierarchyOperationGroup = nil;
-        [self.keyStateReadyDependency cancel];
-        self.keyStateReadyDependency = nil;
+        [op addNullableDependency:self.operationDependencies.zoneModifier.cloudkitRetryAfter.operationDependency];
+        [self.operationDependencies.zoneModifier.cloudkitRetryAfter trigger];
 
-        [self.keyStateNonTransientDependency cancel];
-        self.keyStateNonTransientDependency = nil;
-        return;
+        return op;
     }
 
-    // Now that the current or new state isn't an error or a cancel, proceed.
-    if(self.keyStateMachineOperation && ![self.keyStateMachineOperation isFinished]) {
-        if(state == nil) {
-            // we started this operation to move the state machine. Since you aren't asking for a state transition, and there's an active operation, no need to do anything
-            ckksnotice("ckkskey", self, "Not advancing state machine: waiting for %@", self.keyStateMachineOperation);
-            return;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateLoseTrust]) {
+        if([flags _onqueueContains:CKKSFlagBeginTrustedOperation]) {
+            [flags _onqueueRemoveFlag:CKKSFlagBeginTrustedOperation];
+            // This was likely a race between some operation and the beginTrustedOperation call! Skip changing state and try again.
+            return [OctagonStateTransitionOperation named:@"begin-trusted-operation" entering:SecCKKSZoneKeyStateInitialized];
+        }
+
+        // If our current state is "trusted", fall out
+        if(self.trustStatus == CKKSAccountStatusAvailable) {
+            self.trustStatus = CKKSAccountStatusUnknown;
         }
+        return [OctagonStateTransitionOperation named:@"trust-loss" entering:SecCKKSZoneKeyStateWaitForTrust];
     }
 
-    if(state) {
-        ckksnotice("ckkskey", self, "Preparing to advance key hierarchy state machine from %@ to %@", self.keyHierarchyState, state);
-        self.keyStateMachineOperation = nil;
-    } else {
-        ckksnotice("ckkskey", self, "Key hierarchy state machine is being poked; currently %@", self.keyHierarchyState);
-        state = self.keyHierarchyState;
-    }
-
-#if DEBUG
-    // During testing, keep the developer honest: this function should always have the self identities, unless the account has lost trust
-    // But, beginTrustedOperation is currently racy: if it acquires the queue and sets the trust bit between fetching the trust states and getting on the queue,
-    // this will fire. So, release SecCKKSZoneKeyStateInitialized from this check.
-    if(self.trustStatus == CKKSAccountStatusAvailable
-       && ![state isEqualToString:SecCKKSZoneKeyStateLoggedOut]
-       && ![state isEqualToString:SecCKKSZoneKeyStateInitialized]) {
-        bool hasSelfIdentities = false;
-        NSAssert(self.currentTrustStates.count > 0, @"Should have at least one trust state");
-        for(CKKSPeerProviderState* state in self.currentTrustStates) {
-            if(state.currentSelfPeersError == nil || state.currentSelfPeersError.code != CKKSNoPeersAvailable) {
-                hasSelfIdentities = true;
-            }
+    if([currentState isEqualToString:SecCKKSZoneKeyStateWaitForTrust]) {
+        if(self.trustStatus == CKKSAccountStatusAvailable) {
+            ckksnotice("ckkskey", self, "Beginning trusted state machine operation");
+            return [OctagonStateTransitionOperation named:@"begin-trusted-operation" entering:SecCKKSZoneKeyStateInitialized];
         }
 
-        NSAssert(hasSelfIdentities, @"Must have viable (or errored) self peers to advance key state");
+        if([flags _onqueueContains:CKKSFlagKeyStateProcessRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagKeyStateProcessRequested];
+            return [OctagonStateTransitionOperation named:@"begin-trusted-operation" entering:SecCKKSZoneKeyStateProcess];
+        }
+
+        if([flags _onqueueContains:CKKSFlag24hrNotification]) {
+            [flags _onqueueRemoveFlag:CKKSFlag24hrNotification];
+        }
+
+        return nil;
     }
-#endif
 
-    // Do any of these state transitions below want to change which state we're in?
-    CKKSZoneKeyState* nextState = nil;
-    NSError* nextError = nil;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateBecomeReady]) {
+        return [[CKKSCheckKeyHierarchyOperation alloc] initWithDependencies:self.operationDependencies
+                                                              intendedState:SecCKKSZoneKeyStateReady
+                                                                 errorState:SecCKKSZoneKeyStateError];
+    }
 
-    // Any state that wants should fill this in; it'll be used at the end of this function as well
-    CKKSCurrentKeySet* keyset = nil;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateReady]) {
+        // If we're ready, we can ignore the begin trusted flag
+        [flags _onqueueRemoveFlag:CKKSFlagBeginTrustedOperation];
 
-#if !defined(NDEBUG)
-    {
-        NSError* localerror = nil;
-        NSError* allKeysError = nil;
-        NSArray<CKKSKey*>* allKeys = [CKKSKey allKeys:self.zoneID error:&allKeysError];
+        if(self.keyStateFullRefetchRequested) {
+            // In ready, but something has requested a full refetch.
+            ckksnotice("ckkskey", self, "Kicking off a full key refetch based on request:%d", self.keyStateFullRefetchRequested);
+            [self ensureKeyStateReadyDependency:@"key-state-full-refetch"];
+            return [OctagonStateTransitionOperation named:@"full-refetch" entering:SecCKKSZoneKeyStateNeedFullRefetch];
+        }
 
-        if(localerror) {
-            ckkserror("ckkskey", self, "couldn't fetch all keys from local database, entering error state: %@", allKeysError);
+        if([flags _onqueueContains:CKKSFlagFetchRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagFetchRequested];
+            ckksnotice("ckkskey", self, "Kicking off a key refetch based on request");
+            [self ensureKeyStateReadyDependency:@"key-state-fetch"];
+            return [OctagonStateTransitionOperation named:@"fetch-requested" entering:SecCKKSZoneKeyStateBeginFetch];
         }
-        ckksdebug("ckkskey", self, "All keys: %@", allKeys);
-    }
-#endif
 
-    NSError* hierarchyError = nil;
+        if([flags _onqueueContains:CKKSFlagKeyStateProcessRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagKeyStateProcessRequested];
+            ckksnotice("ckkskey", self, "Kicking off a key reprocess based on request");
+            [self ensureKeyStateReadyDependency:@"key-state-process"];
+            return [OctagonStateTransitionOperation named:@"key-process" entering:SecCKKSZoneKeyStateProcess];
+        }
 
-    if(self.keyStateCloudKitDeleteRequested || [state isEqualToString:SecCKKSZoneKeyStateResettingZone]) {
-        // CloudKit reset requests take precedence over all other state transitions
-        ckksnotice("ckkskey", self, "Deleting the CloudKit Zone");
-        CKKSGroupOperation* op = [[CKKSGroupOperation alloc] init];
+        if(self.trustStatus != CKKSAccountStatusAvailable) {
+            ckksnotice("ckkskey", self, "In ready, but there's no trust; going into waitfortrust");
+            [self ensureKeyStateReadyDependency:@"trust loss"];
+            return [OctagonStateTransitionOperation named:@"trust-gone" entering:SecCKKSZoneKeyStateLoseTrust];
+        }
 
-        CKKSResultOperation* deleteOp = [self createPendingDeleteZoneOperation:self.keyHierarchyOperationGroup];
-        [op runBeforeGroupFinished: deleteOp];
+        if([flags _onqueueContains:CKKSFlagTrustedPeersSetChanged]) {
+            [flags _onqueueRemoveFlag:CKKSFlagTrustedPeersSetChanged];
+            ckksnotice("ckkskey", self, "Received a nudge that the trusted peers set might have changed! Reprocessing.");
+            [self ensureKeyStateReadyDependency:@"Peer set changed"];
+            return [OctagonStateTransitionOperation named:@"trusted-peers-changed" entering:SecCKKSZoneKeyStateProcess];
+        }
 
-        NSOperation* nextStateOp = [CKKSResultOperation named:@"inspect-zone-delete" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) {
-            STRONGIFY(self);
-            [self dispatchSyncWithAccountKeys:^bool {
-                // Did the delete op succeed?
-                if(deleteOp.error == nil) {
-                    ckksnotice("ckkskey", self, "Zone deletion operation complete! Proceeding to reset local data");
-                    [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateResettingLocalData withError:nil];
-                    return true;
-                }
+        if([flags _onqueueContains:CKKSFlag24hrNotification]) {
+            [flags _onqueueRemoveFlag:CKKSFlag24hrNotification];
 
-                ckksnotice("ckkskey", self, "Zone deletion operation failed, will retry: %@", deleteOp.error);
-                [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateResettingZone withError:nil];
+            // We'd like to trigger our 24-hr backup fetch and scan.
+            // That's currently part of the Initialized state, so head that way
+            return [OctagonStateTransitionOperation named:@"24-hr-check" entering:SecCKKSZoneKeyStateInitialized];
+        }
 
-                return true;
-            }];
-        }];
+        if([flags _onqueueContains:CKKSFlagItemReencryptionNeeded]) {
+            [flags _onqueueRemoveFlag:CKKSFlagItemReencryptionNeeded];
 
-        [nextStateOp addDependency:deleteOp];
-        [op runBeforeGroupFinished:nextStateOp];
+            // TODO: this should be part of the state machine
+            CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                                                   ckks:self
+                                                                                                          intendedState:SecCKKSZoneKeyStateReady
+                                                                                                             errorState:SecCKKSZoneKeyStateError];
+            [self scheduleOperation:op];
+            // fall through.
+        }
 
-        self.keyStateMachineOperation = op;
-        self.keyStateCloudKitDeleteRequested = false;
+        if([flags _onqueueContains:CKKSFlagProcessIncomingQueue]) {
+            [flags _onqueueRemoveFlag:CKKSFlagProcessIncomingQueue];
+            // TODO: this should be part of the state machine
 
-        // Also, pending operations should be cancelled
-        [self cancelPendingOperations];
+            [self processIncomingQueue:true];
+            //return [OctagonStateTransitionOperation named:@"process-outgoing" entering:SecCKKSZoneKeyStateProcessIncomingQueue];
+        }
 
-    } else if(self.keyStateLocalResetRequested || [state isEqualToString:SecCKKSZoneKeyStateResettingLocalData]) {
-        // Local reset requests take precedence over all other state transitions
-        ckksnotice("ckkskey", self, "Resetting local data");
-        CKKSGroupOperation* op = [[CKKSGroupOperation alloc] init];
+        if([flags _onqueueContains:CKKSFlagScanLocalItems]) {
+            [flags _onqueueRemoveFlag:CKKSFlagScanLocalItems];
+            ckksnotice("ckkskey", self, "Launching a scan operation to find dropped items");
 
-        CKKSResultOperation* resetOp = [self createPendingResetLocalDataOperation];
-        [op runBeforeGroupFinished: resetOp];
+            // TODO: this should be a state flow
+            [self scanLocalItems:@"per-request"];
+            // fall through
+        }
 
-        NSOperation* nextStateOp = [self operationToEnterState:SecCKKSZoneKeyStateInitializing keyStateError:nil named:@"state-resetting-initialize"];
-        [nextStateOp addDependency:resetOp];
-        [op runBeforeGroupFinished:nextStateOp];
+        if([flags _onqueueContains:CKKSFlagProcessOutgoingQueue]) {
+            [flags _onqueueRemoveFlag:CKKSFlagProcessOutgoingQueue];
 
-        self.keyStateMachineOperation = op;
-        self.keyStateLocalResetRequested = false;
+            [self processOutgoingQueue:nil];
+            // TODO: this should be a state flow.
+            //return [OctagonStateTransitionOperation named:@"process-outgoing" entering:SecCKKSZoneKeyStateProcessOutgoingQueue];
+            // fall through
+        }
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateZoneCreationFailed]) {
-        //Prepare to go back into initializing, as soon as the cloudkitRetryAfter is happy
-        self.keyStateMachineOperation = [self operationToEnterState:SecCKKSZoneKeyStateInitializing keyStateError:nil named:@"recover-from-cloudkit-failure"];
-        [self.keyStateMachineOperation addNullableDependency:self.zoneModifier.cloudkitRetryAfter.operationDependency];
-        [self.zoneModifier.cloudkitRetryAfter trigger];
+        // TODO: kick off a key roll if one has been requested
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForTrust]) {
-        // Actually entering this state should have been handled above, so let's check if we can exit it here...
-        if(self.trustStatus == CKKSAccountStatusAvailable) {
-            ckksnotice("ckkskey", self, "Beginning trusted state machine operation");
-            nextState = SecCKKSZoneKeyStateInitialized;
 
-        } else if (self.tlkCreationRequested) {
-            ckksnotice("ckkskey", self, "No trust, but TLK creation is requested. Moving to fetchcomplete.");
-            nextState = SecCKKSZoneKeyStateFetchComplete;
+        // If we reach this point, we're in ready, and will stay there.
+        // Tell the launch and the viewReadyScheduler about that.
 
-        } else {
-            ckksnotice("ckkskey", self, "Remaining in 'waitfortrust'");
+        [self.launch launch];
+
+        [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastKeystateReady zoneName:self.zoneName];
+        if(self.keyStateReadyDependency) {
+            [self scheduleOperation:self.keyStateReadyDependency];
+            self.keyStateReadyDependency = nil;
         }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateReady]) {
-        NSError* localerror = nil;
-        NSArray<CKKSKey*>* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror];
+        return nil;
+    }
 
-        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([currentState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock]) {
+        if([flags _onqueueContains:CKKSFlagDeviceUnlocked]) {
+            [flags _onqueueRemoveFlag:CKKSFlagDeviceUnlocked];
+            [self ensureKeyStateReadyDependency:@"Device unlocked"];
+            return [OctagonStateTransitionOperation named:@"key-state-ready-after-unlock" entering:SecCKKSZoneKeyStateBecomeReady];
         }
 
-        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]);
-            nextState = SecCKKSZoneKeyStateProcess;
-
-        } else if(self.keyStateFullRefetchRequested) {
-            // In ready, but someone has requested a full fetch. Kick it off.
-            ckksnotice("ckkskey", self, "Kicking off a full key refetch based on request:%d", self.keyStateFullRefetchRequested);
-            nextState = SecCKKSZoneKeyStateNeedFullRefetch;
-
-        } else if(self.keyStateFetchRequested) {
-            // In ready, but someone has requested a fetch. Kick it off.
-            ckksnotice("ckkskey", self, "Kicking off a key refetch based on request:%d", self.keyStateFetchRequested);
-            nextState = SecCKKSZoneKeyStateFetch; // Don't go to 'ready', go to 'initialized', since we want to fetch again
-        } else if (self.trustStatus != CKKSAccountStatusAvailable) {
-            ckksnotice("ckkskey", self, "Asked to go into ready, but there's no trust; going into waitfortrust");
-            nextState = SecCKKSZoneKeyStateWaitForTrust;
-        } else if (self.trustedPeersSetChanged) {
-            ckksnotice("ckkskey", self, "Received a nudge that the trusted peers set might have changed! Reprocessing.");
-            nextState = SecCKKSZoneKeyStateProcess;
-            self.trustedPeersSetChanged = false;
+        if([flags _onqueueContains:CKKSFlagProcessOutgoingQueue]) {
+            [flags _onqueueRemoveFlag:CKKSFlagProcessOutgoingQueue];
+            [self processOutgoingQueue:nil];
+            // TODO: this should become part of the key state hierarchy
         }
 
-        // TODO: kick off a key roll if one has been requested
+        // Ready enough!
 
-        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.
-                ckksnotice("ckkskey", self, "Thought we were ready, but the key hierarchy is %@: %@", checkedstate, hierarchyError);
-                nextState = checkedstate;
-                if([nextState isEqualToString:SecCKKSZoneKeyStateError]) {
-                    nextError = hierarchyError;
-                }
-            }
+        [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastKeystateReady zoneName:self.zoneName];
+        if(self.keyStateReadyDependency) {
+            [self scheduleOperation:self.keyStateReadyDependency];
+            self.keyStateReadyDependency = nil;
         }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateInitialized]) {
-        // We're initialized and CloudKit is ready. If we're trusted, see what needs done. Otherwise, wait.
+        OctagonPendingFlag* unlocked = [[OctagonPendingFlag alloc] initWithFlag:CKKSFlagDeviceUnlocked
+                                                                     conditions:OctagonPendingConditionsDeviceUnlocked];
+        [pendingFlagHandler _onqueueHandlePendingFlag:unlocked];
+        return nil;
+    }
 
-        // Note: we might be still 'untrusted' at this point. The state machine is responsible for not entering 'ready' until
-        // we are trusted.
-        // This is acceptable only if the key state machine does not make new TLKs without being trusted!
+    if([currentState isEqualToString:SecCKKSZoneKeyStateBeginFetch]) {
+        ckksnotice("ckkskey", self, "Starting a key hierarchy fetch");
+        [flags _onqueueRemoveFlag:CKKSFlagFetchComplete];
 
-        // Set this state, for test use
-        self.keyHierarchyState = SecCKKSZoneKeyStateInitialized;
+        WEAKIFY(self);
 
-        CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName];
-        [self _onqueuePerformKeyStateInitialized:ckse];
-
-        // We need to either:
-        //  Wait for the fixup operation to occur
-        //  Go into 'ready'
-        //  Or start a key state fetch
-        if(self.lastFixupOperation && ![self.lastFixupOperation isFinished]) {
-            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);
-            }
+        NSSet<CKKSFetchBecause*>* fetchReasons = self.currentFetchReasons ?
+            [self.currentFetchReasons setByAddingObject:CKKSFetchBecauseKeyHierarchy] :
+            [NSSet setWithObject:CKKSFetchBecauseKeyHierarchy];
 
-            if(keyset.tlk && keyset.classA && keyset.classC && !keyset.error) {
-                // This is likely a restart of securityd, and we think we're ready. Double check.
+        CKKSResultOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:fetchReasons];
+        CKKSResultOperation* flagOp = [CKKSResultOperation named:@"post-fetch"
+                                                       withBlock:^{
+            STRONGIFY(self);
+            [self.stateMachine handleFlag:CKKSFlagFetchComplete];
+        }];
+        [flagOp addDependency:fetchOp];
+        [self scheduleOperation:flagOp];
 
-                CKKSZoneKeyState* checkedstate = [self _onqueueEnsureKeyHierarchyHealth:keyset error:&hierarchyError];
-                if([checkedstate isEqualToString:SecCKKSZoneKeyStateReady] && !hierarchyError) {
-                    ckksnotice("ckkskey", self, "Already have existing key hierarchy for %@; using it.", self.zoneID.zoneName);
-                } else {
-                    ckksnotice("ckkskey", self, "Initial scan shows key hierarchy is %@: %@", checkedstate, hierarchyError);
-                }
-                nextState = checkedstate;
+        return [OctagonStateTransitionOperation named:@"waiting-for-fetch" entering:SecCKKSZoneKeyStateFetch];
+    }
 
-            } else {
-                // We have no local key hierarchy. One might exist in CloudKit, or it might not.
-                ckksnotice("ckkskey", self, "No existing key hierarchy for %@. Check if there's one in CloudKit...", self.zoneID.zoneName);
-                nextState = SecCKKSZoneKeyStateFetch;
-            }
+    if([currentState isEqualToString:SecCKKSZoneKeyStateFetch]) {
+        if([flags _onqueueContains:CKKSFlagFetchComplete]) {
+            [flags _onqueueRemoveFlag:CKKSFlagFetchComplete];
+            return [OctagonStateTransitionOperation named:@"fetch-complete" entering:SecCKKSZoneKeyStateFetchComplete];
         }
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateFetch]) {
-        ckksnotice("ckkskey", self, "Starting a key hierarchy fetch");
-        [self _onqueueKeyHierarchyFetch];
+        // The flags CKKSFlagCloudKitZoneMissing and CKKSFlagChangeTokenOutdated are both handled at the top of this function
+        // So, we don't need to handle them here.
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateNeedFullRefetch]) {
-        ckksnotice("ckkskey", self, "Starting a key hierarchy full refetch");
-        [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithObjects:CKKSFetchBecauseKeyHierarchy, CKKSFetchBecauseResync, nil]];
-        self.keyStateMachineRefetched = true;
-        self.keyStateFullRefetchRequested = false;
+        return nil;
+    }
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForFixupOperation]) {
-        // We should enter 'initialized' when the fixup operation completes
-        ckksnotice("ckkskey", self, "Waiting for the fixup operation: %@", self.lastFixupOperation);
+    if([currentState isEqualToString:SecCKKSZoneKeyStateNeedFullRefetch]) {
+         ckksnotice("ckkskey", self, "Starting a key hierarchy full refetch");
 
-        self.keyStateMachineOperation = [NSBlockOperation named:@"key-state-after-fixup" withBlock:^{
-            STRONGIFY(self);
-            [self dispatchSyncWithAccountKeys:^bool{
-                ckksnotice("ckkskey", self, "Fixup operation complete! Restarting key hierarchy machinery");
-                [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateInitialized withError:nil];
-                return true;
-            }];
-        }];
-        [self.keyStateMachineOperation addNullableDependency:self.lastFixupOperation];
+         //TODO use states here instead of flags
+         self.keyStateMachineRefetched = true;
+         self.keyStateFullRefetchRequested = false;
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateFetchComplete]) {
-        // We've just completed a fetch of everything. Are there any remote keys?
-        keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
+         return [OctagonStateTransitionOperation named:@"fetch-complete" entering:SecCKKSZoneKeyStateResettingLocalData];
+    }
 
-        NSError* localerror = nil;
+    if([currentState isEqualToString:SecCKKSZoneKeyStateFetchComplete]) {
+        [self.launch addEvent:@"fetch-complete"];
+        [self.currentFetchReasons removeAllObjects];
 
-        NSArray<CKKSKey*>* localKeys = [CKKSKey localKeys:self.zoneID error:&localerror];
-        NSArray<CKKSKey*>* remoteKeys = [CKKSKey remoteKeys:self.zoneID error: &localerror];
+        return [OctagonStateTransitionOperation named:@"post-fetch-process" entering:SecCKKSZoneKeyStateProcess];
+    }
 
-        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([currentState isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation]) {
+        if([flags _onqueueContains:CKKSFlagKeyStateProcessRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagKeyStateProcessRequested];
+            ckksnotice("ckkskey", self, "We believe we need to create TLKs but we also received a key nudge; moving to key state Process.");
+            return [OctagonStateTransitionOperation named:@"wait-for-tlk-creation-process" entering:SecCKKSZoneKeyStateProcess];
 
-        if(remoteKeys.count > 0u) {
-            // Process the keys we received.
-            self.keyStateMachineOperation = [[CKKSProcessReceivedKeysStateMachineOperation alloc] initWithCKKSKeychainView: self];
-        } else if( (keyset.currentTLKPointer || keyset.currentClassAPointer || keyset.currentClassCPointer) &&
-                  !(keyset.tlk && keyset.classA && keyset.classC)) {
-            // Huh. We appear to have current key pointers, but the keys themselves don't exist. That's weird.
-            // Transfer to the "unhealthy" state to request a fix
-            ckksnotice("ckkskey", self, "We appear to have current key pointers but no keys to match them: %@ Moving to 'unhealthy'", keyset);
-            nextState = SecCKKSZoneKeyStateUnhealthy;
-        } else {
-            // No remote keys, and the pointers look sane? Do we have an existing key hierarchy?
-            CKKSZoneKeyState* checkedstate = [self _onqueueEnsureKeyHierarchyHealth:keyset error:&hierarchyError];
-            if([checkedstate isEqualToString:SecCKKSZoneKeyStateReady] && !hierarchyError) {
-                ckksnotice("ckkskey", self, "After fetch, everything looks good.");
-                nextState = checkedstate;
-
-            } else if(localKeys.count == 0 && remoteKeys.count == 0) {
-                ckksnotice("ckkskey", self, "After fetch, we don't have any key hierarchy. Entering a waiting state: %@", hierarchyError ?: @"no error");
-                nextState = SecCKKSZoneKeyStateWaitForTLKCreation;
-            } else {
-                ckksnotice("ckkskey", self, "After fetch, we have a possibly unhealthy key hierarchy. Moving to %@: %@", checkedstate, hierarchyError ?: @"no error");
-                nextState = checkedstate;
-            }
-        }
+        } else if([flags _onqueueContains:CKKSFlagFetchRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagFetchRequested];
+            return [OctagonStateTransitionOperation named:@"fetch-requested" entering:SecCKKSZoneKeyStateBeginFetch];
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation]) {
+        } else if([flags _onqueueContains:CKKSFlagTLKCreationRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagTLKCreationRequested];
 
-        if(self.tlkCreationRequested) {
-            self.tlkCreationRequested = false;
-            ckksnotice("ckkskey", self, "TLK creation requested; kicking off operation");
-            self.keyStateMachineOperation = [[CKKSNewTLKOperation alloc] initWithCKKSKeychainView: self ckoperationGroup:self.keyHierarchyOperationGroup];
+            // It's very likely that we're already untrusted at this point. But, sometimes we will be trusted right now, and can lose trust while waiting for the upload.
+            // This probably should be handled by a state increase.
+            [flags _onqueueRemoveFlag:CKKSFlagEndTrustedOperation];
 
-        } else if(self.keyStateProcessRequested) {
-            ckksnotice("ckkskey", self, "We believe we need to create TLKs but we also received a key nudge; moving to key state Process.");
-            nextState = SecCKKSZoneKeyStateProcess;
+            ckksnotice("ckkskey", self, "TLK creation requested; kicking off operation");
+            return [[CKKSNewTLKOperation alloc] initWithDependencies:self.operationDependencies
+                                                                ckks:self];
+        } else if(self.lastNewTLKOperation.keyset) {
+            // This means that we _have_ created new TLKs, and should wait for them to be uploaded. This is ugly and should probably be done with more states.
+            return [OctagonStateTransitionOperation named:@"" entering:SecCKKSZoneKeyStateWaitForTLKUpload];
 
         } else {
             ckksnotice("ckkskey", self, "We believe we need to create TLKs; waiting for Octagon (via %@)", self.suggestTLKUpload);
             [self.suggestTLKUpload trigger];
         }
+    }
 
-
-    } else if([state isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload]) {
         ckksnotice("ckkskey", self, "We believe we have TLKs that need uploading");
 
+        if([flags _onqueueContains:CKKSFlagFetchRequested]) {
+            ckksnotice("ckkskey", self, "Received a nudge to refetch CKKS");
+            return [OctagonStateTransitionOperation named:@"tlk-upload-refetch" entering:SecCKKSZoneKeyStateBeginFetch];
+        }
 
-        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;
-            } else {
-                ckksnotice("ckkskey", self, "Received a nudge that our TLK records might be here, but there's no TLK pointer. Staying in WaitForTLKUpload.");
-                self.keyStateProcessRequested = false;
-            }
+        if([flags _onqueueContains:CKKSFlagKeyStateTLKsUploaded]) {
+            [flags _onqueueRemoveFlag:CKKSFlagKeyStateTLKsUploaded];
+
+            return [OctagonStateTransitionOperation named:@"wait-for-tlk-upload-process" entering:SecCKKSZoneKeyStateProcess];
         }
 
-        if(nextState == nil) {
-            ckksnotice("ckkskey", self, "Alerting any listener of our proposed keyset: %@", self.lastNewTLKOperation.keyset);
-            [self _onqueueRunKeysetProviderOperations:self.lastNewTLKOperation.keyset];
+        if([flags _onqueueContains:CKKSFlagEndTrustedOperation]) {
+            [flags _onqueueRemoveFlag:CKKSFlagEndTrustedOperation];
 
-            ckksnotice("ckkskey", self, "Notifying Octagon again, just in case");
-            [self.suggestTLKUpload trigger];
+            return [OctagonStateTransitionOperation named:@"trust-loss" entering:SecCKKSZoneKeyStateLoseTrust];
         }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateWaitForTLK]) {
+        if([flags _onqueueContains:CKKSFlagKeyStateProcessRequested]) {
+            return [OctagonStateTransitionOperation named:@"wait-for-tlk-fetch-process" entering:SecCKKSZoneKeyStateProcess];
+        }
+
+        // This is quite the hack, but it'll do for now.
+        [self.operationDependencies provideKeySet:self.lastNewTLKOperation.keyset];
+
+        ckksnotice("ckkskey", self, "Notifying Octagon again, just in case");
+        [self.suggestTLKUpload trigger];
+    }
+
+    if([currentState isEqualToString:SecCKKSZoneKeyStateTLKMissing]) {
+        return [self tlkMissingOperation:SecCKKSZoneKeyStateWaitForTLK];
+    }
+
+    if([currentState isEqualToString:SecCKKSZoneKeyStateWaitForTLK]) {
         // We're in a hold state: waiting for the TLK bytes to arrive.
 
-        if(self.keyStateProcessRequested) {
+        if([flags _onqueueContains:CKKSFlagKeyStateProcessRequested]) {
+            [flags _onqueueRemoveFlag:CKKSFlagKeyStateProcessRequested];
             // Someone has requsted a reprocess! Go to the correct state.
             ckksnotice("ckkskey", self, "Received a nudge that our TLK might be here! Reprocessing.");
-            nextState = SecCKKSZoneKeyStateProcess;
+            return [OctagonStateTransitionOperation named:@"wait-for-tlk-process" entering:SecCKKSZoneKeyStateProcess];
+
+        } else if([flags _onqueueContains:CKKSFlagTrustedPeersSetChanged]) {
+            [flags _onqueueRemoveFlag:CKKSFlagTrustedPeersSetChanged];
 
-        } else if(self.trustedPeersSetChanged) {
             // Hmm, maybe this trust set change will cause us to recover this TLK (due to a previously-untrusted share becoming trusted). Worth a shot!
             ckksnotice("ckkskey", self, "Received a nudge that the trusted peers set might have changed! Reprocessing.");
-            nextState = SecCKKSZoneKeyStateProcess;
-            self.trustedPeersSetChanged = false;
+            return [OctagonStateTransitionOperation named:@"wait-for-tlk-peers" entering:SecCKKSZoneKeyStateProcess];
+        }
 
-        } else {
-            keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
+        return nil;
+    }
 
-            // Should we nuke this zone?
-            if(self.trustStatus == CKKSAccountStatusAvailable) {
-                if([self _onqueueOtherDevicesReportHavingTLKs:keyset]) {
-                    ckksnotice("ckkskey", self, "Other devices report having TLK(%@). Entering a waiting state", keyset.currentTLKPointer);
-                } else {
-                    ckksnotice("ckkskey", self, "No other devices have TLK(%@). Beginning zone reset...", keyset.currentTLKPointer);
-                    self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"tlk-missing"];
-                    nextState = SecCKKSZoneKeyStateResettingZone;
-                }
-            } else {
-                ckksnotice("ckkskey", self, "This device isn't trusted, so don't modify the existing TLK(%@)", keyset.currentTLKPointer);
-                nextState = SecCKKSZoneKeyStateWaitForTrust;
-            }
+    if([currentState isEqualToString:SecCKKSZoneKeyStateWaitForUnlock]) {
+        ckksnotice("ckkskey", self, "Requested to enter waitforunlock");
+
+        if([flags _onqueueContains:CKKSFlagDeviceUnlocked ]) {
+            [flags _onqueueRemoveFlag:CKKSFlagDeviceUnlocked];
+            return [OctagonStateTransitionOperation named:@"key-state-after-unlock" entering:SecCKKSZoneKeyStateInitialized];
         }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateWaitForUnlock]) {
-        ckksnotice("ckkskey", self, "Requested to enter waitforunlock");
-        self.keyStateMachineOperation = [self operationToEnterState:SecCKKSZoneKeyStateInitialized keyStateError:nil named:@"key-state-after-unlock"];
-        [self.keyStateMachineOperation addNullableDependency: self.lockStateTracker.unlockDependency];
+        OctagonPendingFlag* unlocked = [[OctagonPendingFlag alloc] initWithFlag:CKKSFlagDeviceUnlocked
+                                                                     conditions:OctagonPendingConditionsDeviceUnlocked];
+        [pendingFlagHandler _onqueueHandlePendingFlag:unlocked];
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateReadyPendingUnlock]) {
-        ckksnotice("ckkskey", self, "Believe we're ready, but rechecking after unlock");
-        self.keyStateMachineOperation = [self operationToEnterState:SecCKKSZoneKeyStateInitialized keyStateError:nil named:@"key-state-after-unlock"];
-        [self.keyStateMachineOperation addNullableDependency: self.lockStateTracker.unlockDependency];
+        return nil;
+    }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateBadCurrentPointers]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateBadCurrentPointers]) {
         // The current key pointers are broken, but we're not sure why.
         ckksnotice("ckkskey", self, "Our current key pointers are reported broken. Attempting a fix!");
-        self.keyStateMachineOperation = [[CKKSHealKeyHierarchyOperation alloc] initWithCKKSKeychainView: self ckoperationGroup:self.keyHierarchyOperationGroup];
+        return [[CKKSHealKeyHierarchyOperation alloc] initWithDependencies:self.operationDependencies
+                                                                      ckks:self
+                                                                 intending:SecCKKSZoneKeyStateBecomeReady
+                                                                errorState:SecCKKSZoneKeyStateError];
+    }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateNewTLKsFailed]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateNewTLKsFailed]) {
         ckksnotice("ckkskey", self, "Creating new TLKs didn't work. Attempting to refetch!");
-        [self _onqueueKeyHierarchyFetch];
+        return [OctagonStateTransitionOperation named:@"new-tlks-failed" entering:SecCKKSZoneKeyStateBeginFetch];
+    }
 
-    } else if([state isEqualToString: SecCKKSZoneKeyStateHealTLKSharesFailed]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateHealTLKSharesFailed]) {
         ckksnotice("ckkskey", self, "Creating new TLK shares didn't work. Attempting to refetch!");
-        [self _onqueueKeyHierarchyFetch];
+        return [OctagonStateTransitionOperation named:@"heal-tlks-failed" entering:SecCKKSZoneKeyStateBeginFetch];
+    }
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateUnhealthy]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateUnhealthy]) {
         if(self.trustStatus != CKKSAccountStatusAvailable) {
             ckksnotice("ckkskey", self, "Looks like the key hierarchy is unhealthy, but we're untrusted.");
-            nextState = SecCKKSZoneKeyStateWaitForTrust;
+            return [OctagonStateTransitionOperation named:@"unhealthy-lacking-trust" entering:SecCKKSZoneKeyStateLoseTrust];
 
         } else {
             ckksnotice("ckkskey", self, "Looks like the key hierarchy is unhealthy. Launching fix.");
-            self.keyStateMachineOperation = [[CKKSHealKeyHierarchyOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:self.keyHierarchyOperationGroup];
+            return [[CKKSHealKeyHierarchyOperation alloc] initWithDependencies:self.operationDependencies
+                                                                          ckks:self
+                                                                     intending:SecCKKSZoneKeyStateBecomeReady
+                                                                    errorState:SecCKKSZoneKeyStateError];
         }
+    }
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateHealTLKShares]) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateHealTLKShares]) {
         ckksnotice("ckksshare", self, "Key hierarchy is okay, but not shared appropriately. Launching fix.");
-        self.keyStateMachineOperation = [[CKKSHealTLKSharesOperation alloc] initWithCKKSKeychainView:self
-                                                                                    ckoperationGroup:self.keyHierarchyOperationGroup];
-
-    } else if([state isEqualToString:SecCKKSZoneKeyStateProcess]) {
-        ckksnotice("ckksshare", self, "Launching key state process");
-        self.keyStateMachineOperation = [[CKKSProcessReceivedKeysStateMachineOperation alloc] initWithCKKSKeychainView: self];
-
-        // Since we're starting a reprocess, this is answering all previous requests.
-        self.keyStateProcessRequested = false;
-
-    } 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;
+        return [[CKKSHealTLKSharesOperation alloc] initWithOperationDependencies:self.operationDependencies
+                                                                            ckks:self];
     }
 
-    // Handle the key state ready dependency
-    // If we're in ready and not entering a non-ready state, we should activate the ready dependency. Otherwise, we should create it.
-    if(([state isEqualToString:SecCKKSZoneKeyStateReady] || [state isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock]) &&
-       (nextState == nil || [nextState isEqualToString:SecCKKSZoneKeyStateReady] || [nextState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock])) {
+    if([currentState isEqualToString:SecCKKSZoneKeyStateProcess]) {
+        [flags _onqueueRemoveFlag:CKKSFlagKeyStateProcessRequested];
 
-        // Ready enough!
-        [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastKeystateReady inView:self];
-
-        if(self.keyStateReadyDependency) {
-            [self scheduleOperation: self.keyStateReadyDependency];
-            self.keyStateReadyDependency = nil;
-        }
-
-        // 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];
-            [self scheduleOperation:op];
-        }
-    } else {
-        // Not in ready: we need a key state ready dependency
-        if(self.keyStateReadyDependency == nil || [self.keyStateReadyDependency isFinished]) {
-            self.keyHierarchyOperationGroup = [CKOperationGroup CKKSGroupWithName:@"key-state-broken"];
-            self.keyStateReadyDependency = [self createKeyStateReadyDependency:@"Key state has become ready again." ckoperationGroup:self.keyHierarchyOperationGroup];
-        }
+        ckksnotice("ckksshare", self, "Launching key state process");
+        return [[CKKSProcessReceivedKeysOperation alloc] initWithDependencies:self.operationDependencies
+                                                                intendedState:SecCKKSZoneKeyStateBecomeReady
+                                                                   errorState:SecCKKSZoneKeyStateError];
     }
 
-    NSAssert(!((self.keyStateMachineOperation != nil) &&
-               (nextState != nil)),
-             @"Should have a machine operation or a next state, not both");
-
-    // Start any operations, or log that we aren't
-    if(self.keyStateMachineOperation) {
-        [self scheduleOperation: self.keyStateMachineOperation];
-        ckksnotice("ckkskey", self, "Now in key state: %@", state);
-        self.keyHierarchyState = state;
+    return nil;
+}
 
-    } else if([state isEqualToString:SecCKKSZoneKeyStateError]) {
-        ckksnotice("ckkskey", self, "Entering key state 'error'");
-        self.keyHierarchyState = state;
+- (OctagonStateTransitionOperation*)tlkMissingOperation:(CKKSZoneKeyState*)newState
+{
+    WEAKIFY(self);
+    return [OctagonStateTransitionOperation named:@"tlk-missing"
+                                        intending:newState
+                                       errorState:SecCKKSZoneKeyStateError
+                              withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
+        STRONGIFY(self);
 
-    } else if(nextState == nil) {
-        ckksnotice("ckkskey", self, "Entering key state: %@", state);
-        self.keyHierarchyState = state;
+        NSArray<CKKSPeerProviderState*>* trustStates = self.operationDependencies.currentTrustStates;
 
-    } else if(![state isEqualToString: nextState]) {
-        ckksnotice("ckkskey", self, "Staying in state %@, but proceeding to %@ as soon as possible", self.keyHierarchyState, nextState);
-        self.keyStateMachineOperation = [self operationToEnterState:nextState keyStateError:nextError named:[NSString stringWithFormat:@"next-key-state-%@", nextState]];
-        [self scheduleOperation: self.keyStateMachineOperation];
+        [self.operationDependencies.databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
+            CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
 
-    } else {
-        // Nothing to do and not in a waiting state? This is likely a bug, but, hey: pretend to be in ready!
-        if(!([state isEqualToString:SecCKKSZoneKeyStateReady] || [state isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock])) {
-            ckkserror("ckkskey", self, "No action to take in state %@; BUG, but: maybe we're ready?", state);
-            nextState = SecCKKSZoneKeyStateReady;
-            self.keyStateMachineOperation = [self operationToEnterState:nextState keyStateError:nil named:@"next-key-state"];
-            [self scheduleOperation: self.keyStateMachineOperation];
-        }
-    }
+            if(keyset.error) {
+                ckkserror("ckkskey", self, "Unable to load keyset: %@", keyset.error);
+                op.nextState = newState;
 
-    // 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];
-}
+                [self.operationDependencies provideKeySet:keyset];
+                return;
+            }
 
-- (void)_onqueueHandleKeyStateNonTransientDependency:(CKKSCurrentKeySet* _Nullable)keyset {
-    dispatch_assert_queue(self.queue);
+            if(!keyset.currentTLKPointer.currentKeyUUID) {
+                // In this case, there's no current TLK at all. Go into "wait for tlkcreation";
+                op.nextState = SecCKKSZoneKeyStateWaitForTLKCreation;
+                [self.operationDependencies provideKeySet:keyset];
+                return;
+            }
 
-    if(CKKSKeyStateTransient(self.keyHierarchyState)) {
-        if(self.keyStateNonTransientDependency == nil || [self.keyStateNonTransientDependency isFinished]) {
-            self.keyStateNonTransientDependency = [self createKeyStateNontransientDependency];
-        }
-    } else {
-        // Nontransient: go for it
-        if(self.keyStateNonTransientDependency) {
-            [self scheduleOperation: self.keyStateNonTransientDependency];
-            self.keyStateNonTransientDependency = nil;
-        }
+            if(self.trustStatus != CKKSAccountStatusAvailable) {
+                ckksnotice("ckkskey", self, "TLK is missing, but no trust is present.");
+                op.nextState = SecCKKSZoneKeyStateLoseTrust;
 
-        if(keyset && keyset.currentTLKPointer.currentKeyUUID) {
-            [self _onqueueRunKeysetProviderOperations:keyset];
-        } else {
-            ckksnotice("ckkskey", self, "State machine is nontransient, but no keyset...");
-        }
-    }
-}
+                [self.operationDependencies provideKeySet:keyset];
+                return;
+            }
 
-- (NSOperation*)operationToEnterState:(CKKSZoneKeyState*)state keyStateError:(NSError* _Nullable)keyStateError named:(NSString*)name {
-    WEAKIFY(self);
+            bool otherDevicesPresent = [self _onqueueOtherDevicesReportHavingTLKs:keyset
+                                                                      trustStates:trustStates];
+            if(otherDevicesPresent) {
+                // We expect this keyset to continue to exist. Send it to our listeners.
+                [self.operationDependencies provideKeySet:keyset];
 
-    return [NSBlockOperation named:name withBlock:^{
-        STRONGIFY(self);
-        if(!self) {
+                op.nextState = newState;
+            } else {
+                ckksnotice("ckkskey", self, "No other devices claim to have the TLK. Resetting zone...");
+                op.nextState = SecCKKSZoneKeyStateResettingZone;
+            }
             return;
-        }
-        [self dispatchSyncWithAccountKeys:^bool{
-            [self _onqueueAdvanceKeyStateMachineToState:state withError:keyStateError];
-            return true;
         }];
     }];
 }
 
-- (BOOL)otherDevicesReportHavingTLKs:(CKKSCurrentKeySet*)keyset
-{
-    __block BOOL report = false;
-    [self dispatchSync:^bool{
-        report = [self _onqueueOtherDevicesReportHavingTLKs:keyset];
-        return true;
-    }];
-    return report ? YES : NO;
-}
-
 - (bool)_onqueueOtherDevicesReportHavingTLKs:(CKKSCurrentKeySet*)keyset
+                                 trustStates:(NSArray<CKKSPeerProviderState*>*)trustStates
 {
-    dispatch_assert_queue(self.queue);
-
     //Has there been any activity indicating that other trusted devices have keys in the past 45 days, or untrusted devices in the past 4?
     // (We chose 4 as devices attempt to upload their device state every 3 days. If a device is unceremoniously kicked out of circle, we normally won't immediately reset.)
     NSDate* now = [NSDate date];
 
 
     NSMutableSet<NSString*>* trustedPeerIDs = [NSMutableSet set];
-    for(CKKSPeerProviderState* trustState in self.currentTrustStates) {
+    for(CKKSPeerProviderState* trustState in trustStates) {
         for(id<CKKSPeer> peer in trustState.currentTrustedPeers) {
             [trustedPeerIDs addObject:peer.peerID];
         }
 
     NSError* localerror = nil;
 
-    NSArray<CKKSDeviceStateEntry*>* allDeviceStates = [CKKSDeviceStateEntry allInZone:self.zoneID error:&localerror];
+    NSArray<CKKSDeviceStateEntry*>* allDeviceStates = [CKKSDeviceStateEntry allInZone:keyset.currentTLKPointer.zoneID error:&localerror];
     if(localerror) {
         ckkserror("ckkskey", self, "Error fetching device states: %@", localerror);
         localerror = nil;
         // The peerIDs in CDSEs aren't written with the peer prefix. Make sure we match both.
         NSString* sosPeerID = device.circlePeerID ? [CKKSSOSPeerPrefix stringByAppendingString:device.circlePeerID] : nil;
 
-        if([trustedPeerIDs containsObject:device.circlePeerID] ||
-           [trustedPeerIDs containsObject:sosPeerID] ||
-           [trustedPeerIDs containsObject:device.octagonPeerID]) {
-            // Is this a recent DSE? If it's older than the deadline, skip it
-            if([device.storedCKRecord.modificationDate compare:trustedDeadline] == NSOrderedAscending) {
-                ckksnotice("ckkskey", self, "Trusted device state (%@) is too old; ignoring", device);
-                continue;
-            }
-        } else {
-            // Device is untrusted. How does it fare with the untrustedDeadline?
-            if([device.storedCKRecord.modificationDate compare:untrustedDeadline] == NSOrderedAscending) {
-                ckksnotice("ckkskey", self, "Device (%@) is not trusted and from too long ago; ignoring device state (%@)", device.circlePeerID, device);
-                continue;
-            } else {
-                ckksnotice("ckkskey", self, "Device (%@) is not trusted, but very recent. Including in heuristic: %@", device.circlePeerID, device);
-            }
-        }
-
-        if([device.keyState isEqualToString:SecCKKSZoneKeyStateReady] ||
-           [device.keyState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock]) {
-            ckksnotice("ckkskey", self, "Other device (%@) has keys; it should send them to us", device);
-            return true;
-        }
-    }
-
-    NSArray<CKKSTLKShareRecord*>* tlkShares = [CKKSTLKShareRecord allForUUID:keyset.currentTLKPointer.currentKeyUUID
-                                                          zoneID:self.zoneID
-                                                           error:&localerror];
-    if(localerror) {
-        ckkserror("ckkskey", self, "Error fetching device states: %@", localerror);
-        localerror = nil;
-        return false;
-    }
-
-    for(CKKSTLKShareRecord* tlkShare in tlkShares) {
-        if([trustedPeerIDs containsObject:tlkShare.senderPeerID] &&
-           [tlkShare.storedCKRecord.modificationDate compare:trustedDeadline] == NSOrderedDescending) {
-            ckksnotice("ckkskey", self, "Trusted TLK Share (%@) created recently; other devices have keys and should send them to us", tlkShare);
-            return true;
-        }
-    }
-
-    // Okay, how about the untrusted deadline?
-    for(CKKSTLKShareRecord* tlkShare in tlkShares) {
-        if([tlkShare.storedCKRecord.modificationDate compare:untrustedDeadline] == NSOrderedDescending) {
-            ckksnotice("ckkskey", self, "Untrusted TLK Share (%@) created very recently; other devices might have keys and should rejoin the circle (and send them to us)", tlkShare);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-// For this key, who doesn't yet have a valid CKKSTLKShare for it?
-// Note that we really want a record sharing the TLK to ourselves, so this function might return
-// a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
-- (NSSet<id<CKKSPeer>>*)_onqueueFindPeers:(CKKSPeerProviderState*)trustState
-                             missingShare:(CKKSKey*)key
-                           afterUploading:(NSSet<CKKSTLKShareRecord*>* _Nullable)newShares
-                                    error:(NSError* __autoreleasing*)error
-{
-    dispatch_assert_queue(self.queue);
-
-    if(!key) {
-        ckkserror("ckksshare", self, "Attempting to find missing shares for nil key");
-        return [NSSet set];
-    }
-
-    if(trustState.currentTrustedPeersError) {
-        ckkserror("ckksshare", self, "Couldn't find missing shares because trusted peers aren't available: %@", trustState.currentTrustedPeersError);
-        if(error) {
-            *error = trustState.currentTrustedPeersError;
-        }
-        return [NSSet set];
-    }
-    if(trustState.currentSelfPeersError) {
-        ckkserror("ckksshare", self, "Couldn't find missing shares because self peers aren't available: %@", trustState.currentSelfPeersError);
-        if(error) {
-            *error = trustState.currentSelfPeersError;
-        }
-        return [NSSet set];
-    }
-
-    NSMutableSet<id<CKKSPeer>>* peersMissingShares = [NSMutableSet set];
-
-    // Ensure that the 'self peer' is one of the current trusted peers. Otherwise, any TLKShare we create
-    // won't be considered trusted the next time through...
-    if(![trustState.currentTrustedPeerIDs containsObject:trustState.currentSelfPeers.currentSelf.peerID]) {
-        ckkserror("ckksshare", self, "current self peer (%@) is not in the set of trusted peers: %@",
-                  trustState.currentSelfPeers.currentSelf.peerID,
-                  trustState.currentTrustedPeerIDs);
-
-        if(error) {
-            *error = [NSError errorWithDomain:CKKSErrorDomain
-                                         code:CKKSLackingTrust
-                                  description:[NSString stringWithFormat:@"current self peer (%@) is not in the set of trusted peers",
-                                               trustState.currentSelfPeers.currentSelf.peerID]];
-        }
-
-        return nil;
-    }
-
-    for(id<CKKSRemotePeerProtocol> peer in trustState.currentTrustedPeers) {
-        if(![peer shouldHaveView:self.zoneName]) {
-            ckkserror("ckksshare", self, "Peer (%@) is not supposed to have view, skipping", peer);
-            continue;
-        }
-
-        NSError* peerError = nil;
-        // Find all the shares for this peer for this key
-        NSArray<CKKSTLKShareRecord*>* currentPeerShares = [CKKSTLKShareRecord allFor:peer.peerID
-                                                                 keyUUID:key.uuid
-                                                                  zoneID:self.zoneID
-                                                                   error:&peerError];
-
-        if(peerError) {
-            ckkserror("ckksshare", self, "Couldn't load shares for peer %@: %@", peer, peerError);
-            if(error) {
-                *error = peerError;
-            }
-            return nil;
-        }
-
-        // Include the new shares, too....
-        NSArray<CKKSTLKShareRecord*>* possiblePeerShares = newShares ? [currentPeerShares arrayByAddingObjectsFromArray:[newShares allObjects]] : currentPeerShares;
-
-        // Determine if we think this peer has enough things shared to them
-        bool alreadyShared = false;
-        for(CKKSTLKShareRecord* existingPeerShare in possiblePeerShares) {
-            // Ensure this share is to this peer...
-            if(![existingPeerShare.share.receiverPeerID isEqualToString:peer.peerID]) {
-                continue;
-            }
-
-            // If an SOS Peer sent this share, is its signature still valid? Or did the signing key change?
-            if([existingPeerShare.senderPeerID hasPrefix:CKKSSOSPeerPrefix]) {
-                NSError* signatureError = nil;
-                if(![existingPeerShare signatureVerifiesWithPeerSet:trustState.currentTrustedPeers error:&signatureError]) {
-                    ckksnotice("ckksshare", self, "Existing TLKShare's signature doesn't verify with current peer set: %@ %@", signatureError, existingPeerShare);
-                    continue;
-                }
-            }
-
-            if([existingPeerShare.tlkUUID isEqualToString:key.uuid] && [trustState.currentTrustedPeerIDs containsObject:existingPeerShare.senderPeerID]) {
-                // Was this shared to us?
-                if([peer.peerID isEqualToString: trustState.currentSelfPeers.currentSelf.peerID]) {
-                    // We only count this as 'found' if we did the sharing and it's to our current keys
-                    NSData* currentKey = trustState.currentSelfPeers.currentSelf.publicEncryptionKey.keyData;
-
-                    if([existingPeerShare.senderPeerID isEqualToString:trustState.currentSelfPeers.currentSelf.peerID] &&
-                       [existingPeerShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKey]) {
-                        ckksnotice("ckksshare", self, "Local peer %@ is shared %@ via self: %@", peer, key, existingPeerShare);
-                        alreadyShared = true;
-                        break;
-                    } else {
-                        ckksnotice("ckksshare", self, "Local peer %@ is shared %@ via trusted %@, but that's not good enough", peer, key, existingPeerShare);
-                    }
-
-                } else {
-                    // Was this shared to the remote peer's current keys?
-                    NSData* currentKeySPKI = peer.publicEncryptionKey.keyData;
-
-                    if([existingPeerShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKeySPKI]) {
-                        // Some other peer has a trusted share. Cool!
-                        ckksnotice("ckksshare", self, "Peer %@ is shared %@ via trusted %@", peer, key, existingPeerShare);
-                        alreadyShared = true;
-                        break;
-                    } else {
-                        ckksnotice("ckksshare", self, "Peer %@ has a share for %@, but to old keys: %@", peer, key, existingPeerShare);
-                    }
-                }
-            }
-        }
-
-        if(!alreadyShared) {
-            // Add this peer to our set, if it has an encryption key to receive the share
-            if(peer.publicEncryptionKey) {
-                [peersMissingShares addObject:peer];
-            }
-        }
-    }
-
-    if(peersMissingShares.count > 0u) {
-        // Log each and every one of the things
-        ckksnotice("ckksshare", self, "Missing TLK shares for %lu peers: %@", (unsigned long)peersMissingShares.count, peersMissingShares);
-        ckksnotice("ckksshare", self, "Self peers are (%@) %@", trustState.currentSelfPeersError ?: @"no error", trustState.currentSelfPeers);
-        ckksnotice("ckksshare", self, "Trusted peers are (%@) %@", trustState.currentTrustedPeersError ?: @"no error", trustState.currentTrustedPeers);
-    }
-
-    return peersMissingShares;
-}
-
-- (BOOL)_onqueueAreNewSharesSufficient:(NSSet<CKKSTLKShareRecord*>*)newShares
-                            currentTLK:(CKKSKey*)key
-                                 error:(NSError* __autoreleasing*)error
-{
-    dispatch_assert_queue(self.queue);
-
-    for(CKKSPeerProviderState* trustState in self.currentTrustStates) {
-        NSError* localError = nil;
-        NSSet<id<CKKSPeer>>* peersMissingShares = [self _onqueueFindPeers:trustState
-                                                             missingShare:key
-                                                           afterUploading:newShares
-                                                                    error:&localError];
-        if(peersMissingShares == nil || localError) {
-            if(trustState.essential) {
-                if(error) {
-                    *error = localError;
-                }
-                return NO;
-            } else {
-                ckksnotice("ckksshare", self, "Failed to find peers for nonessential system: %@", trustState);
-                // Not a hard failure.
-            }
-        }
-
-        if(peersMissingShares.count > 0) {
-            ckksnotice("ckksshare", self, "New share set is missing shares for peers: %@", peersMissingShares);
-            return NO;
-        }
-    }
-
-    return YES;
-}
-
-- (NSSet<CKKSTLKShareRecord*>*)_onqueueCreateMissingKeyShares:(CKKSKey*)key
-                                                        error:(NSError* __autoreleasing*)error
-{
-    NSError* localerror = nil;
-    NSSet<CKKSTLKShareRecord*>* newShares = nil;
-
-    // If any one of our trust states succeed, this function doesn't have an error
-    for(CKKSPeerProviderState* trustState in self.currentTrustStates) {
-        NSError* stateError = nil;
-
-        NSSet<CKKSTLKShareRecord*>* newTrustShares = [self _onqueueCreateMissingKeyShares:key
-                                                                                    peers:trustState
-                                                                                    error:&stateError];
-
-
-        if(newTrustShares && !stateError) {
-            newShares = newShares ? [newShares setByAddingObjectsFromSet:newTrustShares] : newTrustShares;
-        } else {
-            ckksnotice("ckksshare", self, "Unable to create shares for trust set %@: %@", trustState, stateError);
-            if(localerror == nil) {
-                localerror = stateError;
-            }
-        }
-    }
-
-    // Only report an error if none of the trust states were able to succeed
-    if(newShares) {
-        return newShares;
-    } else {
-        if(error && localerror) {
-            *error = localerror;
-        }
-        return nil;
-    }
-}
-
-- (NSSet<CKKSTLKShareRecord*>*)_onqueueCreateMissingKeyShares:(CKKSKey*)key
-                                                        peers:(CKKSPeerProviderState*)trustState
-                                                        error:(NSError* __autoreleasing*)error
-{
-    dispatch_assert_queue(self.queue);
-
-    if(trustState.currentTrustedPeersError) {
-        ckkserror("ckksshare", self, "Couldn't create missing shares because trusted peers aren't available: %@", trustState.currentTrustedPeersError);
-        if(error) {
-            *error = trustState.currentTrustedPeersError;
-        }
-        return nil;
-    }
-    if(trustState.currentSelfPeersError) {
-        ckkserror("ckksshare", self, "Couldn't create missing shares because self peers aren't available: %@", trustState.currentSelfPeersError);
-        if(error) {
-            *error = trustState.currentSelfPeersError;
-        }
-        return nil;
-    }
-
-    NSSet<id<CKKSPeer>>* remainingPeers = [self _onqueueFindPeers:trustState missingShare:key afterUploading:nil error:error];
-    NSMutableSet<CKKSTLKShareRecord*>* newShares = [NSMutableSet set];
-
-    if(!remainingPeers) {
-        return nil;
-    }
-
-    NSError* localerror = nil;
-
-    if(![key ensureKeyLoaded:error]) {
-        return nil;
-    }
-
-    for(id<CKKSPeer> peer in remainingPeers) {
-        if(!peer.publicEncryptionKey) {
-            ckksnotice("ckksshare", self, "No need to make TLK for %@; they don't have any encryption keys", peer);
-            continue;
-        }
-
-        // Create a share for this peer.
-        ckksnotice("ckksshare", self, "Creating share of %@ as %@ for %@", key, trustState.currentSelfPeers.currentSelf, peer);
-        CKKSTLKShareRecord* newShare = [CKKSTLKShareRecord share:key
-                                                  as:trustState.currentSelfPeers.currentSelf
-                                                  to:peer
-                                               epoch:-1
-                                            poisoned:0
-                                               error:&localerror];
-
-        if(localerror) {
-            ckkserror("ckksshare", self, "Couldn't create new share for %@: %@", peer, localerror);
-            if(error) {
-                *error = localerror;
-            }
-            return nil;
-        }
-
-        [newShares addObject: newShare];
-    }
-
-    return newShares;
-}
-
-- (CKKSZoneKeyState*)_onqueueEnsureKeyHierarchyHealth:(CKKSCurrentKeySet*)set error:(NSError* __autoreleasing *)error {
-    dispatch_assert_queue(self.queue);
-
-    if(!set.currentTLKPointer && !set.currentClassAPointer && !set.currentClassCPointer) {
-        ckkserror("ckkskey", self, "Error examining existing key hierarchy (missing all CKPs, likely no hierarchy exists): %@", set);
-        return SecCKKSZoneKeyStateWaitForTLKCreation;
-    }
-
-    // Check keyset
-    if(!set.tlk || !set.classA || !set.classC) {
-        ckkserror("ckkskey", self, "Error examining existing key hierarchy (missing at least one key): %@", set);
-        if(error) {
-            *error = set.error;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    }
-
-    NSError* localerror = nil;
-    bool probablyOkIfUnlocked = false;
-
-    // keychain being locked is not a fatal error here
-    [set.tlk loadKeyMaterialFromKeychain:&localerror];
-    if(localerror && !([localerror.domain isEqual: @"securityd"] && localerror.code == errSecInteractionNotAllowed)) {
-        ckkserror("ckkskey", self, "Error loading TLK(%@): %@", set.tlk, localerror);
-        if(error) {
-            *error = localerror;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    } else if(localerror) {
-        ckkserror("ckkskey", self, "Soft error loading TLK(%@), maybe locked: %@", set.tlk, localerror);
-        probablyOkIfUnlocked = true;
-    }
-    localerror = nil;
-
-    // keychain being locked is not a fatal error here
-    [set.classA loadKeyMaterialFromKeychain:&localerror];
-    if(localerror && !([localerror.domain isEqual: @"securityd"] && localerror.code == errSecInteractionNotAllowed)) {
-        ckkserror("ckkskey", self, "Error loading classA key(%@): %@", set.classA, localerror);
-        if(error) {
-            *error = localerror;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    } else if(localerror) {
-        ckkserror("ckkskey", self, "Soft error loading classA key(%@), maybe locked: %@", set.classA, localerror);
-        probablyOkIfUnlocked = true;
-    }
-    localerror = nil;
-
-    // keychain being locked is a fatal error here, since this is class C
-    [set.classC loadKeyMaterialFromKeychain:&localerror];
-    if(localerror) {
-        ckkserror("ckkskey", self, "Error loading classC(%@): %@", set.classC, localerror);
-        if(error) {
-            *error = localerror;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    }
-
-    // Check that the classA and classC keys point to the current TLK
-    if(![set.classA.parentKeyUUID isEqualToString: set.tlk.uuid]) {
-        localerror = [NSError errorWithDomain:CKKSServerExtensionErrorDomain
-                                         code:CKKSServerUnexpectedSyncKeyInChain
-                                     userInfo:@{
-                                                NSLocalizedDescriptionKey: @"Current class A key does not wrap to current TLK",
-                                               }];
-        ckkserror("ckkskey", self, "Key hierarchy unhealthy: %@", localerror);
-        if(error) {
-            *error = localerror;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    }
-    if(![set.classC.parentKeyUUID isEqualToString: set.tlk.uuid]) {
-        localerror = [NSError errorWithDomain:CKKSServerExtensionErrorDomain
-                                         code:CKKSServerUnexpectedSyncKeyInChain
-                                     userInfo:@{
-                                                NSLocalizedDescriptionKey: @"Current class C key does not wrap to current TLK",
-                                               }];
-        ckkserror("ckkskey", self, "Key hierarchy unhealthy: %@", localerror);
-        if(error) {
-            *error = localerror;
-        }
-        return SecCKKSZoneKeyStateUnhealthy;
-    }
-
-    self.activeTLK = [set.tlk uuid];
-
-    // Now that we're pretty sure we have the keys, are they shared appropriately?
-    // We need trust in order to proceed here
-    if(self.currentTrustStates.count == 0u) {
-        ckkserror("ckkskey", self, "Can't check TLKShares due to missing trust states");
-        return SecCKKSZoneKeyStateWaitForTrust;
-    }
-
-    // Check that every trusted peer has at least one TLK share
-    // If any trust state check works, don't error out
-    bool anyTrustStateSucceeded = false;
-    for(CKKSPeerProviderState* trustState in self.currentTrustStates) {
-        NSSet<id<CKKSPeer>>* missingShares = [self _onqueueFindPeers:trustState missingShare:set.tlk afterUploading:nil error:&localerror];
-        if(localerror && [self.lockStateTracker isLockedError: localerror]) {
-            ckkserror("ckkskey", self, "Couldn't find missing TLK shares due to lock state: %@", localerror);
-            probablyOkIfUnlocked = true;
-
-        } else if(([localerror.domain isEqualToString:TrustedPeersHelperErrorDomain] && localerror.code == TrustedPeersHelperErrorNoPreparedIdentity) ||
-                  ([localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSLackingTrust) ||
-                  ([localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSNoPeersAvailable)) {
-            ckkserror("ckkskey", self, "Couldn't find missing TLK shares due some trust issue: %@", localerror);
-
-            if(trustState.essential) {
-                ckkserror("ckkskey", self, "Trust state is considered essential; entering waitfortrust: %@", trustState);
-
-                // Octagon can reinform us when it thinks we should start again
-                self.trustStatus = CKKSAccountStatusUnknown;
-                return SecCKKSZoneKeyStateWaitForTrust;
-            } else {
-                ckkserror("ckkskey", self, "Peer provider is considered nonessential; ignoring error: %@", trustState);
-                continue;
-            }
-
-        } else if(localerror) {
-            ckkserror("ckkskey", self, "Error finding missing TLK shares: %@", localerror);
-            continue;
-        }
-
-        if(!missingShares || missingShares.count != 0u) {
-            localerror = [NSError errorWithDomain:CKKSErrorDomain code:CKKSMissingTLKShare
-                                      description:[NSString stringWithFormat:@"Missing shares for %lu peers", (unsigned long)missingShares.count]];
-            if(error) {
-                *error = localerror;
+        if([trustedPeerIDs containsObject:device.circlePeerID] ||
+           [trustedPeerIDs containsObject:sosPeerID] ||
+           [trustedPeerIDs containsObject:device.octagonPeerID]) {
+            // Is this a recent DSE? If it's older than the deadline, skip it
+            if([device.storedCKRecord.modificationDate compare:trustedDeadline] == NSOrderedAscending) {
+                ckksnotice("ckkskey", self, "Trusted device state (%@) is too old; ignoring", device);
+                continue;
             }
-            return SecCKKSZoneKeyStateHealTLKShares;
         } else {
-            ckksnotice("ckksshare", self, "TLK (%@) is shared correctly for trust state %@", set.tlk, trustState.peerProviderID);
+            // Device is untrusted. How does it fare with the untrustedDeadline?
+            if([device.storedCKRecord.modificationDate compare:untrustedDeadline] == NSOrderedAscending) {
+                ckksnotice("ckkskey", self, "Device (%@) is not trusted and from too long ago; ignoring device state (%@)", device.circlePeerID, device);
+                continue;
+            } else {
+                ckksnotice("ckkskey", self, "Device (%@) is not trusted, but very recent. Including in heuristic: %@", device.circlePeerID, device);
+            }
         }
 
-        anyTrustStateSucceeded |= true;
-    }
-
-    if(!anyTrustStateSucceeded) {
-        if(error) {
-            *error = localerror;
+        if([device.keyState isEqualToString:SecCKKSZoneKeyStateReady] ||
+           [device.keyState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock]) {
+            ckksnotice("ckkskey", self, "Other device (%@) has keys; it should send them to us", device);
+            return true;
         }
-
-        return SecCKKSZoneKeyStateError;
     }
 
-    // Got to the bottom? Cool! All keys are present and accounted for.
-    return probablyOkIfUnlocked ? SecCKKSZoneKeyStateReadyPendingUnlock : SecCKKSZoneKeyStateReady;
-}
-
-- (void)_onqueueKeyHierarchyFetch {
-    [self _onqueueKeyHierarchyFetchForReasons:[NSSet setWithArray:@[CKKSFetchBecauseKeyHierarchy]]];
-}
-
-- (void)_onqueueKeyHierarchyFetchForReasons:(NSSet<CKKSFetchBecause*>*)reasons
-{
-    dispatch_assert_queue(self.queue);
+    NSArray<CKKSTLKShareRecord*>* tlkShares = [CKKSTLKShareRecord allForUUID:keyset.currentTLKPointer.currentKeyUUID
+                                                                      zoneID:keyset.currentTLKPointer.zoneID
+                                                                       error:&localerror];
+    if(localerror) {
+        ckkserror("ckkskey", self, "Error fetching device states: %@", localerror);
+        localerror = nil;
+        return false;
+    }
 
-    WEAKIFY(self);
-    self.keyStateMachineOperation = [NSBlockOperation blockOperationWithBlock: ^{
-        STRONGIFY(self);
-        if(!self) {
-            ckkserror("ckks", self, "received callback for released object");
-            return;
+    for(CKKSTLKShareRecord* tlkShare in tlkShares) {
+        if([trustedPeerIDs containsObject:tlkShare.senderPeerID] &&
+           [tlkShare.storedCKRecord.modificationDate compare:trustedDeadline] == NSOrderedDescending) {
+            ckksnotice("ckkskey", self, "Trusted TLK Share (%@) created recently; other devices have keys and should send them to us", tlkShare);
+            return true;
         }
-        [self.launch addEvent:@"fetch-complete"];
+    }
 
-        [self dispatchSyncWithAccountKeys: ^bool{
-            [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateFetchComplete withError: nil];
+    // Okay, how about the untrusted deadline?
+    for(CKKSTLKShareRecord* tlkShare in tlkShares) {
+        if([tlkShare.storedCKRecord.modificationDate compare:untrustedDeadline] == NSOrderedDescending) {
+            ckksnotice("ckkskey", self, "Untrusted TLK Share (%@) created very recently; other devices might have keys and should rejoin the circle (and send them to us)", tlkShare);
             return true;
-        }];
-    }];
-    self.keyStateMachineOperation.name = @"waiting-for-fetch";
-
-    NSOperation* fetchOp = [self.zoneChangeFetcher requestSuccessfulFetchForManyReasons:reasons];
-    [self.keyStateMachineOperation addDependency: fetchOp];
+        }
+    }
 
-    self.keyStateFetchRequested = false;
+    return false;
 }
 
-- (void) handleKeychainEventDbConnection: (SecDbConnectionRef) dbconn
-                                  source:(SecDbTransactionSource)txionSource
-                                   added: (SecDbItemRef) added
-                                 deleted: (SecDbItemRef) deleted
-                             rateLimiter: (CKKSRateLimiter*) rateLimiter
+- (void)handleKeychainEventDbConnection:(SecDbConnectionRef) dbconn
+                                 source:(SecDbTransactionSource)txionSource
+                                  added:(SecDbItemRef) added
+                                deleted:(SecDbItemRef) deleted
+                            rateLimiter:(CKKSRateLimiter*) rateLimiter
 {
     if(!SecCKKSIsEnabled()) {
         ckksnotice("ckks", self, "Skipping handleKeychainEventDbConnection due to disabled CKKS");
     bool addedSync   = added   && SecDbItemIsSyncable(added);
     bool deletedSync = deleted && SecDbItemIsSyncable(deleted);
 
+    bool isTombstoneModification = addedTombstone && deletedTombstone;
     bool isAdd    = ( added && !deleted) || (added && deleted && !addedTombstone &&  deletedTombstone) || (added && deleted &&  addedSync && !deletedSync);
     bool isDelete = (!added &&  deleted) || (added && deleted &&  addedTombstone && !deletedTombstone) || (added && deleted && !addedSync &&  deletedSync);
     bool isModify = ( added &&  deleted) && (!isAdd) && (!isDelete);
         return;
     }
 
+    if(isTombstoneModification) {
+        ckksnotice("ckks", self, "skipping syncing update of tombstone item (%d, %d)", addedTombstone, deletedTombstone);
+        return;
+    }
+
     // It's possible to ask for an item to be deleted without adding a corresponding tombstone.
     // This is arguably a bug, as it generates an out-of-sync state, but it is in the API contract.
     // CKKS should ignore these, but log very upset messages.
     }
 
     if(txionSource == kSecDbSOSTransaction) {
-        ckksnotice("ckks", self, "Received an incoming %@ from SOS", isAdd ? @"addition" : (isModify ? @"modification" : @"deletion"));
+        NSString* addedUUID = (__bridge NSString*)SecDbItemGetValue(added, &v10itemuuid, NULL);
+        ckksnotice("ckks", self, "Received an incoming %@ from SOS (%@)",
+                   isAdd ? @"addition" : (isModify ? @"modification" : @"deletion"),
+                   addedUUID);
     }
 
     // Our caller gave us a database connection. We must get on the local queue to ensure atomicity
     // Note that we're at the mercy of the surrounding db transaction, so don't try to rollback here
-    [self dispatchSyncWithConnection: dbconn block: ^bool {
+    [self dispatchSyncWithConnection:dbconn
+                      readWriteTxion:YES
+                               block:^CKKSDatabaseTransactionResult {
         // Schedule a "view changed" notification
         [self.notifyViewChangedScheduler trigger];
 
         if(self.accountStatus == CKKSAccountStatusNoAccount) {
             // No account; CKKS shouldn't attempt anything.
-            self.droppedItems = true;
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagScanLocalItems];
             ckksnotice("ckks", self, "Dropping sync item modification due to CK account state; will scan to find changes later");
 
             // We're positively not logged into CloudKit, and therefore don't expect this item to be synced anytime particularly soon.
                 [CKKSViewManager callSyncCallbackWithErrorNoAccount: syncCallback];
             }
 
-            return true;
+            return CKKSDatabaseTransactionCommit;
         }
 
         CKKSOutgoingQueueEntry* oqe = nil;
         if       (isAdd) {
-            oqe = [CKKSOutgoingQueueEntry withItem: added   action: SecCKKSActionAdd    ckks:self error: &error];
+            oqe = [CKKSOutgoingQueueEntry withItem: added   action: SecCKKSActionAdd    zoneID:self.zoneID error: &error];
         } else if(isDelete) {
-            oqe = [CKKSOutgoingQueueEntry withItem: deleted action: SecCKKSActionDelete ckks:self error: &error];
+            oqe = [CKKSOutgoingQueueEntry withItem: deleted action: SecCKKSActionDelete zoneID:self.zoneID error: &error];
         } else if(isModify) {
-            oqe = [CKKSOutgoingQueueEntry withItem: added   action: SecCKKSActionModify ckks:self error: &error];
+            oqe = [CKKSOutgoingQueueEntry withItem: added   action: SecCKKSActionModify zoneID:self.zoneID error: &error];
         } else {
             ckkserror("ckks", self, "processKeychainEventItemAdded given garbage: %@ %@", added, deleted);
-            return true;
+            return CKKSDatabaseTransactionCommit;
+        }
+
+        if(!self.itemSyncingEnabled) {
+            // Call any callback now; they're not likely to get the sync they wanted
+            SecBoolNSErrorCallback syncCallback = [[CKKSViewManager manager] claimCallbackForUUID:oqe.uuid];
+            if(syncCallback) {
+                syncCallback(false, [NSError errorWithDomain:CKKSErrorDomain
+                                                        code:CKKSErrorViewIsPaused
+                                                 description:@"View is paused; item is not expected to sync"]);
+            }
         }
 
-        CKOperationGroup* operationGroup = [CKOperationGroup CKKSGroupWithName:@"keychain-api-use"];
+        CKOperationGroup* operationGroup = txionSource == kSecDbSOSTransaction
+            ? [CKOperationGroup CKKSGroupWithName:@"sos-incoming-item"]
+            : [CKOperationGroup CKKSGroupWithName:@"keychain-api-use"];
 
         if(error) {
             ckkserror("ckks", self, "Couldn't create outgoing queue entry: %@", error);
-            self.droppedItems = true;
-
-            // If the problem is 'no UUID', launch a scan operation to find and fix it
-            // We don't want to fix it up here, in the closing moments of a transaction
-            if([error.domain isEqualToString:CKKSErrorDomain] && error.code == CKKSNoUUIDOnItem) {
-                ckksnotice("ckks", self, "Launching scan operation to find UUID");
-                [self scanLocalItems:@"uuid-find-scan" ckoperationGroup:operationGroup after:nil];
-            }
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagScanLocalItems];
 
             // If the problem is 'couldn't load key', tell the key hierarchy state machine to fix it
             if([error.domain isEqualToString:CKKSErrorDomain] && error.code == errSecItemNotFound) {
-                [self.pokeKeyStateMachineScheduler trigger];
+                [self.stateMachine _onqueueHandleFlag:CKKSFlagKeyStateProcessRequested];
             }
 
-            return true;
+            return CKKSDatabaseTransactionCommit;
+        } else if(!oqe) {
+            ckkserror("ckks", self, "Decided that no operation needs to occur for %@", error);
+            return CKKSDatabaseTransactionCommit;
         }
 
         if(rateLimiter) {
         [oqe saveToDatabaseWithConnection: dbconn error: &error];
         if(error) {
             ckkserror("ckks", self, "Couldn't save outgoing queue entry to database: %@", error);
-            return true;
+            return CKKSDatabaseTransactionCommit;
         } else {
             ckksnotice("ckks", self, "Saved %@ to outgoing queue", oqe);
         }
 
         // This update supercedes all other local modifications to this item (_except_ those in-flight).
         // Delete all items in reencrypt or error.
-        CKKSOutgoingQueueEntry* reencryptOQE = [CKKSOutgoingQueueEntry tryFromDatabase:oqe.uuid state:SecCKKSStateReencrypt zoneID:self.zoneID error:&error];
+        NSArray<CKKSOutgoingQueueEntry*>* siblings = [CKKSOutgoingQueueEntry allWithUUID:oqe.uuid
+                                                                                  states:@[SecCKKSStateReencrypt, SecCKKSStateError]
+                                                                                  zoneID:self.zoneID
+                                                                                   error:&error];
         if(error) {
-            ckkserror("ckks", self, "Couldn't load reencrypt OQE sibling for %@: %@", oqe, error);
+            ckkserror("ckks", self, "Couldn't load OQE siblings for %@: %@", oqe, error);
         }
-        if(reencryptOQE) {
-            [reencryptOQE deleteFromDatabase:&error];
-            if(error) {
-                ckkserror("ckks", self, "Couldn't delete reencrypt OQE sibling(%@) for %@: %@", reencryptOQE, oqe, error);
+
+        for(CKKSOutgoingQueueEntry* oqeSibling in siblings) {
+            NSError* deletionError = nil;
+            [oqeSibling deleteFromDatabase:&deletionError];
+            if(deletionError) {
+                ckkserror("ckks", self, "Couldn't delete OQE sibling(%@) for %@: %@", oqeSibling, oqe.uuid, deletionError);
             }
-            error = nil;
         }
 
-        CKKSOutgoingQueueEntry* errorOQE = [CKKSOutgoingQueueEntry tryFromDatabase:oqe.uuid state:SecCKKSStateError zoneID:self.zoneID error:&error];
-        if(error) {
-            ckkserror("ckks", self, "Couldn't load error OQE sibling for %@: %@", oqe, error);
-        }
-        if(errorOQE) {
-            [errorOQE deleteFromDatabase:&error];
-            if(error) {
-                ckkserror("ckks", self, "Couldn't delete error OQE sibling(%@) for %@: %@", reencryptOQE, oqe, error);
+        // This update also supercedes any remote changes that are pending.
+        NSError* iqeError = nil;
+        CKKSIncomingQueueEntry* iqe = [CKKSIncomingQueueEntry tryFromDatabase:oqe.uuid zoneID:self.zoneID error:&iqeError];
+        if(iqeError) {
+            ckkserror("ckks", self, "Couldn't find IQE matching %@: %@", oqe.uuid, error);
+        } else if(iqe) {
+            [iqe deleteFromDatabase:&iqeError];
+            if(iqeError) {
+                ckkserror("ckks", self, "Couldn't delete IQE matching %@: %@", oqe.uuid, error);
+            } else {
+                ckksnotice("ckks", self, "Deleted IQE matching changed item %@", oqe.uuid);
             }
         }
 
         [self processOutgoingQueue:operationGroup];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
 
         STRONGIFY(self);
 
-        [self dispatchSync: ^bool {
+        [self dispatchSyncWithReadOnlySQLTransaction:^{
             NSError* error = nil;
             NSString* currentIdentifier = [NSString stringWithFormat:@"%@-%@", accessGroup, identifier];
 
                                                                         zoneID:self.zoneID
                                                                          error:&error];
             if(!cip || error) {
-                ckkserror("ckkscurrent", self, "No current item pointer for %@", currentIdentifier);
+                if([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) {
+                    // This error is common and very, very noisy. Shorten it and don't log here (the framework should log for us)
+                    ckksinfo("ckkscurrent", self, "No current item pointer for %@", currentIdentifier);
+                    error = [NSError errorWithDomain:@"securityd" code:errSecItemNotFound description:[NSString stringWithFormat:@"No current item pointer found for %@", currentIdentifier]];
+                } else {
+                    ckkserror("ckkscurrent", self, "No current item pointer for %@", currentIdentifier);
+                }
                 complete(nil, error);
-                return false;
+                return;
             }
 
             if(!cip.currentItemUUID) {
                 complete(nil, [NSError errorWithDomain:CKKSErrorDomain
                                                   code:errSecInternalError
                                            description:@"Current item pointer is empty"]);
-                return false;
+                return;
             }
 
             ckksinfo("ckkscurrent", self, "Retrieved current item pointer: %@", cip);
             complete(cip.currentItemUUID, NULL);
-            return true;
+            return;
         }];
     }];
 
     [self scheduleOperation: getCurrentItem];
 }
 
-- (CKKSKey*) keyForItem: (SecDbItemRef) item error: (NSError * __autoreleasing *) error {
-    CKKSKeyClass* class = nil;
-
-    NSString* protection = (__bridge NSString*)SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
-    if([protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked]) {
-        class = SecCKKSKeyClassA;
-    } else if([protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAlwaysPrivate] ||
-              [protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAfterFirstUnlock]) {
-        class = SecCKKSKeyClassC;
-    } else {
-        NSError* localError = [NSError errorWithDomain:CKKSErrorDomain
-                                                  code:CKKSInvalidKeyClass
-                                           description:[NSString stringWithFormat:@"can't pick key class for protection %@", protection]];
-        ckkserror("ckks", self, "can't pick key class: %@ %@", localError, item);
-        if(error) {
-            *error = localError;
-        }
-
-        return nil;
-    }
-
-    NSError* currentKeyError = nil;
-    CKKSKey* key = [CKKSKey currentKeyForClass: class zoneID:self.zoneID error:&currentKeyError];
-    if(!key || currentKeyError) {
-        ckkserror("ckks", self, "Couldn't find current key for %@: %@", class, currentKeyError);
-
-        if(error) {
-            *error = currentKeyError;
-        }
-        return nil;
-    }
-
-    // and make sure it's unwrapped.
-    NSError* loadedError = nil;
-    if(![key ensureKeyLoaded:&loadedError]) {
-        ckkserror("ckks", self, "Couldn't load key(%@): %@", key, loadedError);
-        if(error) {
-            *error = loadedError;
-        }
-        return nil;
-    }
-
-    return key;
-}
-
-- (CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*)findKeySet
+- (CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*)findKeySet:(BOOL)refetchBeforeReturningKeySet
 {
     __block CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = nil;
+    __block BOOL moveFromWaitForTrust = NO;
 
-    [self dispatchSyncWithAccountKeys:^bool {
-        CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
-        if(keyset.currentTLKPointer.currentKeyUUID && keyset.tlk.uuid) {
-            ckksnotice("ckks", self, "Already have keyset %@", keyset);
-
-            keysetOp = [[CKKSProvideKeySetOperation alloc] initWithZoneName:self.zoneName keySet:keyset];
-            [self scheduleOperationWithoutDependencies:keysetOp];
-            return true;
-        } else if([self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload]) {
-            CKKSCurrentKeySet* proposedKeySet = self.lastNewTLKOperation.keyset;
-            ckksnotice("ckks", self, "Already have proposed keyset %@", proposedKeySet);
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
+        keysetOp = (CKKSProvideKeySetOperation*)[self findFirstPendingOperation:self.operationDependencies.keysetProviderOperations];
+        if(!keysetOp) {
+            keysetOp = [[CKKSProvideKeySetOperation alloc] initWithZoneName:self.zoneName];
+            [self.operationDependencies.keysetProviderOperations addObject:keysetOp];
 
-            keysetOp = [[CKKSProvideKeySetOperation alloc] initWithZoneName:self.zoneName keySet:proposedKeySet];
+            // This is an abuse of operations: they should generally run when added to a queue, not wait, but this allows recipients to set timeouts
             [self scheduleOperationWithoutDependencies:keysetOp];
-            return true;
-        } else {
-            // No existing keyset (including keys) exists.
-            // The state machine will know what to do!
-            self.tlkCreationRequested = true;
+        }
 
-            ckksnotice("ckks", self, "Received a keyset request; forwarding to state machine");
+        if(refetchBeforeReturningKeySet) {
+            ckksnotice("ckks", self, "Refetch requested before returning key set!");
 
-            keysetOp = (CKKSProvideKeySetOperation*) [self findFirstPendingOperation:self.keysetProviderOperations];
-            if(!keysetOp) {
-                keysetOp = [[CKKSProvideKeySetOperation alloc] initWithZoneName:self.zoneName];
-                [self.keysetProviderOperations addObject:keysetOp];
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagFetchRequested];
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
 
-                // This is an abuse of operations: they should generally run when added to a queue, not wait, but this allows recipients to set timeouts
-                [self scheduleOperationWithoutDependencies:keysetOp];
+            if([self.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateWaitForTrust]) {
+                moveFromWaitForTrust = YES;
             }
-
-            [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
+            return;
         }
 
-        return true;
-    }];
+        CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
+        if(keyset.currentTLKPointer.currentKeyUUID &&
+           (keyset.tlk.uuid ||
+            [self.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateWaitForTrust] ||
+            [self.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateWaitForTLK])) {
+            ckksnotice("ckks", self, "Already have keyset %@", keyset);
 
-    return keysetOp;
-}
+            [keysetOp provideKeySet:keyset];
+            return;
 
-- (void)_onqueueRunKeysetProviderOperations:(CKKSCurrentKeySet*)keyset
-{
-    ckksnotice("ckkskey", self, "Providing keyset (%@) to listeners", keyset);
+        } else if([self.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateWaitForTrust]) {
+            // No keyset exists, but we're in waitfortrust? Seems like a bug. Move us out of this state...
 
-    // We have some keyset; they can ask again if they want a new one
-    self.tlkCreationRequested = false;
+            ckksnotice("ckks", self, "Received a keyset request in an odd state; forwarding to state machine");
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
+            moveFromWaitForTrust = YES;
 
-    for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in self.keysetProviderOperations) {
-        if([op isPending]) {
-            [op provideKeySet:keyset];
-        }
+        } else {
+            // The key state machine will know what to do.
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
+        };
+    }];
+
+    if(moveFromWaitForTrust) {
+        [self.stateMachine handleExternalRequest:[[OctagonStateTransitionRequest alloc] init:@"fix-bug"
+                                                                                sourceStates:[NSSet setWithObject:SecCKKSZoneKeyStateWaitForTrust]
+                                                                                 serialQueue:self.queue
+                                                                                     timeout:5 * NSEC_PER_SEC
+                                                                                transitionOp:[OctagonStateTransitionOperation named:@"fix-bug"
+                                                                                                                           entering:SecCKKSZoneKeyStateWaitForTLKCreation]]];
     }
+
+    return keysetOp;
 }
 
 - (void)receiveTLKUploadRecords:(NSArray<CKRecord*>*)records
         return;
     }
 
-    [self dispatchSyncWithAccountKeys:^bool {
-
+    [self dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         for(CKRecord* record in zoneRecords) {
             [self _onqueueCKRecordChanged:record resync:false];
         }
 
-        return true;
+        [self.stateMachine _onqueueHandleFlag:CKKSFlagKeyStateTLKsUploaded];
+
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
+- (BOOL)requiresTLKUpload
+{
+    __block BOOL requiresUpload = NO;
+    dispatch_sync(self.queue, ^{
+        // We want to return true only if we're in a state that immediately requires an upload.
+        if(([self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload] ||
+            [self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation])) {
+            requiresUpload = YES;
+        }
+    });
+
+    return requiresUpload;
+}
+
 // Use the following method to find the first pending operation in a weak collection
 - (NSOperation*)findFirstPendingOperation: (NSHashTable*) table {
     return [self findFirstPendingOperation:table ofClass:nil];
     }
 }
 
-// Use the following method to count the pending operations in a weak collection
-- (int64_t)countPendingOperations: (NSHashTable*) table {
-    @synchronized(table) {
-        int count = 0;
-        for(NSOperation* op in table) {
-            if(op != nil && !([op isExecuting] || [op isFinished])) {
-                count++;
-            }
-        }
-        return count;
-    }
-}
-
-- (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup*)ckoperationGroup {
+- (CKKSOutgoingQueueOperation*)processOutgoingQueue:(CKOperationGroup* _Nullable)ckoperationGroup {
     return [self processOutgoingQueueAfter:nil ckoperationGroup:ckoperationGroup];
 }
 
-- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
+- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation* _Nullable)after
+                                        ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup {
     return [self processOutgoingQueueAfter:after requiredDelay:DISPATCH_TIME_FOREVER ckoperationGroup:ckoperationGroup];
 }
 
-- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation*)after
+- (CKKSOutgoingQueueOperation*)processOutgoingQueueAfter:(CKKSResultOperation* _Nullable)after
                                            requiredDelay:(uint64_t)requiredDelay
-                                        ckoperationGroup:(CKOperationGroup*)ckoperationGroup
+                                        ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup
 {
     CKKSOutgoingQueueOperation* outgoingop =
             (CKKSOutgoingQueueOperation*) [self findFirstPendingOperation:self.outgoingQueueOperations
             }
 
             // Will log any pending dependencies as well
-            ckksnotice("ckksoutgoing", self, "Returning existing %@", outgoingop);
+            ckksinfo("ckksoutgoing", self, "Returning existing %@", outgoingop);
 
             // Shouldn't be necessary, but can't hurt
             [self.outgoingQueueOperationScheduler triggerAt:requiredDelay];
         }
     }
 
-    CKKSOutgoingQueueOperation* op = [[CKKSOutgoingQueueOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:ckoperationGroup];
+    CKKSOutgoingQueueOperation* op = [[CKKSOutgoingQueueOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                         ckks:self
+                                                                                    intending:SecCKKSZoneKeyStateReady
+                                                                                   errorState:SecCKKSZoneKeyStateUnhealthy
+                                                                             ckoperationGroup:ckoperationGroup];
     op.name = @"outgoing-queue-operation";
     [op addNullableDependency:after];
     [op addNullableDependency:self.outgoingQueueOperationScheduler.operationDependency];
 }
 
 - (CKKSIncomingQueueOperation*) processIncomingQueue:(bool)failOnClassA after: (CKKSResultOperation*) after {
+    return [self processIncomingQueue:failOnClassA after:after policyConsideredAuthoritative:false];
+}
+
+- (CKKSIncomingQueueOperation*)processIncomingQueue:(bool)failOnClassA
+                                              after:(CKKSResultOperation*)after
+                      policyConsideredAuthoritative:(bool)policyConsideredAuthoritative
+{
     CKKSIncomingQueueOperation* incomingop = (CKKSIncomingQueueOperation*) [self findFirstPendingOperation:self.incomingQueueOperations];
     if(incomingop) {
         ckksinfo("ckks", self, "Skipping processIncomingQueue due to at least one pending instance");
         // check (again) for race condition; if the op has started we need to add another (for the dependency)
         if([incomingop isPending]) {
             incomingop.errorOnClassAFailure |= failOnClassA;
+            incomingop.handleMismatchedViewItems |= policyConsideredAuthoritative;
             return incomingop;
         }
     }
 
-    CKKSIncomingQueueOperation* op = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:self errorOnClassAFailure:failOnClassA];
+    CKKSIncomingQueueOperation* op = [[CKKSIncomingQueueOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                         ckks:self
+                                                                                    intending:SecCKKSZoneKeyStateReady
+                                                                                   errorState:SecCKKSZoneKeyStateUnhealthy
+                                                                         errorOnClassAFailure:failOnClassA
+                                                                        handleMismatchedViewItems:policyConsideredAuthoritative];
     op.name = @"incoming-queue-operation";
     if(after != nil) {
         [op addSuccessDependency: after];
     if(self.resultsOfNextIncomingQueueOperationOperation) {
         [self.resultsOfNextIncomingQueueOperationOperation addSuccessDependency:op];
         [self scheduleOperation:self.resultsOfNextIncomingQueueOperationOperation];
+        self.resultsOfNextIncomingQueueOperationOperation = nil;
     }
 
     [self scheduleOperation: op];
         }
     }
 
-    scanOperation = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:self ckoperationGroup:operationGroup];
+    scanOperation = [[CKKSScanLocalItemsOperation alloc] initWithDependencies:self.operationDependencies
+                                                                         ckks:self
+                                                                    intending:SecCKKSZoneKeyStateReady
+                                                                   errorState:SecCKKSZoneKeyStateError
+                                                             ckoperationGroup:operationGroup];
     scanOperation.name = operationName;
 
     [scanOperation addNullableDependency:self.lastFixupOperation];
 
     [scanOperation linearDependencies:self.scanLocalItemsOperations];
 
+    // This might generate items for upload. Make sure that any uploads wait until the scan is complete, so we know what to upload
+    [scanOperation linearDependencies:self.outgoingQueueOperations];
+
     [self scheduleOperation:scanOperation];
+    self.initiatedLocalScan = YES;
     return scanOperation;
 }
 
 - (CKKSUpdateDeviceStateOperation*)updateDeviceState:(bool)rateLimit
                    waitForKeyHierarchyInitialization:(uint64_t)timeout
                                     ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
-
-    WEAKIFY(self);
-
     // If securityd just started, the key state might be in some transient early state. Wait a bit.
-    CKKSResultOperation* waitForKeyReady = [CKKSResultOperation named:@"device-state-wait" withBlock:^{
-        STRONGIFY(self);
-        ckksnotice("ckksdevice", self, "Finished waiting for key hierarchy transient state, currently %@", self.keyHierarchyState);
-    }];
-
-    [waitForKeyReady addNullableDependency:self.keyStateNonTransientDependency];
-    [waitForKeyReady timeout:timeout];
-    [self.waitingQueue addOperation:waitForKeyReady];
+    OctagonStateMultiStateArrivalWatcher* waitForTransient = [[OctagonStateMultiStateArrivalWatcher alloc] initNamed:@"rpc-watcher"
+                                                                                                         serialQueue:self.queue
+                                                                                                              states:CKKSKeyStateNonTransientStates()];
+    [waitForTransient timeout:timeout];
+    [self.stateMachine registerMultiStateArrivalWatcher:waitForTransient];
 
     CKKSUpdateDeviceStateOperation* op = [[CKKSUpdateDeviceStateOperation alloc] initWithCKKSKeychainView:self rateLimit:rateLimit ckoperationGroup:ckoperationGroup];
     op.name = @"device-state-operation";
 
-    [op addDependency: waitForKeyReady];
+    [op addDependency:waitForTransient.result];
 
     // op modifies the CloudKit zone, so it should insert itself into the list of OutgoingQueueOperations.
     // Then, we won't have simultaneous zone-modifying operations and confuse ourselves.
     return op;
 }
 
+- (void)xpc24HrNotification
+{
+    // Called roughly once every 24hrs
+    [self.stateMachine handleFlag:CKKSFlag24hrNotification];
+}
+
 // There are some errors which won't be reported but will be reflected in the CDSE; any error coming out of here is fatal
 - (CKKSDeviceStateEntry*)_onqueueCurrentDeviceStateEntry: (NSError* __autoreleasing*)error {
+    dispatch_assert_queue(self.queue);
     NSError* localerror = nil;
 
     CKKSAccountStateTracker* accountTracker = self.accountTracker;
     return op;
 }
 
-- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because {
-    return [self fetchAndProcessCKChanges:because after:nil];
-}
-
-- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because after:(CKKSResultOperation*)after {
-    if(!SecCKKSIsEnabled()) {
+- (CKKSResultOperation*)fetchAndProcessCKChanges:(CKKSFetchBecause*)because
+{
+     if(!SecCKKSIsEnabled()) {
         ckksinfo("ckks", self, "Skipping fetchAndProcessCKChanges due to disabled CKKS");
         return nil;
     }
 
-    if(after) {
-        [self.zoneChangeFetcher holdFetchesUntil:after];
-    }
-
-    // We fetched some changes; try to process them!
+     // We fetched some changes; try to process them!
     return [self processIncomingQueue:false after:[self.zoneChangeFetcher requestSuccessfulFetch:because]];
 }
 
-- (CKKSResultOperation*)fetchAndProcessCKChangesDueToAPNS:(CKRecordZoneNotification*)notification {
-    if(!SecCKKSIsEnabled()) {
-        ckksinfo("ckks", self, "Skipping fetchAndProcessCKChanges due to disabled CKKS");
-        return nil;
-    }
-
-    CKKSResultOperation *fetchOp = [self.zoneChangeFetcher requestFetchDueToAPNS:notification];
-    if (fetchOp == nil) {
-        ckksnotice("ckks", self, "Skipping push induced processCKChanges due to zones are not ready");
-        return nil;
-    }
-
-    // We fetched some changes; try to process them!
-    return [self processIncomingQueue:false after:fetchOp];
-}
-
 // Lets the view know about a failed CloudKit write. If the error is "already have one of these records", it will
 // store the new records and kick off the new processing
 //
                     // The server thinks the classA/C synckeys don't wrap directly the to top TLK, but we don't (otherwise, we would have fixed it).
                     // Issue a key hierarchy fetch and see what's what.
                     ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@; requesting refetch and reprocess of key hierarchy", thirdLevelError, recordID);
-                    [self _onqueueKeyStateMachineRequestFetch];
+                    [self.stateMachine _onqueueHandleFlag:CKKSFlagFetchRequested];
 
                 } else if(thirdLevelError.code == CKKSServerMissingRecord) {
                     // The server is concerned that there's a missing record somewhere.
                     // Issue a key hierarchy fetch and see what's happening
                     ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@; requesting refetch and reprocess of key hierarchy", thirdLevelError, recordID);
-                    [self _onqueueKeyStateMachineRequestFetch];
+                    [self.stateMachine _onqueueHandleFlag:CKKSFlagFetchRequested];
 
                 } else {
                     ckkserror("ckks", self, "CKKS Server extension has told us about %@ for record %@, but we don't currently handle this error", thirdLevelError, recordID);
     // TODO: resync doesn't really mean much here; what does it mean for a record to be 'deleted' if you're fetching from scratch?
 
     if([recordType isEqual: SecCKRecordItemType]) {
-        ckksinfo("ckks", self, "CloudKit notification: deleted record(%@): %@", recordType, recordID);
+        ckksnotice("ckks", self, "CloudKit notification: deleted record(%@): %@", recordType, recordID);
         NSError* error = nil;
         NSError* iqeerror = nil;
         CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase: [recordID recordName] zoneID:self.zoneID error: &error];
             if(iqeerror) {
                 ckkserror("ckks", self, "Couldn't save incoming queue entry: %@", iqeerror);
             }
+
+            // Delete any pending local changes; this delete wins
+            NSArray<CKKSOutgoingQueueEntry*>* siblings = [CKKSOutgoingQueueEntry allWithUUID:iqe.uuid
+                                                                                      states:@[SecCKKSStateNew,
+                                                                                               SecCKKSStateReencrypt,
+                                                                                               SecCKKSStateError]
+                                                                                      zoneID:self.zoneID
+                                                                                       error:&error];
+            if(error) {
+                ckkserror("ckks", self, "Couldn't load OQE sibling for %@: %@", iqe.uuid, error);
+            }
+
+            for(CKKSOutgoingQueueEntry* oqe in siblings) {
+                NSError* deletionError = nil;
+                [oqe deleteFromDatabase:&deletionError];
+                if(deletionError) {
+                    ckkserror("ckks", self, "Couldn't delete OQE sibling(%@) for %@: %@", oqe, iqe.uuid, deletionError);
+                }
+            }
         }
         ckksinfo("ckks", self, "CKKSMirrorEntry was deleted: %@ %@ error: %@", recordID, ckme, error);
         // TODO: actually pass error back up
     if(ckme) {
         if([ckme matchesCKRecord:record] && !resync) {
             // This is almost certainly a record we uploaded; CKFetchChanges sends them back as new records
-            ckksnotice("ckks", self, "CloudKit has told us of record we already know about; skipping update");
+            ckksnotice("ckks", self, "CloudKit has told us of record we already know about for %@; skipping update", ckme.uuid);
             return;
         }
 
     if(error) {
         ckkserror("ckks", self, "couldn't save new CKRecord to database: %@ %@", record, error);
     } else {
-        ckksdebug("ckks", self, "CKKSMirrorEntry was created: %@", ckme);
+        ckksinfo("ckks", self, "CKKSMirrorEntry was created: %@", ckme);
     }
 
     NSError* iqeerror = nil;
     if(iqeerror) {
         ckkserror("ckks", self, "Couldn't save modified incoming queue entry: %@", iqeerror);
     } else {
-        ckksdebug("ckks", self, "CKKSIncomingQueueEntry was created: %@", iqe);
+        ckksinfo("ckks", self, "CKKSIncomingQueueEntry was created: %@", iqe);
     }
 
     // A remote change has occured for this record. Delete any pending local changes; they will be overwritten.
-    CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase:ckme.uuid state: SecCKKSStateNew zoneID:self.zoneID error: &error];
+    NSArray<CKKSOutgoingQueueEntry*>* siblings = [CKKSOutgoingQueueEntry allWithUUID:iqe.uuid
+                                                                              states:@[SecCKKSStateNew,
+                                                                                       SecCKKSStateReencrypt,
+                                                                                       SecCKKSStateError]
+                                                                              zoneID:self.zoneID
+                                                                               error:&error];
     if(error) {
-        ckkserror("ckks", self, "Couldn't load OutgoingQueueEntry: %@", error);
-    }
-    if(oqe) {
-        [self _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&error];
+        ckkserror("ckks", self, "Couldn't load OQE sibling for %@: %@", iqe.uuid, error);
     }
 
-    // Reencryptions are pending changes too
-    oqe = [CKKSOutgoingQueueEntry tryFromDatabase:ckme.uuid state: SecCKKSStateReencrypt zoneID:self.zoneID error: &error];
-    if(error) {
-        ckkserror("ckks", self, "Couldn't load reencrypted OutgoingQueueEntry: %@", error);
-    }
-    if(oqe) {
-        [oqe deleteFromDatabase:&error];
-        if(error) {
-            ckkserror("ckks", self, "Couldn't delete reencrypted oqe(%@): %@", oqe, error);
+    for(CKKSOutgoingQueueEntry* oqe in siblings) {
+        NSError* deletionError = nil;
+        [oqe deleteFromDatabase:&deletionError];
+        if(deletionError) {
+            ckkserror("ckks", self, "Couldn't delete OQE sibling(%@) for %@: %@", oqe, iqe.uuid, deletionError);
         }
     }
 }
     }
 
     // We've saved a new key in the database; trigger a rekey operation.
-    [self _onqueueKeyStateMachineRequestProcess];
+    [self.stateMachine _onqueueHandleFlag:CKKSFlagKeyStateProcessRequested];
 }
 
 - (void)_onqueueCKRecordTLKShareChanged:(CKRecord*)record resync:(bool)resync {
         ckkserror("ckksshare", self, "Couldn't save new TLK share to database: %@ %@", share, error);
     }
 
-    [self _onqueueKeyStateMachineRequestProcess];
+    [self.stateMachine _onqueueHandleFlag:CKKSFlagKeyStateProcessRequested];
 }
 
 - (void)_onqueueCKRecordCurrentKeyPointerChanged:(CKRecord*)record resync:(bool)resync {
         ckksnotice("ckkskey", self, "Current key pointer modification doesn't change anything interesting; skipping reprocess: %@", record);
     } else {
         // We've saved a new key in the database; trigger a rekey operation.
-        [self _onqueueKeyStateMachineRequestProcess];
+        [self.stateMachine _onqueueHandleFlag:CKKSFlagKeyStateProcessRequested];
     }
 }
 
 
 - (void)_onqueueCKRecordManifestChanged:(CKRecord*)record resync:(bool)resync
 {
+    dispatch_assert_queue(self.queue);
     NSError* error = nil;
     CKKSPendingManifest* manifest = [[CKKSPendingManifest alloc] initWithCKRecord:record];
     [manifest saveToDatabase:&error];
 
 - (void)_onqueueCKRecordManifestLeafChanged:(CKRecord*)record resync:(bool)resync
 {
+    dispatch_assert_queue(self.queue);
     NSError* error = nil;
     CKKSManifestLeafRecord* manifestLeaf = [[CKKSManifestPendingLeafRecord alloc] initWithCKRecord:record];
     [manifestLeaf saveToDatabase:&error];
 }
 
 - (void)_onqueueCKRecordDeviceStateChanged:(CKRecord*)record resync:(bool)resync {
+    dispatch_assert_queue(self.queue);
     if(resync) {
         NSError* dserror = nil;
         CKKSDeviceStateEntry* cdse  = [CKKSDeviceStateEntry tryFromDatabase:record.recordID.recordName zoneID:self.zoneID error:&dserror];
 }
 
 - (bool)_onqueueResetAllInflightOQE:(NSError**)error {
+    dispatch_assert_queue(self.queue);
     NSError* localError = nil;
 
     while(true) {
 
         if(newOQE) {
             ckksnotice("ckksoutgoing", self, "New modification has come in behind inflight %@; dropping failed change", oqe);
-            // recurse for that lovely code reuse
-            [self _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&localerror];
-            if(localerror) {
-                ckkserror("ckksoutgoing", self, "Couldn't delete in-flight OQE: %@", localerror);
-                if(error) {
-                    *error = localerror;
-                }
-            }
-        } else {
-            oqe.state = state;
-            [oqe saveToDatabase: &localerror];
-            if(localerror) {
-                ckkserror("ckks", self, "Couldn't save %@ as %@: %@", oqe, state, localerror);
-            }
-        }
-
-    } else {
-        oqe.state = state;
-        [oqe saveToDatabase: &localerror];
-        if(localerror) {
-            ckkserror("ckks", self, "Couldn't save %@ as %@: %@", oqe, state, localerror);
-        }
-    }
-
-    if(error && localerror) {
-        *error = localerror;
-    }
-    return localerror == nil;
-}
-
-- (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error {
-    dispatch_assert_queue(self.queue);
-
-    SecBoolNSErrorCallback callback = [[CKKSViewManager manager] claimCallbackForUUID:oqe.uuid];
-    if(callback) {
-        callback(false, itemError);
-    }
-    NSError* localerror = nil;
-
-    // Now, delete the OQE: it's never coming back
-    [oqe deleteFromDatabase:&localerror];
-    if(localerror) {
-        ckkserror("ckks", self, "Couldn't delete %@ (due to error %@): %@", oqe, itemError, localerror);
-    }
-
-    if(error && localerror) {
-        *error = localerror;
-    }
-    return localerror == nil;
-}
-
-- (bool)_onqueueUpdateLatestManifestWithError:(NSError**)error
-{
-    dispatch_assert_queue(self.queue);
-    CKKSManifest* manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:error];
-    if (manifest) {
-        self.latestManifest = manifest;
-        return true;
-    }
-    else {
-        return false;
-    }
-}
-
-- (bool)_onqueueWithAccountKeysCheckTLK:(CKKSKey*)proposedTLK error:(NSError* __autoreleasing *)error {
-    dispatch_assert_queue(self.queue);
-    // First, if we have a local identity, check for any TLK shares
-    NSError* localerror = nil;
-
-    if(![proposedTLK wrapsSelf]) {
-        localerror = [NSError errorWithDomain:CKKSErrorDomain code:CKKSKeyNotSelfWrapped description:[NSString stringWithFormat:@"Potential TLK %@ doesn't wrap itself: %@", proposedTLK, proposedTLK.parentKeyUUID] underlying:NULL];
-        ckkserror("ckksshare", self, "%@", localerror);
-        if (error) {
-            *error = localerror;
-        }
-    } else {
-        bool tlkShares = [self _onqueueWithAccountKeysCheckTLKFromShares:proposedTLK error:&localerror];
-        // We only want to error out if a positive error occurred. "No shares" is okay.
-        if(!tlkShares || localerror) {
-            bool noTrustedTLKShares = [localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSNoTrustedTLKShares;
-            bool noSelfPeer = [localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSNoEncryptionKey;
-            bool noTrust = [localerror.domain isEqualToString:CKKSErrorDomain] && localerror.code == CKKSLackingTrust;
-
-            // If this error was something worse than 'couldn't unwrap for reasons including there not being data', report it
-            if(!(noTrustedTLKShares || noSelfPeer || noTrust)) {
+            // recurse for that lovely code reuse
+            [self _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&localerror];
+            if(localerror) {
+                ckkserror("ckksoutgoing", self, "Couldn't delete in-flight OQE: %@", localerror);
                 if(error) {
                     *error = localerror;
                 }
-                ckkserror("ckksshare", self, "Errored unwrapping TLK with TLKShares: %@", localerror);
-                return false;
-            } else {
-                ckkserror("ckksshare", self, "Non-fatal error unwrapping TLK with TLKShares: %@", localerror);
+            }
+        } else {
+            oqe.state = state;
+            [oqe saveToDatabase: &localerror];
+            if(localerror) {
+                ckkserror("ckks", self, "Couldn't save %@ as %@: %@", oqe, state, localerror);
             }
         }
-    }
 
-    if([proposedTLK loadKeyMaterialFromKeychain:error]) {
-        // Hurray!
-        return true;
     } else {
-        return false;
-    }
-}
-
-// This version only examines if this TLK is recoverable from TLK shares
-- (bool)_onqueueWithAccountKeysCheckTLKFromShares:(CKKSKey*)proposedTLK error:(NSError* __autoreleasing *)error {
-    // But being recoverable from any trust set is okay
-    NSError* localerror = nil;
-
-    if(self.currentTrustStates.count == 0u) {
-        if(error) {
-            *error = [NSError errorWithDomain:CKKSErrorDomain
-                                         code:CKKSLackingTrust
-                                  description:@"No current trust states; can't check TLK"];
-        }
-        return false;
-    }
-
-    for(CKKSPeerProviderState* trustState in self.currentTrustStates) {
-        ckkserror("ckksshare", self, "Checking TLK from trust state %@", trustState);
-        bool recovered = [self _onqueueWithAccountKeysWithPeers:trustState
-                                                       checkTLK:proposedTLK
-                                                          error:&localerror];
-
-        if(recovered) {
-            ckkserror("ckksshare", self, "Recovered the TLK");
-            return true;
+        oqe.state = state;
+        [oqe saveToDatabase: &localerror];
+        if(localerror) {
+            ckkserror("ckks", self, "Couldn't save %@ as %@: %@", oqe, state, localerror);
         }
-
-        ckkserror("ckksshare", self, "Unable to recover TLK from trust set: %@", localerror);
     }
 
-    // Only report the last error
     if(error && localerror) {
         *error = localerror;
     }
-    return false;
+    return localerror == nil;
 }
 
-- (bool)_onqueueWithAccountKeysWithPeers:(CKKSPeerProviderState*)trustState
-                                checkTLK:(CKKSKey*)proposedTLK
-                                  error:(NSError* __autoreleasing *)error
-{
-    NSError* localerror = NULL;
-    if(!trustState.currentSelfPeers.currentSelf || trustState.currentSelfPeersError) {
-        ckkserror("ckksshare", self, "Don't have self peers for %@: %@", trustState.peerProviderID, trustState.currentSelfPeersError);
-        if(error) {
-            if([self.lockStateTracker isLockedError:trustState.currentSelfPeersError]) {
-                // Locked error should propagate
-                *error = trustState.currentSelfPeersError;
-            } else {
-                *error = [NSError errorWithDomain:CKKSErrorDomain
-                                             code:CKKSNoEncryptionKey
-                                      description:@"No current self peer"
-                                       underlying:trustState.currentSelfPeersError];
-            }
-        }
-        return false;
-    }
+- (bool)_onqueueErrorOutgoingQueueEntry: (CKKSOutgoingQueueEntry*) oqe itemError: (NSError*) itemError error: (NSError* __autoreleasing*) error {
+    dispatch_assert_queue(self.queue);
 
-    if(!trustState.currentTrustedPeers || trustState.currentTrustedPeersError) {
-        ckkserror("ckksshare", self, "Don't have trusted peers: %@", trustState.currentTrustedPeersError);
-        if(error) {
-            *error = [NSError errorWithDomain:CKKSErrorDomain
-                                         code:CKKSNoPeersAvailable
-                                  description:@"No trusted peers"
-                                   underlying:trustState.currentTrustedPeersError];
-        }
-        return false;
+    SecBoolNSErrorCallback callback = [[CKKSViewManager manager] claimCallbackForUUID:oqe.uuid];
+    if(callback) {
+        callback(false, itemError);
     }
+    NSError* localerror = nil;
 
-    NSError* lastShareError = nil;
-
-    for(id<CKKSSelfPeer> selfPeer in trustState.currentSelfPeers.allSelves) {
-        NSArray<CKKSTLKShareRecord*>* possibleShares = [CKKSTLKShareRecord allFor:selfPeer.peerID
-                                                              keyUUID:proposedTLK.uuid
-                                                               zoneID:self.zoneID
-                                                                error:&localerror];
-        if(localerror) {
-            ckkserror("ckksshare", self, "Error fetching CKKSTLKShares for %@: %@", selfPeer, localerror);
-        }
-
-        if(possibleShares.count == 0) {
-            ckksnotice("ckksshare", self, "No CKKSTLKShares to %@ for %@", selfPeer, proposedTLK);
-            continue;
-        }
-
-        for(CKKSTLKShareRecord* possibleShare in possibleShares) {
-            NSError* possibleShareError = nil;
-            ckksnotice("ckksshare", self, "Checking possible TLK share %@ as %@", possibleShare, selfPeer);
-
-            CKKSKey* possibleKey = [possibleShare recoverTLK:selfPeer
-                                                trustedPeers:trustState.currentTrustedPeers
-                                                       error:&possibleShareError];
-
-            if(possibleShareError) {
-                ckkserror("ckksshare", self, "Unable to unwrap TLKShare(%@) as %@: %@",
-                          possibleShare, selfPeer, possibleShareError);
-                ckkserror("ckksshare", self, "Current trust set: %@", trustState.currentTrustedPeers);
-                lastShareError = possibleShareError;
-                continue;
-            }
-
-            bool result = [proposedTLK trySelfWrappedKeyCandidate:possibleKey.aessivkey error:&possibleShareError];
-            if(possibleShareError) {
-                ckkserror("ckksshare", self, "Unwrapped TLKShare(%@) does not unwrap proposed TLK(%@) as %@: %@",
-                          possibleShare, proposedTLK, trustState.currentSelfPeers.currentSelf, possibleShareError);
-                lastShareError = possibleShareError;
-                continue;
-            }
-
-            if(result) {
-                ckksnotice("ckksshare", self, "TLKShare(%@) unlocked TLK(%@) as %@",
-                           possibleShare, proposedTLK, selfPeer);
-
-                // The proposed TLK is trusted key material. Persist it as a "trusted" key.
-                [proposedTLK saveKeyMaterialToKeychain:true error:&possibleShareError];
-                if(possibleShareError) {
-                    ckkserror("ckksshare", self, "Couldn't store the new TLK(%@) to the keychain: %@", proposedTLK, possibleShareError);
-                    if(error) {
-                        *error = possibleShareError;
-                    }
-                    return false;
-                }
-
-                return true;
-            }
-        }
+    // Now, delete the OQE: it's never coming back
+    [oqe deleteFromDatabase:&localerror];
+    if(localerror) {
+        ckkserror("ckks", self, "Couldn't delete %@ (due to error %@): %@", oqe, itemError, localerror);
     }
 
-    if(error) {
-        *error = [NSError errorWithDomain:CKKSErrorDomain
-                                     code:CKKSNoTrustedTLKShares
-                              description:[NSString stringWithFormat:@"No trusted TLKShares for %@", proposedTLK]
-                               underlying:lastShareError];
+    if(error && localerror) {
+        *error = localerror;
     }
-    return false;
+    return localerror == nil;
 }
 
-- (bool)dispatchSyncWithConnection:(SecDbConnectionRef _Nonnull)dbconn block:(bool (^)(void))block {
+- (bool)dispatchSyncWithConnection:(SecDbConnectionRef _Nonnull)dbconn
+                    readWriteTxion:(BOOL)readWriteTxion
+                             block:(CKKSDatabaseTransactionResult (^)(void))block
+{
     CFErrorRef cferror = NULL;
 
     // Take the DB transaction, then get on the local queue.
     // In the case of exclusive DB transactions, we don't really _need_ the local queue, but, it's here for future use.
-    bool ret = kc_transaction_type(dbconn, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, ^bool{
-        __block bool ok = false;
+
+    SecDbTransactionType txtionType = readWriteTxion ? kSecDbExclusiveRemoteCKKSTransactionType : kSecDbNormalTransactionType;
+    bool ret = kc_transaction_type(dbconn, txtionType, &cferror, ^bool{
+        __block CKKSDatabaseTransactionResult result = CKKSDatabaseTransactionRollback;
+
+        CKKSSQLInTransaction = true;
+        if(readWriteTxion) {
+            CKKSSQLInWriteTransaction = true;
+        }
 
         dispatch_sync(self.queue, ^{
-            ok = block();
+            result = block();
         });
 
-        return ok;
+        if(readWriteTxion) {
+            CKKSSQLInWriteTransaction = false;
+        }
+        CKKSSQLInTransaction = false;
+        return result == CKKSDatabaseTransactionCommit;
     });
 
     if(cferror) {
     return ret;
 }
 
-- (void)dispatchSync: (bool (^)(void)) block {
+- (void)dispatchSyncWithSQLTransaction:(CKKSDatabaseTransactionResult (^)(void))block
+{
     // important enough to block this thread. Must get a connection first, though!
 
     // Please don't jetsam us...
 
     CFErrorRef cferror = NULL;
     kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
-        return [self dispatchSyncWithConnection:dbt block:block];
+        return [self dispatchSyncWithConnection:dbt
+                                 readWriteTxion:YES
+                                          block:block];
+
+    });
+    if(cferror) {
+        ckkserror("ckks", self, "error getting database connection, major problems ahead: %@", cferror);
+    }
+
+    (void)transaction;
+}
+
+- (void)dispatchSyncWithReadOnlySQLTransaction:(void (^)(void))block
+{
+    // Please don't jetsam us...
+    os_transaction_t transaction = os_transaction_create([[NSString stringWithFormat:@"com.apple.securityd.ckks.%@", self.zoneName] UTF8String]);
+
+    CFErrorRef cferror = NULL;
+
+    // Note: we are lying to kc_with_dbt here about whether we're read-and-write or read-only.
+    // This is because the SOS engine's queue are broken: SOSEngineSetNotifyPhaseBlock attempts
+    // to take the SOS engine's queue while a SecDb transaction is still ongoing. But, in
+    // SOSEngineCopyPeerConfirmedDigests, SOS takes the engine queue, then calls dsCopyManifestWithViewNameSet()
+    // which attempts to get a read-only SecDb connection.
+    //
+    // The issue manifests when many CKKS read-only transactions are in-flight, and starve out
+    // the pool of read-only connections. Then, a deadlock forms.
+    //
+    // By claiming to be a read-write connection here, we'll contend on the pool of writer threads,
+    // and shouldn't starve SOS of its read thread.
+    //
+    // But, since we pass NO to readWriteTxion, the SQLite transaction will be of type
+    // kSecDbNormalTransactionType, which won't block other readers.
+
+    kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
+        return [self dispatchSyncWithConnection:dbt
+                                 readWriteTxion:NO
+                                          block:^CKKSDatabaseTransactionResult {
+            block();
+            return CKKSDatabaseTransactionCommit;
+        }];
+
     });
     if(cferror) {
         ckkserror("ckks", self, "error getting database connection, major problems ahead: %@", cferror);
     (void)transaction;
 }
 
-- (void)dispatchSyncWithAccountKeys:(bool (^)(void))block
+- (BOOL)insideSQLTransaction
+{
+    return CKKSSQLInTransaction;
+}
+
+#pragma mark - CKKSZone operations
+
+- (void)beginCloudKitOperation
 {
-    [self dispatchSyncWithPeerProviders:self.currentPeerProviders override:false block:block];
+    [self.accountTracker registerForNotificationsOfCloudKitAccountStatusChange:self];
 }
 
-- (void)dispatchSyncWithPeerProviders:(NSArray<id<CKKSPeerProvider>>*)peerProviders
-                             override:(bool)overridePeerProviders
-                                block:(bool (^)(void))block
+- (CKKSResultOperation*)createAccountLoggedInDependency:(NSString*)message
 {
-    NSArray<id<CKKSPeerProvider>>* actualPeerProviders = overridePeerProviders ? peerProviders : self.currentPeerProviders;
-    NSMutableArray<CKKSPeerProviderState*>* trustStates = [NSMutableArray array];
+    WEAKIFY(self);
+    CKKSResultOperation* accountLoggedInDependency = [CKKSResultOperation named:@"account-logged-in-dependency" withBlock:^{
+        STRONGIFY(self);
+        ckksnotice("ckkszone", self, "%@", message);
+    }];
+    accountLoggedInDependency.descriptionErrorCode = CKKSResultDescriptionPendingAccountLoggedIn;
+    return accountLoggedInDependency;
+}
+
+#pragma mark - CKKSZoneUpdateReceiverProtocol
 
-    for(id<CKKSPeerProvider> provider in actualPeerProviders) {
-        ckksnotice("ckks", self, "Fetching account keys for provider %@", provider);
-        [trustStates addObject:provider.currentState];
+- (CKKSAccountStatus)accountStatusFromCKAccountInfo:(CKAccountInfo*)info
+{
+    if(!info) {
+        return CKKSAccountStatusUnknown;
+    }
+    if(info.accountStatus == CKAccountStatusAvailable &&
+       info.hasValidCredentials) {
+        return CKKSAccountStatusAvailable;
+    } else {
+        return CKKSAccountStatusNoAccount;
     }
+}
 
-    [self dispatchSync:^bool{
-        if(overridePeerProviders) {
-            self.currentPeerProviders = peerProviders;
-        }
-        self.currentTrustStates = trustStates;
+- (void)cloudkitAccountStateChange:(CKAccountInfo* _Nullable)oldAccountInfo to:(CKAccountInfo*)currentAccountInfo
+{
+    ckksnotice("ckkszone", self, "%@ Received notification of CloudKit account status change, moving from %@ to %@",
+               self.zoneID.zoneName,
+               oldAccountInfo,
+               currentAccountInfo);
 
-        bool result = block();
+    // Filter for device2device encryption and cloudkit grey mode
+    CKKSAccountStatus oldStatus = [self accountStatusFromCKAccountInfo:oldAccountInfo];
+    CKKSAccountStatus currentStatus = [self accountStatusFromCKAccountInfo:currentAccountInfo];
 
-        // Forget the peers; they might have class A key material
-        NSMutableArray<CKKSPeerProviderState*>* noTrustStates = [NSMutableArray array];
-        for(id<CKKSPeerProvider> provider in peerProviders) {
-            (void)provider;
-            [noTrustStates addObject:[CKKSPeerProviderState noPeersState:provider]];
+    if(oldStatus == currentStatus) {
+        ckksnotice("ckkszone", self, "Computed status of new CK account info is same as old status: %@", [CKKSAccountStateTracker stringFromAccountStatus:currentStatus]);
+        return;
+    }
+
+    switch(currentStatus) {
+        case CKKSAccountStatusAvailable: {
+            ckksnotice("ckkszone", self, "Logged into iCloud.");
+            [self handleCKLogin];
+
+            if(self.accountLoggedInDependency) {
+                [self.operationQueue addOperation:self.accountLoggedInDependency];
+                self.accountLoggedInDependency = nil;
+            };
         }
-        self.currentTrustStates = noTrustStates;
+            break;
 
-        return result;
-    }];
-}
+        case CKKSAccountStatusNoAccount: {
+            ckksnotice("ckkszone", self, "Logging out of iCloud. Shutting down.");
+
+            if(!self.accountLoggedInDependency) {
+                self.accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in again."];
+            }
 
-#pragma mark - CKKSZoneUpdateReceiver
+            [self handleCKLogout];
+        }
+            break;
 
-- (void)notifyZoneChange: (CKRecordZoneNotification*) notification {
-    ckksnotice("ckks", self, "received a zone change notification for %@ %@", self, notification);
+        case CKKSAccountStatusUnknown: {
+            // We really don't expect to receive this as a notification, but, okay!
+            ckksnotice("ckkszone", self, "Account status has become undetermined. Pausing for %@", self.zoneID.zoneName);
 
-    [self fetchAndProcessCKChangesDueToAPNS:notification];
-}
+            if(!self.accountLoggedInDependency) {
+                self.accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in again."];
+            }
 
-- (void)superHandleCKLogin {
-    [super handleCKLogin];
+            [self handleCKLogout];
+        }
+            break;
+    }
 }
 
-- (void)handleCKLogin {
+- (void)handleCKLogin
+{
     ckksnotice("ckks", self, "received a notification of CK login");
     if(!SecCKKSIsEnabled()) {
         ckksnotice("ckks", self, "Skipping CloudKit initialization due to disabled CKKS");
         return;
     }
 
-    WEAKIFY(self);
-    CKKSResultOperation* login = [CKKSResultOperation named:@"ckks-login" withBlock:^{
-        STRONGIFY(self);
-
-        [self dispatchSyncWithAccountKeys:^bool{
-            [self superHandleCKLogin];
-
-            // Reset key hierarchy state machine to initializing
-            [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateInitializing withError:nil];
-            return true;
-        }];
+    dispatch_sync(self.queue, ^{
+        ckksinfo("ckkszone", self, "received a notification of CK login");
 
         // Change our condition variables to reflect that we think we're logged in
+        self.accountStatus = CKKSAccountStatusAvailable;
         self.loggedOut = [[CKKSCondition alloc] initToChain:self.loggedOut];
         [self.loggedIn fulfill];
-        [self.accountStateKnown fulfill];
-    }];
+    });
 
-    [self scheduleAccountStatusOperation:login];
-}
+    [self.stateMachine handleFlag:CKKSFlagCloudKitLoggedIn];
 
-- (void)superHandleCKLogout {
-    [super handleCKLogout];
+    [self.accountStateKnown fulfill];
 }
 
-- (void)handleCKLogout {
-    WEAKIFY(self);
-    CKKSResultOperation* logout = [CKKSResultOperation named:@"ckks-logout" withBlock: ^{
-        STRONGIFY(self);
-        if(!self) {
-            return;
-        }
-        [self dispatchSync:^bool {
-            ckksnotice("ckks", self, "received a notification of CK logout");
-            [self superHandleCKLogout];
-
-            NSError* error = nil;
-            [self _onqueueResetLocalData: &error];
-            if(error) {
-                ckkserror("ckks", self, "error while resetting local data: %@", error);
-            }
-
-            [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateLoggedOut withError:nil];
+- (void)handleCKLogout
+{
+    dispatch_sync(self.queue, ^{
+        ckksinfo("ckkszone", self, "received a notification of CK logout");
 
-            self.loggedIn = [[CKKSCondition alloc] initToChain: self.loggedIn];
-            [self.loggedOut fulfill];
-            [self.accountStateKnown fulfill];
+        self.accountStatus = CKKSAccountStatusNoAccount;
+        self.loggedIn = [[CKKSCondition alloc] initToChain:self.loggedIn];
+        [self.loggedOut fulfill];
+    });
 
-            return true;
-        }];
-    }];
+    [self.stateMachine handleFlag:CKKSFlagCloudKitLoggedOut];
 
-    [self scheduleAccountStatusOperation: logout];
+    [self.accountStateKnown fulfill];
 }
 
 #pragma mark - Trust operations
 
 - (void)beginTrustedOperation:(NSArray<id<CKKSPeerProvider>>*)peerProviders
              suggestTLKUpload:(CKKSNearFutureScheduler*)suggestTLKUpload
+           requestPolicyCheck:(CKKSNearFutureScheduler*)requestPolicyCheck
 {
     for(id<CKKSPeerProvider> peerProvider in peerProviders) {
         [peerProvider registerForPeerChangeUpdates:self];
 
     [self.launch addEvent:@"beginTrusted"];
 
-    [self dispatchSyncWithPeerProviders:peerProviders override:true block:^bool {
+    dispatch_sync(self.queue, ^{
         ckksnotice("ckkstrust", self, "Beginning trusted operation");
+        self.operationDependencies.peerProviders = peerProviders;
+
         CKKSAccountStatus oldTrustStatus = self.trustStatus;
 
         self.suggestTLKUpload = suggestTLKUpload;
+        self.requestPolicyCheck = requestPolicyCheck;
 
         self.trustStatus = CKKSAccountStatusAvailable;
-        if(self.trustDependency) {
-            [self scheduleOperation: self.trustDependency];
-            self.trustDependency = nil;
-        }
-        [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
+        [self.stateMachine _onqueueHandleFlag:CKKSFlagBeginTrustedOperation];
 
         if(oldTrustStatus == CKKSAccountStatusNoAccount) {
             ckksnotice("ckkstrust", self, "Moving from an untrusted status; we need to process incoming queue and scan for any new items");
 
-            // Next, try to process them (replacing local entries)
-            CKKSIncomingQueueOperation* initialProcess = [self processIncomingQueue:true after:nil];
-            initialProcess.name = @"initial-process-incoming-queue";
-
-            // If all that succeeds, iterate through all keychain items and find the ones which need to be uploaded
-            self.initialScanOperation = [self scanLocalItems:@"newly-trusted-scan"
-                                            ckoperationGroup:nil
-                                                       after:initialProcess];
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagProcessIncomingQueue];
+            [self.stateMachine _onqueueHandleFlag:CKKSFlagScanLocalItems];
         }
-
-        return true;
-    }];
+    });
 }
 
 - (void)endTrustedOperation
 {
     [self.launch addEvent:@"endTrusted"];
 
-    [self dispatchSyncWithPeerProviders:nil override:true block:^bool {
+    dispatch_sync(self.queue, ^{
         ckksnotice("ckkstrust", self, "Ending trusted operation");
 
+        self.operationDependencies.peerProviders = @[];
+
         self.suggestTLKUpload = nil;
 
         self.trustStatus = CKKSAccountStatusNoAccount;
-        if(!self.trustDependency) {
-            self.trustDependency = [CKKSResultOperation named:@"wait-for-trust" withBlock:^{}];
+        [self.stateMachine _onqueueHandleFlag:CKKSFlagEndTrustedOperation];
+    });
+}
+
+- (BOOL)itemSyncingEnabled
+{
+    if(!self.operationDependencies.syncingPolicy) {
+        ckksnotice("ckks", self, "No syncing policy loaded; item syncing is disabled");
+        return NO;
+    } else {
+        return [self.operationDependencies.syncingPolicy isSyncingEnabledForView:self.zoneName];
+    }
+}
+
+- (void)setCurrentSyncingPolicy:(TPSyncingPolicy*)syncingPolicy policyIsFresh:(BOOL)policyIsFresh
+{
+    dispatch_sync(self.queue, ^{
+        BOOL oldEnabled = [self itemSyncingEnabled];
+
+        self.operationDependencies.syncingPolicy = syncingPolicy;
+
+        BOOL enabled = [self itemSyncingEnabled];
+        if(enabled != oldEnabled) {
+            ckksnotice("ckks", self, "Syncing for this view is now %@ (policy: %@)", enabled ? @"enabled" : @"paused", self.operationDependencies.syncingPolicy);
         }
-        [self _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-        return true;
-    }];
+
+        if(enabled) {
+            CKKSResultOperation* incomingOp = [self processIncomingQueue:false after:nil policyConsideredAuthoritative:policyIsFresh];
+            [self processOutgoingQueueAfter:incomingOp ckoperationGroup:nil];
+        }
+    });
+}
+
+- (void)receivedItemForWrongView
+{
+    [self.requestPolicyCheck trigger];
 }
 
 #pragma mark - CKKSChangeFetcherClient
 {
     __block BOOL ready = NO;
 
-    [self dispatchSync: ^bool {
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
         ready = (bool)[self _onQueueZoneIsReadyForFetching];
-        return ready;
     }];
 
     return ready;
 
 - (BOOL)_onQueueZoneIsReadyForFetching
 {
+    dispatch_assert_queue(self.queue);
     if(self.accountStatus != CKKSAccountStatusAvailable) {
         ckksnotice("ckksfetch", self, "Not participating in fetch: not logged in");
         return NO;
     }
 
-    if(!self.zoneCreated) {
+    CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.operationDependencies.zoneID.zoneName];
+
+    if(!ckse.ckzonecreated) {
         ckksnotice("ckksfetch", self, "Not participating in fetch: zone not created yet");
         return NO;
     }
 {
     __block CKKSCloudKitFetchRequest* request = [[CKKSCloudKitFetchRequest alloc] init];
 
-    [self dispatchSync: ^bool {
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
         if (![self _onQueueZoneIsReadyForFetching]) {
             ckksnotice("ckksfetch", self, "skipping fetch since zones are not ready");
-            return false;
+            return;
         }
 
         request.participateInFetch = true;
             CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName];
             if(!ckse) {
                 ckkserror("ckksfetch", self, "couldn't fetch zone change token for %@", self.zoneName);
-                return false;
+                return;
             }
             request.changeToken = ckse.changeToken;
         }
-        return true;
     }];
 
     if (request.changeToken == nil) {
 
     if(changedRecords.count == 0 && deletedRecords.count == 0 && !moreComing && !resync) {
         // Early-exit, so we don't pick up the account keys or kick off an IncomingQueue operation for no changes
-        [self dispatchSync:^bool {
-            ckkserror("ckksfetch", self, "No record changes in this fetch");
+        [self dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            ckksinfo("ckksfetch", self, "No record changes in this fetch");
 
             NSError* error = nil;
             CKKSZoneStateEntry* state = [CKKSZoneStateEntry state:self.zoneName];
             if(error) {
                 ckkserror("ckksfetch", self, "Couldn't save new server change token: %@", error);
             }
-            return true;
+            return CKKSDatabaseTransactionCommit;
         }];
         return;
     }
 
-    [self dispatchSyncWithAccountKeys:^bool{
+    [self dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         for (CKRecord* record in changedRecords) {
             [self _onqueueCKRecordChanged:record resync:resync];
         }
 
         ckksnotice("ckksfetch", self, "Finished processing changes for %@", self.zoneID);
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
     if(isChangeTokenExpiredError) {
         ckkserror("ckks", self, "Received notice that our change token is out of date (for %@). Resetting local data...", self.zoneID);
 
-        // This is a bit scary: we might confuse some poor key hierarchy state machine operation. But, if a key state machine
-        // operation is waiting for a successful fetch, we need to do this reset
-        [self dispatchSyncWithAccountKeys:^bool{
-            NSError* error = nil;
-            [self _onqueueResetLocalData:&error];
-
-            // We need to rescan the local keychain once we return to a good state
-            self.droppedItems = true;
-
-            if(error) {
-                ckksnotice("ckksreset", self, "CloudKit-inspired local reset of %@ ended with error: %@", self.zoneID, error);
-            } else {
-                ckksnotice("ckksreset", self, "CloudKit-inspired local reset of %@ ended successfully", self.zoneID);
-            }
-
-            // If we're in the middle of a fetch for the key state, then the retried fetch (which should succeed) will be sufficient to progress
-            // Otherwise, we need to poke the key hierarchy state machine: all of its data is gone
-            if(![self.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateFetch]) {
-                [self _onqueueKeyStateMachineRequestFetch];
-            }
-
-            return true;
-        }];
-
+        [self.stateMachine handleFlag:CKKSFlagChangeTokenExpired];
         return true;
     }
 
     if(isDeletedZoneError) {
         ckkserror("ckks", self, "Received notice that our zone(%@) does not exist. Resetting local data.", self.zoneID);
 
-        /*
-         * If someone delete our zone, lets just start over from the begining
-         */
-        [self dispatchSync: ^bool{
-            NSError* resetError = nil;
-
-            [self _onqueueResetLocalData: &resetError];
-            if(resetError) {
-                ckksnotice("ckksreset", self, "CloudKit-inspired local reset of %@ ended with error: %@", self.zoneID, resetError);
-            } else {
-                ckksnotice("ckksreset", self, "CloudKit-inspired local reset of %@ ended successfully", self.zoneID);
-            }
-
-            [self _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateInitializing withError:nil];
-            return true;
-        }];
-
+        [self.stateMachine handleFlag:CKKSFlagCloudKitZoneMissing];
         return false;
     }
 
     // The key state machine should handle that, so poke it.
     ckkserror("ckks", self, "Received update that the trust set has changed");
 
-    self.trustedPeersSetChanged = true;
-    [self.pokeKeyStateMachineScheduler trigger];
+    [self.stateMachine handleFlag:CKKSFlagTrustedPeersSetChanged];
 }
 
 #pragma mark - Test Support
 
 - (bool) outgoingQueueEmpty: (NSError * __autoreleasing *) error {
     __block bool ret = false;
-    [self dispatchSync: ^bool{
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
         NSArray* queueEntries = [CKKSOutgoingQueueEntry all: error];
         ret = queueEntries && ([queueEntries count] == 0);
-        return true;
     }];
 
     return ret;
 }
 
-- (CKKSResultOperation*)waitForFetchAndIncomingQueueProcessing {
-    CKKSResultOperation* op = [self fetchAndProcessCKChanges:CKKSFetchBecauseTesting];
-    [op waitUntilFinished];
-    return op;
+- (void)waitForFetchAndIncomingQueueProcessing
+{
+    [[self.zoneChangeFetcher inflightFetch] waitUntilFinished];
+    [self waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 }
 
 - (void)waitForKeyHierarchyReadiness {
     }
 }
 
+#pragma mark - NSOperation assistance
+
+- (void)scheduleOperation:(NSOperation*)op
+{
+    if(self.halted) {
+        ckkserror("ckkszone", self, "attempted to schedule an operation on a halted zone, ignoring");
+        return;
+    }
+
+    [op addNullableDependency:self.accountLoggedInDependency];
+    [self.operationQueue addOperation: op];
+}
+
+// to be used rarely, if at all
+- (bool)scheduleOperationWithoutDependencies:(NSOperation*)op
+{
+    if(self.halted) {
+        ckkserror("ckkszone", self, "attempted to schedule an non-dependent operation on a halted zone, ignoring");
+        return false;
+    }
+
+    [self.operationQueue addOperation: op];
+    return true;
+}
+
+- (void)waitUntilAllOperationsAreFinished
+{
+    [self.operationQueue waitUntilAllOperationsAreFinished];
+}
+
+- (void)waitForOperationsOfClass:(Class)operationClass
+{
+    NSArray* operations = [self.operationQueue.operations copy];
+    for(NSOperation* op in operations) {
+        if([op isKindOfClass:operationClass]) {
+            [op waitUntilFinished];
+        }
+    }
+}
+
 - (void)cancelPendingOperations {
     @synchronized(self.outgoingQueueOperations) {
         for(NSOperation* op in self.outgoingQueueOperations) {
         }
         [self.scanLocalItemsOperations removeAllObjects];
     }
-
-    [super cancelAllOperations];
 }
 
 - (void)cancelAllOperations {
-    [self.zoneSetupOperation cancel];
-    [self.keyStateMachineOperation cancel];
     [self.keyStateReadyDependency cancel];
-    [self.keyStateNonTransientDependency cancel];
     [self.zoneChangeFetcher cancel];
     [self.notifyViewChangedScheduler cancel];
-    [self.pokeKeyStateMachineScheduler cancel];
 
     [self cancelPendingOperations];
-
-    [self dispatchSync:^bool{
-        [self _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateCancelled withError: nil];
-        return true;
-    }];
+    [self.operationQueue cancelAllOperations];
 }
 
 - (void)halt {
-    [super halt];
+    [self.stateMachine haltOperation];
+
+    // Synchronously set the 'halted' bit
+    dispatch_sync(self.queue, ^{
+        self.halted = true;
+    });
+
+    // Bring all operations down, too
+    [self cancelAllOperations];
+
+    // And now, wait for all operations that are running
+    for(NSOperation* op in self.operationQueue.operations) {
+        if(op.isExecuting) {
+            [op waitUntilFinished];
+        }
+    }
 
     // Don't send any more notifications, either
     _notifierClass = nil;
 #define boolstr(obj) (!!(obj) ? @"yes" : @"no")
     __block NSMutableDictionary* ret = nil;
     __block NSError* error = nil;
-    CKKSManifest* manifest = nil;
 
     ret = [[self fastStatus] mutableCopy];
 
-    manifest = [CKKSManifest latestTrustedManifestForZone:self.zoneName error:&error];
-    [self dispatchSync: ^bool {
-
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
         CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.zoneID];
         if(keyset.error) {
             error = keyset.error;
         }
 
-        NSString* manifestGeneration = manifest ? [NSString stringWithFormat:@"%lu", (unsigned long)manifest.generationCount] : nil;
-
         if(error) {
             ckkserror("ckks", self, "error during status: %@", error);
         }
                  @"currentTLKPtr":       CKKSNilToNSNull(keyset.currentTLKPointer.currentKeyUUID),
                  @"currentClassAPtr":    CKKSNilToNSNull(keyset.currentClassAPointer.currentKeyUUID),
                  @"currentClassCPtr":    CKKSNilToNSNull(keyset.currentClassCPointer.currentKeyUUID),
-                 @"currentManifestGen":  CKKSNilToNSNull(manifestGeneration),
+                 @"itemsyncing":         self.itemSyncingEnabled ? @"enabled" : @"paused",
             }];
-        return false;
     }];
     return ret;
 }
 
     __block NSDictionary* ret = nil;
 
-    [self dispatchSync: ^bool {
+    [self dispatchSyncWithReadOnlySQLTransaction:^{
+        CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.zoneName];
 
         ret = @{
             @"view":                CKKSNilToNSNull(self.zoneName),
                 self.accountStatus == CKAccountStatusNoAccount         ? @"logged out" : @"unknown",
             @"accounttracker":      stringify(self.accountTracker),
             @"fetcher":             stringify(self.zoneChangeFetcher),
-            @"zoneCreated":         boolstr(self.zoneCreated),
-            @"zoneCreatedError":    stringify(self.zoneCreatedError),
-            @"zoneSubscribed":      boolstr(self.zoneSubscribed),
-            @"zoneSubscribedError": stringify(self.zoneSubscribedError),
+            @"zoneCreated":         boolstr(ckse.ckzonecreated),
+            @"zoneSubscribed":      boolstr(ckse.ckzonesubscribed),
             @"keystate":            CKKSNilToNSNull(self.keyHierarchyState),
-            @"keyStateError":       stringify(self.keyHierarchyError),
             @"statusError":         [NSNull null],
             @"launchSequence":      CKKSNilToNSNull([self.launch eventsByTime]),
 
-            @"zoneSetupOperation":                 stringify(self.zoneSetupOperation),
-            @"keyStateOperation":                  stringify(self.keyStateMachineOperation),
             @"lastIncomingQueueOperation":         stringify(self.lastIncomingQueueOperation),
             @"lastNewTLKOperation":                stringify(self.lastNewTLKOperation),
             @"lastOutgoingQueueOperation":         stringify(self.lastOutgoingQueueOperation),
             @"lastProcessReceivedKeysOperation":   stringify(self.lastProcessReceivedKeysOperation),
             @"lastReencryptOutgoingItemsOperation":stringify(self.lastReencryptOutgoingItemsOperation),
-            @"lastScanLocalItemsOperation":        stringify(self.lastScanLocalItemsOperation),
         };
-        return false;
     }];
 
     return ret;
diff --git a/keychain/ckks/CKKSLocalResetOperation.h b/keychain/ckks/CKKSLocalResetOperation.h
new file mode 100644 (file)
index 0000000..def140d
--- /dev/null
@@ -0,0 +1,26 @@
+
+#import <Foundation/Foundation.h>
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CKKSLocalResetOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
+// Used to run a local reset without scheduling its surrounding operation.
+// Please be on a SQL transaction when you run this.
+- (void)onqueuePerformLocalReset;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ckks/CKKSLocalResetOperation.m b/keychain/ckks/CKKSLocalResetOperation.m
new file mode 100644 (file)
index 0000000..abb1c8f
--- /dev/null
@@ -0,0 +1,120 @@
+
+#if OCTAGON
+
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ckks/CKKSLocalResetOperation.h"
+#import "keychain/ckks/CKKSZoneStateEntry.h"
+#import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSCurrentItemPointer.h"
+#import "keychain/ckks/CKKSMirrorEntry.h"
+#import "keychain/ot/OTDefines.h"
+
+@implementation CKKSLocalResetOperation
+
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if(self = [super init]) {
+        _deps = dependencies;
+
+        _intendedState = intendedState;
+        _nextState = errorState;
+
+        self.name = @"ckks-local-reset";
+    }
+    return self;
+}
+
+- (void)main {
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult {
+        [self onqueuePerformLocalReset];
+        return CKKSDatabaseTransactionCommit;
+    }];
+}
+
+- (void)onqueuePerformLocalReset
+{
+    NSError* localerror = nil;
+
+    CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
+    ckse.ckzonecreated = false;
+    ckse.ckzonesubscribed = false; // I'm actually not sure about this: can you be subscribed to a non-existent zone?
+    ckse.changeToken = NULL;
+    [ckse saveToDatabase:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't reset zone status: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSMirrorEntry deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSMirrorEntry: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSOutgoingQueueEntry deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSOutgoingQueueEntry: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSIncomingQueueEntry deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSIncomingQueueEntry: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSKey deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSKey: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSTLKShareRecord deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSTLKShare: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSCurrentKeyPointer deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSCurrentKeyPointer: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSCurrentItemPointer deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSCurrentItemPointer: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    [CKKSDeviceStateEntry deleteAll:self.deps.zoneID error:&localerror];
+    if(localerror && self.error == nil) {
+        ckkserror("local-reset", self.deps.zoneID, "couldn't delete all CKKSDeviceStateEntry: %@", localerror);
+        self.error = localerror;
+        localerror = nil;
+    }
+
+    if(!self.error) {
+        ckksnotice("local-reset", self.deps.zoneID, "Successfully deleted all local data");
+        self.nextState = self.intendedState;
+    }
+}
+
+@end
+
+#endif // OCTAGON
+
index fe5c09d01e398479b2df0e0e6826191f4f9baef8..585edc150e082dae36e10e6aed22036a1da2ba6d 100644 (file)
     CKKSKeychainView* ckks = self.ckks;
 
     // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety.
-    [ckks dispatchSync: ^bool{
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
             ckksnotice("ckksresync", ckks, "CKKSSynchronizeOperation cancelled, quitting");
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         //ckks.lastLocalSynchronizeOperation = self;
         [self dependOnBeforeGroupFinished:outgoingOp];
 
         // Step 2
-        CKKSIncomingQueueOperation* incomingOp = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:ckks errorOnClassAFailure:true];
+        CKKSIncomingQueueOperation* incomingOp = [[CKKSIncomingQueueOperation alloc] initWithDependencies:ckks.operationDependencies
+                                                                                                     ckks:ckks
+                                                                                                intending:SecCKKSZoneKeyStateReady
+                                                                                               errorState:SecCKKSZoneKeyStateUnhealthy
+                                                                                     errorOnClassAFailure:true
+                                                                                handleMismatchedViewItems:false];
+
         incomingOp.name = [NSString stringWithFormat: @"resync-step%u-incoming", self.restartCount * steps + 2];
         [incomingOp addSuccessDependency:outgoingOp];
         [self runBeforeGroupFinished:incomingOp];
         [self runBeforeGroupFinished:reloadOp];
 
         // Step 4
-        CKKSIncomingQueueOperation* incomingResyncOp = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:ckks errorOnClassAFailure:true];
+        CKKSIncomingQueueOperation* incomingResyncOp = [[CKKSIncomingQueueOperation alloc] initWithDependencies:ckks.operationDependencies
+                                                                                                           ckks:ckks
+                                                                                                      intending:SecCKKSZoneKeyStateReady
+                                                                                                     errorState:SecCKKSZoneKeyStateUnhealthy
+                                                                                           errorOnClassAFailure:true
+                                                                                      handleMismatchedViewItems:false];
+
         incomingResyncOp.name = [NSString stringWithFormat: @"resync-step%u-incoming-again", self.restartCount * steps + 4];
         [incomingResyncOp addSuccessDependency: reloadOp];
         [self runBeforeGroupFinished:incomingResyncOp];
 
         // Step 5
-        CKKSScanLocalItemsOperation* scan = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:operationGroup];
+        CKKSScanLocalItemsOperation* scan = [[CKKSScanLocalItemsOperation alloc] initWithDependencies:ckks.operationDependencies
+                                                                                                 ckks:ckks
+                                                                                            intending:SecCKKSZoneKeyStateReady
+                                                                                           errorState:SecCKKSZoneKeyStateError
+                                                                                     ckoperationGroup:operationGroup];
         scan.name = [NSString stringWithFormat: @"resync-step%u-scan", self.restartCount * steps + 5];
         [scan addSuccessDependency: incomingResyncOp];
         [self runBeforeGroupFinished: scan];
         [restart addExecutionBlock:^{
             STRONGIFY(self);
             if(!self) {
-                secerror("ckksresync: received callback for released object");
+                ckkserror("ckksresync", ckks, "received callback for released object");
                 return;
             }
 
         [restart addSuccessDependency: scan];
         [self runBeforeGroupFinished: restart];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
 - (void)main {
     CKKSKeychainView* strongCKKS = self.ckks;
 
-    [strongCKKS dispatchSync: ^bool{
+    [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
        NSError* error = nil;
        NSArray<CKKSMirrorEntry*>* mirrorItems = [CKKSMirrorEntry all:strongCKKS.zoneID error:&error];
 
        if(error) {
            ckkserror("ckksresync", strongCKKS, "Couldn't fetch mirror items: %@", error);
            self.error = error;
-           return false;
+           return CKKSDatabaseTransactionRollback;
        }
 
        // Reload all entries back into the local keychain
            [strongCKKS _onqueueCKRecordChanged:ckmeRecord resync:true];
        }
 
-       return true;
+       return CKKSDatabaseTransactionCommit;
     }];
 }
 @end
index 46e6cb2aa845625f361afa60a4a960e70a832a75..774f01950fc06caa5ed4965bb860872f9b263500 100644 (file)
 -(void)resetUnlockDependency {
     if(self.unlockDependency == nil || ![self.unlockDependency isPending]) {
         CKKSResultOperation* op = [CKKSResultOperation named:@"keybag-unlocked-dependency" withBlock: ^{
-            secinfo("ckks", "Keybag unlocked");
+            ckksinfo_global("ckks", "Keybag unlocked");
         }];
         op.descriptionErrorCode = CKKSResultDescriptionPendingUnlock;
         self.unlockDependency = op;
     bool locked = true;
 
     if(!SecAKSGetIsLocked(&locked, &aksError)) {
-        secerror("ckks: error querying lock state: %@", aksError);
+        ckkserror_global("ckks", "error querying lock state: %@", aksError);
         CFReleaseNull(aksError);
     }
 
     });
 }
 
--(bool)isLockedError:(NSError *)error {
+- (bool)lockedError:(NSError *)error
+{
     bool isLockedError = error.code == errSecInteractionNotAllowed &&
         ([error.domain isEqualToString:@"securityd"] || [error.domain isEqualToString:(__bridge NSString*)kSecErrorDomain]);
+    return isLockedError;
+}
+
+- (bool)checkErrorChainForLockState:(NSError*)error
+{
+    while(error != nil) {
+        if([self lockedError:error]) {
+            return true;
+        }
+
+        error = error.userInfo[NSUnderlyingErrorKey];
+    }
+
+    return false;
+}
+
+-(bool)isLockedError:(NSError *)error {
+    bool isLockedError = [self checkErrorChainForLockState:error];
 
     /*
      * If we are locked, and the the current lock state track disagree, lets double check
diff --git a/keychain/ckks/CKKSLogging.m b/keychain/ckks/CKKSLogging.m
new file mode 100644 (file)
index 0000000..4971f41
--- /dev/null
@@ -0,0 +1,33 @@
+
+#import <Foundation/Foundation.h>
+#import "keychain/ckks/CKKS.h"
+
+os_log_t CKKSLogObject(NSString* scope, NSString* _Nullable zoneName)
+{
+    __block os_log_t ret = OS_LOG_DISABLED;
+
+    static dispatch_queue_t logQueue = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        logQueue = dispatch_queue_create("ckks-logger", DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
+    });
+
+    static NSMutableDictionary* scopeMap = nil;
+
+    dispatch_sync(logQueue, ^{
+        if(scopeMap == nil) {
+            scopeMap = [NSMutableDictionary dictionary];
+        }
+
+        NSString* key = zoneName ? [scope stringByAppendingFormat:@"-%@", zoneName] : scope;
+
+        ret = scopeMap[key];
+
+        if(!ret) {
+            ret = os_log_create("com.apple.security.ckks", [key cStringUsingEncoding:NSUTF8StringEncoding]);
+            scopeMap[key] = ret;
+        }
+    });
+
+    return ret;
+}
index 0d7f5562348ef35382504b4640eb371393880e89..4203dff74f95fe84cd63a083166920eddbe92381 100644 (file)
@@ -286,7 +286,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
     [[CKKSEgoManifest egoHelper] performWithSigningKey:^(SFECKeyPair* signingKey, NSError* error) {
         accountInfo.signingKey = signingKey;
         if(error) {
-            secerror("ckksmanifest: cannot get signing key from account: %@", error);
+            ckkserror_global("ckksmanifest", "cannot get signing key from account: %@", error);
             if(accountInfo.setupError == nil) {
                 accountInfo.setupError = error;
             }
@@ -297,7 +297,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
         accountInfo.egoPeerID = egoPeerID;
 
         if(error) {
-            secerror("ckksmanifest: cannot get ego peer ID from account: %@", error);
+            ckkserror_global("ckksmanifest", "cannot get ego peer ID from account: %@", error);
             if(accountInfo.setupError == nil) {
                 accountInfo.setupError = error;
             }
@@ -307,7 +307,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
     [[CKKSEgoManifest egoHelper] performWithPeerVerifyingKeys:^(NSDictionary<NSString*, SFECPublicKey*>* peerKeys, NSError* error) {
         accountInfo.peerVerifyingKeys = peerKeys;
         if(error) {
-            secerror("ckksmanifest: cannot get peer keys from account: %@", error);
+            ckkserror_global("ckksmanifest", "cannot get peer keys from account: %@", error);
             if(accountInfo.setupError == nil) {
                 accountInfo.setupError = error;
             }
@@ -471,11 +471,11 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
 - (instancetype)initWithDigestValue:(NSData*)digestValue zone:(NSString*)zone generationCount:(NSUInteger)generationCount leafRecordIDs:(NSArray<NSString*>*)leafRecordIDs peerManifestIDs:(NSArray<NSString*>*)peerManifestIDs currentItems:(NSDictionary*)currentItems futureData:(NSDictionary*)futureData signatures:(NSDictionary*)signatures signerID:(NSString*)signerID schema:(NSDictionary*)schema helper:(CKKSManifestInjectionPointHelper*)helper
 {
     if ([zone containsString:manifestRecordNameDelimiter]) {
-        secerror("zone contains delimiter: %@", zone);
+        ckkserror_global("ckksmanifest", "zone contains delimiter: %@", zone);
         return nil;
     }
     if ([signerID containsString:manifestRecordNameDelimiter]) {
-        secerror("signerID contains delimiter: %@", signerID);
+        ckkserror_global("ckksmanifest", "signerID contains delimiter: %@", signerID);
         return nil;
     }
 
@@ -687,7 +687,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
     void (^addValueSafelyToDictionaryAndLogIfNil)(NSMutableDictionary*, NSString*, id) = ^(NSMutableDictionary* dictionary, NSString* key, id value) {
         if (!value) {
             value = [NSNull null];
-            secerror("CKKSManifest: saving manifest to database but %@ is nil", key);
+            ckkserror_global("ckksmanifest", "saving manifest to database but %@ is nil", key);
         }
 
         dictionary[key] = value;
@@ -728,7 +728,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
 {
     NSArray* components = [recordName componentsSeparatedByString:manifestRecordNameDelimiter];
     if (components.count < 4) {
-        secerror("CKKSManifest: could not parse components from record name: %@", recordName);
+        ckkserror_global("ckksmanifest", "could not parse components from record name: %@", recordName);
     }
     
     return @{ @"ckzone" : components[1],
@@ -1145,7 +1145,7 @@ static NSUInteger LeafBucketIndexForUUID(NSString* uuid)
         if (leafRecord) {
             [leafRecords addObject:leafRecord];
         } else {
-            secerror("ckksmanifest: error loading leaf record from database: %@", error ? *error : nil);
+            ckkserror_global("ckksmanifest", "error loading leaf record from database: %@", error ? *error : nil);
             return false;
         }
     }
index a35b519bc782f835acf20f72b1dae9dffb23f858..debfd93c0b37b1672f0ad24ae9723f9a5e86462e 100644 (file)
@@ -137,7 +137,7 @@ static NSDictionary* RecordDigestDictFromDER(NSData* data, NSError** error)
     NSData* derData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDERKey] options:0];
     NSDictionary<NSString*, NSData*>* recordDigestDict = RecordDigestDictFromDER(derData, &error);
     if (!recordDigestDict) {
-        secerror("failed to decode manifest leaf node DER with error: %@", error);
+        ckkserror_global("ckksmanifest", "failed to decode manifest leaf node DER with error: %@", error);
         return nil;
     }
     
@@ -148,7 +148,7 @@ static NSDictionary* RecordDigestDictFromDER(NSData* data, NSError** error)
 - (instancetype)initWithUUID:(NSString*)uuid digest:(NSData*)digest recordDigestDict:(NSDictionary<NSString*, NSData*>*)recordDigestDict zone:(NSString*)zone
 {
     if ([uuid containsString:manifestLeafRecordNameDelimiter]) {
-        secerror("uuid contains delimiter: %@", uuid);
+        ckkserror_global("ckksmanifest", "uuid contains delimiter: %@", uuid);
         return nil;
     }
 
@@ -176,7 +176,7 @@ static NSDictionary* RecordDigestDictFromDER(NSData* data, NSError** error)
     void (^addValueSafelyToDictionaryAndLogIfNil)(NSMutableDictionary*, NSString*, id) = ^(NSMutableDictionary* dictionary, NSString* key, id value) {
         if (!value) {
             value = [NSNull null];
-            secerror("CKKSManifestLeafRecord: saving manifest leaf record to database but %@ is nil", key);
+            ckkserror_global("ckksmanifest", "CKKSManifestLeafRecord: saving manifest leaf record to database but %@ is nil", key);
         }
 
         dictionary[key] = value;
@@ -222,7 +222,7 @@ static NSDictionary* RecordDigestDictFromDER(NSData* data, NSError** error)
     NSData* derData = [[NSData alloc] initWithBase64EncodedString:record[SecCKRecordManifestLeafDERKey] options:0];
     NSDictionary<NSString*, NSData*>* recordDigestDict = RecordDigestDictFromDER(derData, &error);
     if (!recordDigestDict || error) {
-        secerror("failed to decode manifest leaf node DER with error: %@", error);
+        ckkserror_global("ckksmanifest", "failed to decode manifest leaf node DER with error: %@", error);
         return;
     }
     
index 59900f08ba837079327407e08d251985a10a01df..edbfe449787e00b23537730aeea1ad4cefbb70a4 100644 (file)
@@ -78,7 +78,7 @@
         // Why is obj-c nullable equality so difficult?
         if(!((record[SecCKRecordServerWasCurrent] == nil && self.wasCurrent == 0) ||
              [record[SecCKRecordServerWasCurrent] isEqual: [NSNumber numberWithUnsignedLongLong:self.wasCurrent]])) {
-            secinfo("ckksitem", "was_current does not match");
+            ckksinfo_global("ckksitem", "was_current does not match");
             matches = false;
         }
     }
index fb831ffebda702c8524d1d11e1f805213f7c73e0..562ff05c01f02082788b27c5d69c5b0486a81a25 100644 (file)
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSGroupOperation.h"
 #import "keychain/ckks/CKKSProvideKeySetOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachine.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 
-@interface CKKSNewTLKOperation : CKKSGroupOperation <CKKSKeySetContainerProtocol>
+@interface CKKSNewTLKOperation : CKKSGroupOperation <CKKSKeySetContainerProtocol,
+                                                     OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks;
 
 @end
 
index 9cf42a1bd4a59df84ab117453bd54eab9df7c2d5..6f39b601817f145b642a491afdc562e3bd8b495c 100644 (file)
@@ -27,6 +27,7 @@
 #import "CKKSNewTLKOperation.h"
 #import "CKKSGroupOperation.h"
 #import "CKKSNearFutureScheduler.h"
+#import "keychain/ckks/CKKSStates.h"
 #import "keychain/ckks/CloudKitCategories.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 
 #import "keychain/ckks/CKKSTLKShareRecord.h"
 
 @interface CKKSNewTLKOperation ()
-@property NSBlockOperation* cloudkitModifyOperationFinished;
-@property CKOperationGroup* ckoperationGroup;
-
 @property (nullable) CKKSCurrentKeySet* keyset;
 @end
 
 @implementation CKKSNewTLKOperation
+@synthesize intendedState = _intendedState;
+@synthesize nextState = _nextState;
 @synthesize keyset;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+{
     if(self = [super init]) {
+        _deps = dependencies;
         _ckks = ckks;
-        _ckoperationGroup = ckoperationGroup;
+
+        _nextState = SecCKKSZoneKeyStateError;
+        _intendedState = SecCKKSZoneKeyStateWaitForTLKUpload;
     }
     return self;
 }
         return;
     }
 
+    NSArray<CKKSPeerProviderState*>* currentTrustStates = self.deps.currentTrustStates;
+
     // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety.
-    __block bool enterWaitForTLKUpload = false;
-    [ckks dispatchSyncWithAccountKeys: ^bool{
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
             ckksnotice("ckkstlk", ckks, "CKKSNewTLKOperation cancelled, quitting");
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         ckks.lastNewTLKOperation = self;
 
         ckksnotice("ckkstlk", ckks, "Old TLK is: %@ %@", oldTLK, error);
         if(error != nil) {
-            ckkserror("ckkstlk", ckks, "Couldn't fetch and unwrap old TLK: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-            return false;
+            if([self.deps.lockStateTracker isLockedError:error]) {
+                ckkserror("ckkstlk", self.deps.zoneID, "Couldn't fetch and unwrap old TLK due to lock state. Entering a waiting state; %@", error);
+                [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+            } else {
+                ckkserror("ckkstlk", self.deps.zoneID, "Couldn't fetch and unwrap old TLK: %@", error);
+                self.nextState = SecCKKSZoneKeyStateError;
+            }
+            self.error = error;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Generate new hierarchy:
         CKKSAESSIVKey* newAESKey = [CKKSAESSIVKey randomKey:&error];
         if(error) {
             ckkserror("ckkstlk", ckks, "Couldn't create new TLK: %@", error);
+            self.nextState = SecCKKSZoneKeyStateError;
             self.error = error;
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:error];
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
         newTLK = [[CKKSKey alloc] initSelfWrappedWithAESKey:newAESKey
                                                        uuid:[[NSUUID UUID] UUIDString]
         if(error != nil) {
             ckkserror("ckkstlk", ckks, "couldn't make new key hierarchy: %@", error);
             // TODO: this really isn't the error state, but a 'retry'.
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-            return false;
+            self.error = error;
+            self.nextState = SecCKKSZoneKeyStateError;
+            return CKKSDatabaseTransactionRollback;
         }
 
         CKKSCurrentKeyPointer* currentTLKPointer =    [CKKSCurrentKeyPointer forKeyClass: SecCKKSKeyClassTLK withKeyUUID:newTLK.uuid       zoneID:ckks.zoneID error: &error];
         if(error != nil) {
             ckkserror("ckkstlk", ckks, "couldn't make current key records: %@", error);
             // TODO: this really isn't the error state, but a 'retry'.
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-            return false;
+            self.nextState = SecCKKSZoneKeyStateError;
+            self.error = error;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Wrap old TLK under the new TLK
         if(wrappedOldTLK) {
             [wrappedOldTLK ensureKeyLoaded: &error];
             if(error != nil) {
-                ckkserror("ckkstlk", ckks, "couldn't unwrap TLK, aborting new TLK operation: %@", error);
-                [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-                return false;
+                if([self.deps.lockStateTracker isLockedError:error]) {
+                    ckkserror("ckkstlk", self.deps.zoneID, "Couldn't unwrap TLK due to lock state. Entering a waiting state; %@", error);
+                    [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
+                    self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+                } else {
+                    ckkserror("ckkstlk",  self.deps.zoneID, "couldn't unwrap TLK, aborting new TLK operation: %@", error);
+                    self.nextState = SecCKKSZoneKeyStateError;
+                }
+                self.error = error;
+                return CKKSDatabaseTransactionRollback;
             }
 
             [wrappedOldTLK wrapUnder: newTLK error:&error];
             // TODO: should we continue in this error state? Might be required to fix broken TLKs/argue over which TLK should be used
             if(error != nil) {
                 ckkserror("ckkstlk", ckks, "couldn't wrap oldTLK, aborting new TLK operation: %@", error);
-                [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-                return false;
+                self.nextState = SecCKKSZoneKeyStateError;
+                self.error = error;
+                return CKKSDatabaseTransactionRollback;
             }
 
             wrappedOldTLK.currentkey = false;
         }
 
         CKKSCurrentKeySet* keyset = [[CKKSCurrentKeySet alloc] init];
+        keyset.viewName = newTLK.zoneID.zoneName;
 
         keyset.tlk = newTLK;
         keyset.classA = newClassAKey;
         [newClassAKey saveKeyMaterialToKeychain: &error];
         [newClassCKey saveKeyMaterialToKeychain: &error];
         if(error) {
+            if([self.deps.lockStateTracker isLockedError:error]) {
+                ckkserror("ckkstlk", self.deps.zoneID, "Couldn't save new key material to keychain due to lock state. Entering a waiting state; %@", error);
+                [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagTLKCreationRequested];
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+            } else {
+                ckkserror("ckkstlk", self.deps.zoneID, "couldn't save new key material to keychain; aborting new TLK operation: %@", error);
+                self.nextState = SecCKKSZoneKeyStateError;
+            }
             self.error = error;
-            ckkserror("ckkstlk", ckks, "couldn't save new key material to keychain, aborting new TLK operation: %@", error);
-            [ckks _onqueueAdvanceKeyStateMachineToState: SecCKKSZoneKeyStateError withError: error];
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Generate the TLK sharing records for all trusted peers
         NSMutableSet<CKKSTLKShareRecord*>* tlkShares = [NSMutableSet set];
-        for(CKKSPeerProviderState* trustState in ckks.currentTrustStates) {
+        for(CKKSPeerProviderState* trustState in currentTrustStates) {
             if(trustState.currentSelfPeers.currentSelf == nil || trustState.currentSelfPeersError) {
                 if(trustState.essential) {
                     ckksnotice("ckkstlk", ckks, "Fatal error: unable to generate TLK shares for (%@): %@", newTLK, trustState.currentSelfPeersError);
                     self.error = trustState.currentSelfPeersError;
-                    [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError withError:trustState.currentSelfPeersError];
-                    return false;
+                    self.nextState = SecCKKSZoneKeyStateError;
+                    return CKKSDatabaseTransactionRollback;
                 }
                 ckksnotice("ckkstlk", ckks, "Unable to generate TLK shares for (%@): %@", newTLK, trustState);
                 continue;
 
         // Finish this transaction to cause a keychiain db commit
         // This means that if we provide the new keys to another thread, they'll be able to immediately load them from the keychain
-        enterWaitForTLKUpload = true;
-        return true;
+        // We'll provide the keyset after the commit occurs.
+        self.nextState = SecCKKSZoneKeyStateWaitForTLKUpload;
+        return CKKSDatabaseTransactionCommit;
     }];
 
-    if(enterWaitForTLKUpload) {
-        // And move the CKKS state machine:
-        [ckks dispatchSyncWithAccountKeys: ^bool{
-            [ckks _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForTLKUpload withError:nil];
-            return true;
-        }];
+    if(self.keyset) {
+        [self.deps provideKeySet:self.keyset];
     }
 }
 
index 2591a046c9f94a9f145c728b881e573fc80c6ed7..25531ee7d727b690b89cffc6c81d723b3106d5ce 100644 (file)
 
 #import "CKKSNotifier.h"
 #import <notify.h>
-#import <utilities/debugging.h>
+#import "keychain/ckks/CKKS.h"
 
 @implementation CKKSNotifyPostNotifier
 
 +(void)post:(NSString*)notification {
     if(notification) {
-        secnotice("ckks", "posting notification %@", notification);
+        ckksnotice_global("ckks", "posting notification %@", notification);
         notify_post([notification UTF8String]);
     }
 }
diff --git a/keychain/ckks/CKKSOperationDependencies.h b/keychain/ckks/CKKSOperationDependencies.h
new file mode 100644 (file)
index 0000000..ce1a6f5
--- /dev/null
@@ -0,0 +1,72 @@
+#if OCTAGON
+
+#import <Foundation/Foundation.h>
+#import <CloudKit/CloudKit.h>
+
+#import "keychain/ckks/CKKSCurrentKeyPointer.h"
+#import "keychain/ckks/CKKSLockStateTracker.h"
+#import "keychain/ckks/CKKSPeerProvider.h"
+#import "keychain/ckks/CKKSProvideKeySetOperation.h"
+#import "keychain/ckks/CKKSReachabilityTracker.h"
+#import "keychain/ckks/CKKSNearFutureScheduler.h"
+#import "keychain/ckks/CKKSSQLDatabaseObject.h"
+#import "keychain/ckks/CKKSZoneModifier.h"
+#import "keychain/analytics/CKKSLaunchSequence.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+#import "keychain/trust/TrustedPeers/TPSyncingPolicy.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface CKKSOperationDependencies : NSObject
+
+@property (readonly) CKRecordZoneID* zoneID;
+@property (nullable) CKOperationGroup* ckoperationGroup;
+
+@property (readonly) CKKSLaunchSequence* launch;
+@property (readonly) id<OctagonStateFlagHandler> flagHandler;
+
+@property (readonly) CKKSLockStateTracker* lockStateTracker;
+@property (readonly) CKKSReachabilityTracker* reachabilityTracker;
+
+// Due to CKKS's current operation scheduling model, these might be updated after object creation
+// For example, if an operation is created and waiting to run, and trust arrives, CKKS will reach in
+// and inject the new providers, possibly before the operation runs.
+@property (atomic) NSArray<id<CKKSPeerProvider>>* peerProviders;
+
+// Filled in after creation item creation
+@property (nullable) TPSyncingPolicy* syncingPolicy;
+
+// This is weak as, currently, the databaseProvider owns the CKKSOperationDependencies.
+@property (readonly,weak) id<CKKSDatabaseProviderProtocol> databaseProvider;
+
+@property CKKSZoneModifier* zoneModifier;
+
+@property (readonly) CKKSNearFutureScheduler* notifyViewChangedScheduler;
+@property (readonly) CKKSNearFutureScheduler* savedTLKNotifier;
+
+// This might contain some key set provider operations. if you're an operation that knows about keysets, feel free to provide them.
+@property NSHashTable<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* keysetProviderOperations;
+
+- (instancetype)initWithZoneID:(CKRecordZoneID*)zoneID
+                  zoneModifier:(CKKSZoneModifier*)zoneModifier
+              ckoperationGroup:(CKOperationGroup* _Nullable)operationGroup
+                   flagHandler:(id<OctagonStateFlagHandler>)flagHandler
+                launchSequence:(CKKSLaunchSequence*)launchSequence
+              lockStateTracker:(CKKSLockStateTracker*)lockStateTracker
+           reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker
+                 peerProviders:(NSArray<id<CKKSPeerProvider>>*)peerProviders
+              databaseProvider:(id<CKKSDatabaseProviderProtocol>)databaseProvider
+    notifyViewChangedScheduler:(CKKSNearFutureScheduler*)notifyViewChangedScheduler
+              savedTLKNotifier:(CKKSNearFutureScheduler*)savedTLKNotifier;
+
+// Convenience method to fetch the trust states from all peer providers
+// Do not call this while on the SQL transaction queue!
+- (NSArray<CKKSPeerProviderState*>*)currentTrustStates;
+
+- (void)provideKeySet:(CKKSCurrentKeySet*)keyset;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ckks/CKKSOperationDependencies.m b/keychain/ckks/CKKSOperationDependencies.m
new file mode 100644 (file)
index 0000000..db09693
--- /dev/null
@@ -0,0 +1,71 @@
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKS.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+
+@implementation CKKSOperationDependencies
+
+- (instancetype)initWithZoneID:(CKRecordZoneID*)zoneID
+                  zoneModifier:(CKKSZoneModifier*)zoneModifier
+              ckoperationGroup:(CKOperationGroup* _Nullable)operationGroup
+                   flagHandler:(id<OctagonStateFlagHandler>)flagHandler
+                launchSequence:(CKKSLaunchSequence*)launchSequence
+              lockStateTracker:(CKKSLockStateTracker*)lockStateTracker
+           reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker
+                 peerProviders:(NSArray<id<CKKSPeerProvider>>*)peerProviders
+              databaseProvider:(id<CKKSDatabaseProviderProtocol>)databaseProvider
+    notifyViewChangedScheduler:(CKKSNearFutureScheduler*)notifyViewChangedScheduler
+              savedTLKNotifier:(CKKSNearFutureScheduler*)savedTLKNotifier
+{
+    if((self = [super init])) {
+        _zoneID = zoneID;
+        _zoneModifier = zoneModifier;
+        _ckoperationGroup = operationGroup;
+        _flagHandler = flagHandler;
+        _launch = launchSequence;
+        _lockStateTracker = lockStateTracker;
+        _reachabilityTracker = reachabilityTracker;
+        _peerProviders = peerProviders;
+        _databaseProvider = databaseProvider;
+        _notifyViewChangedScheduler = notifyViewChangedScheduler;
+        _savedTLKNotifier = savedTLKNotifier;
+
+        _keysetProviderOperations = [NSHashTable weakObjectsHashTable];
+    }
+    return self;
+}
+
+- (NSArray<CKKSPeerProviderState*>*)currentTrustStates
+{
+    NSArray<id<CKKSPeerProvider>>* peerProviders = self.peerProviders;
+    NSMutableArray<CKKSPeerProviderState*>* trustStates = [NSMutableArray array];
+
+#if DEBUG
+    NSAssert(![self.databaseProvider insideSQLTransaction], @"Cannot fetch current trust states from inside a SQL transaction, on pain of deadlocK");
+#endif
+
+    for(id<CKKSPeerProvider> provider in peerProviders) {
+        ckksnotice("ckks", self.zoneID, "Fetching account keys for provider %@", provider);
+        [trustStates addObject:provider.currentState];
+    }
+
+    return trustStates;
+}
+
+- (void)provideKeySet:(CKKSCurrentKeySet*)keyset
+{
+    if(!keyset || !keyset.currentTLKPointer.currentKeyUUID) {
+        ckksnotice("ckkskey", self.zoneID, "No valid keyset provided: %@", keyset);
+        return;
+    }
+    ckksnotice("ckkskey", self.zoneID, "Providing keyset (%@) to listeners", keyset);
+
+    for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in self.keysetProviderOperations) {
+        [op provideKeySet:keyset];
+    }
+}
+
+@end
+
+#endif // OCTAGON
index dd7b00d42ad9bdf9a58b2f2b2a8581d8ff18331c..f9a4e92e60b2318f670ba2cf293840a4ca6f5c41 100644 (file)
@@ -55,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 + (instancetype)withItem:(SecDbItemRef)item
                   action:(NSString*)action
-                    ckks:(CKKSKeychainView*)ckks
+                  zoneID:(CKRecordZoneID*)zoneID
                    error:(NSError* __autoreleasing*)error;
 + (instancetype)fromDatabase:(NSString*)uuid
                        state:(NSString*)state
@@ -75,6 +75,11 @@ NS_ASSUME_NONNULL_BEGIN
                                          zoneID:(CKRecordZoneID*)zoneID
                                           error:(NSError* __autoreleasing*)error;
 
++ (NSArray<CKKSOutgoingQueueEntry*>*)allWithUUID:(NSString*)uuid
+                                          states:(NSArray<NSString*>*)states
+                                          zoneID:(CKRecordZoneID*)zoneID
+                                           error:(NSError * __autoreleasing *)error;
+
 + (NSDictionary<NSString*, NSNumber*>*)countsByStateInZone:(CKRecordZoneID*)zoneID error:(NSError* __autoreleasing*)error;
 + (NSInteger)countByState:(CKKSItemState *)state zone:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error;
 
index 4097edd9d4aface44f0adab2eedb974efe8aceaa..1db55c401119b4abb75fc5913dff4d663751f5c8 100644 (file)
             true) ? YES : NO;
 }
 
-+ (instancetype)withItem:(SecDbItemRef)item action:(NSString*)action ckks:(CKKSKeychainView*)ckks error: (NSError * __autoreleasing *) error {
+
++ (CKKSKey*)keyForItem:(SecDbItemRef)item zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error
+{
+    if(!item) {
+        ckkserror("ckks-key", zoneID, "Cannot select a key for no item!");
+        if(error) {
+            *error = [NSError errorWithDomain:CKKSErrorDomain
+                                         code:CKKSErrorUnexpectedNil
+                                  description:@"can't pick a key class for an empty item"];
+        }
+        return nil;
+    }
+
+    CKKSKeyClass* class = nil;
+
+    NSString* protection = (__bridge NSString*)SecDbItemGetCachedValueWithName(item, kSecAttrAccessible);
+    if([protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleWhenUnlocked]) {
+        class = SecCKKSKeyClassA;
+    } else if([protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAlwaysPrivate] ||
+              [protection isEqualToString: (__bridge NSString*)kSecAttrAccessibleAfterFirstUnlock]) {
+        class = SecCKKSKeyClassC;
+    } else {
+        NSError* localError = [NSError errorWithDomain:CKKSErrorDomain
+                                                  code:CKKSInvalidKeyClass
+                                           description:[NSString stringWithFormat:@"can't pick key class for protection %@", protection]];
+        ckkserror("ckks-key", zoneID, "can't pick key class: %@ %@", localError, item);
+        if(error) {
+            *error = localError;
+        }
+
+        return nil;
+    }
+
+    NSError* currentKeyError = nil;
+    CKKSKey* key = [CKKSKey currentKeyForClass:class zoneID:zoneID error:&currentKeyError];
+    if(!key || currentKeyError) {
+        ckkserror("ckks-key", zoneID, "Couldn't find current key for %@: %@", class, currentKeyError);
+
+        if(error) {
+            *error = currentKeyError;
+        }
+        return nil;
+    }
+
+    // and make sure it's unwrapped.
+    NSError* loadedError = nil;
+    if(![key ensureKeyLoaded:&loadedError]) {
+        ckkserror("ckks-key", zoneID, "Couldn't load key(%@): %@", key, loadedError);
+        if(error) {
+            *error = loadedError;
+        }
+        return nil;
+    }
+
+    return key;
+}
+
++ (instancetype)withItem:(SecDbItemRef)item
+                  action:(NSString*)action
+                  zoneID:(CKRecordZoneID*)zoneID
+                   error:(NSError * __autoreleasing *)error
+{
     CFErrorRef cferror = NULL;
     CKKSKey* key = nil;
     NSString* uuid = nil;
 
     NSMutableDictionary* objd = nil;
 
+    ckkserror("ckksitem", zoneID, "Creating a (%@) outgoing queue entry for: %@", action, item);
+
     NSError* keyError = nil;
-    key = [ckks keyForItem:item error:&keyError];
+    key = [self keyForItem:item
+                    zoneID:zoneID
+                     error:&keyError];
     if(!key || keyError) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:keyError.code description:@"No key for item" underlying:keyError];
-        ckkserror("ckksitem", ckks, "no key for item: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "no key for item: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     objd = (__bridge_transfer NSMutableDictionary*) SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &cferror);
     if(!objd) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:CFErrorGetCode(cferror) description:@"Couldn't create object plist" underlying:(__bridge_transfer NSError*)cferror];
-        ckkserror("ckksitem", ckks, "no plist: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "no plist: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     uuid = (__bridge_transfer NSString*) CFRetainSafe(SecDbItemGetValue(item, &v10itemuuid, &cferror));
     if(!uuid || cferror) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:CKKSNoUUIDOnItem description:@"No UUID for item" underlying:(__bridge_transfer NSError*)cferror];
-        ckkserror("ckksitem", ckks, "No UUID for item: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "No UUID for item: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     }
     if([uuid isKindOfClass:[NSNull class]]) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:CKKSNoUUIDOnItem description:@"UUID not found in object" underlying:nil];
-        ckkserror("ckksitem", ckks, "couldn't fetch UUID: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "couldn't fetch UUID: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     accessgroup = (__bridge_transfer NSString*) CFRetainSafe(SecDbItemGetValue(item, &v6agrp, &cferror));
     if(!accessgroup || cferror) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:CFErrorGetCode(cferror) description:@"accessgroup not found in object" underlying:(__bridge_transfer NSError*)cferror];
-        ckkserror("ckksitem", ckks, "couldn't fetch access group from item: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "couldn't fetch access group from item: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     }
     if([accessgroup isKindOfClass:[NSNull class]]) {
         // That's okay; this is only used for rate limiting.
-        ckkserror("ckksitem", ckks, "couldn't fetch accessgroup: %@", item);
+        ckkserror("ckksitem", zoneID, "couldn't fetch accessgroup: %@", item);
         accessgroup = @"no-group";
     }
 
-    CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:ckks.zoneID error:error];
+    CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:zoneID error:error];
 
     // The action this change should be depends on any existing pending action, if any
     // Particularly, we need to coalesce (existing action, new action) to:
     //    (delete, add) => modify
     NSString* actualAction = action;
 
-    CKKSOutgoingQueueEntry* existingOQE = [CKKSOutgoingQueueEntry tryFromDatabase:uuid state:SecCKKSStateNew zoneID:ckks.zoneID error:error];
+    NSError* fetchError = nil;
+    CKKSOutgoingQueueEntry* existingOQE = [CKKSOutgoingQueueEntry tryFromDatabase:uuid state:SecCKKSStateNew zoneID:zoneID error:&fetchError];
     if(existingOQE) {
         if([existingOQE.action isEqual: SecCKKSActionAdd]) {
             if([action isEqual:SecCKKSActionModify]) {
         if([existingOQE.action isEqual: SecCKKSActionDelete] && [action isEqual:SecCKKSActionAdd]) {
             actualAction = SecCKKSActionModify;
         }
+    } else if(fetchError) {
+        ckkserror("ckksitem", zoneID, "Unable to fetch an existing OQE due to error: %@", fetchError);
+        fetchError = nil;
+
+    } else {
+        if(!ckme && [action isEqualToString:SecCKKSActionDelete]) {
+            CKKSOutgoingQueueEntry* anyExistingOQE = [CKKSOutgoingQueueEntry tryFromDatabase:uuid zoneID:zoneID error:&fetchError];
+
+            if(fetchError) {
+                ckkserror("ckksitem", zoneID, "Unable to fetch an existing OQE (any state) due to error: %@", fetchError);
+            } else if(!anyExistingOQE) {
+                // This is a delete for an item which doesn't exist. Therefore, this is a no-op.
+                ckkserror("ckksitem", zoneID, "Asked to delete a record for which we don't have a CKME or any OQE, ignoring: %@", uuid);
+                return nil;
+            }
+        }
     }
 
     newGenerationCount = ckme ? ckme.item.generationCount : (NSInteger) 0; // TODO: this is wrong
 
+    // Is this modification just changing the mdat? As a performance improvement, don't update the item in CK
+    if(ckme && !existingOQE && [actualAction isEqualToString:SecCKKSActionModify]) {
+        NSError* ckmeError = nil;
+        NSMutableDictionary* mirror = [[CKKSItemEncrypter decryptItemToDictionary:ckme.item error:&ckmeError] mutableCopy];
+        NSMutableDictionary* objdCopy = [objd mutableCopy];
+
+        if(ckmeError) {
+            ckkserror("ckksitem", zoneID, "Unable to decrypt current CKME: %@", ckmeError);
+        } else {
+            mirror[(__bridge id)kSecAttrModificationDate] = nil;
+            mirror[(__bridge id)kSecAttrSHA1] = nil;
+            objdCopy[(__bridge id)kSecAttrModificationDate] = nil;
+            objdCopy[(__bridge id)kSecAttrSHA1] = nil;
+
+            if([mirror isEqualToDictionary:objdCopy]) {
+                ckksnotice("ckksitem", zoneID, "Update to item only changes mdat; skipping %@", uuid);
+                return nil;
+            }
+        }
+    }
+
     // Pull out any unencrypted fields
     NSNumber* pcsServiceIdentifier = objd[(id)kSecAttrPCSPlaintextServiceIdentifier];
     objd[(id)kSecAttrPCSPlaintextServiceIdentifier] = nil;
 
     CKKSItem* baseitem = [[CKKSItem alloc] initWithUUID:uuid
                                           parentKeyUUID:key.uuid
-                                                 zoneID:ckks.zoneID
+                                                 zoneID:zoneID
                                         encodedCKRecord:nil
                                                 encItem:nil
                                              wrappedkey:nil
 
     if(!baseitem) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:CKKSItemCreationFailure description:@"Couldn't create an item" underlying:nil];
-        ckkserror("ckksitem", ckks, "couldn't create an item: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "couldn't create an item: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
 
     if(!encryptedItem || encryptionError) {
         NSError* localerror = [NSError errorWithDomain:CKKSErrorDomain code:encryptionError.code description:@"Couldn't encrypt item" underlying:encryptionError];
-        ckkserror("ckksitem", ckks, "couldn't encrypt item: %@ %@", localerror, item);
+        ckkserror("ckksitem", zoneID, "couldn't encrypt item: %@ %@", localerror, item);
         if(error) {
             *error = localerror;
         }
     return [self allWhere: @{@"state":CKKSNilToNSNull(state), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error:error];
 }
 
++ (NSArray<CKKSOutgoingQueueEntry*>*)allWithUUID:(NSString*)uuid states:(NSArray<NSString*>*)states zoneID:(CKRecordZoneID*)zoneID error:(NSError * __autoreleasing *)error
+{
+    return [self allWhere:@{@"UUID": CKKSNilToNSNull(uuid),
+                            @"state": [[CKKSSQLWhereIn alloc] initWithValues:states],
+                            @"ckzone":CKKSNilToNSNull(zoneID.zoneName)}
+                    error:error];
+}
+
 
 #pragma mark - CKKSSQLDatabaseObject methods
 
index 9bce414218b5fe31e177b4a468203bea08321e9a..49af52dad60d9e292af3c892f2df2bba7deda004 100644 (file)
  * @APPLE_LICENSE_HEADER_END@
  */
 
-#import <Foundation/Foundation.h>
-#import "keychain/ckks/CKKSGroupOperation.h"
 
 #if OCTAGON
 
+#import <Foundation/Foundation.h>
 #import <CloudKit/CloudKit.h>
 
+#import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 
 
-@interface CKKSOutgoingQueueOperation : CKKSGroupOperation
+@interface CKKSOutgoingQueueOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 @property CKOperationGroup* ckoperationGroup;
 
 @property size_t itemsProcessed;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
-
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intending
+                          errorState:(OctagonState*)errorState
+                    ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
 @end
 
 NS_ASSUME_NONNULL_END
index 087ad6a9ff9f4431a59b3e041b826e304c689860..2af7e5d85355dd25ccbf9b59695b9c9df4c678a7 100644 (file)
 #import <CloudKit/CloudKit.h>
 #import <CloudKit/CloudKit_Private.h>
 
+#import "keychain/ckks/CKKSAnalytics.h"
+#import "keychain/ckks/CKKSCurrentKeyPointer.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSItemEncrypter.h"
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSManifest.h"
+#import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CKKSOutgoingQueueOperation.h"
+#import "keychain/ckks/CKKSReencryptOutgoingItemsOperation.h"
+#import "keychain/ckks/CKKSStates.h"
 #import "keychain/ckks/CKKSViewManager.h"
-#import "CKKSKeychainView.h"
-#import "CKKSCurrentKeyPointer.h"
-#import "CKKSOutgoingQueueOperation.h"
-#import "CKKSIncomingQueueEntry.h"
-#import "CKKSItemEncrypter.h"
-#import "CKKSOutgoingQueueEntry.h"
-#import "CKKSReencryptOutgoingItemsOperation.h"
-#import "CKKSManifest.h"
-#import "CKKSAnalytics.h"
 #import "keychain/ckks/CloudKitCategories.h"
 #import "keychain/ot/ObjCImprovements.h"
 
 #include "keychain/securityd/SecItemServer.h"
 #include "keychain/securityd/SecItemDb.h"
 #include <Security/SecItemPriv.h>
-#include <utilities/SecADWrapper.h>
 #import "CKKSPowerCollection.h"
+#import "utilities/SecCoreAnalytics.h"
 
 @interface CKKSOutgoingQueueOperation()
 @property CKModifyRecordsOperation* modifyRecordsOperation;
 @end
 
 @implementation CKKSOutgoingQueueOperation
-
-- (instancetype)init {
-    if(self = [super init]) {
-    }
-    return nil;
-}
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intending
+                          errorState:(OctagonState*)errorState
+                    ckoperationGroup:(CKOperationGroup*)ckoperationGroup
+{
     if(self = [super init]) {
+        _deps = dependencies;
         _ckks = ckks;
         _ckoperationGroup = ckoperationGroup;
 
+        _nextState = errorState;
+        _intendedState = intending;
+
         [self addNullableDependency:ckks.holdOutgoingQueueOperation];
 
         // Depend on all previous CKKSOutgoingQueueOperations
 }
 
 - (void) groupStart {
-    // Synchronous, on some thread. Get back on the CKKS queue for thread-safety.
     WEAKIFY(self);
 
     CKKSKeychainView* ckks = self.ckks;
     if(!ckks) {
-        ckkserror("ckksoutgoing", ckks, "no ckks object");
+        ckkserror("ckksoutgoing", self.deps.zoneID, "no ckks object");
         return;
     }
 
-    [ckks dispatchSync: ^bool{
-        ckks.lastOutgoingQueueOperation = self;
-        if(self.cancelled) {
-            ckksnotice("ckksoutgoing", ckks, "CKKSOutgoingQueueOperation cancelled, quitting");
-            return false;
-        }
+    if(!ckks.itemSyncingEnabled) {
+        ckkserror("ckksoutgoing", self.deps.zoneID, "Item syncing for this view is disabled");
+        return;
+    }
+
+    ckks.lastOutgoingQueueOperation = self;
+
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
 
         NSError* error = nil;
 
 
         for(NSString* uuid in priorityUUIDs) {
             NSError* priorityFetchError = nil;
-            CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase:uuid zoneID:ckks.zoneID error:&priorityFetchError];
+            CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase:uuid zoneID:self.deps.zoneID error:&priorityFetchError];
 
             if(priorityFetchError) {
-                ckkserror("ckksoutgoing", ckks, "Unable to fetch priority uuid %@: %@", uuid, priorityFetchError);
+                ckkserror("ckksoutgoing", self.deps.zoneID, "Unable to fetch priority uuid %@: %@", uuid, priorityFetchError);
                 continue;
             }
 
             }
 
             if(![oqe.state isEqualToString:SecCKKSStateNew]) {
-                ckksnotice("ckksoutgoing", ckks, "Priority uuid %@ is not in 'new': %@", uuid, oqe);
+                ckksnotice("ckksoutgoing", self.deps.zoneID, "Priority uuid %@ is not in 'new': %@", uuid, oqe);
                 continue;
             }
 
             if(oqe) {
-                ckksnotice("ckksoutgoing", ckks, "Found OQE  to fetch priority uuid %@: %@", uuid, priorityFetchError);
+                ckksnotice("ckksoutgoing", self.deps.zoneID, "Found OQE  to fetch priority uuid %@: %@", uuid, priorityFetchError);
                 [priorityEntries addObject:oqe];
                 [priorityEntryUUIDs addObject:oqe.uuid];
             }
         // We only actually care about queue items in the 'new' state
         NSArray<CKKSOutgoingQueueEntry*> * newEntries = [CKKSOutgoingQueueEntry fetch:SecCKKSOutgoingQueueItemsAtOnce
                                                                                 state:SecCKKSStateNew
-                                                                               zoneID:ckks.zoneID
+                                                                               zoneID:self.deps.zoneID
                                                                                 error:&error];
         if(error != nil) {
-            ckkserror("ckksoutgoing", ckks, "Error fetching outgoing queue records: %@", error);
+            ckkserror("ckksoutgoing", self.deps.zoneID, "Error fetching outgoing queue records: %@", error);
             self.error = error;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Build our list of oqes to transmit
 
         bool fullUpload = queueEntries.count >= SecCKKSOutgoingQueueItemsAtOnce;
 
-        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventOutgoingQueue zone:ckks.zoneName count:[queueEntries count]];
+        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventOutgoingQueue zone:self.deps.zoneID.zoneName count:[queueEntries count]];
 
-        ckksinfo("ckksoutgoing", ckks, "processing outgoing queue: %@", queueEntries);
+        ckksinfo("ckksoutgoing", self.deps.zoneID, "processing outgoing queue: %@", queueEntries);
 
         NSMutableDictionary<CKRecordID*, CKRecord*>* recordsToSave = [[NSMutableDictionary alloc] init];
         NSMutableSet<CKRecordID*>* recordIDsModified = [[NSMutableSet alloc] init];
         NSMutableSet<CKKSOutgoingQueueEntry*>*oqesModified = [[NSMutableSet alloc] init];
         NSMutableArray<CKRecordID *>* recordIDsToDelete = [[NSMutableArray alloc] init];
 
-        CKKSCurrentKeyPointer* currentClassAKeyPointer = [CKKSCurrentKeyPointer fromDatabase: SecCKKSKeyClassA zoneID:ckks.zoneID error: &error];
-        CKKSCurrentKeyPointer* currentClassCKeyPointer = [CKKSCurrentKeyPointer fromDatabase: SecCKKSKeyClassC zoneID:ckks.zoneID error: &error];
+        CKKSCurrentKeyPointer* currentClassAKeyPointer = [CKKSCurrentKeyPointer fromDatabase:SecCKKSKeyClassA zoneID:self.deps.zoneID error:&error];
+        CKKSCurrentKeyPointer* currentClassCKeyPointer = [CKKSCurrentKeyPointer fromDatabase:SecCKKSKeyClassC zoneID:self.deps.zoneID error:&error];
         NSMutableDictionary<CKKSKeyClass*, CKKSCurrentKeyPointer*>* currentKeysToSave = [[NSMutableDictionary alloc] init];
         bool needsReencrypt = false;
 
         if(error != nil) {
-            ckkserror("ckksoutgoing", ckks, "Couldn't load current class keys: %@", error);
-            return false;
+            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't load current class keys: %@", error);
+            return CKKSDatabaseTransactionRollback;
         }
 
         for(CKKSOutgoingQueueEntry* oqe in queueEntries) {
             if(self.cancelled) {
                 secdebug("ckksoutgoing", "CKKSOutgoingQueueOperation cancelled, quitting");
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
-            CKKSOutgoingQueueEntry* inflight = [CKKSOutgoingQueueEntry tryFromDatabase: oqe.uuid state:SecCKKSStateInFlight zoneID:ckks.zoneID error: &error];
+            CKKSOutgoingQueueEntry* inflight = [CKKSOutgoingQueueEntry tryFromDatabase: oqe.uuid state:SecCKKSStateInFlight zoneID:self.deps.zoneID error:&error];
             if(!error && inflight) {
                 // There is an inflight request with this UUID. Leave this request in-queue until CloudKit returns and we resolve the inflight request.
                 continue;
 
                 } else {
                     // This item is encrypted under an old key. Set it up for reencryption and move on.
-                    ckksnotice("ckksoutgoing", ckks, "Item's encryption key (%@ %@) is neither %@ or %@", oqe, oqe.item.parentKeyUUID, currentClassAKeyPointer, currentClassCKeyPointer);
+                    ckksnotice("ckksoutgoing", self.deps.zoneID, "Item's encryption key (%@ %@) is neither %@ or %@", oqe, oqe.item.parentKeyUUID, currentClassAKeyPointer, currentClassCKeyPointer);
                     [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateReencrypt error:&error];
                     if(error) {
-                        ckkserror("ckksoutgoing", ckks, "couldn't save oqe to database: %@", error);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save oqe to database: %@", error);
                         self.error = error;
                         error = nil;
                     }
             }
 
             if([oqe.action isEqualToString: SecCKKSActionAdd]) {
-                CKRecord* record = [oqe.item CKRecordWithZoneID: ckks.zoneID];
+                CKRecord* record = [oqe.item CKRecordWithZoneID:self.deps.zoneID];
                 recordsToSave[record.recordID] = record;
                 [recordIDsModified addObject: record.recordID];
                 [oqesModified addObject:oqe];
 
                 [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error];
                 if(error) {
-                    ckkserror("ckksoutgoing", ckks, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
+                    ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
                     self.error = error;
                 }
 
             } else if ([oqe.action isEqualToString: SecCKKSActionDelete]) {
-                CKRecordID* recordIDToDelete = [[CKRecordID alloc] initWithRecordName: oqe.item.uuid zoneID: ckks.zoneID];
+                CKRecordID* recordIDToDelete = [[CKRecordID alloc] initWithRecordName:oqe.item.uuid zoneID:self.deps.zoneID];
                 [recordIDsToDelete addObject: recordIDToDelete];
                 [recordIDsModified addObject: recordIDToDelete];
                 [oqesModified addObject:oqe];
 
                 [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error];
                 if(error) {
-                    ckkserror("ckksoutgoing", ckks, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
+                    ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
                 }
 
             } else if ([oqe.action isEqualToString: SecCKKSActionModify]) {
                 // Load the existing item from the ckmirror.
-                CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: oqe.item.uuid zoneID:ckks.zoneID error:&error];
+                CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:oqe.item.uuid zoneID:self.deps.zoneID error:&error];
                 if(!ckme) {
                     // This is a problem: we have an update to an item that doesn't exist.
                     // Either: an Add operation we launched failed due to a CloudKit error (conflict?) and this is a follow-on update
                     //     Or: ?
-                    ckkserror("ckksoutgoing", ckks, "update to a record that doesn't exist? %@", oqe.item.uuid);
+                    ckkserror("ckksoutgoing", self.deps.zoneID, "update to a record that doesn't exist? %@", oqe.item.uuid);
                     // treat as an add.
-                    CKRecord* record = [oqe.item CKRecordWithZoneID: ckks.zoneID];
+                    CKRecord* record = [oqe.item CKRecordWithZoneID:self.deps.zoneID];
                     recordsToSave[record.recordID] = record;
                     [recordIDsModified addObject: record.recordID];
                     [oqesModified addObject:oqe];
 
                     [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error];
                     if(error) {
-                        ckkserror("ckksoutgoing", ckks, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
                         self.error = error;
                     }
                 } else {
                     if(![oqe.item.storedCKRecord.recordChangeTag isEqual: ckme.item.storedCKRecord.recordChangeTag]) {
                         // The mirror entry has updated since this item was created. If we proceed, we might end up with
                         // a badly-authenticated record.
-                        ckksnotice("ckksoutgoing", ckks, "Record (%@)'s change tag doesn't match ckmirror's change tag, reencrypting", oqe);
+                        ckksnotice("ckksoutgoing", self.deps.zoneID, "Record (%@)'s change tag doesn't match ckmirror's change tag, reencrypting", oqe);
                         [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateReencrypt error:&error];
                         if(error) {
-                            ckkserror("ckksoutgoing", ckks, "couldn't save oqe to database: %@", error);
+                            ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save oqe to database: %@", error);
                             self.error = error;
                             error = nil;
                         }
                         continue;
                     }
                     // Grab the old ckrecord and update it
-                    CKRecord* record = [oqe.item updateCKRecord: ckme.item.storedCKRecord zoneID: ckks.zoneID];
+                    CKRecord* record = [oqe.item updateCKRecord: ckme.item.storedCKRecord zoneID: self.deps.zoneID];
                     recordsToSave[record.recordID] = record;
                     [recordIDsModified addObject: record.recordID];
                     [oqesModified addObject:oqe];
 
                     [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateInFlight error:&error];
                     if(error) {
-                        ckkserror("ckksoutgoing", ckks, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "couldn't save state for CKKSOutgoingQueueEntry: %@", error);
                     }
                 }
             }
         }
 
         if(needsReencrypt) {
-            ckksnotice("ckksoutgoing", ckks, "An item needs reencryption!");
-
-            CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:self.ckoperationGroup];
-            [ckks scheduleOperation: op];
+            ckksnotice("ckksoutgoing", self.deps.zoneID, "An item needs reencryption!");
+            [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagItemReencryptionNeeded];
         }
 
         if([recordsToSave count] == 0 && [recordIDsToDelete count] == 0) {
             // Nothing to do! exit.
-            ckksnotice("ckksoutgoing", ckks, "Nothing in outgoing queue to process");
+            ckksnotice("ckksoutgoing", self.deps.zoneID, "Nothing in outgoing queue to process");
             if(self.ckoperationGroup) {
-                ckksnotice("ckksoutgoing", ckks, "End of operation group: %@", self.ckoperationGroup);
+                ckksinfo("ckksoutgoing", self.deps.zoneID, "End of operation group: %@", self.ckoperationGroup);
             }
             return true;
         }
         modifyComplete.name = @"modifyRecordsComplete";
         [self dependOnBeforeGroupFinished: modifyComplete];
 
-        if ([CKKSManifest shouldSyncManifests]) {
-            if (ckks.egoManifest) {
-                [ckks.egoManifest updateWithNewOrChangedRecords:recordsToSave.allValues deletedRecordIDs:recordIDsToDelete];
-                for(CKRecord* record in [ckks.egoManifest allCKRecordsWithZoneID:ckks.zoneID]) {
-                    recordsToSave[record.recordID] = record;
-                }
-                NSError* saveError = nil;
-                if (![ckks.egoManifest saveToDatabase:&saveError]) {
-                    self.error = saveError;
-                    ckkserror("ckksoutgoing", ckks, "could not save ego manifest with error: %@", saveError);
-                }
-            }
-            else {
-                ckkserror("ckksoutgoing", ckks, "could not get current ego manifest to update");
-            }
-        }
-
         void (^modifyRecordsCompletionBlock)(NSArray<CKRecord*>*, NSArray<CKRecordID*>*, NSError*) = ^(NSArray<CKRecord *> *savedRecords, NSArray<CKRecordID *> *deletedRecordIDs, NSError *ckerror) {
             STRONGIFY(self);
             CKKSKeychainView* strongCKKS = self.ckks;
             if(!self || !strongCKKS) {
-                ckkserror("ckksoutgoing", strongCKKS, "received callback for released object");
+                ckkserror("ckksoutgoing", self.deps.zoneID, "received callback for released object");
                 return;
             }
 
             CKKSAnalytics* logger = [CKKSAnalytics logger];
 
-            [strongCKKS dispatchSyncWithAccountKeys: ^bool{
+            [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 if(ckerror) {
-                    ckkserror("ckksoutgoing", strongCKKS, "error processing outgoing queue: %@", ckerror);
+                    ckkserror("ckksoutgoing", self.deps.zoneID, "error processing outgoing queue: %@", ckerror);
 
                     [logger logRecoverableError:ckerror
                                        forEvent:CKKSEventProcessOutgoingQueue
-                                         inView:strongCKKS
+                                       zoneName:self.deps.zoneID.zoneName
                                  withAttributes:NULL];
 
                     // Tell CKKS about any out-of-date records
 
                         if([self _onqueueIsErrorBadEtagOnKeyPointersOnly:ckerror]) {
                             // The current key pointers have updated without our knowledge, so CloudKit failed this operation. Mark all records as 'needs reencryption' and kick that off.
-                            ckksnotice("ckksoutgoing", strongCKKS, "Error is simply due to current key pointers changing; marking all records as 'needs reencrypt'");
+                            ckksnotice("ckksoutgoing", self.deps.zoneID, "Error is simply due to current key pointers changing; marking all records as 'needs reencrypt'");
                             [self _onqueueModifyAllRecords:failedRecords.allKeys as:SecCKKSStateReencrypt];
                             askForReencrypt = true;
 
                         } else if([self _onqueueIsErrorMissingSyncKey:ckerror]) {
-                            ckksnotice("ckksoutgoing", strongCKKS, "Error is due to the key records missing. Marking all as 'needs reencrypt'");
+                            ckksnotice("ckksoutgoing", self.deps.zoneID, "Error is due to the key records missing. Marking all as 'needs reencrypt'");
                             [self _onqueueModifyAllRecords:failedRecords.allKeys as:SecCKKSStateReencrypt];
                             askForReencrypt = true;
 
                             for(CKRecordID* recordID in failedRecords) {
                                 NSError* recordError = failedRecords[recordID];
 
-                                ckksnotice("ckksoutgoing", strongCKKS, "failed record: %@ %@", recordID, recordError);
+                                ckksnotice("ckksoutgoing", self.deps.zoneID, "failed record: %@ %@", recordID, recordError);
 
                                 if([recordError.domain isEqualToString: CKErrorDomain] && recordError.code == CKErrorServerRecordChanged) {
                                     if([recordID.recordName isEqualToString: SecCKKSKeyClassA] ||
                                         CKKSOutgoingQueueEntry* inflightOQE = [CKKSOutgoingQueueEntry tryFromDatabase:recordID.recordName state:SecCKKSStateInFlight zoneID:recordID.zoneID error:&localerror];
                                         [strongCKKS _onqueueChangeOutgoingQueueEntry:inflightOQE toState:SecCKKSStateNew error:&localerror];
                                         if(localerror) {
-                                            ckkserror("ckksoutgoing", strongCKKS, "Couldn't clean up outgoing queue entry: %@", localerror);
+                                            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't clean up outgoing queue entry: %@", localerror);
                                         }
                                     }
 
                                 } else {
                                     // Some unknown error occurred on this record. If it's an OQE, move it to the error state.
-                                    ckkserror("ckksoutgoing", strongCKKS, "Unknown error on row: %@ %@", recordID, recordError);
+                                    ckkserror("ckksoutgoing", self.deps.zoneID, "Unknown error on row: %@ %@", recordID, recordError);
                                     if([recordIDsModified containsObject:recordID]) {
                                         [self _onqueueModifyRecordAsError:recordID recordError:recordError];
                                     }
                         }
 
                         if(askForReencrypt) {
-                            // This will wait for the key hierarchy to become 'ready'
-                            ckkserror("ckksoutgoing", strongCKKS, "Starting new Reencrypt items operation");
-                            CKKSReencryptOutgoingItemsOperation* op = [[CKKSReencryptOutgoingItemsOperation alloc] initWithCKKSKeychainView:strongCKKS
-                                                                                                                           ckoperationGroup:self.ckoperationGroup];
-                            [strongCKKS scheduleOperation: op];
+                            [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagItemReencryptionNeeded];
                         }
                     } else {
                         // Some non-partial error occured. We should place all "inflight" OQEs back into the outgoing queue.
-                        ckksnotice("ckks", strongCKKS, "Error is scary: putting all inflight OQEs back into state 'new'");
+                        ckksnotice("ckks", self.deps.zoneID, "Error is scary: putting all inflight OQEs back into state 'new'");
                         [self _onqueueModifyAllRecords:[recordIDsModified allObjects] as:SecCKKSStateNew];
                     }
 
                     self.error = ckerror;
-                    return true;
+                    return CKKSDatabaseTransactionCommit;
                 }
 
-                ckksnotice("ckksoutgoing", strongCKKS, "Completed processing outgoing queue (%d modifications, %d deletions)", (int)savedRecords.count, (int)deletedRecordIDs.count);
+                for(CKRecordID* deletedRecordID in deletedRecordIDs) {
+                    ckksnotice("ckksoutgoing", self.deps.zoneID, "Record deletion successful for %@", deletedRecordID.recordName);
+                }
+
+                ckksnotice("ckksoutgoing", self.deps.zoneID, "Completed processing outgoing queue (%d modifications, %d deletions)", (int)savedRecords.count, (int)deletedRecordIDs.count);
                 NSError* error = NULL;
                 CKKSPowerCollection *plstats = [[CKKSPowerCollection alloc] init];
 
                 for(CKRecord* record in savedRecords) {
                     // Save the item records
                     if([record.recordType isEqualToString: SecCKRecordItemType]) {
-                        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase: record.recordID.recordName state: SecCKKSStateInFlight zoneID:strongCKKS.zoneID error:&error];
+                        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:record.recordID.recordName
+                                                                                     state:SecCKKSStateInFlight
+                                                                                    zoneID:self.deps.zoneID
+                                                                                     error:&error];
                         [strongCKKS _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&error];
                         if(error) {
-                            ckkserror("ckksoutgoing", strongCKKS, "Couldn't update %@ in outgoingqueue: %@", record.recordID.recordName, error);
+                            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't update %@ in outgoingqueue: %@", record.recordID.recordName, error);
                             self.error = error;
                         }
                         error = nil;
                         CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKRecord: record];
                         [ckme saveToDatabase: &error];
                         if(error) {
-                            ckkserror("ckksoutgoing", strongCKKS, "Couldn't save %@ to ckmirror: %@", record.recordID.recordName, error);
+                            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't save %@ to ckmirror: %@", record.recordID.recordName, error);
                             self.error = error;
                         }
 
                         CKKSCurrentKeyPointer* currentkey = [[CKKSCurrentKeyPointer alloc] initWithCKRecord: record];
                         [currentkey saveToDatabase: &error];
                         if(error) {
-                            ckkserror("ckksoutgoing", strongCKKS, "Couldn't save %@ to currentkey: %@", record.recordID.recordName, error);
+                            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't save %@ to currentkey: %@", record.recordID.recordName, error);
                             self.error = error;
                         }
 
                         CKKSDeviceStateEntry* newcdse = [[CKKSDeviceStateEntry alloc] initWithCKRecord:record];
                         [newcdse saveToDatabase:&error];
                         if(error) {
-                            ckkserror("ckksoutgoing", strongCKKS, "Couldn't save %@ to ckdevicestate: %@", record.recordID.recordName, error);
+                            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't save %@ to ckdevicestate: %@", record.recordID.recordName, error);
                             self.error = error;
                         }
 
                     } else if ([record.recordType isEqualToString:SecCKRecordManifestType]) {
 
                     } else if (![record.recordType isEqualToString:SecCKRecordManifestLeafType]) {
-                        ckkserror("ckksoutgoing", strongCKKS, "unknown record type in results: %@", record);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "unknown record type in results: %@", record);
                     }
                 }
 
                 for(CKRecordID* ckrecordID in deletedRecordIDs) {
 
                     NSError* error = nil;
-                    CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase: ckrecordID.recordName state: SecCKKSStateInFlight zoneID:strongCKKS.zoneID error:&error];
+                    CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:ckrecordID.recordName
+                                                                                 state:SecCKKSStateInFlight
+                                                                                zoneID:self.deps.zoneID
+                                                                                 error:&error];
                     [strongCKKS _onqueueChangeOutgoingQueueEntry:oqe toState:SecCKKSStateDeleted error:&error];
                     if(error) {
-                        ckkserror("ckksoutgoing", strongCKKS, "Couldn't delete %@ from outgoingqueue: %@", ckrecordID.recordName, error);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't delete %@ from outgoingqueue: %@", ckrecordID.recordName, error);
                         self.error = error;
                     }
                     error = nil;
-                    CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: ckrecordID.recordName zoneID:strongCKKS.zoneID error:&error];
+                    CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: ckrecordID.recordName zoneID:self.deps.zoneID error:&error];
                     [ckme deleteFromDatabase: &error];
                     if(error) {
-                        ckkserror("ckksoutgoing", strongCKKS, "Couldn't delete %@ from ckmirror: %@", ckrecordID.recordName, error);
+                        ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't delete %@ from ckmirror: %@", ckrecordID.recordName, error);
                         self.error = error;
                     }
 
                 [plstats commit];
 
                 if(self.error) {
-                    ckkserror("ckksoutgoing", strongCKKS, "Operation failed; rolling back: %@", self.error);
+                    ckkserror("ckksoutgoing", self.deps.zoneID, "Operation failed; rolling back: %@", self.error);
                     [logger logRecoverableError:self.error
                                        forEvent:CKKSEventProcessOutgoingQueue
-                                         inView:strongCKKS
+                                       zoneName:strongCKKS.zoneName
                                  withAttributes:NULL];
-                    return false;
+                    return CKKSDatabaseTransactionRollback;
                 } else {
-                    [logger logSuccessForEvent:CKKSEventProcessOutgoingQueue inView:strongCKKS];
+                    [logger logSuccessForEvent:CKKSEventProcessOutgoingQueue zoneName:strongCKKS.zoneName];
                 }
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
 
+            self.nextState = self.intendedState;
             [self.operationQueue addOperation: modifyComplete];
-            // Kick off another queue process. We expect it to exit instantly, but who knows!
-            // If we think the network is iffy, though, wait for it to come back
-            CKKSResultOperation* possibleNetworkDependency = nil;
-            CKKSReachabilityTracker* reachabilityTracker = strongCKKS.reachabilityTracker;
-            if(ckerror && [reachabilityTracker isNetworkError:ckerror]) {
-                possibleNetworkDependency = reachabilityTracker.reachabilityDependency;
-            }
 
-            [strongCKKS processOutgoingQueueAfter:possibleNetworkDependency
-                                    requiredDelay:fullUpload && !ckerror ? NSEC_PER_MSEC * 100 : DISPATCH_TIME_FOREVER
-                                 ckoperationGroup:self.ckoperationGroup];
+            // If this was a "full upload", or we errored in any way, then kick off another queue process. There might be more items to send!
+            if(fullUpload || self.error) {
+                // If we think the network is iffy, though, wait for it to come back
+                CKKSResultOperation* possibleNetworkDependency = nil;
+                CKKSReachabilityTracker* reachabilityTracker = strongCKKS.reachabilityTracker;
+                if(ckerror && [reachabilityTracker isNetworkError:ckerror]) {
+                    possibleNetworkDependency = reachabilityTracker.reachabilityDependency;
+                }
+
+                [strongCKKS processOutgoingQueueAfter:possibleNetworkDependency
+                                        requiredDelay:fullUpload && !ckerror ? NSEC_PER_MSEC * 100 : DISPATCH_TIME_FOREVER
+                                     ckoperationGroup:self.ckoperationGroup];
+            }
         };
 
-        ckksinfo("ckksoutgoing", ckks, "Current keys to update: %@", currentKeysToSave);
+        ckksinfo("ckksoutgoing", self.deps.zoneID, "Current keys to update: %@", currentKeysToSave);
         for(CKKSCurrentKeyPointer* keypointer in currentKeysToSave.allValues) {
-            CKRecord* record = [keypointer CKRecordWithZoneID: ckks.zoneID];
+            CKRecord* record = [keypointer CKRecordWithZoneID:self.deps.zoneID];
             recordsToSave[record.recordID] = record;
         }
 
         // Piggyback on this operation to update our device state
         NSError* cdseError = nil;
         CKKSDeviceStateEntry* cdse = [ckks _onqueueCurrentDeviceStateEntry:&cdseError];
-        CKRecord* cdseRecord = [cdse CKRecordWithZoneID: ckks.zoneID];
+        CKRecord* cdseRecord = [cdse CKRecordWithZoneID:self.deps.zoneID];
         if(cdseError) {
-            ckkserror("ckksoutgoing", ckks, "Can't make current device state: %@", cdseError);
+            ckkserror("ckksoutgoing", self.deps.zoneID, "Can't make current device state: %@", cdseError);
         } else if(!cdseRecord) {
-            ckkserror("ckksoutgoing", ckks, "Can't make current device state cloudkit record, but no reason why");
+            ckkserror("ckksoutgoing", self.deps.zoneID, "Can't make current device state cloudkit record, but no reason why");
         } else {
             // Add the CDSE to the outgoing records
             // TODO: maybe only do this every few hours?
-            ckksnotice("ckksoutgoing", ckks, "Updating device state: %@", cdse);
+            ckksnotice("ckksoutgoing", self.deps.zoneID, "Updating device state: %@", cdse);
             recordsToSave[cdseRecord.recordID] = cdseRecord;
         }
 
-        ckksinfo("ckksoutgoing", ckks, "Saving records %@ to CloudKit zone %@", recordsToSave, ckks.zoneID);
+        ckksinfo("ckksoutgoing", self.deps.zoneID, "Saving records %@ to CloudKit zone %@", recordsToSave, self.deps.zoneID);
 
         self.modifyRecordsOperation = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:recordsToSave.allValues recordIDsToDelete:recordIDsToDelete];
         self.modifyRecordsOperation.atomic = TRUE;
 
         self.modifyRecordsOperation.savePolicy = CKRecordSaveIfServerRecordUnchanged;
         self.modifyRecordsOperation.group = self.ckoperationGroup;
-        ckksnotice("ckksoutgoing", ckks, "QoS: %d; operation group is %@", (int)self.modifyRecordsOperation.qualityOfService, self.modifyRecordsOperation.group);
-        ckksnotice("ckksoutgoing", ckks, "Beginning upload for %@ %@", recordsToSave.allKeys, recordIDsToDelete);
+        ckksnotice("ckksoutgoing", self.deps.zoneID, "QoS: %d; operation group is %@", (int)self.modifyRecordsOperation.qualityOfService, self.modifyRecordsOperation.group);
+        ckksnotice("ckksoutgoing", self.deps.zoneID, "Beginning upload for %d records, deleting %d records",
+                   (int)recordsToSave.count,
+                   (int)recordIDsToDelete.count);
+
+        for(CKRecordID* recordID in [recordsToSave allKeys]) {
+            ckksinfo("ckksoutgoing", self.deps.zoneID, "Record to save: %@", recordID);
+        }
+        for(CKRecordID* recordID in recordIDsToDelete) {
+            ckksinfo("ckksoutgoing", self.deps.zoneID, "Record to delete: %@", recordID);
+        }
 
         self.modifyRecordsOperation.perRecordCompletionBlock = ^(CKRecord *record, NSError * _Nullable error) {
             STRONGIFY(self);
-            CKKSKeychainView* blockCKKS = self.ckks;
 
             if(!error) {
-                ckksnotice("ckksoutgoing", blockCKKS, "Record upload successful for %@ (%@)", record.recordID.recordName, record.recordChangeTag);
+                ckksnotice("ckksoutgoing", self.deps.zoneID, "Record upload successful for %@ (%@)", record.recordID.recordName, record.recordChangeTag);
             } else {
-                ckkserror("ckksoutgoing", blockCKKS, "error on row: %@ %@", error, record);
+                ckkserror("ckksoutgoing", self.deps.zoneID, "error on row: %@ %@", error, record);
             }
         };
 
 - (void)_onqueueModifyRecordAsError:(CKRecordID*)recordID recordError:(NSError*)itemerror {
     CKKSKeychainView* ckks = self.ckks;
     if(!ckks) {
-        ckkserror("ckksoutgoing", ckks, "no CKKS object");
+        ckkserror("ckksoutgoing", self.deps.zoneID, "no CKKS object");
         return;
     }
 
        [recordID.recordName hasPrefix:@"ManifestLeafRecord:-:"]) {
         // Nothing to do here. We need a whole key refetch and synchronize.
     } else {
-        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:recordID.recordName state: SecCKKSStateInFlight zoneID:ckks.zoneID error:&error];
+        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:recordID.recordName state:SecCKKSStateInFlight zoneID:self.deps.zoneID error:&error];
         [ckks _onqueueErrorOutgoingQueueEntry: oqe itemError: itemerror error:&error];
         if(error) {
-            ckkserror("ckksoutgoing", ckks, "Couldn't set OQE %@ as error: %@", recordID.recordName, error);
+            ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't set OQE %@ as error: %@", recordID.recordName, error);
             self.error = error;
         }
         count ++;
 - (void)_onqueueModifyAllRecords:(NSArray<CKRecordID*>*)recordIDs as:(CKKSItemState*)state {
     CKKSKeychainView* ckks = self.ckks;
     if(!ckks) {
-        ckkserror("ckksoutgoing", ckks, "no CKKS object");
+        ckkserror("ckksoutgoing", self.deps.zoneID, "no CKKS object");
         return;
     }
 
            [recordID.recordName isEqualToString: SecCKKSKeyClassC]) {
             // Nothing to do here. We need a whole key refetch and synchronize.
         } else {
-            CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:recordID.recordName state: SecCKKSStateInFlight zoneID:ckks.zoneID error:&error];
+            CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry fromDatabase:recordID.recordName state:SecCKKSStateInFlight zoneID:self.deps.zoneID error:&error];
             [ckks _onqueueChangeOutgoingQueueEntry:oqe toState:state error:&error];
             if(error) {
-                ckkserror("ckksoutgoing", ckks, "Couldn't set OQE %@ as %@: %@", recordID.recordName, state, error);
+                ckkserror("ckksoutgoing", self.deps.zoneID, "Couldn't set OQE %@ as %@: %@", recordID.recordName, state, error);
                 self.error = error;
             }
             count ++;
     }
 
     if([state isEqualToString:SecCKKSStateReencrypt]) {
-        SecADAddValueForScalarKey((__bridge CFStringRef) SecCKKSAggdItemReencryption, count);
+        [SecCoreAnalytics sendEvent:SecCKKSAggdItemReencryption event:@{SecCoreAnalyticsValue: [NSNumber numberWithUnsignedInteger:count]}];
     }
 }
 
             NSError* recordError = failedRecords[recordID];
 
             if([recordError isCKKSServerPluginError:CKKSServerMissingRecord]) {
-                secnotice("ckksoutgoing", "Error is a 'missing record' error: %@", recordError);
+                ckksnotice("ckksoutgoing", recordID.zoneID, "Error is a 'missing record' error: %@", recordError);
                 return YES;
             }
         }
 }
 
 - (bool)_onqueueIsErrorBadEtagOnKeyPointersOnly:(NSError*)ckerror {
+    CKKSKeychainView* ckks = self.ckks;
+    dispatch_assert_queue(ckks.queue);
     bool anyOtherErrors = false;
 
     if([ckerror.domain isEqualToString:CKErrorDomain] && (ckerror.code == CKErrorPartialFailure)) {
index 4904574f9537a047aa799372f6466496d6d3a470..75d82dde515109a65561f194ecbee9de833b04a9 100644 (file)
@@ -100,8 +100,7 @@ NSString* const CKKSSOSPeerPrefix = @"spid-";
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder*)decoder
 {
-    self = [super init];
-    if(self) {
+    if ((self = [super init])) {
         _peerID = [decoder decodeObjectOfClass:[NSString class] forKey:@"peerID"];
 
         NSData* encryptionSPKI = [decoder decodeObjectOfClass:[NSData class] forKey:@"encryptionKey"];
@@ -185,8 +184,7 @@ NSString* const CKKSSOSPeerPrefix = @"spid-";
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder*)decoder
 {
-    self = [super init];
-    if(self) {
+    if ((self = [super init])) {
         _spid = [decoder decodeObjectOfClass:[NSString class] forKey:@"spid"];
 
         NSData* encryptionSPKI = [decoder decodeObjectOfClass:[NSData class] forKey:@"encryptionKey"];
index 6811e63c0620c21389dde90bb74726955f56e58e..cb9f30ece1d1e2af5c148eac0533d7a93422a1f1 100644 (file)
@@ -2,6 +2,7 @@
 
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSPeer.h"
+#import "keychain/ckks/CKKSCurrentKeyPointer.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -34,6 +35,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 #pragma mark - CKKSPeerProviderState
 
+@class CKKSKey;
+@class CKKSTLKShareRecord;
+
 @interface CKKSPeerProviderState : NSObject
 @property NSString* peerProviderID;
 
@@ -54,6 +58,13 @@ NS_ASSUME_NONNULL_BEGIN
                           trustedPeers:(NSSet<id<CKKSPeer>>* _Nullable)currentTrustedPeers
                      trustedPeersError:(NSError* _Nullable)trustedPeersError;
 
+- (NSSet<id<CKKSPeer>>* _Nullable)findPeersMissingTLKSharesFor:(CKKSCurrentKeySet*)keyset
+                                                         error:(NSError**)error;
+
+- (BOOL)unwrapKey:(CKKSKey*)proposedTLK
+       fromShares:(NSArray<CKKSTLKShareRecord*>*)tlkShares
+            error:(NSError**)error;
+
 + (CKKSPeerProviderState*)noPeersState:(id<CKKSPeerProvider>)provider;
 
 // Intended for use in PeerProviders. Thread-safety is up to the PeerProvider.
index f773204dc0e9aadb80ef8cdfe84a871781dcdd05..66fe568ae0976d11d968093183b98437f48c4f19 100644 (file)
@@ -1,6 +1,8 @@
 #if OCTAGON
 #import "keychain/ckks/CKKS.h"
+#import "keychain/ckks/CKKSKey.h"
 #import "keychain/ckks/CKKSPeerProvider.h"
+#import "keychain/ckks/CKKSTLKShareRecord.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 
 @implementation CKKSPeerProviderState
                                                     trustedPeers:currentTrustedPeers
                                                trustedPeersError:trustedPeersError];
 }
+
+// For this key, who doesn't yet have a valid CKKSTLKShare for it?
+// Note that we really want a record sharing the TLK to ourselves, so this function might return
+// a non-empty set even if all peers have the TLK: it wants us to make a record for ourself.
+- (NSSet<id<CKKSPeer>>* _Nullable)findPeersMissingTLKSharesFor:(CKKSCurrentKeySet*)keyset
+                                                         error:(NSError**)error
+{
+    if(self.currentTrustedPeersError) {
+        ckkserror("ckksshare", keyset.tlk, "Couldn't find missing shares because trusted peers aren't available: %@", self.currentTrustedPeersError);
+        if(error) {
+            *error = self.currentTrustedPeersError;
+        }
+        return [NSSet set];
+    }
+    if(self.currentSelfPeersError) {
+        ckkserror("ckksshare", keyset.tlk, "Couldn't find missing shares because self peers aren't available: %@", self.currentSelfPeersError);
+        if(error) {
+            *error = self.currentSelfPeersError;
+        }
+        return [NSSet set];
+    }
+
+    NSArray<CKKSTLKShareRecord*>* tlkShares = [keyset.tlkShares arrayByAddingObjectsFromArray:keyset.pendingTLKShares ?: @[]];
+
+    NSMutableSet<id<CKKSPeer>>* peersMissingShares = [NSMutableSet set];
+
+    // Ensure that the 'self peer' is one of the current trusted peers. Otherwise, any TLKShare we create
+    // won't be considered trusted the next time through...
+    if(![self.currentTrustedPeerIDs containsObject:self.currentSelfPeers.currentSelf.peerID]) {
+        ckkserror("ckksshare", keyset.tlk, "current self peer (%@) is not in the set of trusted peers: %@",
+                  self.currentSelfPeers.currentSelf.peerID,
+                  self.currentTrustedPeerIDs);
+
+        if(error) {
+            *error = [NSError errorWithDomain:CKKSErrorDomain
+                                         code:CKKSLackingTrust
+                                  description:[NSString stringWithFormat:@"current self peer (%@) is not in the set of trusted peers",
+                                               self.currentSelfPeers.currentSelf.peerID]];
+        }
+
+        return nil;
+    }
+
+    for(id<CKKSRemotePeerProtocol> peer in self.currentTrustedPeers) {
+        if(![peer shouldHaveView:keyset.tlk.zoneName]) {
+            ckkserror("ckksshare", keyset.tlk.keycore.zoneID, "Peer (%@) is not supposed to have view, skipping", peer);
+            continue;
+        }
+
+        // Determine if we think this peer has enough things shared to them
+        bool alreadyShared = false;
+        for(CKKSTLKShareRecord* existingShare in tlkShares) {
+            // Ensure this share is to this peer...
+            if(![existingShare.share.receiverPeerID isEqualToString:peer.peerID]) {
+                continue;
+            }
+
+            // If an SOS Peer sent this share, is its signature still valid? Or did the signing key change?
+            if([existingShare.senderPeerID hasPrefix:CKKSSOSPeerPrefix]) {
+                NSError* signatureError = nil;
+                if(![existingShare signatureVerifiesWithPeerSet:self.currentTrustedPeers error:&signatureError]) {
+                    ckksnotice("ckksshare", keyset.tlk, "Existing TLKShare's signature doesn't verify with current peer set: %@ %@", signatureError, existingShare);
+                    continue;
+                }
+            }
+
+            if([existingShare.tlkUUID isEqualToString:keyset.tlk.uuid] && [self.currentTrustedPeerIDs containsObject:existingShare.senderPeerID]) {
+                // Was this shared to us?
+                if([peer.peerID isEqualToString:self.currentSelfPeers.currentSelf.peerID]) {
+                    // We only count this as 'found' if we did the sharing and it's to our current keys
+                    NSData* currentKey = self.currentSelfPeers.currentSelf.publicEncryptionKey.keyData;
+
+                    if([existingShare.senderPeerID isEqualToString:self.currentSelfPeers.currentSelf.peerID] &&
+                       [existingShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKey]) {
+                        ckksnotice("ckksshare", keyset.tlk, "Local peer %@ is shared %@ via self: %@", peer, keyset.tlk, existingShare);
+                        alreadyShared = true;
+                        break;
+                    } else {
+                        ckksnotice("ckksshare", keyset.tlk, "Local peer %@ is shared %@ via trusted %@, but that's not good enough", peer, keyset.tlk, existingShare);
+                    }
+
+                } else {
+                    // Was this shared to the remote peer's current keys?
+                    NSData* currentKeySPKI = peer.publicEncryptionKey.keyData;
+
+                    if([existingShare.share.receiverPublicEncryptionKeySPKI isEqual:currentKeySPKI]) {
+                        // Some other peer has a trusted share. Cool!
+                        ckksnotice("ckksshare", keyset.tlk, "Peer %@ is shared %@ via trusted %@", peer, keyset.tlk, existingShare);
+                        alreadyShared = true;
+                        break;
+                    } else {
+                        ckksnotice("ckksshare", keyset.tlk, "Peer %@ has a share for %@, but to old keys: %@", peer, keyset.tlk, existingShare);
+                    }
+                }
+            }
+        }
+
+        if(!alreadyShared) {
+            // Add this peer to our set, if it has an encryption key to receive the share
+            if(peer.publicEncryptionKey) {
+                [peersMissingShares addObject:peer];
+            }
+        }
+    }
+
+    if(peersMissingShares.count > 0u) {
+        // Log each and every one of the things
+        ckksnotice("ckksshare", keyset.tlk, "Missing TLK shares for %lu peers: %@", (unsigned long)peersMissingShares.count, peersMissingShares);
+        ckksnotice("ckksshare", keyset.tlk, "Self peers are (%@) %@", self.currentSelfPeersError ?: @"no error", self.currentSelfPeers);
+        ckksnotice("ckksshare", keyset.tlk, "Trusted peers are (%@) %@", self.currentTrustedPeersError ?: @"no error", self.currentTrustedPeers);
+    }
+
+    return peersMissingShares;
+}
+
+- (BOOL)unwrapKey:(CKKSKey*)proposedTLK
+       fromShares:(NSArray<CKKSTLKShareRecord*>*)tlkShares
+            error:(NSError**)error
+{
+    if(!self.currentSelfPeers.currentSelf || self.currentSelfPeersError) {
+        ckkserror("ckksshare", proposedTLK, "Don't have self peers for %@: %@", self.peerProviderID, self.currentSelfPeersError);
+        if(error) {
+            *error = [NSError errorWithDomain:CKKSErrorDomain
+                                         code:CKKSNoEncryptionKey
+                                  description:@"Key unwrap failed"
+                                   underlying:self.currentSelfPeersError];;
+        }
+        return NO;
+    }
+
+    if(!self.currentTrustedPeers || self.currentTrustedPeersError) {
+        ckkserror("ckksshare", proposedTLK, "Don't have trusted peers: %@", self.currentTrustedPeersError);
+        if(error) {
+            *error = [NSError errorWithDomain:CKKSErrorDomain
+                                         code:CKKSNoPeersAvailable
+                                  description:@"No trusted peers"
+                               underlying:self.currentTrustedPeersError];
+        }
+        return NO;
+    }
+
+    NSError* lastShareError = nil;
+
+    for(id<CKKSSelfPeer> selfPeer in self.currentSelfPeers.allSelves) {
+        NSMutableArray<CKKSTLKShareRecord*>* possibleShares = [NSMutableArray array];
+
+        for(CKKSTLKShareRecord* share in tlkShares) {
+            if([share.share.receiverPeerID isEqualToString:selfPeer.peerID]) {
+                [possibleShares addObject:share];
+            }
+        }
+
+        if(possibleShares.count == 0) {
+            ckksnotice("ckksshare", proposedTLK, "No CKKSTLKShares to %@ for %@", selfPeer, proposedTLK);
+            continue;
+        }
+
+        for(CKKSTLKShareRecord* possibleShare in possibleShares) {
+            NSError* possibleShareError = nil;
+            ckksnotice("ckksshare", proposedTLK, "Checking possible TLK share %@ as %@", possibleShare, selfPeer);
+
+            CKKSKey* possibleKey = [possibleShare recoverTLK:selfPeer
+                                                trustedPeers:self.currentTrustedPeers
+                                                       error:&possibleShareError];
+
+            if(!possibleKey || possibleShareError) {
+                ckkserror("ckksshare", proposedTLK, "Unable to unwrap TLKShare(%@) as %@: %@",
+                          possibleShare, selfPeer, possibleShareError);
+                ckkserror("ckksshare", proposedTLK, "Current trust set: %@", self.currentTrustedPeers);
+                lastShareError = possibleShareError;
+                continue;
+            }
+
+            bool result = [proposedTLK trySelfWrappedKeyCandidate:possibleKey.aessivkey error:&possibleShareError];
+            if(!result || possibleShareError) {
+                ckkserror("ckksshare", proposedTLK, "Unwrapped TLKShare(%@) does not unwrap proposed TLK(%@) as %@: %@",
+                          possibleShare, proposedTLK, self.currentSelfPeers.currentSelf, possibleShareError);
+                lastShareError = possibleShareError;
+                continue;
+            }
+
+            ckksnotice("ckksshare", proposedTLK, "TLKShare(%@) unlocked TLK(%@) as %@",
+                       possibleShare, proposedTLK, selfPeer);
+
+            return YES;
+        }
+    }
+
+    if(error) {
+        *error = [NSError errorWithDomain:CKKSErrorDomain
+                                     code:CKKSNoTrustedTLKShares
+                              description:[NSString stringWithFormat:@"No trusted TLKShares for %@", proposedTLK]
+                               underlying:lastShareError];
+    }
+
+    return NO;
+}
+
 @end
 
 #endif
index 362843ec73a84630be885a80c084af449f26f836..ccc7fcd7d0b04f003dbc1d8ff692f091af48e7c6 100644 (file)
@@ -32,24 +32,16 @@ NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 
-// CKKS's state machine depends on its operations performing callbacks to move the state, but this means
-// the operations cannot be reused outside of the state machine context.
-// Therefore, split this operation into two: one which does the work, and another which does the CKKS state manipulation.
-
-@interface CKKSProcessReceivedKeysOperation : CKKSResultOperation
+@interface CKKSProcessReceivedKeysOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 @property CKKSZoneKeyState* nextState;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks;
-@end
-
-@interface CKKSProcessReceivedKeysStateMachineOperation : CKKSResultOperation
-@property (weak) CKKSKeychainView* ckks;
-
-- (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks;
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
 @end
 
 NS_ASSUME_NONNULL_END
index 3ccc4fe1ca90caf0651cbae97b09763d85c7ac69..d626171fd8efaa88d91108928062a357bba3f800 100644 (file)
 #import "CKKSCurrentKeyPointer.h"
 #import "CKKSKey.h"
 #import "CKKSProcessReceivedKeysOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
 #import "keychain/ckks/CloudKitCategories.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 
 @implementation CKKSProcessReceivedKeysOperation
+@synthesize intendedState = _intendedState;
 
-- (instancetype)init {
-    return nil;
-}
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks {
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
     if(self = [super init]) {
-        _ckks = ckks;
-        _nextState = SecCKKSZoneKeyStateError;
+        _deps = dependencies;
+        _intendedState = intendedState;
+        _nextState = errorState;
     }
     return self;
 }
 
 - (void)main {
-    // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety.
+    NSArray<CKKSPeerProviderState*>* currentTrustStates = self.deps.currentTrustStates;
 
-    CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        secerror("ckkskeys: No CKKS object");
-        return;
-    }
-
-    if(self.cancelled) {
-        ckksinfo("ckkskey", ckks, "CKKSProcessReceivedKeysOperation cancelled, quitting");
-        return;
-    }
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult {
+        bool ok = [self _onqueueMain:currentTrustStates];
 
-    [ckks dispatchSyncWithAccountKeys: ^bool{
-        return [self _onqueueMain:ckks];
+        return ok ? CKKSDatabaseTransactionCommit : CKKSDatabaseTransactionRollback;
     }];
 }
 
-- (bool)_onqueueMain:(CKKSKeychainView*)ckks
+- (bool)_onqueueMain:(NSArray<CKKSPeerProviderState*>*)currentTrustStates
 {
-    if(self.cancelled) {
-        ckksinfo("ckkskey", ckks, "CKKSProcessReceivedKeysOperation cancelled, quitting");
-        return false;
-    }
-
-    ckks.lastProcessReceivedKeysOperation = self;
-
     NSError* error = nil;
     CKKSKey* tlk = nil;
     CKKSKey* topKey = nil;
     // Updates from CloudKit are marked 'remote'; everything else is 'local'.
 
     // Step 1. Find all remote keys.
-    NSArray<CKKSKey*>* remoteKeys = [CKKSKey remoteKeys:ckks.zoneID error:&error];
+    NSArray<CKKSKey*>* remoteKeys = [CKKSKey remoteKeys:self.deps.zoneID error:&error];
     if(!remoteKeys) {
-        ckkserror("ckkskey", ckks, "couldn't fetch list of remote keys: %@", error);
+        ckkserror("ckkskey", self.deps.zoneID, "couldn't fetch list of remote keys: %@", error);
         self.error = error;
         self.nextState = SecCKKSZoneKeyStateError;
         return false;
     }
 
     if([remoteKeys count] == 0u) {
-        ckksnotice("ckkskey", ckks, "No remote keys? Quitting.");
+        ckksnotice("ckkskey", self.deps.zoneID, "No remote keys? Quitting.");
         // Not a ready state, more of a quizzical one? The key state machine will know what to do.
         self.error = error;
-        self.nextState = SecCKKSZoneKeyStateReady;
+        self.nextState = SecCKKSZoneKeyStateBecomeReady;
         return false;
     }
 
-    ckksinfo("ckkskey", ckks, "remote keys: %@", remoteKeys);
+    ckksinfo("ckkskey", self.deps.zoneID, "remote keys: %@", remoteKeys);
 
     // current TLK record:
-    CKKSCurrentKeyPointer* currentTLKPointer    = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassTLK zoneID:ckks.zoneID error:&error];
-    CKKSCurrentKeyPointer* currentClassAPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassA   zoneID:ckks.zoneID error:&error];
-    CKKSCurrentKeyPointer* currentClassCPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassC   zoneID:ckks.zoneID error:&error];
+    CKKSCurrentKeyPointer* currentTLKPointer    = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassTLK zoneID:self.deps.zoneID error:&error];
+    CKKSCurrentKeyPointer* currentClassAPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassA   zoneID:self.deps.zoneID error:&error];
+    CKKSCurrentKeyPointer* currentClassCPointer = [CKKSCurrentKeyPointer tryFromDatabase: SecCKKSKeyClassC   zoneID:self.deps.zoneID error:&error];
 
     // Do these pointers point at anything?
     NSError* localerror = nil;
-    CKKSKey* suggestedTLK    = currentTLKPointer.currentKeyUUID    ? [CKKSKey tryFromDatabaseAnyState:currentTLKPointer.currentKeyUUID    zoneID:ckks.zoneID error:&localerror] : nil;
-    CKKSKey* suggestedClassA = currentClassAPointer.currentKeyUUID ? [CKKSKey tryFromDatabaseAnyState:currentClassAPointer.currentKeyUUID zoneID:ckks.zoneID error:&localerror] : nil;
-    CKKSKey* suggestedClassC = currentClassCPointer.currentKeyUUID ? [CKKSKey tryFromDatabaseAnyState:currentClassCPointer.currentKeyUUID zoneID:ckks.zoneID error:&localerror] : nil;
+    CKKSKey* suggestedTLK    = currentTLKPointer.currentKeyUUID    ? [CKKSKey tryFromDatabaseAnyState:currentTLKPointer.currentKeyUUID    zoneID:self.deps.zoneID error:&localerror] : nil;
+    CKKSKey* suggestedClassA = currentClassAPointer.currentKeyUUID ? [CKKSKey tryFromDatabaseAnyState:currentClassAPointer.currentKeyUUID zoneID:self.deps.zoneID error:&localerror] : nil;
+    CKKSKey* suggestedClassC = currentClassCPointer.currentKeyUUID ? [CKKSKey tryFromDatabaseAnyState:currentClassCPointer.currentKeyUUID zoneID:self.deps.zoneID error:&localerror] : nil;
 
     if(!currentTLKPointer || !currentClassAPointer || !currentClassCPointer ||
        !currentTLKPointer.currentKeyUUID || !currentClassAPointer.currentKeyUUID || !currentClassCPointer.currentKeyUUID ||
        !suggestedTLK || !suggestedClassA || !suggestedClassC) {
-        ckkserror("ckkskey", ckks, "no current pointer for some keyclass: tlk:%@ a:%@ c:%@ %@ %@",
+        ckkserror("ckkskey", self.deps.zoneID, "no current pointer for some keyclass: tlk:%@ a:%@ c:%@ %@ %@",
                  currentTLKPointer, currentClassAPointer, currentClassCPointer, error, localerror);
         self.error = error;
         self.nextState = SecCKKSZoneKeyStateBadCurrentPointers;
                 tlk = key;
             } else {
                 NSError *newError = [NSError errorWithDomain:CKKSErrorDomain code:CKKSKeyNotSelfWrapped description:[NSString stringWithFormat: @"current TLK doesn't wrap itself: %@ %@", key, key.parentKeyUUID] underlying:error];
-                ckkserror("ckkskey", ckks, "%@", error);
+                ckkserror("ckkskey", self.deps.zoneID, "%@", error);
                 self.error = newError;
                 self.nextState = SecCKKSZoneKeyStateUnhealthy;
                 return true;
     }
 
     if(!tlk) {
-        ckkserror("ckkskey", ckks, "couldn't find active TLK: %@", currentTLKPointer);
+        ckkserror("ckkskey", self.deps.zoneID, "couldn't find active TLK: %@", currentTLKPointer);
         self.error = error;
         self.nextState = SecCKKSZoneKeyStateUnhealthy;
         return true;
     }
 
-    // This key is our proposed TLK. Check with the CKKS object.
-    if(![ckks _onqueueWithAccountKeysCheckTLK: tlk error: &error]) {
-        // Was this error "I've never seen that TLK before in my life"? If so, enter the "wait for TLK sync" state.
-        if(error && [error.domain isEqualToString: @"securityd"] && error.code == errSecItemNotFound) {
-            ckksnotice("ckkskey", ckks, "Received a TLK which we don't have in the local keychain(%@). Entering waitfortlk.", tlk);
-            self.nextState = SecCKKSZoneKeyStateWaitForTLK;
-            return true;
-        } else if(error && [ckks.lockStateTracker isLockedError:error]) {
-            // TODO: _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateError should handle this. But, we don't have tests, so, leave this in until 33204154
-            ckksnotice("ckkskey", ckks, "Received a TLK(%@), but keybag appears to be locked. Entering a waiting state.", tlk);
+    if(![tlk validTLK:&error]) {
+        // Something has gone horribly wrong. Enter error state.
+        ckkserror("ckkskey", self.deps.zoneID, "CKKS claims %@ is not a valid TLK: %@", tlk, error);
+        self.error  = [NSError errorWithDomain:CKKSErrorDomain code:CKKSInvalidTLK description:@"invalid TLK from CloudKit" underlying:error];
+        self.nextState = SecCKKSZoneKeyStateError;
+        return true;
+    }
+
+    // This key is our proposed TLK.
+    if(![tlk tlkMaterialPresentOrRecoverableViaTLKShare:currentTrustStates
+                                                  error:&error]) {
+        // TLK is valid, but not present locally
+        if(error && [self.deps.lockStateTracker isLockedError:error]) {
+            ckksnotice("ckkskey", self.deps.zoneID, "Received a TLK(%@), but keybag appears to be locked. Entering a waiting state.", tlk);
             self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
-            return true;
         } else {
-            // Otherwise, something has gone horribly wrong. enter error state.
-            ckkserror("ckkskey", ckks, "CKKS claims %@ is not a valid TLK: %@", tlk, error);
-            self.error  = [NSError errorWithDomain:CKKSErrorDomain code:CKKSInvalidTLK description:@"invalid TLK from CloudKit" underlying:error];
-            self.nextState = SecCKKSZoneKeyStateError;
-            return true;
+            ckksnotice("ckkskey", self.deps.zoneID, "Received a TLK(%@) which we don't have in the local keychain: %@", tlk, error);
+            self.error = error;
+            self.nextState = SecCKKSZoneKeyStateTLKMissing;
         }
+        return true;
     }
 
     // Ensure that new keys wrap to the TLK.
         topKey = [key topKeyInAnyState:&error];
 
         if(error != nil || ![topKey.uuid isEqual: tlk.uuid]) {
-            ckkserror("ckkskey", ckks, "new key %@ is orphaned (%@)", key, error);
+            ckkserror("ckkskey", self.deps.zoneID, "new key %@ is orphaned (%@)", key, error);
             // TODO: possibly re-fetch. Maybe not an actual error state.
             self.error = [NSError errorWithDomain:CKKSErrorDomain
                                              code:CKKSOrphanedKey
 
         // Okay, it wraps to the TLK. Can we unwrap it?
         if(![key unwrapViaKeyHierarchy:&error] || error != nil) {
-            if(error && [ckks.lockStateTracker isLockedError:error]) {
-                ckksnotice("ckkskey", ckks, "Couldn't unwrap new key (%@), but keybag appears to be locked. Entering waitforunlock.", key);
+            if(error && [self.deps.lockStateTracker isLockedError:error]) {
+                ckksnotice("ckkskey", self.deps.zoneID, "Couldn't unwrap new key (%@), but keybag appears to be locked. Entering waitforunlock.", key);
                 self.error = error;
                 self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
                 return true;
             } else {
-                ckkserror("ckkskey", ckks, "new key %@ claims to wrap to TLK, but we can't unwrap it: %@", topKey, error);
+                ckkserror("ckkskey", self.deps.zoneID, "new key %@ claims to wrap to TLK, but we can't unwrap it: %@", topKey, error);
                 self.error = [NSError errorWithDomain:CKKSErrorDomain
                                                  code:CKKSOrphanedKey
                                           description:[NSString stringWithFormat:@"unwrappable key(%@) in hierarchy: %@", topKey, error]
             }
         }
 
-        ckksnotice("ckkskey", ckks, "New key %@ wraps to tlk %@", key, tlk);
+        ckksnotice("ckkskey", self.deps.zoneID, "New key %@ wraps to tlk %@", key, tlk);
     }
 
 
 
         [key saveKeyMaterialToKeychain: &error];
 
+
         if(error) {
-            ckkserror("ckkskey", ckks, "couldn't save newly local key %@ to database: %@", key, error);
+            if([self.deps.lockStateTracker isLockedError:error]) {
+                ckksnotice("ckkskey", self.deps.zoneID, "Couldn't save newly local key %@ keychain, due to lock state. Entering a waiting state; %@", key, error);
+                self.nextState = SecCKKSZoneKeyStateWaitForUnlock;
+            } else {
+                ckkserror("ckkskey", self.deps.zoneID, "couldn't save newly local key %@ to database: %@", key, error);
+                self.nextState = SecCKKSZoneKeyStateError;
+            }
             self.error = error;
-            self.nextState = SecCKKSZoneKeyStateError;
             return false;
         }
     }
 
     // New key hierarchy? Get it backed up!
     // TLKs are now saved in the local keychain; fire off a backup
-    CKKSNearFutureScheduler* tlkNotifier = ckks.savedTLKNotifier;
-    ckksnotice("ckkstlk", ckks, "triggering new TLK notification: %@", tlkNotifier);
+    CKKSNearFutureScheduler* tlkNotifier = self.deps.savedTLKNotifier;
+    ckksnotice("ckkstlk", self.deps.zoneID, "triggering new TLK notification: %@", tlkNotifier);
     [tlkNotifier trigger];
 
     if(!error) {
-        ckksnotice("ckkskey", ckks, "Accepted new key hierarchy");
-        self.nextState = SecCKKSZoneKeyStateReady;
+        ckksnotice("ckkskey", self.deps.zoneID, "Accepted new key hierarchy");
+        self.nextState = self.intendedState;
     } else {
-        ckkserror("ckkskey", ckks, "error accepting new key hierarchy: %@", error);
+        ckkserror("ckkskey", self.deps.zoneID, "error accepting new key hierarchy: %@", error);
         self.error = error;
         self.nextState = SecCKKSZoneKeyStateError;
     }
 
 @end;
 
-@implementation CKKSProcessReceivedKeysStateMachineOperation
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks {
-    if(self = [super init]) {
-        _ckks = ckks;
-    }
-    return self;
-}
-
-- (void)main
-{
-    CKKSKeychainView* ckks = self.ckks;
-
-    // The following is an abuse of operations, but we need the state machine advancement to be in the same txion as the decision
-    CKKSProcessReceivedKeysOperation* op = [[CKKSProcessReceivedKeysOperation alloc] initWithCKKSKeychainView:ckks];
-
-    [ckks dispatchSyncWithAccountKeys:^bool {
-        bool ret = [op _onqueueMain:ckks];
-        ckksnotice("ckkskey", ckks, "Finished processing received keys, moving to state %@", op.nextState);
-        [ckks _onqueueAdvanceKeyStateMachineToState:op.nextState withError:op.error];
-        return ret;
-    }];
-}
-
-@end
-
 #endif
index 5ea8c2fecb97d8754ca5d84529348620f497afe6..f037108ebf859943a041db6dca1f6941403c6124 100644 (file)
@@ -23,7 +23,6 @@ NS_ASSUME_NONNULL_BEGIN
 //     But! -timeout: will work, and the operation will finish
 @interface CKKSProvideKeySetOperation : CKKSGroupOperation <CKKSKeySetProviderOperationProtocol>
 - (instancetype)initWithZoneName:(NSString*)zoneName;
-- (instancetype)initWithZoneName:(NSString*)zoneName keySet:(CKKSCurrentKeySet*)set;
 
 - (void)provideKeySet:(CKKSCurrentKeySet*)keyset;
 @end
index 0ea2aa79c578ffa6f13521ed168d11747fd03d93..a274764a2361dbcb6bb503f8e098e4a33ab02cc7 100644 (file)
@@ -5,6 +5,7 @@
 
 @interface CKKSProvideKeySetOperation ()
 @property (nullable) CKKSCurrentKeySet* keyset;
+@property dispatch_queue_t queue;
 
 @property (nullable) NSOperation* startDependency;
 @end
         _zoneName = zoneName;
         _keyset = nil;
         _startDependency = [NSBlockOperation blockOperationWithBlock:^{}];
+        _startDependency.name = @"key-set-provided";
 
-        [self addDependency:_startDependency];
-    }
-    return self;
-}
+        _queue = dispatch_queue_create("key-set-queue", DISPATCH_QUEUE_SERIAL);
 
-- (instancetype)initWithZoneName:(NSString*)zoneName keySet:(CKKSCurrentKeySet*)set
-{
-    if((self = [super init])) {
-        _zoneName = zoneName;
-        _keyset = set;
-        _startDependency = nil;
+        [self addDependency:_startDependency];
     }
     return self;
 }
 
 - (void)provideKeySet:(CKKSCurrentKeySet *)keyset
 {
-    self.keyset = keyset;
-    if(self.startDependency) {
-        [[NSOperationQueue currentQueue] addOperation:self.startDependency];
-        self.startDependency = nil;
-    }
+    // Ensure that only one keyset is provided through each operation
+    dispatch_sync(self.queue, ^{
+        if(!self.keyset) {
+            self.keyset = keyset;
+            if(self.startDependency) {
+                // Create a new queue here, just to be safe in case someone is waiting
+                NSOperationQueue* queue = [[NSOperationQueue alloc] init];
+                [queue addOperation:self.startDependency];
+                self.startDependency = nil;
+            }
+        }
+    });
+
 }
 @end
 
index 7eb34b36d33d7e510c7279aaa51a58f50882af0f..9994c922ed8c6463b28851006ab4ca6418a91065 100644 (file)
@@ -23,7 +23,6 @@
 
 #if OCTAGON
 #import "CKKSRateLimiter.h"
-#import <utilities/debugging.h>
 #import <TargetConditionals.h>
 
 typedef NS_ENUM(int, BucketType) {
@@ -45,8 +44,7 @@ typedef NS_ENUM(int, BucketType) {
 }
 
 - (instancetype)initWithCoder:(NSCoder *)coder {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         if (coder) {
             NSDictionary *encoded;
             encoded = [coder decodeObjectOfClasses:[NSSet setWithObjects:[NSDictionary class],
index d13ecc3c087f83427cb2eea5a02dddf2e968aabb..736a7367737ef1435aca97a077659b7ac12e5eb1 100644 (file)
@@ -71,7 +71,7 @@
                 STRONGIFY(self);
                 bool networkAvailable = (nw_path_get_status(path) == nw_path_status_satisfied);
 
-                secinfo("ckksnetwork", "nw_path update: network is %@", networkAvailable ? @"available" : @"unavailable");
+                ckksinfo_global("ckksnetwork", "nw_path update: network is %@", networkAvailable ? @"available" : @"unavailable");
                 [self _onqueueSetNetworkReachability:networkAvailable];
             });
             nw_path_monitor_start(self.networkMonitor);
     if(self.reachabilityDependency == nil || ![self.reachabilityDependency isPending]) {
         WEAKIFY(self);
 
-        secnotice("ckksnetwork", "Network unavailable");
+        ckksnotice_global("network", "Network unavailable");
         self.reachabilityDependency = [CKKSResultOperation named:@"network-available-dependency" withBlock: ^{
             STRONGIFY(self);
             if (self.haveNetwork) {
-                secnotice("ckksnetwork", "Network available");
+                ckksnotice_global("network", "Network available");
             } else {
-                secnotice("ckksnetwork", "Network still not available, retrying after waiting %2.1f hours",
-                        ((float)(REACHABILITY_TIMEOUT/NSEC_PER_SEC)) / 3600);
+                ckksnotice_global("network", "Network still not available, retrying after waiting %2.1f hours",
+                                  ((float)(REACHABILITY_TIMEOUT/NSEC_PER_SEC)) / 3600);
             }
         }];
 
index bb9db9138566eb64a08a54d12a786c5f9e010cf2..3ad87f77846379ffd069fac6558405a05e0937c9 100644 (file)
@@ -54,7 +54,7 @@
         _encodedCKRecord = encodedCKRecord;
 
         if(self.encodedCKRecord && ![self.storedCKRecord.recordID.zoneID isEqual: self.zoneID]) {
-            secerror("ckks: mismatching zone ids in a single record: %@ and %@", self.zoneID, self.storedCKRecord.recordID.zoneID);
+            ckkserror("ckks", self.zoneID, "mismatching zone ids in a single record: %@ and %@", self.zoneID, self.storedCKRecord.recordID.zoneID);
         }
     }
     return self;
index e8947de59d48168698491688490f08126ab6823f..ae94d53c3e77e00d4f318108885953c21afd96fd 100644 (file)
 #import <CloudKit/CloudKit.h>
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
 
-@interface CKKSReencryptOutgoingItemsOperation : CKKSResultOperation
-
+@interface CKKSReencryptOutgoingItemsOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
 
 @end
 
index 6727f3bbf402c699244b1578cd6555132ea11e3c..f50324d517bc7282a20d805f4458083495f6ca3f 100644 (file)
 
 // Note: reencryption is not, strictly speaking, a CloudKit operation. However, we preserve this to pass it back to the outgoing queue operation we'll create
 @interface CKKSReencryptOutgoingItemsOperation ()
-@property CKOperationGroup* ckoperationGroup;
 @end
 
 @implementation CKKSReencryptOutgoingItemsOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
     if(self = [super init]) {
+        _deps = dependencies;
         _ckks = ckks;
-        _ckoperationGroup = ckoperationGroup;
+
+        _nextState = errorState;
+        _intendedState = intendedState;
 
         [self addNullableDependency:ckks.keyStateReadyDependency];
         [self addNullableDependency:ckks.holdReencryptOutgoingItemsOperation];
 
         // We also depend on the key hierarchy being reasonable
         [self addNullableDependency:ckks.keyStateReadyDependency];
-
     }
     return self;
 }
 
-- (void) main {
+- (void)main
+{
     CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksreencrypt", ckks, "no CKKS object");
-        return;
-    }
 
-    [ckks dispatchSync: ^bool{
+    [self.deps.databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
-            ckksnotice("ckksreencrypt", ckks, "CKKSReencryptOutgoingItemsOperation cancelled, quitting");
-            return false;
+            ckksnotice("ckksreencrypt", self.deps.zoneID, "CKKSReencryptOutgoingItemsOperation cancelled, quitting");
+            return CKKSDatabaseTransactionRollback;
         }
 
         ckks.lastReencryptOutgoingItemsOperation = self;
         NSError* error = nil;
         bool newItems = false;
 
-        NSArray<CKKSOutgoingQueueEntry*>* oqes = [CKKSOutgoingQueueEntry allInState: SecCKKSStateReencrypt zoneID:ckks.zoneID error:&error];
+        NSArray<CKKSOutgoingQueueEntry*>* oqes = [CKKSOutgoingQueueEntry allInState:SecCKKSStateReencrypt zoneID:self.deps.zoneID error:&error];
         if(error) {
-            ckkserror("ckksreencrypt", ckks, "Error fetching oqes from database: %@", error);
+            ckkserror("ckksreencrypt", self.deps.zoneID, "Error fetching oqes from database: %@", error);
             self.error = error;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
-        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventReencryptOutgoing  zone:ckks.zoneName count:oqes.count];
+        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventReencryptOutgoing zone:self.deps.zoneID.zoneName count:oqes.count];
 
         for(CKKSOutgoingQueueEntry* oqe in oqes) {
             // If there's already a 'new' item replacing this one, drop the reencryption on the floor
             CKKSOutgoingQueueEntry* newOQE = [CKKSOutgoingQueueEntry tryFromDatabase:oqe.uuid state:SecCKKSStateNew zoneID:oqe.item.zoneID error:&error];
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't load 'new' OQE to determine status: %@", error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't load 'new' OQE to determine status: %@", error);
                 self.error = error;
                 error = nil;
                 continue;
             }
             if(newOQE) {
-                ckksnotice("ckksreencrypt", ckks, "Have a new OQE superceding %@ (%@), skipping", oqe, newOQE);
+                ckksnotice("ckksreencrypt", self.deps.zoneID, "Have a new OQE superceding %@ (%@), skipping", oqe, newOQE);
                 // Don't use the state transition here, either, since this item isn't really changing states
                 [oqe deleteFromDatabase:&error];
                 if(error) {
-                    ckkserror("ckksreencrypt", ckks, "Couldn't delete reencrypting OQE(%@) from database: %@", oqe, error);
+                    ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't delete reencrypting OQE(%@) from database: %@", oqe, error);
                     self.error = error;
                     error = nil;
                     continue;
                 continue;
             }
 
-            ckksnotice("ckksreencrypt", ckks, "Reencrypting item %@", oqe);
+            ckksnotice("ckksreencrypt", self.deps.zoneID, "Reencrypting item %@", oqe);
 
             NSDictionary* item = [CKKSItemEncrypter decryptItemToDictionary: oqe.item error:&error];
             if(error) {
                 if ([error.domain isEqualToString:@"securityd"] && error.code == errSecItemNotFound) {
-                    ckkserror("ckksreencrypt", ckks, "Couldn't find key in keychain; attempting to poke key hierarchy: %@", error);
-                    [ckks.pokeKeyStateMachineScheduler trigger];
+                    ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't find key in keychain; asking for reset: %@", error);
+                    [ckks _onqueuePokeKeyStateMachine];
+                    self.nextState = SecCKKSZoneKeyStateUnhealthy;
                 } else {
-                    ckkserror("ckksreencrypt", ckks, "Couldn't decrypt item %@: %@", oqe, error);
+                    ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't decrypt item %@: %@", oqe, error);
                 }
                 self.error = error;
                 error = nil;
             }
 
             // Pick a key whose class matches the keyclass that this item
-            CKKSKey* originalKey = [CKKSKey fromDatabase: oqe.item.parentKeyUUID zoneID:ckks.zoneID error:&error];
+            CKKSKey* originalKey = [CKKSKey fromDatabase: oqe.item.parentKeyUUID zoneID:self.deps.zoneID error:&error];
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't fetch key (%@) for item %@: %@", oqe.item.parentKeyUUID, oqe, error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't fetch key (%@) for item %@: %@", oqe.item.parentKeyUUID, oqe, error);
                 self.error = error;
                 error = nil;
                 continue;
             }
 
-            CKKSKey* newkey = [CKKSKey currentKeyForClass: originalKey.keyclass zoneID:ckks.zoneID error:&error];
+            CKKSKey* newkey = [CKKSKey currentKeyForClass: originalKey.keyclass zoneID:self.deps.zoneID error:&error];
             [newkey ensureKeyLoaded: &error];
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't fetch the current key for class %@: %@", originalKey.keyclass, error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't fetch the current key for class %@: %@", originalKey.keyclass, error);
                 self.error = error;
                 error = nil;
                 continue;
             }
 
-            CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:oqe.item.uuid zoneID:ckks.zoneID error:&error];
+            CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:oqe.item.uuid zoneID:self.deps.zoneID error:&error];
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't fetch ckme (%@) for item %@: %@", oqe.item.parentKeyUUID, oqe, error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't fetch ckme (%@) for item %@: %@", oqe.item.parentKeyUUID, oqe, error);
                 self.error = error;
                 error = nil;
                 continue;
                                                                    error:&error];
 
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't encrypt under the new key %@: %@", newkey, error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't encrypt under the new key %@: %@", newkey, error);
                 self.error = error;
                 error = nil;
                 continue;
             [oqe deleteFromDatabase:&error];
             [replacement saveToDatabase:&error];
             if(error) {
-                ckkserror("ckksreencrypt", ckks, "Couldn't save newly-encrypted oqe %@: %@", replacement, error);
+                ckkserror("ckksreencrypt", self.deps.zoneID, "Couldn't save newly-encrypted oqe %@: %@", replacement, error);
                 self.error = error;
                 error = nil;
                 continue;
 
         CKKSAnalytics* logger = [CKKSAnalytics logger];
         if (self.error) {
-            [logger logRecoverableError:error forEvent:CKKSEventProcessReencryption inView:ckks withAttributes:nil];
+            [logger logRecoverableError:error forEvent:CKKSEventProcessReencryption zoneName:self.deps.zoneID.zoneName withAttributes:nil];
         } else {
-            [logger logSuccessForEvent:CKKSEventProcessReencryption inView:ckks];
+            [logger logSuccessForEvent:CKKSEventProcessReencryption zoneName:self.deps.zoneID.zoneName ];
         }
 
         if(newItems) {
-            [ckks processOutgoingQueue:self.ckoperationGroup];
+            [ckks processOutgoingQueue:self.deps.ckoperationGroup];
         }
+        self.nextState = self.intendedState;
         return true;
     }];
 }
index 5b29fcccd833e4970f63783fef1123ab11d1d6cf..318f366508ef7d8ddfb50e71e91dfa2ea8dd960b 100644 (file)
@@ -45,7 +45,7 @@ enum {
 @property (nullable) NSDate* finishDate;
 @property CKKSCondition* completionHandlerDidRunCondition;
 
-@property NSInteger descriptionErrorCode; // Set to non-0 for inclusion of this operation in NSError chains. Code is application-dependent.
+@property NSInteger descriptionErrorCode; // Set to non-0 for inclusion of this operation in NSError chains. Code is application-dependent, but will be -1 in cases of excessive recursion.
 
 // If you subclass CKKSResultOperation, this is the method corresponding to descriptionErrorCode. Fill it in to your heart's content.
 - (NSError* _Nullable)descriptionError;
index 57417657e9fc4212127ea38d1c4103c580250093..8228f0e6eb2c21fa7cd28927b10e8792b44d3928 100644 (file)
@@ -28,7 +28,7 @@
 #import "keychain/ckks/CKKSCondition.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #import "keychain/ot/ObjCImprovements.h"
-#include <utilities/debugging.h>
+#import "keychain/ckks/CKKS.h"
 
 @interface CKKSResultOperation()
 @property NSMutableArray<CKKSResultOperation*>* successDependencies;
@@ -92,7 +92,7 @@
     [super setCompletionBlock:^(void) {
         STRONGIFY(self);
         if (!self) {
-            secerror("ckksresultoperation: completion handler called on deallocated operation instance");
+            ckkserror_global("resultoperation", "completion handler called on deallocated operation instance");
             completionBlock(); // go ahead and still behave as things would if this method override were not here
             return;
         }
 // Returns, for this CKKSResultOperation, an error describing this operation or its dependents.
 // Used mainly by other CKKSResultOperations who time out waiting for this operation to start/complete.
 - (NSError* _Nullable)descriptionError {
+    static __thread unsigned __descriptionRecursion = 0;
+
+    NSError* result = nil;
+
+    __descriptionRecursion += 1;
+
     if(self.descriptionErrorCode != 0) {
-        return [NSError errorWithDomain:CKKSResultDescriptionErrorDomain
-                                   code:self.descriptionErrorCode
-                               userInfo:nil];
+        result = [NSError errorWithDomain:CKKSResultDescriptionErrorDomain
+                                     code:self.descriptionErrorCode
+                                 userInfo:nil];
+    } else if(__descriptionRecursion > 10) {
+        result = [NSError errorWithDomain:CKKSResultDescriptionErrorDomain
+                                     code:-1
+                              description:@"Excess recursion"];
     } else {
-        return [self dependenciesDescriptionError];
+        result = [self dependenciesDescriptionError];
     }
+
+    __descriptionRecursion -= 1;
+
+    return result;
 }
 
 - (NSError*)_onqueueTimeoutError {
+    dispatch_assert_queue(self.timeoutQueue);
     // Find if any of our dependencies are CKKSResultOperations with a custom reason for existing
 
     NSError* underlyingReason = [self descriptionError];
index 718954e8519b5925c488fb726f478626f3134ca6..3b9e492a5b0d86398080ba1e01bfeb228c0464f4 100644 (file)
@@ -52,6 +52,9 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithData:(NSData*)data;
 - (NSData*)wrappedData;
 - (NSString*)base64WrappedKey;
+
+// Almost certainly not a valid key; use if you need a placeholder
++ (CKKSWrappedAESSIVKey*)zeroedKey;
 @end
 
 @interface CKKSAESSIVKey : CKKSBaseAESSIVKey
@@ -71,6 +74,9 @@ NS_ASSUME_NONNULL_BEGIN
                authenticatedData:(NSDictionary<NSString*, NSData*>* _Nullable)ad
                            error:(NSError* __autoreleasing*)error;
 
+// Please only call this if you're storing this key to the keychain, or sending it to a peer.
+- (NSData*)keyMaterial;
+
 @end
 
 NS_ASSUME_NONNULL_END
index dde5f3c102395a266a4386fe3cd03d68cf06e972..7388162cfe13af97bf7bb53d13f00dce1b917569 100644 (file)
 }
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)decoder {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         NSUInteger len = 0;
         const uint8_t * bytes = [decoder decodeBytesForKey:@"wrappedkey" returnedLength:&len];
 
     return self;
 }
 
++ (CKKSWrappedAESSIVKey*)zeroedKey
+{
+    NSData* zeroedData = [NSMutableData dataWithLength:CKKSWrappedKeySize];
+    return [[CKKSWrappedAESSIVKey alloc] initWithData:zeroedData];
+}
+
 @end
 
 @implementation CKKSAESSIVKey
@@ -427,6 +432,11 @@ out:
     return localerror == NULL;
 }
 
+- (NSData*)keyMaterial
+{
+    return [NSData _newZeroingDataWithBytes:self->key length:self->size];
+}
+
 
 @end
 
index a4698b38a08106cc922db6b3792464a8841a8a67..c857976300778739549cf0c7ca48a8056e4785d3 100644 (file)
@@ -53,6 +53,26 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSData* _Nullable)asBase64DecodedData;
 @end
 
+// These thread-local variables should be set by your database layer
+// This ensures that all SQL write operations are performed under the protection of a transaction.
+// Use [CKKSSQLDatabaseObject +performCKKSTransaction] to get one of these if you don't have any other mechanism.
+extern __thread bool CKKSSQLInTransaction;
+extern __thread bool CKKSSQLInWriteTransaction;
+
+typedef NS_ENUM(uint8_t, CKKSDatabaseTransactionResult) {
+    CKKSDatabaseTransactionRollback = 0,
+    CKKSDatabaseTransactionCommit = 1,
+};
+
+// A database provider must provide these operations.
+@protocol CKKSDatabaseProviderProtocol
+- (void)dispatchSyncWithSQLTransaction:(CKKSDatabaseTransactionResult (^)(void))block;
+- (void)dispatchSyncWithReadOnlySQLTransaction:(void (^)(void))block;
+
+// Used to maintain lock ordering.
+- (BOOL)insideSQLTransaction;
+@end
+
 @interface CKKSSQLDatabaseObject : NSObject <NSCopying>
 
 @property (copy) NSDictionary<NSString*, NSString*>* originalSelfWhereClause;
@@ -114,6 +134,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 + (NSString *)quotedString:(NSString *)string;
 
++ (BOOL)performCKKSTransaction:(CKKSDatabaseTransactionResult (^)(void))block;
+
 #pragma mark - Subclasses must implement the following:
 
 // Given a row from the database, make this object
@@ -171,5 +193,10 @@ NSString* CKKSSQLWhereColumnNameAsString(CKKSSQLWhereColumnName columnName);
 + (instancetype)op:(CKKSSQLWhereComparator)op value:(NSString*)value;
 @end
 
+@interface CKKSSQLWhereIn : NSObject
+@property NSArray<NSString*>* values;
+- (instancetype)initWithValues:(NSArray<NSString*>*)values;
+@end
+
 
 NS_ASSUME_NONNULL_END
index f8c70d96a7457b3b86c0c942d33767688e30a955..55b1dc24ea10f9eadda8c365428474873b3cc3a5 100644 (file)
@@ -24,6 +24,7 @@
 #import <Foundation/Foundation.h>
 #import "CKKSSQLDatabaseObject.h"
 #include "keychain/securityd/SecItemServer.h"
+#include "keychain/securityd/SecItemDb.h"
 
 #import "keychain/ckks/CKKS.h"
 #import "CKKSKeychainView.h"
 }
 @end
 
+__thread bool CKKSSQLInTransaction = false;
+__thread bool CKKSSQLInWriteTransaction = false;
+
 @implementation CKKSSQLDatabaseObject
 
 + (bool) saveToDatabaseTable: (NSString*) table row: (NSDictionary*) row connection: (SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error {
     __block CFErrorRef cferror = NULL;
 
+#if DEBUG
+    NSAssert(CKKSSQLInTransaction, @"Must be in a transaction to perform database writes");
+    NSAssert(CKKSSQLInWriteTransaction, @"Must be in a write transaction to perform database writes");
+#endif
+
     bool (^doWithConnection)(SecDbConnectionRef) = ^bool (SecDbConnectionRef dbconn) {
         NSString * columns = [row.allKeys componentsJoinedByString:@", "];
         NSMutableString * values = [[NSMutableString alloc] init];
              CKKSSQLWhereComparatorAsString(obj.sqlOp),
              CKKSSQLWhereColumnNameAsString(obj.columnName)];
 
+        } else if([value isMemberOfClass:[CKKSSQLWhereIn class]]) {
+            CKKSSQLWhereIn* obj = (CKKSSQLWhereIn*)value;
+
+            NSMutableArray* q = [NSMutableArray arrayWithCapacity:obj.values.count];
+            for(NSString* value in obj.values) {
+                [q addObject: @"?"];
+                (void)value;
+            }
+
+            NSString* binds = [q componentsJoinedByString:@", "];
+
+            [whereClause appendFormat:@"%@ IN (%@)", key, binds];
+
         } else {
             [whereClause appendFormat: @"%@=(?)", key];
         }
 
 + (void)bindWhereClause:(sqlite3_stmt*)stmt whereDict:(NSDictionary*)whereDict cferror:(CFErrorRef*)cferror
 {
-    __block int whereObjectsSkipped = 0;
+    __block int whereLocation = 1;
+
     [whereDict.allKeys enumerateObjectsUsingBlock:^(id  _Nonnull key, NSUInteger i, BOOL * _Nonnull stop) {
         if([whereDict[key] class] == [CKKSSQLWhereValue class]) {
             CKKSSQLWhereValue* obj = (CKKSSQLWhereValue*)whereDict[key];
-            SecDbBindObject(stmt, (int)(i+1-whereObjectsSkipped), (__bridge CFStringRef)obj.value, cferror);
+            SecDbBindObject(stmt, whereLocation, (__bridge CFStringRef)obj.value, cferror);
+            whereLocation++;
+
         } else if([whereDict[key] class] == [CKKSSQLWhereColumn class]) {
             // skip
-            whereObjectsSkipped += 1;
+        } else if([whereDict[key] isMemberOfClass:[CKKSSQLWhereIn class]]) {
+            CKKSSQLWhereIn* obj = (CKKSSQLWhereIn*)whereDict[key];
+
+            for(NSString* value in obj.values) {
+                SecDbBindObject(stmt, whereLocation, (__bridge CFStringRef)value, cferror);
+                whereLocation++;
+            }
+
         } else {
-            SecDbBindObject(stmt, (int)(i+1-whereObjectsSkipped), (__bridge CFStringRef) whereDict[key], cferror);
+            SecDbBindObject(stmt, whereLocation, (__bridge CFStringRef) whereDict[key], cferror);
+            whereLocation++;
         }
     }];
 }
 + (bool) deleteFromTable: (NSString*) table where: (NSDictionary*) whereDict connection:(SecDbConnectionRef) dbconn error: (NSError * __autoreleasing *) error {
     __block CFErrorRef cferror = NULL;
 
+#if DEBUG
+    NSAssert(CKKSSQLInTransaction, @"Must be in a transaction to perform database writes");
+    NSAssert(CKKSSQLInWriteTransaction, @"Must be in a write transaction to perform database writes");
+#endif
+
     bool (^doWithConnection)(SecDbConnectionRef) = ^bool (SecDbConnectionRef dbconn) {
         NSString* whereClause = [CKKSSQLDatabaseObject makeWhereClause: whereDict];
 
     return ret;
 }
 
++ (BOOL)performCKKSTransaction:(CKKSDatabaseTransactionResult (^)(void))block
+{
+    CFErrorRef cferror = NULL;
+    bool ok = kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbconn) {
+        CFErrorRef cferrorInternal = NULL;
+        bool ret = kc_transaction_type(dbconn, kSecDbExclusiveRemoteCKKSTransactionType, &cferrorInternal, ^bool{
+            CKKSDatabaseTransactionResult result = CKKSDatabaseTransactionRollback;
+
+            CKKSSQLInTransaction = true;
+            CKKSSQLInWriteTransaction = true;
+            result = block();
+            CKKSSQLInWriteTransaction = false;
+            CKKSSQLInTransaction = false;
+            return result == CKKSDatabaseTransactionCommit;
+        });
+        if(cferrorInternal) {
+            ckkserror_global("ckkssql",  "error performing database transaction, major problems ahead: %@", cferrorInternal);
+        }
+        CFReleaseNull(cferrorInternal);
+        return ret;
+    });
+
+    if(cferror) {
+        ckkserror_global("ckkssql",  "error performing database operation, major problems ahead: %@", cferror);
+    }
+    CFReleaseNull(cferror);
+    return ok;
+}
+
++ (BOOL)performCKKSReadonlyTransaction:(void(^)(void))block
+{
+    CFErrorRef cferror = NULL;
+    bool ok = kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbconn) {
+        CFErrorRef cferrorInternal = NULL;
+        bool ret = kc_transaction_type(dbconn, kSecDbNormalTransactionType, &cferrorInternal, ^bool{
+            CKKSSQLInTransaction = true;
+            block();
+            CKKSSQLInTransaction = false;
+            return true;
+        });
+        if(cferrorInternal) {
+            ckkserror_global("ckkssql",  "error performing database transaction, major problems ahead: %@", cferrorInternal);
+        }
+        CFReleaseNull(cferrorInternal);
+        return ret;
+    });
+
+    if(cferror) {
+        ckkserror_global("ckkssql",  "error performing database operation, major problems ahead: %@", cferror);
+    }
+    CFReleaseNull(cferror);
+    return ok;
+}
+
 #pragma mark - Instance methods
 
 - (bool) saveToDatabase: (NSError * __autoreleasing *) error {
@@ -579,3 +671,15 @@ NSString* CKKSSQLWhereColumnNameAsString(CKKSSQLWhereColumnName columnName)
 
 }
 @end
+
+#pragma mark - CKKSSQLWhereIn
+
+@implementation CKKSSQLWhereIn : NSObject
+- (instancetype)initWithValues:(NSArray<NSString*>*)values
+{
+    if((self = [super init])) {
+         _values = values;
+    }
+    return self;
+}
+@end
index 0ad03e5789caf367258f6c5028f4d90fe152518a..3b1f930aa991d648b41d48ec8b1974d2758a143c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2016-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
 
 #import <Foundation/Foundation.h>
 
-#import "keychain/ckks/CKKSGroupOperation.h"
-
 #if OCTAGON
 
+#import "keychain/ckks/CKKSResultOperation.h"
+#import "keychain/ckks/CKKSOperationDependencies.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+
 NS_ASSUME_NONNULL_BEGIN
 
 @class CKKSKeychainView;
-@class CKKSEgoManifest;
 
-@interface CKKSScanLocalItemsOperation : CKKSResultOperation
-@property CKOperationGroup* ckoperationGroup;
+@interface CKKSScanLocalItemsOperation : CKKSResultOperation <OctagonStateTransitionOperationProtocol>
+@property (nullable) CKOperationGroup* ckoperationGroup;
 
+@property CKKSOperationDependencies* deps;
 @property (weak) CKKSKeychainView* ckks;
 
 @property size_t recordsFound;
@@ -43,8 +45,11 @@ NS_ASSUME_NONNULL_BEGIN
 @property size_t missingLocalItemsFound;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup;
-
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+                    ckoperationGroup:(CKOperationGroup* _Nullable)ckoperationGroup;
 @end
 
 NS_ASSUME_NONNULL_END
index 3c3a6afe4533ca1206a264488113c482aa20f853..e1f66eb8ff7fb24d6a4967b975a349b2598f04a2 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #if OCTAGON
-#import <TrustedPeers/TPPolicy.h>
+#import <TrustedPeers/TPSyncingPolicy.h>
 #import <TrustedPeers/TPPBPolicyKeyViewMapping.h>
 #import <TrustedPeers/TPDictionaryMatchingRules.h>
 
@@ -36,8 +36,9 @@
 #import "keychain/ckks/CKKSGroupOperation.h"
 #import "keychain/ckks/CKKSKey.h"
 #import "keychain/ckks/CKKSViewManager.h"
-#import "keychain/ckks/CKKSManifest.h"
 #import "keychain/ckks/CKKSItemEncrypter.h"
+#import "keychain/ckks/CKKSStates.h"
+#import "keychain/ckks/CKKSZoneStateEntry.h"
 
 #import "CKKSPowerCollection.h"
 
 
 @interface CKKSScanLocalItemsOperation ()
 @property (assign) NSUInteger processedItems;
+
+@property BOOL newCKKSEntries;
 @end
 
 @implementation CKKSScanLocalItemsOperation
+@synthesize nextState = _nextState;
+@synthesize intendedState = _intendedState;
 
 - (instancetype)init {
     return nil;
 }
-- (instancetype)initWithCKKSKeychainView:(CKKSKeychainView*)ckks ckoperationGroup:(CKOperationGroup*)ckoperationGroup {
-    if(self = [super init]) {
+- (instancetype)initWithDependencies:(CKKSOperationDependencies*)dependencies
+                                ckks:(CKKSKeychainView*)ckks
+                           intending:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+                    ckoperationGroup:(CKOperationGroup*)ckoperationGroup
+{
+    if((self = [super init])) {
+        _deps = dependencies;
         _ckks = ckks;
         _ckoperationGroup = ckoperationGroup;
+
+        _nextState = errorState;
+        _intendedState = intendedState;
+
         _recordsFound = 0;
         _recordsAdded = 0;
     }
     return self;
 }
 
-// returns true if the currently loaded TPPolicy in the view manager says that only items with a VewHint
-// matching the viewName belong to this view.
-- (BOOL)policyRecommendsOnlyViewHintItems:(CKKSKeychainView*)ckks
-{
-    // Early-exit for when feature is not on:
-    if(![[CKKSViewManager manager] useCKKSViewsFromPolicy]) {
-        return YES;
-    }
-
+- (NSDictionary*)queryPredicatesForViewMapping {
     TPPBPolicyKeyViewMapping* viewRule = nil;
 
-    // If there's more than one rule matching this view, then exit with NO.
+    // If there's more than one rule matching this view, then exit with an empty dictionary: the language doesn't support ORs.
     for(TPPBPolicyKeyViewMapping* mapping in [CKKSViewManager manager].policy.keyViewMapping) {
-        if([mapping.view isEqualToString:ckks.zoneName]) {
+        if([mapping.view isEqualToString:self.deps.zoneID.zoneName]) {
             if(viewRule == nil) {
                 viewRule = mapping;
             } else {
                 // Too many rules for this view! Don't perform optimization.
-                ckksnotice("ckksscan", ckks, "Too many policy rules for view %@", ckks.zoneName);
-                return NO;
+                ckksnotice("ckksscan", self.deps.zoneID, "Too many policy rules for view %@", self.deps.zoneID.zoneName);
+                return @{};
             }
         }
     }
        !viewRule.matchingRule.hasNot &&
        !viewRule.matchingRule.hasExists &&
        viewRule.matchingRule.hasMatch) {
-        if([@"vwht" isEqualToString:viewRule.matchingRule.match.fieldName] &&
-           [viewRule.matchingRule.match.regex isEqualToString:[NSString stringWithFormat:@"^%@$", ckks.zoneName]]) {
-            return YES;
+        if([((id)kSecAttrSyncViewHint) isEqualToString:viewRule.matchingRule.match.fieldName] &&
+           [viewRule.matchingRule.match.regex isEqualToString:[NSString stringWithFormat:@"^%@$", self.deps.zoneID.zoneName]]) {
+            return @{
+                (id)kSecAttrSyncViewHint: self.deps.zoneID.zoneName,
+            };
+        } else if([((id)kSecAttrAccessGroup) isEqualToString:viewRule.matchingRule.match.fieldName] &&
+                  [viewRule.matchingRule.match.regex isEqualToString:@"^com\\.apple\\.cfnetwork$"]) {
+            // We can't match on any regex agrp match, because it might be some actually difficult regex. But, we know about this one!
+            return @{
+                (id)kSecAttrAccessGroup: @"com.apple.cfnetwork",
+            };
+
+        } else if([((id)kSecAttrAccessGroup) isEqualToString:viewRule.matchingRule.match.fieldName] &&
+                  [viewRule.matchingRule.match.regex isEqualToString:@"^com\\.apple\\.safari\\.credit-cards$"]) {
+            // We can't match on any regex agrp match, because it might be some actually difficult regex. But, we know about this one!
+            return @{
+                (id)kSecAttrAccessGroup: @"com.apple.safari.credit-cards",
+            };
+
         } else {
-            ckksnotice("ckksscan", ckks, "Policy view rule is not a match against viewhint: %@", viewRule);
+            ckksnotice("ckksscan", self.deps.zoneID, "Policy view rule is not a match against viewhint: %@", viewRule);
         }
     } else {
-        ckksnotice("ckksscan", ckks, "Policy view rule is of unknown type: %@", viewRule);
+        ckksnotice("ckksscan", self.deps.zoneID, "Policy view rule is complex: %@", viewRule);
     }
 
-    return NO;
+    return @{};
 }
 
-- (void) main {
-    // Take a strong reference.
-    CKKSKeychainView* ckks = self.ckks;
-    if(!ckks) {
-        ckkserror("ckksscan", ckks, "no CKKS object");
+- (BOOL)executeQuery:(NSDictionary*)queryPredicates readWrite:(bool)readWrite error:(NSError**)error block:(void (^_Nonnull)(SecDbItemRef item))block
+{
+    __block CFErrorRef cferror = NULL;
+    __block bool ok = false;
+
+    Query *q = query_create_with_limit((__bridge CFDictionaryRef)queryPredicates, NULL, kSecMatchUnlimited, NULL, &cferror);
+
+    if(cferror) {
+        ckkserror("ckksscan", self.deps.zoneID, "couldn't create query: %@", cferror);
+        SecTranslateError(error, cferror);
+        return NO;
+    }
+
+    ok = kc_with_dbt(readWrite, &cferror, ^(SecDbConnectionRef dbt) {
+        return SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) {
+            block(item);
+        });
+    });
+
+    if(readWrite) {
+        ok = query_notify_and_destroy(q, ok, &cferror);
+    } else {
+        ok = query_destroy(q, &cferror);
+    }
+
+    if(cferror || !ok) {
+        ckkserror("ckksscan", self.deps.zoneID, "couldn't execute query: %@", cferror);
+        SecTranslateError(error, cferror);
+        return NO;
+    }
+
+    return YES;
+}
+
+- (BOOL)onboardItemToCKKS:(SecDbItemRef)item error:(NSError**)error
+{
+    NSError* itemSaveError = nil;
+
+    CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry withItem:item
+                                                            action:SecCKKSActionAdd
+                                                            zoneID:self.deps.zoneID
+                                                             error:&itemSaveError];
+
+    if(itemSaveError) {
+        ckkserror("ckksscan", self.deps.zoneID, "Need to upload %@, but can't create outgoing entry: %@", item, itemSaveError);
+        if(error) {
+            *error = itemSaveError;
+        }
+        return NO;
+    }
+
+    ckksnotice("ckksscan", self.deps.zoneID, "Syncing new item: %@", oqe);
+
+    [oqe saveToDatabase:&itemSaveError];
+    if(itemSaveError) {
+        ckkserror("ckksscan", self.deps.zoneID, "Need to upload %@, but can't save to database: %@", oqe, itemSaveError);
+        self.error = itemSaveError;
+        return NO;
+    }
+
+    self.newCKKSEntries = true;
+    self.recordsAdded += 1;
+
+    return YES;
+}
+
+- (void)onboardItemsWithUUIDs:(NSSet<NSString*>*)uuids itemClass:(NSString*)itemClass databaseProvider:(id<CKKSDatabaseProviderProtocol>)databaseProvider
+{
+    ckksnotice("ckksscan", self.deps.zoneID, "Found %d missing %@ items", (int)uuids.count, itemClass);
+    // Use one transaction for each item to allow for SecItem API calls to interleave
+    for(NSString* itemUUID in uuids) {
+        [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult {
+            NSDictionary* queryAttributes = @{
+                (id)kSecClass: itemClass,
+                (id)kSecReturnRef: @(YES),
+                (id)kSecAttrSynchronizable: @(YES),
+                (id)kSecAttrTombstone: @(NO),
+                (id)kSecAttrUUID: itemUUID,
+            };
+
+            ckksnotice("ckksscan", self.deps.zoneID, "Onboarding %@ %@", itemClass, itemUUID);
+
+            __block NSError* itemSaveError = nil;
+
+            [self executeQuery:queryAttributes readWrite:false error:&itemSaveError block:^(SecDbItemRef itemToSave) {
+                [self onboardItemToCKKS:itemToSave error:&itemSaveError];
+            }];
+
+            if(itemSaveError) {
+                ckkserror("ckksscan", self.deps.zoneID, "Need to upload %@, but can't save to database: %@", itemUUID, itemSaveError);
+                self.error = itemSaveError;
+                return CKKSDatabaseTransactionRollback;
+            }
+
+            return CKKSDatabaseTransactionCommit;
+        }];
+    }
+}
+
+- (void)fixUUIDlessItemsWithPrimaryKeys:(NSMutableSet<NSDictionary*>*)primaryKeys databaseProvider:(id<CKKSDatabaseProviderProtocol>)databaseProvider
+{
+    ckksnotice("ckksscan", self.deps.zoneID, "Found %d items missing UUIDs", (int)primaryKeys.count);
+
+    if([primaryKeys count] == 0) {
         return;
     }
 
-    [ckks.launch addEvent:@"scan-local-items"];
+    [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        __block NSError* itemError = nil;
+
+        for(NSDictionary* primaryKey in primaryKeys) {
+            ckksnotice("ckksscan", self.deps.zoneID, "Found item with no uuid: %@", primaryKey);
+
+            __block CFErrorRef cferror = NULL;
+
+            bool connectionSuccess = kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
+                Query *q = query_create_with_limit((__bridge CFDictionaryRef)primaryKey, NULL, kSecMatchUnlimited, NULL, &cferror);
+
+                if(!q || cferror) {
+                    ckkserror("ckksscan", self.deps.zoneID, "couldn't create query: %@", cferror);
+                    return false;
+                }
+
+                __block bool ok = true;
+
+                ok &= SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef uuidlessItem, bool *stop) {
+                    NSString* uuid = [[NSUUID UUID] UUIDString];
+                    NSDictionary* updates = @{(id)kSecAttrUUID: uuid};
+
+                    ckksnotice("ckksscan", self.deps.zoneID, "Assigning new UUID %@ for item %@", uuid, uuidlessItem);
+
+                    SecDbItemRef new_item = SecDbItemCopyWithUpdates(uuidlessItem, (__bridge CFDictionaryRef)updates, &cferror);
+
+                    if(!new_item) {
+                        SecTranslateError(&itemError, cferror);
+                        self.error = itemError;
+                        ckksnotice("ckksscan", self.deps.zoneID, "Unable to copy item with new UUID: %@", cferror);
+                        return;
+                    }
+
+                    bool updateSuccess = kc_transaction_type(dbt, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, ^{
+                        return SecDbItemUpdate(uuidlessItem, new_item, dbt, kCFBooleanFalse, q->q_uuid_from_primary_key, &cferror);
+                    });
+
+                    if(updateSuccess) {
+                        [self onboardItemToCKKS:new_item error:&itemError];
+                    } else {
+                        ckksnotice("ckksscan", self.deps.zoneID, "Unable to update item with new UUID: %@", cferror);
+                    }
+
+                    ok &= updateSuccess;
+                });
+
+                ok &= query_notify_and_destroy(q, ok, &cferror);
+
+                return true;
+            });
 
-    [ckks dispatchSyncWithAccountKeys: ^bool{
-        if(self.cancelled) {
-            ckksnotice("ckksscan", ckks, "CKKSScanLocalItemsOperation cancelled, quitting");
-            return false;
+            if(!connectionSuccess) {
+                ckkserror("ckksscan", self.deps.zoneID, "couldn't execute query: %@", cferror);
+                SecTranslateError(&itemError, cferror);
+                self.error = itemError;
+                return CKKSDatabaseTransactionRollback;
+            }
         }
-        ckks.lastScanLocalItemsOperation = self;
 
-        NSMutableArray* itemsForManifest = [NSMutableArray array];
+        return CKKSDatabaseTransactionCommit;
+    }];
+}
+
+- (void)retriggerMissingMirrorEntires:(NSSet<NSString*>*)mirrorUUIDs
+                                 ckks:(CKKSKeychainView*)ckks
+                     databaseProvider:(id<CKKSDatabaseProviderProtocol>)databaseProvider
+{
+    if (mirrorUUIDs.count > 0) {
+        [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+            NSError* error = nil;
+            ckkserror("ckksscan", self.deps.zoneID, "BUG: keychain missing %lu items from mirror and/or queues: %@", (unsigned long)mirrorUUIDs.count, mirrorUUIDs);
+            self.missingLocalItemsFound = mirrorUUIDs.count;
+
+            [[CKKSAnalytics logger] logMetric:[NSNumber numberWithUnsignedInteger:mirrorUUIDs.count] withName:CKKSEventMissingLocalItemsFound];
+
+            for (NSString* uuid in mirrorUUIDs) {
+                CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:self.deps.zoneID error:&error];
 
+                if(!ckme || error) {
+                    ckkserror("ckksscan", self.deps.zoneID, "BUG: error fetching previously-extant CKME (uuid: %@) from database: %@", uuid, error);
+                    self.error = error;
+                } else {
+                    [ckks _onqueueCKRecordChanged:ckme.item.storedCKRecord resync:true];
+                }
+            }
+
+            // And, if you're not in the tests, try to collect a sysdiagnose I guess?
+            // <rdar://problem/36166435> Re-enable IMCore autosysdiagnose capture to securityd
+            //if(SecIsInternalRelease() && !SecCKKSTestsEnabled()) {
+            //    [[IMCloudKitHooks sharedInstance] tryToAutoCollectLogsWithErrorString:@"35810558" sendLogsTo:@"rowdy_bot@icloud.com"];
+            //}
+            return CKKSDatabaseTransactionCommit;
+        }];
+    } else {
+        ckksnotice("ckksscan", self.deps.zoneID,"No missing local items found");
+    }
+}
+
+- (void)main
+{
+    if(SecCKKSTestsEnabled() && SecCKKSTestSkipScan()) {
+        ckksnotice("ckksscan", self.deps.zoneID, "Scan cancelled by test request");
+        return;
+    }
+
+    // We need to not be jetsamed while running this
+    os_transaction_t transaction = os_transaction_create([[NSString stringWithFormat:@"com.apple.securityd.ckks.scan.%@", self.deps.zoneID] UTF8String]);
+
+    id<CKKSDatabaseProviderProtocol> databaseProvider = self.deps.databaseProvider;
+    CKKSKeychainView* ckks = self.ckks;
+
+    [self.deps.launch addEvent:@"scan-local-items"];
+
+    // A map of ItemClass -> Set of found UUIDs
+    NSMutableDictionary<NSString*, NSMutableSet<NSString*>*>* itemUUIDsNotYetInCKKS = [NSMutableDictionary dictionary];
+
+    // A list of primary keys of items that fit in this view, but have no UUIDs
+    NSMutableSet<NSDictionary*>* primaryKeysWithNoUUIDs = [NSMutableSet set];
+
+    // We want this set to be empty after scanning, or else the keychain (silently) dropped something on the floor
+    NSMutableSet<NSString*>* mirrorUUIDs = [NSMutableSet set];
+
+    [databaseProvider dispatchSyncWithReadOnlySQLTransaction:^{
         // First, query for all synchronizable items
-        __block CFErrorRef cferror = NULL;
         __block NSError* error = nil;
-        __block bool newEntries = false;
 
-        // We want this set to be empty after scanning, or else the keychain (silently) dropped something on the floor
-        NSMutableSet<NSString*>* mirrorUUIDs = [NSMutableSet setWithArray:[CKKSMirrorEntry allUUIDs:ckks.zoneID error:&error]];
+        [mirrorUUIDs addObjectsFromArray:[CKKSMirrorEntry allUUIDs:self.deps.zoneID error:&error]];
 
         // Must query per-class, so:
         const SecDbSchema *newSchema = current_schema();
         for (const SecDbClass *const *class = newSchema->classes; *class != NULL; class++) {
-            cferror = NULL;
-
             if(!((*class)->itemclass)) {
                 // Don't try to scan non-item 'classes'
                 continue;
             }
 
-            // As a performance optimization, if the current policy says that this view only includes items by viewhint,
-            // add that to the query.
-            BOOL limitToViewHint = [self policyRecommendsOnlyViewHintItems:ckks];
+            NSString* itemClass = (__bridge NSString*)(*class)->name;
 
             NSMutableDictionary* queryAttributes = [
-                                                    @{(__bridge NSString*) kSecClass: (__bridge NSString*) (*class)->name,
-                                                      (__bridge NSString*) kSecReturnRef: @(YES),
-                                                      (__bridge NSString*) kSecAttrSynchronizable: @(YES),
-                                                      (__bridge NSString*) kSecAttrTombstone: @(NO),
+                                                    @{(__bridge NSString*)kSecClass: itemClass,
+                                                      (__bridge NSString*)kSecReturnRef: @(YES),
+                                                      (__bridge NSString*)kSecAttrSynchronizable: @(YES),
+                                                      (__bridge NSString*)kSecAttrTombstone: @(NO),
                                                     } mutableCopy];
 
-            if(limitToViewHint) {
-                queryAttributes[(__bridge NSString*)kSecAttrSyncViewHint] = ckks.zoneName;
-            }
-
-            ckksnotice("ckksscan", ckks, "Scanning all synchronizable %@ items(%@) for: %@", (__bridge NSString*)(*class)->name, self.name, queryAttributes);
-
-            Query *q = query_create_with_limit( (__bridge CFDictionaryRef) queryAttributes, NULL, kSecMatchUnlimited, &cferror);
-            bool ok = false;
+            NSDictionary* extraQueryPredicates = [self queryPredicatesForViewMapping];
+            [queryAttributes addEntriesFromDictionary:extraQueryPredicates];
 
-            if(cferror) {
-                ckkserror("ckksscan", ckks, "couldn't create query: %@", cferror);
-                SecTranslateError(&error, cferror);
-                self.error = error;
-                continue;
-            }
+            ckksnotice("ckksscan", self.deps.zoneID, "Scanning all synchronizable %@ items(%@) for: %@", itemClass, self.name, queryAttributes);
 
-            ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt) {
-                return SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) {
-                    ckksnotice("ckksscan", ckks, "scanning item: %@", item);
+            [self executeQuery:queryAttributes readWrite:false error:&error block:^(SecDbItemRef item) {
+                ckksnotice("ckksscan", self.deps.zoneID, "scanning item: %@", item);
 
-                    self.processedItems += 1;
+                self.processedItems += 1;
 
-                    SecDbItemRef itemToSave = NULL;
-
-                    // First check: is this a tombstone? If so, skip with prejudice.
-                    if(SecDbItemIsTombstone(item)) {
-                        ckksinfo("ckksscan", ckks, "Skipping tombstone %@", item);
-                        return;
-                    }
+                // First check: is this a tombstone? If so, skip with prejudice.
+                if(SecDbItemIsTombstone(item)) {
+                    ckksinfo("ckksscan", self.deps.zoneID, "Skipping tombstone %@", item);
+                    return;
+                }
 
-                    // Second check: is this item even for this view? If not, skip.
-                    NSString* viewForItem = [[CKKSViewManager manager] viewNameForItem:item];
-                    if(![viewForItem isEqualToString: ckks.zoneName]) {
-                        ckksinfo("ckksscan", ckks, "Scanned item is for view %@, skipping", viewForItem);
-                        return;
-                    }
+                // Second check: is this item a CKKS key for a view? If so, skip.
+                if([CKKSKey isItemKeyForKeychainView:item] != nil) {
+                    ckksinfo("ckksscan", self.deps.zoneID, "Scanned item is a CKKS internal key, skipping");
+                    return;
+                }
 
-                    // Third check: is this item one of our keys for a view? If not, skip.
-                    if([CKKSKey isItemKeyForKeychainView: item] != nil) {
-                        ckksinfo("ckksscan", ckks, "Scanned item is a CKKS internal key, skipping");
-                        return;
-                    }
+                // Third check: What view is this for?
+                NSString* viewForItem = [[CKKSViewManager manager] viewNameForItem:item];
+                if(![viewForItem isEqualToString:self.deps.zoneID.zoneName]) {
+                    ckksinfo("ckksscan", self.deps.zoneID, "Scanned item is for view %@, skipping", viewForItem);
+                    return;
+                }
 
-                    // Fourth check: does this item have a UUID? If not, ONBOARD!
-                    NSString* uuid = (__bridge_transfer NSString*) CFRetain(SecDbItemGetValue(item, &v10itemuuid, &cferror));
-                    if(!uuid || [uuid isEqual: [NSNull null]]) {
-                        ckksnotice("ckksscan", ckks, "making new UUID for item %@", item);
-
-                        uuid = [[NSUUID UUID] UUIDString];
-                        NSDictionary* updates = @{(id) kSecAttrUUID: uuid};
-
-                        SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, (__bridge CFDictionaryRef) updates, &cferror);
-                        if(SecErrorGetOSStatus(cferror) != errSecSuccess) {
-                            ckkserror("ckksscan", ckks, "couldn't update item with new UUID: %@", cferror);
-                            SecTranslateError(&error, cferror);
-                            self.error = error;
-                            CFReleaseNull(new_item);
-                            return;
-                        }
-
-                        if (new_item) {
-                            bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, ^{
-                                return SecDbItemUpdate(item, new_item, dbt, kCFBooleanFalse, q->q_uuid_from_primary_key, &cferror);
-                            });
-
-                            if(!ok || SecErrorGetOSStatus(cferror) != errSecSuccess) {
-                                ckkserror("ckksscan", ckks, "couldn't update item with new UUID: %@", cferror);
-                                SecTranslateError(&error, cferror);
-                                self.error = error;
-                                CFReleaseNull(new_item);
-                                return;
-                            }
-                        }
-                        itemToSave = CFRetainSafe(new_item);
-                        CFReleaseNull(new_item);
+                // Fourth check: does this item have a UUID? If not, mark for later onboarding.
+                CFErrorRef cferror = NULL;
 
-                    } else {
-                        // Is there a known sync item with this UUID?
-                        CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase: uuid zoneID:ckks.zoneID error: &error];
-                        if(ckme != nil) {
-                            if ([CKKSManifest shouldSyncManifests]) {
-                                [itemsForManifest addObject:ckme.item];
-                            }
-                            [mirrorUUIDs removeObject:uuid];
-                            ckksinfo("ckksscan", ckks, "Existing mirror entry with UUID %@", uuid);
-
-                            if([self areEquivalent:item ckksItem:ckme.item]) {
-                                // Fair enough.
-                                return;
-                            } else {
-                                ckksnotice("ckksscan", ckks, "Existing mirror entry with UUID %@ does not match local item", uuid);
-                            }
-                        }
-
-                        // We don't care about the oqe state here, just that one exists
-                        CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase: uuid zoneID:ckks.zoneID error: &error];
-                        if(oqe != nil) {
-                            ckksnotice("ckksscan", ckks, "Existing outgoing queue entry with UUID %@", uuid);
-                            // If its state is 'new', mark down that we've seen new entries that need processing
-                            newEntries |= !![oqe.state isEqualToString: SecCKKSStateNew];
-                            return;
-                        }
-
-                        itemToSave = CFRetainSafe(item);
-                    }
+                NSString* uuid = (__bridge_transfer NSString*) CFRetain(SecDbItemGetValue(item, &v10itemuuid, &cferror));
+                if(!uuid || [uuid isEqual: [NSNull null]]) {
+                    ckksnotice("ckksscan", self.deps.zoneID, "making new UUID for item %@: %@", item, cferror);
 
-                    // Hurray, we can help!
-                    self.recordsFound += 1;
+                    NSMutableDictionary* primaryKey = [(NSDictionary*)CFBridgingRelease(SecDbItemCopyPListWithMask(item, kSecDbPrimaryKeyFlag, &cferror)) mutableCopy];
 
-                    CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry withItem: itemToSave action: SecCKKSActionAdd ckks:ckks error: &error];
+                    // Class is an important part of a primary key, SecDb
+                    primaryKey[(id)kSecClass] = itemClass;
 
-                    if(error) {
-                        ckkserror("ckksscan", ckks, "Need to upload %@, but can't create outgoing entry: %@", item, error);
+                    if(SecErrorGetOSStatus(cferror) != errSecSuccess) {
+                        ckkserror("ckksscan", self.deps.zoneID, "couldn't copy UUID-less item's primary key: %@", cferror);
+                        SecTranslateError(&error, cferror);
                         self.error = error;
-                        CFReleaseNull(itemToSave);
                         return;
                     }
 
-                    ckksnotice("ckksscan", ckks, "Syncing new item: %@", oqe);
-                    CFReleaseNull(itemToSave);
+                    [primaryKeysWithNoUUIDs addObject:primaryKey];
+                    return;
+                }
 
-                    [oqe saveToDatabase: &error];
-                    if(error) {
-                        ckkserror("ckksscan", ckks, "Need to upload %@, but can't save to database: %@", oqe, error);
-                        self.error = error;
+                // Is there a known sync item with this UUID?
+                CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid
+                                                                  zoneID:self.deps.zoneID
+                                                                   error:&error];
+                if(ckme != nil) {
+                    [mirrorUUIDs removeObject:uuid];
+                    ckksinfo("ckksscan", self.deps.zoneID, "Existing mirror entry with UUID %@", uuid);
+
+                    if([self areEquivalent:item ckksItem:ckme.item]) {
+                        // Fair enough.
                         return;
+                    } else {
+                        ckksnotice("ckksscan", self.deps.zoneID, "Existing mirror entry with UUID %@ does not match local item", uuid);
                     }
-                    newEntries = true;
-                    if ([CKKSManifest shouldSyncManifests]) {
-                        [itemsForManifest addObject:oqe.item];
-                    }
-
-                    self.recordsAdded += 1;
-                });
-            });
+                }
 
-            if(cferror || !ok) {
-                ckkserror("ckksscan", ckks, "error processing or finding items: %@", cferror);
-                SecTranslateError(&error, cferror);
-                self.error = error;
-                query_destroy(q, NULL);
-                continue;
-            }
+                // We don't care about the oqe state here, just that one exists
+                CKKSOutgoingQueueEntry* oqe = [CKKSOutgoingQueueEntry tryFromDatabase:uuid
+                                                                               zoneID:self.deps.zoneID
+                                                                                error:&error];
+                if(oqe != nil) {
+                    ckksnotice("ckksscan", self.deps.zoneID, "Existing outgoing queue entry with UUID %@", uuid);
+                    // If its state is 'new', mark down that we've seen new entries that need processing
+                    self.newCKKSEntries |= !![oqe.state isEqualToString:SecCKKSStateNew];
+                    return;
+                }
 
-            ok = query_notify_and_destroy(q, ok, &cferror);
+                // Hurray, we can help!
+                ckksnotice("ckksscan", self.deps.zoneID, "Item(%@) is new; will attempt to add to CKKS", uuid);
+                self.recordsFound += 1;
 
-            if(cferror || !ok) {
-                ckkserror("ckksscan", ckks, "couldn't delete query: %@", cferror);
-                SecTranslateError(&error, cferror);
-                self.error = error;
-                continue;
-            }
+                NSMutableSet<NSString*>* classUUIDs = itemUUIDsNotYetInCKKS[itemClass];
+                if(!classUUIDs) {
+                    classUUIDs = [NSMutableSet set];
+                    itemUUIDsNotYetInCKKS[itemClass] = classUUIDs;
+                }
+                [classUUIDs addObject:uuid];
+            }];
         }
 
-        // We're done checking local keychain for extra items, now let's make sure the mirror doesn't have extra items, either
+        // We're done checking local keychain for extra items, now let's make sure the mirror doesn't have extra items that the keychain doesn't have, either
         if (mirrorUUIDs.count > 0) {
-            ckksnotice("ckksscan", ckks, "keychain missing %lu items from mirror, proceeding with queue scanning", (unsigned long)mirrorUUIDs.count);
-            [mirrorUUIDs minusSet:[NSSet setWithArray:[CKKSIncomingQueueEntry allUUIDs:ckks.zoneID error:&error]]];
+            ckksnotice("ckksscan", self.deps.zoneID, "keychain missing %lu items from mirror, proceeding with queue scanning", (unsigned long)mirrorUUIDs.count);
+            [mirrorUUIDs minusSet:[NSSet setWithArray:[CKKSIncomingQueueEntry allUUIDs:self.deps.zoneID error:&error]]];
             if (error) {
-                ckkserror("ckksscan", ckks, "unable to inspect incoming queue: %@", error);
+                ckkserror("ckksscan",  self.deps.zoneID, "unable to inspect incoming queue: %@", error);
                 self.error = error;
-                return false;
+                return;
             }
 
-            [mirrorUUIDs minusSet:[NSSet setWithArray:[CKKSOutgoingQueueEntry allUUIDs:ckks.zoneID error:&error]]];
+            [mirrorUUIDs minusSet:[NSSet setWithArray:[CKKSOutgoingQueueEntry allUUIDs:self.deps.zoneID error:&error]]];
             if (error) {
-                ckkserror("ckksscan", ckks, "unable to inspect outgoing queue: %@", error);
+                ckkserror("ckksscan", self.deps.zoneID, "unable to inspect outgoing queue: %@", error);
                 self.error = error;
-                return false;
+                return;
             }
+        }
 
-            if (mirrorUUIDs.count > 0) {
-                ckkserror("ckksscan", ckks, "BUG: keychain missing %lu items from mirror and/or queues: %@", (unsigned long)mirrorUUIDs.count, mirrorUUIDs);
-                self.missingLocalItemsFound = mirrorUUIDs.count;
+        // Drop off of read-only transaction
+    }];
 
-                [[CKKSAnalytics logger] logMetric:[NSNumber numberWithUnsignedInteger:mirrorUUIDs.count] withName:CKKSEventMissingLocalItemsFound];
+    if(self.error) {
+        ckksnotice("ckksscan", self.deps.zoneID, "Exiting due to previous error: %@", self.error);
+        return;
+    }
 
-                for (NSString* uuid in mirrorUUIDs) {
-                    CKKSMirrorEntry* ckme = [CKKSMirrorEntry tryFromDatabase:uuid zoneID:ckks.zoneID error:&error];
-                    [ckks _onqueueCKRecordChanged:ckme.item.storedCKRecord resync:true];
-                }
+    ckksnotice("ckksscan", self.deps.zoneID, "Found %d item classes with missing items", (int)itemUUIDsNotYetInCKKS.count);
 
-                // And, if you're not in the tests, try to collect a sysdiagnose I guess?
-                // <rdar://problem/36166435> Re-enable IMCore autosysdiagnose capture to securityd
-                //if(SecIsInternalRelease() && !SecCKKSTestsEnabled()) {
-                //    [[IMCloudKitHooks sharedInstance] tryToAutoCollectLogsWithErrorString:@"35810558" sendLogsTo:@"rowdy_bot@icloud.com"];
-                //}
-            } else {
-                ckksnotice("ckksscan", ckks, "No missing local items found");
-            }
-        }
+    for(NSString* itemClass in [itemUUIDsNotYetInCKKS allKeys]) {
+        [self onboardItemsWithUUIDs:itemUUIDsNotYetInCKKS[itemClass] itemClass:itemClass databaseProvider:databaseProvider];
+    }
 
-        [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventScanLocalItems  zone:ckks.zoneName count:self.processedItems];
+    [self fixUUIDlessItemsWithPrimaryKeys:primaryKeysWithNoUUIDs databaseProvider:databaseProvider];
 
-        if ([CKKSManifest shouldSyncManifests]) {
-            // TODO: this manifest needs to incorporate peer manifests
-            CKKSEgoManifest* manifest = [CKKSEgoManifest newManifestForZone:ckks.zoneName withItems:itemsForManifest peerManifestIDs:@[] currentItems:@{} error:&error];
-            if (!manifest || error) {
-                ckkserror("ckksscan", ckks, "could not create manifest: %@", error);
-                self.error = error;
-                return false;
-            }
+    [self retriggerMissingMirrorEntires:mirrorUUIDs
+                                   ckks:ckks
+                       databaseProvider:databaseProvider];
 
-            [manifest saveToDatabase:&error];
-            if (error) {
-                ckkserror("ckksscan", ckks, "could not save manifest to database: %@", error);
-                self.error = error;
-                return false;
-            }
+    [CKKSPowerCollection CKKSPowerEvent:kCKKSPowerEventScanLocalItems zone:self.deps.zoneID.zoneName count:self.processedItems];
 
-            ckks.egoManifest = manifest;
-        }
+    // Write down that a scan occurred
+    [databaseProvider dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        CKKSZoneStateEntry* zoneState = [CKKSZoneStateEntry state:self.deps.zoneID.zoneName];
 
-        if(newEntries) {
-            // Schedule a "view changed" notification
-            [ckks.notifyViewChangedScheduler trigger];
+        zoneState.lastLocalKeychainScanTime = [NSDate now];
 
-            // notify CKKS that it should process these new entries
-            [ckks processOutgoingQueue:self.ckoperationGroup];
-        }
+        NSError* saveError = nil;
+        [zoneState saveToDatabase:&saveError];
 
-        if(self.missingLocalItemsFound > 0) {
-            [ckks processIncomingQueue:false];
+        if(saveError) {
+            ckkserror("ckksscan", self.deps.zoneID, "Unable to save 'scanned' bit: %@", saveError);
+        } else {
+            ckksnotice("ckksscan", self.deps.zoneID, "Saved scanned status.");
         }
 
-        ckksnotice("ckksscan", ckks, "Completed scan");
-        ckks.droppedItems = false;
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
+
+    if(self.newCKKSEntries) {
+        // Schedule a "view changed" notification
+        [self.deps.notifyViewChangedScheduler trigger];
+
+        // notify CKKS that it should process these new entries
+        [ckks processOutgoingQueue:self.ckoperationGroup];
+        // TODO: self.nextState = SecCKKSZoneKeyStateProcessOutgoingQueue;
+    } else {
+        self.nextState = self.intendedState;
+    }
+
+    if(self.missingLocalItemsFound > 0) {
+        [ckks processIncomingQueue:false];
+        // TODO [self.deps.flagHandler _onqueueHandleFlag:CKKSFlagProcessIncomingQueue];
+    }
+
+    ckksnotice("ckksscan", self.deps.zoneID, "Completed scan");
+    (void)transaction;
 }
 
 - (BOOL)areEquivalent:(SecDbItemRef)item ckksItem:(CKKSItem*)ckksItem
 {
-    CKKSKeychainView* ckks = self.ckks;
-
     NSError* localerror = nil;
     NSDictionary* attributes = [CKKSIncomingQueueOperation decryptCKKSItemToAttributes:ckksItem error:&localerror];
     if(!attributes || localerror) {
-        ckksnotice("ckksscan", ckks, "Could not decrypt item for comparison: %@", localerror);
+        ckksnotice("ckksscan", self.deps.zoneID, "Could not decrypt item for comparison: %@", localerror);
         return YES;
     }
 
     localerror = (NSError*)CFBridgingRelease(cferror);
 
     if(!objdict || localerror) {
-        ckksnotice("ckksscan", ckks, "Could not get item contents for comparison: %@", localerror);
+        ckksnotice("ckksscan", self.deps.zoneID, "Could not get item contents for comparison: %@", localerror);
 
         // Fail open: assert that this item doesn't match
         return NO;
diff --git a/keychain/ckks/CKKSStates.h b/keychain/ckks/CKKSStates.h
new file mode 100644 (file)
index 0000000..9ec50e1
--- /dev/null
@@ -0,0 +1,50 @@
+
+#if OCTAGON
+
+#import <Foundation/Foundation.h>
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ot/OctagonStateMachine.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+// Flag initialization
+typedef OctagonFlag CKKSFlag;
+
+// The set of trusted peers has changed
+extern CKKSFlag* const CKKSFlagTrustedPeersSetChanged;
+
+// A client has requested that TLKs be created
+extern CKKSFlag* const CKKSFlagTLKCreationRequested;
+// We were waiting for a TLK upload, and one has occurred
+extern CKKSFlag* const CKKSFlagKeyStateTLKsUploaded;
+
+extern CKKSFlag* const CKKSFlagCloudKitLoggedIn;
+extern CKKSFlag* const CKKSFlagCloudKitLoggedOut;
+
+extern CKKSFlag* const CKKSFlagBeginTrustedOperation;
+extern CKKSFlag* const CKKSFlagEndTrustedOperation;
+
+extern CKKSFlag* const CKKSFlagChangeTokenExpired;
+extern CKKSFlag* const CKKSFlagCloudKitZoneMissing;
+
+extern CKKSFlag* const CKKSFlagDeviceUnlocked;
+
+extern CKKSFlag* const CKKSFlagFetchRequested;
+// Added when a key hierarchy fetch completes.
+extern CKKSFlag* const CKKSFlagFetchComplete;
+
+extern CKKSFlag* const CKKSFlagKeyStateProcessRequested;
+
+extern CKKSFlag* const CKKSFlagProcessIncomingQueue;
+extern CKKSFlag* const CKKSFlagProcessOutgoingQueue;
+extern CKKSFlag* const CKKSFlagScanLocalItems;
+extern CKKSFlag* const CKKSFlagItemReencryptionNeeded;
+
+extern CKKSFlag* const CKKSFlag24hrNotification;
+
+NSSet<CKKSFlag*>* CKKSAllStateFlags(void);
+
+NS_ASSUME_NONNULL_END
+
+#endif
diff --git a/keychain/ckks/CKKSStates.m b/keychain/ckks/CKKSStates.m
new file mode 100644 (file)
index 0000000..5eb3b4a
--- /dev/null
@@ -0,0 +1,65 @@
+
+#if OCTAGON
+
+#import "keychain/ckks/CKKSStates.h"
+#import "keychain/ckks/CKKSKeychainView.h"
+#import "keychain/ot/ObjCImprovements.h"
+
+CKKSFlag* const CKKSFlagTrustedPeersSetChanged = (CKKSFlag*) @"trusted_peers_changed";
+
+CKKSFlag* const CKKSFlagTLKCreationRequested = (CKKSFlag*)@"tlk_creation";
+CKKSFlag* const CKKSFlagKeyStateTLKsUploaded = (CKKSFlag*)@"tlks_uploaded";
+
+CKKSFlag* const CKKSFlagCloudKitLoggedIn = (CKKSFlag*)@"ck_account_logged_in";
+CKKSFlag* const CKKSFlagCloudKitLoggedOut = (CKKSFlag*)@"ck_account_logged_out";
+
+CKKSFlag* const CKKSFlagBeginTrustedOperation = (CKKSFlag*)@"trusted_operation_begin";
+CKKSFlag* const CKKSFlagEndTrustedOperation = (CKKSFlag*)@"trusted_operation_end";
+
+CKKSFlag* const CKKSFlagChangeTokenExpired = (CKKSFlag*)@"ck_change_token_expired";
+CKKSFlag* const CKKSFlagCloudKitZoneMissing = (CKKSFlag*)@"ck_zone_missing";
+
+CKKSFlag* const CKKSFlagDeviceUnlocked = (CKKSFlag*)@"device_unlocked";
+
+CKKSFlag* const CKKSFlagFetchRequested = (CKKSFlag*) @"fetch_requested";
+CKKSFlag* const CKKSFlagFetchComplete = (CKKSFlag*)@"fetch_complete";
+
+CKKSFlag* const CKKSFlagKeyStateProcessRequested = (CKKSFlag*) @"key_process_requested";
+
+CKKSFlag* const CKKSFlagProcessIncomingQueue = (CKKSFlag*)@"process_incoming_queue";
+CKKSFlag* const CKKSFlagProcessOutgoingQueue = (CKKSFlag*)@"process_outgoing_queue";
+CKKSFlag* const CKKSFlagScanLocalItems = (CKKSFlag*)@"dropped_items";
+CKKSFlag* const CKKSFlagItemReencryptionNeeded = (CKKSFlag*)@"item_reencryption_needed";
+
+CKKSFlag* const CKKSFlag24hrNotification = (CKKSFlag*)@"24_hr_notification";
+
+NSSet<CKKSFlag*>* CKKSAllStateFlags(void)
+{
+    static NSSet<CKKSFlag*>* s = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        s = [NSSet setWithArray:@[
+            CKKSFlagFetchRequested,
+            CKKSFlagKeyStateProcessRequested,
+            CKKSFlagTrustedPeersSetChanged,
+            CKKSFlagTLKCreationRequested,
+            CKKSFlagScanLocalItems,
+            CKKSFlagCloudKitLoggedIn,
+            CKKSFlagCloudKitLoggedOut,
+            CKKSFlagCloudKitZoneMissing,
+            CKKSFlagChangeTokenExpired,
+            CKKSFlagProcessIncomingQueue,
+            CKKSFlagProcessOutgoingQueue,
+            CKKSFlagItemReencryptionNeeded,
+            CKKSFlagBeginTrustedOperation,
+            CKKSFlagEndTrustedOperation,
+            CKKSFlagDeviceUnlocked,
+            CKKSFlagKeyStateTLKsUploaded,
+            CKKSFlagFetchComplete,
+            CKKSFlag24hrNotification,
+        ]];
+    });
+    return s;
+}
+
+#endif
index f507bcb68fd9e7b147255026df5cb914d46699b2..a6e7424d9eb726e4530e9c744767c6fecf3a7cc5 100644 (file)
     CKKSKeychainView* ckks = self.ckks;
 
     // Synchronous, on some thread. Get back on the CKKS queue for SQL thread-safety.
-    [ckks dispatchSync: ^bool{
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
             ckksnotice("ckksresync", ckks, "CKKSSynchronizeOperation cancelled, quitting");
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         ckks.lastSynchronizeOperation = self;
         [self runBeforeGroupFinished: fetchOp];
 
         // Step 2
-        CKKSIncomingQueueOperation* incomingOp = [[CKKSIncomingQueueOperation alloc] initWithCKKSKeychainView:ckks errorOnClassAFailure:true];
+        CKKSIncomingQueueOperation* incomingOp = [[CKKSIncomingQueueOperation alloc] initWithDependencies:ckks.operationDependencies
+                                                                                                     ckks:ckks
+                                                                                                intending:SecCKKSZoneKeyStateReady
+                                                                                               errorState:SecCKKSZoneKeyStateUnhealthy
+                                                                                     errorOnClassAFailure:true
+                                                                                handleMismatchedViewItems:false];
+
         incomingOp.name = [NSString stringWithFormat: @"resync-step%u-incoming", self.restartCount * steps + 2];
         [incomingOp addSuccessDependency:fetchOp];
         [self runBeforeGroupFinished:incomingOp];
 
         // Step 3
-        CKKSScanLocalItemsOperation* scan = [[CKKSScanLocalItemsOperation alloc] initWithCKKSKeychainView:ckks ckoperationGroup:operationGroup];
+        CKKSScanLocalItemsOperation* scan = [[CKKSScanLocalItemsOperation alloc] initWithDependencies:ckks.operationDependencies
+                                                                                                 ckks:ckks
+                                                                                            intending:SecCKKSZoneKeyStateReady
+                                                                                           errorState:SecCKKSZoneKeyStateError
+                                                                                     ckoperationGroup:operationGroup];
         scan.name = [NSString stringWithFormat: @"resync-step%u-scan", self.restartCount * steps + 3];
         [scan addSuccessDependency: incomingOp];
         [self runBeforeGroupFinished: scan];
         CKKSOutgoingQueueOperation* outgoingOp = [ckks processOutgoingQueue: operationGroup];
         outgoingOp.name = [NSString stringWithFormat: @"resync-step%u-outgoing", self.restartCount * steps + 4];
         [self dependOnBeforeGroupFinished:outgoingOp];
+        [outgoingOp addDependency:scan];
 
         // Step 5:
         CKKSResultOperation* restart = [[CKKSResultOperation alloc] init];
         [restart addExecutionBlock:^{
             STRONGIFY(self);
             if(!self) {
-                secerror("ckksresync: received callback for released object");
+                ckkserror("ckksresync", ckks, "received callback for released object");
                 return;
             }
 
         [restart addSuccessDependency: outgoingOp];
         [self runBeforeGroupFinished: restart];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
index eb4de292769410ff8081b515925255036df1f785..29753d6ad711d09aa9d3bd9d80a951b6ba863380 100644 (file)
@@ -75,7 +75,7 @@ typedef NS_ENUM(NSUInteger, SecCKKSTLKShareVersion) {
 - (instancetype)initForKey:(NSString*)tlkUUID
               senderPeerID:(NSString*)senderPeerID
             recieverPeerID:(NSString*)receiverPeerID
-  receiverEncPublicKeySPKI:(NSData*)publicKeySPKI
+  receiverEncPublicKeySPKI:(NSData* _Nullable)publicKeySPKI
                      curve:(SFEllipticCurve)curve
                    version:(SecCKKSTLKShareVersion)version
                      epoch:(NSInteger)epoch
index f1019b9f0cda5f5ff8db2f9a621697c4beedd630..281f1ead5f5a99b48d66c5a019ef6b44d1dcaf13 100644 (file)
@@ -69,7 +69,7 @@
 - (instancetype)initForKey:(NSString*)tlkUUID
               senderPeerID:(NSString*)senderPeerID
             recieverPeerID:(NSString*)receiverPeerID
-  receiverEncPublicKeySPKI:(NSData*)publicKeySPKI
+  receiverEncPublicKeySPKI:(NSData* _Nullable)publicKeySPKI
                      curve:(SFEllipticCurve)curve
                    version:(SecCKKSTLKShareVersion)version
                      epoch:(NSInteger)epoch
                   error:(NSError* __autoreleasing*)error
 {
     if(!peer.publicSigningKey) {
-        secerror("ckksshare: no signing key for peer: %@", peer);
+        ckkserror("ckksshare", self.zoneID, "no signing key for peer: %@", peer);
         if(error) {
             *error = [NSError
                 errorWithDomain:CKKSErrorDomain
                                          ckrecord:ckrecord
                                             error:&localerror];
             if(localerror) {
-                secerror("ckksshare: signature didn't verify for %@ %@: %@", self, peer, localerror);
+                ckkserror("ckksshare", self.zoneID, "signature didn't verify for %@ %@: %@", self, peer, localerror);
                 lastVerificationError = localerror;
             }
             if(isSigned) {
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder*)decoder
 {
-    self = [super init];
-    if(self) {
+    if ((self = [super init])) {
         _zoneID = [decoder decodeObjectOfClass:[CKRecordZoneID class] forKey:@"zoneID"];
         _curve = (SFEllipticCurve) [decoder decodeInt64ForKey:@"curve"];
         _version = (SecCKKSTLKShareVersion)[decoder decodeInt64ForKey:@"version"];
     share.wrappedTLK =
         [share wrap:key publicKey:receiver.publicEncryptionKey error:&localerror];
     if(localerror) {
-        secerror("ckksshare: couldn't share %@ (wrap failed): %@", key, localerror);
+        ckkserror("ckksshare", key.zoneID, "couldn't share %@ (wrap failed): %@", key, localerror);
         if(error) {
             *error = localerror;
         }
                                ckrecord:nil
                                  error:&localerror];
     if(localerror) {
-        secerror("ckksshare: couldn't share %@ (signing failed): %@", key, localerror);
+        ckkserror("ckksshare", key.zoneID, "couldn't share %@ (signing failed): %@", key, localerror);
         if(error) {
             *error = localerror;
         }
index ac6ee5adf88508d0b9c88ee5ddb777a623c1d63e..9b1d1a38f97fd0e3e2910bcf5111e0783aa5761e 100644 (file)
                                                                  zoneID:key.zoneID
                                                                   error:&localerror];
     if(localerror) {
-        secerror("ckksshare: couldn't load old share for %@: %@", key, localerror);
+        ckkserror("ckksshare", key.zoneID, "couldn't load old share for %@: %@", key, localerror);
         if(error) {
             *error = localerror;
         }
index 00080ba265413acd1d2f9b5e6b3b4fc4a3cce277..f087686b277c3d32ce5a81b222e4b65d160024b9 100644 (file)
 
     WEAKIFY(self);
 
-    [ckks dispatchSyncWithAccountKeys:^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         if(self.cancelled) {
             ckksnotice("ckkscurrent", ckks, "CKKSUpdateCurrentItemPointerOperation cancelled, quitting");
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         NSError* error = nil;
         if(!self.newItem || error) {
             ckksnotice("ckkscurrent", ckks, "Couldn't fetch new item, quitting: %@", error);
             self.error = error;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Now that we're on the db queue, ensure that the given hashes for the items match the hashes as they are now.
                                              code:CKKSItemChanged
                                       description:@"New item has changed; hashes mismatch. Refetch and try again."
                                        underlying:(NSError*)CFBridgingRelease(cferror)];
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         newItemUUID = (NSString*) CFBridgingRelease(CFRetainSafe(SecDbItemGetValue(self.newItem, &v10itemuuid, &cferror)));
         if(!newItemUUID || cferror) {
             ckkserror("ckkscurrent", ckks, "Error fetching UUID for new item: %@", cferror);
             self.error = (NSError*) CFBridgingRelease(cferror);
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // If the old item is nil, that's an indicator that the old item isn't expected to exist in the keychain anymore
             if(!self.oldItem || error) {
                 ckksnotice("ckkscurrent", ckks, "Couldn't fetch old item, quitting: %@", error);
                 self.error = error;
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             oldCurrentItemHash = (NSData*) CFBridgingRelease(CFRetainSafe(SecDbItemGetSHA1(self.oldItem, &cferror)));
                                                  code:CKKSItemChanged
                                           description:@"Old item has changed; hashes mismatch. Refetch and try again."
                                            underlying:(NSError*)CFBridgingRelease(cferror)];
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
 
             oldCurrentItemUUID = (NSString*) CFBridgingRelease(CFRetainSafe(SecDbItemGetValue(self.oldItem, &v10itemuuid, &cferror)));
             if(!oldCurrentItemUUID || cferror) {
                 ckkserror("ckkscurrent", ckks, "Error fetching UUID for old item: %@", cferror);
                 self.error = (NSError*) CFBridgingRelease(cferror);
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
         }
 
                                              code:CKKSRemoteItemChangePending
                                       description:[NSString stringWithFormat:@"Update to current item pointer is pending."]];
             ckkserror("ckkscurrent", ckks, "Attempt to set a new current item pointer when one exists: %@", self.error);
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         CKKSCurrentItemPointer* cip = [CKKSCurrentItemPointer tryFromDatabase:self.currentPointerIdentifier state:SecCKKSProcessedStateLocal zoneID:ckks.zoneID error:&error];
                 self.error = [NSError errorWithDomain:CKKSErrorDomain
                                                  code:CKKSItemChanged
                                           description:[NSString stringWithFormat:@"Current pointer(%@) does not match user-supplied %@, aborting", cip, oldCurrentItemUUID]];
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
             // Cool. Since you know what you're updating, you're allowed to update!
             cip.currentItemUUID = newItemUUID;
             self.error = [NSError errorWithDomain:CKKSErrorDomain
                                              code:CKKSItemChanged
                                       description:[NSString stringWithFormat:@"Current pointer(%@) does not match given value of '%@', aborting", cip, oldCurrentItemUUID]];
-            return false;
+            return CKKSDatabaseTransactionRollback;
         } else {
             // No current item pointer? How exciting! Let's make you a nice new one.
             cip = [[CKKSCurrentItemPointer alloc] initForIdentifier:self.currentPointerIdentifier
         if(error) {
             ckkserror("ckkscurrent", ckks, "Error attempting to update current item pointer %@: %@", self.currentPointerIdentifier, error);
             self.error = error;
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         // Make sure the item is synced, though!
                                   underlying:error];
 
             self.error = error;
-            return false;
-        }
-
-        if ([CKKSManifest shouldSyncManifests]) {
-            [ckks.egoManifest setCurrentItemUUID:newItemUUID forIdentifier:self.currentPointerIdentifier];
+            return CKKSDatabaseTransactionRollback;
         }
 
         ckksnotice("ckkscurrent", ckks, "Saving new current item pointer %@", cip);
         CKRecord* record = [cip CKRecordWithZoneID:ckks.zoneID];
         recordsToSave[record.recordID] = record;
 
-        if([CKKSManifest shouldSyncManifests]) {
-            for(CKRecord* record in [ckks.egoManifest allCKRecordsWithZoneID:ckks.zoneID]) {
-                recordsToSave[record.recordID] = record;
-            }
-        }
-
         // Start a CKModifyRecordsOperation to save this new/updated record.
         NSBlockOperation* modifyComplete = [[NSBlockOperation alloc] init];
         modifyComplete.name = @"updateCurrentItemPointer-modifyRecordsComplete";
                 ckkserror("ckkscurrent", strongCKKS, "CloudKit returned an error: %@", ckerror);
                 self.error = ckerror;
 
-                [strongCKKS dispatchSync:^bool {
-                    return [strongCKKS _onqueueCKWriteFailed:ckerror attemptedRecordsChanged:recordsToSave];
+                [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+                    return [strongCKKS _onqueueCKWriteFailed:ckerror attemptedRecordsChanged:recordsToSave] ? CKKSDatabaseTransactionCommit : CKKSDatabaseTransactionRollback;
                 }];
 
                 [strongCKKS scheduleOperation: modifyComplete];
 
             __block NSError* error = nil;
 
-            [strongCKKS dispatchSync: ^bool{
+            [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 for(CKRecord* record in savedRecords) {
                     // Save the item records
                     if([record.recordType isEqualToString: SecCKRecordCurrentItemType]) {
                     // Schedule a 'view changed' notification
                     [strongCKKS.notifyViewChangedScheduler trigger];
                 }
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
 
             self.error = error;
         [self dependOnBeforeGroupFinished: self.modifyRecordsOperation];
         [ckks.database addOperation: self.modifyRecordsOperation];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
 - (SecDbItemRef _Nullable)_onqueueFindSecDbItem:(NSData*)persistentRef accessGroup:(NSString*)accessGroup error:(NSError**)error {
+    CKKSKeychainView* ckks = self.ckks;
+    dispatch_assert_queue(ckks.queue);
     __block SecDbItemRef blockItem = NULL;
     CFErrorRef cferror = NULL;
     __block NSError* localerror = NULL;
 
-    CKKSKeychainView* ckks = self.ckks;
     bool ok = kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
         // Find the items from their persistent refs.
         CFErrorRef blockcfError = NULL;
                                                                          },
                                            NULL,
                                            1,
+                                           NULL, 
                                            &blockcfError);
         if(blockcfError || !q) {
             ckkserror("ckkscurrent", ckks, "couldn't create query for item persistentRef: %@", blockcfError);
index 7905d589d238da40dea6ec0f10d1bf67000c610d..790d364f52fba8cd5592e937599e6979e55a9c56 100644 (file)
         ckkserror("ckksdevice", ckks, "Not quite sure if the account isa HSA2 or not. Probably will quit?");
     }
 
-    [ckks dispatchSyncWithAccountKeys:^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
 
         CKKSDeviceStateEntry* cdse = [ckks _onqueueCurrentDeviceStateEntry:&error];
         if(error || !cdse) {
             ckkserror("ckksdevice", ckks, "Error creating device state entry; quitting: %@", error);
-            return false;
+            return CKKSDatabaseTransactionRollback;
         }
 
         if(self.rateLimit) {
                 self.error =  [NSError errorWithDomain:@"securityd"
                                                   code:errSecInternalError
                                               userInfo:@{NSLocalizedDescriptionKey: @"Rate-limited the CKKSUpdateDeviceStateOperation"}];
-                return false;
+                return CKKSDatabaseTransactionRollback;
             }
         }
 
 
             __block NSError* error = nil;
 
-            [strongCKKS dispatchSync: ^bool{
+            [strongCKKS dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
                 for(CKRecord* record in savedRecords) {
                     // Save the item records
                     if([record.recordType isEqualToString: SecCKRecordDeviceStateType]) {
                         }
                     }
                 }
-                return true;
+                return CKKSDatabaseTransactionCommit;
             }];
 
             self.error = error;
         [self dependOnBeforeGroupFinished: self.modifyRecordsOperation];
         [ckks.database addOperation: self.modifyRecordsOperation];
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
index f19cccabe43ae3b54517fece49ddb1f563181531..6a6b1df879e8f34f8e2a11179177173ab3183637 100644 (file)
 #import "keychain/ckks/CloudKitDependencies.h"
 #import "keychain/ckks/CKKSZoneChangeFetcher.h"
 #import "keychain/ckks/CKKSZoneModifier.h"
+#import "keychain/ckks/CKKSKeychainBackedKey.h"
 
 #import "keychain/ot/OTSOSAdapter.h"
 #import "keychain/ot/OTDefines.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
-@class CKKSKeychainView, CKKSRateLimiter, TPPolicy;
+@class CKKSKeychainView, CKKSRateLimiter, TPSyncingPolicy;
 
 @interface CKKSViewManager : NSObject <CKKSControlProtocol>
 
@@ -65,7 +66,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property id<OTSOSAdapter> sosPeerAdapter;
 
-@property (readonly, nullable) TPPolicy* policy;
+@property (readonly, nullable) TPSyncingPolicy* policy;
 
 @property (readonly) NSMutableDictionary<NSString*, CKKSKeychainView*>* views;
 
@@ -75,15 +76,22 @@ NS_ASSUME_NONNULL_BEGIN
                  lockStateTracker:(CKKSLockStateTracker*)lockStateTracker
         cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies;
 
-- (CKKSKeychainView*)findView:(NSString*)viewName;
+// Note: findView will not wait for any views to be created. You must handle
+// states where the daemon has not entirely started up yourself
+- (CKKSKeychainView* _Nullable)findView:(NSString*)viewName;
+
+// Similar to findView, but will create the view if it's not already present.
 - (CKKSKeychainView*)findOrCreateView:(NSString*)viewName;
+
+// findViewOrError will wait for the Syncing Policy to be loaded, which
+// creates all views. Don't call this from any important queues.
+- (CKKSKeychainView* _Nullable)findView:(NSString*)viewName error:(NSError**)error;
+
 - (void)setView:(CKKSKeychainView*)obj;
 - (void)clearView:(NSString*)viewName;
 
 - (NSSet<CKKSKeychainView*>*)currentViews;
 
-- (NSDictionary<NSString*, NSString*>*)activeTLKs;
-
 - (void)setupAnalytics;
 
 - (NSString* _Nullable)viewNameForItem:(SecDbItemRef)item;
@@ -126,7 +134,11 @@ NS_ASSUME_NONNULL_BEGIN
 // Call this to set the syncing views+policy that this manager will use.
 // If beginCloudKitOperationOfAllViews has previously been called, then any new views created
 // as a result of this call will begin CK operation.
-- (void)setSyncingViews:(NSSet<NSString*>* _Nullable)viewNames sortingPolicy:(TPPolicy* _Nullable)policy;
+- (BOOL)setCurrentSyncingPolicy:(TPSyncingPolicy* _Nullable)syncingPolicy;
+
+// Similar to above, but please only pass policyIsFresh=YES if Octagon has contacted cuttlefish immediately previously
+// Returns YES if the view set has changed as part of this set
+- (BOOL)setCurrentSyncingPolicy:(TPSyncingPolicy* _Nullable)syncingPolicy policyIsFresh:(BOOL)policyIsFresh;
 
 - (void)clearAllViews;
 
@@ -154,8 +166,12 @@ NS_ASSUME_NONNULL_BEGIN
 // Checks featureflags to return whether we should use policy-based views, or use the hardcoded list
 - (BOOL)useCKKSViewsFromPolicy;
 
+// Extract TLKs for sending to some peer. Pass restrictToPolicy=True if you want to restrict the returned TLKs
+// to what the current policy indicates (allowing to prioritize transferred TLKs)
+- (NSArray<CKKSKeychainBackedKey*>* _Nullable)currentTLKsFilteredByPolicy:(BOOL)restrictToPolicy error:(NSError**)error;
+
 // Interfaces to examine sync callbacks
-- (SecBoolNSErrorCallback _Nullable)claimCallbackForUUID:(NSString*)uuid;
+- (SecBoolNSErrorCallback _Nullable)claimCallbackForUUID:(NSString* _Nullable)uuid;
 - (NSSet<NSString*>*)pendingCallbackUUIDs;
 + (void)callSyncCallbackWithErrorNoAccount:(SecBoolNSErrorCallback)syncCallback;
 @end
index 3838cc6b381ea1697dd9e0bde6a917da2337a6ba..d381ec95373d4f3100e0ecd4178c582f8b7b6248 100644 (file)
@@ -34,6 +34,7 @@
 #import "keychain/ckks/CKKSCondition.h"
 #import "keychain/ckks/CKKSListenerCollection.h"
 #import "keychain/ckks/CloudKitCategories.h"
+#import "keychain/ckks/OctagonAPSReceiver.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #import "keychain/analytics/SecEventMetric.h"
 #import "keychain/analytics/SecMetrics.h"
@@ -43,7 +44,7 @@
 #import "keychain/ot/OTConstants.h"
 #import "keychain/ot/ObjCImprovements.h"
 
-#import "TPPolicy.h"
+#import "keychain/trust/TrustedPeers/TPSyncingPolicy.h"
 
 #import "SecEntitlements.h"
 
@@ -94,7 +95,8 @@
 @property BOOL itemModificationsBeforePolicyLoaded;
 
 // Make writable
-@property (nullable) TPPolicy* policy;
+@property (nullable) TPSyncingPolicy* policy;
+@property CKKSCondition* policyLoaded;
 
 #endif
 @end
         _zoneChangeFetcher = [[CKKSZoneChangeFetcher alloc] initWithContainer:_container
                                                                    fetchClass:cloudKitClassDependencies.fetchRecordZoneChangesOperationClass
                                                           reachabilityTracker:_reachabilityTracker];
+        OctagonAPSReceiver* globalAPSReceiver = [OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                              apsConnectionClass:cloudKitClassDependencies.apsConnectionClass];
+        [globalAPSReceiver registerCKKSReceiver:_zoneChangeFetcher];
 
         _zoneModifier = [[CKKSZoneModifier alloc] initWithContainer:_container
                                                 reachabilityTracker:_reachabilityTracker
         }];
 
         _policy = nil;
+        _policyLoaded = [[CKKSCondition alloc] init];
 
         _listener = [NSXPCListener anonymousListener];
         _listener.delegate = self;
         NSError* sosCircleError = nil;
         SOSCCStatus sosStatus = [self.sosPeerAdapter circleStatus:&sosCircleError];
         if(sosCircleError) {
-            secerror("CKKSViewManager: couldn't fetch sos status for SF report: %@", sosCircleError);
+            ckkserror_global("manager", " couldn't fetch sos status for SF report: %@", sosCircleError);
         }
 
         NSMutableDictionary* values = [NSMutableDictionary dictionary];
             NSError* sosCircleError = nil;
             SOSCCStatus sosStatus = [self.sosPeerAdapter circleStatus:&sosCircleError];
             if(sosCircleError) {
-                secerror("CKKSViewManager: couldn't fetch sos status for SF report: %@", sosCircleError);
+                ckkserror_global("manager", " couldn't fetch sos status for SF report: %@", sosCircleError);
             }
             BOOL inCircle = (sosStatus == kSOSCCInCircle);
             NSMutableDictionary* values = [NSMutableDictionary dictionary];
             CKKSKeychainView* view = [self findOrCreateView:viewName];
-            NSDate* dateOfLastSyncClassA = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassA inView:view];
-            NSDate* dateOfLastSyncClassC = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:view];
-            NSDate* dateOfLastKSR = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastKeystateReady inView:view];
+            NSDate* dateOfLastSyncClassA = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassA zoneName:view.zoneName];
+            NSDate* dateOfLastSyncClassC = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC zoneName:view.zoneName];
+            NSDate* dateOfLastKSR = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastKeystateReady zoneName:view.zoneName];
 
             NSInteger fuzzyDaysSinceClassASync = [CKKSAnalytics fuzzyDaysSinceDate:dateOfLastSyncClassA];
             NSInteger fuzzyDaysSinceClassCSync = [CKKSAnalytics fuzzyDaysSinceDate:dateOfLastSyncClassC];
             [values setValue:@(fuzzyDaysSinceClassCSync) forKey:[NSString stringWithFormat:@"%@-daysSinceClassCSync", viewName]];
             [values setValue:@(fuzzyDaysSinceKSR) forKey:[NSString stringWithFormat:@"%@-daysSinceLastKeystateReady", viewName]];
 
-            BOOL hasTLKs = [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateReady] || [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock];
-            /* only synced recently if between [0...7, ie withing 7 days */
+            BOOL hasTLKs = [view.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateReady] || [view.stateMachine.currentState isEqualToString:SecCKKSZoneKeyStateReadyPendingUnlock];
+            /* only synced recently if between [0...7, ie within 7 days */
             BOOL syncedClassARecently = fuzzyDaysSinceClassASync >= 0 && fuzzyDaysSinceClassASync < 7;
             BOOL syncedClassCRecently = fuzzyDaysSinceClassCSync >= 0 && fuzzyDaysSinceClassCSync < 7;
             BOOL incomingQueueIsErrorFree = view.lastIncomingQueueOperation.error == nil;
@@ -314,7 +320,7 @@ dispatch_once_t globalZoneStateQueueOnce;
         CKKSZoneStateEntry* allEntry = [CKKSZoneStateEntry tryFromDatabase: @"all" error:&error];
 
         if(error) {
-            secerror("CKKSViewManager: couldn't load global zone state: %@", error);
+            ckkserror_global("manager", " couldn't load global zone state: %@", error);
         }
 
         if(!error && allEntry.rateLimiter) {
@@ -366,56 +372,90 @@ dispatch_once_t globalZoneStateQueueOnce;
     return [self.views.allKeys copy];
 }
 
-- (void)setSyncingViews:(NSSet<NSString*>*)viewNames sortingPolicy:(TPPolicy*)policy
+- (BOOL)setCurrentSyncingPolicy:(TPSyncingPolicy* _Nullable)syncingPolicy
 {
-    secnotice("ckks-policy", "New syncing policy: %@ views: %@", policy, viewNames);
+    return [self setCurrentSyncingPolicy:syncingPolicy policyIsFresh:NO];
+}
+
+- (BOOL)setCurrentSyncingPolicy:(TPSyncingPolicy* _Nullable)syncingPolicy policyIsFresh:(BOOL)policyIsFresh
+{
+    if(syncingPolicy == nil) {
+        ckksnotice_global("ckks-policy", "Nil syncing policy presented; ignoring");
+        return NO;
+    }
+
+    NSSet<NSString*>* viewNames = syncingPolicy.viewList;
+    ckksnotice_global("ckks-policy", "New syncing policy: %@ views: %@", syncingPolicy, viewNames);
 
     if(![self useCKKSViewsFromPolicy]) {
         // Thanks, but no thanks.
         viewNames = [self defaultViewList];
-        secnotice("ckks-policy", "Reverting to default view list: %@", viewNames);
+        ckksnotice_global("ckks-policy", "Reverting to default view list: %@", viewNames);
     }
 
     if(self.viewAllowList) {
-        secnotice("ckks-policy", "Intersecting view list with allow list: %@", self.viewAllowList);
+        ckksnotice_global("ckks-policy", "Intersecting view list with allow list: %@", self.viewAllowList);
         NSMutableSet<NSString*>* set = [viewNames mutableCopy];
         [set intersectSet:self.viewAllowList];
 
         viewNames = set;
-        secnotice("ckks-policy", "Final list: %@", viewNames);
+        ckksnotice_global("ckks-policy", "Final list: %@", viewNames);
     }
 
-    self.policy = policy;
+    // We need to not be synchronized on self.views before issuing commands to CKKS views.
+    // So, store the pointers for use after the critical section.
+    NSArray<CKKSKeychainView*>* activeViews = nil;
+    BOOL scanAll = NO;
+    BOOL viewsChanged = NO;
 
     @synchronized(self.views) {
+        self.policy = syncingPolicy;
+
         NSArray* previousViewNames = [self.views.allKeys copy];
 
         // First, shut down any views that are no longer in the set
         for(NSString* viewName in previousViewNames) {
             if(![viewNames containsObject:viewName]) {
-                secnotice("ckks-policy", "Stopping old view %@", viewName);
+                ckksnotice_global("ckks-policy", "Stopping old view %@", viewName);
                 [self clearView:viewName];
+                viewsChanged = YES;
             }
         }
 
         for(NSString* viewName in viewNames) {
+            CKKSKeychainView* view = nil;
+
             if([previousViewNames containsObject:viewName]) {
-                CKKSKeychainView* view = [self findView:viewName];
-                secnotice("ckks-policy", "Already have view %@", view);
+                view = [self findView:viewName];
+                ckksinfo_global("ckks-policy", "Already have view %@", view);
+
             } else {
-                CKKSKeychainView* view = [self findOrCreateView:viewName];
-                secnotice("ckks-policy", "Created new view %@", view);
+                view = [self findOrCreateView:viewName];
+                ckksnotice_global("ckks-policy", "Created new view %@", view);
+                viewsChanged = YES;
             }
         }
 
+        activeViews = [self.views.allValues copy];
+
         if(self.itemModificationsBeforePolicyLoaded) {
-            secnotice("ckks-policy", "Issuing scan suggestions to handle missed items");
-            for(CKKSKeychainView* view in [self.views allValues]) {
-                [view scanLocalItems:@"item-added-before-policy"];
-            }
+            ckksnotice_global("ckks-policy", "Issuing scan suggestions to handle missed items");
+            scanAll = YES;
             self.itemModificationsBeforePolicyLoaded = NO;
         }
     }
+
+    for(CKKSKeychainView* view in activeViews) {
+        [view setCurrentSyncingPolicy:self.policy policyIsFresh:policyIsFresh];
+
+        if(scanAll) {
+            [view scanLocalItems:@"item-added-before-policy"];
+        }
+    }
+
+    // The policy is considered loaded once the views have been created
+    [self.policyLoaded fulfill];
+    return viewsChanged;
 }
 
 - (void)setSyncingViewsAllowList:(NSSet<NSString*>*)viewNames
@@ -425,8 +465,9 @@ dispatch_once_t globalZoneStateQueueOnce;
 
 - (void)resetSyncingPolicy
 {
-    secnotice("ckks-policy", "Setting policy to nil");
+    ckksnotice_global("ckks-policy", "Setting policy to nil");
     self.policy = nil;
+    self.policyLoaded = [[CKKSCondition alloc] init];
 
     self.startCKOperationAtViewCreation = NO;
 }
@@ -476,11 +517,43 @@ dispatch_once_t globalZoneStateQueueOnce;
     if(!viewName) {
         return nil;
     }
+
     @synchronized(self.views) {
         return self.views[viewName];
     }
 }
 
+- (CKKSKeychainView* _Nullable)findView:(NSString*)viewName error:(NSError**)error
+{
+    if([self.policyLoaded wait:5*NSEC_PER_SEC] != 0) {
+        ckkserror_global("ckks", "Haven't yet received a syncing policy; expect failure finding views");
+
+        if([self useCKKSViewsFromPolicy]) {
+            if(error) {
+                *error = [NSError errorWithDomain:CKKSErrorDomain
+                                             code:CKKSErrorPolicyNotLoaded
+                                         userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"CKKS syncing policy not yet loaded; cannot find view '%@'", viewName]}];
+
+            }
+            return nil;
+        }
+    }
+
+    @synchronized(self.views) {
+        CKKSKeychainView* view = self.views[viewName];
+        if(!view) {
+            if(error) {
+                *error = [NSError errorWithDomain:CKKSErrorDomain
+                                             code:CKKSNoSuchView
+                                         userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No syncing view for '%@'", viewName]}];
+            }
+            return nil;
+        }
+
+        return view;
+    }
+}
+
 - (CKKSKeychainView*)findOrCreateView:(NSString*)viewName {
     @synchronized(self.views) {
         CKKSKeychainView* kcv = self.views[viewName];
@@ -526,7 +599,7 @@ dispatch_once_t globalZoneStateQueueOnce;
             (void)view;
         }
     } else {
-        secnotice("ckks-views", "Not loading default view list due to enabled CKKS4All");
+        ckksnotice_global("ckks-views", "Not loading default view list due to enabled CKKS4All");
     }
 }
 
@@ -539,21 +612,6 @@ dispatch_once_t globalZoneStateQueueOnce;
     }
 }
 
-- (NSDictionary<NSString *,NSString *> *)activeTLKs
-{
-    NSMutableDictionary<NSString *,NSString *> *tlks = [NSMutableDictionary new];
-    @synchronized(self.views) {
-        for (NSString *name in self.views) {
-            CKKSKeychainView *view = self.views[name];
-            NSString *tlk = view.lastActiveTLKUUID;
-            if (tlk) {
-                tlks[name] = tlk;
-            }
-        }
-    }
-    return tlks;
-}
-
 - (void)haltZone:(NSString*)viewName
 {
     @synchronized(self.views) {
@@ -566,7 +624,11 @@ dispatch_once_t globalZoneStateQueueOnce;
 
 - (CKKSKeychainView*)restartZone:(NSString*)viewName {
     [self haltZone:viewName];
-    return [self findOrCreateView: viewName];
+    CKKSKeychainView* view = [self findOrCreateView: viewName];
+
+    [view setCurrentSyncingPolicy:self.policy policyIsFresh:NO];
+
+    return view;
 }
 
 - (NSString*)viewNameForViewHint: (NSString*) viewHint {
@@ -596,7 +658,7 @@ dispatch_once_t globalZoneStateQueueOnce;
 
         static dispatch_once_t onceToken;
         dispatch_once(&onceToken, ^{
-            secnotice("ckks", "ViewsFromPolicy feature flag: %@", viewsFromPolicy ? @"on" : @"off");
+            ckksnotice_global("ckks", "ViewsFromPolicy feature flag: %@", viewsFromPolicy ? @"on" : @"off");
         });
         return viewsFromPolicy;
     }
@@ -609,32 +671,27 @@ dispatch_once_t globalZoneStateQueueOnce;
         NSMutableDictionary *dict = (__bridge_transfer NSMutableDictionary*) SecDbItemCopyPListWithMask(item, kSecDbSyncFlag, &cferror);
 
         if(cferror) {
-            secerror("ckks: Couldn't fetch attributes from item: %@", cferror);
+            ckkserror_global("ckks", "Couldn't fetch attributes from item: %@", cferror);
             CFReleaseNull(cferror);
             return nil;
         }
 
-        NSString* view = [self.policy mapKeyToView:dict];
+        // Ensure that we've added the class name, because SecDbItemCopyPListWithMask doesn't do that for some reason.
+        dict[(__bridge NSString*)kSecClass] = (__bridge NSString*)item->class->name;
+
+        NSString* view = [self.policy mapDictionaryToView:dict];
         if (view == nil) {
-            secerror("ckks: No view returned from policy (%@): %@", self.policy, dict);
+            ckkserror_global("ckks", "No view returned from policy (%@): %@", self.policy, item);
             return nil;
         }
 
-        // Horrible hack until <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-        if([view isEqualToString:@"CreditCards"]) {
-            return @"SafariCreditCards";
-        }
-        if([view isEqualToString:@"Passwords"]) {
-            return @"SafariPasswords";
-        }
-
         return view;
     } else {
         CFErrorRef cferror = NULL;
         NSString* viewHint = (__bridge NSString*) SecDbItemGetValue(item, &v7vwht, &cferror);
 
         if(cferror) {
-            secerror("ckks: Couldn't fetch the viewhint for some reason: %@", cferror);
+            ckkserror_global("ckks", "Couldn't fetch the viewhint for some reason: %@", cferror);
             CFReleaseNull(cferror);
             viewHint = nil;
         }
@@ -646,18 +703,22 @@ dispatch_once_t globalZoneStateQueueOnce;
 - (void)registerSyncStatusCallback: (NSString*) uuid callback: (SecBoolNSErrorCallback) callback {
     // Someone is requesting future notification of this item.
     @synchronized(self.pendingSyncCallbacks) {
-        secnotice("ckkscallback", "registered callback for UUID: %@", uuid);
+        ckksnotice_global("ckkscallback", "registered callback for UUID: %@", uuid);
         self.pendingSyncCallbacks[uuid] = callback;
     }
 }
 
-- (SecBoolNSErrorCallback _Nullable)claimCallbackForUUID:(NSString*)uuid
+- (SecBoolNSErrorCallback _Nullable)claimCallbackForUUID:(NSString* _Nullable)uuid
 {
+    if(!uuid) {
+        return nil;
+    }
+
     @synchronized(self.pendingSyncCallbacks) {
         SecBoolNSErrorCallback callback = self.pendingSyncCallbacks[uuid];
 
         if(callback) {
-            secerror("ckkscallback : fetched UUID: %@", uuid);
+            ckksnotice_global("ckkscallback", "fetched UUID: %@", uuid);
         }
 
         self.pendingSyncCallbacks[uuid] = nil;
@@ -679,7 +740,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     } else {
         @synchronized(self.pendingSyncCallbacks) {
             if(self.pendingSyncCallbacks.count > 0) {
-                secnotice("ckkscallback", "No CK account; failing all pending sync callbacks");
+                ckksnotice_global("ckkscallback", "No CK account; failing all pending sync callbacks");
 
                 for(NSString* uuid in [self.pendingSyncCallbacks allKeys]) {
                     [CKKSViewManager callSyncCallbackWithErrorNoAccount:self.pendingSyncCallbacks[uuid]];
@@ -725,7 +786,7 @@ dispatch_once_t globalZoneStateQueueOnce;
 
     if(!addedSync && !deletedSync) {
         // Local-only change. Skip with prejudice.
-        secinfo("ckks", "skipping sync of non-sync item (%d, %d)", addedSync, deletedSync);
+        ckksinfo_global("ckks", "skipping sync of non-sync item (%d, %d)", addedSync, deletedSync);
         return;
     }
 
@@ -733,17 +794,17 @@ dispatch_once_t globalZoneStateQueueOnce;
 
     @synchronized(self.views) {
         if([self useCKKSViewsFromPolicy] && !self.policy) {
-            secerror("ckks: No policy configured(%@). Skipping item: %@", self.policy, modified);
+            ckkserror_global("ckks", "No policy configured(%@). Skipping item: %@", self.policy, modified);
             self.itemModificationsBeforePolicyLoaded = YES;
 
             return;
         }
-
-        viewName = [self viewNameForItem:modified];
     }
 
+    viewName = [self viewNameForItem:modified];
+
     if(!viewName) {
-        secnotice("ckks", "No intended CKKS view for item; skipping: %@", modified);
+        ckksnotice_global("ckks", "No intended CKKS view for item; skipping: %@", modified);
         return;
     }
 
@@ -751,7 +812,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     CKKSKeychainView* view = [self findView:viewName];
 
     if(!view) {
-        secnotice("ckks", "No CKKS view for %@, skipping: %@", viewName, modified);
+        ckksnotice_global("ckks", "No CKKS view for %@, skipping: %@", viewName, modified);
 
         NSString* uuid = (__bridge NSString*) SecDbItemGetValue(modified, &v10itemuuid, NULL);
         SecBoolNSErrorCallback syncCallback = [self claimCallbackForUUID:uuid];
@@ -781,13 +842,12 @@ dispatch_once_t globalZoneStateQueueOnce;
                                hash:(NSData*)oldItemSHA1
                            complete:(void (^) (NSError* operror)) complete
 {
-    CKKSKeychainView* view = [self findView:viewHint];
+    NSError* viewError = nil;
+    CKKSKeychainView* view = [self findView:viewHint error:&viewError];
 
     if(!view) {
-        secnotice("ckks", "No CKKS view for %@, skipping current request", viewHint);
-        complete([NSError errorWithDomain:CKKSErrorDomain
-                                     code:CKKSNoSuchView
-                              description:[NSString stringWithFormat: @"No syncing view for view hint '%@'", viewHint]]);
+        ckksnotice_global("ckks", "No CKKS view for %@, skipping setcurrent request: %@", viewHint, viewError);
+        complete(viewError);
         return;
     }
 
@@ -806,12 +866,11 @@ dispatch_once_t globalZoneStateQueueOnce;
                     fetchCloudValue:(bool)fetchCloudValue
                            complete:(void (^) (NSString* uuid, NSError* operror)) complete
 {
-    CKKSKeychainView* view = [self findView:viewHint];
+    NSError* viewError = nil;
+    CKKSKeychainView* view = [self findView:viewHint error:&viewError];
     if(!view) {
-        secnotice("ckks", "No CKKS view for %@, skipping current fetch request", viewHint);
-        complete(NULL, [NSError errorWithDomain:CKKSErrorDomain
-                                           code:CKKSNoSuchView
-                                    description:[NSString stringWithFormat: @"No view for '%@'", viewHint]]);
+        ckksnotice_global("ckks", "No CKKS view for %@, skipping current fetch request: %@", viewHint, viewError);
+        complete(NULL, viewError);
         return;
     }
 
@@ -832,7 +891,7 @@ dispatch_once_t globalZoneStateQueueOnce;
 
 -(void)notifyNewTLKsInKeychain {
     // Why two functions here? Limitation of OCMock, unfortunately: can't stub and expect the same method
-    secnotice("ckksbackup", "New TLKs have arrived");
+    ckksnotice_global("ckksbackup", "New TLKs have arrived");
     [self syncBackupAndNotifyAboutSync];
 }
 
@@ -840,7 +899,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     SOSAccount* account = (__bridge SOSAccount*)SOSKeychainAccountGetSharedAccount();
     
     if(!account) {
-        secnotice("ckks", "Failed to get account object");
+        ckksnotice_global("ckks", "Failed to get account object");
         return;
     }
 
@@ -850,14 +909,71 @@ dispatch_once_t globalZoneStateQueueOnce;
         (void)ignore;
 
         if(error) {
-            secerror("ckksbackup: Couldn't process sync with backup peers: %@", error);
+            ckkserror_global("backup", "Couldn't process sync with backup peers: %@", error);
         } else {
-            secnotice("ckksbackup", "telling CloudServices about TLK arrival");
+            ckksnotice_global("ckksbackup", "telling CloudServices about TLK arrival");
             notify_post(kSecItemBackupNotification);
         };
     }];
 }
 
+
+
+- (NSArray<CKKSKeychainBackedKey*>* _Nullable)currentTLKsFilteredByPolicy:(BOOL)restrictToPolicy error:(NSError**)error
+{
+    NSError* localError = nil;
+    NSArray<CKKSKeychainView*>* actualViews = [self views:nil operation:@"current TLKs" error:&localError];
+    if(localError) {
+        ckkserror_global("ckks", "Error getting views: %@", localError);
+        if(error) {
+            *error = localError;
+        }
+        return nil;
+    }
+
+    NSMutableArray<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* keyFetchOperations = [NSMutableArray array];
+    for (CKKSKeychainView* view in actualViews) {
+        if(restrictToPolicy && [self useCKKSViewsFromPolicy] && ![self.policy.viewsToPiggybackTLKs containsObject:view.zoneName]) {
+            continue;
+        }
+
+        CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op = [view findKeySet:NO];
+        [op timeout:10*NSEC_PER_SEC];
+        [keyFetchOperations addObject:op];
+    }
+
+    NSMutableArray<CKKSKeychainBackedKey*>* tlks = [NSMutableArray array];
+
+    for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in keyFetchOperations) {
+        [op waitUntilFinished];
+
+        if(op.error) {
+            ckkserror_global("ckks", "Error getting keyset: %@", op.error);
+            if(error) {
+                *error = op.error;
+            }
+        } else {
+            if(op.keyset.tlk) {
+                // Keys provided by this function must have the key material loaded
+                NSError* loadError = nil;
+                [op.keyset.tlk ensureKeyLoaded:&loadError];
+                if(loadError) {
+                    ckkserror_global("ckks", "Error loading key: %@", loadError);
+                    if(error) {
+                        *error = loadError;
+                    }
+                } else {
+                    [tlks addObject:[op.keyset.tlk.keycore copy]];
+                }
+            } else {
+                ckkserror_global("ckks", "Do not have TLK: %@", op.keyset);
+            }
+        }
+    }
+
+    return tlks;
+}
+
 #pragma mark - RPCs to manage and report state
 
 - (void)performanceCounters:(void(^)(NSDictionary <NSString *, NSNumber *> *counter))reply {
@@ -865,32 +981,53 @@ dispatch_once_t globalZoneStateQueueOnce;
 }
 
 - (NSArray<CKKSKeychainView*>*)views:(NSString*)viewName operation:(NSString*)opName error:(NSError**)error
+{
+    return [self views:viewName operation:opName errorOnPolicyMissing:YES error:error];
+}
+
+- (NSArray<CKKSKeychainView*>*)views:(NSString*)viewName
+                           operation:(NSString*)opName
+                errorOnPolicyMissing:(BOOL)errorOnPolicyMissing
+                               error:(NSError**)error
 {
     NSArray* actualViews = nil;
 
     // Ensure we've actually set up, but don't wait too long. Clients get impatient.
     if([self.completedSecCKKSInitialize wait:5*NSEC_PER_SEC]) {
-        secerror("ckks: Haven't yet initialized zones; expect failure fetching views");
+        ckkserror_global("ckks", "Haven't yet initialized zones; expect failure fetching views");
     }
 
-    @synchronized(self.views) {
-        if(viewName) {
-            CKKSKeychainView* view = self.views[viewName];
-            secnotice("ckks", "Received a %@ request for zone %@ (%@)", opName, viewName, view);
+    // If the caller doesn't mind if the policy is missing, wait some, but not the full 5s
+    BOOL policyLoaded = [self.policyLoaded wait:(errorOnPolicyMissing ? 5 : 0.5)*NSEC_PER_SEC] == 0;
+    if(!policyLoaded) {
+        ckkserror_global("ckks", "Haven't yet received a policy; expect failure fetching views");
+    }
 
-            if(!view) {
+    if(viewName) {
+        CKKSKeychainView* view = errorOnPolicyMissing ? [self findView:viewName error:error] : [self findView:viewName];
+        ckksnotice_global("ckks", "Received a %@ request for zone %@ (%@)", opName, viewName, view);
+
+        if(!view) {
+            return nil;
+        }
+
+        actualViews = @[view];
+
+    } else {
+        if(!policyLoaded && [self useCKKSViewsFromPolicy] && errorOnPolicyMissing) {
+            if(error) {
                 if(error) {
                     *error = [NSError errorWithDomain:CKKSErrorDomain
-                                                 code:CKKSNoSuchView
-                                             userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"No view for '%@'", viewName]}];
+                                                 code:CKKSErrorPolicyNotLoaded
+                                             userInfo:@{NSLocalizedDescriptionKey: @"CKKS syncing policy not yet loaded; cannot list all views"}];
                 }
-                return nil;
             }
+            return nil;
+        }
 
-            actualViews = @[view];
-        } else {
+        @synchronized(self.views) {
             actualViews = [self.views.allValues copy];
-            secnotice("ckks", "Received a %@ request for all zones: %@", opName, actualViews);
+            ckksnotice_global("ckks", "Received a %@ request for all zones: %@", opName, actualViews);
         }
     }
     actualViews = [actualViews sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"zoneName" ascending:YES]]];
@@ -901,16 +1038,16 @@ dispatch_once_t globalZoneStateQueueOnce;
     NSError* localError = nil;
     NSArray* actualViews = [self views:viewName operation:@"local reset" error:&localError];
     if(localError) {
-        secerror("ckks: Error getting view %@: %@", viewName, localError);
+        ckkserror_global("ckks", "Error getting view %@: %@", viewName, localError);
         reply(localError);
         return;
     }
 
     CKKSResultOperation* op = [CKKSResultOperation named:@"local-reset-zones-waiter" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull strongOp) {
         if(!strongOp.error) {
-            secnotice("ckksreset", "Completed rpcResetLocal");
+            ckksnotice_global("ckksreset", "Completed rpcResetLocal");
         } else {
-            secnotice("ckks", "Completed rpcResetLocal with error: %@", strongOp.error);
+            ckksnotice_global("ckks", "Completed rpcResetLocal with error: %@", strongOp.error);
         }
         reply(CKXPCSuitableError(strongOp.error));
     }];
@@ -928,7 +1065,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     NSError* localError = nil;
     NSArray* actualViews = [self views:viewName operation:@"CloudKit reset" error:&localError];
     if(localError) {
-        secerror("ckks: Error getting view %@: %@", viewName, localError);
+        ckkserror_global("ckks", "Error getting view %@: %@", viewName, localError);
         reply(localError);
         return;
     }
@@ -940,9 +1077,9 @@ dispatch_once_t globalZoneStateQueueOnce;
     [op setCompletionBlock:^{
         __strong __typeof(op) strongOp = weakOp;
         if(!strongOp.error) {
-            secnotice("ckksreset", "Completed rpcResetCloudKit");
+            ckksnotice_global("ckksreset", "Completed rpcResetCloudKit");
         } else {
-            secnotice("ckksreset", "Completed rpcResetCloudKit with error: %@", strongOp.error);
+            ckksnotice_global("ckksreset", "Completed rpcResetCloudKit with error: %@", strongOp.error);
         }
         reply(CKXPCSuitableError(strongOp.error));
     }];
@@ -961,7 +1098,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     NSError* localError = nil;
     NSArray* actualViews = [self views:viewName operation:@"CloudKit resync" error:&localError];
     if(localError) {
-        secerror("ckks: Error getting view %@: %@", viewName, localError);
+        ckkserror_global("ckks", "Error getting view %@: %@", viewName, localError);
         reply(localError);
         return;
     }
@@ -973,7 +1110,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     // Use the completion block instead of the operation block, so that it runs even if the cancel fires
     [op setCompletionBlock:^{
         __strong __typeof(op) strongOp = weakOp;
-        secnotice("ckks", "Ending rsync-CloudKit rpc with %@", strongOp.error);
+        ckksnotice_global("ckks", "Ending rsync-CloudKit rpc with %@", strongOp.error);
         reply(CKXPCSuitableError(strongOp.error));
     }];
 
@@ -992,7 +1129,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     NSError* localError = nil;
     NSArray* actualViews = [self views:viewName operation:@"local resync" error:&localError];
     if(localError) {
-        secerror("ckks: Error getting view %@: %@", viewName, localError);
+        ckkserror_global("ckks", "Error getting view %@: %@", viewName, localError);
         reply(localError);
         return;
     }
@@ -1003,7 +1140,7 @@ dispatch_once_t globalZoneStateQueueOnce;
     // Use the completion block instead of the operation block, so that it runs even if the cancel fires
     [op setCompletionBlock:^{
         __strong __typeof(op) strongOp = weakOp;
-        secnotice("ckks", "Ending rsync-local rpc with %@", strongOp.error);
+        ckksnotice_global("ckks", "Ending rsync-local rpc with %@", strongOp.error);
         reply(CKXPCSuitableError(strongOp.error));
     }];
 
@@ -1023,9 +1160,9 @@ dispatch_once_t globalZoneStateQueueOnce;
 {
     NSMutableArray* a = [[NSMutableArray alloc] init];
 
-    // Now, query the views about their status
+    // Now, query the views about their status. Don't wait for the policy to be loaded
     NSError* error = nil;
-    NSArray* actualViews = [self views:viewName operation:@"status" error:&error];
+    NSArray* actualViews = [self views:viewName operation:@"status" errorOnPolicyMissing:NO error:&error];
     if(!actualViews || error) {
         reply(nil, error);
         return;
@@ -1075,21 +1212,23 @@ dispatch_once_t globalZoneStateQueueOnce;
 
     // If we're signed in, give the views a few seconds to enter what they consider to be a non-transient state (in case this daemon just launched)
     if([self.accountTracker.ckAccountInfoInitialized wait:5*NSEC_PER_SEC]) {
-        secerror("ckks status: Haven't yet figured out cloudkit account state");
+        ckkserror_global("account", "Haven't yet figured out cloudkit account state");
     }
 
     if(self.accountTracker.currentCKAccountInfo.accountStatus == CKAccountStatusAvailable) {
         if (![self waitForTrustReady]) {
-            secerror("ckks status: Haven't yet figured out trust status");
+            ckkserror_global("trust", "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) {
-            [blockOp addNullableDependency:view.keyStateNonTransientDependency];
+            OctagonStateMultiStateArrivalWatcher* waitForTransient = [[OctagonStateMultiStateArrivalWatcher alloc] initNamed:@"rpc-watcher"
+                                                                                                                 serialQueue:view.queue
+                                                                                                                      states:CKKSKeyStateNonTransientStates()];
+            [waitForTransient timeout:5*NSEC_PER_SEC];
+            [view.stateMachine registerMultiStateArrivalWatcher:waitForTransient];
+
+            [statusOp addDependency:waitForTransient.result];
         }
-        [statusOp addDependency:blockOp];
-        [self.operationQueue addOperation:blockOp];
     }
     [self.operationQueue addOperation:statusOp];
 
@@ -1188,15 +1327,14 @@ dispatch_once_t globalZoneStateQueueOnce;
     }];
     [[SecMetrics managerObject] submitEvent:metric];
     reply(NULL);
-
 }
 
 -(void)xpc24HrNotification {
     // XPC has poked us and said we should do some cleanup!
-    secnotice("ckks", "Received a 24hr notification from XPC");
+    ckksnotice_global("ckks", "Received a 24hr notification from XPC");
 
     if (![self waitForTrustReady]) {
-        secnotice("ckks", "Trust not ready, still going ahead");
+        ckksnotice_global("ckks", "Trust not ready, still going ahead");
     }
 
     [[CKKSAnalytics logger] dailyCoreAnalyticsMetrics:@"com.apple.security.CKKSHealthSummary"];
@@ -1213,19 +1351,19 @@ dispatch_once_t globalZoneStateQueueOnce;
         ckksnotice("ckks", view, "Starting device state XPC update");
         // Let the update know it should rate-limit itself
         [view updateDeviceState:true waitForKeyHierarchyInitialization:30*NSEC_PER_SEC ckoperationGroup:group];
+        [view xpc24HrNotification];
     }
 }
 
 - (void)haltAll
 {
-    [self.zoneModifier halt];
-
     @synchronized(self.views) {
         for(CKKSKeychainView* view in self.views.allValues) {
             [view halt];
         }
     }
 
+    [self.zoneModifier halt];
 }
 
 #endif // OCTAGON
diff --git a/keychain/ckks/CKKSZone.h b/keychain/ckks/CKKSZone.h
deleted file mode 100644 (file)
index 5869326..0000000
+++ /dev/null
@@ -1,138 +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@
- */
-
-#import <Foundation/Foundation.h>
-
-#if OCTAGON
-#import "keychain/ckks/CKKSAccountStateTracker.h"
-#import "keychain/ckks/CKKSReachabilityTracker.h"
-#import "keychain/ckks/CloudKitDependencies.h"
-#import "keychain/ckks/CKKSCloudKitClassDependencies.h"
-#import "keychain/ckks/OctagonAPSReceiver.h"
-#import "keychain/ckks/CKKSGroupOperation.h"
-#import "keychain/ckks/CKKSNearFutureScheduler.h"
-#import "keychain/ckks/CKKSZoneModifier.h"
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface CKKSZone : NSObject <CKKSZoneUpdateReceiver, CKKSCloudKitAccountStateListener>
-{
-    CKContainer* _container;
-    CKDatabase* _database;
-    CKRecordZone* _zone;
-}
-
-@property (readonly) NSString* zoneName;
-
-@property CKKSGroupOperation* zoneSetupOperation;
-@property (nullable) CKOperationGroup* zoneSetupOperationGroup; // set this if you want zone creates to use a different operation group
-
-@property bool zoneCreated;
-@property bool zoneSubscribed;
-@property (nullable) NSError* zoneCreatedError;
-@property (nullable) NSError* zoneSubscribedError;
-
-// True if this zone object has been halted. Halted zones will never recover.
-@property (readonly) bool halted;
-
-@property CKKSAccountStatus accountStatus;
-
-@property (readonly) CKContainer* container;
-@property (readonly) CKDatabase* database;
-
-@property (weak) CKKSAccountStateTracker* accountTracker;
-@property (weak) CKKSReachabilityTracker* reachabilityTracker;
-
-@property (readonly) CKRecordZone* zone;
-@property (readonly) CKRecordZoneID* zoneID;
-
-@property (readonly) CKKSZoneModifier* zoneModifier;
-
-// Dependencies (for injection)
-@property (readonly) CKKSCloudKitClassDependencies* cloudKitClassDependencies;
-
-@property dispatch_queue_t queue;
-
-- (instancetype)initWithContainer:(CKContainer*)container
-                         zoneName:(NSString*)zoneName
-                   accountTracker:(CKKSAccountStateTracker*)accountTracker
-              reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker
-                     zoneModifier:(CKKSZoneModifier*)zoneModifier
-        cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies;
-
-
-- (CKKSResultOperation* _Nullable)deleteCloudKitZoneOperation:(CKOperationGroup* _Nullable)ckoperationGroup;
-
-// Called when CloudKit notifies us that we just logged in.
-// That is, if we transition from any state to CKAccountStatusAvailable.
-// This will be called under the protection of dispatchSync.
-// This is a no-op; you should intercept this call and call handleCKLogin:zoneSubscribed:
-// with the appropriate state
-- (void)handleCKLogin;
-
-// Actually start a cloudkit login. Pass in whether you believe this zone has been created and if this device has
-// subscribed to this zone on the server.
-- (CKKSResultOperation* _Nullable)handleCKLogin:(bool)zoneCreated zoneSubscribed:(bool)zoneSubscribed;
-
-// Called when CloudKit notifies us that we just logged out.
-// i.e. we transition from CKAccountStatusAvailable to any other state.
-// This will be called under the protection of dispatchSync
-- (void)handleCKLogout;
-
-// Call this when you're ready for this zone to kick off operations
-// based on iCloud account status
-- (void)beginCloudKitOperation;
-
-// Cancels all operations (no matter what they are).
-- (void)cancelAllOperations;
-
-// Schedules this operation for execution (if the CloudKit account exists)
-- (bool)scheduleOperation:(NSOperation*)op;
-
-// Use this to schedule an operation handling account status (cleaning up after logout, etc.).
-- (bool)scheduleAccountStatusOperation:(NSOperation*)op;
-
-// Schedules this operation for execution, and doesn't do any dependency magic
-// This should _only_ be used if you want to run something even if the CloudKit account is logged out
-- (bool)scheduleOperationWithoutDependencies:(NSOperation*)op;
-
-// Use this for testing.
-- (void)waitUntilAllOperationsAreFinished;
-
-// Use this for testing, to only wait for a certain type of operation to finish.
-- (void)waitForOperationsOfClass:(Class)operationClass;
-
-// If this object wants to do anything that needs synchronization, use this.
-// If this object has had -halt called, this block will never fire.
-- (void)dispatchSync:(bool (^)(void))block;
-
-// Call this to halt everything this zone is doing. This object will never recover. Use for testing.
-- (void)halt;
-
-// Call this to reset this object's setup, so you can call createSetupOperation again.
-- (void)resetSetup;
-
-@end
-
-NS_ASSUME_NONNULL_END
-#endif  // OCTAGON
diff --git a/keychain/ckks/CKKSZone.m b/keychain/ckks/CKKSZone.m
deleted file mode 100644 (file)
index c5f878b..0000000
+++ /dev/null
@@ -1,465 +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 <AssertMacros.h>
-
-#import <Foundation/Foundation.h>
-
-#if OCTAGON
-#import "CloudKitDependencies.h"
-#import "keychain/ckks/CKKSAccountStateTracker.h"
-#import "keychain/ckks/CloudKitCategories.h"
-#import "keychain/categories/NSError+UsefulConstructors.h"
-#import <CloudKit/CloudKit.h>
-#import <CloudKit/CloudKit_Private.h>
-
-#import "keychain/ot/ObjCImprovements.h"
-
-#import "CKKSKeychainView.h"
-#import "CKKSZone.h"
-
-#include <utilities/debugging.h>
-
-@interface CKKSZone()
-
-@property CKDatabaseOperation<CKKSModifyRecordZonesOperation>* zoneCreationOperation;
-@property CKDatabaseOperation<CKKSModifyRecordZonesOperation>* zoneDeletionOperation;
-@property CKDatabaseOperation<CKKSModifySubscriptionsOperation>* zoneSubscriptionOperation;
-
-@property NSOperationQueue* operationQueue;
-@property CKKSResultOperation* accountLoggedInDependency;
-
-@property NSHashTable<NSOperation*>* accountOperations;
-
-// Make writable
-@property bool halted;
-@end
-
-@implementation CKKSZone
-
-- (instancetype)initWithContainer:(CKContainer*)container
-                         zoneName:(NSString*)zoneName
-                   accountTracker:(CKKSAccountStateTracker*)accountTracker
-              reachabilityTracker:(CKKSReachabilityTracker*)reachabilityTracker
-                     zoneModifier:(CKKSZoneModifier*)zoneModifier
-        cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies
-{
-    if(self = [super init]) {
-        _container = container;
-        _zoneName = zoneName;
-        _accountTracker = accountTracker;
-        _reachabilityTracker = reachabilityTracker;
-
-        _zoneModifier = zoneModifier;
-
-        _halted = false;
-
-        _database = [_container privateCloudDatabase];
-        _zone = [[CKRecordZone alloc] initWithZoneID: [[CKRecordZoneID alloc] initWithZoneName:zoneName ownerName:CKCurrentUserDefaultName]];
-
-        _accountStatus = CKKSAccountStatusUnknown;
-
-        _accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in."];
-
-        _accountOperations = [NSHashTable weakObjectsHashTable];
-
-        _cloudKitClassDependencies = cloudKitClassDependencies;
-
-        _queue = dispatch_queue_create([[NSString stringWithFormat:@"CKKSQueue.%@.zone.%@", container.containerIdentifier, zoneName] UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
-        _operationQueue = [[NSOperationQueue alloc] init];
-    }
-    return self;
-}
-
-- (CKKSResultOperation*)createAccountLoggedInDependency:(NSString*)message {
-    WEAKIFY(self);
-    CKKSResultOperation* accountLoggedInDependency = [CKKSResultOperation named:@"account-logged-in-dependency" withBlock:^{
-        STRONGIFY(self);
-        ckksnotice("ckkszone", self, "%@", message);
-    }];
-    accountLoggedInDependency.descriptionErrorCode = CKKSResultDescriptionPendingAccountLoggedIn;
-    return accountLoggedInDependency;
-}
-
-- (void)beginCloudKitOperation {
-    [self.accountTracker registerForNotificationsOfCloudKitAccountStatusChange:self];
-}
-
-- (void)resetSetup {
-    self.zoneCreated = false;
-    self.zoneSubscribed = false;
-    self.zoneCreatedError = nil;
-    self.zoneSubscribedError = nil;
-
-    self.zoneCreationOperation = nil;
-    self.zoneSubscriptionOperation = nil;
-    self.zoneDeletionOperation = nil;
-}
-
-- (CKRecordZoneID*)zoneID {
-    return [self.zone zoneID];
-}
-
-- (CKKSAccountStatus)accountStatusFromCKAccountInfo:(CKAccountInfo*)info
-{
-    if(!info) {
-        return CKKSAccountStatusUnknown;
-    }
-    if(info.accountStatus == CKAccountStatusAvailable &&
-       info.hasValidCredentials) {
-        return CKKSAccountStatusAvailable;
-    } else {
-        return CKKSAccountStatusNoAccount;
-    }
-}
-
-
-- (void)cloudkitAccountStateChange:(CKAccountInfo* _Nullable)oldAccountInfo to:(CKAccountInfo*)currentAccountInfo
-{
-    ckksnotice("ckkszone", self, "%@ Received notification of CloudKit account status change, moving from %@ to %@",
-               self.zoneID.zoneName,
-               oldAccountInfo,
-               currentAccountInfo);
-
-    // Filter for device2device encryption and cloudkit grey mode
-    CKKSAccountStatus oldStatus = [self accountStatusFromCKAccountInfo:oldAccountInfo];
-    CKKSAccountStatus currentStatus = [self accountStatusFromCKAccountInfo:currentAccountInfo];
-
-    if(oldStatus == currentStatus) {
-        ckksnotice("ckkszone", self, "Computed status of new CK account info is same as old status: %@", [CKKSAccountStateTracker stringFromAccountStatus:currentStatus]);
-        return;
-    }
-
-    switch(currentStatus) {
-        case CKKSAccountStatusAvailable: {
-            ckksnotice("ckkszone", self, "Logged into iCloud.");
-            [self handleCKLogin];
-
-            if(self.accountLoggedInDependency) {
-                [self.operationQueue addOperation:self.accountLoggedInDependency];
-                self.accountLoggedInDependency = nil;
-            };
-        }
-            break;
-
-        case CKKSAccountStatusNoAccount: {
-            ckksnotice("ckkszone", self, "Logging out of iCloud. Shutting down.");
-
-            if(!self.accountLoggedInDependency) {
-                self.accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in again."];
-            }
-
-            [self handleCKLogout];
-        }
-            break;
-
-        case CKKSAccountStatusUnknown: {
-            // We really don't expect to receive this as a notification, but, okay!
-            ckksnotice("ckkszone", self, "Account status has become undetermined. Pausing for %@", self.zoneID.zoneName);
-
-            if(!self.accountLoggedInDependency) {
-                self.accountLoggedInDependency = [self createAccountLoggedInDependency:@"CloudKit account logged in again."];
-            }
-
-            [self handleCKLogout];
-        }
-            break;
-    }
-}
-
-- (CKKSResultOperation*)handleCKLogin:(bool)zoneCreated zoneSubscribed:(bool)zoneSubscribed {
-    if(!SecCKKSIsEnabled()) {
-        ckksinfo("ckkszone", self, "Skipping CloudKit registration due to disabled CKKS");
-        return nil;
-    }
-
-    // If we've already started set up and that hasn't finished, complain
-    if([self.zoneSetupOperation isPending] || [self.zoneSetupOperation isExecuting]) {
-        ckksnotice("ckkszone", self, "Asked to handleCKLogin, but zoneSetupOperation appears to not be complete? %@ Continuing anyway", self.zoneSetupOperation);
-    }
-
-    self.zoneSetupOperation = [[CKKSGroupOperation alloc] init];
-    self.zoneSetupOperation.name = [NSString stringWithFormat:@"zone-setup-operation-%@", self.zoneName];
-
-    self.zoneCreated = zoneCreated;
-    self.zoneSubscribed = zoneSubscribed;
-
-    ckksnotice("ckkszone", self, "Setting up zone %@", self.zoneName);
-
-    WEAKIFY(self);
-
-    // First, check the account status. If it's sufficient, add the necessary CloudKit operations to this operation
-    __weak CKKSGroupOperation* weakZoneSetupOperation = self.zoneSetupOperation;
-    [self.zoneSetupOperation runBeforeGroupFinished:[CKKSResultOperation named:[NSString stringWithFormat:@"zone-setup-%@", self.zoneName] withBlock:^{
-        STRONGIFY(self);
-        __strong __typeof(self.zoneSetupOperation) zoneSetupOperation = weakZoneSetupOperation;
-        if(!self || !zoneSetupOperation) {
-            ckkserror("ckkszone", self, "received callback for released object");
-            return;
-        }
-
-        if(self.accountStatus != CKKSAccountStatusAvailable) {
-            ckkserror("ckkszone", self, "Zone doesn't believe it's logged in; quitting setup");
-            return;
-        }
-
-        NSBlockOperation* setupCompleteOperation = [NSBlockOperation blockOperationWithBlock:^{
-            STRONGIFY(self);
-            if(!self) {
-                secerror("ckkszone: received callback for released object");
-                return;
-            }
-
-            ckksnotice("ckkszone", self, "%@: Setup complete", self.zoneName);
-        }];
-        setupCompleteOperation.name = @"zone-setup-complete-operation";
-
-        // We have an account, so fetch the push environment and bring up APS
-        [self.container serverPreferredPushEnvironmentWithCompletionHandler: ^(NSString *apsPushEnvString, NSError *error) {
-            STRONGIFY(self);
-            if(!self) {
-                secerror("ckkszone: received callback for released object");
-                return;
-            }
-
-            if(error || (apsPushEnvString == nil)) {
-                ckkserror("ckkszone", self, "Received error fetching preferred push environment (%@). Keychain syncing is highly degraded: %@", apsPushEnvString, error);
-            } else {
-                OctagonAPSReceiver* aps = [OctagonAPSReceiver receiverForEnvironment:apsPushEnvString
-                                                             namedDelegatePort:SecCKKSAPSNamedPort
-                                                            apsConnectionClass:self.cloudKitClassDependencies.apsConnectionClass];
-                [aps registerReceiver:self forZoneID:self.zoneID];
-            }
-        }];
-
-        if(!zoneCreated || !zoneSubscribed) {
-            ckksnotice("ckkszone", self, "Asking to create and subscribe to CloudKit zone '%@'", self.zoneName);
-            CKKSZoneModifyOperations* zoneOps = [self.zoneModifier createZone:self.zone];
-
-            CKKSResultOperation* handleModificationsOperation = [CKKSResultOperation named:@"handle-modification" withBlock:^{
-                STRONGIFY(self);
-                if([zoneOps.savedRecordZones containsObject:self.zone]) {
-                    ckksnotice("ckkszone", self, "Successfully created '%@'", self.zoneName);
-                    self.zoneCreated = true;
-                } else {
-                    ckksnotice("ckkszone", self, "Failed to create '%@'", self.zoneName);
-                    self.zoneCreatedError = zoneOps.zoneModificationOperation.error;
-                }
-
-                bool createdSubscription = false;
-                for(CKSubscription* subscription in zoneOps.savedSubscriptions) {
-                    if([subscription.zoneID isEqual:self.zoneID]) {
-                        createdSubscription = true;
-                        break;
-                    }
-                }
-
-                if(createdSubscription) {
-                    ckksnotice("ckkszone", self, "Successfully subscribed '%@'", self.zoneName);
-                    self.zoneSubscribed = true;
-                } else {
-                    ckksnotice("ckkszone", self, "Failed to subscribe to '%@'", self.zoneName);
-                    self.zoneSubscribedError = zoneOps.zoneSubscriptionOperation.error;
-                }
-            }];
-            [setupCompleteOperation addDependency:zoneOps.zoneModificationOperation];
-            [handleModificationsOperation addDependency:zoneOps.zoneModificationOperation];
-            [handleModificationsOperation addDependency:zoneOps.zoneSubscriptionOperation];
-            [zoneSetupOperation runBeforeGroupFinished:handleModificationsOperation];
-        } else {
-            ckksnotice("ckkszone", self, "no need to create or subscribe to the zone '%@'", self.zoneName);
-        }
-
-        [self.zoneSetupOperation runBeforeGroupFinished:setupCompleteOperation];
-    }]];
-
-    [self scheduleAccountStatusOperation:self.zoneSetupOperation];
-    return self.zoneSetupOperation;
-}
-
-
-- (CKKSResultOperation*)deleteCloudKitZoneOperation:(CKOperationGroup* _Nullable)ckoperationGroup {
-    if(!SecCKKSIsEnabled()) {
-        ckksnotice("ckkszone", self, "Skipping CloudKit reset due to disabled CKKS");
-        return nil;
-    }
-
-    WEAKIFY(self);
-
-    // We want to delete this zone and this subscription from CloudKit.
-
-    // Step 1: cancel setup operations (if they exist)
-    [self.accountLoggedInDependency cancel];
-    [self.zoneSetupOperation cancel];
-    [self.zoneCreationOperation cancel];
-    [self.zoneSubscriptionOperation cancel];
-
-    // Step 2: Try to delete the zone
-
-    CKKSZoneModifyOperations* zoneOps = [self.zoneModifier deleteZone:self.zoneID];
-
-    CKKSResultOperation* afterModification = [CKKSResultOperation named:@"after-modification" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) {
-        STRONGIFY(self);
-
-        bool fatalError = false;
-
-        NSError* operationError = zoneOps.zoneModificationOperation.error;
-        bool removed = [zoneOps.deletedRecordZoneIDs containsObject:self.zoneID];
-
-        if(!removed && operationError) {
-            // Okay, but if this error is either 'ZoneNotFound' or 'UserDeletedZone', that's fine by us: the zone is deleted.
-            NSDictionary* partialErrors = operationError.userInfo[CKPartialErrorsByItemIDKey];
-            if([operationError.domain isEqualToString:CKErrorDomain] && operationError.code == CKErrorPartialFailure && partialErrors) {
-                for(CKRecordZoneID* errorZoneID in partialErrors.allKeys) {
-                    NSError* errorZone = partialErrors[errorZoneID];
-
-                    if(errorZone && [errorZone.domain isEqualToString:CKErrorDomain] &&
-                       (errorZone.code == CKErrorZoneNotFound || errorZone.code == CKErrorUserDeletedZone)) {
-                        ckksnotice("ckkszone", self, "Attempted to delete zone %@, but it's already missing. This is okay: %@", errorZoneID, errorZone);
-                    } else {
-                        fatalError = true;
-                    }
-                }
-
-            } else {
-                fatalError = true;
-            }
-
-            ckksnotice("ckkszone", self, "deletion of record zone %@ completed with error: %@", self.zoneID, operationError);
-
-            if(fatalError) {
-                op.error = operationError;
-            }
-        } else {
-            ckksnotice("ckkszone", self, "deletion of record zone %@ completed successfully", self.zoneID);
-        }
-    }];
-
-    [afterModification addDependency:zoneOps.zoneModificationOperation];
-    return afterModification;
-}
-
-- (void)notifyZoneChange: (CKRecordZoneNotification*) notification {
-    ckksnotice("ckkszone", self, "received a notification for CK zone change, ignoring");
-}
-
-- (void)handleCKLogin {
-    ckksinfo("ckkszone", self, "received a notification of CK login");
-    self.accountStatus = CKKSAccountStatusAvailable;
-}
-
-- (void)handleCKLogout {
-    ckksinfo("ckkszone", self, "received a notification of CK logout");
-    self.accountStatus = CKKSAccountStatusNoAccount;
-    [self resetSetup];
-}
-
-- (bool)scheduleOperation: (NSOperation*) op {
-    if(self.halted) {
-        ckkserror("ckkszone", self, "attempted to schedule an operation on a halted zone, ignoring");
-        return false;
-    }
-
-    [op addNullableDependency:self.accountLoggedInDependency];
-
-    [self.operationQueue addOperation: op];
-    return true;
-}
-
-- (void)cancelAllOperations {
-    [self.operationQueue cancelAllOperations];
-}
-
-- (void)waitUntilAllOperationsAreFinished {
-    [self.operationQueue waitUntilAllOperationsAreFinished];
-}
-
-- (void)waitForOperationsOfClass:(Class) operationClass {
-    NSArray* operations = [self.operationQueue.operations copy];
-    for(NSOperation* op in operations) {
-        if([op isKindOfClass:operationClass]) {
-            [op waitUntilFinished];
-        }
-    }
-}
-
-- (bool)scheduleAccountStatusOperation: (NSOperation*) op {
-    if(self.halted) {
-        ckkserror("ckkszone", self, "attempted to schedule an account operation on a halted zone, ignoring");
-        return false;
-    }
-
-    // Always succeed. But, account status operations should always proceed in-order.
-    [op linearDependencies:self.accountOperations];
-    [self.operationQueue addOperation: op];
-    return true;
-}
-
-// to be used rarely, if at all
-- (bool)scheduleOperationWithoutDependencies:(NSOperation*)op {
-    if(self.halted) {
-        ckkserror("ckkszone", self, "attempted to schedule an non-dependent operation on a halted zone, ignoring");
-        return false;
-    }
-
-    [self.operationQueue addOperation: op];
-    return true;
-}
-
-- (void) dispatchSync: (bool (^)(void)) block {
-    // important enough to block this thread.
-    __block bool ok = false;
-    dispatch_sync(self.queue, ^{
-        if(self.halted) {
-            ckkserror("ckkszone", self, "CKKSZone not dispatchSyncing a block (due to being halted)");
-            return;
-        }
-
-        ok = block();
-        if(!ok) {
-            ckkserror("ckkszone", self, "CKKSZone block returned false");
-        }
-    });
-}
-
-- (void)halt {
-    // Synchronously set the 'halted' bit
-    dispatch_sync(self.queue, ^{
-        self.halted = true;
-    });
-
-    // Bring all operations down, too
-    [self cancelAllOperations];
-
-    // And now, wait for all operations that are running
-    for(NSOperation* op in self.operationQueue.operations) {
-        if(op.isExecuting) {
-            [op waitUntilFinished];
-        }
-    }
-}
-
-@end
-
-#endif /* OCTAGON */
-
index 08510fb26205cee96ebebd4419bd2abe4692f345..dedcf5872ca9be6f96588a791337f25952e27769 100644 (file)
@@ -26,6 +26,7 @@
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSResultOperation.h"
 #import "keychain/ckks/CKKSFetchAllRecordZoneChangesOperation.h"
+#import "keychain/ckks/OctagonAPSReceiver.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -39,7 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
 @class CKKSReachabilityTracker;
 @class CKKSNearFutureScheduler;
 
-@interface CKKSZoneChangeFetcher : NSObject
+@interface CKKSZoneChangeFetcher : NSObject <CKKSZoneUpdateReceiverProtocol>
 @property (readonly) Class<CKKSFetchRecordZoneChangesOperation> fetchRecordZoneChangesOperationClass;
 @property (readonly) CKContainer* container;
 @property CKKSReachabilityTracker* reachabilityTracker;
@@ -56,8 +57,11 @@ NS_ASSUME_NONNULL_BEGIN
 - (CKKSResultOperation*)requestSuccessfulFetch:(CKKSFetchBecause*)why;
 - (CKKSResultOperation*)requestSuccessfulFetchForManyReasons:(NSSet<CKKSFetchBecause*>*)why;
 
-// let server know we seen this push and if zones are ready actually perform a fetch
-- (CKKSResultOperation* _Nullable)requestFetchDueToAPNS:(CKRecordZoneNotification*)notification;
+// Returns the next fetch, if one is scheduled, or the last/currently executing fetch if not.
+- (CKKSResultOperation* _Nullable)inflightFetch;
+
+// CKKSZoneUpdateReceiverProtocol
+- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification;
 
 // We don't particularly care what this does, as long as it finishes
 - (void)holdFetchesUntil:(CKKSResultOperation* _Nullable)holdOperation;
index ead140b93cd73dbb211e5bcfab799d4932cc02da..3eced57aa2478fe1c4924cf4df321f27afc20e03 100644 (file)
@@ -104,6 +104,8 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
 @property bool newRequests; // true if there's someone pending on successfulFetchDependency
 @property CKKSZoneChangeFetchDependencyOperation* successfulFetchDependency;
 
+@property (nullable) CKKSZoneChangeFetchDependencyOperation* inflightFetchDependency;
+
 @property CKKSResultOperation* holdOperation;
 @end
 
@@ -127,11 +129,12 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
         _queue = dispatch_queue_create([_name UTF8String], DISPATCH_QUEUE_SERIAL_WITH_AUTORELEASE_POOL);
         _operationQueue = [[NSOperationQueue alloc] init];
         _successfulFetchDependency = [self createSuccesfulFetchDependency];
+        _inflightFetchDependency = nil;
 
         _newRequests = false;
 
-        // 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 initial delay, use 0.5 second. Otherwise, 2s.
+        dispatch_time_t initialDelay = (SecCKKSReduceRateLimiting() ? 500 * NSEC_PER_MSEC : 2 * 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);
@@ -185,6 +188,12 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     return [self requestSuccessfulFetchForManyReasons:[NSSet setWithObject:why]];
 }
 
+- (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification
+{
+    ckksnotice_global("ckkspush", "received a zone change notification for %@ %@", self, notification);
+    [self requestFetchDueToAPNS:notification];
+}
+
 - (CKKSResultOperation*)requestFetchDueToAPNS:(CKRecordZoneNotification*)notification
 {
     __block BOOL notReady = YES;
@@ -197,6 +206,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     for(id<CKKSChangeFetcherClient> client in clients) {
         if([client zoneIsReadyForFetching]) {
             notReady = NO;
+            break;
         }
     }
 
@@ -206,7 +216,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
             [self.apnsPushes addObject:notification];
             if(notification.ckksPushTracingEnabled) {
                 // Report that we saw this notification before doing anything else
-                secnotice("ckksfetch", "Submitting initial CKEventMetric due to notification %@", notification);
+                ckksnotice_global("ckksfetch", "Submitting initial CKEventMetric due to notification %@", notification);
 
                 CKEventMetric *metric = [[CKEventMetric alloc] initWithEventName:@"APNSPushMetrics"];
                 metric.isPushTriggerFired = true;
@@ -230,7 +240,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     });
 
     if (notReady) {
-        secnotice("ckksfetch", "Skipping fetching size no zone is ready");
+        ckksnotice_global("ckksfetch", "Skipping fetching size no zone is ready");
         return NULL;
     }
 
@@ -251,6 +261,23 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     return dependency;
 }
 
+- (CKKSResultOperation* _Nullable)inflightFetch
+{
+    __block CKKSResultOperation* dependency = nil;
+    dispatch_sync(self.queue, ^{
+
+        // If we'll have a new fetch in the future, return its status.
+        if(self.newRequests || self.inflightFetchDependency == nil) {
+            dependency = self.successfulFetchDependency;
+        } else {
+            // Otherwise, return the last triggered fetch
+            dependency = self.inflightFetchDependency;
+        }
+    });
+
+    return dependency;
+}
+
 -(void)maybeCreateNewFetchOnQueue {
     dispatch_assert_queue(self.queue);
     if(self.newRequests &&
@@ -272,12 +299,14 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     WEAKIFY(self);
 
     CKKSZoneChangeFetchDependencyOperation* dependency = self.successfulFetchDependency;
+    self.inflightFetchDependency = dependency;
+
     NSMutableSet<CKKSFetchBecause*>* lastFetchReasons = self.currentFetchReasons;
     self.currentFetchReasons = [[NSMutableSet alloc] init];
 
     NSString *reasonsString = [[lastFetchReasons sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES]]] componentsJoinedByString:@","];
 
-    secnotice("ckksfetcher", "Starting a new fetch, reasons: %@", reasonsString);
+    ckksnotice_global("ckksfetcher", "Starting a new fetch, reasons: %@", reasonsString);
 
     NSMutableSet<CKRecordZoneNotification*>* lastAPNSPushes = self.apnsPushes;
     self.apnsPushes = [[NSMutableSet alloc] init];
@@ -287,7 +316,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     NSArray<id<CKKSChangeFetcherClient>> *clients = [self clients];
 
     if(clients.count == 0u) {
-        secnotice("ckksfetcher", "No clients");
+        ckksnotice_global("ckksfetcher", "No clients");
         // Nothing to do, really.
     }
 
@@ -300,7 +329,7 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
                                                                                                                ckoperationGroup:operationGroup];
 
     if ([lastFetchReasons containsObject:CKKSFetchBecauseNetwork]) {
-        secnotice("ckksfetcher", "blocking fetch on network reachability");
+        ckksnotice_global("ckksfetcher", "blocking fetch on network reachability");
         [fetchAllChanges addNullableDependency: self.reachabilityTracker.reachabilityDependency]; // wait on network, if its unavailable
     }
     [fetchAllChanges addNullableDependency: self.holdOperation];
@@ -308,13 +337,13 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
     self.currentProcessResult = [CKKSResultOperation operationWithBlock: ^{
         STRONGIFY(self);
         if(!self) {
-            secerror("ckksfetcher: Received a null self pointer; strange.");
+            ckkserror_global("ckksfetcher", "Received a null self pointer; strange.");
             return;
         }
 
         bool attemptAnotherFetch = false;
         if(fetchAllChanges.error != nil) {
-            secerror("ckksfetcher: Interrogating clients about fetch error: %@", fetchAllChanges.error);
+            ckkserror_global("ckksfetcher", "Interrogating clients about fetch error: %@", fetchAllChanges.error);
 
             // Check in with clients: should we keep fetching for them?
             @synchronized(self.clientMap) {
@@ -345,17 +374,17 @@ CKKSFetchBecause* const CKKSFetchBecauseMoreComing = (CKKSFetchBecause*) @"more-
                 [self.operationQueue addOperation: dependency];
 
                 if(!attemptAnotherFetch) {
-                    secerror("ckksfetcher: All clients thought %@ is a fatal error. Not restarting fetch.", fetchAllChanges.error);
+                    ckkserror_global("ckksfetcher", "All clients thought %@ is a fatal error. Not restarting fetch.", fetchAllChanges.error);
                     return;
                 }
 
                 // And in a bit, try the fetch again.
                 NSTimeInterval delay = CKRetryAfterSecondsForError(fetchAllChanges.error);
                 if (delay) {
-                    secnotice("ckksfetcher", "Fetch failed with rate-limiting error, restarting in %.1f seconds: %@", delay, fetchAllChanges.error);
+                    ckksnotice_global("ckksfetcher", "Fetch failed with rate-limiting error, restarting in %.1f seconds: %@", delay, fetchAllChanges.error);
                     [self.fetchScheduler waitUntil:NSEC_PER_SEC * delay];
                 } else {
-                    secnotice("ckksfetcher", "Fetch failed with error, restarting soon: %@", fetchAllChanges.error);
+                    ckksnotice_global("ckksfetcher", "Fetch failed with error, restarting soon: %@", fetchAllChanges.error);
                 }
 
                 // Add the failed fetch reasons to the new fetch reasons
index 58905c26230cfd740fd373a535cab558f2a5902b..85dd700fbf7c33dc36d30c119dd45439e1958e6c 100644 (file)
@@ -8,7 +8,6 @@
 #import "keychain/ckks/CKKSReachabilityTracker.h"
 #import "keychain/ckks/CKKSZoneModifier.h"
 
-#import "utilities/debugging.h"
 #import "keychain/ot/ObjCImprovements.h"
 
 @implementation CKKSZoneModifyOperations
 
     if(!self.pendingOperations) {
         CKKSResultOperation* zoneModificationOperationDependency = [CKKSResultOperation named:@"zone-modification" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) {
-            secnotice("ckkszonemodifier", "finished creating zones");
+            ckksnotice_global("ckkszonemodifier", "finished creating zones");
         }];
 
         CKKSResultOperation* zoneSubscriptionOperationDependency = [CKKSResultOperation named:@"zone-subscription" withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) {
-            secnotice("ckkszonemodifier", "finished subscribing to zones");
+            ckksnotice_global("ckkszonemodifier", "finished subscribing to zones");
         }];
 
         self.pendingOperations = [[CKKSZoneModifyOperations alloc] initWithZoneModificationOperation:zoneModificationOperationDependency
 {
     dispatch_sync(self.queue, ^{
         if(self.halted) {
-            secnotice("ckkszonemodifier", "Halted; not launching operations");
+            ckksnotice_global("ckkszonemodifier", "Halted; not launching operations");
             return;
         }
 
         CKKSZoneModifyOperations* ops = self.pendingOperations;
         if(!ops) {
-            secinfo("ckkszonemodifier", "No pending zone modification operations; quitting");
+            ckksinfo_global("ckkszonemodifier", "No pending zone modification operations; quitting");
             return;
         }
 
         if(self.inflightOperations && (![self.inflightOperations.zoneModificationOperation isFinished] ||
                                        ![self.inflightOperations.zoneSubscriptionOperation isFinished])) {
-            secnotice("ckkszonemodifier", "Have in-flight zone modification operations, will retry later");
+            ckksnotice_global("ckkszonemodifier", "Have in-flight zone modification operations, will retry later");
 
             WEAKIFY(self);
             CKKSResultOperation* retrigger = [CKKSResultOperation named:@"retry" withBlock:^{
 
 - (CKDatabaseOperation<CKKSModifyRecordZonesOperation>*)createModifyZonesOperation:(CKKSZoneModifyOperations*)ops
 {
-    secnotice("ckkszonemodifier", "Attempting to create zones %@, delete zones %@", ops.zonesToCreate, ops.zoneIDsToDelete);
+    ckksnotice_global("ckkszonemodifier", "Attempting to create zones %@, delete zones %@", ops.zonesToCreate, ops.zoneIDsToDelete);
 
     CKDatabaseOperation<CKKSModifyRecordZonesOperation>* zoneModifyOperation = [[self.cloudKitClassDependencies.modifyRecordZonesOperationClass alloc] initWithRecordZonesToSave:ops.zonesToCreate recordZoneIDsToDelete:ops.zoneIDsToDelete];
     [zoneModifyOperation linearDependencies:self.ckOperations];
         STRONGIFY(self);
 
         if(operationError) {
-            secerror("ckkszonemodifier: Zone modification failed: %@", operationError);
+            ckkserror_global("ckkszonemodifier", "Zone modification failed: %@", operationError);
             [self inspectErrorForRetryAfter:operationError];
 
             if ([self.reachabilityTracker isNetworkError:operationError]){
                 self.networkFailure = true;
             }
         }
-        secnotice("ckkszonemodifier", "created zones: %@", savedRecordZones);
-        secnotice("ckkszonemodifier", "deleted zones: %@", deletedRecordZoneIDs);
+        ckksnotice_global("ckkszonemodifier", "created zones: %@", savedRecordZones);
+        ckksnotice_global("ckkszonemodifier", "deleted zones: %@", deletedRecordZoneIDs);
 
         ops.savedRecordZones = savedRecordZones;
         ops.deletedRecordZoneIDs = deletedRecordZoneIDs;
     };
 
     if(self.networkFailure) {
-        secnotice("ckkszonemodifier", "Waiting for reachabilty before issuing zone creation");
+        ckksnotice_global("ckkszonemodifier", "Waiting for reachabilty before issuing zone creation");
         [zoneModifyOperation addNullableDependency:self.reachabilityTracker.reachabilityDependency];
     }
 
 
 - (CKDatabaseOperation<CKKSModifySubscriptionsOperation>* _Nullable)createModifySubscriptionsOperation:(CKKSZoneModifyOperations*)ops
 {
-    secnotice("ckkszonemodifier", "Attempting to subscribe to zones %@", ops.subscriptionsToSubscribe);
+    ckksnotice_global("ckkszonemodifier", "Attempting to subscribe to zones %@", ops.subscriptionsToSubscribe);
 
     if(ops.subscriptionsToSubscribe.count == 0) {
         [self.operationQueue addOperation: ops.zoneSubscriptionOperation];
         STRONGIFY(self);
 
         if(operationError) {
-            secerror("ckkszonemodifier: Couldn't create cloudkit zone subscription; keychain syncing is severely degraded: %@", operationError);
+            ckkserror_global("ckkszonemodifier", "Couldn't create cloudkit zone subscription; keychain syncing is severely degraded: %@", operationError);
             [self inspectErrorForRetryAfter:operationError];
 
             if ([self.reachabilityTracker isNetworkError:operationError]){
                 self.networkFailure = true;
             }
         }
-        secnotice("ckkszonemodifier", "Successfully subscribed to %@", savedSubscriptions);
+        ckksnotice_global("ckkszonemodifier", "Successfully subscribed to %@", savedSubscriptions);
 
         ops.savedSubscriptions = savedSubscriptions;
         ops.deletedSubscriptionIDs = deletedSubscriptionIDs;
     [zoneSubscriptionOperation addNullableDependency:ops.zoneModificationOperation];
 
     if(self.networkFailure) {
-        secnotice("ckkszonemodifier", "Waiting for reachabilty before issuing zone subscription");
+        ckksnotice_global("ckkszonemodifier", "Waiting for reachabilty before issuing zone subscription");
         [zoneSubscriptionOperation addNullableDependency:self.reachabilityTracker.reachabilityDependency];
     }
 
     NSTimeInterval delay = CKRetryAfterSecondsForError(ckerror);
     if(delay) {
         uint64_t ns_delay = NSEC_PER_SEC * ((uint64_t) delay);
-        secnotice("ckkszonemodifier", "CK operation failed with rate-limit, scheduling delay for %.1f seconds: %@", delay, ckerror);
+        ckksnotice_global("ckkszonemodifier", "CK operation failed with rate-limit, scheduling delay for %.1f seconds: %@", delay, ckerror);
         [self.cloudkitRetryAfter waitUntil:ns_delay];
     }
 }
index 27213bcab00acf01d7879b5ddf894c4f27c1010a..f2c7a5b2102ec8e9a13659b10c29d487b3c9b9d8 100644 (file)
@@ -57,9 +57,11 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nullable) NSData* encodedChangeToken;
 @property BOOL moreRecordsInCloudKit;
 @property (nullable) NSDate* lastFetchTime;
+@property (nullable) NSDate* lastLocalKeychainScanTime;
 
 @property CKKSFixup lastFixup;
 
+
 @property (nullable) CKKSRateLimiter* rateLimiter;
 @property (nullable) NSData* encodedRateLimiter;
 
@@ -74,10 +76,11 @@ NS_ASSUME_NONNULL_BEGIN
                    changeToken:(NSData* _Nullable)changetoken
          moreRecordsInCloudKit:(BOOL)moreRecords
                      lastFetch:(NSDate* _Nullable)lastFetch
+                      lastScan:(NSDate* _Nullable)localKeychainScanned
                      lastFixup:(CKKSFixup)lastFixup
             encodedRateLimiter:(NSData* _Nullable)encodedRateLimiter;
 
-- (CKServerChangeToken*)getChangeToken;
+- (CKServerChangeToken* _Nullable)getChangeToken;
 - (void)setChangeToken:(CKServerChangeToken* _Nullable)token;
 
 - (BOOL)isEqual:(id)object;
index f835d9ab270017b9f52d65df166604d8efee6d43..0f15f257133cea1d9d5288ee5acc9e03f8461311 100644 (file)
@@ -48,6 +48,7 @@
                    changeToken:(NSData*)changetoken
          moreRecordsInCloudKit:(BOOL)moreRecords
                      lastFetch:(NSDate*)lastFetch
+                      lastScan:(NSDate* _Nullable)lastScan
                      lastFixup:(CKKSFixup)lastFixup
             encodedRateLimiter:(NSData*)encodedRateLimiter
 {
@@ -58,6 +59,7 @@
         _encodedChangeToken = changetoken;
         _moreRecordsInCloudKit = moreRecords;
         _lastFetchTime = lastFetch;
+        _lastLocalKeychainScanTime = lastScan;
         _lastFixup = lastFixup;
 
         self.encodedRateLimiter = encodedRateLimiter;
@@ -80,6 +82,7 @@
             ((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 &&
+            ((self.lastLocalKeychainScanTime == nil && obj.lastLocalKeychainScanTime == nil) || [self.lastLocalKeychainScanTime isEqualToDate: obj.lastLocalKeychainScanTime]) &&
             true) ? YES : NO;
 }
 
@@ -88,7 +91,7 @@
     CKKSZoneStateEntry* ret = [CKKSZoneStateEntry tryFromDatabase:ckzone error:&error];
 
     if(error) {
-        secerror("CKKS: error fetching CKState(%@): %@", ckzone, error);
+        ckkserror_global("ckks", "error fetching CKState(%@): %@", ckzone, error);
     }
 
     if(!ret) {
                                              changeToken:nil
                                    moreRecordsInCloudKit:NO
                                                lastFetch:nil
+                                                lastScan:nil
                                                lastFixup:CKKSCurrentFixupNumber
                                       encodedRateLimiter:nil];
     }
     return ret;
 }
 
-- (CKServerChangeToken*) getChangeToken {
+- (CKServerChangeToken* _Nullable) getChangeToken {
     if(self.encodedChangeToken) {
         NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.encodedChangeToken error:nil];
         return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey];
 }
 
 + (NSArray<NSString*>*) sqlColumns {
-    return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup", @"morecoming"];
+    // Note that 'extra' is not currently used, but the schema supports adding a protobuf or other serialized data
+    return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup", @"morecoming", @"lastscan", @"extra"];
 }
 
 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
 - (NSDictionary<NSString*,id>*) 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),
-         @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]),
-             @"lastFixup": [NSNumber numberWithLong:self.lastFixup],
-             @"morecoming": [NSNumber numberWithBool:self.moreRecordsInCloudKit],
-             };
+    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),
+        @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]),
+        @"lastFixup": [NSNumber numberWithLong:self.lastFixup],
+        @"morecoming": [NSNumber numberWithBool:self.moreRecordsInCloudKit],
+        @"lastscan": CKKSNilToNSNull(self.lastLocalKeychainScanTime ? [dateFormat stringFromDate:self.lastLocalKeychainScanTime] : nil),
+    };
 }
 
 + (instancetype)fromDatabaseRow:(NSDictionary<NSString*, CKKSSQLResult*>*)row {
                                           changeToken:row[@"changetoken"].asBase64DecodedData
                                 moreRecordsInCloudKit:row[@"morecoming"].asBOOL
                                             lastFetch:row[@"lastfetch"].asISO8601Date
+                                             lastScan:row[@"lastscan"].asISO8601Date
                                             lastFixup:(CKKSFixup)row[@"lastFixup"].asNSInteger
                                    encodedRateLimiter:row[@"ratelimiter"].asBase64DecodedData
             ];
index 50bb89046dd700f15e69e35b7a6096e03eed3943..896b27adabcb5c63991418678a1cd071e917688e 100644 (file)
@@ -83,7 +83,7 @@
 
             if([cuttlefishError.domain isEqualToString:CuttlefishErrorDomain]) {
                 NSNumber* val = cuttlefishError.userInfo[CuttlefishErrorRetryAfterKey];
-                if (val) {
+                if (val != nil) {
                     return (NSTimeInterval)val.doubleValue;
                 }
             }
index ae9ad1c3dfa9f56e431c26e76432e19eede540b0..15c4b9015ba4ea7ffcd89422ceeec792f5e1035e 100644 (file)
@@ -103,6 +103,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property (nonatomic, copy) NSString *operationID;
 @property (nonatomic, readonly, strong, nullable) CKOperationConfiguration *resolvedConfiguration;
+
+@property (nonatomic, strong) NSString *deviceIdentifier;
 @end
 
 @interface CKFetchRecordZoneChangesOperation () <CKKSFetchRecordZoneChangesOperation>
@@ -151,13 +153,15 @@ NS_ASSUME_NONNULL_BEGIN
 
 /* APSConnection */
 @protocol OctagonAPSConnection <NSObject>
+@property NSArray<NSString*>* enabledTopics;
+@property NSArray<NSString*>* opportunisticTopics;
+@property NSArray<NSString*>* darkWakeTopics;
+
 + (instancetype)alloc;
 - (id)initWithEnvironmentName:(NSString*)environmentName
             namedDelegatePort:(NSString*)namedDelegatePort
                         queue:(dispatch_queue_t)queue;
 
-- (void)setEnabledTopics:(NSArray<NSString *> *)enabledTopics;
-- (void)setDarkWakeTopics:(NSArray<NSString *> *)darkWakeTopics;
 
 @property (nonatomic, readwrite, assign) id<APSConnectionDelegate> delegate;
 @end
index b9ea9410afc597d179506f1c176b46a727e6905d..5867d70019477edada6d00cdd0cd8eee502540aa 100644 (file)
@@ -22,9 +22,9 @@
  */
 
 #import <Foundation/Foundation.h>
+#import "keychain/ckks/CKKS.h"
 #import "keychain/ckks/NSOperationCategories.h"
 #import "keychain/ot/ObjCImprovements.h"
-#import "utilities/debugging.h"
 
 @implementation NSOperation (CKKSUsefulPrintingOperation)
 - (NSString*)selfname {
@@ -43,7 +43,7 @@
                 continue;
             }
 #if DEBUG
-            secnotice("ckks-operation", "adding dependency of %@ on %@", self, existingop);
+            ckksnotice_global("ckks-operation", "adding dependency of %@ on %@", self.name, existingop);
 #endif
             [self addDependency: existingop];
         }
index 98b8920c1eeeb562e1df24a7003ae796268b83a3..a5c22a02641cced4dd0603df0418e83bd35e6bc4 100644 (file)
@@ -39,7 +39,7 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, strong, nullable) NSDate* ckksPushReceivedDate;
 @end
 
-@protocol CKKSZoneUpdateReceiver <NSObject>
+@protocol CKKSZoneUpdateReceiverProtocol <NSObject>
 - (void)notifyZoneChange:(CKRecordZoneNotification* _Nullable)notification;
 @end
 
@@ -55,28 +55,32 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property (readonly) BOOL haveStalePushes;
 
-+ (instancetype)receiverForEnvironment:(NSString*)environmentName
-                     namedDelegatePort:(NSString*)namedDelegatePort
-                    apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass;
++ (instancetype)receiverForNamedDelegatePort:(NSString*)namedDelegatePort
+                          apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass;
++ (void)resetGlobalDelegatePortMap;
 
-- (CKKSCondition*)registerReceiver:(id<CKKSZoneUpdateReceiver>)receiver forZoneID:(CKRecordZoneID*)zoneID;
+- (void)registerForEnvironment:(NSString*)environmentName;
+
+- (CKKSCondition*)registerCKKSReceiver:(id<CKKSZoneUpdateReceiverProtocol>)receiver;
+
+// APS reserves the right to coalesce pushes by topic. So, any cuttlefish container push might hide pushes for other cuttlefish containers.
+// This is okay for now, as we only have one active cuttlefish container per device, but if we start to have multiple accounts, this handling might need to change.
 - (CKKSCondition*)registerCuttlefishReceiver:(id<OctagonCuttlefishUpdateReceiver>)receiver forContainerName:(NSString*)containerName;
 
 // Test support:
-- (instancetype)initWithEnvironmentName:(NSString*)environmentName
-                      namedDelegatePort:(NSString*)namedDelegatePort
+- (instancetype)initWithNamedDelegatePort:(NSString*)namedDelegatePort
                      apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass;
-- (instancetype)initWithEnvironmentName:(NSString*)environmentName
-                      namedDelegatePort:(NSString*)namedDelegatePort
+- (instancetype)initWithNamedDelegatePort:(NSString*)namedDelegatePort
                      apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
                        stalePushTimeout:(uint64_t)stalePushTimeout;
+
 // This is the queue that APNS will use send the notifications to us
 + (dispatch_queue_t)apsDeliveryQueue;
+- (NSArray<NSString *>*)registeredPushEnvironments;
 @end
 
 @interface OctagonAPSReceiver (Testing)
-+ (void)resetGlobalEnviornmentMap;
-- (void)reportDroppedPushes:(NSDictionary<NSString*, NSMutableSet<CKRecordZoneNotification*>*>*)notifications;
+- (void)reportDroppedPushes:(NSSet<CKRecordZoneNotification*>*)notifications;
 @end
 
 NS_ASSUME_NONNULL_END
index e8eeb4f7df38281cc84354ae6662910c15e32630..682ef868fecd97f1ccefd74d0d2380611205239c 100644 (file)
@@ -33,7 +33,6 @@
 #import "keychain/ot/ObjCImprovements.h"
 #import <CloudKit/CloudKit_Private.h>
 #include <utilities/SecAKSWrappers.h>
-#include <utilities/debugging.h>
 
 @implementation CKRecordZoneNotification (CKKSPushTracing)
 - (void)setCkksPushTracingEnabled:(BOOL)ckksPushTracingEnabled {
 
 @property CKKSNearFutureScheduler *clearStalePushNotifications;
 
+@property NSString* namedDelegatePort;
+@property NSMutableDictionary<NSString*, id<OctagonAPSConnection>>* environmentMap;
+
+
 // If we receive notifications for a record zone that hasn't been registered yet, send them a their updates when they register
-@property NSMutableDictionary<NSString*, NSMutableSet<CKRecordZoneNotification*>*>* undeliveredUpdates;
+@property NSMutableSet<CKRecordZoneNotification*>* undeliveredUpdates;
 
 // Same, but for cuttlefish containers (and only remember that a push was received; don't remember the pushes themselves)
 @property NSMutableSet<NSString*>* undeliveredCuttlefishUpdates;
 
-@property NSMapTable<NSString*, id<CKKSZoneUpdateReceiver>>* zoneMap;
+@property (nullable) id<CKKSZoneUpdateReceiverProtocol> zoneUpdateReceiver;
 @property NSMapTable<NSString*, id<OctagonCuttlefishUpdateReceiver>>* octagonContainerMap;
 @end
 
 @implementation OctagonAPSReceiver
 
-+ (instancetype)receiverForEnvironment:(NSString *)environmentName
-                     namedDelegatePort:(NSString*)namedDelegatePort
-                    apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
++ (instancetype)receiverForNamedDelegatePort:(NSString*)namedDelegatePort
+                          apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
 {
-    if(environmentName == nil) {
-        secnotice("octagonpush", "No push environment; not bringing up APS.");
-        return nil;
-    }
-
     @synchronized([self class]) {
-        NSMutableDictionary<NSString*, OctagonAPSReceiver*>* environmentMap = [self synchronizedGlobalEnvironmentMap];
+        NSMutableDictionary<NSString*, OctagonAPSReceiver*>* delegatePortMap = [self synchronizedGlobalDelegatePortMap];
 
-        OctagonAPSReceiver* recv = [environmentMap valueForKey: environmentName];
+        OctagonAPSReceiver* recv = delegatePortMap[namedDelegatePort];
 
         if(recv == nil) {
-            recv = [[OctagonAPSReceiver alloc] initWithEnvironmentName: environmentName namedDelegatePort:namedDelegatePort apsConnectionClass: apsConnectionClass];
-            [environmentMap setValue: recv forKey: environmentName];
+            recv = [[OctagonAPSReceiver alloc] initWithNamedDelegatePort:namedDelegatePort
+                                                      apsConnectionClass:apsConnectionClass];
+            delegatePortMap[namedDelegatePort] = recv;
         }
 
         return recv;
     }
 }
 
-+ (void)resetGlobalEnviornmentMap
++ (void)resetGlobalDelegatePortMap
 {
     @synchronized (self) {
-        [self resettableSynchronizedGlobalEnvironmentMap:YES];
+        [self resettableSynchronizedGlobalDelegatePortMap:YES];
     }
 }
 
-+ (NSMutableDictionary<NSString*, OctagonAPSReceiver*>*)synchronizedGlobalEnvironmentMap
++ (NSMutableDictionary<NSString*, OctagonAPSReceiver*>*)synchronizedGlobalDelegatePortMap
 {
-    return [self resettableSynchronizedGlobalEnvironmentMap:NO];
+    return [self resettableSynchronizedGlobalDelegatePortMap:NO];
 }
 
-+ (NSMutableDictionary<NSString*, OctagonAPSReceiver*>*)resettableSynchronizedGlobalEnvironmentMap:(BOOL)reset
++ (NSMutableDictionary<NSString*, OctagonAPSReceiver*>*)resettableSynchronizedGlobalDelegatePortMap:(BOOL)reset
 {
-    static NSMutableDictionary<NSString*, OctagonAPSReceiver*>* environmentMap = nil;
+    static NSMutableDictionary<NSString*, OctagonAPSReceiver*>* delegatePortMap = nil;
 
-    if(environmentMap == nil || reset) {
-        environmentMap = [[NSMutableDictionary alloc] init];
+    if(delegatePortMap == nil || reset) {
+        delegatePortMap = [[NSMutableDictionary alloc] init];
     }
 
-    return environmentMap;
+    return delegatePortMap;
+}
+
+- (NSArray<NSString *>*)registeredPushEnvironments
+{
+    __block NSArray<NSString*>* environments = nil;
+    dispatch_sync([OctagonAPSReceiver apsDeliveryQueue], ^{
+        environments = [self.environmentMap allKeys];
+    });
+    return environments;
 }
 
 + (dispatch_queue_t)apsDeliveryQueue {
     return haveStalePushes;
 }
 
-- (NSSet<NSString*>*)cuttlefishPushTopics
+- (NSArray<NSString*>*)cuttlefishPushTopics
 {
     NSString* cuttlefishTopic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.security.cuttlefish"];
 
     // Currently cuttlefish pushes are sent to TPH. System XPC services can't properly register to be woken
     // at push time, so receive them for it.
     NSString* tphTopic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.TrustedPeersHelper"];
-    NSString* securitydTopic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.securityd"];
 
-    return [NSSet setWithArray:@[cuttlefishTopic, tphTopic, securitydTopic]];
+    return @[cuttlefishTopic, tphTopic];
 }
 
-- (instancetype)initWithEnvironmentName:(NSString*)environmentName
-                      namedDelegatePort:(NSString*)namedDelegatePort
-                     apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
+- (instancetype)initWithNamedDelegatePort:(NSString*)namedDelegatePort
+                       apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
 {
-    return [self initWithEnvironmentName:environmentName
-                       namedDelegatePort:namedDelegatePort
-                      apsConnectionClass:apsConnectionClass
-                        stalePushTimeout:5*60*NSEC_PER_SEC];
+    return [self initWithNamedDelegatePort:namedDelegatePort
+                        apsConnectionClass:apsConnectionClass
+                          stalePushTimeout:5*60*NSEC_PER_SEC];
 }
 
-- (instancetype)initWithEnvironmentName:(NSString*)environmentName
-                      namedDelegatePort:(NSString*)namedDelegatePort
-                     apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
-                       stalePushTimeout:(uint64_t)stalePushTimeout
+- (instancetype)initWithNamedDelegatePort:(NSString*)namedDelegatePort
+                       apsConnectionClass:(Class<OctagonAPSConnection>)apsConnectionClass
+                         stalePushTimeout:(uint64_t)stalePushTimeout
 {
-    if(self = [super init]) {
+    if((self = [super init])) {
         _apsConnectionClass = apsConnectionClass;
-        _apsConnection = NULL;
 
-        _undeliveredUpdates = [NSMutableDictionary dictionary];
+        _undeliveredUpdates = [NSMutableSet set];
         _undeliveredCuttlefishUpdates = [[NSMutableSet alloc] init];
 
-        // APS might be slow. This doesn't need to happen immediately, so let it happen later.
-        WEAKIFY(self);
-        dispatch_async([OctagonAPSReceiver apsDeliveryQueue], ^{
-            STRONGIFY(self);
-            if(!self) {
-                return;
-            }
-            self.apsConnection = [[self.apsConnectionClass alloc] initWithEnvironmentName:environmentName namedDelegatePort:namedDelegatePort queue:[OctagonAPSReceiver apsDeliveryQueue]];
-            self.apsConnection.delegate = self;
+        _namedDelegatePort = namedDelegatePort;
 
-            // The following string should match: [[NSBundle mainBundle] bundleIdentifier]
-            NSString* ckksTopic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.securityd"];
+        _environmentMap = [NSMutableDictionary dictionary];
 
-            NSArray* topics = [@[ckksTopic] arrayByAddingObjectsFromArray:[self cuttlefishPushTopics].allObjects];
-            [self.apsConnection setEnabledTopics:topics];
-#if TARGET_OS_OSX
-            [self.apsConnection setDarkWakeTopics:topics];
-#endif
-        });
-
-        _zoneMap = [NSMapTable strongToWeakObjectsMapTable];
         _octagonContainerMap = [NSMapTable strongToWeakObjectsMapTable];
+        _zoneUpdateReceiver = nil;
 
+        WEAKIFY(self);
         void (^clearPushBlock)(void) = ^{
             dispatch_async([OctagonAPSReceiver apsDeliveryQueue], ^{
-                NSDictionary<NSString*, NSMutableSet<CKRecordZoneNotification*>*> *droppedUpdates;
+                NSMutableSet<CKRecordZoneNotification*> *droppedUpdates;
                 STRONGIFY(self);
                 if (self == nil) {
                     return;
 
                 droppedUpdates = self.undeliveredUpdates;
 
-                self.undeliveredUpdates = [NSMutableDictionary dictionary];
+                self.undeliveredUpdates = [NSMutableSet set];
                 [self.undeliveredCuttlefishUpdates removeAllObjects];
 
                 [self reportDroppedPushes:droppedUpdates];
     return self;
 }
 
+- (void)registerForEnvironment:(NSString*)environmentName
+{
+    WEAKIFY(self);
+
+    // APS might be slow. This doesn't need to happen immediately, so let it happen later.
+    dispatch_async([OctagonAPSReceiver apsDeliveryQueue], ^{
+        STRONGIFY(self);
+        if(!self) {
+            return;
+        }
+
+        id<OctagonAPSConnection> apsConnection = self.environmentMap[environmentName];
+        if(apsConnection) {
+            // We've already set one of these up.
+            return;
+        }
+
+        apsConnection = [[self.apsConnectionClass alloc] initWithEnvironmentName:environmentName namedDelegatePort:self.namedDelegatePort queue:[OctagonAPSReceiver apsDeliveryQueue]];
+        self.environmentMap[environmentName] = apsConnection;
+
+        apsConnection.delegate = self;
+
+        // The following string should match: [[NSBundle mainBundle] bundleIdentifier]
+        NSString* ckksTopic = [kCKPushTopicPrefix stringByAppendingString:@"com.apple.securityd"];
+
+#if TARGET_OS_WATCH
+        // Watches treat CKKS as opportunistic, and Octagon as normal priority.
+        apsConnection.enabledTopics = [self cuttlefishPushTopics];
+        apsConnection.opportunisticTopics = @[ckksTopic];
+#else
+        apsConnection.enabledTopics = [[self cuttlefishPushTopics] arrayByAddingObject:ckksTopic];
+#if TARGET_OS_OSX
+        apsConnection.darkWakeTopics = self.apsConnection.enabledTopics;
+#endif // TARGET_OS_OSX
+
+#endif // TARGET_OS_WATCH
+    });
+}
+
 // Report that pushes we are dropping
-- (void)reportDroppedPushes:(NSDictionary<NSString*, NSMutableSet<CKRecordZoneNotification*>*>*)notifications
+- (void)reportDroppedPushes:(NSSet<CKRecordZoneNotification*>*)notifications
 {
     bool hasBeenUnlocked = false;
     CFErrorRef error = NULL;
         eventName = @"CKKS APNS Push Dropped - never unlocked";
     }
 
-    for (NSString *zone in notifications) {
-        for (CKRecordZoneNotification *notification in notifications[zone]) {
-            if (notification.ckksPushTracingEnabled) {
-                secnotice("apsnotification", "Submitting initial CKEventMetric due to notification %@", notification);
+    for (CKRecordZoneNotification *notification in notifications) {
+        if (notification.ckksPushTracingEnabled) {
+            ckksnotice_global("apsnotification", "Submitting initial CKEventMetric due to notification %@", notification);
 
-                SecEventMetric *metric = [[SecEventMetric alloc] initWithEventName:@"APNSPushMetrics"];
-                metric[@"push_token_uuid"] = notification.ckksPushTracingUUID;
-                metric[@"push_received_date"] = notification.ckksPushReceivedDate;
+            SecEventMetric *metric = [[SecEventMetric alloc] initWithEventName:@"APNSPushMetrics"];
+            metric[@"push_token_uuid"] = notification.ckksPushTracingUUID;
+            metric[@"push_received_date"] = notification.ckksPushReceivedDate;
 
-                metric[@"push_event_name"] = eventName;
+            metric[@"push_event_name"] = eventName;
 
-                [[SecMetrics managerObject] submitEvent:metric];
-            }
+            [[SecMetrics managerObject] submitEvent:metric];
         }
     }
 }
 
-
-
-- (CKKSCondition*)registerReceiver:(id<CKKSZoneUpdateReceiver>)receiver forZoneID:(CKRecordZoneID *)zoneID {
+- (CKKSCondition*)registerCKKSReceiver:(id<CKKSZoneUpdateReceiverProtocol>)receiver
+{
     CKKSCondition* finished = [[CKKSCondition alloc] init];
 
     WEAKIFY(self);
     dispatch_async([OctagonAPSReceiver apsDeliveryQueue], ^{
         STRONGIFY(self);
         if(!self) {
-            secerror("ckks: received registration for released OctagonAPSReceiver");
+            ckkserror_global("octagonpush", "received registration for released OctagonAPSReceiver");
             return;
         }
 
-        [self.zoneMap setObject:receiver forKey: zoneID.zoneName];
+        ckksnotice_global("octagonpush", "Registering new CKKS push receiver: %@", receiver);
+
+        self.zoneUpdateReceiver = receiver;
 
-        NSMutableSet<CKRecordZoneNotification*>* currentPendingMessages = self.undeliveredUpdates[zoneID.zoneName];
-        [self.undeliveredUpdates removeObjectForKey:zoneID.zoneName];
+        NSMutableSet<CKRecordZoneNotification*>* currentPendingMessages = [self.undeliveredUpdates copy];
+        [self.undeliveredUpdates removeAllObjects];
 
         for(CKRecordZoneNotification* message in currentPendingMessages.allObjects) {
             // Now, send the receiver its notification!
-            secerror("ckks: sending stored push(%@) to newly-registered zone(%@): %@", message, zoneID.zoneName, receiver);
+            ckkserror_global("octagonpush", "sending stored push(%@) to newly-registered receiver: %@", message, receiver);
             [receiver notifyZoneChange:message];
         }
 
     dispatch_async([OctagonAPSReceiver apsDeliveryQueue], ^{
         STRONGIFY(self);
         if(!self) {
-            secerror("octagon: received registration for released OctagonAPSReceiver");
+            ckkserror_global("octagonpush", "received registration for released OctagonAPSReceiver");
             return;
         }
 
             [self.undeliveredCuttlefishUpdates removeObject:containerName];
 
             // Now, send the receiver its fake notification!
-            secerror("octagon: sending fake push to newly-registered cuttlefish receiver(%@): %@", containerName, receiver);
+            ckkserror_global("octagonpush", "sending fake push to newly-registered cuttlefish receiver(%@): %@", containerName, receiver);
             [receiver notifyContainerChange:nil];
         }
 
 
 - (void)connection:(APSConnection *)connection didReceivePublicToken:(NSData *)publicToken {
     // no-op.
-    secnotice("octagonpush", "OctagonAPSDelegate initiated: %@", connection);
+    ckksnotice_global("octagonpush", "OctagonAPSDelegate initiated: %@", connection);
 }
 
 - (void)connection:(APSConnection *)connection didReceiveToken:(NSData *)token forTopic:(NSString *)topic identifier:(NSString *)identifier {
-    secnotice("octagonpush", "Received per-topic push token \"%@\" for topic \"%@\" identifier \"%@\" on connection %@", token, topic, identifier, connection);
+    ckksnotice_global("octagonpush", "Received per-topic push token \"%@\" for topic \"%@\" identifier \"%@\" on connection %@", token, topic, identifier, connection);
 }
 
 - (void)connection:(APSConnection *)connection didReceiveIncomingMessage:(APSIncomingMessage *)message {
-    secnotice("octagonpush", "OctagonAPSDelegate received a message(%@): %@ ", message.topic, message.userInfo);
+    ckksnotice_global("octagonpush", "OctagonAPSDelegate received a message(%@): %@ ", message.topic, message.userInfo);
 
     // Report back through APS that we received a message
     if(message.tracingEnabled) {
         [connection confirmReceiptForMessage:message];
     }
 
-    NSSet<NSString*>* cuttlefishTopics = [self cuttlefishPushTopics];
-
     // Separate and handle cuttlefish notifications
-    if([cuttlefishTopics containsObject:message.topic] && [message.userInfo objectForKey:@"cf"]) {
+    if(message.userInfo[@"cf"] != nil) {
         NSDictionary* cfInfo = message.userInfo[@"cf"];
         NSString* container = cfInfo[@"c"];
 
-        secnotice("octagonpush", "Received a cuttlefish push to container %@", container);
+        ckksnotice_global("octagonpush", "Received a cuttlefish push to container %@", container);
         [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastOctagonPush];
 
         if(container) {
             if(receiver) {
                 [receiver notifyContainerChange:message];
             } else {
-                secerror("octagonpush: received cuttlefish push for unregistered container: %@", container);
+                ckkserror_global("octagonpush", "received cuttlefish push for unregistered container: %@", container);
                 [self.undeliveredCuttlefishUpdates addObject:container];
                 [self.clearStalePushNotifications trigger];
             }
         [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:CKKSAnalyticsLastCKKSPush];
 
         // Find receiever in map
-        id<CKKSZoneUpdateReceiver> recv = [self.zoneMap objectForKey:rznotification.recordZoneID.zoneName];
+        id<CKKSZoneUpdateReceiverProtocol> recv = self.zoneUpdateReceiver;
         if(recv) {
             [recv notifyZoneChange:rznotification];
         } else {
-            secerror("ckks: received push for unregistered zone: %@", rznotification);
-            if(rznotification.recordZoneID) {
-                NSMutableSet<CKRecordZoneNotification*>* currentPendingMessages = self.undeliveredUpdates[rznotification.recordZoneID.zoneName];
-                if(currentPendingMessages) {
-                    [currentPendingMessages addObject:rznotification];
-                } else {
-                    self.undeliveredUpdates[rznotification.recordZoneID.zoneName] = [NSMutableSet setWithObject:rznotification];
-                    [self.clearStalePushNotifications trigger];
-                }
-            }
+            ckkserror_global("ckkspush", "received push for unregistered receiver: %@", rznotification);
+            [self.undeliveredUpdates addObject:rznotification];
+            [self.clearStalePushNotifications trigger];
         }
     } else {
-        secerror("ckks: unexpected notification: %@", notification);
+        ckkserror_global("ckkspush", "unexpected notification: %@", notification);
     }
 }
 
index 1dd8432055c66c5051de1a700d4da974f45c5d0e..ed7fb034eddb29c4d6ec37c4a3f13f50cab239d5 100644 (file)
@@ -22,8 +22,8 @@
  */
 
 #import "RateLimiter.h"
-#import <utilities/debugging.h>
 #import "sec_action.h"
+#import "keychain/ckks/CKKS.h"
 #import <CoreFoundation/CFPreferences.h>   // For clarity. Also included in debugging.h
 
 @interface RateLimiter()
@@ -37,8 +37,7 @@
 @implementation RateLimiter
 
 - (instancetype)initWithConfig:(NSDictionary *)config {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _config = config;
         _assetType = nil;
         [self reset];
@@ -50,8 +49,7 @@
     if (!coder) {
         return nil;
     }
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _groups = [coder decodeObjectOfClasses:[NSSet setWithObjects: [NSArray class],
                                                                       [NSMutableDictionary class],
                                                                       [NSString class],
@@ -87,7 +85,7 @@
         dispatch_once(&token, ^{
             action = sec_action_create("ratelimiterdisabledlogevent", 60);
             sec_action_set_handler(action, ^{
-                secnotice("ratelimit", "Rate limiting disabled, returning automatic all-clear");
+                ckksnotice_global("ratelimit", "Rate limiting disabled, returning automatic all-clear");
           });
         });
         sec_action_perform(action);
         // approved properties 'accessGroup' and 'uuid' and if the item doesn't have either it's sad times anyway.
         // <rdar://problem/33434425> Improve rate limiter error handling
         if (!name) {
-            secerror("RateLimiter[%@]: Got nil instead of property named %@", self.config[@"general"][@"name"], groupConfig[@"property"]);
+            ckkserror_global("ratelimiter", "RateLimiter[%@]: Got nil instead of property named %@", self.config[@"general"][@"name"], groupConfig[@"property"]);
             continue;
         }
         NSDate *singleTokenTime = [self consumeTokenFromBucket:self.groups[idx]
     if ([self stateSize] > [self.config[@"general"][@"maxStateSize"] unsignedIntegerValue]) {
         // Trimming did not reduce size (enough), we need to take measures
         self.overloadUntil = [time dateByAddingTimeInterval:[self.config[@"general"][@"overloadDuration"] unsignedIntValue]];
-        secerror("RateLimiter[%@] state size %lu exceeds max %lu, overloaded until %@",
+        ckkserror_global("ratelimiter", "RateLimiter[%@] state size %lu exceeds max %lu, overloaded until %@",
                  self.config[@"general"][@"name"],
                  (unsigned long)[self stateSize],
                  [self.config[@"general"][@"maxStateSize"] unsignedLongValue],
index 796ef505f37e7ba54346bdb8153190ca840d88ba..81fb47f4e31407c838e8cbbb9668239f25354fa3 100644 (file)
@@ -41,8 +41,7 @@ read_releases_pending(int fd, void (^handler)(ssize_t))
 
         char *line = NULL;
         size_t linecap = 0;
-        ssize_t linelen;
-        while ((linelen = getline(&line, &linecap, fp)) > 0) {
+        while (getline(&line, &linecap, fp) > 0) {
             ssize_t pending;
 
             if (sscanf(line, "objc[%*d]: %ld releases pending", &pending) == 1) {
index 1dc7249fe82354aab72a030c684f85a4c7cff9ae..5c395edc5a259a226fbc075bdd649e17b9b9a25c 100644 (file)
     NSData* testCKRecord = [@"nonsense" dataUsingEncoding:NSUTF8StringEncoding];
     CKKSKey* tlk =  [self fakeTLK:self.testZoneID];
 
-    [tlk saveToDatabase:&error];
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [tlk saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "tlk saved to database without error");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
     [tlk saveKeyMaterialToKeychain:&error];
     XCTAssertNil(error, "tlk saved to database without error");
 
     XCTAssertNotNil(level1, "level 1 key created");
     XCTAssertNil(error, "level 1 key created");
 
-    [level1 saveToDatabase:&error];
-    XCTAssertNil(error, "level 1 key saved to database without error");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [level1 saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "level 1 key saved to database without error");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSKey* level2 = [CKKSKey randomKeyWrappedByParent: level1 error:&error];
     level2.encodedCKRecord = testCKRecord;
     XCTAssertNotNil(level2, "level 2 key created");
     XCTAssertNil(error, "no error creating level 2 key");
-    [level2 saveToDatabase:&error];
-    XCTAssertNil(error, "level 2 key saved to database without error");
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [level2 saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "level 2 key saved to database without error");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     NSString* level2UUID = level2.uuid;
 
 
 - (void)ensureKeychainSaveLoad: (CKKSKey*) key {
     NSError* error = nil;
-    [key saveToDatabase:&error];
-    XCTAssertNil(error, "no error saving to database");
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [key saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
     [key saveKeyMaterialToKeychain:&error];
     XCTAssertNil(error, "no error saving to keychain");
 
     NSString *uuid = @"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7";
 
     CKKSKey* key = [self fakeTLK:self.testZoneID];
-    [key saveToDatabase: &error];
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [key saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
     [key saveKeyMaterialToKeychain:&error];
     XCTAssertNil(error, @"could save the fake TLK to the database");
 
                                                                error:&error];
     XCTAssertNil(error);
     CKKSKey* key = [self fakeTLK:self.testZoneID];
-    [key saveToDatabase: &error];
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [key saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "could save the fake TLK to the database");
+        return CKKSDatabaseTransactionCommit;
+    }];
     [key saveKeyMaterialToKeychain:&error];
-    XCTAssertNil(error, @"could save the fake TLK to the database");
+    XCTAssertNil(error, @"could save the fake TLK to the keychain");
 
     CKKSAESSIVKey* keyToWrap = [[CKKSAESSIVKey alloc] initWithBase64: @"uImdbZ7Zg+6WJXScTnRBfNmoU1UiMkSYxWc+d1Vuq3IFn2RmTRkTdWTe3HmeWo1pAomqy+upK8KHg2PGiRGhqg=="];
     CKKSWrappedAESSIVKey* wrappedKey = [key wrapAESKey: keyToWrap error:&error];
        memset((unsigned char *)[data mutableBytes], 0x55, 23);
        NSData *padded = [CKKSItemEncrypter padData:data blockSize:0 additionalBlock:extra];
        XCTAssertNotNil(padded, "Padding never returns nil");
-    XCTAssertTrue(padded.length == data.length + extra ? 2 : 1, "One byte of padding has been added, 2 if extra padding");
+    XCTAssertTrue(padded.length == data.length + (extra ? 2 : 1), "One byte of padding has been added, 2 if extra padding");
        NSData *unpadded = [CKKSItemEncrypter removePaddingFromData:padded];
        XCTAssertNotNil(unpadded, "Successfully removed padding again");
        XCTAssertEqualObjects(data, unpadded, "Data effectively unmodified through padding-unpadding trip");
index 4aa357acaaf2b1037637623999503c40a8a8438b..3a5e8077e18808a8cb46ea23a4f75d45ccff4226 100644 (file)
 
     // Inject a message at the APS layer
     // Because we can only make APS receivers once iCloud tells us the push environment after sign-in, we can't use our normal injection strategy, and fell back on global state.
-    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForEnvironment:self.apsEnvironment
-                                                         namedDelegatePort:SecCKKSAPSNamedPort
-                                                        apsConnectionClass:[FakeAPSConnection class]];
+    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                    apsConnectionClass:[FakeAPSConnection class]];
     XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver");
 
     // Also, CKKS should handle this in one single fetch
 
     // Inject a message at the APS layer
     // Because we can only make APS receivers once iCloud tells us the push environment after sign-in, we can't use our normal injection strategy, and fell back on global state.
-    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForEnvironment:self.apsEnvironment
-                                                         namedDelegatePort:SecCKKSAPSNamedPort
-                                                        apsConnectionClass:[FakeAPSConnection class]];
+    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                    apsConnectionClass:[FakeAPSConnection class]];
     XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver");
 
     // Also, CKKS should handle this in one single fetch
     // Launch!
     [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage];
     OCMVerifyAllWithDelay(self.mockContainerExpectations, 16);
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Now, wait for both views to run their processing
     [keychainProcessTimeoutOp waitUntilFinished];
 
     // Inject a message at the APS layer
     // Because we can only make APS receivers once iCloud tells us the push environment after sign-in, we can't use our normal injection strategy, and fell back on global state.
-    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForEnvironment:self.apsEnvironment
-                                                               namedDelegatePort:SecCKKSAPSNamedPort
-                                                              apsConnectionClass:[FakeAPSConnection class]];
+    OctagonAPSReceiver* apsReceiver = [OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                    apsConnectionClass:[FakeAPSConnection class]];
     XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver");
 
-    [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage];
-    [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage2];
-
     // Expect four metric pushes, two per push: one from receiving the push and one from after we finish the fetch
     // AFAICT there's no way to introspect a metric object to ensure we did it right
     OCMExpect([self.mockContainerExpectations submitEventMetric:[OCMArg any]]);
     OCMExpect([self.mockContainerExpectations submitEventMetric:[OCMArg any]]);
     OCMExpect([self.mockContainerExpectations submitEventMetric:[OCMArg any]]);
 
+    [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage];
+    [apsReceiver connection:nil didReceiveIncomingMessage:apsMessage2];
+
     // Launch!
     CKKSKeychainView* pushTestView = [self.injectedManager findOrCreateView:pushTestZone.zoneName];
     [self.ckksViews addObject:pushTestView];
     APSIncomingMessage* apsMessage = [CKKSAPSHandlingTests messageWithTracingEnabledForZoneID:pushTestZone];
 
     // Don't use the global map here, because we need to ensure we create a new object (to use the stalePushTimeout we injected above)
-    OctagonAPSReceiver* apsReceiver = OCMPartialMock([[OctagonAPSReceiver alloc] initWithEnvironmentName:self.apsEnvironment
-                                                                                       namedDelegatePort:SecCKKSAPSNamedPort
+    OctagonAPSReceiver* apsReceiver = OCMPartialMock([[OctagonAPSReceiver alloc] initWithNamedDelegatePort:SecCKKSAPSNamedPort
                                                                                       apsConnectionClass:[FakeAPSConnection class]
                                                                                         stalePushTimeout:4 * NSEC_PER_SEC]);
     XCTAssertNotNil(apsReceiver, "Should have gotten an APS receiver");
diff --git a/keychain/ckks/tests/CKKSCloudKitTests.m b/keychain/ckks/tests/CKKSCloudKitTests.m
deleted file mode 100644 (file)
index 8223981..0000000
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#import <XCTest/XCTest.h>
-#import <CloudKit/CloudKit.h>
-#import <CloudKit/CloudKit_Private.h>
-
-#import <Security/SecureObjectSync/SOSViews.h>
-#import <utilities/SecFileLocations.h>
-#import "keychain/securityd/SecItemServer.h"
-#if NO_SERVER
-#include "keychain/securityd/spi.h"
-#endif
-
-#import "keychain/ckks/CKKS.h"
-#import "keychain/ckks/CKKSViewManager.h"
-#import "keychain/ckks/CKKSKeychainView.h"
-#import "keychain/ckks/CKKSCurrentKeyPointer.h"
-#import "keychain/ckks/CKKSMirrorEntry.h"
-#import "keychain/ckks/CKKSItemEncrypter.h"
-#import "keychain/ckks/CloudKitCategories.h"
-#import "keychain/categories/NSError+UsefulConstructors.h"
-#import "keychain/ckks/tests/MockCloudKit.h"
-#import "keychain/ot/OTManager.h"
-
-@interface CKKSCloudKitTests : XCTestCase
-
-@property NSOperationQueue *operationQueue;
-@property CKContainer *container;
-@property CKDatabase *database;
-@property CKKSKeychainView *kcv;
-@property NSString *zoneName;
-@property CKRecordZoneID *zoneID;
-@property NSDictionary *remoteItems;
-@property NSInteger queueTimeout;
-
-@end
-
-// TODO: item modification should up gencount, check this
-
-@implementation CKKSCloudKitTests
-
-#if OCTAGON
-
-#pragma mark Setup
-
-+ (void)setUp {
-    SecCKKSResetSyncing();
-    SecCKKSTestsEnable();
-    SecCKKSSetReduceRateLimiting(true);
-    [super setUp];
-
-#if NO_SERVER
-    securityd_init_local_spi();
-#endif
-}
-
-- (void)setUp {
-    self.remoteItems = nil;
-    self.queueTimeout = 900;    // CloudKit can be *very* slow, and some tests upload a lot of items indeed
-    NSString *containerName = [NSString stringWithFormat:@"com.apple.test.p01.B.com.apple.security.keychain.%@", [[NSUUID new] UUIDString]];
-    self.container = [CKContainer containerWithIdentifier:containerName];
-
-    SecCKKSTestResetFlags();
-    SecCKKSTestSetDisableSOS(true);
-
-    self.operationQueue = [NSOperationQueue new];
-
-    CKKSCloudKitClassDependencies* cloudKitClassDependencies = [[CKKSCloudKitClassDependencies alloc] initWithFetchRecordZoneChangesOperationClass:[CKFetchRecordZoneChangesOperation class]
-                                                                                                                        fetchRecordsOperationClass:[CKFetchRecordsOperation class]
-                                                                                                                               queryOperationClass:[CKQueryOperation class]
-                                                                                                                 modifySubscriptionsOperationClass:[CKModifySubscriptionsOperation class]
-                                                                                                                   modifyRecordZonesOperationClass:[CKModifyRecordZonesOperation class]
-                                                                                                                                apsConnectionClass:[APSConnection class]
-                                                                                                                         nsnotificationCenterClass:[NSNotificationCenter class]
-                                                                                                              nsdistributednotificationCenterClass:[NSDistributedNotificationCenter class]
-                                                                                                                                     notifierClass:[FakeCKKSNotifier class]];
-
-    CKContainer* container = [CKKSViewManager makeCKContainer:SecCKKSContainerName usePCS:SecCKKSContainerUsePCS];
-    CKKSAccountStateTracker* accountStateTracker = [[CKKSAccountStateTracker alloc] init:container
-                                                               nsnotificationCenterClass:cloudKitClassDependencies.nsnotificationCenterClass];
-
-    CKKSLockStateTracker* lockStateTracker = [[CKKSLockStateTracker alloc] init];
-
-    CKKSViewManager* manager = [[CKKSViewManager alloc] initWithContainer:container
-                                                               sosAdapter:nil
-                                                      accountStateTracker:accountStateTracker
-                                                         lockStateTracker:lockStateTracker
-                                                cloudKitClassDependencies:cloudKitClassDependencies];
-    // No longer a supported mechanism:
-    //[CKKSViewManager resetManager:false setTo:manager];
-    (void)manager;
-
-    // Make a new fake keychain
-    NSString* smallName = [self.name componentsSeparatedByString:@" "][1];
-    smallName = [smallName stringByReplacingOccurrencesOfString:@"]" withString:@""];
-
-    NSString* tmp_dir = [NSString stringWithFormat: @"/tmp/%@.%X", smallName, arc4random()];
-    [[NSFileManager defaultManager] createDirectoryAtPath:[NSString stringWithFormat: @"%@/Library/Keychains", tmp_dir] withIntermediateDirectories:YES attributes:nil error:NULL];
-
-    SetCustomHomeURLString((__bridge CFStringRef) tmp_dir);
-    SecKeychainDbReset(NULL);
-    // Actually load the database.
-    kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { return false; });
-
-    self.zoneName = @"keychain";
-    self.zoneID = [[CKRecordZoneID alloc] initWithZoneName:self.zoneName ownerName:CKCurrentUserDefaultName];
-    self.kcv = [[CKKSViewManager manager] findOrCreateView:@"keychain"];
-}
-
-- (void)tearDown {
-    self.remoteItems = nil;
-    [[CKKSViewManager manager] clearView:@"keychain"];
-    SecCKKSTestResetFlags();
-}
-
-+ (void)tearDown {
-    SecCKKSResetSyncing();
-}
-
-#pragma mark Helpers
-
-- (BOOL)waitForEmptyOutgoingQueue:(CKKSKeychainView *)view {
-    [view processOutgoingQueue:[CKOperationGroup CKKSGroupWithName:@"waitForEmptyOutgoingQueue"]];
-    NSInteger secondsToWait = self.queueTimeout;
-    while (true) {
-        if ([view outgoingQueueEmpty:nil]) {
-            return YES;
-        }
-        [NSThread sleepForTimeInterval:1];
-        if (--secondsToWait % 60 == 0) {
-            long minutesWaited = (self.queueTimeout - secondsToWait)/60;
-            NSLog(@"Waiting %ld minute%@ for empty outgoingQueue", minutesWaited, minutesWaited > 1 ? @"s" : @"");
-        }
-        if (secondsToWait <= 0) {
-            XCTFail(@"Timed out waiting for '%@' OutgoingQueue to become empty", view);
-            NSLog(@"Giving up waiting for empty outgoingQueue");
-            return NO;
-        }
-
-    }
-}
-
-- (void)startCKKSSubsystem {
-    // TODO: we removed this mechanism, but haven't tested to see if these tests still succeed
-}
-
-- (NSMutableDictionary *)fetchLocalItems {
-    NSDictionary *query = @{(id)kSecClass               : (id)kSecClassGenericPassword,
-                            (id)kSecAttrSynchronizable  : (id)kCFBooleanTrue,
-                            (id)kSecReturnAttributes    : (id)kCFBooleanTrue,
-                            (id)kSecReturnData          : (id)kCFBooleanTrue,
-                            (id)kSecMatchLimit          : (id)kSecMatchLimitAll,
-                            };
-    CFTypeRef cfresults;
-    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfresults);
-    XCTAssert(status == errSecSuccess || status == errSecItemNotFound, @"retrieved zero or more local items");
-    if (status == errSecItemNotFound) {
-        return [NSMutableDictionary new];
-    } else if (status != errSecSuccess) {
-        return nil;
-    }
-
-    NSArray *results = CFBridgingRelease(cfresults);
-
-    NSMutableDictionary *ret = [NSMutableDictionary new];
-    for (NSMutableDictionary *item in results) {
-        ret[item[@"UUID"]] = item;
-    }
-
-    return ret;
-}
-
-- (NSMutableDictionary *)fetchRemoteItems {
-    CKFetchRecordZoneChangesConfiguration *options = [CKFetchRecordZoneChangesConfiguration new];
-    options.previousServerChangeToken = nil;
-
-    CKFetchRecordZoneChangesOperation *op = [[CKFetchRecordZoneChangesOperation alloc] initWithRecordZoneIDs:@[self.zoneID] configurationsByRecordZoneID:@{self.zoneID : options}];
-    op.configuration.automaticallyRetryNetworkFailures = NO;
-    op.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
-    op.configuration.isCloudKitSupportOperation = YES;
-    op.configuration.container = self.container;
-
-    __block NSMutableDictionary *data = [NSMutableDictionary new];
-    __block NSUInteger synckeys = 0;
-    __block NSUInteger currkeys = 0;
-    op.recordChangedBlock = ^(CKRecord *record) {
-        if ([record.recordType isEqualToString:SecCKRecordItemType]) {
-            data[record.recordID.recordName] = [self decryptRecord:record];
-        } else if ([record.recordType isEqualToString:SecCKRecordIntermediateKeyType]) {
-            synckeys += 1;
-        } else if ([record.recordType isEqualToString:SecCKRecordCurrentKeyType]) {
-            currkeys += 1;
-        } else {
-            XCTFail(@"Encountered unexpected item %@", record);
-        }
-    };
-
-    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
-    op.recordZoneFetchCompletionBlock = ^(CKRecordZoneID * _Nonnull recordZoneID,
-                                          CKServerChangeToken * _Nullable serverChangeToken,
-                                          NSData * _Nullable clientChangeTokenData,
-                                          BOOL moreComing,
-                                          NSError * _Nullable recordZoneError) {
-        XCTAssertNil(recordZoneError, @"No error in recordZoneFetchCompletionBlock");
-        if (!moreComing) {
-            dispatch_semaphore_signal(sema);
-        }
-    };
-    
-    [op start];
-    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
-    
-    // These are new, fresh zones for each test. There should not be old keys yet.
-    if (synckeys != 3) {XCTFail(@"Unexpected number of synckeys: %lu", (unsigned long)synckeys);}
-    if (currkeys != 3) {XCTFail(@"Unexpected number of current keys: %lu", (unsigned long)currkeys);}
-
-    self.remoteItems = data;
-    return data;
-}
-
-- (BOOL)compareLocalItem:(NSDictionary *)lhs remote:(NSDictionary *)rhs {
-    if ([lhs[@"cdat"] compare: rhs[@"cdat"]] != NSOrderedSame) {XCTFail(@"Creation date differs"); return NO;}
-    if ([lhs[@"mdat"] compare: rhs[@"mdat"]] != NSOrderedSame) {XCTFail(@"Modification date differs"); return NO;}
-    if (![lhs[@"agrp"] isEqualToString:rhs[@"agrp"]]) {XCTFail(@"Access group differs"); return NO;}
-    if (![lhs[@"acct"] isEqualToString:rhs[@"acct"]]) {XCTFail(@"Account differs"); return NO;}
-    if (![lhs[@"v_Data"] isEqualToData:rhs[@"v_Data"]]) {XCTFail(@"Data differs"); return NO;}
-    // class for lhs is already genp due to copymatching query
-    if (![rhs[@"class"] isEqualToString:@"genp"]) {XCTFail(@"Class not genp for remote item"); return NO;}
-    return YES;
-}
-
-- (BOOL)compareLocalKeychainWithCloudKitState {
-    BOOL success = YES;
-    NSMutableDictionary *localItems = [self fetchLocalItems];
-    if (localItems == nil) {XCTFail(@"Received nil for localItems"); return NO;}
-    NSMutableDictionary *remoteItems = [self fetchRemoteItems];
-    if (remoteItems == nil) {XCTFail(@"Received nil for remoteItems"); return NO;}
-
-    for (NSString *uuid in localItems.allKeys) {
-        if (remoteItems[uuid] == nil) {
-            XCTFail(@"account %@ item %@ not present in remote", localItems[uuid][@"acct"], localItems[uuid]);
-            success = NO;
-            continue;
-        }
-        if (![self compareLocalItem:localItems[uuid] remote:remoteItems[uuid]]) {
-            XCTFail(@"local item %@ matches remote item %@", localItems[uuid], remoteItems[uuid]);
-            success = NO;
-        }
-        [remoteItems removeObjectForKey:uuid];
-    }
-    if ([remoteItems count]) {
-        XCTFail(@"No remote items present not found in local, %@", remoteItems);
-        return NO;
-    }
-    return success;
-}
-
-- (BOOL)updateGenericPassword:(NSString *)password account:(NSString *)account {
-    NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword,
-                            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
-                            (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
-                            (id)kSecAttrAccount : account,
-                            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
-                            };
-    NSDictionary *newpasswd = @{(id)kSecValueData : (id) [password dataUsingEncoding:NSUTF8StringEncoding]};
-
-    return errSecSuccess == SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)newpasswd);
-}
-
-- (BOOL)uploadRecords:(NSArray<CKRecord*>*)records {
-    CKModifyRecordsOperation *op = [[CKModifyRecordsOperation alloc] initWithRecordsToSave:records recordIDsToDelete:nil];
-    op.configuration.automaticallyRetryNetworkFailures = NO;
-    op.configuration.discretionaryNetworkBehavior = CKOperationDiscretionaryNetworkBehaviorNonDiscretionary;
-    op.configuration.isCloudKitSupportOperation = YES;
-    op.configuration.container = self.container;
-    
-    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
-    __block BOOL result = NO;
-    op.modifyRecordsCompletionBlock = ^(NSArray<CKRecord *> *savedRecords,
-                                        NSArray<CKRecordID *> *deletedRecordIDs,
-                                        NSError *operationError) {
-        XCTAssertNil(operationError, @"No error uploading records, %@", operationError);
-        if (operationError == nil) {
-            result = YES;
-        }
-        dispatch_semaphore_signal(sema);
-    };
-
-    [op start];
-    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
-
-    return result;
-}
-
-#pragma mark Helpers Adapted from MockXCTest
-
-- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName {
-    return [self createFakeRecord: zoneID recordName:recordName withAccount: nil];
-}
-
-- (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName withAccount: (NSString*) account {
-    NSError* error = nil;
-
-    /* Basically: @{
-     @"acct"  : @"account-delete-me",
-     @"agrp"  : @"com.apple.security.sos",
-     @"cdat"  : @"2016-12-21 03:33:25 +0000",
-     @"class" : @"genp",
-     @"mdat"  : @"2016-12-21 03:33:25 +0000",
-     @"musr"  : [[NSData alloc] init],
-     @"pdmn"  : @"ak",
-     @"sha1"  : [[NSData alloc] initWithBase64EncodedString: @"C3VWONaOIj8YgJjk/xwku4By1CY=" options:0],
-     @"svce"  : @"",
-     @"tomb"  : [NSNumber numberWithInt: 0],
-     @"v_Data" : [@"data" dataUsingEncoding: NSUTF8StringEncoding],
-     };
-     TODO: this should be binary encoded instead of expanded, but the plist encoder should handle it fine */
-    NSData* itemdata = [[NSData alloc] initWithBase64EncodedString:@"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBsaXN0IFBVQkxJQyAiLS8vQXBwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJzaW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+YWNjdDwva2V5PgoJPHN0cmluZz5hY2NvdW50LWRlbGV0ZS1tZTwvc3RyaW5nPgoJPGtleT5hZ3JwPC9rZXk+Cgk8c3RyaW5nPmNvbS5hcHBsZS5zZWN1cml0eS5zb3M8L3N0cmluZz4KCTxrZXk+Y2RhdDwva2V5PgoJPGRhdGU+MjAxNi0xMi0yMVQwMzozMzoyNVo8L2RhdGU+Cgk8a2V5PmNsYXNzPC9rZXk+Cgk8c3RyaW5nPmdlbnA8L3N0cmluZz4KCTxrZXk+bWRhdDwva2V5PgoJPGRhdGU+MjAxNi0xMi0yMVQwMzozMzoyNVo8L2RhdGU+Cgk8a2V5Pm11c3I8L2tleT4KCTxkYXRhPgoJPC9kYXRhPgoJPGtleT5wZG1uPC9rZXk+Cgk8c3RyaW5nPmFrPC9zdHJpbmc+Cgk8a2V5PnNoYTE8L2tleT4KCTxkYXRhPgoJQzNWV09OYU9JajhZZ0pqay94d2t1NEJ5MUNZPQoJPC9kYXRhPgoJPGtleT5zdmNlPC9rZXk+Cgk8c3RyaW5nPjwvc3RyaW5nPgoJPGtleT50b21iPC9rZXk+Cgk8aW50ZWdlcj4wPC9pbnRlZ2VyPgoJPGtleT52X0RhdGE8L2tleT4KCTxkYXRhPgoJWkdGMFlRPT0KCTwvZGF0YT4KPC9kaWN0Pgo8L3BsaXN0Pgo=" options:0];
-    NSMutableDictionary * item = [[NSPropertyListSerialization propertyListWithData:itemdata
-                                                                            options:0
-                                                                             format:nil
-                                                                              error:&error] mutableCopy];
-    // Fix up dictionary
-    item[@"agrp"] = @"com.apple.security.ckks";
-
-    XCTAssertNil(error, "interpreted data as item");
-
-    if(account) {
-        [item setObject: account forKey: (__bridge id) kSecAttrAccount];
-    }
-
-    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:recordName zoneID:zoneID];
-    return [self newRecord: ckrid withNewItemData: item];
-}
-
-- (CKRecord*)newRecord: (CKRecordID*) recordID withNewItemData:(NSDictionary*) dictionary {
-    NSError* error = nil;
-    CKKSKey* classCKey = [CKKSKey currentKeyForClass:SecCKKSKeyClassC zoneID:recordID.zoneID error:&error];
-    XCTAssertNotNil(classCKey, "Have class C key for zone");
-
-    CKKSItem* cipheritem = [CKKSItemEncrypter encryptCKKSItem:[[CKKSItem alloc] initWithUUID:recordID.recordName
-                                                                               parentKeyUUID:classCKey.uuid
-                                                                                      zoneID:recordID.zoneID]
-                                               dataDictionary:dictionary
-                                             updatingCKKSItem:nil
-                                                    parentkey:classCKey
-                                                        error:&error];
-
-    CKKSOutgoingQueueEntry* ciphertext = [[CKKSOutgoingQueueEntry alloc] initWithCKKSItem:cipheritem
-                                                                                   action:SecCKKSActionAdd
-                                                                                    state:SecCKKSStateNew
-                                                                                waitUntil:nil
-                                                                              accessGroup:@"unused in this function"];
-    XCTAssertNil(error, "encrypted item with class c key");
-
-    CKRecord* ckr = [ciphertext.item CKRecordWithZoneID: recordID.zoneID];
-    XCTAssertNotNil(ckr, "Created a CKRecord");
-    return ckr;
-}
-
-- (NSDictionary*)decryptRecord: (CKRecord*) record {
-    CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKRecord: record];
-
-    NSError* error = nil;
-
-    NSDictionary* ret = [CKKSItemEncrypter decryptItemToDictionary:ckme.item error:&error];
-    XCTAssertNil(error);
-    XCTAssertNotNil(ret);
-    return ret;
-}
-
-- (BOOL)addMultiplePasswords:(NSString *)password account:(NSString *)account amount:(NSUInteger)amount {
-    while (amount > 0) {
-        if (![self addGenericPassword:password account:[NSString stringWithFormat:@"%@%03lu", account, amount]]) {
-            return NO;
-        }
-        amount -= 1;
-    }
-    return YES;
-}
-
-- (BOOL)deleteMultiplePasswords:(NSString *)account amount:(NSUInteger)amount {
-    while (amount > 0) {
-        if (![self deleteGenericPassword:[NSString stringWithFormat:@"%@%03lu", account, amount]]) {
-            return NO;
-        }
-        amount -= 1;
-    }
-    return YES;
-}
-
-- (BOOL)addGenericPassword: (NSString*) password account: (NSString*) account viewHint: (NSString*) viewHint expecting: (OSStatus) status message: (NSString*) message {
-    NSMutableDictionary* query = [@{
-                                    (id)kSecClass : (id)kSecClassGenericPassword,
-                                    (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
-                                    (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
-                                    (id)kSecAttrAccount : account,
-                                    (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
-                                    (id)kSecValueData : (id) [password dataUsingEncoding:NSUTF8StringEncoding],
-                                    } mutableCopy];
-
-    if(viewHint) {
-        query[(id)kSecAttrSyncViewHint] = viewHint;
-    }
-
-    return status == SecItemAdd((__bridge CFDictionaryRef) query, NULL);
-}
-
-- (BOOL)addGenericPassword: (NSString*) password account: (NSString*) account expecting: (OSStatus) status message: (NSString*) message {
-    return [self addGenericPassword:password account:account viewHint:nil expecting:errSecSuccess message:message];
-}
-
-- (BOOL)addGenericPassword: (NSString*) password account: (NSString*) account {
-    return [self addGenericPassword:password account:account viewHint:nil expecting:errSecSuccess message:@"Add item to keychain"];
-}
-
-- (BOOL)addGenericPassword: (NSString*) password account: (NSString*) account viewHint:(NSString*)viewHint {
-    return [self addGenericPassword:password account:account viewHint:viewHint expecting:errSecSuccess message:@"Add item to keychain with a viewhint"];
-}
-
-- (BOOL)deleteGenericPassword: (NSString*) account {
-    NSDictionary* query = @{(id)kSecClass : (id)kSecClassGenericPassword,
-                            (id)kSecAttrAccount : account,
-                            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,};
-
-    return errSecSuccess == SecItemDelete((__bridge CFDictionaryRef) query);
-}
-
-- (BOOL)findGenericPassword: (NSString*) account expecting: (OSStatus) status {
-    NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword,
-                            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
-                            (id)kSecAttrAccount : account,
-                            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
-                            (id)kSecMatchLimit : (id)kSecMatchLimitOne,};
-
-    return status == SecItemCopyMatching((__bridge CFDictionaryRef) query, NULL);
-}
-
-- (void)checkGenericPassword: (NSString*) password account: (NSString*) account {
-    NSDictionary *query = @{(id)kSecClass : (id)kSecClassGenericPassword,
-                            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
-                            (id)kSecAttrAccount : account,
-                            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
-                            (id)kSecMatchLimit : (id)kSecMatchLimitOne,
-                            (id)kSecReturnData : (id)kCFBooleanTrue,
-                            };
-    CFTypeRef result = NULL;
-
-    XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &result), "Finding item %@", account);
-    XCTAssertNotNil((__bridge id)result, "Received an item");
-
-    NSString* storedPassword = [[NSString alloc] initWithData: (__bridge NSData*) result encoding: NSUTF8StringEncoding];
-    XCTAssertNotNil(storedPassword, "Password parsed as a password");
-
-    XCTAssertEqualObjects(storedPassword, password, "Stored password matches received password");
-}
-
-#pragma mark Tests
-
-- (void)testAddDelete {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-
-    XCTAssert([self addGenericPassword:@"data" account:@"ck-test-adddelete"], @"Added single item");
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAdd: states match after add");
-    
-    XCTAssert([self deleteGenericPassword:@"ck-test-adddelete"], @"Deleted single item");
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAdd: states match after delete");
-}
-
-- (void)testAddModDelete {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-    
-    [self addGenericPassword:@"data" account:@"ck-test-addmoddelete"];
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMod: states match after add");
-    
-    [self updateGenericPassword:@"otherdata" account:@"ck-test-addmoddelete"];
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMod: states match after mod");
-    
-    [self deleteGenericPassword:@"ck-test-addmoddelete"];
-
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMod: states match after del");
-}
-
-- (void)testAddModDeleteImmediate {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-
-    XCTAssert([self addGenericPassword:@"data" account:@"ck-test-addmoddeleteimmediate"], @"Added item");
-    XCTAssert([self updateGenericPassword:@"otherdata" account:@"ck-test-addmoddeleteimmediate"], @"Modified item");
-    XCTAssert([self deleteGenericPassword:@"ck-test-addmoddeleteimmediate"], @"Deleted item");
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    [self.kcv waitForFetchAndIncomingQueueProcessing];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMod: states match after immediate add/mod/delete");
-}
-
-- (void)testReceive {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-
-    [self findGenericPassword:@"ck-test-receive" expecting:errSecItemNotFound];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testReceive: states match before receive");
-
-    CKRecord *record = [self createFakeRecord:self.zoneID recordName:@"b6050e4d-e7b7-4e4e-b318-825cacc34722" withAccount:@"ck-test-receive"];
-    [self uploadRecords:@[record]];
-
-    [self.kcv notifyZoneChange:nil];
-    [self.kcv waitForFetchAndIncomingQueueProcessing];
-
-    [self findGenericPassword:@"ck-test-receive" expecting:errSecSuccess];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testReceive: states match after receive");
-}
-
-- (void)testReceiveColliding {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-
-    XCTAssert([self findGenericPassword:@"ck-test-receivecolliding" expecting:errSecItemNotFound], @"test item not yet in keychain");
-
-    // Conflicting items! This test does not care how conflict gets resolved, just that state is consistent after syncing
-    CKRecord *r1 = [self createFakeRecord:self.zoneID recordName:@"97576447-c6b8-47fe-8f00-64f5da49d538" withAccount:@"ck-test-receivecolliding"];
-    CKRecord *r2 = [self createFakeRecord:self.zoneID recordName:@"c6b86447-9757-47fe-8f00-64f5da49d538" withAccount:@"ck-test-receivecolliding"];
-    [self uploadRecords:@[r1,r2]];
-
-    // poke CKKS since we won't have a real CK notification
-    [self.kcv notifyZoneChange:nil];
-    [self.kcv waitForFetchAndIncomingQueueProcessing];
-    [self waitForEmptyOutgoingQueue:self.kcv];
-
-    XCTAssert([self findGenericPassword:@"ck-test-receivecolliding" expecting:errSecSuccess], @"Item present after download");
-    // This will also flag an issue if the two conflicting items persist
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"Back in sync after processing incoming changes");
-}
-
-- (void)testAddMultipleDeleteAll {
-    [self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-    
-    XCTAssert([self addMultiplePasswords:@"data" account:@"ck-test-addmultipledeleteall" amount:5]);
-    
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMultipleDeleteAll: states match after adds");
-
-    XCTAssert([self deleteMultiplePasswords:@"ck-test-addmultipledeleteall" amount:3]);
-
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMultipleDeleteAll: states match after deletes");
-
-    XCTAssert([self deleteGenericPassword:@"ck-test-addmultipledeleteall005"]);
-    XCTAssert([self deleteGenericPassword:@"ck-test-addmultipledeleteall004"]);
-
-    [self waitForEmptyOutgoingQueue:self.kcv];
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddMultipleDeleteAll: states match after deletes");
-}
-
-- (void)testAddLotsOfItems {
-    [ self startCKKSSubsystem];
-    [self.kcv waitForKeyHierarchyReadiness];
-    
-    XCTAssert([self addMultiplePasswords:@"data" account:@"ck-test-addlotsofitems" amount:250], @"Added a truckload of items");
-
-    XCTAssert([self waitForEmptyOutgoingQueue:self.kcv], @"Completed upload within %ld seconds", (long)self.queueTimeout);
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddLotsOfItems: states match after adding tons of items");
-    
-    XCTAssert([self deleteMultiplePasswords:@"ck-test-addlotsofitems" amount:250], @"Got rid of a truckload of items");
-    XCTAssert([self waitForEmptyOutgoingQueue:self.kcv], @"Completed deletions within %ld seconds",(long)self.queueTimeout);
-    
-    XCTAssert([self compareLocalKeychainWithCloudKitState], @"testAddLotsOfItems: states match after removing tons of items again");
-}
-
-#endif
-
-@end
diff --git a/keychain/ckks/tests/CKKSCloudKitTestsInfo.plist b/keychain/ckks/tests/CKKSCloudKitTestsInfo.plist
deleted file mode 100644 (file)
index 6c6c23c..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>CFBundleDevelopmentRegion</key>
-       <string>en</string>
-       <key>CFBundleExecutable</key>
-       <string>$(EXECUTABLE_NAME)</string>
-       <key>CFBundleIdentifier</key>
-       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
-       <key>CFBundleInfoDictionaryVersion</key>
-       <string>6.0</string>
-       <key>CFBundleName</key>
-       <string>$(PRODUCT_NAME)</string>
-       <key>CFBundlePackageType</key>
-       <string>BNDL</string>
-       <key>CFBundleShortVersionString</key>
-       <string>1.0</string>
-       <key>CFBundleVersion</key>
-       <string>1</string>
-</dict>
-</plist>
index 1c0c6bb2bb9aaf7cf53231a2eff20fac976d0dba..df6bc28fe0bb27695f16ff02e056f99836c7acb2 100644 (file)
@@ -25,7 +25,6 @@
 #import <XCTest/XCTest.h>
 #import <XCTest/XCTest.h>
 #import "keychain/ckks/CKKSCondition.h"
-#import <utilities/debugging.h>
 
 @interface CKKSConditionTests : XCTestCase
 @end
index 8d0c019ad3f950ecbfba1093592551479627afe7..65f3d717afbda00dc44b400bd65e3b1591f7be5f 100644 (file)
     [op waitUntilFinished];
 
     // And now, if the update is old enough, that'll work too
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry fromDatabase:self.accountStateTracker.ckdeviceID zoneID:self.keychainZoneID error:&error];
         XCTAssertNil(error, "No error fetching device state entry");
         [cdse saveToDatabase:&error];
         XCTAssertNil(error, "No error saving device state entry");
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // And now the rate-limiting doesn't get in the way
     NSString* oldDeviceID = self.accountStateTracker.ckdeviceID;
     self.accountStateTracker.ckdeviceID = nil;
 
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry fromDatabase:oldDeviceID zoneID:self.keychainZoneID error:&error];
         XCTAssertNil(error, "No error fetching device state entry");
 
         NSDate* m = record.modificationDate;
         XCTAssertNotNil(m, "Have modification date");
-
-        return true;
     }];
 
     // It shouldn't try to upload a new CDSE; there's no device ID
     [self.keychainZone addToZone:[octagonOnly CKRecordWithZoneID:self.keychainZoneID]];
 
     // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray<CKKSDeviceStateEntry*>* cdses = [CKKSDeviceStateEntry allInZone:self.keychainZoneID error:&error];
         XCTAssertNil(error, "No error fetching CDSEs");
         XCTAssertEqualObjects(octagondevice.currentTLKUUID,    zoneKeys.tlk.uuid,    "correct tlk uuid");
         XCTAssertEqualObjects(octagondevice.currentClassAUUID, zoneKeys.classA.uuid, "correct classA uuid");
         XCTAssertEqualObjects(octagondevice.currentClassCUUID, zoneKeys.classC.uuid, "correct classC uuid");
-
-        return false;
     }];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     [self startCKKSSubsystem];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "CKKS entered waitfortlk");
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateWaitForTLK, "CKKS entered waitfortlk");
 
     __weak __typeof(self) weakSelf = self;
     [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]}
 
     [self startCKKSSubsystem];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "CKKS entered waitfortlk");
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateWaitForTLK, "CKKS entered waitfortlk");
 
     // And restart CKKS...
     self.keychainView = [[CKKSViewManager manager] restartZone: self.keychainZoneID.zoneName];
     [self beginSOSTrustedViewOperation:self.keychainView];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "CKKS entered waitfortlk");
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateWaitForTLK, "CKKS entered waitfortlk");
 
     __weak __typeof(self) weakSelf = self;
     [self expectCKModifyRecords: @{SecCKRecordDeviceStateType: [NSNumber numberWithInt:1]}
 
     [self.keychainView updateDeviceState:false waitForKeyHierarchyInitialization:8*NSEC_PER_SEC ckoperationGroup:nil];
 
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateFetch, "CKKS re-entered fetch");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateFetch] wait:20*NSEC_PER_SEC], "Key state should become fetch");
     [self releaseCloudKitFetchHold];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
index 433a2b20c048852203384f6aa59e70df25ba6383..f1f97783b0ca4860d82d0a83c6340914b3e8fb81 100644 (file)
@@ -53,9 +53,7 @@
         }
     } runBeforeFinished:^{}];
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
         }
     } runBeforeFinished:^{}];
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
         }
     } runBeforeFinished:^{}];
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     }];
 
     // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     // Wait for both fetches....
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self expectCKFetch];
 
     // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
     // Now, edit the on-disk CKSE
     [self.keychainView halt];
 
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error];
 
         ckse.moreRecordsInCloudKit = YES;
         [ckse saveToDatabase: &error];
         XCTAssertNil(error, "no error saving to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // CKKS should, upon restart, kick off a fetch starting from the previous checkpoint
index 692f1a054788e96c5498e963c0f5d1c0c6ee503f..0c60d25e423ffe69c79623e5905e76e3c6890959 100644 (file)
@@ -179,7 +179,14 @@ static void _XCTAssertTimeDiffWithInterval(CKKSAnalyticsTests* self, const char*
             va_end(args);
             arg = [[NSString alloc] initWithFormat: format arguments: args];
         }
-        [self recordFailureWithDescription: [comparison stringByAppendingString: arg] inFile: [NSString stringWithUTF8String: filename] atLine: line expected: YES];
+
+        XCTIssue* issue = [[XCTIssue alloc] initWithType:XCTIssueTypeAssertionFailure
+                                      compactDescription:[comparison stringByAppendingString: arg]
+                                     detailedDescription:nil
+                                       sourceCodeContext:[[XCTSourceCodeContext alloc] init]
+                                         associatedError:nil
+                                             attachments:@[]];
+        [self recordIssue:issue];
     }
 }
 
@@ -190,24 +197,25 @@ static void _XCTAssertTimeDiffWithInterval(CKKSAnalyticsTests* self, const char*
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
     [self.keychainZone addToZone: ckr];
     
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-    
-    [[[self.keychainView waitForFetchAndIncomingQueueProcessing] completionHandlerDidRunCondition] wait:4 * NSEC_PER_SEC];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+
+    [[self.injectedManager.zoneChangeFetcher inflightFetch] waitUntilFinished];
+    CKKSResultOperation* op = [self.keychainView processIncomingQueue:false];
+    [[op completionHandlerDidRunCondition] wait:4 * NSEC_PER_SEC];
 
     NSDate* nowDate = [NSDate date];
 
     /*
      * Check last sync date for class A
      */
-    NSDate* syncADate = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassA inView:self.keychainView];
+    NSDate* syncADate = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassA zoneName:self.keychainView.zoneName];
     XCTAssertNotNil(syncADate, "Failed to get a last successful A sync date");
     XCTAssertTimeDiffWithInterval(syncADate, nowDate, 15, "Last sync A date should be recent");
 
     /*
      * Check last sync date for class C
      */
-    NSDate *syncCDate = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC inView:self.keychainView];
+    NSDate *syncCDate = [[CKKSAnalytics logger] dateOfLastSuccessForEvent:CKKSEventProcessIncomingQueueClassC zoneName:self.keychainView.zoneName];
     XCTAssertNotNil(syncCDate, "Failed to get a last successful C sync date");
     XCTAssertTimeDiffWithInterval(syncCDate, nowDate, 15, "Last sync C date should be recent");
 
@@ -246,7 +254,7 @@ static void _XCTAssertTimeDiffWithInterval(CKKSAnalyticsTests* self, const char*
     for (NSInteger i = 0; i < 5; i++) {
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
             CKKSAnalytics* logger = [CKKSAnalytics logger];
-            [logger logSuccessForEvent:(CKKSAnalyticsFailableEvent*)@"test_event" inView:self.keychainView];
+            [logger logSuccessForEvent:(CKKSAnalyticsFailableEvent*)@"test_event" zoneName:self.keychainView.zoneName];
             dispatch_semaphore_signal(semaphore);
         });
     }
index fbd7f9916432a910a98c7eb4b419ac2b0d65874d..064e99cceac6b1b3c002f3a3c06348a28dbc2145 100644 (file)
@@ -53,7 +53,7 @@
     NSMutableArray* items = [[NSMutableArray alloc] init];
     __weak __typeof(self) weakSelf = self;
     __block NSError* error = nil;
-    [self.keychainView dispatchSync:^bool(void) {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         for (CKRecord* record in records) {
             CKKSMirrorEntry* mirrorEntry = [CKKSMirrorEntry tryFromDatabase:record.recordID.recordName zoneID:weakSelf.keychainZoneID error:&error];
             XCTAssertNil(error, @"error encountered trying to generate CKKSMirrorEntry: %@", error);
@@ -63,7 +63,7 @@
             }
         }
         
-        return YES;
+        return CKKSDatabaseTransactionCommit;
     }];
     
     return items;
     SFECKeyPair* keyPair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
     [CKKSManifestInjectionPointHelper registerEgoPeerID:@"MeMyselfAndI" keyPair:keyPair];
 
-    // Always sync manifests, and never enforce them
-    SecCKKSSetSyncManifests(true);
+    // We've now disabled manifests.
+    SecCKKSSetSyncManifests(false);
     SecCKKSSetEnforceManifests(false);
 
-    XCTAssertTrue([CKKSManifest shouldSyncManifests], "Manifests syncing is enabled");
+    XCTAssertFalse([CKKSManifest shouldSyncManifests], "Manifests syncing is disabled");
     XCTAssertFalse([CKKSManifest shouldEnforceManifests], "Manifests enforcement is disabled");
 
     NSError* error = nil;
         [self.keychainZone addToZone:record];
     }
     
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-    
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
     
     return query;
 
 - (void)testSaveManifestWithNilValues
 {
-    SFECKeyPair* keyPair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
-    CKKSManifest* manifest = [CKKSEgoManifest newFakeManifestForZone:@"SomeZone" withItemRecords:@[] currentItems:@{} signerID:@"BadBoy" keyPair:keyPair error:nil];
-    [manifest nilAllIvars];
-    XCTAssertNil(manifest.zoneID);
-    XCTAssertNil(manifest.signerID);
-    XCTAssertNoThrow([manifest saveToDatabase:nil]);
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        SFECKeyPair* keyPair = [[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]];
+        CKKSManifest* manifest = [CKKSEgoManifest newFakeManifestForZone:@"SomeZone" withItemRecords:@[] currentItems:@{} signerID:@"BadBoy" keyPair:keyPair error:nil];
+        [manifest nilAllIvars];
+        XCTAssertNil(manifest.zoneID);
+        XCTAssertNil(manifest.signerID);
+        XCTAssertNoThrow([manifest saveToDatabase:nil]);
+        return CKKSDatabaseTransactionRollback;
+    }];
 }
 
 @end
index 4eb485201408c9dd5bff27714b3392b2025ab844..66d11d89b6f7532ccac57380b5488182955d5ee4 100644 (file)
@@ -13,6 +13,8 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nullable) NSError* selfPeerError;
 @property (nullable) NSError* trustedPeersError;
 
+@property BOOL aksLocked;
+
 @property bool excludeSelfPeerFromTrustSet;
 
 @property SOSCCStatus circleStatus;
@@ -21,6 +23,11 @@ NS_ASSUME_NONNULL_BEGIN
 @property CKKSSOSSelfPeer* selfPeer;
 @property NSMutableSet<id<CKKSSOSPeerProtocol>>* trustedPeers;
 
+@property BOOL safariViewEnabled;
+
+@property BOOL ckks4AllStatus;
+@property BOOL ckks4AllStatusIsSet;
+
 @property (nullable) void (^updateOctagonKeySetListener)(id<CKKSSelfPeer>);
 
 - (instancetype)initWithSelfPeer:(CKKSSOSSelfPeer*)selfPeer
index 7f8077ec55850dc90c1cbfd7be012c263e24c7e7..d1696e64db085dba1f446dfa8eb3182435e42e22 100644 (file)
         _essential = essential;
 
         _circleStatus = kSOSCCInCircle;
+        _safariViewEnabled = YES;
 
         _excludeSelfPeerFromTrustSet = false;
 
         _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-mock-sos"];
 
+        _ckks4AllStatus = NO;
+        _ckks4AllStatusIsSet = NO;
+
         _selfPeer = selfPeer;
         _trustedPeers = [trustedPeers mutableCopy];
     }
         return nil;
     }
 
+    if(self.aksLocked) {
+        if(error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInteractionNotAllowed userInfo:nil];
+        }
+        return nil;
+    }
+
     if(self.sosEnabled && self.circleStatus == kSOSCCInCircle) {
         return self.selfPeer;
     } else {
@@ -81,7 +92,7 @@
 - (NSSet<id<CKKSRemotePeerProtocol>> * _Nullable)fetchTrustedPeers:(NSError * _Nullable __autoreleasing * _Nullable)error
 {
     if(self.trustedPeersError) {
-        if(*error) {
+        if(error) {
             *error = self.trustedPeersError;
         }
         return nil;
     }
 }
 
-- (void)updateOctagonKeySetWithAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
+- (BOOL)updateOctagonKeySetWithAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
     if(self.updateOctagonKeySetListener) {
         self.updateOctagonKeySetListener(currentSelfPeer);
     }
-    return;
+    return YES;
+}
+
+- (BOOL)updateCKKS4AllStatus:(BOOL)status error:(NSError**)error
+{
+    self.ckks4AllStatus = status;
+    self.ckks4AllStatusIsSet = YES;
+    return YES;
 }
 
 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
     return [self.trustedPeers setByAddingObject: s];
 }
 
+- (BOOL)safariViewSyncingEnabled:(NSError**)error
+{
+    // TODO: what happens if you call this when not in circle?
+    return self.safariViewEnabled;
+}
+
+- (BOOL)preloadOctagonKeySetOnAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
+    // No-op
+    return YES;
+}
+
 @end
index 913a7901e6c50401ae9d3fa93c843b445f830837..b3c6e30db6282f627512f671bb041cb993b4b9a5 100644 (file)
     XCTAssertFalse([group isPending], "group operation isn't pending, as it's cancelled");
 }
 
+- (void)testResultOperationDeepDependencyChain {
+    NSMutableArray<CKKSResultOperation*>* ops = [NSMutableArray array];
+
+    CKKSResultOperation* op = nil;
+
+    for(int i = 0; i < 100; i++) {
+        op = [CKKSResultOperation named:[NSString stringWithFormat:@"operation-%d", i] withBlock:^{}];
+        [op addNullableDependency:[ops lastObject]];
+
+        [ops addObject:op];
+    }
+
+    NSString* description = [op description];
+    XCTAssertNotNil(description, "Should have received some description for the operation");
+}
+
+- (void)testGroupOperationDeepDependencyChain {
+    NSMutableArray<CKKSGroupOperation*>* ops = [NSMutableArray array];
+
+    CKKSGroupOperation* op = nil;
+
+    for(int i = 0; i < 100; i++) {
+        op = [CKKSGroupOperation named:[NSString stringWithFormat:@"operation-%d", i] withBlock:^{}];
+        [op addNullableDependency:[ops lastObject]];
+
+        [ops addObject:op];
+    }
+
+    NSString* description = [op description];
+    XCTAssertNotNil(description, "Should have received some description for the operation");
+}
+
 
 @end
 
index 7ac4dbacf172e48d3dc718ae6ce1193b68d5de62..c773c09fe9a53a4a06237862790a7bd4f2e40f93 100644 (file)
@@ -70,6 +70,8 @@
     [self saveFakeKeyHierarchyToLocalDatabase:self.manateeZoneID];
     [self saveTLKMaterialToKeychain:self.manateeZoneID];
 
+    [self startCKKSSubsystem];
+
     NSDictionary* piggyTLKs = [self SOSPiggyBackCopyFromKeychain];
 
     [self deleteTLKMaterialFromKeychain:self.manateeZoneID];
@@ -86,6 +88,8 @@
     [self putFakeDeviceStatusesInCloudKit];
     [self saveTLKsToKeychain];
 
+    [self startCKKSSubsystem];
+
     NSDictionary* piggyTLKs = [self SOSPiggyBackCopyFromKeychain];
 
     [self deleteTLKMaterialsFromKeychain];
     XCTAssertNil(error, "No error loading Home tlk from piggy contents");
 }
 
--(NSString*)fileForStorage
-{
-    static dispatch_once_t onceToken;
-    static NSString *tempPath = NULL;
-    dispatch_once(&onceToken, ^{
-        tempPath = [[[[NSFileManager defaultManager] temporaryDirectory] URLByAppendingPathComponent:@"PiggyPacket"] path];
-
-    });
-    return tempPath;
-}
-
 -(void)testPiggybackingData{
     [self putFakeKeyHierachiesInCloudKit];
     [self saveTLKsToKeychain];
     NSData *initial = SOSPiggyCreateInitialSyncData(icloudidentities, tlks);
 
     XCTAssertNotNil(initial, "Initial not set");
-    BOOL writeStatus = [initial writeToFile:[self fileForStorage] options:NSDataWritingAtomic error: nil];
-    XCTAssertTrue(writeStatus, "had trouble writing to disk");
     XCTAssertNotEqual((int)[initial length], 0, "initial sync data is greater than 0");
 
     /*
     XCTAssertEqual([copiediCloudidentities count], [icloudidentities count], "ident count not same");
 }
 
+
+- (void)testPiggybackingTLKRequest {
+    [self putFakeKeyHierachiesInCloudKit];
+    [self saveTLKsToKeychain];
+
+    for(CKRecordZoneID* zoneID in self.ckksZones) {
+        [self expectCKKSTLKSelfShareUpload:zoneID];
+    }
+    [self startCKKSSubsystem];
+    [self waitForKeyHierarchyReadinesses];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // The "tlk request" piggybacking session calls SOSAccountCopyInitialSyncData
+    __block CFErrorRef cferror = NULL;
+    NSData* piggybackingData = (NSData*) CFBridgingRelease(SOSAccountCopyInitialSyncData(nil, kSOSInitialSyncFlagTLKsRequestOnly, &cferror));
+
+    XCTAssertEqual(cferror, NULL, "Should have no error fetching only the TLKs");
+    XCTAssertNotNil(piggybackingData, "Should have received some sync data");
+
+    const uint8_t* der = [piggybackingData bytes];
+    const uint8_t *der_end = der + [piggybackingData length];
+
+    NSDictionary *result = SOSPiggyCopyInitialSyncData(&der, der_end);
+    XCTAssertNotNil(result, "Should be able to parse the piggybacking data");
+
+    NSArray *copiedTLKs = result[@"tlks"];
+    XCTAssertNotNil(copiedTLKs, "should have some tlks");
+    XCTAssertEqual([copiedTLKs count], 1u, "piggybacking should have gotten 1 TLK");
+    XCTAssertEqualObjects(copiedTLKs[0][@"srvr"], @"Passwords", "should have the passwords TLK only");
+    NSData* keyData = copiedTLKs[0][@"v_Data"];
+    XCTAssertNotNil(keyData, "Should have some key material");
+    XCTAssertEqual([keyData length], 64, "Key material should be 64 bytes");
+
+    NSArray *copiediCloudidentities = result[@"idents"];
+    XCTAssertNotNil(copiediCloudidentities, "idents not set");
+    XCTAssertEqual([copiediCloudidentities count], 0, "Should have no icloud identities");
+}
+
 -(void)testVerifyTLKSorting {
     char key[32*2] = {0};
     NSArray<NSDictionary *> *tlks = @[
     
     // Verify that there are three local keys, and three local current key records
     __weak __typeof(self) weakSelf = self;
-    [self.manateeView dispatchSync: ^bool{
+    [self.manateeView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
         
         XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef)query, &result), "Found a syncable TLK");
         XCTAssertNotNil((__bridge id) result, "Received a result from SecItemCopyMatching");
         CFReleaseNull(result);
-        
-        return false;
     }];
 }
 
index 827a5c83a13fd3d2ec78989b696ab5609d8bd6a7..4361b4748d186892a6d8560de303975fbe57fec4 100644 (file)
@@ -30,7 +30,9 @@
 
 #import "keychain/ckks/CKKS.h"
 #import "keychain/ckks/CKKSKey.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
 #import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
 #import "keychain/ckks/CKKSZoneStateEntry.h"
 #import "keychain/ckks/CKKSDeviceStateEntry.h"
 #import "keychain/ckks/CKKSRateLimiter.h"
                                                                          waitUntil:nil
                                                                        accessGroup:@"nope"];
 
-    NSError* error = nil;
-    [one saveToDatabase:&error];
-    [two saveToDatabase: &error];
-    [three saveToDatabase: &error];
-    XCTAssertNil(error, "no error saving ZoneStateEntries to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* error = nil;
+        [one saveToDatabase:&error];
+        [two saveToDatabase: &error];
+        [three saveToDatabase: &error];
+        XCTAssertNil(error, "no error saving ZoneStateEntries to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 }
 
 - (void)testCKKSOutgoingQueueEntry {
                                                                                state:SecCKKSStateError
                                                                            waitUntil:[NSDate date]
                                                                          accessGroup:@"nope"];
-    [other saveToDatabase:&nserror];
-    XCTAssertNil(nserror, "no error occurred saving to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [other saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSOutgoingQueueEntry * oqe = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:@"unprocessed" zoneID:self.testZoneID error: &nserror];
     XCTAssertNil(nserror, "no error occurred creating from database");
     oqe.item.base64encitem = @"bW9yZW5vbnNlbnNlCg==";
     oqe.item.encver = 1;
 
-    XCTAssertTrue([oqe saveToDatabase: &nserror], "saving to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [oqe saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSOutgoingQueueEntry * oqe2 = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:@"savedtocloud" zoneID:self.testZoneID error: &nserror];
     XCTAssertNil(nserror, "no error occurred");
 
     // Test row deletion
     nserror = nil;
-    [oqe2 deleteFromDatabase:&nserror];
-    XCTAssertNil(nserror, "No NSError exists when deleting existing item");
+
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* deleteError = nil;
+        [oqe2 deleteFromDatabase:&deleteError];
+        XCTAssertNil(deleteError, "no error occurred deleting existing item");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
     oqe2 = [CKKSOutgoingQueueEntry fromDatabase:testUUID state:@"savedtocloud" zoneID:self.testZoneID error: &nserror];
     XCTAssertNil(oqe2, "Can't find a nonexisting object");
     XCTAssertNotNil(nserror, "NSError exists when things break");
     XCTAssertEqualObjects(other, other2, "loaded object is equal to object");
 }
 
+- (void)testOverwriteCKKSIncomingQueueEntry {
+    NSError* error = nil;
+
+    CKKSItem* baseitem = [[CKKSItem alloc] initWithUUID: [[NSUUID UUID] UUIDString]
+                                          parentKeyUUID:[[NSUUID UUID] UUIDString]
+                                                 zoneID:self.testZoneID
+                                                encItem:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]
+                                             wrappedkey:[[CKKSWrappedAESSIVKey alloc]initWithBase64: @"KFfL58XtugiYNoD859EjG0StfrYd6eakm0CQrgX7iO+DEo4kio3WbEeA1kctCU0GaeTGsRFpbdy4oo6jXhVu7cZqB0svhUPGq55aGnszUjI="]
+                                        generationCount:0
+                                                 encver:0];
+    CKKSIncomingQueueEntry* delete = [[CKKSIncomingQueueEntry alloc] initWithCKKSItem:baseitem
+                                                                               action:SecCKKSActionDelete
+                                                                                state:SecCKKSStateNew];
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [delete saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving delete IQE to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    NSArray<CKKSIncomingQueueEntry*>* entries = [CKKSIncomingQueueEntry all:&error];
+    XCTAssertNil(error, "Should be no error fetching alll IQEs");
+    XCTAssertEqual(entries.count, 1u, "Should be one entry");
+    XCTAssertEqualObjects(entries[0].action, SecCKKSActionDelete, "Should have delete as an action");
+
+    CKKSIncomingQueueEntry* add = [[CKKSIncomingQueueEntry alloc] initWithCKKSItem:baseitem
+                                                                            action:SecCKKSActionAdd
+                                                                             state:SecCKKSStateNew];
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [add saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving add IQE to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    entries = [CKKSIncomingQueueEntry all:&error];
+    XCTAssertNil(error, "Should be no error fetching alll IQEs");
+    XCTAssertEqual(entries.count, 1u, "Should be one entry");
+    XCTAssertEqualObjects(entries[0].action, SecCKKSActionAdd, "Should have add as an action");
+}
+
 -(void)testCKKSZoneStateEntrySQL {
     CKKSZoneStateEntry* zse = [[CKKSZoneStateEntry alloc] initWithCKZone:@"sqltest"
                                                              zoneCreated:true
                                                              changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]
                                                    moreRecordsInCloudKit:YES
                                                                lastFetch:[NSDate date]
+                                                                lastScan:[NSDate date]
                                                                lastFixup:CKKSCurrentFixupNumber
                                                       encodedRateLimiter:nil];
     zse.rateLimiter = [[CKKSRateLimiter alloc] init];
                                                                   changeToken:[@"nonsense" dataUsingEncoding:NSUTF8StringEncoding]
                                                         moreRecordsInCloudKit:YES
                                                                     lastFetch:zse.lastFetchTime
+                                                                     lastScan:zse.lastLocalKeychainScanTime
                                                                     lastFixup:CKKSCurrentFixupNumber
                                                            encodedRateLimiter:zse.encodedRateLimiter];
 
                                                                       changeToken:[@"allnonsense" dataUsingEncoding:NSUTF8StringEncoding]
                                                             moreRecordsInCloudKit:NO
                                                                         lastFetch:zse.lastFetchTime
+                                                                         lastScan:zse.lastLocalKeychainScanTime
                                                                         lastFixup:CKKSCurrentFixupNumber
                                                                encodedRateLimiter:zse.encodedRateLimiter];
     XCTAssertEqualObjects(zse, zseClone, "CKKSZoneStateEntry isEqual of equal objects seems sane");
     XCTAssertNil(error, "No error trying to load nonexistent record");
     XCTAssertNil(loaded, "No record saved in database");
 
-    [zse saveToDatabase: &error];
-    XCTAssertNil(error, "no error saving CKKSZoneStateEntry to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [zse saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving CKKSZoneStateEntry to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     loaded = [CKKSZoneStateEntry tryFromDatabase: @"sqltest" error:&error];
     XCTAssertNil(error, "No error trying to load saved record");
     // We only compare to the minute level, as that's enough to test the save+load.
     XCTAssert([[NSCalendar currentCalendar] isDate:zse.lastFetchTime equalToDate: loaded.lastFetchTime toUnitGranularity:NSCalendarUnitMinute],
                                                                    "lastFetchTime persisted through db save and load");
+    XCTAssert([[NSCalendar currentCalendar] isDate:zse.lastLocalKeychainScanTime equalToDate:loaded.lastLocalKeychainScanTime toUnitGranularity:NSCalendarUnitMinute],
+              "lastLocalKeychainScanTime persisted through db save and load");
 }
 
 -(void)testRoundtripCKKSDeviceStateEntry {
                                                                       zoneID:self.testZoneID
                                                              encodedCKRecord:nil];
     XCTAssertNotNil(cdse, "Constructor works");
-    NSError* saveError = nil;
-    [cdse saveToDatabase:&saveError];
-    XCTAssertNil(saveError, "No error saving cdse to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [cdse saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving cdse to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     NSError* loadError = nil;
     CKKSDeviceStateEntry* loadedCDSE = [CKKSDeviceStateEntry fromDatabase:testUUID zoneID:self.testZoneID error:&loadError];
                                       currentkey:true];
     XCTAssertNotNil(key, "could create key");
 
-    [key saveToDatabase: &error];
-    XCTAssertNil(error, "could save key to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [key saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving key to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
     error = nil;
 
     CKKSKey* key2 = [CKKSKey fromDatabase:testUUID zoneID:self.testZoneID error:&error];
                                                        zoneID:self.testZoneID
                                               encodedCKRecord: testCKRecord
                                                    currentkey: true];
-    XCTAssertTrue([tlk saveToDatabase: &error], "TLK saved to database");
-    XCTAssertNil(error, "no error saving TLK to database");
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [tlk saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving TLK to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSKey* wrappedKey = [[CKKSKey alloc] initWrappedBy: tlk
                                                   AESKey:[CKKSAESSIVKey randomKey:&error]
                                                   zoneID:self.testZoneID
                                          encodedCKRecord:testCKRecord
                                               currentkey:true];
-    XCTAssertTrue([wrappedKey saveToDatabase: &error], "key saved to database");
-    XCTAssertNil(error, "no error saving key to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [wrappedKey saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "no error occurred saving key to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     NSString* secondUUID = @"8b2aeb7f-0000-0000-0000-70d5c728ebf7";
     CKKSKey* secondtlk = [[CKKSKey alloc] initSelfWrappedWithAESKey:[[CKKSAESSIVKey alloc] initWithBase64: @"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="]
                                                              zoneID:self.testZoneID
                                                     encodedCKRecord:testCKRecord
                                                          currentkey:true];
-    XCTAssertTrue([secondtlk saveToDatabase: &error], "Second TLK saved to database");
-    XCTAssertNil(error, "no error saving TLK to database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        XCTAssertTrue([secondtlk saveToDatabase:&saveError], "Second TLK saved to database");
+        XCTAssertNil(saveError, "no error occurred saving second TLK to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     NSArray<CKKSKey*>* tlks = [CKKSKey allWhere: @{@"UUID": @"8b2aeb7f-4af3-43e9-b6e6-70d5c728ebf7"} error: &error];
     XCTAssertNotNil(tlks, "Returned some array from allWhere");
     XCTAssertNil(error, "no error back from allWhere");
     XCTAssertEqual([selfWrapped3 count], 1ul, "Should have received one rows");
     XCTAssertEqualObjects([selfWrapped3[0] uuid], secondUUID, "Should received second TLK UUID");
+
+    NSArray<CKKSKey*>* whereFound = [CKKSKey allWhere: @{@"uuid": [[CKKSSQLWhereIn alloc] initWithValues:@[tlk.uuid, wrappedKey.uuid,  @"not-found"]]} error:&error];
+    XCTAssertNil(error, "no error back from search");
+    XCTAssertEqual([whereFound count], 2ul, "Should have received two rows");
+    XCTAssertEqualObjects([whereFound[1] uuid], tlk.uuid, "Should received TLK UUID");
+    XCTAssertEqualObjects([whereFound[0] uuid], wrappedKey.uuid, "Should received wrapped key UUID");
 }
 
 - (void)testGroupBy {
index acc1818d8a240b515b22342f367468310d94c3fc..2e800d889377e938a96934ef83582cb2a133c7c7 100644 (file)
     self.keychainZone.currentDatabase[self.keychainZoneKeys.currentClassCPointer.storedCKRecord.recordID][SecCKRecordParentKeyRefKey] = oldClassCKey;
     self.keychainZoneKeys.currentClassCPointer.currentKeyUUID = oldClassCKey.recordID.recordName;
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     // CKKS should then fix the pointers and give itself a new TLK share record, but not update any keys
     [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:1 tlkShareRecords:1 zoneID:self.keychainZoneID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // And then upload the item as usual
     [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
 
     [self saveTLKMaterialToKeychain:self.keychainZoneID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // And then use the 'new' key as it should
index 67b08ac5331afb68f5675c7981057af3e042e9c1..d22c68aeb9b2db5b6d50549fc34ab0d888061f7d 100644 (file)
@@ -27,6 +27,7 @@
 #import "keychain/ckks/CKKS.h"
 #import "keychain/ckks/CKKSKey.h"
 #import "keychain/ckks/CKKSTLKShareRecord.h"
+#import "keychain/ckks/CKKSSQLDatabaseObject.h"
 #import "keychain/ckks/CKKSPeer.h"
 #import "keychain/ckks/tests/CloudKitMockXCTest.h"
 
                                                        viewList:self.managedViewList];
     XCTAssertNotNil(self.localPeer, "Should be able to make a new local peer");
 
-    self.remotePeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote"
+    self.remotePeer = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote1"
                                                    encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
                                                       signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
                                                         viewList:self.managedViewList];
     XCTAssertNotNil(self.remotePeer, "Should be able to make a new remote peer");
 
-    self.remotePeer2 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote"
+    self.remotePeer2 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote2"
                                                     encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
                                                        signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
                                                          viewList:self.managedViewList];
                                         error:&error];
     XCTAssertNil(error, "Should have been no error sharing a CKKSKey");
 
-    [share saveToDatabase:&error];
-    XCTAssertNil(error, "Shouldn't be an error saving a TLKShare record to the database");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [share saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "Shouldn't be an error saving a TLKShare record to the database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSTLKShareRecord* loadedShare = [CKKSTLKShareRecord fromDatabase:self.tlk.uuid
                                             receiverPeerID:self.remotePeer.peerID
     XCTAssertEqualObjects(share, fromCKRecord, "TLK shares sent through CloudKit should be identical");
 }
 
+- (void)testKeyExtractFromTrustState {
+    NSError* error = nil;
+    CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
+                                           as:self.remotePeer
+                                           to:self.localPeer
+                                        epoch:-1
+                                     poisoned:0
+                                        error:&error];
+    XCTAssertNotNil(share, "Should have a TLKShare");
+    XCTAssertNil(error, "Should have been no error sharing a CKKSKey from a remote peer to a local peer");
+
+    CKKSPeerProviderState* trustState = [[CKKSPeerProviderState alloc] initWithPeerProviderID:@"test-provider"
+                                                                                    essential:YES
+                                                                                    selfPeers:[[CKKSSelves alloc] initWithCurrent:self.localPeer allSelves:nil]
+                                                                               selfPeersError:nil
+                                                                                 trustedPeers:[NSSet setWithArray:@[
+                                                                                     self.localPeer,
+                                                                                     self.remotePeer,
+                                                                                     self.remotePeer2,
+                                                                                 ]]
+                                                                            trustedPeersError:nil];
+    CKKSKey* shareExtraction = [share recoverTLK:self.localPeer
+                                    trustedPeers:trustState.currentTrustedPeers
+                                           error:&error];
+    XCTAssertNotNil(shareExtraction, "Should be able to recover the share from the currently trusted peers");
+    XCTAssertNil(error, "Should be no error extracting TLK");
+
+    BOOL extracted = [trustState unwrapKey:self.tlk
+                                fromShares:@[share]
+                                     error:&error];
+
+    XCTAssertTrue(extracted, "Should be able to extract the TLK via a share");
+    XCTAssertNil(error, "Should be no error extracting TLK");
+
+    CKKSPeerProviderState* remotePeer2TrustState = [[CKKSPeerProviderState alloc] initWithPeerProviderID:@"test-provider"
+                                                                                               essential:YES
+                                                                                               selfPeers:[[CKKSSelves alloc] initWithCurrent:self.remotePeer2 allSelves:nil]
+                                                                                          selfPeersError:nil
+                                                                                            trustedPeers:[NSSet setWithArray:@[
+                                                                                                self.localPeer,
+                                                                                                self.remotePeer,
+                                                                                                self.remotePeer2,
+                                                                                            ]]
+                                                                                       trustedPeersError:nil];
+
+    BOOL remotePeerExtracted = [remotePeer2TrustState unwrapKey:self.tlk
+                                                     fromShares:@[share]
+                                                          error:&error];
+    XCTAssertFalse(remotePeerExtracted, "Should not be able to extract the TLK if there's no share to the self peer");
+    XCTAssertNotNil(error, "Should be an error when failing to extract TLK");
+}
+
 - (void)testKeyShareSignExtraFieldsInCKRecord {
     NSError* error = nil;
     CKKSTLKShareRecord* share = [CKKSTLKShareRecord share:self.tlk
     // And verify that saving to disk and reloading is successful
     share2.storedCKRecord = record;
     XCTAssert([share2 verifySignature:share2.signature verifyingPeer:self.localPeer error:&error], "Signature with extra data should verify");
-    [share2 saveToDatabase:&error];
-    XCTAssertNil(error, "No error saving share2 to database");
+
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* saveError = nil;
+        [share2 saveToDatabase:&saveError];
+        XCTAssertNil(saveError, "No error saving share2 to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
 
     CKKSTLKShareRecord* loadedShare2 = [CKKSTLKShareRecord tryFromDatabaseFromCKRecordID:record.recordID error:&error];
     XCTAssertNil(error, "No error loading loadedShare2 from database");
index ece1aebdf43915d868ea5e0d5809e8e8af077a62..1c2cb8025c887f469bebe43b4e7801a4673a8be9 100644 (file)
 
     // Verify that there are three local keys, and three local current key records
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         NSArray<CKKSCurrentKeyPointer*>* currentkeys = [CKKSCurrentKeyPointer all:&error];
         XCTAssertNil(error, "no error fetching current keys");
         XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database");
-
-        return false;
     }];
 }
 
 
     // Verify that there are three local keys, and three local current key records
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         NSArray<CKKSCurrentKeyPointer*>* currentkeys = [CKKSCurrentKeyPointer all:&error];
         XCTAssertNil(error, "no error fetching current keys");
         XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database");
-
-        return false;
     }];
 }
 
 
     // Verify that making a new share will have the old share's change tag
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSyncWithAccountKeys: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         XCTAssertNotNil(cloudKitRecord.recordChangeTag, "Existing record should have a change tag");
 
         XCTAssertEqualObjects(cloudKitRecord.recordChangeTag, newRecord.recordChangeTag, "Change tags on existing and new records should match");
-
-        return false;
     }];
 }
 
     CKRecord* shareCKRecord = [share CKRecordWithZoneID: self.keychainZoneID];
     XCTAssertNotNil(shareCKRecord, "Should have been able to create a CKRecord");
     [self.keychainZone addToZone:shareCKRecord];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* blockerror = nil;
         CKKSTLKShareRecord* localshare = [CKKSTLKShareRecord tryFromDatabaseFromCKRecordID:shareCKRecord.recordID error:&blockerror];
         XCTAssertNil(blockerror, "Shouldn't error finding TLKShare record in database");
         XCTAssertNotNil(localshare, "Should be able to find a TLKShare record in database");
-        return true;
     }];
 
     // Delete the record in CloudKit...
     [self.keychainZone deleteCKRecordIDFromZone:shareCKRecord.recordID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Should be gone now.
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* blockerror = nil;
         CKKSTLKShareRecord* localshare = [CKKSTLKShareRecord tryFromDatabaseFromCKRecordID:shareCKRecord.recordID error:&blockerror];
 
         XCTAssertNil(blockerror, "Shouldn't error trying to find non-existent TLKShare record in database");
         XCTAssertNil(localshare, "Shouldn't be able to find a TLKShare record in database");
-
-        return true;
     }];
 }
 
     [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID];
 
     [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:self.remotePeer1 zoneID:self.keychainZoneID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
     [self waitForCKModifications];
 
     // Now, delete all the TLK Shares, so CKKS will upload them again
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         [CKKSTLKShareRecord deleteAll:self.keychainZoneID error:&error];
         XCTAssertNil(error, "Shouldn't be an error deleting all TLKShares");
             }
         }
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // Restart. We expect an upload of 3 TLK shares.
     [self expectCKModifyKeyRecords: 0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID];
 
     // Trigger a notification
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self saveTLKMaterialToKeychain:self.keychainZoneID];
 
     // Trigger a notification
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
 
     // The CKKS subsystem should go into waitfortlk, since it doesn't trust this peer, but the peer is active
     [self startCKKSSubsystem];
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "Key state should become ready");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], "Key state should become waitfortlk");
 }
 
 - (void)testAcceptSharedTLKOnTrustSetAdditionOfSharer {
 
     // step 2: add a new peer who already has a share; no share should be created
     [self putTLKShareInCloudKit:self.keychainZoneKeys.tlk from:self.remotePeer1 to:self.remotePeer2 zoneID:self.keychainZoneID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // CKKS should not upload a tlk share for this peer
                }];
 
     [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:self.remotePeer1 zoneID:self.keychainZoneID];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
 
     NSMutableArray<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* keysetOps = [NSMutableArray array];
     for(CKKSKeychainView* view in self.ckksViews) {
         XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:40*NSEC_PER_SEC], @"key state should enter 'waitfortlkcreation' (view %@)", view);
-        [keysetOps addObject: [view findKeySet]];
+        [keysetOps addObject: [view findKeySet:NO]];
     }
 
     // Now that we've kicked them all off, wait for them to not crash
     [self.keychainView endTrustedOperation];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], "Key state should become 'waitfortrust'");
 
-    [self.keychainView beginTrustedOperation:@[self.mockSOSAdapter, brokenAdapter] suggestTLKUpload:self.suggestTLKUpload];
+    [self.keychainView beginTrustedOperation:@[self.mockSOSAdapter, brokenAdapter]
+                            suggestTLKUpload:self.suggestTLKUpload
+                          requestPolicyCheck:self.requestPolicyCheck];
 
     // CKKS should ignore the non-essential and broken peer adapter
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become 'ready'");
 
     // Spin up Octagon. We expect an upload of 3 TLK shares, this time for the octagon peer
     [self expectCKModifyKeyRecords: 0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID];
-    [self.keychainView beginTrustedOperation:@[self.mockSOSAdapter, self.mockOctagonAdapter] suggestTLKUpload:self.suggestTLKUpload];
+    [self.keychainView beginTrustedOperation:@[self.mockSOSAdapter, self.mockOctagonAdapter]
+                            suggestTLKUpload:self.suggestTLKUpload
+                          requestPolicyCheck:self.requestPolicyCheck];
     [self.mockOctagonAdapter sendTrustedPeerSetChangedUpdate];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
 }
 
+- (void)testQuiesceOnTrustLossDuringInitialFetch {
+    // Test starts with no keys in CKKS database, but one in our fake CloudKit.
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:self.remotePeer1 zoneID:self.keychainZoneID];
+
+    [self holdCloudKitFetches];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateFetch] wait:20*NSEC_PER_SEC], "Key state should become 'fetch'");
+
+    [self endSOSTrustedOperationForAllViews];
+
+    [self releaseCloudKitFetchHold];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], "Key state should become 'waitfortrust'");
+}
+
 @end
 
 #endif // OCTAGON
index 10235c423cdd612e8ec90ce389fc451210dab21d..18e3f5881be1d6e7449c8950406993114a9a78e4 100644 (file)
     [self waitForCKModifications];
     OCMVerifyAllWithDelay(self.mockDatabase, 40);
 
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     self.keychainView.holdOutgoingQueueOperation = [CKKSGroupOperation named:@"outgoing-hold" withBlock: ^{
-        secnotice("ckks", "releasing outgoing-queue hold");
+        ckksnotice_global("ckks", "releasing outgoing-queue hold");
     }];
 
     for(size_t count = 0; count < 150; count++) {
         [blockExpectation fulfill];
     }), @"_SecItemAddAndNotifyOnSync succeeded");
 
-    // Release the hounds
-    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
 
     XCTestExpectation* firstQueueOperation = [self expectationWithDescription: @"found the item in the first queue iteration"];
     [self expectCKModifyItemRecords:SecCKKSOutgoingQueueItemsAtOnce
     }];
     [self expectCKModifyItemRecords:51 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
 
-    [self waitForExpectationsWithTimeout:5.0 handler:nil];
+    // Release the hounds
+    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
+
+    [self waitForExpectations:@[blockExpectation, firstQueueOperation] timeout:20];
+    OCMVerifyAllWithDelay(self.mockDatabase, 10);
 }
 
 - (void)testAddAndNotifyOnSyncFailure {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
     [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Due to item UUID selection, this item will be added with UUID 50184A35-4480-E8BA-769B-567CF72F1EC0.
 
     [self startCKKSSubsystem];
     XCTAssertEqual(0, [self.keychainView.loggedIn wait:20*NSEC_PER_SEC], "CKKS should log in");
-    [self.keychainView.zoneSetupOperation waitUntilFinished];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateFetch] wait:20*NSEC_PER_SEC], @"Should have reached key state 'fetch', but no further");
 
     NSMutableDictionary* query = [@{
                                     (id)kSecClass : (id)kSecClassGenericPassword,
     // When the policy is loaded, the item should upload and the callback should fire
     [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
 
-    [self.injectedManager setSyncingViews:self.managedViewList sortingPolicy:self.viewSortingPolicyForManagedViewList];
+    [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
     self.keychainView = [self.injectedManager findView:self.keychainZoneID.zoneName];
 
     [self.injectedManager beginCloudKitOperationOfAllViews];
     [self waitForExpectations:@[blockExpectation] timeout:5];
 }
 
+- (void)testAddAndNotifyOnSyncReaddAtSameUUIDAfterDeleteItem {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; // Make life easy for this test.
+
+    __block CKRecordID* itemRecordID = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemRecordID = record.recordID;
+        return YES;
+    }];
+
+    [self startCKKSSubsystem];
+
+    // Let things shake themselves out.
+    [self.keychainView waitForKeyHierarchyReadiness];
+    [self waitForCKModifications];
+
+    NSMutableDictionary* query = [@{
+                                    (id)kSecClass : (id)kSecClassGenericPassword,
+                                    (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+                                    (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
+                                    (id)kSecAttrAccount : @"testaccount",
+                                    (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+                                    (id)kSecAttrSyncViewHint : self.keychainView.zoneName,
+                                    (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding],
+                                    } mutableCopy];
+
+    XCTestExpectation* blockExpectation = [self expectationWithDescription: @"callback occurs"];
+
+    XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, NULL, ^(bool didSync, CFErrorRef error) {
+        XCTAssertTrue(didSync, "Item synced properly");
+        XCTAssertNil((__bridge NSError*)error, "No error syncing item");
+
+        [blockExpectation fulfill];
+    }), @"_SecItemAddAndNotifyOnSync succeeded");
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 10);
+
+    [self waitForExpectations:@[blockExpectation] timeout:5];
+
+    // And the item is deleted
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+    [self deleteGenericPassword:@"testaccount"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the item is readded. It should come back to its previous UUID.
+    XCTAssertNotNil(itemRecordID, "Should have an item record ID");
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        XCTAssertEqualObjects(itemRecordID.recordName, record.recordID.recordName, "Uploaded item UUID should match previous upload");
+        return YES;
+    }];
+    XCTestExpectation* blockExpectation2 = [self expectationWithDescription: @"callback occurs"];
+    XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, NULL, ^(bool didSync, CFErrorRef error) {
+        XCTAssertTrue(didSync, "Item synced properly");
+        XCTAssertNil((__bridge NSError*)error, "No error syncing item");
+
+        [blockExpectation2 fulfill];
+    }), @"_SecItemAddAndNotifyOnSync succeeded");
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 10);
+    [self waitForExpectations:@[blockExpectation2] timeout:5];
+}
+
 - (void)testPCSUnencryptedFieldsAdd {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
     [self.keychainZone addToZone: record];
 
     // Trigger a notification
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     CFTypeRef item = NULL;
 
     [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword,
 
     [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword,
     [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
     [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID];
 
-    // Spin up CKKS subsystem.
+    // Spin up CKKS subsystem. It should fetch once.
+    [self expectCKFetch];
     [self startCKKSSubsystem];
 
     XCTAssertEqual(0, [self.keychainView.loggedIn wait:500*NSEC_PER_MSEC], "Should have been told of a 'login' event on startup");
 
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should arrive at 'waitfortrust''");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
     NSData* changeTokenData = [[[NSUUID UUID] UUIDString] dataUsingEncoding:NSUTF8StringEncoding];
     CKServerChangeToken* changeToken = [[CKServerChangeToken alloc] initWithData:changeTokenData];
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.keychainView.zoneName];
         ckse.changeToken = changeToken;
 
         NSError* error = nil;
         [ckse saveToDatabase:&error];
         XCTAssertNil(error, "No error saving new zone state to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // after the reset, CKKS should refetch what's available
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"local reset callback occurs"];
     [self.injectedManager rpcResetLocal:nil reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting local");
-        secnotice("ckks", "Received a rpcResetLocal callback");
+        ckksnotice_global("ckks", "Received a rpcResetLocal callback");
 
-        [self.keychainView dispatchSync: ^bool{
+        [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
             CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry state:self.keychainView.zoneName];
             XCTAssertNotEqualObjects(changeToken, ckse.changeToken, "Change token is reset");
-            return true;
         }];
 
         [resetExpectation fulfill];
     [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
     [self beginSOSTrustedViewOperation:self.keychainView];
 
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at 'ready''");
+
     [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"
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testResetLocalWhileLoggedOut {
+    self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
+    self.accountStatus = CKAccountStatusNoAccount;
+    [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
+    self.silentFetchesAllowed = false;
+
+    // Test starts with local TLK and key hierarchy in our fake cloudkit
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.loggedOut wait:20*NSEC_PER_SEC], "CKKS should positively log out");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], @"Key state should arrive at 'loggedout'");
+
+    // Can we reset local data while logged out?
+    XCTestExpectation* resetExpectation = [self expectationWithDescription: @"local reset callback occurs"];
+    [self.injectedManager rpcResetLocal:nil reply:^(NSError* result) {
+        XCTAssertNil(result, "no error resetting local");
+        ckksnotice_global("ckks", "Received a rpcResetLocal callback");
+
+        [resetExpectation fulfill];
+    }];
+
+    [self waitForExpectations:@[resetExpectation] timeout:20];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], @"Key state should arrive at 'loggedout'");
+}
+
 -(void)testResetLocalMultipleTimes {
     // Test starts with nothing in database, but one in our fake CloudKit.
     [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
     [self addGenericPassword: @"data" account: @"account-delete-me"];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self waitForCKModifications];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
 
     // During the reset, Octagon will upload the key hierarchy, and then CKKS will upload the class C item
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
                    expecting:errSecSuccess
                      message:@"Adding class A item"];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
 }
 
 - (void)testResetCloudKitZoneCloudKitRejects {
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
 
     [self waitForExpectations:@[resetExpectation] timeout:20];
 
-    XCTAssertTrue([outgoingOp isCancelled], "old stuck ProcessOutgoingQueue should be cancelled");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // And adding another item works too
                    expecting:errSecSuccess
                      message:@"Adding class A item"];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertTrue([outgoingOp isFinished], "old ProcessOutgoingQueue should be finished");
 }
 
 /*
     XCTAssertNotNil(self.keychainZone.currentDatabase, "Zone exists");
     XCTAssertNotNil(self.keychainZone.currentDatabase[ckr.recordID], "An item exists in the fake zone");
 
+    // Make the zone, so we know if it was deleted
+    self.keychainZone.flag = true;
+
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
     [self waitForExpectations:@[resetExpectation] timeout:20];
 
-    XCTAssertNil(self.keychainZone.currentDatabase, "No zone anymore!");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], "CKKS entered 'waitfortlkcreation'");
+
+    XCTAssertFalse(self.keychainZone.flag, "Zone was deleted at some point");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Now log in, and see what happens! It should create the zone again and upload a whole new key hierarchy
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testRPCKnownBadStateWhenNoCloudKit {
+    self.accountStatus = CKAccountStatusNoAccount;
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered loggedout");
+
+    XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+
+    [self.ckksControl rpcKnownBadState:@"keychain" reply:^(CKKSKnownBadState result) {
+        XCTAssertEqual(result, CKKSKnownStateNoCloudKitAccount, "State should be 'no cloudkit account'");
+        [callbackOccurs fulfill];
+    }];
+
+    [self waitForExpectations:@[callbackOccurs] timeout:20];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testRPCKnownBadStateWhenNoTrust {
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
+
+    self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
+    [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], "CKKS entered waitfortrust");
+
+    XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+
+    [self.ckksControl rpcKnownBadState:@"keychain" reply:^(CKKSKnownBadState result) {
+        XCTAssertEqual(result, CKKSKnownStateWaitForOctagon, "State should be 'waitforoctagon'");
+        [callbackOccurs fulfill];
+    }];
+
+    [self waitForExpectations:@[callbackOccurs] timeout:20];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
 - (void)testRPCKnownBadStateWhenTLKsMissing {
     // Bring CKKS up in waitfortlk
     [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
 - (void)testRpcStatusIsFastDuringError {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
-    self.keychainFetchError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInternalError description:@"injected keychain failure"];
-
-    // Let CKKS come up; it should enter 'error'
+    // Let CKKS come up, then force it into error
     [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+
+    OctagonStateTransitionOperation* op = [OctagonStateTransitionOperation named:@"enter" entering:SecCKKSZoneKeyStateError];
+    OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"enter-wait-for-trust"
+                                                                            sourceStates:[NSSet setWithArray:[CKKSZoneKeyStateMap() allKeys]]
+                                                                             serialQueue:self.keychainView.queue
+                                                                                 timeout:10 * NSEC_PER_SEC
+                                                                            transitionOp:op];
+    [self.keychainView.stateMachine handleExternalRequest:request];
+
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateError] wait:20*NSEC_PER_SEC], "CKKS entered 'error'");
 
     // Fire off the status RPC; it should return immediately
     [self waitForExpectations:@[callbackOccurs] timeout:20];
 }
 
+- (void)testResetLocalAPIWakesDaemon {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:[self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+
+    // Now, simulate a restart: all views suddenly go missing from the ViewManager
+    [self.injectedManager clearAllViews];
+    [self.injectedManager resetSyncingPolicy];
+    [self.injectedManager beginCloudKitOperationOfAllViews];
+
+    // And a reset-local API call wakes the daemon
+    // The policy arrives after 500ms
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
+        [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
+        self.ckksViews = [NSMutableSet setWithArray:[self.injectedManager.views allValues]];
+        self.keychainView = [self.injectedManager findView:@"keychain"];
+        [self beginSOSTrustedOperationForAllViews];
+    });
+
+    XCTestExpectation* resetExpectation = [self expectationWithDescription: @"local reset callback occurs"];
+    [self.injectedManager rpcResetLocal:self.keychainZoneID.zoneName reply:^(NSError* result) {
+        XCTAssertNil(result, "no error resetting local");
+        [resetExpectation fulfill];
+    }];
+
+    [self waitForExpectations:@[resetExpectation] timeout:20];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testPushAPIWakesDaemon {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:[self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+
+    // Now, simulate a restart: all views suddenly go missing from the ViewManager
+    [self.injectedManager clearAllViews];
+    [self.injectedManager resetSyncingPolicy];
+    [self.injectedManager beginCloudKitOperationOfAllViews];
+
+    // And a fetch API call wakes the daemon
+    // The policy arrives after 500msx
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
+        [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
+        self.ckksViews = [NSMutableSet setWithArray:[self.injectedManager.views allValues]];
+        [self beginSOSTrustedOperationForAllViews];
+    });
+
+    XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+    [self.ckksControl rpcPushOutgoingChanges:nil reply:^(NSError * _Nullable error) {
+        XCTAssertNil(error, "Should have received no error");
+        [callbackOccurs fulfill];
+    }];
+
+    [self waitForExpectations:@[callbackOccurs] timeout:60];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testFetchAPIWakesDaemon {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:[self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+
+    // Now, simulate a restart: all views suddenly go missing from the ViewManager
+    [self.injectedManager clearAllViews];
+    [self.injectedManager resetSyncingPolicy];
+    [self.injectedManager beginCloudKitOperationOfAllViews];
+
+    // And a fetch API call wakes the daemon
+    // The policy arrives after 500ms
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0.5 * NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
+        [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
+        self.ckksViews = [NSMutableSet setWithArray:[self.injectedManager.views allValues]];
+        [self beginSOSTrustedOperationForAllViews];
+    });
+
+    XCTestExpectation* callbackOccurs = [self expectationWithDescription:@"callback-occurs"];
+    [self.ckksControl rpcFetchAndProcessChanges:nil reply:^(NSError * _Nullable error) {
+        XCTAssertNil(error, "Should have received no error");
+        [callbackOccurs fulfill];
+    }];
+
+    [self waitForExpectations:@[callbackOccurs] timeout:20];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
 @end
 
 #endif // OCTAGON
index b49644417dd0517da57ca807acb466cf0a5f4c83..1006a9e8d79dc2268bb3b7f7a950e20cf755d68e 100644 (file)
     [self waitForCKModifications];
 
     // Okay, now the delete/add. Note that this is not a coalescing operation, since the new item
-    // will have a completely different UUID, and so will delete the old record and upload the new one.
+    // has different contents. (This test used to upload the item to a different UUID, but no longer).
+
+    self.keychainView.holdOutgoingQueueOperation = [CKKSResultOperation named:@"hold-outgoing-queue"
+                                                                    withBlock:^{}];
 
-    [self.keychainView.operationQueue waitUntilAllOperationsAreFinished];
-    self.keychainView.operationQueue.suspended = YES;
     [self deleteGenericPassword: account];
-    [self addGenericPassword: @"data" account: account];
+    [self addGenericPassword: @"data_new_contents" account: account];
+
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID
+                          checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"data_new_contents"]];
 
-    [self expectCKModifyRecords:@{SecCKRecordItemType: [NSNumber numberWithUnsignedInteger: 1],
-                                  SecCKRecordCurrentKeyType: [NSNumber numberWithUnsignedInteger: 1],
-                                  SecCKRecordDeviceStateType: [NSNumber numberWithUnsignedInteger: 1],
-                                  }
-        deletedRecordTypeCounts:@{SecCKRecordItemType: [NSNumber numberWithUnsignedInteger: 1]}
-                         zoneID:self.keychainZoneID
-            checkModifiedRecord:nil
-           runAfterModification:nil];
-    self.keychainView.operationQueue.suspended = NO;
+    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testCoalesceReceiveModifyWhileDeletingItem {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+
+    NSString* account = @"account-delete-me";
+
+    [self addGenericPassword:@"data" account:account];
+
+    // We expect a single record to be uploaded.
+    __block CKRecord* itemRecord = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID
+                          checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemRecord = record;
+        return YES;
+    }];
+
+    [self startCKKSSubsystem];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self waitForCKModifications];
+
+    // Now, we receive a modification from CK, but then delete the item locally before processing the IQE.
+
+    XCTAssertNotNil(itemRecord, "Should have a record for the uploaded item");
+    NSMutableDictionary* contents = [[self decryptRecord:itemRecord] mutableCopy];
+    contents[@"v_Data"] = [@"updated" dataUsingEncoding:NSUTF8StringEncoding];
+
+    CKRecord* recordUpdate = [self newRecord:itemRecord.recordID withNewItemData:contents];
+    [self.keychainZone addCKRecordToZone:recordUpdate];
+
+    self.keychainView.holdIncomingQueueOperation = [NSBlockOperation blockOperationWithBlock:^{}];
+
+    // Ensure we wait for the whole fetch
+    NSOperation* fetchOp = [self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+
+    [fetchOp waitUntilFinished];
+
+    // now, delete the item
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+    [self deleteGenericPassword:account];
+
+    [self.operationQueue addOperation:self.keychainView.holdIncomingQueueOperation];
+
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the item shouldn't be present, since it was deleted via API after the item was fetched
+    [self findGenericPassword:account expecting:errSecItemNotFound];
+}
+
+- (void)testCoalesceReceiveDeleteWhileModifyingItem {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+
+    NSString* account = @"account-delete-me";
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+
+    __block CKRecord* itemRecord = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID
+                          checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemRecord = record;
+        return YES;
+    }];
+
+    [self addGenericPassword:@"data" account:account];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self waitForCKModifications];
+
+    // Ensure we fetch again, to prime the delete (due to insufficient mock CK)
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    // Now, we receive a delete from CK, but after we modify the item locally
+    self.keychainView.holdOutgoingQueueOperation = [NSBlockOperation blockOperationWithBlock:^{}];
+
+    XCTAssertNotNil(itemRecord, "Should have an item record from the upload");
+    [self.keychainZone deleteCKRecordIDFromZone:itemRecord.recordID];
+    [self updateGenericPassword:@"new-password" account:account];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self findGenericPassword:account expecting:errSecItemNotFound];
+
+    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
+
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the item shouldn't be present, since it was deleted via CK after the API change
+    [self findGenericPassword:account expecting:errSecItemNotFound];
+}
+
 @end
 
 #endif
index e2b7c7537c09847304e12eed0d7d72ed2e07cc55..e740a001322414d869f03af9ab8f064a40f949a1 100644 (file)
     CFReleaseNull(cfresult);
 
     if(![actualSHA1 isEqual:sha1]) {
-        secnotice("ckks", "SHA1s don't match, but why?");
+        ckksnotice_global("ckks", "SHA1s don't match, but why?");
     }
 
     XCTestExpectation* otherSetCurrentExpectation = [self expectationWithDescription: @"callback occurs"];
     // Ensure that receiving the current item pointer generates a notification
     keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self waitForExpectations:@[keychainChanged] timeout:8];
 
     keychainChanged = [self expectChangeForView:self.keychainZoneID.zoneName];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self waitForExpectations:@[keychainChanged] timeout:8];
     CKRecord* currentPointerRecord = self.keychainZone.currentDatabase[currentPointerRecordID];
     XCTAssertNotNil(currentPointerRecord, "Found record in CloudKit at expected UUID");
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self fetchCurrentPointer:false persistentRef:persistentRef];
 
     // Another machine comes along and deletes the pointer!
     [self.keychainZone deleteCKRecordIDFromZone: currentPointerRecordID];
-    [self.keychainView notifyZoneChange:nil];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
     [self waitForExpectations:@[keychainChanged] timeout:8];
 
     modifiedRecord[SecCKRecordServerWasCurrent] = [NSNumber numberWithInteger:10];
     [self.keychainZone addToZone:modifiedRecord];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Check that the number is on the CKKSMirrorEntry
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase:@"50184A35-4480-E8BA-769B-567CF72F1EC0" zoneID:self.keychainZoneID error:&error];
 
         XCTAssertNotNil(ckme, "Received a ckme");
 
         XCTAssertEqual(ckme.wasCurrent, 10u, "Properly received wasCurrent");
-
-        return true;
     }];
 }
 
     [self.keychainZone addToZone: mismatchedRecord];
 
     self.keychainView.holdIncomingQueueOperation = [CKKSResultOperation named:@"hold-incoming" withBlock:^{
-        secnotice("ckks", "Releasing process incoming queue hold");
+        ckksnotice_global("ckks", "Releasing process incoming queue hold");
     }];
 
     NSData* firstItemData = [@"asdf" dataUsingEncoding:NSUTF8StringEncoding];
     [self waitForExpectations:@[setCurrentExpectation] timeout:20];
 
     // Reissue a fetch and find the new persistent ref and sha1 for the item at this UUID
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // The conflicting item update should have won
diff --git a/keychain/ckks/tests/CKKSTests+ForwardCompatibility.m b/keychain/ckks/tests/CKKSTests+ForwardCompatibility.m
new file mode 100644 (file)
index 0000000..2682468
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2020 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 <CloudKit/CloudKit.h>
+#import <XCTest/XCTest.h>
+#import <OCMock/OCMock.h>
+
+#import <TrustedPeers/TrustedPeers.h>
+#import <TrustedPeers/TPPBPolicyKeyViewMapping.h>
+#import <TrustedPeers/TPDictionaryMatchingRules.h>
+
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ckks/CKKS.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CloudKitCategories.h"
+#import "keychain/ckks/tests/CKKSTests.h"
+#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h"
+#import "keychain/ckks/tests/CloudKitMockXCTest.h"
+#import "keychain/ckks/tests/MockCloudKit.h"
+
+@interface CloudKitKeychainForwardCompatibilityTests : CloudKitKeychainSyncingTestsBase
+@property CKRecordZoneID* unknownZoneID;
+@property CKRecordZoneID* passwordsZoneID;
+@property CKKSKeychainView* passwordsView;
+
+@property TPSyncingPolicy* originalPolicy;
+@property TPSyncingPolicy* originalPolicyPlusUnknownVwht;
+@property TPSyncingPolicy* allItemsToPasswordsPolicy;
+@end
+
+@implementation CloudKitKeychainForwardCompatibilityTests
+
+- (void)setUp {
+    [super setUp];
+
+    self.passwordsZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Passwords" ownerName:CKCurrentUserDefaultName];
+    self.unknownZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"unknown-zone" ownerName:CKCurrentUserDefaultName];
+
+    self.zones[self.passwordsZoneID] = [[FakeCKZone alloc] initZone:self.passwordsZoneID];
+
+    self.originalPolicy = self.viewSortingPolicyForManagedViewList;
+
+
+    NSMutableArray<TPPBPolicyKeyViewMapping*>* newRules = [self.originalPolicy.keyViewMapping mutableCopy];
+    TPPBPolicyKeyViewMapping* unknownVwhtMapping = [[TPPBPolicyKeyViewMapping alloc] init];
+    unknownVwhtMapping.view = self.keychainZoneID.zoneName;
+    unknownVwhtMapping.matchingRule = [TPDictionaryMatchingRule fieldMatch:@"vwht"
+                                                                fieldRegex:[NSString stringWithFormat:@"^%@$", self.unknownZoneID.zoneName]];
+    [newRules insertObject:unknownVwhtMapping atIndex:0];
+
+    self.originalPolicyPlusUnknownVwht = [[TPSyncingPolicy alloc] initWithModel:@"test-policy"
+                                                                        version:[[TPPolicyVersion alloc] initWithVersion:2 hash:@"fake-policy-for-views-with-unknown-view"]
+                                                                       viewList:self.originalPolicy.viewList
+                                                          userControllableViews:self.originalPolicy.userControllableViews
+                                                      syncUserControllableViews:self.originalPolicy.syncUserControllableViews
+                                                           viewsToPiggybackTLKs:self.originalPolicy.viewsToPiggybackTLKs
+                                                                 keyViewMapping:newRules];
+
+    TPPBPolicyKeyViewMapping* passwordsVwhtMapping = [[TPPBPolicyKeyViewMapping alloc] init];
+    passwordsVwhtMapping.view = self.passwordsZoneID.zoneName;
+    passwordsVwhtMapping.matchingRule = [TPDictionaryMatchingRule trueMatch];
+
+    self.allItemsToPasswordsPolicy = [[TPSyncingPolicy alloc] initWithModel:@"test-policy"
+                                                                    version:[[TPPolicyVersion alloc] initWithVersion:2 hash:@"fake-policy-for-views-with-passwords-view"]
+                                                                   viewList:[NSSet setWithArray:@[self.keychainView.zoneName, self.passwordsZoneID.zoneName]]
+                                                      userControllableViews:self.originalPolicy.userControllableViews
+                                                  syncUserControllableViews:self.originalPolicy.syncUserControllableViews
+                                                       viewsToPiggybackTLKs:self.originalPolicy.viewsToPiggybackTLKs
+                                                             keyViewMapping:@[passwordsVwhtMapping]];
+}
+
+- (void)setPolicyAndWaitForQuiescence:(TPSyncingPolicy*)policy policyIsFresh:(BOOL)policyIsFresh {
+    [self.injectedManager setCurrentSyncingPolicy:policy policyIsFresh:policyIsFresh];
+    self.ckksViews = [NSMutableSet setWithArray:[[self.injectedManager views] allValues]];
+    [self beginSOSTrustedOperationForAllViews];
+
+    // And wait for everything to enter a resting state
+    for(CKKSKeychainView* view in self.ckksViews) {
+        XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+        [view waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+        [view waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    }
+}
+
+- (void)testReceiveItemForWrongView {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    NSString* wrongZoneAccount = @"wrong-zone";
+    NSDictionary* item = [self fakeRecordDictionary:wrongZoneAccount zoneID:self.unknownZoneID];
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:item];
+    [self.keychainZone addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    [self findGenericPassword:wrongZoneAccount expecting:errSecItemNotFound];
+
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+
+    NSError* zoneError = nil;
+    NSInteger count = [CKKSIncomingQueueEntry countByState:SecCKKSStateMismatchedView zone:self.keychainView.zoneID error:&zoneError];
+    XCTAssertNil(zoneError, "should be no error counting all IQEs");
+    XCTAssertEqual(count, 1, "Should be one mismatched IQE");
+}
+
+- (void)testConflictingItemInWrongView {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+    self.passwordsView = [self.injectedManager findView:@"Passwords"];
+    XCTAssertNotNil(self.passwordsView, @"Policy created a passwords view");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+    XCTAssertEqual(0, [self.passwordsView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    NSDictionary* item = [self fakeRecordDictionary:@"account-delete-me" zoneID:self.passwordsZoneID];
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.passwordsZoneID];
+    CKRecordID* ckr2id = [[CKRecordID alloc] initWithRecordName:@"FFFF8D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:item];
+
+    NSMutableDictionary* item2 = [item mutableCopy];
+    item2[@"v_Data"] = @"wrongview";
+    CKRecord* ckr2 = [self newRecord:ckr2id withNewItemData:item2];
+
+    // Receive the passwords item first
+    [self.zones[self.passwordsZoneID] addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.passwordsView waitForFetchAndIncomingQueueProcessing];
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    [self.zones[self.keychainZoneID] addToZone:ckr2];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // THe view should ask for an update, and receive one
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    // And we have ignored the change in the other view
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the item is then deleted
+    [self.zones[self.keychainZoneID] deleteCKRecordIDFromZone:ckr2id];
+    OCMExpect([self.requestPolicyCheck trigger]);
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    // The password should still exist
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+}
+
+- (void)testConflictingItemInWrongViewWithLowerUUID {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+    self.passwordsView = [self.injectedManager findView:@"Passwords"];
+    XCTAssertNotNil(self.passwordsView, @"Policy created a passwords view");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+    XCTAssertEqual(0, [self.passwordsView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    NSDictionary* item = [self fakeRecordDictionary:@"account-delete-me" zoneID:self.passwordsZoneID];
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.passwordsZoneID];
+    CKRecordID* ckr2id = [[CKRecordID alloc] initWithRecordName:@"00008D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:item];
+
+    NSMutableDictionary* item2 = [item mutableCopy];
+    item2[@"v_Data"] = @"wrongview";
+    CKRecord* ckr2 = [self newRecord:ckr2id withNewItemData:item2];
+
+    // Receive the passwords item first
+    [self.zones[self.passwordsZoneID] addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.passwordsView waitForFetchAndIncomingQueueProcessing];
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    [self.zones[self.keychainZoneID] addToZone:ckr2];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // THe view should ask for an update, and receive one
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    // And the item is then deleted
+    [self.zones[self.keychainZoneID] deleteCKRecordIDFromZone:ckr2id];
+    OCMExpect([self.requestPolicyCheck trigger]);
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    // The password should still exist
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+}
+
+- (void)testConflictingItemInWrongViewWithSameUUID {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+    self.passwordsView = [self.injectedManager findView:@"Passwords"];
+    XCTAssertNotNil(self.passwordsView, @"Policy created a passwords view");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+    XCTAssertEqual(0, [self.passwordsView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    NSDictionary* item = [self fakeRecordDictionary:@"account-delete-me" zoneID:self.passwordsZoneID];
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.passwordsZoneID];
+    CKRecordID* ckr2id = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:item];
+
+    NSMutableDictionary* item2 = [item mutableCopy];
+    item2[@"v_Data"] = @"wrongview";
+    CKRecord* ckr2 = [self newRecord:ckr2id withNewItemData:item2];
+
+    // Receive the passwords item first
+    [self.zones[self.passwordsZoneID] addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.passwordsView waitForFetchAndIncomingQueueProcessing];
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    [self.zones[self.keychainZoneID] addToZone:ckr2];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // THe view should ask for a policy update, and receive one
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+
+    // And the item is then deleted
+    [self.zones[self.keychainZoneID] deleteCKRecordIDFromZone:ckr2id];
+    OCMExpect([self.requestPolicyCheck trigger]);
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    // The password should still exist
+    [self checkGenericPassword:@"data" account:@"account-delete-me"];
+}
+
+- (void)testReceiveItemForFuturePolicy {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    NSString* wrongZoneAccount = @"wrong-zone";
+    NSDictionary* item = [self fakeRecordDictionary:wrongZoneAccount zoneID:self.unknownZoneID];
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" zoneID:self.keychainZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:item];
+    [self.keychainZone addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    [self findGenericPassword:wrongZoneAccount expecting:errSecItemNotFound];
+
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+
+    // Now, Octagon discovers that there's a new policy that allows this item in the keychain view
+    TPSyncingPolicy* currentPolicy = self.injectedManager.policy;
+    XCTAssertNotNil(currentPolicy, "should have a current policy");
+
+    [self setPolicyAndWaitForQuiescence:self.originalPolicyPlusUnknownVwht policyIsFresh:YES];
+
+    [self findGenericPassword:wrongZoneAccount expecting:errSecSuccess];
+}
+
+- (void)testHandleItemMovedBetweenViewsBeforePolicyChange {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    // A password is created and uploaded out of the keychain view.
+    __block CKRecord* itemCKRecord = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemCKRecord = record;
+        return YES;
+    }];
+    NSString* itemAccount = @"account-delete-me";
+    [self addGenericPassword:@"data" account:itemAccount viewHint:self.keychainZoneID.zoneName];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertNotNil(itemCKRecord, "Should have some CKRecord for the added item");
+
+    // Update etag as well
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // Another device shows up, changes the item sync policy, and moves the item over into the passwords view.
+
+    NSDictionary* itemContents = [self decryptRecord:itemCKRecord];
+    XCTAssertNotNil(itemContents, "should have some item contents");
+
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:itemCKRecord.recordID.recordName zoneID:self.passwordsZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:itemContents];
+    [self.zones[self.passwordsZoneID] addToZone:ckr];
+
+    TPSyncingPolicy* currentPolicy = self.injectedManager.policy;
+    XCTAssertNotNil(currentPolicy, "should have a current policy");
+
+    // In this test, we receive the deletion, and then the policy change adding the Passwords view
+    [self.keychainZone deleteCKRecordIDFromZone:itemCKRecord.recordID];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self findGenericPassword:itemAccount expecting:errSecItemNotFound];
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+
+    // And once passwords syncs, the item should appear again
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+}
+
+- (void)testHandleItemMovedBetweenViewsAfterPolicyChange {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    // A password is created and uploaded out of the keychain view.
+    __block CKRecord* itemCKRecord = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemCKRecord = record;
+        return YES;
+    }];
+    NSString* itemAccount = @"account-delete-me";
+    [self addGenericPassword:@"data" account:itemAccount viewHint:self.keychainZoneID.zoneName];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertNotNil(itemCKRecord, "Should have some CKRecord for the added item");
+
+    // Update etag as well
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // Another device shows up, changes the item sync policy, and moves the item over into the Passwords view.
+    // But, in this case, we receive the item delete in the Keychain view after we've synced the item in the Passwords view
+
+    NSDictionary* itemContents = [self decryptRecord:itemCKRecord];
+    XCTAssertNotNil(itemContents, "should have some item contents");
+
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:itemCKRecord.recordID.recordName zoneID:self.passwordsZoneID];
+    CKRecord* ckr = [self newRecord:ckrid withNewItemData:itemContents];
+    [self.zones[self.passwordsZoneID] addToZone:ckr];
+
+    TPSyncingPolicy* currentPolicy = self.injectedManager.policy;
+    XCTAssertNotNil(currentPolicy, "should have a current policy");
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+
+    CKKSKeychainView* passwordsView = [self.injectedManager findView:self.passwordsZoneID.zoneName];
+    XCTAssertNotNil(passwordsView, @"Should have a passwords view");
+
+    // And once Passwords syncs, the item should appear again
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+
+    // And now we receive the delete in the keychain view. The item should still exist!
+    [self.keychainZone deleteCKRecordIDFromZone:itemCKRecord.recordID];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+
+    // Keychain View should have asked for a policy set
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+    [self.injectedManager setCurrentSyncingPolicy:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+
+    NSError* zoneError = nil;
+    NSInteger count = [CKKSIncomingQueueEntry countByState:SecCKKSStateMismatchedView zone:self.keychainView.zoneID error:&zoneError];
+    XCTAssertNil(zoneError, "should be no error counting all IQEs");
+    XCTAssertEqual(count, 0, "Should be no remaining mismatched IQEs");
+}
+
+- (void)testMoveItemUploadedToOldZone {
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMExpect([self.requestPolicyCheck trigger]);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self createAndSaveFakeKeyHierarchy:self.passwordsZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    [self setPolicyAndWaitForQuiescence:self.allItemsToPasswordsPolicy policyIsFresh:NO];
+
+    // Now, someone uploads an item to the keychain view. We should move it to the passwords view
+    CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"account0"];
+    [self.keychainZone addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // The keychain view should request a policy refetch
+    OCMVerifyAllWithDelay(self.requestPolicyCheck, 10);
+
+    // Note that ideally, we'd remove the old item from CloudKit. But, other devices which participate in CKKS4All
+    // might not have this forward-compatiblity change, and will treat this as a deletion. If they process this deletion,
+    // then sync the resulting tombstone to a third SOS device, then receive the addition in the 'right' view, and then the
+    // tombstone syncs back to the CKKS4All devices, then we might end up deleting the item across the account.
+    // Until enough internal folk have moved onto builds with this forward-compat change, we can't issue these deletes.
+    //[self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+
+    // The item should be reuploaded to Passwords, though.
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.passwordsZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        return [record.recordID.recordName isEqualToString:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
+    }];
+
+    [self.injectedManager setCurrentSyncingPolicy:self.allItemsToPasswordsPolicy policyIsFresh:YES];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the keychain item should still exist
+    [self findGenericPassword:@"account0" expecting:errSecSuccess];
+}
+
+@end
+
+#endif // OCTAGON
diff --git a/keychain/ckks/tests/CKKSTests+ItemSyncChoice.m b/keychain/ckks/tests/CKKSTests+ItemSyncChoice.m
new file mode 100644 (file)
index 0000000..7ec26bf
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2020 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 <CloudKit/CloudKit.h>
+#import <XCTest/XCTest.h>
+#import <OCMock/OCMock.h>
+
+#import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/ckks/CKKS.h"
+#import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSOutgoingQueueEntry.h"
+#import "keychain/ckks/CloudKitCategories.h"
+#import "keychain/ckks/tests/CKKSTests.h"
+#import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h"
+#import "keychain/ckks/tests/CloudKitMockXCTest.h"
+#import "keychain/ckks/tests/MockCloudKit.h"
+
+@interface CloudKitKeychainSyncingItemSyncChoiceTests : CloudKitKeychainSyncingTestsBase
+@property CKKSSOSSelfPeer* remotePeer1;
+@end
+
+@implementation CloudKitKeychainSyncingItemSyncChoiceTests
+
+- (size_t)outgoingQueueSize:(CKKSKeychainView*)view {
+    __block size_t result = 0;
+
+    [view dispatchSyncWithReadOnlySQLTransaction:^{
+        NSError* zoneError = nil;
+        NSArray<CKKSOutgoingQueueEntry*>* entries = [CKKSOutgoingQueueEntry all:view.zoneID error:&zoneError];
+        XCTAssertNil(zoneError, "should be no error fetching all OQEs");
+
+        result = (size_t)entries.count;
+    }];
+    return result;
+}
+
+- (size_t)incomingQueueSize:(CKKSKeychainView*)view {
+    __block size_t result = 0;
+
+    [view dispatchSyncWithReadOnlySQLTransaction:^{
+        NSError* zoneError = nil;
+        NSArray<CKKSIncomingQueueEntry*>* entries = [CKKSIncomingQueueEntry all:view.zoneID error:&zoneError];
+        XCTAssertNil(zoneError, "should be no error fetching all IQEs");
+
+        result = (size_t)entries.count;
+    }];
+    return result;
+}
+
+- (void)setUp {
+    [super setUp];
+
+    self.remotePeer1 = [[CKKSSOSSelfPeer alloc] initWithSOSPeerID:@"remote-peer1"
+                                                    encryptionKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
+                                                       signingKey:[[SFECKeyPair alloc] initRandomKeyPairWithSpecifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]]
+                                                         viewList:self.managedViewList];
+}
+
+- (void)testAddItemToPausedView {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    XCTAssertEqual(1, [self outgoingQueueSize:self.keychainView], "There should be one pending item in the outgoing queue");
+
+    // and again
+    [self addGenericPassword:@"data" account:@"account-delete-me-2"];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    XCTAssertEqual(2, [self outgoingQueueSize:self.keychainView], "There should be two pending item in the outgoing queue");
+
+    // When syncing is enabled, these items should sync
+    [self expectCKModifyItemRecords:2 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_ENABLED]
+                                 policyIsFresh:NO];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testReceiveItemToPausedView {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    [self findGenericPassword: @"account0" expecting:errSecItemNotFound];
+
+    [self.keychainZone addToZone:[self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D00" withAccount:@"account0"]];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    XCTAssertEqual(1, [self incomingQueueSize:self.keychainView], "There should be one pending item in the incoming queue");
+
+    [self.keychainZone addToZone:[self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-0000-5A507ACB2D00" withAccount:@"account1"]];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    XCTAssertEqual(2, [self incomingQueueSize:self.keychainView], "There should be two pending item in the incoming queue");
+
+    [self findGenericPassword:@"account0" expecting:errSecItemNotFound];
+    [self findGenericPassword:@"account1" expecting:errSecItemNotFound];
+
+    // When syncing is enabled, these items should sync
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_ENABLED]
+                                 policyIsFresh:NO];
+
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+    [self findGenericPassword:@"account0" expecting:errSecSuccess];
+    [self findGenericPassword:@"account1" expecting:errSecSuccess];
+}
+
+- (void)testAcceptKeyHierarchyWhilePaused {
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self saveTLKMaterialToKeychain:self.keychainZoneID];
+    [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should have become ready");
+}
+
+- (void)testUploadSelfTLKShare {
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    // Test starts with no keys in CKKS database, but one in our fake CloudKit.
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+
+    // Test also starts with the TLK shared to all trusted peers from peer1
+    [self.mockSOSAdapter.trustedPeers addObject:self.remotePeer1];
+    [self putTLKSharesInCloudKit:self.keychainZoneKeys.tlk from:self.remotePeer1 zoneID:self.keychainZoneID];
+
+    // 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 startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testSendNewTLKSharesOnTrustSetAddition {
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    // step 1: add a new peer; we should share the TLK with them
+    // start with no trusted peers
+    [self.mockSOSAdapter.trustedPeers removeAllObjects];
+
+    [self startCKKSSubsystem];
+    [self performOctagonTLKUpload:self.ckksViews];
+
+    [self expectCKModifyKeyRecords:0 currentKeyPointerRecords:0 tlkShareRecords:1 zoneID:self.keychainZoneID];
+    [self.mockSOSAdapter.trustedPeers addObject:self.remotePeer1];
+    [self.mockSOSAdapter sendTrustedPeerSetChangedUpdate];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self waitForCKModifications];
+
+    // and just double-check that no syncing is occurring
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    XCTAssertEqual(1, [self outgoingQueueSize:self.keychainView], "There should be one pending item in the outgoing queue");
+}
+
+- (void)testAddAndNotifyOnSyncDuringPausedOperation {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should have become ready");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView setCurrentSyncingPolicy:[self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet setWithObject:self.keychainView.zoneName]
+                                                                                        syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED]
+                                 policyIsFresh:NO];
+
+    NSMutableDictionary* query = [@{
+                                    (id)kSecClass : (id)kSecClassGenericPassword,
+                                    (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+                                    (id)kSecAttrAccessible: (id)kSecAttrAccessibleAfterFirstUnlock,
+                                    (id)kSecAttrAccount : @"testaccount",
+                                    (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+                                    (id)kSecAttrSyncViewHint : self.keychainView.zoneName,
+                                    (id)kSecValueData : (id) [@"asdf" dataUsingEncoding:NSUTF8StringEncoding],
+                                    } mutableCopy];
+
+    XCTestExpectation* blockExpectation = [self expectationWithDescription: @"callback occurs"];
+
+    XCTAssertEqual(errSecSuccess, _SecItemAddAndNotifyOnSync((__bridge CFDictionaryRef) query, NULL, ^(bool didSync, CFErrorRef cferror) {
+        XCTAssertFalse(didSync, "Item did not sync");
+
+        NSError* error = (__bridge NSError*)cferror;
+        XCTAssertNotNil(error, "Error syncing item");
+        XCTAssertEqual(error.domain, CKKSErrorDomain, "Error domain was CKKSErrorDomain");
+        XCTAssertEqual(error.code, CKKSErrorViewIsPaused, "Error code is 'view is paused'");
+
+        [blockExpectation fulfill];
+    }), @"_SecItemAddAndNotifyOnSync succeeded");
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 10);
+
+    [self waitForExpectationsWithTimeout:5.0 handler:nil];
+}
+
+@end
+
+#endif // OCTAGON
index 0823b71d1cd41ee49c7b4e5e34a1e790652e5f51..acc9d41e6a9c01b58114106ddd46e4d4d9c774e4 100644 (file)
@@ -20,6 +20,7 @@
 #import "keychain/ckks/CKKSKey.h"
 #import "keychain/ckks/CKKSOutgoingQueueEntry.h"
 #import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSStates.h"
 #import "keychain/ckks/CKKSSynchronizeOperation.h"
 #import "keychain/ckks/CKKSViewManager.h"
 #import "keychain/ckks/CKKSZoneStateEntry.h"
 
 - (NSSet*)managedViewList {
     NSMutableSet* parentSet = [[super managedViewList] mutableCopy];
-    [parentSet addObject:@"SafariPasswords"];
+    [parentSet addObject:@"Passwords"];
     return parentSet;
 }
 
 // Make a policy as normal for most views, but Passwords is special
-- (TPPolicy*)viewSortingPolicyForManagedViewList
+- (TPSyncingPolicy*)viewSortingPolicyForManagedViewList
 {
     NSMutableArray<TPPBPolicyKeyViewMapping*>* rules = [NSMutableArray array];
 
@@ -67,7 +68,7 @@
         mapping.view = viewName;
 
         // The real passwords view is on com.appple.cfnetwork, but for these tests, let's just use the sbd agrp (because of how the entitlements are specified)
-        if([viewName isEqualToString:@"SafariPasswords"]) {
+        if([viewName isEqualToString:@"Passwords"]) {
             mapping.matchingRule = [TPDictionaryMatchingRule fieldMatch:@"agrp"
                                                              fieldRegex:[NSString stringWithFormat:@"^com\\.apple\\.sbd$"]];
         } else {
         [rules addObject:mapping];
     }
 
-    TPPolicy* policy = [TPPolicy policyWithModelToCategory:@[]
-                                          categoriesByView:@{}
-                                     introducersByCategory:@{}
-                                            keyViewMapping:rules
-                                         unknownRedactions:NO
-                                                   version:[[TPPolicyVersion alloc] initWithVersion:1 hash:@"fake-policy-for-views"]];
+    NSSet<NSString*>* viewList = [self managedViewList];
+    TPSyncingPolicy* policy = [[TPSyncingPolicy alloc] initWithModel:@"test-policy"
+                                                             version:[[TPPolicyVersion alloc] initWithVersion:1 hash:@"fake-policy-for-views"]
+                                                            viewList:viewList
+                                               userControllableViews:[NSSet set]
+                                           syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_ENABLED
+                                                viewsToPiggybackTLKs:[viewList containsObject:@"Passwords"] ? [NSSet setWithObject:@"Passwords"] : [NSSet set]
+                                                      keyViewMapping:rules];
 
     return policy;
 }
     [self.ckksViews addObject:self.limitedView];
     [self.ckksZones addObject:self.limitedZoneID];
 
-    self.passwordsZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"SafariPasswords" ownerName:CKCurrentUserDefaultName];
+    self.passwordsZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"Passwords" ownerName:CKCurrentUserDefaultName];
     self.passwordsZone = [[FakeCKZone alloc] initZone: self.passwordsZoneID];
     self.zones[self.passwordsZoneID] = self.passwordsZone;
-    self.passwordsView = [[CKKSViewManager manager] findOrCreateView:@"SafariPasswords"];
+    self.passwordsView = [[CKKSViewManager manager] findOrCreateView:@"Passwords"];
     XCTAssertNotNil(self.passwordsView, "should have a passwords ckks view");
     XCTAssertNotNil(self.passwordsView, "CKKSViewManager created the Passwords view");
     [self.ckksViews addObject:self.passwordsView];
 
     // These tests, at least, will use the policy codepaths!
     [self.injectedManager setOverrideCKKSViewsFromPolicy:YES];
-    [self.injectedManager setSyncingViews:self.managedViewList sortingPolicy:self.viewSortingPolicyForManagedViewList];
+    [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
 }
 
 + (void)tearDown {
     [self waitForKeyHierarchyReadinesses];
     [self.passwordsView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
+    // Ensure that we catch up to the newest CK change token so our fake cloudkit will notice the delete at fetch time
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.passwordsView waitForFetchAndIncomingQueueProcessing];
+
     // Now, the item is deleted. Do we properly remove it?
     CKRecord* itemRecord = nil;
     for(CKRecord* record in [self.passwordsZone.currentDatabase allValues]) {
 
     CFTypeRef item = NULL;
     XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should still exist");
-    XCTAssertNotNil((__bridge id)item, "No item should have been found");
+    XCTAssertNotNil((__bridge id)item, "An item should have been found");
     CFReleaseNull(item);
 
     // Now, the item is deleted. The passwords view should delete the local item, even though it has the wrong 'vwht' on disk.
+    XCTAssertNotNil(self.passwordsZone.currentDatabase[itemRecord.recordID], "Record should exist in fake CK");
     [self.passwordsZone deleteCKRecordIDFromZone:itemRecord.recordID];
-    [self.passwordsView notifyZoneChange:nil];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.passwordsView waitForFetchAndIncomingQueueProcessing];
 
     XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should no longer exist");
     [self saveFakeKeyHierarchiesToLocalDatabase]; // Make life easy for this test.
     [self startCKKSSubsystem];
 
-    for(CKRecordZoneID* zoneID in self.ckksZones) {
-        [self expectCKKSTLKSelfShareUpload:zoneID];
-    }
-
     [self waitForKeyHierarchyReadinesses];
+    [self.engramView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
     [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound];
 
     XCTestExpectation* engramChanged = [self expectChangeForView:self.engramZoneID.zoneName];
     XCTestExpectation* pcsChanged = [self expectChangeForView:@"PCS"];
 
+    self.silentFetchesAllowed = false;
+    [self expectCKFetch];
+
     // Trigger a notification (with hilariously fake data)
-    [self.engramView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self.engramView waitForFetchAndIncomingQueueProcessing];
+
     [self findGenericPassword:@"account-delete-me" expecting:errSecSuccess];
 
     [self waitForExpectations:@[engramChanged] timeout:1];
     [self expectCKFetch]; // one to fail with a CKErrorChangeTokenExpired error
     [self expectCKFetch]; // and one to succeed
 
-    [self.manateeView dispatchSyncWithAccountKeys: ^bool {
-        [self.manateeView _onqueueKeyStateMachineRequestFetch];
-        return true;
-    }];
+    [self.manateeView.stateMachine handleFlag:CKKSFlagFetchRequested];
 
     XCTAssertEqual(0, [self.manateeView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS should enter 'ready'");
 
-    [self.manateeView waitForFetchAndIncomingQueueProcessing];
+    // Don't cause another fetch, because the machinery might not be ready
+    [self.manateeView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-all-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-all-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
     XCTestExpectation* resetExpectation = [self expectationWithDescription: @"reset callback occurs"];
     [self.injectedManager rpcResetCloudKit:nil reason:@"reset-test" reply:^(NSError* result) {
         XCTAssertNil(result, "no error resetting cloudkit");
-        secnotice("ckks", "Received a resetCloudKit callback");
+        ckksnotice_global("ckks", "Received a resetCloudKit callback");
         [resetExpectation fulfill];
     }];
 
     self.manateeZone.limitFetchTo = manateeChangeToken1;
 
     // Attempt to trigger simultaneous key state resyncs. This is a horrible hack...
-    [self.manateeView dispatchSyncWithAccountKeys:^bool {
+    [self.manateeView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         self.manateeView.keyStateFullRefetchRequested = YES;
-        [self.manateeView _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-        return true;
+        [self.manateeView _onqueuePokeKeyStateMachine];
+        return CKKSDatabaseTransactionCommit;
     }];
-    [self.healthView dispatchSyncWithAccountKeys:^bool {
+    [self.healthView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         self.healthView.keyStateFullRefetchRequested = YES;
-        [self.healthView _onqueueAdvanceKeyStateMachineToState:nil withError:nil];
-        return true;
+        [self.healthView _onqueuePokeKeyStateMachine];
+        return CKKSDatabaseTransactionCommit;
     }];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
index 8baf53aa9175d2e00e019c74fb12bf724f572c27..a25f962f04b9658aa21ac4fcdf35da52bd357038 100644 (file)
 #import "keychain/ckks/CKKSKey.h"
 #import "keychain/ckks/CKKSOutgoingQueueEntry.h"
 #import "keychain/ckks/CKKSIncomingQueueEntry.h"
+#import "keychain/ckks/CKKSStates.h"
 #import "keychain/ckks/CKKSSynchronizeOperation.h"
 #import "keychain/ckks/CKKSViewManager.h"
 #import "keychain/ckks/CKKSZoneStateEntry.h"
 #import "keychain/ckks/CKKSManifest.h"
 #import "keychain/ckks/CKKSAnalytics.h"
-#import "keychain/ckks/CKKSHealKeyHierarchyOperation.h"
 #import "keychain/ckks/CKKSZoneChangeFetcher.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #import "keychain/ckks/CKKSPeer.h"
@@ -57,6 +57,7 @@
 #import "keychain/ckks/tests/MockCloudKit.h"
 
 #import "keychain/ckks/tests/CKKSTests.h"
+#import "keychain/ot/ObjCImprovements.h"
 #import <utilities/SecCoreAnalytics.h>
 
 // break abstraction
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
-- (void)testActiveTLKS {
+- (void)testActiveTLKs {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
     // We expect a single record to be uploaded.
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
 
     [self startCKKSSubsystem];
-
     [self addGenericPassword: @"data" account: @"account-delete-me"];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
-    NSDictionary<NSString *,NSString *>* tlks = [[CKKSViewManager manager] activeTLKs];
+    NSError* localError = nil;
+    NSArray<CKKSKeychainBackedKey*>* tlks = [[CKKSViewManager manager] currentTLKsFilteredByPolicy:NO error:&localError];
+    XCTAssertNil(localError, "Should have no error fetching current TLKs");
+
+    XCTAssertEqual([tlks count], (NSUInteger)1, "Should have one TLK");
+    XCTAssertEqualObjects(tlks[0].zoneID.zoneName, @"keychain", "should have a TLK for keychain");
 
-    XCTAssertEqual([tlks count], (NSUInteger)1, "One TLK");
-    XCTAssertNotNil(tlks[@"keychain"], "keychain have a UUID");
+    XCTAssertEqualObjects(tlks[0].uuid, self.keychainZoneKeys.tlk.uuid, "should have the TLK matching cloudkit");
 }
 
+- (void)testActiveTLKsWhenMissing {
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], @"Key state should have arrived at waitfortlk");
+
+    NSError* localError = nil;
+    NSArray<CKKSKeychainBackedKey*>* tlks = [[CKKSViewManager manager] currentTLKsFilteredByPolicy:NO error:&localError];
+    XCTAssertNil(localError, "Should have no error fetching current TLKs");
+
+    XCTAssertEqual([tlks count], (NSUInteger)0, "Should have zero TLKs");
+}
+
+- (void)testActiveTLKsWhenLocked {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+
+    self.aksLockState = true;
+    [self.lockStateTracker recheck];
+
+    NSError* localError = nil;
+    NSArray<CKKSKeychainBackedKey*>* tlks = [[CKKSViewManager manager] currentTLKsFilteredByPolicy:NO error:&localError];
+    XCTAssertNotNil(localError, "Should have an error fetching current TLKs");
+
+    XCTAssertEqual([tlks count], (NSUInteger)0, "Should have zero TLKs");
+}
 
 - (void)testAddMultipleItems {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
 
     [self.keychainView waitUntilAllOperationsAreFinished];
 
+    // We expect an upload of the added item, once CKKS finds the UUID-less item and fixes it
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+
     SecCKKSTestSetDisableAutomaticUUID(true);
     [self addGenericPassword: @"data" account: @"account-delete-me-no-UUID" expecting:errSecSuccess message: @"Add item (no UUID) to keychain"];
-
     SecCKKSTestSetDisableAutomaticUUID(false);
 
-    // We then expect an upload of the added item
-    [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
+    [self findGenericPassword:@"account-delete-me-no-UUID" expecting:errSecSuccess];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
     // Stop the reencrypt operation from happening
     self.keychainView.holdReencryptOutgoingItemsOperation = [CKKSGroupOperation named:@"reencrypt-hold" withBlock: ^{
-        secnotice("ckks", "releasing reencryption hold");
+        ckksnotice_global("ckks", "releasing reencryption hold");
     }];
 
     // The cloudkit operation finishes, letting the next OQO proceed (and set up the reencryption operation)
 
     // Pause outgoing queue operations to ensure the reencryption operation runs first
     self.keychainView.holdOutgoingQueueOperation = [CKKSGroupOperation named:@"outgoing-hold" withBlock: ^{
-        secnotice("ckks", "releasing outgoing-queue hold");
+        ckksnotice_global("ckks", "releasing outgoing-queue hold");
     }];
 
     // Run the reencrypt items operation to completion.
 
     // Stop the reencrypt operation from happening
     self.keychainView.holdReencryptOutgoingItemsOperation = [CKKSGroupOperation named:@"reencrypt-hold" withBlock: ^{
-        secnotice("ckks", "releasing reencryption hold");
+        ckksnotice_global("ckks", "releasing reencryption hold");
     }];
 
     // The cloudkit operation finishes, letting the next OQO proceed (and set up the reencryption operation)
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
     NSString* account = @"fake-account";
 
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
 
         CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:@"50184A35-4480-E8BA-769B-567CF72F1EC0" zoneID:self.keychainZoneID];
         [oqe saveToDatabase:&error];
 
         XCTAssertNil(error, "Shouldn't error saving new OQE to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     NSError *error = NULL;
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testDeleteItemAndReaddAtSameUUID {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded.
+    __block CKRecordID* itemRecordID = nil;
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        itemRecordID = record.recordID;
+        return YES;
+    }];
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // We expect a single record to be deleted.
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+    [self deleteGenericPassword:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // And the item is readded. It should come back to its previous UUID.
+    XCTAssertNotNil(itemRecordID, "Should have an item record ID");
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID checkItem:^BOOL(CKRecord * _Nonnull record) {
+        XCTAssertEqualObjects(itemRecordID.recordName, record.recordID.recordName, "Uploaded item UUID should match previous upload");
+        return YES;
+    }];
+    [self addGenericPassword:@"data" account:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
 - (void)testDeleteItemImmediatelyAfterModify {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
     NSString* account = @"account-delete-me";
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testDeleteItemDuringAddUpload {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+    NSString* account = @"account-delete-me";
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'");
+
+    // We expect a single record to be uploaded. But, while that's happening, delete it via the API.
+
+    XCTestExpectation *deleteBlock = [self expectationWithDescription:@"delete block called"];
+
+    WEAKIFY(self);
+    self.keychainZone.blockBeforeWriteOperation = ^() {
+        STRONGIFY(self);
+        [self deleteGenericPassword:account];
+        self.keychainZone.blockBeforeWriteOperation = nil;
+        [deleteBlock fulfill];
+    };
+
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+
+    // This should cause a deletion
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+    [self addGenericPassword:@"data" account:account];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self waitForExpectations: @[deleteBlock] timeout:5];
+}
+
+- (void)testDeleteItemDuringModificationUpload {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+    NSString* account = @"account-delete-me";
+
+    [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:10*NSEC_PER_SEC], @"key state should enter 'ready'");
+
+    // We expect a single record to be uploaded.
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+    [self addGenericPassword: @"data" account: account];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // We expect a single modification record to be uploaded, and want to delete the item while the upload is ongoing
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID
+                          checkItem:[self checkPasswordBlock:self.keychainZoneID account:account password:@"otherdata"]];
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+
+    XCTestExpectation *deleteBlock = [self expectationWithDescription:@"delete block called"];
+
+    WEAKIFY(self);
+    self.keychainZone.blockBeforeWriteOperation = ^() {
+        STRONGIFY(self);
+        [self deleteGenericPassword:account];
+        self.keychainZone.blockBeforeWriteOperation = nil;
+        [deleteBlock fulfill];
+    };
+
+    [self updateGenericPassword:@"otherdata" account:account];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self waitForExpectations: @[deleteBlock] timeout:5];
+}
+
 - (void)testDeleteItemAfterFetchAfterModify {
     [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
     NSString* account = @"account-delete-me";
 
     // Right now, the write in CloudKit is pending. Place a hold on outgoing queue processing
     // Place a hold on processing the outgoing queue.
-    CKKSResultOperation* blockOutgoing = [CKKSResultOperation operationWithBlock:^{
-        secnotice("ckks", "Outgoing queue hold released.");
+    self.keychainView.holdOutgoingQueueOperation = [CKKSResultOperation named:@"outgoing-queue-hold"
+                                                                    withBlock:^{
+        ckksnotice_global("ckks", "Outgoing queue hold released.");
     }];
-    blockOutgoing.name = @"outgoing-queue-hold";
-    CKKSResultOperation* outgoingQueueOperation = [self.keychainView processOutgoingQueueAfter:blockOutgoing ckoperationGroup:nil];
 
     [self deleteGenericPassword:account];
-
     [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
 
     // Release the CK modification hold
     //[self releaseCloudKitModificationHold];
 
     // And cause a fetch
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
-    [self.operationQueue addOperation:blockOutgoing];
-    [outgoingQueueOperation waitUntilFinished];
+    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
 
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
     [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     // Ensure nothing is in the outgoing queue
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray<NSString*>* uuids = [CKKSOutgoingQueueEntry allUUIDs:self.keychainZoneID
                                                                error:&error];
         XCTAssertNil(error, "should be no error fetching uuids");
         XCTAssertEqual(uuids.count, 0u, "There should be zero OQEs");
-        return false;
     }];
 
     // And a simple fetch doesn't bring it back
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
     [self findGenericPassword:account expecting:errSecItemNotFound];
 
     CFTypeRef item = NULL;
     XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist");
 
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
     [self.keychainZone addToZone: ckr];
 
     // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
     XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now");
 }
 
         }
     }
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
-
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword: @"account0" expecting:errSecSuccess];
     [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
 
     // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];;
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now");
 
     [self waitForCKModifications];
     XCTAssertNil(self.keychainZone.currentDatabase[ckr2.recordID], "Correct record was deleted from CloudKit");
+
+    // And the local item should have ckr's UUID
+    [self checkGenericPasswordStoredUUID:ckr.recordID.recordName account:@"account-delete-me"];
+}
+
+- (void)testReceiveCorruptedItem {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+    [self startCKKSSubsystem];
+
+    [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound];
+
+    CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
+
+    // I don't know of any codepaths that cause this, but it apparently has happened.
+    ckr[SecCKRecordWrappedKeyKey] = nil;
+    [self.keychainZone addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // The item still shouldn't exist, because it was corrupted in flight
+    [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound];
+
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
+        NSError* error = nil;
+        NSArray<CKKSIncomingQueueEntry*>* iqes = [CKKSIncomingQueueEntry all:&error];
+        XCTAssertNil(error, "No error loading IQEs");
+        XCTAssertNotNil(iqes, "Could load IQEs");
+        XCTAssertEqual(iqes.count, 1u, "Incoming queue has one item");
+        XCTAssertEqualObjects(iqes[0].state, SecCKKSStateNew, "Item state should be 'new'");
+    }];
 }
 
 -(void)testReceiveItemDelete {
                             (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
                             (id)kSecAttrAccount : @"account-delete-me",
                             (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+                            (id)kSecReturnAttributes : @YES,
                             (id)kSecMatchLimit : (id)kSecMatchLimitOne,
                             };
 
-    CFTypeRef item = NULL;
-    XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist");
+    CFTypeRef cfitem = NULL;
+    XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfitem), "item should not yet exist");
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName: @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
     [self.keychainZone addToZone: ckr];
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
-    XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now");
-    CFReleaseNull(item);
+    XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfitem), "item should exist now");
+
+    NSDictionary* item = (NSDictionary*) CFBridgingRelease(cfitem);
+    cfitem = NULL;
+    NSDate* itemModificationDate = item[(id)kSecAttrModificationDate];
+    XCTAssertNotNil(itemModificationDate, "Should have a modification date");
 
     // Trigger a delete
     [self.keychainZone deleteCKRecordIDFromZone: [ckr recordID]];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
-    XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should no longer exist");
+    XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &cfitem), "item should no longer exist");
+    CFReleaseNull(cfitem);
+
+    // Now, double-check the tombstone. Its modification date should be derived from the item's mdat.
+    NSDictionary *tombquery = @{(id)kSecClass : (id)kSecClassGenericPassword,
+                            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+                            (id)kSecAttrAccount : @"account-delete-me",
+                            (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+                            (id)kSecAttrTombstone : @YES,
+                            (id)kSecReturnAttributes : @YES,
+                            (id)kSecMatchLimit : (id)kSecMatchLimitOne,};
+
+    CFTypeRef cfref = NULL;
+    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)tombquery, &cfref);
+    XCTAssertEqual(status, errSecSuccess, "Should have found a tombstone");
+
+    NSDictionary* tombstone = (NSDictionary*)CFBridgingRelease(cfref);
+    XCTAssertNotNil(tombstone, "Should have found a tombstone");
+
+    NSDate* tombstoneModificationDate = tombstone[(id)kSecAttrModificationDate];
+    XCTAssertEqual([tombstoneModificationDate compare:itemModificationDate], NSOrderedDescending, "tombstone should be later than item");
+
+    NSTimeInterval tombestoneDelta = [tombstoneModificationDate timeIntervalSinceDate:itemModificationDate];
+    XCTAssertGreaterThan(tombestoneDelta, 0, "Delta should be positive");
+    XCTAssertLessThan(tombestoneDelta, 5, "tombstone mdat should be no later than 5s after item mdat");
+
+    // And just as a sanity, mdat is already far ago, right?
+    NSTimeInterval itemDelta = [[NSDate date] timeIntervalSinceDate:itemModificationDate];
+    XCTAssertGreaterThan(itemDelta, 10, "item mdat should at least 10s in the past");
+}
+
+- (void)testReceiveTombstoneItem {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+    [self startCKKSSubsystem];
+
+    NSString* account = @"account-delete-me";
+
+    CKRecord* ckr = [self createFakeTombstoneRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" account:account];
+    [self.keychainZone addToZone:ckr];
+
+    // This device should delete the tombstone entry
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    // The tombstone shouldn't exist
+    NSDictionary *tombquery = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+        (id)kSecAttrAccount : account,
+        (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+        (id)kSecReturnAttributes : @YES,
+        (id)kSecAttrTombstone : @YES,
+    };
+
+    CFTypeRef cftype = NULL;
+    XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef)tombquery, &cftype), "item should not exist now");
+    XCTAssertNil((__bridge id)cftype, "Should have found no tombstones");
+
+    // And the delete should occur
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
+        NSError* error = nil;
+        NSArray<NSString*>* uuids = [CKKSIncomingQueueEntry allUUIDs:self.keychainZoneID
+                                                                error:&error];
+        XCTAssertNil(error, "should be no error fetching uuids");
+        XCTAssertEqual(uuids.count, 0u, "There should be zero IQEs");
+    }];
+}
+
+- (void)testReceiveItemDeleteAndReaddAtDifferentUUIDInSameFetch {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    NSString* itemAccount = @"account-delete-me";
+    [self findGenericPassword:itemAccount expecting:errSecItemNotFound];
+
+    NSString* uuidOriginalItem = @"7B598D31-F9C5-481E-98AC-5A507ACB2D85";
+    NSString* uuidGreater      = @"7B598D31-FFFF-FFFF-98AC-5A507ACB2D85";
+
+    CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:uuidOriginalItem];
+    CKRecord* ckrGreater = [self createFakeRecord:self.keychainZoneID recordName:uuidGreater];
+
+    [self.keychainZone addToZone:ckr];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+    [self checkGenericPasswordStoredUUID:uuidOriginalItem account:itemAccount];
+
+    // Now, the item is deleted and re-added with a greater UUID
+    [self.keychainZone deleteCKRecordIDFromZone:[ckr recordID]];
+    [self.keychainZone addToZone:ckrGreater];
+
+    // This node should not upload anything.
+    [[self.mockDatabase reject] addOperation:[OCMArg any]];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+
+    // Item should still exist.
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+    [self checkGenericPasswordStoredUUID:uuidGreater account:itemAccount];
 }
 
 -(void)testReceiveItemPhantomDelete {
     CFTypeRef item = NULL;
     XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should not yet exist");
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName: @"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
     [self.keychainZone addToZone: ckr];
 
-    // Trigger a notification (with hilariously fake data)
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     XCTAssertEqual(errSecSuccess, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should exist now");
     [self.keychainZone deleteCKRecordIDFromZone: [ckr recordID]];
 
     // and add another, incorrect IQE
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         // Inefficient, but hey, it works
         CKRecord* record = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-FFFF-FFFF-5A507ACB2D85"];
         CKKSItem* fakeItem = [[CKKSItem alloc] initWithCKRecord: record];
         NSError* error = nil;
         XCTAssert([iqe saveToDatabase: &error], "Saved fake IQE to database");
         XCTAssertNil(error, "No error saving fake IQE to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     XCTAssertEqual(errSecItemNotFound, SecItemCopyMatching((__bridge CFDictionaryRef) query, &item), "item should no longer exist");
 
     // The incoming queue should be empty
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray* iqes = [CKKSIncomingQueueEntry all:&error];
         XCTAssertNil(error, "No error loading IQEs");
         XCTAssertNotNil(iqes, "Could load IQEs");
         XCTAssertEqual(iqes.count, 0u, "Incoming queue is empty");
-        return false;
     }];
 }
 
     [self.keychainView waitUntilAllOperationsAreFinished];
 
     // Place a hold on processing the outgoing queue.
-    CKKSResultOperation* blockOutgoing = [CKKSResultOperation operationWithBlock:^{
-        secnotice("ckks", "Outgoing queue hold released.");
+    self.keychainView.holdOutgoingQueueOperation = [CKKSResultOperation named:@"outgoing-queue-hold"
+                                                                    withBlock:^{
+        ckksnotice_global("ckks", "Outgoing queue hold released.");
     }];
-    blockOutgoing.name = @"outgoing-queue-hold";
-    CKKSResultOperation* outgoingQueueOperation = [self.keychainView processOutgoingQueueAfter:blockOutgoing ckoperationGroup:nil];
 
-    CKKSResultOperation* blockIncoming = [CKKSResultOperation operationWithBlock:^{
-        secnotice("ckks", "Incoming queue hold released.");
+    self.keychainView.holdIncomingQueueOperation = [CKKSResultOperation named:@"incoming-queue-hold"
+                                                                    withBlock:^{
+        ckksnotice_global("ckks", "Incoming queue hold released.");
     }];
-    blockIncoming.name = @"incoming-queue-hold";
-    CKKSResultOperation* incomingQueueOperation = [self.keychainView processIncomingQueue:false after: blockIncoming];
 
     [self addGenericPassword:@"localchange" account:@"account-delete-me"];
 
     // Pull out the new item's UUID.
     __block NSString* itemUUID = nil;
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray<NSString*>* uuids = [CKKSOutgoingQueueEntry allUUIDs:self.keychainZoneID ?: [[CKRecordZoneID alloc] initWithZoneName:@"keychain"
                                                                                                                            ownerName:CKCurrentUserDefaultName]
         itemUUID = uuids[0];
 
         XCTAssertNotNil(itemUUID, "Have a UUID for our new item");
-        return false;
     }];
 
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName: itemUUID]];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [[self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished];
 
     // Allow the outgoing queue operation to proceed
-    [self.operationQueue addOperation:blockOutgoing];
-    [outgoingQueueOperation waitUntilFinished];
+    [self.operationQueue addOperation:self.keychainView.holdOutgoingQueueOperation];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     // Allow the incoming queue operation to proceed
-    [self.operationQueue addOperation:blockIncoming];
-    [incomingQueueOperation waitUntilFinished];
+    [self.operationQueue addOperation:self.keychainView.holdIncomingQueueOperation];
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
     [self checkGenericPassword:@"data" account:@"account-delete-me"];
 
     [self.keychainView waitUntilAllOperationsAreFinished];
 
     // Place a hold on processing the outgoing queue.
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     self.keychainView.holdOutgoingQueueOperation = [CKKSResultOperation named:@"outgoing-queue-hold" withBlock:^{
-        secnotice("ckks", "Outgoing queue hold released.");
+        ckksnotice_global("ckks", "Outgoing queue hold released.");
     }];
 
     [self addGenericPassword:@"localchange" account:@"account-delete-me"];
 
     // Pull out the new item's UUID.
     __block NSString* itemUUID = nil;
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray<NSString*>* uuids = [CKKSOutgoingQueueEntry allUUIDs:self.keychainZoneID ?: [[CKRecordZoneID alloc] initWithZoneName:@"keychain"
                                                                                                                            ownerName:CKCurrentUserDefaultName]
         itemUUID = uuids[0];
 
         XCTAssertNotNil(itemUUID, "Have a UUID for our new item");
-        return false;
     }];
 
     // Add a second item: this item should be uploaded after the failure of the first item
     ckr[@"server_new_server_field"] = future_server_field;
     [self.keychainZone addToZone:ckr];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword,
 
     [self.keychainZone addToZone:[cipheritem CKRecordWithZoneID: recordID.zoneID]];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     NSDictionary* query = @{(id)kSecClass: (id)kSecClassGenericPassword,
     XCTAssertEqualObjects(newRecord[SecCKRecordEncryptionVersionKey], [NSNumber numberWithInteger:(int) CKKSItemEncryptionVersion2], "Uploaded using encv2");
 }
 
+- (void)testLocalUpdateToTombstoneItem {
+    // Some CKKS clients may accidentally upload entries with tomb=1.
+    // We should delete these items with extreme predjudice.
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded.
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+    [self addGenericPassword: @"data" account: @"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // We expect a single record to be deleted.
+    [self expectCKDeleteItemRecords: 1 zoneID:self.keychainZoneID];
+    [self deleteGenericPassword:@"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // Now, SOS comes along and updates the tombstone
+    // CKKS should _not_ try to upload a tombstone
+    NSDictionary *tombquery = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+        (id)kSecAttrAccount : @"account-delete-me",
+        (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+        (id)kSecAttrTombstone : @YES,
+    };
+
+    NSDictionary* update = @{
+        (id)kSecAttrModificationDate : [NSDate date],
+    };
+
+    __block CFErrorRef cferror = NULL;
+    kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
+        bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteSOSTransactionType, &cferror, ^bool {
+            OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)tombquery, (__bridge CFDictionaryRef)update);
+            XCTAssertEqual(status, errSecSuccess, "Should have been able to update a tombstone");
+
+            return true;
+        });
+        return ok;
+    });
+
+    XCTAssertNil((__bridge NSError*)cferror, "Should be no error updating a tombstone");
+
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+}
+
+- (void)testIgnoreUpdateToModificationDateItem {
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID];
+    [self startCKKSSubsystem];
+
+    // We expect a single record to be uploaded.
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+    [self addGenericPassword:@"data" account: @"account-delete-me"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // Nothing more should be uploaded
+    NSDictionary *query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+        (id)kSecAttrAccount : @"account-delete-me",
+        (id)kSecAttrSynchronizable : (id)kCFBooleanTrue,
+    };
+
+    NSDictionary* update = @{
+        (id)kSecAttrModificationDate : [NSDate date],
+    };
+
+    __block CFErrorRef cferror = NULL;
+    kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
+        bool ok = kc_transaction_type(dbt, kSecDbExclusiveRemoteSOSTransactionType, &cferror, ^bool {
+            OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update);
+            XCTAssertEqual(status, errSecSuccess, "Should have been able to update the item");
+
+            return true;
+        });
+        return ok;
+    });
+
+    XCTAssertNil((__bridge NSError*)cferror, "Should be no error updating just the mdat");
+
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+}
+
 - (void)testUploadPagination {
-    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID]; // Make life easy for this test.
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
+    [self saveTLKMaterialToKeychain:self.keychainZoneID];
+    [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
 
     for(size_t count = 0; count < 250; count++) {
         [self addGenericPassword: @"data" account: [NSString stringWithFormat:@"account-delete-me-%03lu", count]];
     }
 
-    [self startCKKSSubsystem];
-
     [self expectCKModifyItemRecords: SecCKKSOutgoingQueueItemsAtOnce currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
     [self expectCKModifyItemRecords: SecCKKSOutgoingQueueItemsAtOnce currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
     [self expectCKModifyItemRecords: 50 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
 
+    [self startCKKSSubsystem];
+
+    // For the next 5 seconds, try to add and then find an item. Each attempt should be fairly quick: no long multisecond pauses while CKKS Scans
+    NSTimeInterval elapsed = 0;
+    uint64_t count = 0;
+    while(elapsed < 10) {
+        NSDate* begin = [NSDate now];
+
+        NSString* account = [NSString stringWithFormat:@"non-syncable-%d", (int)count];
+
+        NSDictionary* query = @{
+            (id)kSecClass : (id)kSecClassGenericPassword,
+            (id)kSecAttrAccount : account,
+            (id)kSecAttrSynchronizable : @NO,
+            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+            (id)kSecValueData : [@"asdf" dataUsingEncoding:NSUTF8StringEncoding],
+        };
+
+        XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess, @"Should be able to add nonsyncable item");
+        ckksnotice("ckkstest", self.keychainView, "SecItemAdd of %@ successful", account);
+
+        NSDictionary *findQuery = @{
+            (id)kSecClass : (id)kSecClassGenericPassword,
+            (id)kSecAttrAccount : account,
+            (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+            (id)kSecMatchLimit : (id)kSecMatchLimitOne,
+        };
+        XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)findQuery, NULL), errSecSuccess, "Finding item %@", account);
+        ckksnotice("ckkstest", self.keychainView, "SecItemCopyMatching of %@ successful", account);
+
+        NSDate* end = [NSDate now];
+        NSTimeInterval delta = [end timeIntervalSinceDate:begin];
+
+        XCTAssertLessThan(delta, 2, @"Keychain API should respond in two seconds");
+        ckksnotice("ckkstest", self.keychainView, "SecItemAdd/SecItemCopyMatching pair of %@ took %.4fs", account, delta);
+
+        usleep(10000); // sleep for 10ms, to let some other things get done
+
+        // And retake the time elasped for the overall count
+        elapsed += [[NSDate now] timeIntervalSinceDate:begin];
+        count += 1;
+    }
+
     OCMVerifyAllWithDelay(self.mockDatabase, 40);
 }
 
 
     for(CKKSKeychainView* view in self.ckksViews) {
         XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:40*NSEC_PER_SEC], @"key state should enter 'waitfortlkcreation' (view %@)", view);
-        [keysetOps addObject: [view findKeySet]];
+        [keysetOps addObject: [view findKeySet:NO]];
     }
 
     // Now that we've kicked them all off, wait for them to resolve (and nudge each one, as if a key was saved)
 
         CKKSCondition* viewProcess = view.keyHierarchyConditions[SecCKKSZoneKeyStateProcess];
         [view keyStateMachineRequestProcess];
-        XCTAssertNotEqual(0, [viewProcess wait:500*NSEC_PER_MSEC], "CKKS should not reprocess the key hierarchy, even if nudged");
+
+        // Since we do need to leave SecCKKSZoneKeyStateWaitForTLKUpload if a fetch occurs with new keys, make sure we do the right thing
+        XCTAssertEqual(0, [viewProcess wait:10*NSEC_PER_MSEC], "CKKS should reprocess the key hierarchy when nudged");
+        XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKUpload] wait:40*NSEC_PER_SEC], @"key state should re-enter 'waitfortlkupload'");
     }
 
     // The views should remain in waitfortlkcreation, and not go through process into an error
         [keysetOp waitUntilFinished];
         XCTAssertNil(keysetOp.error, "Should be no error fetching keyset from CKKS");
 
-        NSArray<CKRecord*>* records = [self putKeySetInCloudKit:keysetOp.keyset];
-        [keyHierarchyRecords addObjectsFromArray:records];
-    }
+        NSArray<CKRecord*>* records = [self putKeySetInCloudKit:keysetOp.keyset];
+        [keyHierarchyRecords addObjectsFromArray:records];
+    }
+
+    // Tell our views about our shiny new records!
+    for(CKKSKeychainView* view in self.ckksViews) {
+        [view receiveTLKUploadRecords: keyHierarchyRecords];
+    }
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+}
+
+
+- (void)testReceiveChangedKeySetFromWaitingForTLKUpload {
+    // Test starts with nothing in database. CKKS should get into the "please upload my keys" state
+
+    [self startCKKSSubsystem];
+
+    // After each zone arrives in WaitForTLKCreation, new keys are uploaded
+    for(CKKSKeychainView* view in self.ckksViews) {
+        XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:40*NSEC_PER_SEC], @"key state should enter 'waitfortlkcreation' (view %@)", view);
+    }
+
+    for(CKKSKeychainView* view in self.ckksViews) {
+        [self putFakeKeyHierarchyInCloudKit:view.zoneID];
+        [self putFakeDeviceStatusInCloudKit:view.zoneID];
+    }
+
+    // If we ask the zones for their keysets, they should return the local set ready for upload
+    NSMutableArray<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* keysetOps = [NSMutableArray array];
+
+    for(CKKSKeychainView* view in self.ckksViews) {
+        [keysetOps addObject:[view findKeySet:NO]];
+    }
+
+    for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp in keysetOps) {
+        [keysetOp waitUntilFinished];
+        XCTAssertNil(keysetOp.error, "Should be no error fetching keyset from CKKS");
+
+        CKRecordZoneID* zoneID = [[CKRecordZoneID alloc] initWithZoneName:keysetOp.zoneName
+                                                                ownerName:CKCurrentUserDefaultName];
+        ZoneKeys* zk = self.keys[zoneID];
+        XCTAssertNotNil(zk, "Should have new zone keys for zone %@", keysetOp.zoneName);
+        XCTAssertNotEqualObjects(keysetOp.keyset.currentTLKPointer.currentKeyUUID, zk.tlk.uuid, "Fetched TLK and CK TLK should be different");
+    }
+
+    // Now, find the keysets again, asking for a fetch this time
+    NSMutableArray<CKKSResultOperation<CKKSKeySetProviderOperationProtocol>*>* fetchedKeysetOps = [NSMutableArray array];
+
+    for(CKKSKeychainView* view in self.ckksViews) {
+        [fetchedKeysetOps addObject:[view findKeySet:YES]];
+    }
+
+    for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp in fetchedKeysetOps) {
+        [keysetOp waitUntilFinished];
+        XCTAssertNil(keysetOp.error, "Should be no error fetching keyset from CKKS");
+
+        CKRecordZoneID* zoneID = [[CKRecordZoneID alloc] initWithZoneName:keysetOp.zoneName
+                                                                ownerName:CKCurrentUserDefaultName];
+        ZoneKeys* zk = self.keys[zoneID];
+        XCTAssertNotNil(zk, "Should have new zone keys for zone %@", keysetOp.zoneName);
+        XCTAssertEqualObjects(keysetOp.keyset.currentTLKPointer.currentKeyUUID, zk.tlk.uuid, "Fetched TLK and CK TLK should now match");
+    }
+}
+
+- (void)testProvideKeysetFromNoTrust {
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+
+    self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should become 'waitfortrust'");
+
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
+    [keysetOp timeout:20*NSEC_PER_SEC];
+    [keysetOp waitUntilFinished];
+
+    XCTAssertNil(keysetOp.error, "Should be no error fetching a keyset");
+}
+
+- (void)testProvideKeysetFromNoTrustWithRefetch {
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+
+    self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should become 'waitfortrust'");
+
+    self.silentFetchesAllowed = false;
+    [self expectCKFetch];
+
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:YES];
+    [keysetOp timeout:20*NSEC_PER_SEC];
+    [keysetOp waitUntilFinished];
 
-    // Tell our views about our shiny new records!
-    for(CKKSKeychainView* view in self.ckksViews) {
-        [view receiveTLKUploadRecords: keyHierarchyRecords];
-    }
-    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    XCTAssertNil(keysetOp.error, "Should be no error fetching a keyset");
 
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
-- (void)testProvideKeysetFromNoTrust {
+- (void)testProvideKeysetAfterReceivingTLKInNoTrust {
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
 
     self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
     [self startCKKSSubsystem];
 
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], @"Key state should become 'waitfortlkcreation'");
-    // I'm not sure how CKKS ends up in 'waitfortrust' without a keyset, so force that state
-    // In 52301278, it occurred with some complex interaction of zone deletions, fetches, and trust operations
-    [self.keychainView dispatchSyncWithAccountKeys:^bool{
-        [self.keychainView _onqueueAdvanceKeyStateMachineToState:SecCKKSZoneKeyStateWaitForTrust withError:nil];
-        return true;
-    }];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should become 'waitfortrust'");
 
-    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet];
+    // This isn't necessarily SOS, but perhaps SBD.
+    [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID];
+
+    // Still ends up in waitfortrust...
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should become 'waitfortrust'");
+
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
     [keysetOp timeout:20*NSEC_PER_SEC];
     [keysetOp waitUntilFinished];
 
     XCTAssertNil(keysetOp.error, "Should be no error fetching a keyset");
+    XCTAssertNotNil(keysetOp.keyset, "Should have a keyset");
+    XCTAssertNotNil(keysetOp.keyset.tlk, "Should have a TLK");
 }
 
-// This test no longer is very interesting, since Octagon needs to handle lock states, not CKKS...
 - (void)testUploadInitialKeyHierarchyAfterLockedStart {
     // 'Lock' the keybag
     self.aksLockState = true;
 
     [self startCKKSSubsystem];
 
-    // Wait for the key hierarchy state machine to get stuck waiting for the unlock dependency. No uploads should occur.
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], @"Key state should get stuck in waitfortlkcreation");
 
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
+
+    // Wait for the key hierarchy state machine to get stuck waiting for the unlock dependency. No uploads should occur.
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForUnlock] wait:20*NSEC_PER_SEC], @"Key state should get stuck in waitforunlock");
+
     // After unlock, the key hierarchy should be created.
     self.aksLockState = false;
     [self.lockStateTracker recheck];
 
-    [self performOctagonTLKUpload:self.ckksViews];
+    [keysetOp timeout:10 * NSEC_PER_SEC];
+    [keysetOp waitUntilFinished];
+    XCTAssertNil(keysetOp.error, @"Should be no error performing keyset op");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKUpload] wait:20*NSEC_PER_SEC], @"Key state should enter 'waitfortlkupload'");
+
+    NSArray<CKRecord*>* keyHierarchyRecords = [self putKeySetInCloudKit:keysetOp.keyset];
+    [self.keychainView receiveTLKUploadRecords:keyHierarchyRecords];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should enter 'ready'");
 
     // We expect a single class C record to be uploaded.
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
+- (void)testExitWaitForTLKUploadIfTLKsCreated {
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], @"Key state should get stuck in waitfortlkcreation");
+
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
+
+    [keysetOp timeout:10 * NSEC_PER_SEC];
+    [keysetOp waitUntilFinished];
+    XCTAssertNil(keysetOp.error, @"Should be no error performing keyset op");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKUpload] wait:20*NSEC_PER_SEC], @"Key state should enter 'waitfortlkupload'");
+
+    // But another device beats us to it!
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLK] wait:20*NSEC_PER_SEC], @"Key state should enter 'waitfortlk'");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
+- (void)testExitWaitForTLKUploadIfTLKsCreatedWhileNoTrust {
+    self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
+    [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], @"Key state should get stuck in waitfortlkcreation");
+
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
+
+    [keysetOp timeout:10 * NSEC_PER_SEC];
+    [keysetOp waitUntilFinished];
+    XCTAssertNil(keysetOp.error, @"Should be no error performing keyset op");
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKUpload] wait:20*NSEC_PER_SEC], @"Key state should enter 'waitfortlkupload'");
+
+    // But another device beats us to it!
+    [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
+    [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] wait:20*NSEC_PER_SEC], @"Key state should enter 'waitfortrust'");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+}
+
 - (void)testLockImmediatelyAfterUploadingInitialKeyHierarchy {
 
     __weak __typeof(self) weakSelf = self;
     // 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.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [[self.keychainView.zoneChangeFetcher requestSuccessfulFetch:CKKSFetchBecauseTesting] waitUntilFinished];
 
     self.aksLockState = false;
     [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"];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should become 'ready'");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 }
 
     [self putFakeDeviceStatusInCloudKit:self.keychainZoneID];
 
     // Also, CKKS _should_ be able to return the key hierarchy if asked before it starts
-    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet];
+    CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* keysetOp = [self.keychainView findKeySet:NO];
 
     NSDateComponents* offset = [[NSDateComponents alloc] init];
     [offset setDay:-5];
 
     // Verify that there are three local keys, and three local current key records
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         NSArray<CKKSCurrentKeyPointer*>* currentkeys = [CKKSCurrentKeyPointer all: &error];
         XCTAssertNil(error, "no error fetching current keys");
         XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database");
-
-        return false;
     }];
 }
 
 
     // Verify that there are three local keys, and three local current key records
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         NSArray<CKKSCurrentKeyPointer*>* currentkeys = [CKKSCurrentKeyPointer all: &error];
         XCTAssertNil(error, "no error fetching current keys");
         XCTAssertEqual(currentkeys.count, 3u, "Three current key pointers in local database");
-
-        return false;
     }];
 }
 
     [self startCKKSSubsystem];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should become 'ready'");
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword:@"classCItem" expecting:errSecItemNotFound];
     XCTAssertNotNil(self.keychainZoneKeys.classA, "Have class A key for zone");
     XCTAssertNotNil(self.keychainZoneKeys.classC, "Have class C key for zone");
 
-    [self.keychainView dispatchSyncWithAccountKeys: ^bool {
-        [self.keychainView _onqueueKeyStateMachineRequestProcess];
-        return true;
-    }];
+    [self.keychainView.stateMachine handleFlag:CKKSFlagKeyStateProcessRequested];
+
     // And ensure we end up back in 'readypendingunlock': we have the keys, we're just locked now
     [self.keychainView waitForOperationsOfClass:[CKKSProcessReceivedKeysOperation class]];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReadyPendingUnlock] wait:20*NSEC_PER_SEC], @"Key state should become 'readypendingunlock'");
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"classCItem" key:self.keychainZoneKeys.classC]];
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-FFFF-FFFF-FFFF-5A507ACB2D85" withAccount:@"classAItem" key:self.keychainZoneKeys.classA]];
 
-    CKKSResultOperation* op = [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    CKKSResultOperation* op = self.keychainView.resultsOfNextProcessIncomingQueueOperation;
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
     // The processing op should NOT error, even though it didn't manage to process the classA item
     XCTAssertNil(op.error, "no error while failing to process a class A item");
 
     [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
     [self saveTLKMaterialToKeychain:self.keychainZoneID];
 
-    // Trigger a notification
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     // Make life easy on this test; testAcceptKeyConflictAndUploadReencryptedItem will check the case when we don't receive the notification
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Just in extra case of threading issues, force a reexamination of the key hierarchy
-    [self.keychainView dispatchSyncWithAccountKeys: ^bool {
-        [self.keychainView _onqueueAdvanceKeyStateMachineToState: nil withError: nil];
-        return true;
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        [self.keychainView _onqueuePokeKeyStateMachine];
+        return CKKSDatabaseTransactionCommit;
     }];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should become 'ready'");
 
     // Verify that there are six local keys, and three local current key records
-    [self.keychainView dispatchSync: ^bool{
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
                 XCTFail("Unknown key class: %@", key.keyclass);
             }
         }
-
-        return false;
     }];
 
     // We expect a single record to be uploaded.
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
 
     // TODO: remove this by writing code for item reencrypt after key arrival
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self addGenericPassword: @"data" account: @"account-delete-me-rolled-key"];
     [self startCKKSSubsystem];
     [self.keychainView waitUntilAllOperationsAreFinished];
 
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
+
     // We expect a single record to be uploaded.
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
 
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self waitForCKModifications];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
 
     [self rollFakeKeyHierarchyInCloudKit:self.keychainZoneID];
 
 
     [self waitForCKModifications];
 
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // CKKS should not roll the keys while progressing back to 'ready', but it will fetch once
     self.silentFetchesAllowed = false;
     [self expectCKFetch];
 
-    [self.keychainView dispatchSyncWithAccountKeys: ^bool {
-        [self.keychainView _onqueueKeyStateMachineRequestFetch];
-        return true;
-    }];
+    [self.keychainView.stateMachine handleFlag:CKKSFlagFetchRequested];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should have returned to ready");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Spin up CKKS subsystem.
     [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
     [self.keychainView waitForFetchAndIncomingQueueProcessing]; // just to be sure it's fetched
 
     // Items should upload.
 
     // Spin up CKKS subsystem.
     [self startCKKSSubsystem];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"key state should enter 'ready'");
     [self.keychainView waitForFetchAndIncomingQueueProcessing]; // just to be sure it's fetched
 
     // Items should upload.
     XCTAssertNotEqualObjects(currentClassC.etag, self.keychainZone.currentDatabase[currentClassCID].etag, "Etag should have changed");
 
     // Add another item. This write should fail, then CKKS should recover without rolling the key hierarchy or issuing a fetch.
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     self.keychainView.holdOutgoingQueueOperation = [CKKSGroupOperation named:@"outgoing-hold" withBlock: ^{
-        secnotice("ckks", "releasing outgoing-queue hold");
+        ckksnotice_global("ckks", "releasing outgoing-queue hold");
     }];
 
     self.silentFetchesAllowed = false;
     XCTAssertTrue(self.keychainZone.flag, "Keychain zone shouldn't have been reset");
 }
 
+- (void)testOnboardOldItemMatchingExistingCKKSItem {
+    [self createAndSaveFakeKeyHierarchy: self.keychainZoneID];
+
+    NSString* itemAccount = @"account-delete-me";
+    [self addGenericPassword:@"password" account:itemAccount];
+
+    CKRecord* ckr = [self createFakeRecord:self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
+    [self.keychainZone addToZone:ckr];
+
+    [self startCKKSSubsystem];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should have become ready");
+
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
+
+    [self findGenericPassword:itemAccount expecting:errSecSuccess];
+
+    // And, the local item should now match the UUID downloaded from CKKS
+    [self checkGenericPasswordStoredUUID:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" account:itemAccount];
+}
+
 - (void)testResync {
     // We need to set up a desynced situation to test our resync.
     // First, let CKKS start up and send several items to CloudKit (that we'll then desync!)
     [self addGenericPassword: @"data" account: @"third"];
     [self addGenericPassword: @"data" account: @"fourth"];
     [self addGenericPassword: @"data" account: @"fifth"];
-    NSUInteger passwordCount = 5u;
+    [self addGenericPassword: @"data" account: @"sixth"];
+    NSUInteger passwordCount = 6u;
 
     [self checkGenericPassword: @"data" account: @"first"];
     [self checkGenericPassword: @"data" account: @"second"];
     [self checkGenericPassword: @"data" account: @"third"];
     [self checkGenericPassword: @"data" account: @"fourth"];
     [self checkGenericPassword: @"data" account: @"fifth"];
+    [self checkGenericPassword: @"data" account: @"sixth"];
 
     [self expectCKModifyItemRecords: passwordCount currentKeyPointerRecords: 1 zoneID:self.keychainZoneID];
 
     XCTAssertNotNil(deleteAccount, "received an account for the local delete object");
 
     __weak __typeof(self) weakSelf = self;
-    [self.keychainView dispatchSync:^bool{
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
             [iqe deleteFromDatabase: &error];
         }
         XCTAssertNil(error, "no error removing IQE");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // For the second record, delete all traces of it from CloudKit.
     [self checkGenericPassword:@"newpassword"  account:localDataChangedAccount];
     SecCKKSEnable();
 
+    // The sixth record matches what's in CloudKit, but the local UUID has changed (and CKKS didn't notice, for whatever reason)
+    CKRecord* uuidMismatch = items[5];
+    NSMutableDictionary* uuidMisMatchDictionary = [[self decryptRecord:uuidMismatch] mutableCopy];
+    NSString* uuidMismatchAccount = uuidMisMatchDictionary[(__bridge id)kSecAttrAccount];
+    NSString* newUUID = @"55463F83-3AAE-462D-B95F-2FA6AD088980";
+    SecCKKSDisable();
+    [self setGenericPasswordStoredUUID:newUUID account:uuidMismatchAccount];
+    [self checkGenericPasswordStoredUUID:newUUID account:uuidMismatchAccount];
+    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.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
+    // The seventh 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
     NSString* remoteOnlyAccount = @"remote-only";
     ckksnotice("ckksresync", self.keychainView, "Remote data changed: %@ %@", remoteDataChanged.recordID.recordName, remoteDataChangedAccount);
     ckksnotice("ckksresync", self.keychainView, "in-sync:             %@ %@", items[3].recordID.recordName, insyncAccount);
     ckksnotice("ckksresync", self.keychainView, "local update:        %@ %@", items[4].recordID.recordName, localDataChangedAccount);
+    ckksnotice("ckksresync", self.keychainView, "uuid mismatch:       %@ %@", items[5].recordID.recordName, uuidMismatchAccount);
     ckksnotice("ckksresync", self.keychainView, "Remote only:         %@ %@", ckr.recordID.recordName, remoteOnlyAccount);
 
     CKKSSynchronizeOperation* resyncOperation = [self.keychainView resyncWithCloud];
     [self findGenericPassword: remoteDataChangedAccount expecting: errSecSuccess];
     [self findGenericPassword: insyncAccount            expecting: errSecSuccess];
     [self findGenericPassword: localDataChangedAccount  expecting: errSecSuccess];
+    [self findGenericPassword: uuidMismatchAccount      expecting: errSecSuccess];
     [self findGenericPassword: remoteOnlyAccount        expecting: errSecSuccess];
 
     [self checkGenericPassword: @"data"         account: deleteAccount];
     [self checkGenericPassword: @"CloudKitWins" account: remoteDataChangedAccount];
     [self checkGenericPassword: @"data"         account: insyncAccount];
     [self checkGenericPassword:@"data"          account:localDataChangedAccount];
+    [self checkGenericPassword:@"data"          account:uuidMismatchAccount];
     [self checkGenericPassword: @"data"         account: remoteOnlyAccount];
 
-    [self.keychainView dispatchSync:^bool{
+    [self checkGenericPasswordStoredUUID:uuidMismatch.recordID.recordName account:uuidMismatchAccount];
+
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         __strong __typeof(weakSelf) strongSelf = weakSelf;
         XCTAssertNotNil(strongSelf, "self exists");
 
         ckme = [CKKSMirrorEntry tryFromDatabase:ckr.recordID.recordName zoneID:strongSelf.keychainZoneID error:&error];
         XCTAssertNil(error);
         XCTAssertNotNil(ckme);
-        return true;
     }];
 }
 
     [self startCKKSSubsystem];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self waitForCKModifications];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Now, place an item in the outgoing queue
 
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"fourth"];
     [self.keychainZone addToZone:ckr];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     // Now, where are we....
     CKKSScanLocalItemsOperation* scanLocal = [self.keychainView scanLocalItems:@"test-scan"];
-    [scanLocal waitUntilFinished];
-
-    XCTAssertEqual(scanLocal.missingLocalItemsFound, 1u, "Should have found one missing item");
+    // This operation will wait for the CKKSOutgoingQueue operation (currently held writing to cloudkit) to finish before beginning
 
     // Allow everything to proceed
     [self releaseCloudKitModificationHold];
+
+    [scanLocal waitUntilFinished];
+    XCTAssertEqual(scanLocal.missingLocalItemsFound, 1u, "Should have found one missing item");
+
     [self.operationQueue addOperation:self.keychainView.holdIncomingQueueOperation];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView waitForFetchAndIncomingQueueProcessing];
     [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
     // And ensure that all four items are present again
     [self startCKKSSubsystem];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     [self waitForCKModifications];
+
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
     [self findGenericPassword: @"second" expecting: errSecSuccess];
 }
 
+- (void)testEnsureScanOccursOnNextStartIfCancelled {
+    // We want to set up a situation where a CKKSScanLocalItemsOperation is cancelled by daemon quitting.
+    NSString* itemAccount = @"first";
+    [self addGenericPassword:@"data" account:itemAccount];
+    [self addGenericPassword:@"data" account:@"second"];
+
+    // We're going to pretend that the scan doesn't happen due to daemon restart
+    SecCKKSSetTestSkipScan(true);
+
+    [self createAndSaveFakeKeyHierarchy:self.keychainZoneID]; // Make life easy for this test.
+
+    [self startCKKSSubsystem];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self waitForCKModifications];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    // CKKS should perform normally if new items are added
+    [self expectCKModifyItemRecords:1 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+    [self addGenericPassword:@"found" account:@"after-setup"];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    // Now, simulate a restart
+    SecCKKSSetTestSkipScan(false);
+
+    [self expectCKModifyItemRecords:2 currentKeyPointerRecords:1 zoneID:self.keychainZoneID];
+
+    [self.keychainView halt];
+    self.keychainView = [[CKKSViewManager manager] restartZone:self.keychainZoneID.zoneName];
+    [self.keychainView beginCloudKitOperation];
+    [self beginSOSTrustedViewOperation:self.keychainView];
+
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self findGenericPassword:@"first"  expecting:errSecSuccess];
+    [self findGenericPassword:@"second" expecting:errSecSuccess];
+}
+
 - (void)testResyncLocal {
     [self putFakeKeyHierarchyInCloudKit:self.keychainZoneID];
     [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
 
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
     // Tear down the CKKS object and disallow fetches
     [self.keychainView halt];
     self.silentFetchesAllowed = false;
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
+    XCTAssertFalse(self.keychainView.initiatedLocalScan, "Should not have initiated a local items scan due to a restart with a recent fetch");
+
     // Okay, cool, rad, now let's set the date to be very long ago and check that there's positively a fetch
     [self.keychainView halt];
     self.silentFetchesAllowed = false;
 
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error];
 
         ckse.lastFetchTime = [NSDate distantPast];
         [ckse saveToDatabase: &error];
         XCTAssertNil(error, "no error saving to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     [self expectCKFetch];
     [self beginSOSTrustedViewOperation:self.keychainView];
     [self.keychainView waitForKeyHierarchyReadiness];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertFalse(self.keychainView.initiatedLocalScan, "Should not have initiated a local items scan due to a restart (when we haven't fetched in a while, but did scan recently)");
+
+    // Now restart again, but cause a scan to occur
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        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.lastLocalKeychainScanTime = [NSDate distantPast];
+        [ckse saveToDatabase:&error];
+        XCTAssertNil(error, "no error saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    [self.keychainView halt];
+    self.keychainView = [[CKKSViewManager manager] restartZone: self.keychainZoneID.zoneName];
+    [self beginSOSTrustedViewOperation:self.keychainView];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    XCTAssertTrue(self.keychainView.initiatedLocalScan, "Should have initiated a local items scan due to 24-hr notification");
+}
+
+- (void)testFetchAndScanOn24HrNotification {
+    // Every 24 hrs, CKKS should fetch if there hasn't been a fetch in a while.
+    [self startCKKSSubsystem];
+    [self performOctagonTLKUpload:self.ckksViews];
+
+    [self waitForCKModifications];
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    // We now get the 24-hr notification. Set this bit for later checking
+    XCTAssertTrue(self.keychainView.initiatedLocalScan, "Should have initiated a local items scan during bringup");
+    self.keychainView.initiatedLocalScan = NO;
+
+    self.silentFetchesAllowed = false;
+
+    [self.keychainView xpc24HrNotification];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    XCTAssertFalse(self.keychainView.initiatedLocalScan, "Should not have initiated a local items scan due to a 24-hr notification with a recent fetch");
+
+    // Okay, cool, rad, now let's set the last local-keychain-scan date to be very long ago and retry
+    // This shouldn't fetch, but it should scan the local keychain
+    self.silentFetchesAllowed = false;
+
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        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.lastLocalKeychainScanTime = [NSDate distantPast];
+        [ckse saveToDatabase:&error];
+        XCTAssertNil(error, "no error saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    [self.keychainView xpc24HrNotification];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    XCTAssertTrue(self.keychainView.initiatedLocalScan, "Should have initiated a local items scan due to 24-hr notification");
+    self.keychainView.initiatedLocalScan = false;
+
+    // And check that the fetch occurs as well
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        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.lastFetchTime = [NSDate distantPast];
+        [ckse saveToDatabase:&error];
+        XCTAssertNil(error, "no error saving to database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    [self expectCKFetch];
+    [self.keychainView xpc24HrNotification];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should arrive at ready");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView waitForOperationsOfClass:[CKKSScanLocalItemsOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
+    XCTAssertFalse(self.keychainView.initiatedLocalScan, "Should not have initiated a local items scan due to 24-hr notification (if we've done one recently)");
 }
 
 - (void)testRecoverFromZoneCreationFailure {
     [self waitForCKModifications];
     [self.keychainView waitUntilAllOperationsAreFinished];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85" withAccount:@"account0"];
                                                                             }), @"Deleting local keys");
     SecCKKSTestSetDisableKeyNotifications(false);
 
-    // Trigger a notification (with hilariously fake data)
     [self.keychainZone addToZone: ckr];
-    [self.keychainView notifyZoneChange:nil];
-    [self.keychainView waitForFetchAndIncomingQueueProcessing];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword: @"account0" expecting:errSecSuccess];
 
     // Trigger a notification (with hilariously fake data)
     [self.keychainZone addToZone: ckr];
-    [self.keychainView notifyZoneChange:nil];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should return to 'ready'");
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing]; // Do this again, to allow for non-atomic key state machinery switching
 
     [self findGenericPassword: @"account0" expecting:errSecSuccess];
     XCTAssertNil(error, "Should be no error deleting old key material from keychain");
 
     [self.keychainZone addToZone:ckrAddedLater];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword:accountShouldExist expecting:errSecSuccess];
     [self.lockStateTracker recheck];
 
     [self.keychainZone addToZone:ckrAddedLater];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Item should still not exist due to the lock state....
     [self waitForCKModifications];
 
     // Now, delete most of the key records are from on-disk, but the change token is not changed
-    [self.keychainView dispatchSync:^bool{
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         CKKSCurrentKeySet* keyset = [CKKSCurrentKeySet loadForZone:self.keychainZoneID];
 
         XCTAssertNotNil(keyset.currentTLKPointer, @"should be a TLK pointer");
         [keyset.classC deleteFromDatabase:&error];
         XCTAssertNil(error, "Should be no error deleting classC from database");
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // A restart should realize there's an issue, and pause for help
     [self startCKKSSubsystem];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered ready");
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateReady, "CKKS entered ready");
 
     // Network is unavailable
     [self.reachabilityTracker setNetworkReachability:false];
     // Say network is available
     [self.reachabilityTracker setNetworkReachability:true];
 
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword:@"account-delete-me" expecting:errSecSuccess];
     [self startCKKSSubsystem];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateInitializing] wait:20*NSEC_PER_SEC], "CKKS entered initializing");
-    XCTAssertEqualObjects(self.keychainView.keyHierarchyState, SecCKKSZoneKeyStateInitializing, "CKKS entered initializing");
 
     // Now, save the TLK to the keychain (to simulate it coming in later via SOS).
     [self expectCKKSTLKSelfShareUpload:self.keychainZoneID];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:8*NSEC_PER_SEC], "CKKS entered ready");
 
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+
     // Network is now unavailable
     [self.reachabilityTracker setNetworkReachability:false];
 
     [self expectCKFetch]; // and one to succeed
 
     // Trigger a fake change notification
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID];
 
     // Save a new device state record with some fake etag
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         CKKSDeviceStateEntry* cdse = [[CKKSDeviceStateEntry alloc] initForDevice:self.ckDeviceID
                                                                        osVersion:@"fake-record"
                                                                   lastUnlockTime:[NSDate date]
         [cdse saveToDatabase:&error];
         XCTAssertNil(error, @"No error saving cdse to database");
 
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // Spin up CKKS subsystem.
     CKRecord* ckr = [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"];
     [self.keychainZone addToZone:ckr];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     [self findGenericPassword:@"account-delete-me" expecting:errSecSuccess];
     // We expect CKKS to recreate the zone, then have octagon reupload the keys, and then the class C item upload
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     [self performOctagonTLKUpload:self.ckksViews];
 
     // We expect CKKS to reset itself and recover, then have octagon upload the keys, and then the class C item upload
     [self expectCKModifyItemRecords: 1 currentKeyPointerRecords: 1 zoneID:self.keychainZoneID checkItem: [self checkClassCBlock:self.keychainZoneID message:@"Object was encrypted under class C key in hierarchy"]];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     [self performOctagonTLKUpload:self.ckksViews];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     [self addGenericPassword: @"data" account: @"account-delete-me"];
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     // simulate a NSNotification callback (but still logged out)
     self.accountStatus = CKAccountStatusNoAccount;
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
     [self addGenericPassword: @"data" account: @"account-delete-me-3"];
 
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Test that there are no items in the database (since we never logged in)
     [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS should enter 'loggedout'");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForCloudKitAccountStatus] wait:20*NSEC_PER_SEC], "CKKS should enter 'waitforcloudkitaccount'");
 
     // There should be no uploads, even when we save keychain items and enter/exit circle
     [self addGenericPassword: @"data" account: @"account-delete-me"];
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
     [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
     [self beginSOSTrustedViewOperation:self.keychainView];
     [self addGenericPassword: @"data" account: @"account-delete-me-3"];
 
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Test that there are no items in the database (since we never were in an HSA2 account)
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     [self addGenericPassword: @"data" account: @"account-delete-me"];
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], "CKKS entered 'waitfortlkcreation'");
 
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
     [self addGenericPassword: @"data" account: @"account-delete-me-3"];
 
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Test that there are no items in the database (since we never logged in)
     [self startCKKSSubsystem];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should have arrived at ready");
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     // But then, trust departs
     self.mockSOSAdapter.circleStatus = kSOSCCNotInCircle;
 
     // No writes yet, since we're not in circle
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:20*NSEC_PER_SEC], "CKKS entered 'waitfortlkcreation'");
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
 
     self.mockSOSAdapter.circleStatus = kSOSCCInCircle;
     [self.accountStateTracker notifyCircleStatusChangeAndWaitForSignal];
     [self checkNoCKKSData: self.keychainView];
 
     // Force zone into error state
-    self.keychainView.keyHierarchyState = SecCKKSZoneKeyStateError;
+    OctagonStateTransitionOperation* transitionOp = [OctagonStateTransitionOperation named:@"enter" entering:SecCKKSZoneKeyStateError];
+    OctagonStateTransitionRequest* request = [[OctagonStateTransitionRequest alloc] init:@"enter-wait-for-trust"
+                                                                            sourceStates:[NSSet setWithArray:[CKKSZoneKeyStateMap() allKeys]]
+                                                                             serialQueue:self.keychainView.queue
+                                                                                 timeout:10 * NSEC_PER_SEC
+                                                                            transitionOp:transitionOp];
+    [self.keychainView.stateMachine handleExternalRequest:request];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateError] wait:20*NSEC_PER_SEC], "CKKS entered 'error'");
 
     self.accountStatus = CKAccountStatusAvailable;
     [self.accountStateTracker notifyCKAccountStatusChangeAndWaitForSignal];
     [op addDependency:self.keychainView.keyStateReadyDependency];
     [self.operationQueue addOperation:op];
 
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
+
     XCTAssertEqual(0,    [self.keychainView.loggedIn wait:2000*NSEC_PER_MSEC], "Should have been told of a 'login'");
     XCTAssertNotEqual(0, [self.keychainView.loggedOut wait:100*NSEC_PER_MSEC], "'logout' event should be reset");
     XCTAssertEqual(0,    [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKK should know the account state");
     XCTAssertEqual(0,    [self.keychainView.loggedOut wait:20*NSEC_PER_SEC], "Should have been told of a 'logout'");
     XCTAssertNotEqual(0, [self.keychainView.loggedIn wait:50*NSEC_PER_MSEC], "'login' event should be reset");
     XCTAssertEqual(0,    [self.keychainView.accountStateKnown wait:50*NSEC_PER_MSEC], "CKK should know the account state");
-    [self checkNoCKKSData: self.keychainView];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered 'logged out'");
+    [self checkNoCKKSData:self.keychainView];
 
     // There should be no further uploads, even when we save keychain items
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
     [self addGenericPassword: @"data" account: @"account-delete-me-3"];
 
-    [self.keychainView waitUntilAllOperationsAreFinished];
+    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
+    [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // Also, fetches shouldn't occur
 
     // And fetching still works!
     [self.keychainZone addToZone: [self createFakeRecord: self.keychainZoneID recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D00" withAccount:@"account0"]];
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
     [self findGenericPassword: @"account0" expecting:errSecSuccess];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
 
     // Add a keychain item, and make sure it doesn't upload yet.
     [self addGenericPassword: @"data" account: @"account-delete-me"];
-    [self.keychainView waitForOperationsOfClass:[CKKSOutgoingQueueOperation class]];
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered 'loggedout'");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForCloudKitAccountStatus] wait:20*NSEC_PER_SEC], "CKKS entered 'waitforcloudkitaccount'");
+    XCTAssertNotEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:1*NSEC_PER_SEC], "CKKS shouldn't have entered 'waitforcloudkitaccount'");
 
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
     // CKKS shouldn't decide to poke its state machine, but it should still send the notification
     XCTestExpectation* viewChangeNotification = [self expectChangeForView:self.keychainZoneID.zoneName];
 
-    // Reject all attempts to trigger a state machine update
-    id pokeKeyStateMachineScheduler = OCMClassMock([CKKSNearFutureScheduler class]);
-    OCMReject([pokeKeyStateMachineScheduler trigger]);
-    self.keychainView.pokeKeyStateMachineScheduler = pokeKeyStateMachineScheduler;
-
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
 
     [self waitForExpectations:@[viewChangeNotification] timeout:8];
-    [pokeKeyStateMachineScheduler stopMocking];
 }
 
 - (void)testUploadSyncableItemsAddedWhileUntrusted {
 
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
 
-    sleep(2);
-
     NSError* error = nil;
     NSDictionary* currentOQEs = [CKKSOutgoingQueueEntry countsByStateInZone:self.keychainZoneID error:&error];
     XCTAssertNil(error, "Should be no error counting OQEs");
     XCTAssertNil(error, "Should be no error counting OQEs");
     XCTAssertEqual(0, currentOQEs.count, "Should be no OQEs");
 
-    [self.injectedManager setSyncingViews:self.managedViewList sortingPolicy:self.viewSortingPolicyForManagedViewList];
+    [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
     self.keychainView = [self.injectedManager findView:self.keychainZoneID.zoneName];
     // end of daemon restart
 
     [self addGenericPassword: @"data" account: @"account-delete-me-2"];
     XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:100*NSEC_PER_MSEC], "CKKS should still have no idea what the account state is");
     XCTAssertEqual(self.keychainView.accountStatus, CKKSAccountStatusUnknown, "Account status should be unknown");
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered 'logged out'");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForCloudKitAccountStatus] wait:20*NSEC_PER_SEC], "CKKS entered 'waitforcloudkitaccount'");
 
     [self.keychainView beginCloudKitOperation];
 
     [self updateGenericPassword:@"newdata" account: @"account-delete-me-2"];
     XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:100*NSEC_PER_MSEC], "CKKS should still have no idea what the account state is");
     XCTAssertEqual(self.keychainView.accountStatus, CKKSAccountStatusUnknown, "Account status should be unknown");
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered 'logged out'");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForCloudKitAccountStatus] wait:20*NSEC_PER_SEC], "CKKS entered 'waitforcloudkitaccount'");
 
     [self.keychainView beginCloudKitOperation];
 
     [self deleteGenericPassword:@"account-delete-me-2"];
     XCTAssertNotEqual(0, [self.keychainView.accountStateKnown wait:100*NSEC_PER_MSEC], "CKKS should still have no idea what the account state is");
     XCTAssertEqual(self.keychainView.accountStatus, CKKSAccountStatusUnknown, "Account status should be unknown");
-    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateLoggedOut] wait:20*NSEC_PER_SEC], "CKKS entered 'logged out'");
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForCloudKitAccountStatus] wait:20*NSEC_PER_SEC], "CKKS entered 'waitforcloudkitaccount'");
 
     [self.keychainView beginCloudKitOperation];
 
     [self startCKKSSubsystem];
 
     [self waitForExpectations: @[operationRun] timeout:20];
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "CKKS entered 'ready'");
 }
 
 - (void)testCKKSControlBringup {
     }
 
     [self measureBlock:^{
-        [self.keychainView dispatchSyncWithAccountKeys:^bool{
+        [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
             for(CKRecord* record in tlkShareRecords) {
                 [self.keychainView _onqueueCKRecordChanged:record resync:false];
             }
-            return true;
+            return CKKSDatabaseTransactionCommit;
         }];
     }];
 }
 
     [self saveTLKMaterialToKeychainSimulatingSOS:self.keychainZoneID];
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
 
     XCTAssertNotEqual(0, [fetcherCondition wait:(3 * NSEC_PER_SEC)], "not supposed to get a fetch data");
 
index e0701910f012ba6dd04654f9804d66f802bdc900..dea65b2ad7d42de3925e2a57d936b092e714901b 100644 (file)
@@ -49,7 +49,7 @@
 
 - (void)testNoFixupOnInitialStart {
     id mockFixups = OCMClassMock([CKKSFixups class]);
-    OCMReject([[[mockFixups stub] ignoringNonObjectArgs] fixup:0 for:[OCMArg any]]);
+    [[[mockFixups reject] ignoringNonObjectArgs] fixup:0 for:[OCMArg any]];
 
     [self startCKKSSubsystem];
     [self performOctagonTLKUpload:self.ckksViews];
     CKRecord* currentPointerRecord2 = self.keychainZone.currentDatabase[currentPointerRecordID2];
     XCTAssertNotNil(currentPointerRecord2, "Found record in CloudKit at expected UUID");
 
-    [self.keychainView notifyZoneChange:nil];
+    [self.injectedManager.zoneChangeFetcher notifyZoneChange:nil];
     [self.keychainView waitForFetchAndIncomingQueueProcessing];
 
     // Tear down the CKKS object
     [self.keychainView halt];
 
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         // Edit the zone state entry to have no fixups
         NSError* error = nil;
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error];
         XCTAssertEqual(cip3.identifier, @"garbage", "Identifier is what we thought it was");
         [cip3 saveToDatabase:&error];
         XCTAssertNil(error, "no error saving to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     self.silentFetchesAllowed = false;
     [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
-    [self.keychainView dispatchSync: ^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         // The zone state entry should be up the most recent fixup level
         NSError* error = nil;
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:self.keychainZoneID.zoneName error:&error];
         }
 
         [self waitForExpectations:@[foundCIP2] timeout:0.1];
-        return true;
     }];
 }
 
 - (void)setFixupNumber:(CKKSFixup)newFixup ckks:(CKKSKeychainView*)ckks {
-    [ckks dispatchSync: ^bool {
+    [ckks dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         // Edit the zone state entry to have no fixups
         NSError* error = nil;
         CKKSZoneStateEntry* ckse = [CKKSZoneStateEntry fromDatabase:ckks.zoneID.zoneName error:&error];
         ckse.lastFixup = newFixup;
         [ckse saveToDatabase: &error];
         XCTAssertNil(error, "no error saving to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 }
 
     [self waitForCKModifications];
     OCMVerifyAllWithDelay(self.mockDatabase, 20);
 
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
+
     // Tear down the CKKS object
     [self.keychainView halt];
     [self setFixupNumber:CKKSFixupRefetchCurrentItemPointers ckks:self.keychainView];
 
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForFixupOperation] wait:20*NSEC_PER_SEC], "Key state should become waitforfixup");
 
-    self.silentFetchesAllowed = true;
     [self releaseCloudKitFetchHold];
     XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], "Key state should become ready");
 
     XCTAssertNil(self.keychainView.lastFixupOperation.error, "Shouldn't have been any error performing fixup");
 
     // and check that the share made it
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* blockerror = nil;
         CKKSTLKShareRecord* localshare = [CKKSTLKShareRecord tryFromDatabaseFromCKRecordID:shareCKRecord.recordID error:&blockerror];
         XCTAssertNil(blockerror, "Shouldn't error finding new TLKShare record in database");
         XCTAssertNotNil(localshare, "Should be able to find a new TLKShare record in database");
-        return true;
     }];
 }
 
     [self deleteGenericPassword:@"first"];
 
     // Corrupt the second item's CKMirror entry to only contain system fields in the CKRecord portion (to emulate early CKKS behavior)
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         CKKSMirrorEntry* ckme = [CKKSMirrorEntry fromDatabase:secondRecordID.recordName zoneID:self.keychainZoneID error:&error];
         XCTAssertNil(error, "Should have no error pulling second CKKSMirrorEntry from database");
 
         [ckme saveToDatabase:&error];
         XCTAssertNil(error, "No error saving system-fielded CKME back to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // Now, restart CKKS, but place a hold on the fixup operation
 
 
     // Modify the sqlite DB to simulate how earlier verions would save these records
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
         NSError* error = nil;
         CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry fromDatabase:self.remoteSOSOnlyPeer.peerID zoneID:self.keychainZoneID error:&error];
         XCTAssertNil(error, "Should have no error pulling CKKSDeviceStateEntry from database");
 
         [cdse saveToDatabase:&error];
         XCTAssertNil(error, "No error saving modified CDSE back to database");
-        return true;
+        return CKKSDatabaseTransactionCommit;
     }];
 
     // Tear down the CKKS object
     [self.keychainView waitForOperationsOfClass:[CKKSIncomingQueueOperation class]];
 
     // And all CDSEs should have an octagon peer ID again!
-    [self.keychainView dispatchSync:^bool {
+    [self.keychainView dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         CKKSDeviceStateEntry* cdse = [CKKSDeviceStateEntry fromDatabase:self.remoteSOSOnlyPeer.peerID zoneID:self.keychainZoneID error:&error];
         XCTAssertNil(error, "Should have no error pulling CKKSDeviceStateEntry from database");
 
         XCTAssertNotNil(cdse.octagonPeerID, "CDSE should have an octagon peer ID");
         XCTAssertNotNil(cdse.octagonStatus, "CDSE should have an octagon status");
-        return false;
     }];
 }
 
+- (void)testFixupDeletesTombstoneEntries {
+    [self startCKKSSubsystem];
+    [self performOctagonTLKUpload:self.ckksViews];
+
+    XCTAssertEqual(0, [self.keychainView.keyHierarchyConditions[SecCKKSZoneKeyStateReady] wait:20*NSEC_PER_SEC], @"Key state should become 'ready'");
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+    [self waitForCKModifications];
+
+    // The CKKS stack now rejects tombstone items. So, let's inject one out of band.
+
+    [self.keychainView halt];
+
+    [self setFixupNumber:CKKSFixupResaveDeviceStateEntries ckks:self.keychainView];
+
+    CKRecord* ckr = [self createFakeTombstoneRecord:self.keychainZoneID
+                                         recordName:@"7B598D31-F9C5-481E-98AC-5A507ACB2D85"
+                                            account:@"account-delete-me"];
+    [self.keychainZone addToZone:ckr];
+
+    [self.keychainView dispatchSyncWithSQLTransaction:^CKKSDatabaseTransactionResult{
+        CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKRecord:ckr];
+        NSError* error = nil;
+        [ckme saveToDatabase:&error];
+
+        XCTAssertNil(error, "Should be no error saving the CKME to the database");
+        return CKKSDatabaseTransactionCommit;
+    }];
+
+    // Now, restart CKKS. The bad record should be deleted.
+    [self expectCKDeleteItemRecords:1 zoneID:self.keychainZoneID];
+
+    self.keychainView = [[CKKSViewManager manager] restartZone:self.keychainZoneID.zoneName];
+    [self beginSOSTrustedViewOperation:self.keychainView];
+
+    // Deletions should occur
+    OCMVerifyAllWithDelay(self.mockDatabase, 20);
+
+    [self.keychainView.lastFixupOperation waitUntilFinished];
+    XCTAssertNil(self.keychainView.lastFixupOperation.error, "Shouldn't have been any error performing fixup");
+
+    [self findGenericPassword:@"account-delete-me" expecting:errSecItemNotFound];
+}
+
 @end
 
 #endif // OCTAGON
index f64abed9bf3ab1a68d222ad251f0e55430fc4da0..1b01318e2118994ccacb2def8e607ebc2121063c 100644 (file)
@@ -29,7 +29,6 @@
 #import "keychain/ckks/CKKSCurrentKeyPointer.h"
 #import "keychain/ckks/CKKSItem.h"
 #import "keychain/ckks/tests/CKKSMockSOSPresentAdapter.h"
-#import "keychain/ot/proto/generated_source/OTAccountMetadataClassC.h"
 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
 #include "OSX/sec/Security/SecItemShim.h"
 
@@ -51,7 +50,6 @@ NS_ASSUME_NONNULL_BEGIN
 @interface CloudKitKeychainSyncingMockXCTest : CloudKitMockXCTest
 
 @property CKKSControl* ckksControl;
-@property OTCuttlefishAccountStateHolder *accountMetaDataStore;
 @property (nullable) id mockCKKSKeychainBackedKey;
 
 @property (nullable) NSError* keychainFetchError;
@@ -62,8 +60,9 @@ NS_ASSUME_NONNULL_BEGIN
 // Set this to false after calling -setUp if you want to initialize the views yourself
 @property bool automaticallyBeginCKKSViewCloudKitOperation;
 
-// Fill this in before allowing initialization to use your own mock instead of a default stub
+// Fill these in before allowing initialization to use your own mock instead of a default stub
 @property id suggestTLKUpload;
+@property id requestPolicyCheck;
 
 @property NSMutableSet<CKKSKeychainView*>* ckksViews;
 @property NSMutableSet<CKRecordZoneID*>* ckksZones;
@@ -122,14 +121,19 @@ NS_ASSUME_NONNULL_BEGIN
                   withAccount:(NSString* _Nullable)account
                           key:(CKKSKey* _Nullable)key;
 
+- (CKRecord*)createFakeTombstoneRecord:(CKRecordZoneID*)zoneID recordName:(NSString*)recordName account:(NSString*)account;
+
 - (CKKSItem*)newItem:(CKRecordID*)recordID withNewItemData:(NSDictionary*) dictionary key:(CKKSKey*)key;
 - (CKRecord*)newRecord:(CKRecordID*)recordID withNewItemData:(NSDictionary*)dictionary;
 - (CKRecord*)newRecord:(CKRecordID*)recordID withNewItemData:(NSDictionary*)dictionary key:(CKKSKey*)key;
 - (NSDictionary*)decryptRecord:(CKRecord*)record;
 
+- (void)addItemToCloudKitZone:(NSDictionary*)itemDict recordName:(NSString*)recordName zoneID:(CKRecordZoneID*)zoneID;
+
 // Do keychain things:
 - (void)addGenericPassword:(NSString*)password account:(NSString*)account;
 - (void)addGenericPassword:(NSString*)password account:(NSString*)account viewHint:(NSString* _Nullable)viewHint;
+- (void)addGenericPassword:(NSString*)password account:(NSString*)account accessGroup:(NSString*)accessGroup;
 - (void)addGenericPassword:(NSString*)password
                    account:(NSString*)account
                   viewHint:(NSString* _Nullable)viewHint
@@ -158,6 +162,9 @@ NS_ASSUME_NONNULL_BEGIN
 - (void)findGenericPassword:(NSString*)account expecting:(OSStatus)status;
 - (void)checkGenericPassword:(NSString*)password account:(NSString*)account;
 
+- (void)checkGenericPasswordStoredUUID:(NSString*)uuid account:(NSString*)account;
+- (void)setGenericPasswordStoredUUID:(NSString*)uuid account:(NSString*)account;
+
 - (void)createClassCItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account;
 - (void)createClassAItemAndWaitForUpload:(CKRecordZoneID*)zoneID account:(NSString*)account;
 
index f7edec830d5cc3902162ed3718adef9960fe24ab..44da3423271783247ca07f9871f40e9efc7bcca8 100644 (file)
 
 #if OCTAGON
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
 #import <OCMock/OCMock.h>
+#pragma clang diagnostic pop
 
 #import "keychain/ckks/tests/CloudKitMockXCTest.h"
 #import "keychain/ckks/tests/CloudKitKeychainSyncingMockXCTest.h"
 
+#import "keychain/securityd/SecItemSchema.h"
 #import "keychain/securityd/SecItemServer.h"
 #import "keychain/securityd/SecItemDb.h"
 
     self.suggestTLKUpload = OCMClassMock([CKKSNearFutureScheduler class]);
     OCMStub([self.suggestTLKUpload trigger]);
 
+    self.requestPolicyCheck = OCMClassMock([CKKSNearFutureScheduler class]);
+    OCMStub([self.requestPolicyCheck trigger]);
+
     // If a subclass wants to fill these in before calling setUp, fine.
     self.ckksZones = self.ckksZones ?: [NSMutableSet set];
     self.ckksViews = self.ckksViews ?: [NSMutableSet set];
     OCMStub([mockConnection remoteObjectProxyWithErrorHandler:[OCMArg any]]).andCall(self, @selector(injectedManager));
     self.ckksControl = [[CKKSControl alloc] initWithConnection:mockConnection];
     XCTAssertNotNil(self.ckksControl, "Should have received control object");
-
-    self.accountMetaDataStore = OCMPartialMock([[OTCuttlefishAccountStateHolder alloc]init]);
-    OCMStub([self.accountMetaDataStore loadOrCreateAccountMetadata:[OCMArg anyObjectRef]]).andCall(self, @selector(loadOrCreateAccountMetadata:));
 }
 
 - (void)tearDown {
-    // Make sure the key state machine won't be poked after teardown
+    // Make sure the key state machines won't continue
     for(CKKSKeychainView* view in self.ckksViews) {
-        [view.pokeKeyStateMachineScheduler cancel];
+        [view.stateMachine haltOperation];
     }
     [self.ckksViews removeAllObjects];
 
     [self.mockCKKSKeychainBackedKey stopMocking];
     self.mockCKKSKeychainBackedKey = nil;
 
-    [((id)self.accountMetaDataStore) stopMocking];
-
     self.remoteSOSOnlyPeer = nil;
 }
 
         [view beginCloudKitOperation];
     }
 
-    [view beginTrustedOperation:@[self.mockSOSAdapter] suggestTLKUpload:self.suggestTLKUpload];
+    [view beginTrustedOperation:@[self.mockSOSAdapter]
+               suggestTLKUpload:self.suggestTLKUpload
+             requestPolicyCheck:self.requestPolicyCheck];
 }
 
 - (void)endSOSTrustedOperationForAllViews {
     NSError* error = nil;
 
     ZoneKeys* zonekeys = [[ZoneKeys alloc] init];
+    zonekeys.viewName = zoneID.zoneName;
 
     zonekeys.tlk = [self fakeTLK:zoneID];
     [zonekeys.tlk CKRecordWithZoneID: zoneID]; // no-op here, but memoize in the object
 }
 
 - (void)saveFakeKeyHierarchyToLocalDatabase: (CKRecordZoneID*)zoneID {
-    NSError* error = nil;
     ZoneKeys* zonekeys = [self createFakeKeyHierarchy: zoneID oldTLK:nil];
 
-    [zonekeys.tlk saveToDatabase:&error];
-    XCTAssertNil(error, "TLK saved to database successfully");
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult {
+        NSError* error = nil;
+
+        [zonekeys.tlk saveToDatabase:&error];
+        XCTAssertNil(error, "TLK saved to database successfully");
+
+        [zonekeys.classA saveToDatabase:&error];
+        XCTAssertNil(error, "Class A key saved to database successfully");
 
-    [zonekeys.classA saveToDatabase:&error];
-    XCTAssertNil(error, "Class A key saved to database successfully");
+        [zonekeys.classC saveToDatabase:&error];
+        XCTAssertNil(error, "Class C key saved to database successfully");
 
-    [zonekeys.classC saveToDatabase:&error];
-    XCTAssertNil(error, "Class C key saved to database successfully");
+        [zonekeys.currentTLKPointer saveToDatabase:&error];
+        XCTAssertNil(error, "Current TLK pointer saved to database successfully");
 
-    [zonekeys.currentTLKPointer saveToDatabase:&error];
-    XCTAssertNil(error, "Current TLK pointer saved to database successfully");
+        [zonekeys.currentClassAPointer saveToDatabase:&error];
+        XCTAssertNil(error, "Current Class A pointer saved to database successfully");
 
-    [zonekeys.currentClassAPointer saveToDatabase:&error];
-    XCTAssertNil(error, "Current Class A pointer saved to database successfully");
+        [zonekeys.currentClassCPointer saveToDatabase:&error];
+        XCTAssertNil(error, "Current Class C pointer saved to database successfully");
 
-    [zonekeys.currentClassCPointer saveToDatabase:&error];
-    XCTAssertNil(error, "Current Class C pointer saved to database successfully");
+        return CKKSDatabaseTransactionCommit;
+    }];
 }
 
 - (void)putFakeDeviceStatusInCloudKit:(CKRecordZoneID*)zoneID zonekeys:(ZoneKeys*)zonekeys {
 
     for(CKKSKeychainView* view in views) {
         XCTAssertEqual(0, [view.keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTLKCreation] wait:40*NSEC_PER_SEC], @"key state should enter 'waitfortlkcreation' (view %@)", view);
-        [keysetOps addObject: [view findKeySet]];
+        [keysetOps addObject: [view findKeySet:NO]];
     }
 
     // Now that we've kicked them all off, wait for them to resolve
@@ -577,6 +587,7 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     CFReleaseNull(cferror);
     return piggybackdata;
 }
+
 - (void)SOSPiggyBackAddToKeychain:(NSDictionary*)piggydata{
     __block CFErrorRef cferror = NULL;
     kc_with_dbt(true, &cferror, ^bool (SecDbConnectionRef dbt) {
@@ -676,11 +687,15 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     ZoneKeys* keys = self.keys[zoneID];
     XCTAssertNotNil(keys, "Have a zonekeys object for this zone");
 
-    for(CKKSTLKShareRecord* share in keys.tlkShares) {
-        NSError* error = nil;
-        [share saveToDatabase:&error];
-        XCTAssertNil(error, "Shouldn't have been an error saving a TLKShare to the database");
-    }
+    [CKKSSQLDatabaseObject performCKKSTransaction:^CKKSDatabaseTransactionResult{
+        for(CKKSTLKShareRecord* share in keys.tlkShares) {
+            NSError* error = nil;
+            [share saveToDatabase:&error];
+            XCTAssertNil(error, "Shouldn't have been an error saving a TLKShare to the database");
+        }
+
+        return CKKSDatabaseTransactionCommit;
+    }];
 }
 
 - (void)createAndSaveFakeKeyHierarchy: (CKRecordZoneID*)zoneID {
@@ -862,7 +877,7 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
 
 - (void)checkNoCKKSData: (CKKSKeychainView*) view {
     // Test that there are no items in the database
-    [view dispatchSync:^bool{
+    [view dispatchSyncWithReadOnlySQLTransaction:^{
         NSError* error = nil;
         NSArray<CKKSMirrorEntry*>* ckmes = [CKKSMirrorEntry all: view.zoneID error:&error];
         XCTAssertNil(error, "No error fetching CKMEs");
@@ -883,7 +898,6 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
         NSArray<CKKSDeviceStateEntry*>* deviceStates = [CKKSDeviceStateEntry allInZone:view.zoneID error:&error];
         XCTAssertNil(error, "should be no error fetching device states");
         XCTAssertEqual(deviceStates.count, 0ul, "No Device State entries");
-        return false;
     }];
 }
 
@@ -982,6 +996,15 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     return item;
 }
 
+
+- (CKRecord*)createFakeTombstoneRecord:(CKRecordZoneID*)zoneID recordName:(NSString*)recordName account:(NSString*)account {
+    NSMutableDictionary* item = [[self fakeRecordDictionary:account zoneID:zoneID] mutableCopy];
+    item[@"tomb"] = @YES;
+
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:recordName zoneID:zoneID];
+    return [self newRecord:ckrid withNewItemData:item];
+}
+
 - (CKRecord*)createFakeRecord: (CKRecordZoneID*)zoneID recordName:(NSString*)recordName {
     return [self createFakeRecord: zoneID recordName:recordName withAccount: nil key:nil];
 }
@@ -1037,6 +1060,17 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     return ckr;
 }
 
+- (void)addItemToCloudKitZone:(NSDictionary*)itemDict recordName:(NSString*)recordName zoneID:(CKRecordZoneID*)zoneID
+{
+    FakeCKZone* zone = self.zones[zoneID];
+    XCTAssertNotNil(zone, "Should have a zone for %@", zoneID);
+
+    CKRecordID* ckrid = [[CKRecordID alloc] initWithRecordName:recordName zoneID:zoneID];
+    CKRecord* record = [self newRecord:ckrid withNewItemData:itemDict];
+
+    [zone addToZone:record];
+}
+
 - (NSDictionary*)decryptRecord: (CKRecord*) record {
     CKKSItem* item = [[CKKSItem alloc] initWithCKRecord: record];
 
@@ -1099,6 +1133,18 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     [self addGenericPassword:password account:account viewHint:viewHint access:(id)kSecAttrAccessibleAfterFirstUnlock expecting:errSecSuccess message:@"Add item to keychain with a viewhint"];
 }
 
+
+- (void)addGenericPassword:(NSString*)password account:(NSString*)account accessGroup:(NSString*)accessGroup
+{
+    [self addGenericPassword:password
+                     account:account
+                      access:(id)kSecAttrAccessibleAfterFirstUnlock
+                    viewHint:nil
+                 accessGroup:accessGroup
+                   expecting:errSecSuccess
+                     message:@"Add item to keychain with an access group"];
+}
+
 - (void)updateGenericPassword: (NSString*) newPassword account: (NSString*)account {
     NSDictionary* query = @{
                                     (id)kSecClass : (id)kSecClassGenericPassword,
@@ -1178,10 +1224,83 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     XCTAssertEqualObjects(storedPassword, password, "Stored password should match received password");
 }
 
+- (void)checkGenericPasswordStoredUUID:(NSString*)uuid account:(NSString*)account {
+    NSDictionary* queryAttributes = @{(id)kSecClass: (id)kSecClassGenericPassword,
+                                      (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+                                      (id)kSecAttrAccount : account,
+                                      (id)kSecAttrSynchronizable: @(YES),
+                                      (id)kSecReturnAttributes : @(YES),
+                                      (id)kSecReturnData : (id)kCFBooleanTrue,
+    };
+
+    __block CFErrorRef cferror = nil;
+    Query *q = query_create_with_limit( (__bridge CFDictionaryRef)queryAttributes, NULL, kSecMatchUnlimited, NULL, &cferror);
+    XCTAssertNil((__bridge id)cferror, "Should be no error creating query");
+    CFReleaseNull(cferror);
+
+    __block size_t count = 0;
+
+    bool ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt) {
+        return SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) {
+            count += 1;
+
+            NSString* itemUUID = (NSString*) CFBridgingRelease(CFRetain(SecDbItemGetValue(item, &v10itemuuid, &cferror)));
+            XCTAssertEqualObjects(uuid, itemUUID, "Item uuid should match expectation");
+        });
+    });
+
+    XCTAssertTrue(ok, "query should have been successful");
+    XCTAssertNil((__bridge id)cferror, "Should be no error performing query");
+    CFReleaseNull(cferror);
+
+    XCTAssertEqual(count, 1, "Should have processed one item");
+}
+
+- (void)setGenericPasswordStoredUUID:(NSString*)uuid account:(NSString*)account {
+    NSDictionary* queryAttributes = @{(id)kSecClass: (id)kSecClassGenericPassword,
+                                      (id)kSecAttrAccessGroup : @"com.apple.security.ckks",
+                                      (id)kSecAttrAccount : account,
+                                      (id)kSecAttrSynchronizable: @(YES),
+                                      (id)kSecReturnAttributes : @(YES),
+                                      (id)kSecReturnData : (id)kCFBooleanTrue,
+    };
+
+    __block CFErrorRef cferror = nil;
+    Query *q = query_create_with_limit( (__bridge CFDictionaryRef)queryAttributes, NULL, kSecMatchUnlimited, NULL, &cferror);
+    XCTAssertNil((__bridge id)cferror, "Should be no error creating query");
+    CFReleaseNull(cferror);
+
+    __block size_t count = 0;
+
+    bool ok = kc_with_dbt(true, &cferror, ^(SecDbConnectionRef dbt) {
+        return SecDbItemQuery(q, NULL, dbt, &cferror, ^(SecDbItemRef item, bool *stop) {
+            count += 1;
+
+            NSDictionary* updates = @{(id) kSecAttrUUID: uuid};
+
+            SecDbItemRef new_item = SecDbItemCopyWithUpdates(item, (__bridge CFDictionaryRef)updates, &cferror);
+            XCTAssertTrue(new_item != NULL, "Should be able to create a new item");
+
+            bool updateOk = kc_transaction_type(dbt, kSecDbExclusiveRemoteCKKSTransactionType, &cferror, ^{
+                return SecDbItemUpdate(item, new_item, dbt, kCFBooleanFalse, q->q_uuid_from_primary_key, &cferror);
+            });
+            XCTAssertTrue(updateOk, "Should be able to update item");
+
+            return;
+        });
+    });
+
+    XCTAssertTrue(ok, "query should have been successful");
+    XCTAssertNil((__bridge id)cferror, "Should be no error performing query");
+    CFReleaseNull(cferror);
+
+    XCTAssertEqual(count, 1, "Should have processed one item");
+}
+
 -(XCTestExpectation*)expectChangeForView:(NSString*)view {
     NSString* notification = [NSString stringWithFormat: @"com.apple.security.view-change.%@", view];
     return [self expectationForNotification:notification object:nil handler:^BOOL(NSNotification * _Nonnull nsnotification) {
-        secnotice("ckks", "Got a notification for %@: %@", notification, nsnotification);
+        ckksnotice_global("ckks", "Got a notification for %@: %@", notification, nsnotification);
         return YES;
     }];
 }
@@ -1210,14 +1329,6 @@ static CFDictionaryRef SOSCreatePeerGestaltFromName(CFStringRef name)
     }
 }
 
-- (OTAccountMetadataClassC*)loadOrCreateAccountMetadata:(NSError**)error
-{
-    if(error) {
-        *error = [NSError errorWithDomain:@"securityd" code:errSecInteractionNotAllowed userInfo:nil];
-    }
-    return nil;
-}
-
 @end
 
 #endif // OCTAGON
index 0cb5406bdba9171e995d676917ee56485f9d9692..f8694906da42d5e6e1036f48bc03c33c4db3ee91 100644 (file)
 #define CloudKitKeychainSyncingTestsBase_h
 
 #import <CloudKit/CloudKit.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
 #import <OCMock/OCMock.h>
+#pragma clang diagnostic pop
+
 #import <XCTest/XCTest.h>
 
 #include <Security/SecItemPriv.h>
index 4df9a3cba9ccd3b977d926da11d453c6112fd0fc..40b9ea6fdbf027db6ba4da8cbaa83e9c85865096 100644 (file)
@@ -36,6 +36,7 @@
 #import "keychain/ckks/tests/MockCloudKit.h"
 
 #import "keychain/ot/OTManager.h"
+#import "keychain/trust/TrustedPeers/TPSyncingPolicy.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -48,6 +49,9 @@ NS_ASSUME_NONNULL_BEGIN
 @class CKKSReachabilityTracker;
 @class SOSCKKSPeerAdapter;
 
+@interface CKKSTestFailureLogger : NSObject <XCTestObservation>
+@end
+
 @interface CloudKitMockXCTest : XCTestCase
 
 @property CKRecordZoneID* testZoneID;
@@ -106,7 +110,9 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nullable) CKKSMockOctagonAdapter *mockOctagonAdapter;
 
 - (NSSet<NSString*>*)managedViewList;
-- (TPPolicy*)viewSortingPolicyForManagedViewList;
+- (TPSyncingPolicy*)viewSortingPolicyForManagedViewList;
+- (TPSyncingPolicy*)viewSortingPolicyForManagedViewListWithUserControllableViews:(NSSet<NSString*>*)ucv
+                                                       syncUserControllableViews:(TPPBPeerStableInfo_UserControllableViewStatus)syncUserControllableViews;
 
 @property (nullable) id mockCKKSViewManager;
 @property (nullable) CKKSViewManager* injectedManager;
@@ -127,6 +133,9 @@ NS_ASSUME_NONNULL_BEGIN
 // Fill this in to fail the next modifyzones operation
 @property (nullable) NSError* nextModifyRecordZonesError;
 
+// Used to track the test failure logger (for test teardown purposes)
+@property (class) CKKSTestFailureLogger* testFailureLogger;
+
 - (CKKSKey*)fakeTLK:(CKRecordZoneID*)zoneID;
 
 - (void)expectCKModifyItemRecords:(NSUInteger)expectedNumberOfRecords
index f8e42b58f730724f91c1ad068ce4b7577f2efe6c..02e3b87e972e722d70664291da7c85121b44a31d 100644 (file)
 #import <CloudKit/CloudKit.h>
 #import <CloudKit/CloudKit_Private.h>
 #import <CloudKit/CKContainer_Private.h>
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
 #import <OCMock/OCMock.h>
+#pragma clang diagnostic pop
+
 #import <TrustedPeers/TrustedPeers.h>
 #import <TrustedPeers/TPPBPolicyKeyViewMapping.h>
 #import <TrustedPeers/TPDictionaryMatchingRules.h>
 - (void)_checkSelfCloudServicesEntitlement;
 @end
 
+@implementation CKKSTestFailureLogger
+- (instancetype)init {
+    if((self = [super init])) {
+    }
+    return self;
+}
+
+- (void)testCase:(XCTestCase *)testCase didRecordIssue:(XCTIssue *)issue {
+    ckksnotice_global("ckkstests", "XCTest failure: (%@)%@:%lu error: %@ -- %@\n%@",
+                      testCase.name,
+                      issue.sourceCodeContext.location.fileURL,
+                      (long)issue.sourceCodeContext.location.lineNumber,
+                      issue.compactDescription,
+                      issue.detailedDescription,
+                      issue.sourceCodeContext.callStack);
+}
+@end
 
 @implementation CloudKitMockXCTest
 @synthesize aksLockState = _aksLockState;
 
+static CKKSTestFailureLogger* _testFailureLoggerVariable;
+
 + (void)setUp {
     // Turn on testing
     SecCKKSEnable();
     SecCKKSTestsEnable();
     SecCKKSSetReduceRateLimiting(true);
+
+    self.testFailureLogger = [[CKKSTestFailureLogger alloc] init];
+
+    [[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:self.testFailureLogger];
+
     [super setUp];
 
 #if NO_SERVER
 #endif
 }
 
++ (void)tearDown {
+    [super tearDown];
+    [[XCTestObservationCenter sharedTestObservationCenter] removeTestObserver:self.testFailureLogger];
+}
+
++ (CKKSTestFailureLogger*)testFailureLogger {
+    return _testFailureLoggerVariable;
+}
+
++ (void)setTestFailureLogger:(CKKSTestFailureLogger*)logger {
+    _testFailureLoggerVariable = logger;
+}
+
 - (BOOL)isRateLimited:(SecTapToRadar *)ttrRequest
 {
     return self.isTTRRatelimited;
     self.apsEnvironment = @"fake APS push string";
 
     // Static variables are a scourge. Let's reset this one...
-    [OctagonAPSReceiver resetGlobalEnviornmentMap];
+    [OctagonAPSReceiver resetGlobalDelegatePortMap];
 
     self.mockDatabaseExceptionCatcher = OCMStrictClassMock([CKDatabase class]);
     self.mockDatabase = OCMStrictClassMock([CKDatabase class]);
     // Inject a fake operation dependency so we won't respond with the CloudKit account status immediately
     // The CKKSAccountStateTracker won't send any login/logout calls without that information, so this blocks all CKKS setup
     self.ckaccountHoldOperation = [NSBlockOperation named:@"ckaccount-hold" withBlock:^{
-        secnotice("ckks", "CKKS CK account status test hold released");
+        ckksnotice_global("ckks", "CKKS CK account status test hold released");
     }];
 
     OCMStub([self.mockContainer accountStatusWithCompletionHandler:
     OCMStub([self.mockCKKSViewManager syncBackupAndNotifyAboutSync]);
     OCMStub([self.mockCKKSViewManager waitForTrustReady]).andReturn(YES);
 
-    if(!self.disableConfigureCKKSViewManagerWithViews) {
-        // Normally, the Octagon state machine calls this. But, since we won't be running that, help it out.
-        [self.injectedManager setSyncingViews:[self managedViewList]
-                                sortingPolicy:[self viewSortingPolicyForManagedViewList]];
-    }
-
     // Lie and say network is available
     [self.reachabilityTracker setNetworkReachability:true];
 
 
     // Actually load the database.
     kc_with_dbt(true, NULL, ^bool (SecDbConnectionRef dbt) { return false; });
+
+    if(!self.disableConfigureCKKSViewManagerWithViews) {
+        // Normally, the Octagon state machine calls this. But, since we won't be running that, help it out.
+        // CKKS might try to take a DB lock, so do this after the DB load above
+        [self.injectedManager setCurrentSyncingPolicy:self.viewSortingPolicyForManagedViewList];
+    }
 }
 
 - (OTManager*)setUpOTManager:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies
 
 - (void)setAksLockState:(bool)aksLockState
 {
-
+    ckksnotice_global("ckkstests", "Setting mock AKS lock state to: %@", (aksLockState ? @"locked" : @"unlocked"));
     if(aksLockState) {
         [SecMockAKS lockClassA];
+
+        self.mockSOSAdapter.aksLocked = YES;
     } else {
         [SecMockAKS unlockAllClasses];
+
+        self.mockSOSAdapter.aksLocked = NO;
     }
     _aksLockState = aksLockState;
 }
     return (NSSet*) CFBridgingRelease(SOSViewCopyViewSet(kViewSetCKKS));
 }
 
-- (TPPolicy*)viewSortingPolicyForManagedViewList
+- (TPSyncingPolicy*)viewSortingPolicyForManagedViewList
+{
+    return [self viewSortingPolicyForManagedViewListWithUserControllableViews:[NSSet set]
+                                                    syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_ENABLED];
+}
+
+- (TPSyncingPolicy*)viewSortingPolicyForManagedViewListWithUserControllableViews:(NSSet<NSString*>*)ucv
+                                                       syncUserControllableViews:(TPPBPeerStableInfo_UserControllableViewStatus)syncUserControllableViews
 {
     NSMutableArray<TPPBPolicyKeyViewMapping*>* rules = [NSMutableArray array];
 
         [rules addObject:mapping];
     }
 
-    TPPolicy* policy = [TPPolicy policyWithModelToCategory:@[]
-                                          categoriesByView:@{}
-                                     introducersByCategory:@{}
-                                            keyViewMapping:rules
-                                         unknownRedactions:NO
-                                                   version:[[TPPolicyVersion alloc] initWithVersion:1 hash:@"fake-policy-for-views"]];
-
+    TPSyncingPolicy* policy = [[TPSyncingPolicy alloc] initWithModel:@"test-policy"
+                                                             version:[[TPPolicyVersion alloc] initWithVersion:1 hash:@"fake-policy-for-views"]
+                                                            viewList:[self managedViewList]
+                                               userControllableViews:ucv
+                                           syncUserControllableViews:syncUserControllableViews
+                                                viewsToPiggybackTLKs:[NSSet set]
+                                                      keyViewMapping:rules];
     return policy;
 }
 
 -(void)holdCloudKitModifications {
     XCTAssertFalse([self.ckModifyHoldOperation isPending], "Shouldn't already be a pending cloudkit modify hold operation");
     self.ckModifyHoldOperation = [NSBlockOperation blockOperationWithBlock:^{
-        secnotice("ckks", "Released CloudKit modification hold.");
+        ckksnotice_global("ckks", "Released CloudKit modification hold.");
     }];
 }
 -(void)releaseCloudKitModificationHold {
 -(void)holdCloudKitFetches {
     XCTAssertFalse([self.ckFetchHoldOperation isPending], "Shouldn't already be a pending cloudkit fetch hold operation");
     self.ckFetchHoldOperation = [NSBlockOperation blockOperationWithBlock:^{
-        secnotice("ckks", "Released CloudKit fetch hold.");
+        ckksnotice_global("ckks", "Released CloudKit fetch hold.");
     }];
 }
 -(void)releaseCloudKitFetchHold {
 -(void)holdCloudKitModifyRecordZones {
     XCTAssertFalse([self.ckModifyRecordZonesHoldOperation isPending], "Shouldn't already be a pending cloudkit zone create hold operation");
     self.ckModifyRecordZonesHoldOperation = [NSBlockOperation blockOperationWithBlock:^{
-        secnotice("ckks", "Released CloudKit zone create hold.");
+        ckksnotice_global("ckks", "Released CloudKit zone create hold.");
     }];
 }
 -(void)releaseCloudKitModifyRecordZonesHold {
 -(void)holdCloudKitModifySubscription {
     XCTAssertFalse([self.ckModifySubscriptionsHoldOperation isPending], "Shouldn't already be a pending cloudkit subscription hold operation");
     self.ckModifySubscriptionsHoldOperation = [NSBlockOperation blockOperationWithBlock:^{
-        secnotice("ckks", "Released CloudKit zone create hold.");
+        ckksnotice_global("ckks", "Released CloudKit zone create hold.");
     }];
 }
 -(void)releaseCloudKitModifySubscriptionHold {
                 if(expectedRecordTypeCounts) {
                     matches &= !![modifiedRecordTypeCounts isEqual: filteredExpectedRecordTypeCounts];
                     if(!matches) {
-                        secnotice("fakecloudkit", "Record number mismatch: %@ %@", modifiedRecordTypeCounts, filteredExpectedRecordTypeCounts);
+                        secnotice("fakecloudkit", "Record number mismatch: attempted:%@ expected:%@", modifiedRecordTypeCounts, filteredExpectedRecordTypeCounts);
                         result = NO;
                         return;
                     }
                 } else {
                     matches &= op.recordsToSave.count == 0u;
                     if(!matches) {
-                        secnotice("fakecloudkit", "Record number mismatch: %@ 0", modifiedRecordTypeCounts);
+                        secnotice("fakecloudkit", "Record number mismatch: attempted:%@ expected:0", modifiedRecordTypeCounts);
                         result = NO;
                         return;
                     }
                 if(expectedDeletedRecordTypeCounts) {
                     matches &= !![deletedRecordTypeCounts  isEqual: expectedDeletedRecordTypeCounts];
                     if(!matches) {
-                        secnotice("fakecloudkit", "Deleted record number mismatch: %@ %@", deletedRecordTypeCounts, expectedDeletedRecordTypeCounts);
+                        secnotice("fakecloudkit", "Deleted record number mismatch: attempted:%@ expected:%@", deletedRecordTypeCounts, expectedDeletedRecordTypeCounts);
                         result = NO;
                         return;
                     }
                 } else {
                     matches &= op.recordIDsToDelete.count == 0u;
                     if(!matches) {
-                        secnotice("fakecloudkit", "Deleted record number mismatch: %@ 0", deletedRecordTypeCounts);
+                        secnotice("fakecloudkit", "Deleted record number mismatch: attempted:%@ expected:0", deletedRecordTypeCounts);
                         result = NO;
                         return;
                     }
                     // if you'd like to read the data from this write.
                     NSBlockOperation* ckop = [NSBlockOperation named:@"cloudkit-write" withBlock: ^{
                         @synchronized(zone.currentDatabase) {
+                            if(zone.blockBeforeWriteOperation) {
+                                zone.blockBeforeWriteOperation();
+                            }
+
                             NSMutableArray* savedRecords = [[NSMutableArray alloc] init];
                             for(CKRecord* record in op.recordsToSave) {
                                 CKRecord* reflectedRecord = [record copy];
index 912260561900469fc81c3fa0ddf837012ab412d2..6267a478dc12978916ce67c6065f959b3bf269b2 100644 (file)
@@ -120,6 +120,9 @@ typedef NSMutableDictionary<CKRecordZoneID*, FakeCKZone*> FakeCKDatabase;
 // Serial queue. Use this for transactionality.
 @property dispatch_queue_t queue;
 
+// Set this to run some code after a write operation has started, but before any results are delivered
+@property (nullable) void (^blockBeforeWriteOperation)(void);
+
 - (instancetype)initZone:(CKRecordZoneID*)zoneID;
 
 // Always Succeed
index 1a15ff54961305c0d99d50b07f1d38abb632b6da..337750473d4e2ba61839c018bfa161b6dae568e6 100644 (file)
@@ -75,7 +75,7 @@
         self.completionBlock = ^{
             __strong __typeof(weakSelf) strongSelf = weakSelf;
             if(!strongSelf) {
-                secerror("ckks: received callback for released object");
+                ckkserror_global("ckks", "received callback for released object");
                 return;
             }
 
 
         if(!skipCreation) {
             // Create the zone:
-            secnotice("ckks", "Creating zone %@", zone);
+            ckksnotice_global("ckks", "Creating zone %@", zone);
             ckdb[zone.zoneID] = [[FakeCKZone alloc] initZone: zone.zoneID];
         }
 
         self.completionBlock = ^{
             __strong __typeof(weakSelf) strongSelf = weakSelf;
             if(!strongSelf) {
-                secerror("ckks: received callback for released object");
+                ckkserror_global("ckks", "received callback for released object");
                 return;
             }
 
 @synthesize recordZoneFetchCompletionBlock = _recordZoneFetchCompletionBlock;
 @synthesize fetchRecordZoneChangesCompletionBlock = _fetchRecordZoneChangesCompletionBlock;
 
+@synthesize deviceIdentifier = _deviceIdentifier;
+
 @synthesize operationID = _operationID;
 @synthesize resolvedConfiguration = _resolvedConfiguration;
 @synthesize group = _group;
         _configurationsByRecordZoneID = configurationsByRecordZoneID;
 
         _operationID = @"fake-operation-ID";
+        _deviceIdentifier = @"ckkstests";
     }
     return self;
 }
 
         self.recordZoneChangeTokensUpdatedBlock(zoneID, currentChangeToken, nil);
         self.recordZoneFetchCompletionBlock(zoneID, currentChangeToken, nil, moreComing, opError);
+    }
 
-        if(self.blockAfterFetch) {
-            self.blockAfterFetch();
-        }
-
+    if(self.blockAfterFetch) {
+        self.blockAfterFetch();
     }
 
     self.fetchRecordZoneChangesCompletionBlock(nil);
 @implementation FakeAPSConnection
 @synthesize delegate;
 
+@synthesize enabledTopics;
+@synthesize opportunisticTopics;
+@synthesize darkWakeTopics;
+
 - (id)initWithEnvironmentName:(NSString *)environmentName namedDelegatePort:(NSString*)namedDelegatePort queue:(dispatch_queue_t)queue {
     if(self = [super init]) {
     }
     return self;
 }
-
-- (void)setEnabledTopics:(NSArray<NSString *> *)enabledTopics {
-}
-
-- (void)setDarkWakeTopics:(NSArray<NSString *> *)darkWakeTopics {
-}
-
 @end
 
 // Do literally nothing
 - (NSError*)deleteCKRecordIDFromZone:(CKRecordID*) recordID {
     // todo: fail somehow
     dispatch_sync(self.queue, ^{
+        ckksnotice("fakeck", self.zoneID, "Change token before server-deleted record is : %@", self.currentChangeToken);
+
         self.pastDatabases[self.currentChangeToken] = [self.currentDatabase mutableCopy];
         [self _onqueueRollChangeToken];
 
         [self.currentDatabase removeObjectForKey: recordID];
+
+        ckksnotice("fakeck", self.zoneID, "Change token after server-deleted record is : %@", self.currentChangeToken);
     });
     return nil;
 }
     if(notification) {
         // This isn't actually fake, but XCTest likes NSNotificationCenter a whole lot.
         // These notifications shouldn't escape this process, so it's perfect.
-        secnotice("ckks", "sending fake NSNotification %@", notification);
+        ckksnotice_global("ckks", "sending fake NSNotification %@", notification);
         [[NSNotificationCenter defaultCenter] postNotificationName:notification object:nil];
     }
 }
index 12ae14e69f518d4bfb950add38fe0393c88bacac..18970fcb38b6d3723857bc2d45ea2e32164e2698 100644 (file)
@@ -33,7 +33,7 @@
 
 #if OCTAGON
 
-@interface CKKSAPSNotificationReceiver : NSObject <CKKSZoneUpdateReceiver>
+@interface CKKSAPSNotificationReceiver : NSObject <CKKSZoneUpdateReceiverProtocol>
 @property XCTestExpectation* expectation;
 @property void (^block)(CKRecordZoneNotification* notification);
 
 - (void)testRegisterAndReceive {
     __weak __typeof(self)weakSelf = self;
 
-    OctagonAPSReceiver* apsr = [[OctagonAPSReceiver alloc] initWithEnvironmentName:@"testenvironment"
-                                                           namedDelegatePort:SecCKKSAPSNamedPort
-                                                          apsConnectionClass:[FakeAPSConnection class]];
+    OctagonAPSReceiver* apsr = [[OctagonAPSReceiver alloc] initWithNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                  apsConnectionClass:[FakeAPSConnection class]];
 
     XCTAssertNotNil(apsr, "Should have received a OctagonAPSReceiver");
 
                                             XCTAssertEqual(strongSelf.testZoneID, notification.recordZoneID, "Should have received a notification for the test zone");
                                         }];
 
-    CKKSCondition* registered = [apsr registerReceiver:anr forZoneID:self.testZoneID];
+    CKKSCondition* registered = [apsr registerCKKSReceiver:anr];
     XCTAssertEqual(0, [registered wait:1*NSEC_PER_SEC], "Registration should have completed within a second");
     APSIncomingMessage* message = [OctagonAPSReceiverTests messageForZoneID:self.testZoneID];
     XCTAssertNotNil(message, "Should have received a APSIncomingMessage");
     [self waitForExpectationsWithTimeout:5.0 handler:nil];
 }
 
-- (void)testRegisterMultipleAndReceive {
-    __weak __typeof(self)weakSelf = self;
-
-    OctagonAPSReceiver* apsr = [[OctagonAPSReceiver alloc] initWithEnvironmentName:@"testenvironment"
-                                                           namedDelegatePort:SecCKKSAPSNamedPort
-                                                          apsConnectionClass:[FakeAPSConnection class]];
-
-    XCTAssertNotNil(apsr, "Should have received a OctagonAPSReceiver");
-
-    CKRecordZoneID* otherZoneID = [[CKRecordZoneID alloc] initWithZoneName:@"otherzone" ownerName:CKCurrentUserDefaultName];
-
-    CKKSAPSNotificationReceiver* anr = [[CKKSAPSNotificationReceiver alloc] initWithExpectation:[self expectationWithDescription:@"receive testZoneID notification"]
-                                                                                          block:
-                                        ^(CKRecordZoneNotification* notification) {
-                                            __strong __typeof(self) strongSelf = weakSelf;
-                                            XCTAssertNotNil(notification, "Should have received a notification");
-                                            XCTAssertEqual(strongSelf.testZoneID, notification.recordZoneID, "Should have received a notification for the test zone");
-                                        }];
-    CKKSAPSNotificationReceiver* anr2 = [[CKKSAPSNotificationReceiver alloc] initWithExpectation:[self expectationWithDescription:@"receive otherzone notification"]
-                                                                                          block:
-                                        ^(CKRecordZoneNotification* notification) {
-                                            XCTAssertNotNil(notification, "Should have received a notification");
-                                            XCTAssertEqual(otherZoneID, notification.recordZoneID, "Should have received a notification for the test zone");
-                                        }];
-
-    CKKSCondition* registered = [apsr registerReceiver:anr forZoneID:self.testZoneID];
-    CKKSCondition* registered2 = [apsr registerReceiver:anr2 forZoneID:otherZoneID];
-    XCTAssertEqual(0, [registered wait:1*NSEC_PER_SEC], "Registration should have completed within a second");
-    XCTAssertEqual(0, [registered2 wait:1*NSEC_PER_SEC], "Registration should have completed within a second");
-
-    [apsr connection:apsr.apsConnection didReceiveIncomingMessage:[OctagonAPSReceiverTests messageForZoneID:self.testZoneID]];
-    [apsr connection:apsr.apsConnection didReceiveIncomingMessage:[OctagonAPSReceiverTests messageForZoneID:otherZoneID]];
-
-    [self waitForExpectationsWithTimeout:5.0 handler:nil];
-}
-
 - (void)testReceiveNotificationIfRegisteredAfterDelivery {
-    OctagonAPSReceiver* apsr = [[OctagonAPSReceiver alloc] initWithEnvironmentName:@"testenvironment"
-                                                           namedDelegatePort:SecCKKSAPSNamedPort
-                                                          apsConnectionClass:[FakeAPSConnection class]];
+    OctagonAPSReceiver* apsr = [[OctagonAPSReceiver alloc] initWithNamedDelegatePort:SecCKKSAPSNamedPort
+                                                                  apsConnectionClass:[FakeAPSConnection class]];
     XCTAssertNotNil(apsr, "Should have received a OctagonAPSReceiver");
 
     // Receives a notification for the test zone
                                             XCTAssertNotNil(notification, "Should have received a (stored) notification");
                                         }];
 
-    CKKSCondition* registered = [apsr registerReceiver:anr forZoneID:self.testZoneID];
+    CKKSCondition* registered = [apsr registerCKKSReceiver:anr];
     XCTAssertEqual(0, [registered wait:1*NSEC_PER_SEC], "Registration should have completed within a second");
 
     [self waitForExpectationsWithTimeout:5.0 handler:nil];
index 67f906bcb88c609ebe39f6dc4b8cf7845ff9b85a..03c8056f6f396b38c666e839c0bc47a2e13a4380 100644 (file)
 
 @implementation TestObject
 - (instancetype)init {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _uuid = [[NSUUID UUID] UUIDString];
     }
     return self;
 }
 
 - (instancetype)initWithNilUuid {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _uuid = nil;
     }
     return self;
index 52065f618144cda5389b8e80e5df2b4d831cc8dd..d3b6db8cb20d116db79d4e1571d72f5ef89ce0b5 100644 (file)
@@ -59,7 +59,10 @@ for x in get_class_names():
     test_dictionary['WorkingDirectory'] = '/AppleInternal/XCTests/com.apple.security/'
 
     test_command = Foundation.NSMutableArray.array()
-    test_command.append('BATS_XCTEST_CMD -XCTest {} CKKSTests.xctest'.format(x))
+    test_command.append('BATS_XCTEST_CMD')
+    test_command.append('-XCTest')
+    test_command.append('{}'.format(x))
+    test_command.append('CKKSTests.xctest')
     test_dictionary['Command'] = test_command
 
     test_list.append(test_dictionary)
diff --git a/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner-Entitlements.plist
deleted file mode 100644 (file)
index 46c3d41..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>com.apple.application-identifier</key>
-       <string>com.apple.security.KeychainEntitledTestRunner</string>
-       <key>application-identifier</key>
-       <string>com.apple.security.KeychainEntitledTestRunner</string>
-       <key>com.apple.developer.icloud-services</key>
-       <array>
-               <string>CloudKit</string>
-       </array>
-       <key>com.apple.private.cloudkit.masquerade</key>
-       <true/>
-       <key>com.apple.private.cloudkit.customAccounts</key>
-       <true/>
-       <key>com.apple.developer.icloud-container-environment</key>
-       <string>Development</string>
-       <key>com.apple.private.aps-connection-initiate</key>
-       <true/>
-       <key>aps-connection-initiate</key>
-       <true/>
-       <key>aps-environment</key>
-       <string>serverPreferred</string>
-    <key>keychain-access-groups</key>
-       <array>
-               <string>com.apple.security.ckks</string>
-       </array>
-       <key>keychain-cloud-circle</key>
-       <true/>
-</dict>
-</plist>
diff --git a/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m b/keychain/ckks/tests/testrunner/KeychainEntitledTestRunner.m
deleted file mode 100644 (file)
index cf5cbc5..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-//
-//  KeychainEntitledTestRunner.m
-//  KeychainEntitledTestRunner
-//
-//  Stolen from Mark Pauley / CDEntitledTestRunner who stole it from Drew Terry / MobileContainerManager
-//  Copyright 2016-2017 Apple. All rights reserved.
-//
-
-#import <Foundation/Foundation.h>
-#import <unistd.h>
-#import <XCTest/XCTest.h>
-
-@interface TestRunner : NSObject <XCTestObservation> {
-    NSBundle *_bundle;
-    XCTestSuite *_testSuite;
-}
-
-- (instancetype)initWithBundlePath:(NSString *)path andTestNames:(NSArray *)names;
-- (NSUInteger)runUnitTestSuite;
-
-- (void)testLogWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
-- (void)testLogWithFormat:(NSString *)format arguments:(va_list)arguments NS_FORMAT_FUNCTION(1,0);
-
-@end
-
-@implementation TestRunner
-- (instancetype)initWithBundlePath:(NSString *)path andTestNames:(NSArray *)names
-{
-    self = [super init];
-    if (self) {
-        NSError *error = nil;
-        
-        _bundle = [NSBundle bundleWithPath:path];
-        if (!_bundle) {
-            [self testLogWithFormat:@"No bundle at location %@ (%s)\n", path, strerror(errno)];
-            return nil;
-        }
-        if (![_bundle loadAndReturnError:&error]) {
-            [self testLogWithFormat:@"Test Bundle at %@ didn't load: %@\n", path, error];
-            return nil;
-        }
-
-        if(names) {
-            XCTestSuite* testSuite = [[XCTestSuite alloc] initWithName:[[path lastPathComponent] stringByDeletingPathExtension]];
-            XCTestSuite* loadedSuite = [XCTestSuite testSuiteForBundlePath:path];
-            // Filter out only the tests that were named.
-            [loadedSuite.tests enumerateObjectsUsingBlock:^(__kindof XCTest * _Nonnull test, NSUInteger __unused idx, BOOL * __unused _Nonnull stop) {
-                [self testLogWithFormat:@"Checking test %@\n", test.name];
-                if([names containsObject:test.name]) {
-                    [testSuite addTest:test];
-                }
-            }];
-            _testSuite = testSuite;
-        }
-        else {
-            _testSuite = [XCTestSuite testSuiteForBundlePath:path];
-        }
-    }
-    return self;
-}
-
-- (NSUInteger)runUnitTestSuite
-{
-    [[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:self];
-    
-    [_testSuite runTest];
-    
-    XCTestRun *testRun = [_testSuite testRun];
-    
-    return testRun.totalFailureCount;
-}
-
-- (NSFileHandle *)logFileHandle
-{
-    return [NSFileHandle fileHandleWithStandardOutput];
-}
-
-- (void)testLogWithFormat:(NSString *)format, ...
-{
-    va_list ap;
-    va_start(ap, format);
-    [self testLogWithFormat:format arguments:ap];
-    va_end(ap);
-}
-
-- (void)testLogWithFormat:(NSString *)format arguments:(va_list)arguments
-{
-    NSString *message = [[NSString alloc] initWithFormat:format arguments:arguments];
-    [self.logFileHandle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
-}
-
-- (NSDateFormatter *)dateFormatter
-{
-    static NSDateFormatter *dateFormatter;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        dateFormatter = [NSDateFormatter new];
-        dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
-    });
-    return dateFormatter;
-}
-
-/* -testBundleWillStart:                            // exactly once per test bundle
- *      -testSuiteWillStart:                        // exactly once per test suite
- *          -testCaseWillStart:                     // exactly once per test case
- *          -testCase:didFailWithDescription:...    // zero or more times per test case, any time between test case start and finish
- *          -testCaseDidFinish:                     // exactly once per test case
- *      -testSuite:didFailWithDescription:...       // zero or more times per test suite, any time between test suite start and finish
- *      -testSuiteDidFinish:                        // exactly once per test suite
- * -testBundleDidFinish:                            // exactly once per test bundle
- */
-
-- (void)testSuiteWillStart:(XCTestSuite *)testSuite
-{
-    [self testLogWithFormat:@"Test Suite '%@' started at %@\n", testSuite.name, [self.dateFormatter stringFromDate:testSuite.testRun.startDate]];
-}
-
-- (void)testSuite:(XCTestSuite *)testSuite didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber
-{
-    [self testLogWithFormat:@"%@:%lu: error: %@ : %@\n", ((nil != filePath) ? filePath : @"<unknown>"), ((unsigned long)((nil != filePath) ? lineNumber : 0)), testSuite.name, description];
-}
-
-- (void)testSuiteDidFinish:(XCTestSuite *)testSuite
-{
-    XCTestRun *testRun = testSuite.testRun;
-    [self testLogWithFormat:@"Test Suite '%@' %s at %@.\n\t Executed %lu test%s, with %lu failure%s (%lu unexpected) in %.3f (%.3f) seconds\n",
-     testSuite.name,
-     (testRun.hasSucceeded ? "passed" : "failed"),
-     [self.dateFormatter stringFromDate:testRun.stopDate],
-     ((unsigned long)testRun.executionCount), (testRun.executionCount != 1 ? "s" : ""),
-     ((unsigned long)testRun.totalFailureCount), (testRun.totalFailureCount != 1 ? "s" : ""),
-     ((unsigned long)testRun.unexpectedExceptionCount),
-     testRun.testDuration,
-     testRun.totalDuration];
-}
-
-- (void)testCaseWillStart:(XCTestCase *)testCase
-{
-    [self testLogWithFormat:@"Test Case '%@' started.\n", testCase.name];
-}
-
-- (void)testCase:(XCTestCase *)testCase didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber
-{
-    [self testLogWithFormat:@"%@:%lu: error: %@ : %@\n", ((nil != filePath) ? filePath : @"<unknown>"), ((unsigned long)((nil != filePath) ? lineNumber : 0)), testCase.name, description];
-}
-
-- (void)testCaseDidFinish:(XCTestCase *)testCase
-{
-    [self testLogWithFormat:@"Test Case '%@' %s (%.3f seconds).\n", testCase.name, (testCase.testRun.hasSucceeded ? "passed" : "failed"), testCase.testRun.totalDuration];
-    
-}
-@end
-
-
-
-
-static char* gTestBundleDir = "/AppleInternal/XCTests/com.apple.security";
-static char* gTestBundleName = "CKKSCloudKitTests";
-
-static NSMutableArray* gTestCaseNames = nil;
-
-static const char* opt_str = "d:t:c:h";
-
-static void usage(char*const binName, bool longUsage) {
-    fprintf(stderr, "Usage: %s [-d <test_dir>] -t test_bundle_name [(-c test_case_name)*]\n", binName);
-    if (longUsage) {
-        fprintf(stderr, "-d: argument = path to directory where test bundles live\n");
-        fprintf(stderr, "-t: argument = name of test bundle to be run (without extension)\n");
-        fprintf(stderr, "-c: argument = name of test case to be run (multiple)\n");
-    }
-}
-
-static void getOptions(int argc, char *const *argv) {
-    int ch;
-    while ( (ch = getopt(argc, argv, opt_str)) != -1 ) {
-        switch(ch)
-        {
-            case 'd':
-                gTestBundleDir = optarg;
-                break;
-            case 't':
-                gTestBundleName = optarg;
-                break;
-            case 'c':
-                if(!gTestCaseNames) {
-                    gTestCaseNames = [NSMutableArray new];
-                }
-                [gTestCaseNames addObject:@(optarg)];
-                break;
-            case 'h':
-            case '?':
-            default:
-                usage(argv[0], true);
-                exit(0);
-                break;
-        }
-    }
-}
-
-int main (int argc, const char * argv[])
-{
-    @autoreleasepool {
-        getOptions(argc, (char*const*)argv);
-        NSString *testBundleDir = [NSString stringWithCString:gTestBundleDir encoding:NSUTF8StringEncoding];
-        NSString *testBundleName = [NSString stringWithCString:gTestBundleName encoding:NSUTF8StringEncoding];
-        NSString *testBundlePath = [[testBundleDir stringByAppendingPathComponent:testBundleName] stringByAppendingPathExtension:@"xctest"];
-        
-        printf("Running unit tests %s at: %s\n", gTestCaseNames?gTestCaseNames.description.UTF8String:"[All]", testBundlePath.UTF8String);
-        
-        TestRunner *unitTest = [[TestRunner alloc] initWithBundlePath:testBundlePath andTestNames:gTestCaseNames];
-        if (!unitTest) {
-            fprintf(stderr, "Failed to load unit test runner at: %s\n", testBundlePath.UTF8String);
-            return 1;
-        }
-        
-        //runUnitTestSuite returns the number of failures. 0 = success, non-zero means failure. This complies with BATS testing standards.
-        return (int)[unitTest runUnitTestSuite];
-        
-        return 0;
-    }
-}
index d27cf2176312a017c413f59ed04d9b8963cee49a..48d96d626b59122857a997698409748fec59fb75 100644 (file)
@@ -353,20 +353,17 @@ static void print_entry(id k, id v, int ind)
             NSString* accountTracker = pop(status,@"accounttracker", NSString);
             NSString* fetcher = pop(status,@"fetcher", NSString);
             NSString* zoneCreated = pop(status,@"zoneCreated", NSString);
-            NSString* zoneCreatedError = pop(status,@"zoneCreatedError", NSString);
             NSString* zoneSubscribed = pop(status,@"zoneSubscribed", NSString);
-            NSString* zoneSubscribedError = pop(status,@"zoneSubscribedError", NSString);
             NSString* zoneInitializeScheduler = pop(status,@"zoneInitializeScheduler", NSString);
             NSString* keystate = pop(status,@"keystate", NSString);
-            NSString* keyStateError = pop(status,@"keyStateError", NSString);
             NSString* statusError = pop(status,@"statusError", NSString);
+            NSString* itemSyncEnabled = pop(status,@"itemsyncing", NSString);
             NSString* currentTLK =    pop(status,@"currentTLK", NSString);
             NSString* currentClassA = pop(status,@"currentClassA", NSString);
             NSString* currentClassC = pop(status,@"currentClassC", NSString);
             NSString* currentTLKPtr =    pop(status,@"currentTLKPtr", NSString);
             NSString* currentClassAPtr = pop(status,@"currentClassAPtr", NSString);
             NSString* currentClassCPtr = pop(status,@"currentClassCPtr", NSString);
-            NSString* currentManifestGeneration = pop(status,@"currentManifestGen", NSString);
             NSArray* launchSequence = pop(status, @"launchSequence", NSArray);
 
             NSDictionary* oqe = pop(status,@"oqe", NSDictionary);
@@ -376,14 +373,11 @@ static void print_entry(id k, id v, int ind)
             NSArray* devicestates = pop(status, @"devicestates", NSArray);
             NSArray* tlkshares = pop(status, @"tlkshares", NSArray);
 
-            NSString* zoneSetupOperation                  = pop(status,@"zoneSetupOperation", NSString);
-            NSString* keyStateOperation                   = pop(status,@"keyStateOperation", NSString);
             NSString* lastIncomingQueueOperation          = pop(status,@"lastIncomingQueueOperation", NSString);
             NSString* lastNewTLKOperation                 = pop(status,@"lastNewTLKOperation", NSString);
             NSString* lastOutgoingQueueOperation          = pop(status,@"lastOutgoingQueueOperation", NSString);
             NSString* lastProcessReceivedKeysOperation    = pop(status,@"lastProcessReceivedKeysOperation", NSString);
             NSString* lastReencryptOutgoingItemsOperation = pop(status,@"lastReencryptOutgoingItemsOperation", NSString);
-            NSString* lastScanLocalItemsOperation         = pop(status,@"lastScanLocalItemsOperation", NSString);
 
             printf("================================================================================\n\n");
 
@@ -398,18 +392,12 @@ static void print_entry(id k, id v, int ind)
 
             if(!([zoneCreated isEqualToString:@"yes"] && [zoneSubscribed isEqualToString:@"yes"])) {
                 printf("CK Zone Created:            %s\n", [[zoneCreated description] UTF8String]);
-                printf("CK Zone Created error:      %s\n", [[zoneCreatedError description] UTF8String]);
-
                 printf("CK Zone Subscribed:         %s\n", [[zoneSubscribed description] UTF8String]);
-                printf("CK Zone Subscription error: %s\n", [[zoneSubscribedError description] UTF8String]);
                 printf("CK Zone initialize retry:   %s\n", [[zoneInitializeScheduler description] UTF8String]);
                 printf("\n");
             }
 
             printf("Key state:            %s\n", [keystate UTF8String]);
-            if(keyStateError != nil) {
-                printf("Key State Error: %s\n", [keyStateError UTF8String]);
-            }
             printf("Current TLK:          %s\n", currentTLK != nil
                    ? [currentTLK    UTF8String]
                    : [[NSString stringWithFormat:@"missing; pointer is %@", currentTLKPtr] UTF8String]);
@@ -422,23 +410,20 @@ static void print_entry(id k, id v, int ind)
 
             printf("TLK shares:           %s\n", [[tlkshares description] UTF8String]);
 
+            printf("Item syncing:          %s\n", [[itemSyncEnabled description] UTF8String]);
             printf("Outgoing Queue counts: %s\n", [[oqe description] UTF8String]);
             printf("Incoming Queue counts: %s\n", [[iqe description] UTF8String]);
             printf("Key counts: %s\n", [[keys description] UTF8String]);
-            printf("latest manifest generation: %s\n", currentManifestGeneration == nil ? "null" : currentManifestGeneration.UTF8String);
 
             printf("Item counts (by key):  %s\n", [[ckmirror description] UTF8String]);
             printf("Peer states:           %s\n", [[devicestates description] UTF8String]);
 
             printf("zone change fetcher:                 %s\n", [[fetcher description] UTF8String]);
-            printf("zoneSetupOperation:                  %s\n", zoneSetupOperation                  == nil ? "never" : [zoneSetupOperation                  UTF8String]);
-            printf("keyStateOperation:                   %s\n", keyStateOperation                   == nil ? "never" : [keyStateOperation                   UTF8String]);
             printf("lastIncomingQueueOperation:          %s\n", lastIncomingQueueOperation          == nil ? "never" : [lastIncomingQueueOperation          UTF8String]);
             printf("lastNewTLKOperation:                 %s\n", lastNewTLKOperation                 == nil ? "never" : [lastNewTLKOperation                 UTF8String]);
             printf("lastOutgoingQueueOperation:          %s\n", lastOutgoingQueueOperation          == nil ? "never" : [lastOutgoingQueueOperation          UTF8String]);
             printf("lastProcessReceivedKeysOperation:    %s\n", lastProcessReceivedKeysOperation    == nil ? "never" : [lastProcessReceivedKeysOperation    UTF8String]);
             printf("lastReencryptOutgoingItemsOperation: %s\n", lastReencryptOutgoingItemsOperation == nil ? "never" : [lastReencryptOutgoingItemsOperation UTF8String]);
-            printf("lastScanLocalItemsOperation:         %s\n", lastScanLocalItemsOperation         == nil ? "never" : [lastScanLocalItemsOperation         UTF8String]);
 
             printf("Launch sequence:\n");
             for (NSString *event in launchSequence) {
@@ -476,7 +461,8 @@ static void print_entry(id k, id v, int ind)
         dispatch_semaphore_signal(sema);
     }];
 
-    if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 65)) != 0) {
+    // The maximum device-side delay to start a fetch is 120s, so we must wait longer than that for a response.
+    if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 135)) != 0) {
         printf("\n\nError: timed out waiting for response\n");
         return -1;
     }
index 517279eed6238dc9c68de88d8ec9b7bd87ec07be..57d6edac9f83d2d8d410059fcfdc0a77fd55872b 100644 (file)
@@ -57,6 +57,7 @@ OctagonState* const EscrowRequestStateWaitForUnlock = (OctagonState*)@"wait_for_
                                                                                                          flags:(nonnull OctagonFlags *)flags
                                                                                                   pendingFlags:(nonnull id<OctagonStateOnqueuePendingFlagHandler>)pendingFlagHandler
 {
+    dispatch_assert_queue(self.queue);
     if([flags _onqueueContains:OctagonFlagEscrowRequestInformCloudServicesOperation]) {
         [flags _onqueueRemoveFlag:OctagonFlagEscrowRequestInformCloudServicesOperation];
         return [[EscrowRequestInformCloudServicesOperation alloc] initWithIntendedState:EscrowRequestStateNothingToDo
index 2bdaa7ae5a1cefb254ba35eea17131bde0908cda..a35ad32f728e02c511ba45b27aa587fdd64fe528 100644 (file)
@@ -1,51 +1,27 @@
 
 #import <Foundation/Foundation.h>
 #import <objc/runtime.h>
+#import <Security/SecXPCHelper.h>
 
 #import "keychain/escrowrequest/EscrowRequestXPCProtocol.h"
 #import "utilities/debugging.h"
 
 NSXPCInterface* SecEscrowRequestSetupControlProtocol(NSXPCInterface* interface) {
-    static NSMutableSet *errClasses;
-
-    static dispatch_once_t onceToken;
-
-    dispatch_once(&onceToken, ^{
-        errClasses = [NSMutableSet set];
-        char *classes[] = {
-            "NSArray",
-            "NSData",
-            "NSDate",
-            "NSDictionary",
-            "NSError",
-            "NSNull",
-            "NSNumber",
-            "NSOrderedSet",
-            "NSSet",
-            "NSString",
-            "NSURL",
-        };
-
-        for (unsigned n = 0; n < sizeof(classes)/sizeof(classes[0]); n++) {
-            Class cls = objc_getClass(classes[n]);
-            if (cls) {
-                [errClasses addObject:cls];
-            }
-        }
-    });
+    NSSet<Class>* errClasses = [SecXPCHelper safeErrorClasses];
 
     @try {
         [interface setClasses:errClasses forSelector:@selector(triggerEscrowUpdate:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(cachePrerecord:serializedPrerecord:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(fetchPrerecord:reply:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errClasses forSelector:@selector(fetchRequestWaitingOnPasscode:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(fetchRequestStatuses:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(resetAllRequests:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errClasses forSelector:@selector(storePrerecordsInEscrow:) argumentIndex:1 ofReply:YES];
         
     }
     @catch(NSException* e) {
         secerror("SecEscrowRequestSetupControlProtocol failed, continuing, but you might crash later: %@", e);
-#if DEBUG
         @throw e;
-#endif
     }
 
     return interface;
index 5b66b242797cc11d28886cc66efea90232fd7ac1..5d54f5812dc4916fb3a6207fe1a3115a0b3e2782 100644 (file)
@@ -94,7 +94,7 @@ typedef CF_OPTIONS(CFOptionFlags, SecAccessControlCreateFlags) {
     kSecAccessControlBiometryCurrentSet     API_AVAILABLE(macos(10.13.4), ios(11.3)) = 1u << 3,
     kSecAccessControlTouchIDCurrentSet      API_DEPRECATED_WITH_REPLACEMENT("kSecAccessControlBiometryCurrentSet", macos(10.12.1, 10.13.4), ios(9.0, 11.3)) = 1u << 3,
     kSecAccessControlDevicePasscode         API_AVAILABLE(macos(10.11), ios(9.0)) = 1u << 4,
-    kSecAccessControlWatch                  API_AVAILABLE(macos(10.15), ios(NA), iosmac(13.0)) = 1u << 5,
+    kSecAccessControlWatch                  API_AVAILABLE(macos(10.15), ios(NA), macCatalyst(13.0)) = 1u << 5,
     kSecAccessControlOr                     API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 14,
     kSecAccessControlAnd                    API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 15,
     kSecAccessControlPrivateKeyUsage        API_AVAILABLE(macos(10.12.1), ios(9.0)) = 1u << 30,
index 99a62abb4ea0b4bc443e98aca72aa85418d7d4e1..2a54502eb8bdbd5216fc208dfaaf56edb080bf3a 100644 (file)
@@ -51,91 +51,6 @@ SecIdentityRef SecIdentityCreate(
     //__OSX_AVAILABLE_STARTING(__MAC_10_3, __SEC_IPHONE_UNKNOWN);
 
 #if SEC_OS_OSX
-/*!
-    @function SecIdentityCompare
-    @abstract Compares two SecIdentityRef instances for equality.
-    @param identity1 An identity reference.
-    @param identity2 An identity reference.
-    @param compareOptions A value containing option flags. Currently there are no compare options, so 0 should be passed for this parameter.
-    @result An enumerated value of type CFComparisonResult. See CFBase.h.
-    @discussion Two identities are considered equal if they contain identical certificate and private key components.
-    @deprecated in Mac OS X 10.5 and later; the CFEqual function should be used instead (CFBase.h).
- */
-CFComparisonResult SecIdentityCompare(
-    SecIdentityRef identity1,
-    SecIdentityRef identity2,
-    CFOptionFlags compareOptions)
-     DEPRECATED_IN_MAC_OS_X_VERSION_10_5_AND_LATER;
-
-/*!
-    @function SecIdentityFindPreferenceItem
-    @abstract Returns an identity preference item, given an identity string.
-    @param keychainOrArray A reference to an array of keychains to search, a single keychain, or NULL to search the user's default keychain search list.
-    @param idString A string containing a URI, hostname, or email (RFC822) address.
-    @param itemRef On return, a reference to the keychain item which was found. The caller is responsible for releasing this reference.
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-    @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string.
-    @deprecated in Mac OS X 10.7 and later; use SecIdentityCopyPreferred() instead (SecIdentity.h)
-
-     WARNING: This function is based on an implementation detail and will go away
-     in a future release; its use should be avoided at all costs. It does not
-     provide a way to find a preference item based on key usage, and it can only
-     find preferences which are stored as keychain items, so it may fail to find
-     the item you expect. Please use the public API functions to manipulate
-     identity preferences.
-*/
-OSStatus SecIdentityFindPreferenceItem(
-     CFTypeRef keychainOrArray,
-     CFStringRef idString,
-     SecKeychainItemRef *itemRef)
-     API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreferred", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
-
-/*!
-    @function SecIdentityAddPreferenceItem
-    @abstract Adds a new identity preference item to the specified keychain.
-    @param keychainRef A reference to the keychain in which to store the preference item. Pass NULL to specify the user's default keychain.
-    @param identityRef An identity reference.
-    @param idString A string containing a URI, hostname, or email (RFC822) address.
-    @param itemRef On return, a reference to the new keychain item. The caller is responsible for releasing this reference. Pass NULL if the reference is not needed.
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-    @discussion An identity preference item maps a particular identity to a string, such as a URI or email address. It specifies that this identity should be preferred in transactions which match the provided string.
-    @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h).
-*/
-OSStatus SecIdentityAddPreferenceItem(
-     SecKeychainRef keychainRef,
-     SecIdentityRef identityRef,
-     CFStringRef idString,
-     SecKeychainItemRef *itemRef)
-     API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
-
-/*!
-    @function SecIdentityUpdatePreferenceItem
-    @abstract Given an existing identity preference keychain item, update it with the provided identity.
-    @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem.
-    @param identityRef An identity reference.
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-    @discussion This function is used to update an existing preference item when a different identity is preferred.
-    @deprecated in Mac OS X 10.5; use SecIdentitySetPreference() instead (SecIdentity.h).
-*/
-OSStatus SecIdentityUpdatePreferenceItem(
-     SecKeychainItemRef itemRef,
-     SecIdentityRef identityRef)
-     API_DEPRECATED_WITH_REPLACEMENT("SecIdentitySetPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
-
-/*!
-    @function SecIdentityCopyFromPreferenceItem
-    @abstract Given an existing identity preference keychain item, obtain a SecIdentityRef for the identity it specifies.
-    @param itemRef An identity preference keychain item, as returned by SecIdentityFindPreferenceItem or SecIdentityAddPreferenceItem.
-    @param identityRef On return, an identity reference. The caller is responsible for releasing this reference.
-    @result A result code.  See "Security Error Codes" (SecBase.h).
-    @discussion This function is used to obtain a SecIdentityRef from an existing preference item.
-    @deprecated in Mac OS X 10.5; use SecIdentityCopyPreference() instead (SecIdentity.h).
-*/
-OSStatus SecIdentityCopyFromPreferenceItem(
-     SecKeychainItemRef itemRef,
-     SecIdentityRef *identityRef)
-     API_DEPRECATED_WITH_REPLACEMENT("SecIdentityCopyPreference", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
-
 /*!
     @function ConvertArrayToKeyUsage
     @abstract Given an array of key usages defined in SecItem.h return the equivalent CSSM_KEYUSE
index c6c91c6aa9cf7c79e4462a5c0e47f6aefcb437f8..ba56a79298f05b8470d74038efbe32b18fee8e70 100644 (file)
@@ -149,7 +149,7 @@ typedef CF_OPTIONS(uint32_t, SecKeyImportExportFlags)
 /*
  * Parameters specific to SecKeyRefs.
  */
-typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac)
+typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst)
 {
      /* for import and export */
      uint32_t                    version;        /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */
@@ -166,10 +166,10 @@ typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac)
      CSSM_KEYUSE                    keyUsage;    /* CSSM_KEYUSE_DECRYPT, CSSM_KEYUSE_SIGN,
                                                   *    etc. */
      CSSM_KEYATTR_FLAGS          keyAttributes;  /* CSSM_KEYATTR_PERMANENT, etc. */
-} SecKeyImportExportParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+} SecKeyImportExportParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 
-typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac)
+typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst)
 {
      /* for import and export */
      uint32_t                    version;        /* SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION */
@@ -194,7 +194,7 @@ typedef struct API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac)
                                                   *    - kSecAttrIsSensitive for private keys
                                                   *    - kSecAttrIsExtractable by default
                                                   */
-} SecItemImportExportKeyParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+} SecItemImportExportKeyParameters API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * SecKeychainItemExport()
@@ -254,7 +254,7 @@ OSStatus SecKeychainItemExport(
      SecItemImportExportFlags               flags,                  /* kSecItemPemArmour, etc. */
      const SecKeyImportExportParameters * __nullable keyParams,     /* optional */
      CFDataRef * __nonnull CF_RETURNS_RETAINED exportedData)        /* external representation returned here */
-          API_DEPRECATED_WITH_REPLACEMENT("SecItemExport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+          API_DEPRECATED_WITH_REPLACEMENT("SecItemExport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * SecItemExport()
@@ -472,7 +472,7 @@ OSStatus SecKeychainItemImport(
      const SecKeyImportExportParameters * __nullable keyParams,         /* optional */
      SecKeychainRef __nullable               importKeychain,            /* optional */
      CFArrayRef * __nullable CF_RETURNS_RETAINED outItems)              /* optional */
-          API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+          API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*
  * SecItemImport()
index 6d43101f8fbbe8e7c64d1e77c793530e34ac577c..c70c3958ba21650355727005ef8c985607c66db1 100644 (file)
@@ -10,7 +10,7 @@ CF_IMPLICIT_BRIDGING_ENABLED
 
 #if TARGET_OS_OSX
 OSStatus SecPKCS12Import_ios(CFDataRef pkcs12_data, CFDictionaryRef options, CFArrayRef * __nonnull CF_RETURNS_RETAINED items)
-     SPI_AVAILABLE(macos(10.15), iosmac(13.0)) API_UNAVAILABLE(ios, watchos, tvos);
+     SPI_AVAILABLE(macos(10.15), macCatalyst(13.0)) API_UNAVAILABLE(ios, watchos, tvos);
 #endif
 
 CF_IMPLICIT_BRIDGING_DISABLED
index baef2e98404e80d6626311060a6ccfe245bbcf7c..03a0d784c5e97a9698b76934ad168fc91263de9c 100644 (file)
@@ -1026,12 +1026,12 @@ extern const CFStringRef kSecValuePersistentRef
 */
 extern const CFStringRef kSecUseItemList
     API_AVAILABLE(macos(10.6))
-    API_DEPRECATED("Not implemented on this platform", ios(2.0, 12.0), tvos(9.0, 12.0), watchos(1.0, 5.0))
-    API_UNAVAILABLE(bridgeos, iosmac);
+    API_DEPRECATED("Not implemented on this platform", ios(2.0, 12.0), tvos(9.0, 12.0), watchos(1.0, 5.0), macCatalyst(13.0, 13.0))
+    API_UNAVAILABLE(bridgeos);
 extern const CFStringRef kSecUseKeychain
     API_AVAILABLE(macos(10.7), ios(NA), bridgeos(NA));
 extern const CFStringRef kSecUseOperationPrompt
-    API_AVAILABLE(macos(10.10), ios(8.0));
+    API_DEPRECATED("Use kSecUseAuthenticationContext and set LAContext.localizedReason property", macos(10.10, 10.16), ios(8.0, 14.0));
 extern const CFStringRef kSecUseNoAuthenticationUI
     API_DEPRECATED("Use kSecUseAuthenticationUI instead.", macos(10.10, 10.11), ios(8.0, 9.0));
 extern const CFStringRef kSecUseAuthenticationUI
@@ -1057,9 +1057,9 @@ extern const CFStringRef kSecUseDataProtectionKeychain
         only with SecItemCopyMatching.
 */
 extern const CFStringRef kSecUseAuthenticationUIAllow
-    API_AVAILABLE(macos(10.11), ios(9.0));
+    API_DEPRECATED("Instead of kSecUseAuthenticationUI, use kSecUseAuthenticationContext and set LAContext.interactionNotAllowed property", macos(10.11, 10.16), ios(9.0, 14.0));
 extern const CFStringRef kSecUseAuthenticationUIFail
-    API_AVAILABLE(macos(10.11), ios(9.0));
+    API_DEPRECATED("Instead of kSecUseAuthenticationUI, use kSecUseAuthenticationContext and set LAContext.interactionNotAllowed property", macos(10.11, 10.16), ios(9.0, 14.0));
 extern const CFStringRef kSecUseAuthenticationUISkip
     API_AVAILABLE(macos(10.11), ios(9.0));
 
index c458816df288e651cbbed4cd7c1697ab103b41de..9720d12e479689e505e116e48e1156c678c83a6d 100644 (file)
@@ -305,6 +305,19 @@ extern const CFStringRef kSecAttrPCSPlaintextPublicKey
 extern const CFStringRef kSecAttrPCSPlaintextPublicIdentity
     __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
 
+extern const CFStringRef kSecDataInetExtraNotes
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+extern const CFStringRef kSecDataInetExtraHistory
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+extern const CFStringRef kSecDataInetExtraClientDefined0
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+extern const CFStringRef kSecDataInetExtraClientDefined1
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+extern const CFStringRef kSecDataInetExtraClientDefined2
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+extern const CFStringRef kSecDataInetExtraClientDefined3
+__OSX_AVAILABLE(10.16) __IOS_AVAILABLE(14.0) __TVOS_AVAILABLE(14.0) __WATCHOS_AVAILABLE(7.0);
+
 // ObjectID of item stored on the token.  Token-type specific BLOB.
 // For kSecAttrTokenIDSecureEnclave and kSecAttrTokenIDAppleKeyStore, ObjectID is libaks's blob representation of encoded key.
 extern const CFStringRef kSecAttrTokenOID
@@ -433,7 +446,7 @@ extern const CFStringRef kSecUseCallerName
 extern const CFStringRef kSecUseTokenRawItems
     __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
 extern const CFStringRef kSecUseCertificatesWithMatchIssuers
-    __OSX_AVAILABLE(10.14) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
+    __OSX_AVAILABLE(10.14) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
 
 extern const CFStringRef kSOSInternalAccessGroup
     __OSX_AVAILABLE(10.9) __IOS_AVAILABLE(7.0) __TVOS_AVAILABLE(9.3) __WATCHOS_AVAILABLE(2.3);
@@ -455,24 +468,6 @@ extern const CFStringRef kSecAttrTokenIDAppleKeyStore
 
 extern const CFStringRef kSecNetworkExtensionAccessGroupSuffix;
 
-/*!
-    @function SecItemCopyDisplayNames
-    @abstract Returns an array containing unique display names for each of the
-        certificates, keys, identities, or passwords in the provided items
-        array.
-    @param items An array containing items of type SecKeychainItemRef,
-        SecKeyRef, SecCertificateRef, or SecIdentityRef. All items in the
-        array should be of the same type.
-    @param displayNames On return, an array of CFString references containing
-        unique names for the supplied items. You are responsible for releasing
-        this array reference by calling the CFRelease function.
-    @result A result code. See "Security Error Codes" (SecBase.h).
-    @discussion Use this function to obtain item names which are suitable for
-        display in a menu or list view. The returned names are guaranteed to
-        be unique across the set of provided items.
-*/
-OSStatus SecItemCopyDisplayNames(CFArrayRef items, CFArrayRef *displayNames);
-
 /*!
     @function SecItemDeleteAll
     @abstract Removes all items from the keychain.
@@ -526,6 +521,7 @@ void SecItemFetchCurrentItemAcrossAllDevices(CFStringRef accessGroup,
     @function SecItemVerifyBackupIntegrity
     @abstract Verifies the presence and integrity of all key material required
         to restore a backup of the keychain.
+    @discussion This function performs a synchronous call to securityd, be prepared to wait for it to scan the keychain.
     @param lightweight Only verify the item keys wrapped by backup keys instead
         of the default rigorous pass. This mode can be run in any
         security class.
@@ -601,8 +597,7 @@ bool _SecSystemKeychainTransfer(CFErrorRef *error);
 bool _SecSyncDeleteUserViews(uid_t uid, CFErrorRef *error);
 
 
-
-OSStatus SecItemUpdateTokenItems(CFTypeRef tokenID, CFArrayRef tokenItemsAttributes);
+OSStatus SecItemUpdateTokenItemsForAccessGroups(CFTypeRef tokenID, CFArrayRef accessGroups, CFArrayRef tokenItemsAttributes);
 
 #if SEC_OS_OSX
 CFTypeRef SecItemCreateFromAttributeDictionary_osx(CFDictionaryRef refAttributes);
@@ -695,6 +690,17 @@ __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_NA);
 extern const CFStringRef kSecAttrTokenIDSecureElement
 SPI_AVAILABLE(ios(10.13));
 
+/*!
+ @function SecItemDeleteKeychainItemsForAppClip
+ @abstract Remove all keychain items of specified App Clip's application identifier
+ @discussion At uninstallation time an App Clip should not leave behind any data. This function deletes any keychain items it might have had.
+ @param applicationIdentifier Name of the App Clip application identifier which is getting uninstalled.
+ @result Returns errSecSuccess if zero or more items were successfully deleted, otherwise errSecInternal
+ */
+OSStatus
+SecItemDeleteKeychainItemsForAppClip(CFStringRef applicationIdentifier)
+SPI_AVAILABLE(ios(10.14));
+
 __END_DECLS
 
 #endif /* !_SECURITY_SECITEMPRIV_H_ */
index 9b0a67b070e03d334b881b04e21edbf27718c7a0..a905732c2e3a6c2ac7e2a682bbf16ea16135bd63 100644 (file)
@@ -915,19 +915,19 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV
     RSA signature with PKCS#1 padding, input data must be SHA-512 generated digest.
 
     @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1
-    RSA signature with PKCS#1 padding, SHA-1 digest is generated from input data of any size.
+    RSA signature with PKCS#1 padding, SHA-1 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224
-    RSA signature with PKCS#1 padding, SHA-224 digest is generated from input data of any size.
+    RSA signature with PKCS#1 padding, SHA-224 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256
-    RSA signature with PKCS#1 padding, SHA-256 digest is generated from input data of any size.
+    RSA signature with PKCS#1 padding, SHA-256 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384
-    RSA signature with PKCS#1 padding, SHA-384 digest is generated from input data of any size.
+    RSA signature with PKCS#1 padding, SHA-384 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512
-    RSA signature with PKCS#1 padding, SHA-512 digest is generated from input data of any size.
+    RSA signature with PKCS#1 padding, SHA-512 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSASignatureDigestPSSSHA1
     RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, input data must be SHA-1 generated digest.
@@ -950,60 +950,60 @@ __OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AV
     PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size).
 
     @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA1
-    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-1 digest is generated from input data of any size.
+    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-1 digest is generated by called function automatically from input data of any size.
     PSS padding is calculated using MGF1 with SHA1 and saltLength parameter is set to 20 (SHA-1 output size).
 
     @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA224
-    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-224 digest is generated from input data of any size.
+    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-224 digest is generated by called function automatically from input data of any size.
     PSS padding is calculated using MGF1 with SHA224 and saltLength parameter is set to 28 (SHA-224 output size).
 
     @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA256
-    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-256 digest is generated from input data of any size.
+    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-256 digest is generated by called function automatically from input data of any size.
     PSS padding is calculated using MGF1 with SHA256 and saltLength parameter is set to 32 (SHA-256 output size).
 
     @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA384
-    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-384 digest is generated from input data of any size.
+    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-384 digest is generated by called function automatically from input data of any size.
     PSS padding is calculated using MGF1 with SHA384 and saltLength parameter is set to 48 (SHA-384 output size).
 
     @constant kSecKeyAlgorithmRSASignatureMessagePSSSHA512
-    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-512 digest is generated from input data of any size.
+    RSA signature with RSASSA-PSS padding according to PKCS#1 v2.1, SHA-512 digest is generated by called function automatically from input data of any size.
     PSS padding is calculated using MGF1 with SHA512 and saltLength parameter is set to 64 (SHA-512 output size).
 
     @constant kSecKeyAlgorithmECDSASignatureRFC4754
-    ECDSA algorithm, signature is concatenated r and s, big endian, data is message digest.
+    ECDSA algorithm, signature is concatenated r and s, big endian, input data must be message digest generated by some hash function.
 
     @constant kSecKeyAlgorithmECDSASignatureDigestX962
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest.
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest generated by some hash functions.
 
     @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA1 algorithm.
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest created by SHA1 algorithm.
 
-    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA224 algorithm.
+    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA224
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest created by SHA224 algorithm.
 
-    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA256 algorithm.
+    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA256
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest created by SHA256 algorithm.
 
-    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA384 algorithm.
+    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA384
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest created by SHA384 algorithm.
 
-    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, input data is message digest created by SHA512 algorithm.
+    @constant kSecKeyAlgorithmECDSASignatureDigestX962SHA512
+    ECDSA algorithm, signature is in DER x9.62 encoding, input data must be message digest created by SHA512 algorithm.
 
     @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA1
-    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-1 digest is generated from input data of any size.
+    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-1 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA224
-    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-224 digest is generated from input data of any size.
+    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-224 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA256
-    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-256 digest is generated from input data of any size.
+    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-256 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA384
-    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-384 digest is generated from input data of any size.
+    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-384 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmECDSASignatureMessageX962SHA512
-    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-512 digest is generated from input data of any size.
+    ECDSA algorithm, signature is in DER x9.62 encoding, SHA-512 digest is generated by called function automatically from input data of any size.
 
     @constant kSecKeyAlgorithmRSAEncryptionRaw
     Raw RSA encryption or decryption, size of data must match RSA key modulus size.  Note that direct
index 1f22315a6c6de50d49094c217da9c2b1f6337f8b..06eaa37c1ee823d0cfa5a1d1f5cbd2c570ce17e7 100644 (file)
@@ -357,7 +357,7 @@ SPI_AVAILABLE(macos(10.8), ios(9.0));
      For compatibility, your code should migrate to use SecKeyGetAlgorithmId instead.
 */
 CFIndex SecKeyGetAlgorithmID(SecKeyRef key)
-API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", ios(5.0, 9.0)) API_UNAVAILABLE(iosmac);
+API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", ios(5.0, 9.0)) API_UNAVAILABLE(macCatalyst);
 #endif // TARGET_OS_IPHONE
 
 #if TARGET_OS_OSX
@@ -372,7 +372,7 @@ API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", ios(5.0, 9.0)) API_UNAVA
  had different arguments and a different return value. Use SecKeyGetAlgorithmId instead.
  */
 OSStatus SecKeyGetAlgorithmID(SecKeyRef key, const CSSM_X509_ALGORITHM_IDENTIFIER **algid)
-API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", macos(10.2, 10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
+API_DEPRECATED_WITH_REPLACEMENT("SecKeyGetAlgorithmId", macos(10.2, 10.8)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
 #endif
 
 #if !SEC_OS_OSX
@@ -473,7 +473,7 @@ OSStatus SecKeyImportPair(
         SecAccessRef initialAccess,
         SecKeyRef* publicKey,
         SecKeyRef* privateKey)
-        API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+        API_DEPRECATED_WITH_REPLACEMENT("SecItemImport", macos(10.0, 10.5)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 
 /*!
     @function SecKeyCreate
@@ -504,7 +504,7 @@ SecKeyRef SecKeyCreate(CFAllocatorRef allocator,
 */
 OSStatus SecKeyCreateWithCSSMKey(const CSSM_KEY *key, SecKeyRef* keyRef) API_DEPRECATED("CSSM_KEY is deprecated", macos(10.11, 10.14));
 
-// Alias macOS versions of this deprecated SPI to unique macOS names. Undecorated names are used for iosmac.
+// Alias macOS versions of this deprecated SPI to unique macOS names. Undecorated names are used for macCatalyst.
 #define SecKeyRawSign SecKeyRawSign_macOS
 #define SecKeyRawVerify SecKeyRawVerify_macOS
 
@@ -809,6 +809,10 @@ typedef CF_ENUM(uint32_t, SecKeyAttestationKeyType)
     kSecKeyAttestationKeyTypeUIKCommitted SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 2,
     kSecKeyAttestationKeyTypeUIKProposed SPI_AVAILABLE(macos(10.14), ios(12.0), tvos(12.0), watchos(5.0)) = 3,
     kSecKeyAttestationKeyTypeSecureElement SPI_AVAILABLE(ios(13.0)) = 4,
+    kSecKeyAttestationKeyTypeOIKCommitted SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0)) = 5,
+    kSecKeyAttestationKeyTypeOIKProposed SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0)) = 6,
+    kSecKeyAttestationKeyTypeDAKCommitted SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0)) = 7,
+    kSecKeyAttestationKeyTypeDAKProposed SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0)) = 8,
 } SPI_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0));
 
 /*!
index 21a894447d62229441314816c6e9d8504d4a126e..0d047b708d9c4413fde39ccd62f1ff89292537e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2016 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2014-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -52,7 +52,9 @@ CF_IMPLICIT_BRIDGING_ENABLED
         shared password. You use this key to get a value of type CFStringRef
         that contains a password.
 */
-extern const CFStringRef kSecSharedPassword API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos);
+extern const CFStringRef kSecSharedPassword
+    API_AVAILABLE(ios(8.0), macCatalyst(14.0), macos(10.16))
+    API_UNAVAILABLE(tvos, watchos);
 
 /*!
  @function SecAddSharedWebCredential
@@ -66,7 +68,9 @@ extern const CFStringRef kSecSharedPassword API_AVAILABLE(ios(8.0)) API_UNAVAILA
  Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available.
  */
 void SecAddSharedWebCredential(CFStringRef fqdn, CFStringRef account, CFStringRef __nullable password,
-    void (^completionHandler)(CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos);
+    void (^completionHandler)(CFErrorRef __nullable error))
+    API_AVAILABLE(ios(8.0), macCatalyst(14.0), macos(10.16))
+    API_UNAVAILABLE(tvos, watchos);
 
 /*!
  @function SecRequestSharedWebCredential
@@ -87,7 +91,10 @@ void SecAddSharedWebCredential(CFStringRef fqdn, CFStringRef account, CFStringRe
  Note: since a request involving shared web credentials may potentially require user interaction or other verification to be approved, this function is dispatched asynchronously; your code provides a completion handler that will be called once the results (if any) are available.
  */
 void SecRequestSharedWebCredential(CFStringRef __nullable fqdn, CFStringRef __nullable account,
-    void (^completionHandler)(CFArrayRef __nullable credentials, CFErrorRef __nullable error)) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos);
+    void (^completionHandler)(CFArrayRef __nullable credentials, CFErrorRef __nullable error))
+    API_DEPRECATED("Use ASAuthorizationController to make an ASAuthorizationPasswordRequest (AuthenticationServices framework)",
+                    ios(8.0,14.0), macCatalyst(14.0,14.0), macos(10.16,10.16))
+    API_UNAVAILABLE(tvos, watchos);
 
 /*!
  @function SecCreateSharedWebCredentialPassword
@@ -95,7 +102,9 @@ void SecRequestSharedWebCredential(CFStringRef __nullable fqdn, CFStringRef __nu
  @return CFStringRef password in the form xxx-xxx-xxx-xxx where x is taken from the sets "abcdefghkmnopqrstuvwxy", "ABCDEFGHJKLMNPQRSTUVWXYZ", "3456789" with at least one character from each set being present.
 */
 __nullable
-CFStringRef SecCreateSharedWebCredentialPassword(void) API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(macos, iosmac, tvos, watchos);
+CFStringRef SecCreateSharedWebCredentialPassword(void)
+    API_AVAILABLE(ios(8.0), macCatalyst(14.0), macos(10.16))
+    API_UNAVAILABLE(tvos, watchos);
 
 
 #endif /* __BLOCKS__ */
index 868f2bd848362e135583c949c1bb2b7015483ea5..731be0edf7649545fa9de356c9f622a4fe9bc9af 100644 (file)
@@ -310,8 +310,9 @@ enum {NUM_RETRIES = 5};
                   deviceName:(nullable NSString*)deviceName
                 serialNumber:(NSString *)serialNumber
                    osVersion:(NSString *)osVersion
-               policyVersion:(nullable TPPolicy *)policyVersion
+               policyVersion:(nullable TPPolicyVersion *)policyVersion
                policySecrets:(nullable NSDictionary<NSString*,NSData*> *)policySecrets
+   syncUserControllableViews:(TPPBPeerStableInfo_UserControllableViewStatus)syncUserControllableViews
  signingPrivKeyPersistentRef:(nullable NSData *)spkPr
      encPrivKeyPersistentRef:(nullable NSData*)epkPr
                        reply:(void (^)(NSString * _Nullable peerID,
@@ -319,8 +320,7 @@ enum {NUM_RETRIES = 5};
                                        NSData * _Nullable permanentInfoSig,
                                        NSData * _Nullable stableInfo,
                                        NSData * _Nullable stableInfoSig,
-                                       NSSet<NSString*>* syncingViews,
-                                       TPPolicy* _Nullable syncingPolicy,
+                                       TPSyncingPolicy* _Nullable syncingPolicy,
                                        NSError * _Nullable error))reply
 {
     __block int i = 0;
@@ -333,7 +333,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, nil, nil, nil, nil, nil, error);
+                        reply(nil, nil, nil, nil, nil, nil, error);
                     }
                     ++i;
                 }] prepareWithContainer:container
@@ -348,6 +348,7 @@ enum {NUM_RETRIES = 5};
          osVersion:osVersion
          policyVersion:policyVersion
          policySecrets:policySecrets
+         syncUserControllableViews:syncUserControllableViews
          signingPrivKeyPersistentRef:spkPr
          encPrivKeyPersistentRef:epkPr
          reply:reply];
@@ -361,6 +362,7 @@ enum {NUM_RETRIES = 5};
                preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                          reply:(void (^)(NSString * _Nullable peerID,
                                          NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                         TPSyncingPolicy* _Nullable syncingPolicy,
                                          NSError * _Nullable error))reply
 {
     __block int i = 0;
@@ -373,7 +375,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, error);
+                        reply(nil, nil, nil, error);
                     }
                     ++i;
                 }] establishWithContainer:container context:context ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply];
@@ -414,8 +416,8 @@ enum {NUM_RETRIES = 5};
                                       context:(nonnull NSString *)context
                                      bottleID:(nonnull NSString *)bottleID
                                         reply:(nonnull void (^)(NSString * _Nullable,
-                                                                NSSet<NSString*>* _Nullable peerSyncingViewList,
-                                                                TPPolicy * _Nullable peerSyncingPolicy,
+                                                                TPSyncingPolicy* _Nullable peerSyncingPolicy,
+                                                                BOOL refetchWasNeeded,
                                                                 NSError * _Nullable))reply {
     __block int i = 0;
     __block bool retry;
@@ -427,7 +429,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, nil, error);
+                        reply(nil, nil, false, error);
                     }
                     ++i;
                 }] preflightVouchWithBottleWithContainer:container
@@ -471,8 +473,7 @@ enum {NUM_RETRIES = 5};
                                        recoveryKey:(NSString*)recoveryKey
                                               salt:(NSString*)salt
                                              reply:(nonnull void (^)(NSString * _Nullable,
-                                                                     NSSet<NSString*>* _Nullable peerSyncingViewList,
-                                                                     TPPolicy * _Nullable peerSyncingPolicy,
+                                                                     TPSyncingPolicy* _Nullable peerSyncingPolicy,
                                                                      NSError * _Nullable))reply {
     __block int i = 0;
     __block bool retry;
@@ -484,7 +485,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, nil, error);
+                        reply(nil, nil, error);
                     }
                     ++i;
                 }] preflightVouchWithRecoveryKeyWithContainer:container
@@ -527,11 +528,10 @@ enum {NUM_RETRIES = 5};
                voucherSig:(NSData *)voucherSig
                  ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)viewKeySets
                 tlkShares:(NSArray<CKKSTLKShare*> *)tlkShares
-          preapprovedKeys:(NSArray<NSData*> *)preapprovedKeys
+          preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                     reply:(void (^)(NSString * _Nullable peerID,
                                     NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
-                                    NSSet<NSString*>* _Nullable viewSet,
-                                    TPPolicy* _Nullable syncingPolicy,
+                                    TPSyncingPolicy* _Nullable syncingPolicy,
                                     NSError * _Nullable error))reply
 {
     __block int i = 0;
@@ -544,7 +544,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, nil, nil, error);
+                        reply(nil, nil, nil, error);
                     }
                     ++i;
                 }] joinWithContainer:container context:context voucherData:voucherData voucherSig:voucherSig ckksKeys:viewKeySets tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply];
@@ -553,6 +553,7 @@ enum {NUM_RETRIES = 5};
 
 - (void)preflightPreapprovedJoinWithContainer:(NSString *)container
                                       context:(NSString *)context
+                              preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                                         reply:(void (^)(BOOL launchOkay,
                                                         NSError * _Nullable error))reply
 {
@@ -569,7 +570,7 @@ enum {NUM_RETRIES = 5};
                         reply(NO, error);
                     }
                     ++i;
-                }] preflightPreapprovedJoinWithContainer:container context:context reply:reply];
+        }] preflightPreapprovedJoinWithContainer:container context:context preapprovedKeys:preapprovedKeys reply:reply];
     } while (retry);
 }
 
@@ -577,11 +578,10 @@ enum {NUM_RETRIES = 5};
                                     context:(NSString *)context
                                    ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)ckksKeys
                                   tlkShares:(NSArray<CKKSTLKShare*> *)tlkShares
-                            preapprovedKeys:(NSArray<NSData*> *)preapprovedKeys
+                            preapprovedKeys:(nullable NSArray<NSData*> *)preapprovedKeys
                                       reply:(void (^)(NSString * _Nullable peerID,
                                                       NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
-                                                      NSSet<NSString*>* _Nullable syncingViewList,
-                                                      TPPolicy* _Nullable syncingPolicy,
+                                                      TPSyncingPolicy* _Nullable syncingPolicy,
                                                       NSError * _Nullable error))reply
 {
     __block int i = 0;
@@ -594,10 +594,15 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, nil, nil, error);
+                        reply(nil, nil, nil, error);
                     }
                     ++i;
-                }] attemptPreapprovedJoinWithContainer:container context:context ckksKeys:ckksKeys tlkShares:tlkShares preapprovedKeys:preapprovedKeys reply:reply];
+        }] attemptPreapprovedJoinWithContainer:container
+                                       context:context
+                                      ckksKeys:ckksKeys
+                                     tlkShares:tlkShares
+                               preapprovedKeys:preapprovedKeys
+                                         reply:reply];
     } while (retry);
 }
 
@@ -608,7 +613,8 @@ enum {NUM_RETRIES = 5};
                   osVersion:(nullable NSString *)osVersion
               policyVersion:(nullable NSNumber *)policyVersion
               policySecrets:(nullable NSDictionary<NSString*,NSData*> *)policySecrets
-                      reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState, NSError * _Nullable error))reply
+  syncUserControllableViews:(nullable NSNumber *)syncUserControllableViews
+                      reply:(void (^)(TrustedPeersHelperPeerState* _Nullable peerState, TPSyncingPolicy* _Nullable policy, NSError * _Nullable error))reply
 {
     __block int i = 0;
     __block bool retry;
@@ -620,10 +626,18 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, error);
+                        reply(nil, nil, error);
                     }
                     ++i;
-                }] updateWithContainer:container context:context deviceName:deviceName serialNumber:serialNumber osVersion:osVersion policyVersion:policyVersion policySecrets:policySecrets reply:reply];
+                }] updateWithContainer:container
+                               context:context
+                            deviceName:deviceName
+                          serialNumber:serialNumber
+                             osVersion:osVersion
+                         policyVersion:policyVersion
+                         policySecrets:policySecrets
+             syncUserControllableViews:syncUserControllableViews
+                                 reply:reply];
     } while (retry);
 }
 
@@ -742,8 +756,9 @@ enum {NUM_RETRIES = 5};
 
 - (void)fetchCurrentPolicyWithContainer:(NSString*)container
                                 context:(NSString*)context
-                                  reply:(void (^)(NSSet<NSString*>* _Nullable viewList,
-                                                  TPPolicy * _Nullable policy,
+                        modelIDOverride:(NSString* _Nullable)modelIDOverride
+                                  reply:(void (^)(TPSyncingPolicy* _Nullable syncingPolicy,
+                                                  TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers,
                                                   NSError * _Nullable error))reply
 {
     __block int i = 0;
@@ -756,10 +771,12 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(nil, nil, error);
+                        reply(nil,
+                              TPPBPeerStableInfo_UserControllableViewStatus_UNKNOWN,
+                              error);
                     }
                     ++i;
-                }] fetchCurrentPolicyWithContainer:container context:context reply:reply];
+        }] fetchCurrentPolicyWithContainer:container context:context modelIDOverride:modelIDOverride reply:reply];
     } while (retry);
 }
 
@@ -813,7 +830,8 @@ enum {NUM_RETRIES = 5};
                         recoveryKey:(NSString *)recoveryKey
                                salt:(NSString *)salt
                            ckksKeys:(NSArray<CKKSKeychainBackedKeySet*> *)ckksKeys
-                              reply:(void (^)(NSError* _Nullable error))reply
+                              reply:(void (^)(NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                              NSError* _Nullable error))reply
 {
     __block int i = 0;
     __block bool retry;
@@ -825,7 +843,7 @@ enum {NUM_RETRIES = 5};
                         retry = true;
                     } else {
                         secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
-                        reply(error);
+                        reply(nil, error);
                     }
                     ++i;
                 }] setRecoveryKeyWithContainer:container context:context recoveryKey:recoveryKey salt:salt ckksKeys:ckksKeys reply:reply];
@@ -920,4 +938,43 @@ enum {NUM_RETRIES = 5};
 
 }
 
+- (void)fetchViableEscrowRecordsWithContainer:(nonnull NSString *)container context:(nonnull NSString *)context forceFetch:(BOOL)forceFetch reply:(nonnull void (^)(NSArray<NSData *> * _Nullable, NSError * _Nullable))reply
+{
+    __block int i = 0;
+    __block bool retry;
+    do {
+        retry = false;
+        [[self.cuttlefishXPCConnection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *_Nonnull error) {
+            if (i < NUM_RETRIES && [self.class retryable:error]) {
+                secnotice("octagon", "retrying cuttlefish XPC, (%d, %@)", i, error);
+                retry = true;
+            } else {
+                secerror("octagon: Can't talk with TrustedPeersHelper: %@", error);
+                reply(nil, error);
+            }
+            ++i;
+        }] fetchViableEscrowRecordsWithContainer:container context:context forceFetch:forceFetch reply:reply];
+    } while (retry);
+}
+
+- (void)removeEscrowCacheWithContainer:(nonnull NSString *)container context:(nonnull NSString *)context reply:(nonnull 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;
+        }] removeEscrowCacheWithContainer:container context:context reply:reply];
+    } while (retry);
+}
+
+
+
 @end
index 88f684f1b07bd16dc23b94ec311b6341f7f6f1f5..cbb6e8ad1a091a87552e1c993dbe5afa00ee8a12 100644 (file)
@@ -286,7 +286,8 @@ NSDictionary<OctagonState*, NSNumber*>* OctagonClientStateMap(void) {
      osVersion:nil
      policyVersion:nil
      policySecrets:nil
-     reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) {
+     syncUserControllableViews:nil
+     reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* policy, NSError* error) {
          if(error) {
              secerror("OTCuttlefishContext: updating errored: %@", error);
          } else {
index 6257c0d24cc6ab1d140f5e7c1c93c62fca0f655c..f7951b8d680901e3fab7851df97f59642154f2bc 100644 (file)
@@ -77,7 +77,8 @@
     WEAKIFY(self);
 
     // Acquire the CKKS TLKs to pass in
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.operationDependencies];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"vouch-with-keys"
diff --git a/keychain/ot/OTClique+Private.h b/keychain/ot/OTClique+Private.h
new file mode 100644 (file)
index 0000000..298321d
--- /dev/null
@@ -0,0 +1,24 @@
+
+#ifndef OTClique_Private_h
+#define OTClique_Private_h
+
+#import <Security/OTClique.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OTClique(Private)
+
++ (NSArray<NSData*>* _Nullable)fetchEscrowRecordsInternal:(OTConfigurationContext*)configurationContext
+                                                    error:(NSError* __autoreleasing *)error;
+
++ (BOOL)isCloudServicesAvailable;
+
+- (BOOL)resetAndEstablish:(CuttlefishResetReason)resetReason error:(NSError**)error;
+
+- (BOOL)establish:(NSError**)error;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif /* OTClique_Private_h */
index cfe080f159ece349964878f71f355feb2ab91064..eccb408a53dddaf72a2f8046b068296c372da60e 100644 (file)
 #ifndef OTClique_h
 #define OTClique_h
 
+#if __OBJC2__
+
+#import <Foundation/Foundation.h>
+#import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
+#import <Security/SecureObjectSync/SOSPeerInfo.h>
+#import <Security/SecureObjectSync/SOSTypes.h>
+#import <Security/OTConstants.h>
+#import <Security/SecRecoveryKey.h>
+
 typedef NS_ENUM(NSInteger, CliqueStatus) {
     CliqueStatusIn         = 0, /*There is a clique and I am in it*/
     CliqueStatusNotIn      = 1, /*There is a clique and I am not in it - you should get a voucher to join or tell another peer to trust us*/
@@ -34,16 +43,6 @@ typedef NS_ENUM(NSInteger, CliqueStatus) {
     CliqueStatusError      = -1 /*unable to determine circle status, inspect CFError to find out why */
 };
 
-#import <Security/SecRecoveryKey.h>
-
-#if __OBJC2__
-
-#import <Foundation/Foundation.h>
-#import <Security/SecureObjectSync/SOSCloudCircleInternal.h>
-#import <Security/SecureObjectSync/SOSPeerInfo.h>
-#import <Security/SecureObjectSync/SOSTypes.h>
-#import <Security/OTConstants.h>
-
 typedef NS_ENUM(NSInteger, OTCDPStatus) {
     OTCDPStatusUnknown = 0,
     OTCDPStatusDisabled = 1,
@@ -67,11 +66,12 @@ extern NSString* kSecEntitlementPrivateOctagonEscrow;
 
 @interface OTConfigurationContext : NSObject
 @property (nonatomic, copy) NSString* context;
+@property (nonatomic, copy) NSString* containerName;
 @property (nonatomic, copy, nullable) NSString* dsid;
 @property (nonatomic, copy, nullable) NSString* altDSID;
-@property (nonatomic, strong, nullable) SFSignInAnalytics* analytics;
 @property (nonatomic, copy, nullable) NSString* authenticationAppleID;
 @property (nonatomic, copy, nullable) NSString* passwordEquivalentToken;
+@property (nonatomic) BOOL overrideEscrowCache;
 
 // Use this to inject your own OTControl object. It must be configured as synchronous.
 @property (nullable, strong) OTControl* otControl;
@@ -129,11 +129,6 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode;
  */
 - (instancetype)initWithContextData:(OTConfigurationContext *)ctx;
 
-/*
- * Much like initWithContextData, but might fail. There are currently no failures possible.
- */
-- (instancetype _Nullable)initWithContextData:(OTConfigurationContext *)ctx error:(NSError**)error __deprecated_msg("Use initWithContextData instead");
-
 /* *
  * @abstract   Establish a new clique, reset protected data
  *   Reset the clique
@@ -247,7 +242,6 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode;
  */
 - (NSDictionary<NSString*,NSString*>* _Nullable)peerDeviceNamesByPeerID:(NSError * __autoreleasing *)error;
 
-
 /*
  * CDP bit handling
  */
@@ -258,11 +252,31 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode;
 + (OTCDPStatus)getCDPStatus:(OTConfigurationContext*)arguments
                       error:(NSError* __autoreleasing *)error;
 
+/*
+ * User view handling
+ */
+
+/* *
+ * @abstract Set the current status of user-controllable views. This is unavailable on TV and Watch, and will error.
+ * @param error, This will return an error if anything goes wrong
+ * @return success
+ */
+- (BOOL)setUserControllableViewsSyncStatus:(BOOL)enabled
+                                     error:(NSError* __autoreleasing *)error;
+
+/* *
+ * @abstract Fetch the current status of user-controllable views
+ * @param   error, This will return an error if anything goes wrong
+ * @return status, The status of syncing. Note that in the success case, this can be NO while error remains empty.
+ */
+- (BOOL)fetchUserControllableViewsSyncingEnabled:(NSError* __autoreleasing *)error __attribute__((swift_error(nonnull_error)));
+
 /* SOS glue */
 
 - (BOOL)joinAfterRestore:(NSError * __autoreleasing *)error;
 
-- (BOOL)safariPasswordSyncingEnabled:(NSError *__autoreleasing*)error;
+- (BOOL)safariPasswordSyncingEnabled:(NSError *__autoreleasing*)error
+API_DEPRECATED_WITH_REPLACEMENT("fetchUserControllableViewsSyncingEnabled",macos(10.15, 10.16), ios(13.0, 14.0), watchos(6.0, 7.0), tvos(13.0,14.0));
 
 - (BOOL)isLastFriend:(NSError *__autoreleasing*)error;
 
@@ -270,7 +284,9 @@ extern OTCliqueCDPContextType OTCliqueCDPContextTypeUpdatePasscode;
 
 - (NSArray* _Nullable)copyViewUnawarePeerInfo:(NSError *__autoreleasing*)error;
 
-- (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews;
+- (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
+API_DEPRECATED_WITH_REPLACEMENT("setUserControllableViewsSyncStatus",macos(10.15, 10.16), ios(13.0, 14.0), watchos(6.0, 7.0), tvos(13.0,14.0));
+
 
 - (BOOL)setUserCredentialsAndDSID:(NSString*)userLabel
                               password:(NSData*)userPassword
index fbf8e5dab09e8b3cfa4c2e7c2626c7a7144711f7..41d426a63d2ebee0c1a81948baa851d0ec8f62e2 100644 (file)
@@ -27,6 +27,7 @@
 #import <Foundation/Foundation.h>
 
 #import "keychain/ot/OTClique.h"
+#import "keychain/ot/OTClique+Private.h"
 #import "keychain/ot/OTConstants.h"
 #import "keychain/ot/OTDefines.h"
 #import "keychain/SigninMetrics/OctagonSignPosts.h"
@@ -51,7 +52,7 @@ const NSString* kSecEntitlementPrivateOctagonEscrow = @"com.apple.private.octago
 #import "keychain/ot/categories/OctagonEscrowRecoverer.h"
 
 SOFT_LINK_FRAMEWORK(PrivateFrameworks, KeychainCircle);
-SOFT_LINK_FRAMEWORK(PrivateFrameworks, CloudServices);
+SOFT_LINK_OPTIONAL_FRAMEWORK(PrivateFrameworks, CloudServices);
 
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wstrict-prototypes"
@@ -124,6 +125,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
 
 @implementation OTConfigurationContext
+
 - (OTControl* _Nullable)makeOTControl:(NSError**)error
 {
 #if OCTAGON
@@ -225,23 +227,17 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     [self.defaults removeObjectForKey:OTDefaultsOctagonEnable];
 }
 
-- (instancetype)initWithContextData:(OTConfigurationContext *)ctx error:(NSError * __autoreleasing *)error
-{
-    return [self initWithContextData:ctx];
-}
-
 - (instancetype)initWithContextData:(OTConfigurationContext *)ctx
 {
 #if OCTAGON
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         _ctx = [[OTConfigurationContext alloc]init];
         _ctx.context = ctx.context ?: OTDefaultContext;
         _ctx.dsid = [ctx.dsid copy];
         _ctx.altDSID = [ctx.altDSID copy];
-        _ctx.analytics = ctx.analytics;
         _ctx.otControl = ctx.otControl;
         _ctx.ckksControl = ctx.ckksControl;
+        _ctx.overrideEscrowCache = ctx.overrideEscrowCache;
 
         self.defaults = [NSMutableDictionary dictionary];
     }
@@ -250,7 +246,8 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     NSAssert(false, @"OTClique is not implemented on this platform");
 
     // make the build analyzer happy
-    self = [super init];
+    if ((self = [super init])) {
+    }
     return self;
 #endif // OCTAGON
 }
@@ -385,7 +382,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     secnotice("clique-newfriends", "makeNewFriends invoked using context: %@, dsid: %@", data.context, data.dsid);
     bool result = false;
     bool subTaskSuccess = false;
-    OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNameMakeNewFriends);
+    OctagonSignpost newFriendsSignpost = OctagonSignpostBegin(OctagonSignpostNameMakeNewFriends);
 
     OTClique* clique = [[OTClique alloc] initWithContextData:data];
 
@@ -398,7 +395,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
             if(error) {
                 *error = localError;
             }
-            OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
+            OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
             return nil;
         } else {
             secnotice("clique-newfriends", "Octagon account reset succeeded");
@@ -416,7 +413,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
             } else {
                 CFBridgingRelease(resetError);
             }
-            OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
+            OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
             return nil;
         }
         secnotice("clique-newfriends", "newFriendsWithContextData: reset the SOS circle");
@@ -426,7 +423,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     secnotice("clique-newfriends", "makeNewFriends complete");
 
     subTaskSuccess = true;
-    OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
+    OctagonSignpostEnd(newFriendsSignpost, OctagonSignpostNameMakeNewFriends, OctagonSignpostNumber1(OctagonSignpostNameMakeNewFriends), (int)subTaskSuccess);
 
     return clique;
 
@@ -437,11 +434,35 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 #endif
 }
 
++ (BOOL)isCloudServicesAvailable
+{
+#if OCTAGON
+    if (isCloudServicesAvailable()) {
+        return YES;
+    }
+
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        secnotice("octagon", "CloudServices is unavailable on this platform");
+    });
+    return NO;
+#else
+    return NO;
+#endif
+}
+
 + (OTClique* _Nullable)performEscrowRecoveryWithContextData:(OTConfigurationContext*)data
                                             escrowArguments:(NSDictionary*)sbdRecoveryArguments
                                                       error:(NSError**)error
 {
 #if OCTAGON
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+        }
+        return nil;
+    }
+
     OctagonSignpost performEscrowRecoverySignpost = OctagonSignpostBegin(OctagonSignpostNamePerformEscrowRecovery);
     bool subTaskSuccess = false;
     NSError* localError = nil;
@@ -511,7 +532,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
         secnotice("clique-recovery", "recovering from bottle: %@", bottleID);
         __block NSError* restoreBottleError = nil;
 
-        OctagonSignpost bottleRecoverySignPost = OctagonSignpostBegin(OctagonSignpostNamePerformBottleRecovery);
+        OctagonSignpost bottleRecoverySignPost = OctagonSignpostBegin(OctagonSignpostNamePerformOctagonJoin);
         //restore bottle!
         [control restore:OTCKContainerName
                contextID:data.context
@@ -528,7 +549,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
             }];
 
         subTaskSuccess = (restoreBottleError == nil) ? true : false;
-        OctagonSignpostEnd(bottleRecoverySignPost, OctagonSignpostNamePerformBottleRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformBottleRecovery), (int)subTaskSuccess);
+        OctagonSignpostEnd(bottleRecoverySignPost, OctagonSignpostNamePerformOctagonJoin, OctagonSignpostNumber1(OctagonSignpostNamePerformOctagonJoin), (int)subTaskSuccess);
 
         if(restoreBottleError) {
             if(error){
@@ -553,6 +574,11 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
         if(resetError) {
             secnotice("clique-recovery", "failed to reset octagon: %@", resetError);
+            if(error){
+                *error = resetError;
+            }
+            OctagonSignpostEnd(performEscrowRecoverySignpost, OctagonSignpostNamePerformEscrowRecovery, OctagonSignpostNumber1(OctagonSignpostNamePerformEscrowRecovery), (int)subTaskSuccess);
+            return nil;
         } else{
             secnotice("clique-recovery", "reset octagon succeeded");
         }
@@ -791,20 +817,9 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
     if([OTClique platformSupportsSOS] && sosIdentifiers.count >0) {
         CFErrorRef removeFriendError = NULL;
-        NSData* analyticsData = nil;
 
         secnotice("clique-removefriends", "removing sos friends: %@", sosIdentifiers);
-
-        if(self.ctx.analytics){
-            NSError* encodingError = nil;
-            analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
-        }
-
-        if(analyticsData) {
-            result = SOSCCRemovePeersFromCircleWithAnalytics((__bridge CFArrayRef)friendIdentifiers, (__bridge CFDataRef)analyticsData, &removeFriendError);
-        } else {
-            result = SOSCCRemovePeersFromCircle((__bridge CFArrayRef)friendIdentifiers, &removeFriendError);
-        }
+        result = SOSCCRemovePeersFromCircle((__bridge CFArrayRef)friendIdentifiers, &removeFriendError);
 
         if(removeFriendError) {
             secnotice("clique-removefriends", "removeFriendsInClique failed: unable to remove friends: %@", removeFriendError);
@@ -879,21 +894,7 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     }
 
     if([OTClique platformSupportsSOS]) {
-        NSData* analyticsData = nil;
-
-        if(self.ctx.analytics) {
-            NSError* encodingError = nil;
-            analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
-            if(!analyticsData){
-                secnotice("clique-leaveClique", "leaveClique unable to archive analytics object: %@", encodingError);
-            }
-        }
-
-        if(analyticsData) {
-            result &= SOSCCRemoveThisDeviceFromCircleWithAnalytics((__bridge CFDataRef)analyticsData, &removeThisDeviceError);
-        } else {
-            result &= SOSCCRemoveThisDeviceFromCircle(&removeThisDeviceError);
-        }
+        result &= SOSCCRemoveThisDeviceFromCircle(&removeThisDeviceError);
         if (error) {
             *error = (NSError*)CFBridgingRelease(removeThisDeviceError);
         } else {
@@ -1013,6 +1014,11 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 }
 
 - (BOOL)safariPasswordSyncingEnabled:(NSError **)error
+{
+    return [self fetchUserControllableViewsSyncingEnabled:error];
+}
+
+- (BOOL)sosSafariPasswordSyncingEnabled:(NSError **)error
 {
     secnotice("clique-safari", "safariPasswordSyncingEnabled for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
     OctagonSignpost safariSyncingEnabledSignPost = OctagonSignpostBegin(OctagonSignpostNameSafariPasswordSyncingEnabled);
@@ -1046,6 +1052,158 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     }
 }
 
+- (BOOL)setUserControllableViewsSyncStatus:(BOOL)enabled
+                                     error:(NSError* __autoreleasing *)error
+{
+    if([OTClique platformSupportsSOS]) {
+        // We either enable or disable this list of SOS views, taken from CDP.
+        NSSet<NSString*>* sosViews = [NSSet setWithObjects:(__bridge id)kSOSViewWiFi,
+                                      (__bridge id)kSOSViewAutofillPasswords,
+                                      (__bridge id)kSOSViewSafariCreditCards,
+                                      (__bridge id)kSOSViewOtherSyncable,
+                                      nil];
+
+        BOOL sosResult = NO;
+        if(enabled) {
+            sosResult = [self sosViewSet:sosViews disabledViews:[NSSet set]];
+        } else {
+            sosResult = [self sosViewSet:[NSSet set] disabledViews:sosViews];
+        }
+
+        if(sosResult == NO) {
+            secnotice("clique-user-sync", "SOS view setting failed, but no error returned");
+            if(error) {
+                *error = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain
+                                             code:kSOSErrorNotReady
+                                         userInfo:@{
+                                             NSLocalizedDescriptionKey: @"SOS reported failure, but no error given"
+                                         }];
+            }
+
+            return NO;
+        }
+    }
+
+    if(OctagonIsEnabled()) {
+        return [self setOctagonUserControllableViewsSyncEnabled:enabled
+                                                          error:error];
+    }
+
+    return YES;
+}
+
+- (BOOL)setOctagonUserControllableViewsSyncEnabled:(BOOL)enabled
+                                             error:(NSError* __autoreleasing *)error
+{
+#if OCTAGON
+    OTControl* control = [self makeOTControl:error];
+    if(!control) {
+        return NO;
+    }
+
+    __block NSError* localError = nil;
+
+    secnotice("clique-user-sync", "setting user-controllable-sync status to %@", enabled ? @"enabled" : @"paused");
+
+    [control setUserControllableViewsSyncStatus:self.ctx.containerName
+                                      contextID:self.ctx.context
+                                        enabled:enabled
+                                          reply:^(BOOL nowSyncing, NSError* _Nullable fetchError) {
+        if(fetchError) {
+            secnotice("clique-user-sync", "setting user-controllable-sync status errored: %@", fetchError);
+            localError = fetchError;
+        } else {
+            secnotice("clique-user-sync", "setting user-controllable-sync status succeeded, now : %@", nowSyncing ? @"enabled" : @"paused");
+        }
+    }];
+
+    if(error && localError) {
+        *error = localError;
+    }
+
+    return localError == nil;
+#else
+    if(error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                     code:errSecUnimplemented
+                                 userInfo:@{NSLocalizedDescriptionKey: @"setOctagonUserControllableViewSync unimplemented on this platform"}];
+    }
+    return NO;
+#endif
+}
+
+- (BOOL)fetchUserControllableViewsSyncingEnabled:(NSError* __autoreleasing *)error
+{
+    if(!OctagonIsEnabled() && ![OTClique platformSupportsSOS]) {
+        secnotice("clique-user-sync", "No syncing platforms enabled; views are not syncing");
+        return NO;
+    }
+
+    __block BOOL octagonSyncing = NO;
+#if OCTAGON
+    if(OctagonIsEnabled()) {
+        OTControl* control = [self makeOTControl:error];
+        if(!control) {
+            return NO;
+        }
+
+        __block NSError* localError = nil;
+        [control fetchUserControllableViewsSyncStatus:self.ctx.containerName
+                                            contextID:self.ctx.context
+                                                reply:^(BOOL nowSyncing, NSError* _Nullable fetchError) {
+            if(fetchError) {
+                secnotice("clique-user-sync", "fetching user-controllable-sync status errored: %@", fetchError);
+            } else {
+                secnotice("clique-user-sync", "fetched user-controllable-sync status as : %@", nowSyncing ? @"enabled" : @"paused");
+            }
+            octagonSyncing = nowSyncing;
+            localError = fetchError;
+        }];
+
+        if(localError) {
+            if(error) {
+                *error = localError;
+            }
+            return octagonSyncing;
+        }
+    }
+#endif
+
+    BOOL sosSafariEnabled = NO;
+    if([OTClique platformSupportsSOS]) {
+        NSError* localError = nil;
+        sosSafariEnabled = [self sosSafariPasswordSyncingEnabled:&localError];
+
+        if(localError) {
+            if(error) {
+                *error = localError;
+            }
+            return sosSafariEnabled;
+        }
+    }
+
+    if(OctagonIsEnabled() && [OTClique platformSupportsSOS]) {
+        // Return the OR of this value, so that the UI checkbox will be on if any syncing is occurring
+        return octagonSyncing || sosSafariEnabled;
+
+    } else if(OctagonIsEnabled() && ![OTClique platformSupportsSOS]) {
+        return octagonSyncing;
+
+    } else if(!OctagonIsEnabled()&& [OTClique platformSupportsSOS]) {
+        return sosSafariEnabled;
+
+    } else {
+        // Should be impossible, due to the check above. So:
+        if(error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                         code:errSecUnimplemented
+                                     userInfo:@{NSLocalizedDescriptionKey: @"fetchUserControllableViewsSyncingEnabled has no meaning if all sync systems are not on this platform"}];
+        }
+        return NO;
+    }
+}
+
+
 - (BOOL)isLastFriend:(NSError **)error
 {
     secnotice("clique-isLastFriend", "is last friend");
@@ -1061,20 +1219,8 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
     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);
-        }
+        BOOL initialSyncResult = SOSCCWaitForInitialSync(&initialSyncErrorRef) ? YES : NO;
 
-        BOOL initialSyncResult = result ? YES : NO;
         if (error) {
             *error = (NSError*)CFBridgingRelease(initialSyncErrorRef);
         } else {
@@ -1133,23 +1279,28 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
 - (BOOL)viewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
 {
-    secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@", self.ctx.context, self.ctx.altDSID);
+    if(OctagonIsEnabled()) {
+        bool enableUserViews = [enabledViews containsObject:(__bridge NSString*)kSOSViewAutofillPasswords];
+        NSError* octagonError = nil;
+        // This function should log its success or failure
+        BOOL result = [self setOctagonUserControllableViewsSyncEnabled:enableUserViews error:&octagonError];
+        if(!result) {
+            return NO;
+        }
+    }
+
+    return [self sosViewSet:enabledViews disabledViews:disabledViews];
+}
+
+- (BOOL)sosViewSet:(NSSet*)enabledViews disabledViews:(NSSet*)disabledViews
+{
+    secnotice("clique-legacy", "viewSet for context:%@, altdsid:%@ enable:%@, disable:%@",
+              self.ctx.context, self.ctx.altDSID, enabledViews, disabledViews);
     OctagonSignpost signPost = OctagonSignpostBegin(OctagonSignpostNameViewSet);
     bool subTaskSuccess = false;
 
     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);
-        }
+        bool result = SOSCCViewSet((__bridge CFSetRef)enabledViews, (__bridge CFSetRef)disabledViews);
 
         BOOL viewSetResult = result ? YES : NO;
         subTaskSuccess = result;
@@ -1172,28 +1323,10 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 
     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);
-        }
+        bool result = SOSCCSetUserCredentialsAndDSID((__bridge CFStringRef)userLabel,
+                                                     (__bridge CFDataRef)userPassword,
+                                                     (__bridge CFStringRef)self.ctx.dsid,
+                                                     &setCredentialsErrorRef);
 
         BOOL setCredentialsResult = result ? YES : NO;
         secnotice("clique-legacy", "setUserCredentialsAndDSID results: %d %@", setCredentialsResult, setCredentialsErrorRef);
@@ -1379,19 +1512,8 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 #endif // OCTAGON
 
     if([OTClique platformSupportsSOS]) {
-        NSData* analyticsData = nil;
         CFErrorRef joinErrorRef = NULL;
-        if(self.ctx.analytics){
-            NSError* encodingError = nil;
-            analyticsData = [NSKeyedArchiver archivedDataWithRootObject:self.ctx.analytics requiringSecureCoding:YES error:&encodingError];
-        }
-
-        if(analyticsData){
-            result = SOSCCRequestToJoinCircleWithAnalytics((__bridge CFDataRef)analyticsData, &joinErrorRef);
-        } else {
-            result = SOSCCRequestToJoinCircle(&joinErrorRef);
-        }
-
+        result = SOSCCRequestToJoinCircle(&joinErrorRef);
         secnotice("clique-legacy", "sos requestToJoinCircle complete: %d %@", result, joinErrorRef);
         if (error) {
             *error = (NSError*)CFBridgingRelease(joinErrorRef);
@@ -1427,6 +1549,62 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
     }
 }
 
++ (NSArray<NSData*>* _Nullable)fetchEscrowRecordsInternal:(OTConfigurationContext*)configurationContext
+                                                    error:(NSError**)error
+{
+#if OCTAGON
+    secnotice("clique-fetchrecords", "fetching escrow records for context:%@, altdsid:%@", configurationContext.context, configurationContext.altDSID);
+
+    if(OctagonIsEnabled()) {
+        __block NSError* localError = nil;
+        __block NSArray<NSData*>* localRecords = nil;
+
+        OTControl *control = [configurationContext makeOTControl:&localError];
+        if (!control) {
+            secnotice("clique-fetchrecords", "unable to create otcontrol: %@", localError);
+            if (error) {
+                *error = localError;
+            }
+            return nil;
+        }
+        [control fetchEscrowRecords:OTCKContainerName
+                          contextID:configurationContext.context
+                         forceFetch:configurationContext.overrideEscrowCache
+                              reply:^(NSArray<NSData *> * _Nullable records,
+                                      NSError * _Nullable fetchError) {
+            if(fetchError) {
+                secnotice("clique-fetchrecords", "fetchEscrowRecords errored: %@", fetchError);
+            } else {
+                secnotice("clique-fetchrecords", "fetchEscrowRecords succeeded: %@", records);
+            }
+            localError = fetchError;
+            localRecords = records;
+        }];
+        
+        if(error && localError) {
+            *error = localError;
+        }
+
+        secnotice("clique-fetchrecords", "fetchEscrowRecords complete");
+
+        return localRecords;
+    } else {
+        // With octagon off, fail with 'unimplemented'
+        if(error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                         code:errSecUnimplemented
+                                     userInfo:@{NSLocalizedDescriptionKey: @"fetching escrow records unimplemented"}];
+        }
+        return nil;
+    }
+#else // !OCTAGON
+    if (error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+    }
+    return NULL;
+#endif
+}
+
 // MARK: SBD interfaces
 + (OTBottleIDs* _Nullable)findOptimalBottleIDsWithContextData:(OTConfigurationContext*)data
                                                         error:(NSError**)error
@@ -1574,7 +1752,11 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
         secerror("octagon-setrecoverykey, SecRKCreateRecoveryKeyWithError() failed: %@", createRecoveryKeyError);
         userInfo[NSLocalizedDescriptionKey] = @"SecRKCreateRecoveryKeyWithError() failed";
         userInfo[NSUnderlyingErrorKey] = createRecoveryKeyError;
-        retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
+        if ([OTClique isCloudServicesAvailable] == NO) {
+            retError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:userInfo];
+        } else {
+            retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
+        }
         OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
         reply(nil, retError);
         return;
@@ -1586,7 +1768,11 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
             NSError *underlyingError = CFBridgingRelease(registerError);
             userInfo[NSLocalizedDescriptionKey] = @"SecRKRegisterBackupPublicKey() failed";
             userInfo[NSUnderlyingErrorKey] = underlyingError;
-            retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
+            if ([OTClique isCloudServicesAvailable] == NO) {
+                retError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:userInfo];
+            } else {
+                retError = [NSError errorWithDomain:getkSecureBackupErrorDomain() code:kSecureBackupInternalError userInfo:userInfo];
+            }
             OctagonSignpostEnd(signPost, OctagonSignpostNameSetNewRecoveryKeyWithData, OctagonSignpostNumber1(OctagonSignpostNameSetNewRecoveryKeyWithData), (int)subTaskSuccess);
             reply(nil,retError);
             return;
@@ -1858,6 +2044,12 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
 + (OTClique* _Nullable)resetProtectedData:(OTConfigurationContext*)data error:(NSError**)error
 {
 #if OCTAGON
+    if ([OTClique isCloudServicesAvailable] == NO) {
+        if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecUnimplemented userInfo:nil];
+        }
+        return nil;
+    }
     NSError *controlError = nil;
     OTControl *control = [data makeOTControl:&controlError];
     if (!control) {
@@ -1924,22 +2116,6 @@ NSString* OTCDPStatusToString(OTCDPStatus status) {
         }
     }
 
-    //reset ckks
-    CKKSControl* ckksControl = [data makeCKKSControl:&localError];
-    [ckksControl rpcResetCloudKit:nil reason:@"clique-reset-protected-data" reply:^(NSError* resetError){
-        localError = resetError;
-    }];
-
-    if(localError) {
-        secerror("clique-reset-protected-data: ckks cloudkit reset failed: %@", localError);
-        if(error) {
-            *error = localError;
-        }
-        return nil;
-    } else {
-        secnotice("clique-reset-protected-data", "ckks cloudkit reset succeeded");
-    }
-
     return clique;
 #else // !OCTAGON
     if(error) {
index 736ab162c2ee4b744116698f58a8d5f11793de87..6898c1b729deca866848757a502f9322c45fe53b 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdbool.h>
 
 bool OctagonIsEnabled(void);
+bool SecErrorIsNestedErrorCappingEnabled(void);
 
 #if __OBJC__
 
@@ -44,6 +45,7 @@ extern NSString* OTProtocolPairing;
 extern NSString* OTProtocolPiggybacking;
 
 extern const char * OTTrustStatusChangeNotification;
+extern NSString* OTEscrowRecordPrefix;
 
 
 BOOL OctagonPlatformSupportsSOS(void);
@@ -64,6 +66,17 @@ void OctagonAuthoritativeTrustSetIsEnabled(BOOL value);
 BOOL OctagonIsSOSFeatureEnabled(void);
 void OctagonSetSOSFeatureEnabled(BOOL value);
 
+BOOL OctagonIsOptimizationEnabled(void);
+void OctagonSetOptimizationEnabled(BOOL value);
+
+BOOL OctagonIsEscrowRecordFetchEnabled(void);
+void OctagonSetEscrowRecordFetchEnabled(BOOL value);
+
+BOOL SecKVSOnCloudKitIsEnabled(void);
+void SecKVSOnCloudKitSetOverrideIsEnabled(BOOL value);
+
+void SecErrorSetOverrideNestedErrorCappingIsEnabled(BOOL value);
+
 typedef NS_ENUM(NSInteger, CuttlefishResetReason) {
     CuttlefishResetReasonUnknown = 0,
     CuttlefishResetReasonUserInitiatedReset = 1,
@@ -74,6 +87,9 @@ typedef NS_ENUM(NSInteger, CuttlefishResetReason) {
     CuttlefishResetReasonTestGenerated = 6,
 };
 
+extern NSString* const CuttlefishErrorDomain;
+extern NSString* const CuttlefishErrorRetryAfterKey;
+
 #endif // __OBJC__
 
 #endif /* OTConstants_h */
index e839d139f4d92ac8bf7d32e2e1749a3978997af4..9d133e618608a0bbbbd5e9b1d9a35e0dbe0ffcf0 100644 (file)
@@ -42,6 +42,11 @@ NSString* OTProtocolPiggybacking = @"OctagonPiggybacking";
 
 const char * OTTrustStatusChangeNotification = "com.apple.security.octagon.trust-status-change";
 
+NSString* const CuttlefishErrorDomain = @"CuttlefishError";
+NSString* const CuttlefishErrorRetryAfterKey = @"retryafter";
+
+NSString* OTEscrowRecordPrefix = @"com.apple.icdp.record.";
+
 // I don't recommend using this command, but it does describe the plist that will enable this feature:
 //
 //  defaults write /System/Library/FeatureFlags/Domain/Security octagon -dict Enabled -bool YES
@@ -58,6 +63,18 @@ static bool OctagonAuthoritativeTrustEnabledOverride = false;
 static bool OctagonSOSFeatureIsEnabledOverrideSet = false;
 static bool OctagonSOSFeatureIsEnabledOverride = false;
 
+static bool OctagonOptimizationIsEnabledOverrideSet = false;
+static bool OctagonOptimizationIsEnabledOverride = false;
+
+static bool OctagonEscrowRecordFetchIsEnabledOverrideSet = false;
+static bool OctagonEscrowRecordFetchIsEnabledOverride = false;
+
+static bool SecKVSOnCloudKitIsEnabledOverrideSet = false;
+static bool SecKVSOnCloudKitIsEnabledOverride = false;
+
+static bool SecErrorNestedErrorCappingIsEnabledOverrideSet = false;
+static bool SecErrorNestedErrorCappingIsEnabledOverride = false;
+
 bool OctagonIsEnabled(void)
 {
     if(OctagonEnabledOverrideSet) {
@@ -191,7 +208,7 @@ BOOL OctagonIsSOSFeatureEnabled(void)
 {
     if(OctagonSOSFeatureIsEnabledOverrideSet) {
         secnotice("octagon", "SOS Feature is %@ (overridden)", OctagonSOSFeatureIsEnabledOverride ? @"enabled" : @"disabled");
-        return OctagonSOSFeatureIsEnabledOverrideSet;
+        return OctagonSOSFeatureIsEnabledOverride;
     }
 
     static bool sosEnabled = true;
@@ -209,3 +226,100 @@ void OctagonSetSOSFeatureEnabled(BOOL value)
     OctagonSOSFeatureIsEnabledOverrideSet = true;
     OctagonSOSFeatureIsEnabledOverride = value;
 }
+
+//feature flag for enabling/disabling performance enhancements
+BOOL OctagonIsOptimizationEnabled(void)
+{
+    if(OctagonOptimizationIsEnabledOverrideSet) {
+        secnotice("octagon", "Octagon Optimization is %@ (overridden)", OctagonOptimizationIsEnabledOverride ? @"enabled" : @"disabled");
+        return OctagonOptimizationIsEnabledOverride;
+    }
+
+    static bool optimizationEnabled = true;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        optimizationEnabled = os_feature_enabled(Security, OctagonOptimization);
+        secnotice("octagon", "Octagon Optimization is %@ (via feature flags)", optimizationEnabled ? @"enabled" : @"disabled");
+    });
+
+    return optimizationEnabled;
+}
+
+void OctagonSetOptimizationEnabled(BOOL value)
+{
+    OctagonOptimizationIsEnabledOverrideSet = true;
+    OctagonOptimizationIsEnabledOverride = value;
+}
+
+
+//feature flag for checking if escrow record fetching is enabled
+BOOL OctagonIsEscrowRecordFetchEnabled(void)
+{
+    if(OctagonEscrowRecordFetchIsEnabledOverrideSet) {
+        secnotice("octagon", "Octagon Escrow Record Fetching is %@ (overridden)", OctagonEscrowRecordFetchIsEnabledOverride ? @"enabled" : @"disabled");
+        return OctagonEscrowRecordFetchIsEnabledOverride;
+    }
+
+    static bool escrowRecordFetchingEnabled = true;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        escrowRecordFetchingEnabled = os_feature_enabled(Security, OctagonEscrowRecordFetch);
+        secnotice("octagon", "Octagon Escrow Record Fetching is %@ (via feature flags)", escrowRecordFetchingEnabled ? @"enabled" : @"disabled");
+    });
+
+    return escrowRecordFetchingEnabled;
+}
+
+void OctagonSetEscrowRecordFetchEnabled(BOOL value)
+{
+    OctagonEscrowRecordFetchIsEnabledOverrideSet = true;
+    OctagonEscrowRecordFetchIsEnabledOverride = value;
+}
+
+//feature flag for checking kvs on cloudkit enablement
+BOOL SecKVSOnCloudKitIsEnabled(void)
+{
+    if(SecKVSOnCloudKitIsEnabledOverrideSet) {
+        secnotice("octagon", "KVS on CloudKit is %@ (overridden)", SecKVSOnCloudKitIsEnabledOverride ? @"enabled" : @"disabled");
+        return SecKVSOnCloudKitIsEnabledOverride;
+    }
+
+    static bool kvsOnCloudKitEnabled = true;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        kvsOnCloudKitEnabled = os_feature_enabled(KVS, KVSOnCloudKitForAll);
+        secnotice("octagon", "KVS on CloudKit is %@ (via feature flags)", kvsOnCloudKitEnabled ? @"enabled" : @"disabled");
+    });
+
+    return kvsOnCloudKitEnabled;
+}
+
+void SecKVSOnCloudKitSetOverrideIsEnabled(BOOL value)
+{
+    SecKVSOnCloudKitIsEnabledOverrideSet = true;
+    SecKVSOnCloudKitIsEnabledOverride = value;
+}
+
+//feature flag for checking whether or not we should cap the number of nested errors
+bool SecErrorIsNestedErrorCappingEnabled(void)
+{
+    if(SecErrorNestedErrorCappingIsEnabledOverrideSet) {
+        secnotice("octagon", "SecError Nested Error Capping is %@ (overridden)", SecErrorNestedErrorCappingIsEnabledOverride ? @"enabled" : @"disabled");
+        return SecErrorNestedErrorCappingIsEnabledOverride;
+    }
+
+    static bool errorCappingEnabled = true;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        errorCappingEnabled = os_feature_enabled(Security, SecErrorNestedErrorCapping);
+        secnotice("octagon", "SecError Nested Error Capping is %@ (via feature flags)", errorCappingEnabled ? @"enabled" : @"disabled");
+    });
+
+    return errorCappingEnabled;
+}
+
+void SecErrorSetOverrideNestedErrorCappingIsEnabled(BOOL value)
+{
+    SecErrorNestedErrorCappingIsEnabledOverrideSet = true;
+    SecErrorNestedErrorCappingIsEnabledOverride = value;
+}
index c279f62c8070a64ccd3ff790bc795bc1763ad6c2..9b903dc8cd32ca16086f80c17155e70106b22572 100644 (file)
@@ -214,10 +214,6 @@ NS_ASSUME_NONNULL_BEGIN
 skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
               reply:(void (^)(NSError *_Nullable error))reply;
 
-- (void)attemptSosUpgrade:(NSString* _Nullable)container
-                  context:(NSString*)context
-                    reply:(void (^)(NSError* _Nullable error))reply;
-
 - (void)waitForOctagonUpgrade:(NSString* _Nullable)container
                       context:(NSString*)context
                         reply:(void (^)(NSError* _Nullable error))reply;
@@ -246,6 +242,26 @@ skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
                 contextID:(NSString*)contextID
                     reply:(void (^)(NSError* _Nullable error))reply;
 
+
+- (void)fetchEscrowRecords:(NSString * _Nullable)container
+                 contextID:(NSString*)contextID
+                forceFetch:(BOOL)forceFetch
+                     reply:(void (^)(NSArray<NSData*>* _Nullable records,
+                                     NSError* _Nullable error))reply;
+
+- (void)setUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                 contextID:(NSString*)contextID
+                                   enabled:(BOOL)enabled
+                                     reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply;
+
+- (void)fetchUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                   contextID:(NSString*)contextID
+                                       reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply;
+
+- (void)invalidateEscrowCache:(NSString * _Nullable)containerName
+                    contextID:(NSString*)contextID
+                        reply:(nonnull void (^)(NSError * _Nullable error))reply;
+
 @end
 
 NS_ASSUME_NONNULL_END
index e5669901fb6269076970a86df86bf5ce4fd51fa7..67cd5ea5ed8e8a6ef18eaaa7946d3c2498de4ab8 100644 (file)
@@ -441,15 +441,6 @@ skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
     }] healthCheck:container context:context skipRateLimitingCheck:skipRateLimitingCheck reply:reply];
 }
 
-- (void)attemptSosUpgrade:(NSString* _Nullable)container
-                  context:(NSString*)context
-                    reply:(void (^)(NSError* _Nullable error))reply
-{
-    [[self getConnection: ^(NSError* error) {
-        reply(error);
-    }] attemptSosUpgrade:container context:context reply:reply];
-}
-
 - (void)waitForOctagonUpgrade:(NSString* _Nullable)container
                       context:(NSString*)context
                         reply:(void (^)(NSError* _Nullable error))reply
@@ -508,6 +499,46 @@ skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
     }] getCDPStatus:containerName contextID:contextID reply:reply];
 }
 
+- (void)fetchEscrowRecords:(NSString * _Nullable)container
+                 contextID:(NSString*)contextID
+                forceFetch:(BOOL)forceFetch
+                     reply:(void (^)(NSArray<NSData*>* _Nullable records,
+                                     NSError* _Nullable error))reply
+{
+    [[self getConnection: ^(NSError* connectionError) {
+        reply(nil, connectionError);
+    }] fetchEscrowRecords:container contextID:contextID forceFetch:forceFetch reply:reply];
+}
+
+- (void)setUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                 contextID:(NSString*)contextID
+                                   enabled:(BOOL)enabled
+                                     reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
+{
+    [[self getConnection: ^(NSError* connectionError) {
+        reply(NO, connectionError);
+    }] setUserControllableViewsSyncStatus:containerName contextID:contextID enabled:enabled reply:reply];
+
+}
+
+- (void)fetchUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                   contextID:(NSString*)contextID
+                                       reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
+{
+    [[self getConnection: ^(NSError* connectionError) {
+        reply(NO, connectionError);
+    }] fetchUserControllableViewsSyncStatus:containerName contextID:contextID reply:reply];
+}
+
+- (void)invalidateEscrowCache:(NSString * _Nullable)containerName
+                    contextID:(NSString*)contextID
+                        reply:(nonnull void (^)(NSError * _Nullable error))reply
+{
+    [[self getConnection: ^(NSError* connectionError) {
+        reply(connectionError);
+    }] invalidateEscrowCache:containerName contextID:contextID reply:reply];
+}
+
 + (OTControl*)controlObject:(NSError* __autoreleasing *)error {
     return [OTControl controlObject:false error:error];
 }
index 48f99a779fe9f0cc941ddbe06044d88ea5761da1..736875b49aa164c38718be093a05a87a909f4caa 100644 (file)
@@ -34,8 +34,6 @@ NS_ASSUME_NONNULL_BEGIN
 
 @class OTJoiningConfiguration;
 
-typedef void (^OTNextJoinCompleteBlock)(BOOL finished, NSData* _Nullable message, NSError* _Nullable error);
-
 @protocol OTControlProtocol
 - (void)restore:(NSString *)contextID dsid:(NSString *)dsid secret:(NSData*)secret escrowRecordID:(NSString*)escrowRecordID reply:(void (^)(NSData* _Nullable signingKeyData, NSData* _Nullable encryptionKeyData, NSError * _Nullable error))reply;
 - (void)octagonEncryptionPublicKey:(void (^)(NSData* _Nullable encryptionKey, NSError * _Nullable))reply;
@@ -185,10 +183,6 @@ typedef void (^OTNextJoinCompleteBlock)(BOOL finished, NSData* _Nullable message
 skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
               reply:(void (^)(NSError *_Nullable error))reply;
 
-- (void)attemptSosUpgrade:(NSString* _Nullable)container
-                  context:(NSString*)context
-                    reply:(void (^)(NSError* _Nullable error))reply;
-
 - (void)waitForOctagonUpgrade:(NSString* _Nullable)container
                       context:(NSString*)context
                         reply:(void (^)(NSError* _Nullable error))reply;
@@ -217,6 +211,25 @@ skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
            contextID:(NSString*)contextID
                reply:(void (^)(OTCDPStatus status, NSError* _Nullable error))reply;
 
+- (void)fetchEscrowRecords:(NSString * _Nullable)container
+                 contextID:(NSString*)contextID
+                forceFetch:(BOOL)forceFetch
+                     reply:(void (^)(NSArray<NSData*>* _Nullable records,
+                                     NSError* _Nullable error))reply;
+
+- (void)invalidateEscrowCache:(NSString * _Nullable)containerName
+                    contextID:(NSString*)contextID
+                        reply:(nonnull void (^)(NSError * _Nullable error))reply;
+
+/* View Handling */
+- (void)setUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                 contextID:(NSString*)contextID
+                                   enabled:(BOOL)enabled
+                                     reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply;
+
+- (void)fetchUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                   contextID:(NSString*)contextID
+                                       reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply;
 @end
 
 NSXPCInterface* OTSetupControlProtocol(NSXPCInterface* interface);
index 9c0df1987c201f7d01d891b60c807e468acd4dfb..d0ab951a3adb9a9ec9d31a13737511f518b17925 100644 (file)
 #import "keychain/ot/OTControlProtocol.h"
 #import "keychain/ot/OTJoiningConfiguration.h"
 #import <Security/SecXPCHelper.h>
-
-#if OCTAGON
-#import <CloudKit/CloudKit.h>
-#import <CloudKit/CloudKit_Private.h>
-#import <utilities/debugging.h>
-#include <dlfcn.h>
-#import <KeychainCircle/KeychainCircle.h>
-#import <SecurityFoundation/SFKey.h>
-#endif // OCTAGON
-
+#include <utilities/debugging.h>
 
 NSXPCInterface* OTSetupControlProtocol(NSXPCInterface* interface) {
 #if OCTAGON
     NSSet<Class> *errorClasses = [SecXPCHelper safeErrorClasses];
 
     @try {
-        [interface setClasses:errorClasses forSelector:@selector(restore:dsid:secret:escrowRecordID:reply:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(octagonEncryptionPublicKey:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(octagonSigningPublicKey:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(listOfEligibleBottledPeerRecords:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(signOut:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(restore:dsid:secret:escrowRecordID:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(octagonEncryptionPublicKey:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(octagonSigningPublicKey:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(listOfEligibleBottledPeerRecords:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(signIn:container:context:reply:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(reset:) argumentIndex:0 ofReply:YES];
-
+        [interface setClasses:errorClasses forSelector:@selector(signOut:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(notifyIDMSTrustLevelChangeForContainer:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(reset:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(handleIdentityChangeForSigningKey:ForEncryptionKey:ForPeerID:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(rpcEpochWithConfiguration:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(rpcPrepareIdentityAsApplicantWithConfiguration:reply:) argumentIndex:5 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(rpcVoucherWithConfiguration:peerID:permanentInfo:permanentInfoSig:stableInfo:stableInfoSig:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(rpcJoinWithConfiguration:vouchData:vouchSig:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(preflightBottledPeer:dsid:reply:) argumentIndex:3 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(launchBottledPeer:bottleID:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(scrubBottledPeer:bottleID:reply:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(handleIdentityChangeForSigningKey:ForEncryptionKey:ForPeerID:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(status:context:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(fetchEgoPeerID:context:reply:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(fetchCliqueStatus:context:configuration:reply:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(fetchTrustStatus:context:configuration:reply:) argumentIndex:4 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(fetchEscrowContents:contextID:reply:) argumentIndex:3 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(startOctagonStateMachine:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(resetAndEstablish:context:altDSID:resetReason:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(establish:context:altDSID:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(leaveClique:context:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(removeFriendsInClique:context:peerIDs:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(peerDeviceNamesByPeerID:context:reply:) argumentIndex:1 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(fetchAllViableBottles:context:reply:) argumentIndex:2 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(restore:contextID:bottleSalt:entropy:bottleID:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(fetchEscrowContents:contextID:reply:) argumentIndex:3 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(createRecoveryKey:contextID:recoveryKey:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(joinWithRecoveryKey:contextID:recoveryKey:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(healthCheck:context:skipRateLimitingCheck:reply:) argumentIndex:0 ofReply:YES];
-        [interface setClasses:errorClasses forSelector:@selector(attemptSosUpgrade:context:reply:) argumentIndex:0 ofReply:YES];
         [interface setClasses:errorClasses forSelector:@selector(waitForOctagonUpgrade:context:reply:) argumentIndex:0 ofReply:YES];
         [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__
-
-        [interface setClasses:errorClasses
-                  forSelector:@selector(rpcEpochWithConfiguration:reply:)
-                argumentIndex:1
-                      ofReply:YES];
-        [interface setClasses:errorClasses
-                  forSelector:@selector(rpcPrepareIdentityAsApplicantWithConfiguration:reply:)
-                argumentIndex:5
-                      ofReply:YES];
-        [interface setClasses:errorClasses
-                  forSelector:@selector(rpcVoucherWithConfiguration:peerID:permanentInfo:permanentInfoSig:stableInfo:stableInfoSig:reply:)
-                argumentIndex:2
-                      ofReply:YES];
-        [interface setClasses:errorClasses
-                  forSelector:@selector(rpcJoinWithConfiguration:vouchData:vouchSig:reply:)
-                argumentIndex:0
-                      ofReply:YES];
-#endif /* __OBJC2__ */
+        [interface setClasses:errorClasses forSelector:@selector(refetchCKKSPolicy:contextID:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(setCDPEnabled:contextID:reply:) argumentIndex:0 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(getCDPStatus:contextID:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(fetchEscrowRecords:contextID:forceFetch:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(setUserControllableViewsSyncStatus:contextID:enabled:reply:) argumentIndex:1 ofReply:YES];
+        [interface setClasses:errorClasses forSelector:@selector(fetchUserControllableViewsSyncStatus:contextID:reply:) argumentIndex:1 ofReply:YES];
     }
     @catch(NSException* e) {
         secerror("OTSetupControlProtocol failed, continuing, but you might crash later: %@", e);
-#if DEBUG
         @throw e;
-#endif
     }
 #endif
     
index abdb5e32f6a3cbbcc737e2c045de8434b9476b7a..6267d27f8db35a8865ddcc1db519dc95fd19720c 100644 (file)
@@ -34,8 +34,6 @@ NS_ASSUME_NONNULL_BEGIN
 - (BOOL)persistNewTrustState:(OTAccountMetadataClassC_TrustState)newState
                        error:(NSError**)error;
 
-- (BOOL)persistNewEpoch:(uint64_t)epoch error:(NSError**)error;
-
 - (BOOL)persistAccountChanges:(OTAccountMetadataClassC* _Nullable (^)(OTAccountMetadataClassC* metadata))makeChanges
                         error:(NSError**)error;
 
@@ -45,7 +43,6 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSDate *)lastHealthCheckupDate:(NSError * _Nullable *)error;
 - (BOOL)persistLastHealthCheck:(NSDate*)lastCheck error:(NSError**)error;
 
-- (OTAccountMetadataClassC_AttemptedAJoinState)fetchPersistedJoinAttempt:(NSError * _Nullable *)error;
 - (BOOL)persistOctagonJoinAttempt:(OTAccountMetadataClassC_AttemptedAJoinState)attempt error:(NSError**)error;
 
 @end
index b6d596d12e3923cc63593e5a57ac2a0a19409173..5b9ea18aa988f978de841d9777d30054187133b0 100644 (file)
     return current.peerID;
 }
 
-- (OTAccountMetadataClassC_AttemptedAJoinState)fetchPersistedJoinAttempt:(NSError * _Nullable *)error {
-    NSError* localError = nil;
-    OTAccountMetadataClassC* current = [self loadOrCreateAccountMetadata:&localError];
-
-    if(localError || !current) {
-        if(error) {
-            *error = localError;
-        }
-        return OTAccountMetadataClassC_AttemptedAJoinState_UNKNOWN;
-    }
-    return current.attemptedJoin;
-}
-
 - (NSDate *)lastHealthCheckupDate:(NSError * _Nullable *)error {
     NSError* localError = nil;
 
     } error:error];
 }
 
-- (BOOL)persistNewAccountState:(OTAccountMetadataClassC_AccountState)newState
-               optionalAltDSID:(NSString* _Nullable)altDSID
-                         error:(NSError**)error
-{
-    return [self persistAccountChanges:^(OTAccountMetadataClassC *metadata) {
-        metadata.icloudAccountState = newState;
-        metadata.altDSID = altDSID;
-        return metadata;
-    } error:error];
-}
-
-- (BOOL)persistNewEpoch:(uint64_t)epoch
-                  error:(NSError**)error
-{
-    return [self persistAccountChanges:^(OTAccountMetadataClassC *metadata) {
-        metadata.epoch = epoch;
-        return metadata;
-    } error:error];
-}
-
 - (BOOL)persistAccountChanges:(OTAccountMetadataClassC* _Nullable (^)(OTAccountMetadataClassC*))makeChanges
                         error:(NSError**)error
 {
     });
 }
 
-
 @end
index 714b7013b4eeaf7010684d673e77f676d4510739..828662e4240bb460319e65682ac2ab3589c48358 100644 (file)
@@ -159,9 +159,17 @@ NS_ASSUME_NONNULL_BEGIN
                                  NSString* _Nullable peerID,
                                  NSDictionary<NSString*, NSNumber*>* _Nullable peerCountByModelID,
                                  BOOL isExcluded,
+                                 BOOL isLocked,
                                  NSError * _Nullable))reply;
 - (void)rpcFetchDeviceNamesByPeerID:(void (^)(NSDictionary<NSString*, NSString*>* _Nullable peers, NSError* _Nullable error))reply;
-- (void)rpcFetchAllViableBottles:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs, NSArray<NSString*>* _Nullable sortedPartialEscrowRecordIDs, NSError* _Nullable error))reply;
+- (void)rpcFetchAllViableBottles:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs,
+                                           NSArray<NSString*>* _Nullable sortedPartialEscrowRecordIDs,
+                                           NSError* _Nullable error))reply;
+
+- (void)rpcFetchAllViableEscrowRecords:(BOOL)forceFetch reply:(void (^)(NSArray<NSData*>* _Nullable records,
+                                                                        NSError* _Nullable error))reply;
+- (void)rpcInvalidateEscrowCache:(void (^)(NSError* _Nullable error))reply;
+
 - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy,
                                       NSString* _Nullable bottleID,
                                       NSData* _Nullable signingPublicKey,
@@ -170,6 +178,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (void)rpcRefetchCKKSPolicy:(void (^)(NSError * _Nullable error))reply;
 
+- (void)rpcFetchUserControllableViewsSyncingStatus:(void (^)(BOOL areSyncing, NSError* _Nullable error))reply;
+- (void)rpcSetUserControllableViewsSyncingStatus:(BOOL)status reply:(void (^)(BOOL areSyncing, NSError* _Nullable error))reply;
+
 - (void)requestTrustedDeviceListRefresh;
 
 - (OTDeviceInformation*)prepareInformation;
@@ -179,19 +190,15 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (OTOperationDependencies*)operationDependencies;
 
-- (void)attemptSOSUpgrade:(void (^)(NSError* _Nullable error))reply;
-
 - (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply NS_SWIFT_NAME(waitForOctagonUpgrade(reply:));
 
 - (BOOL)waitForReady:(int64_t)timeOffset;
 
-
 // For testing.
 - (OTAccountMetadataClassC_AccountState)currentMemoizedAccountState;
 - (OTAccountMetadataClassC_TrustState)currentMemoizedTrustState;
 - (NSDate* _Nullable) currentMemoizedLastHealthCheck;
-- (void) checkTrustStatusAndPostRepairCFUIfNecessary:(void (^ _Nullable)(CliqueStatus status, BOOL posted, BOOL hasIdentity, NSError * _Nullable error))reply;
-- (void) setAccountStateHolder:(OTCuttlefishAccountStateHolder*)accountMetadataStore;
+- (void)checkTrustStatusAndPostRepairCFUIfNecessary:(void (^ _Nullable)(CliqueStatus status, BOOL posted, BOOL hasIdentity, BOOL isLocked, NSError * _Nullable error))reply;
 
 - (void)clearCKKSViewManager;
 
@@ -199,8 +206,6 @@ NS_ASSUME_NONNULL_BEGIN
 
 // Octagon Health Check Helpers
 - (void)checkOctagonHealth:(BOOL)skipRateLimitingCheck reply:(void (^)(NSError * _Nullable error))reply;
-- (BOOL)postRepairCFU:(NSError**)error;
-- (void)postConfirmPasscodeCFU:(NSError**)error;
 
 // For reporting
 - (BOOL)machineIDOnMemoizedList:(NSString*)machineID error:(NSError**)error NS_SWIFT_NOTHROW;
index a4e5c8fcf7b35ccae2a3149d908d021fac12ccf6..a5e52ed41d2ea8c879df6aa86c7f72e0ed17b3dc 100644 (file)
@@ -33,6 +33,7 @@
 
 
 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
+#include "keychain/SecureObjectSync/SOSInternal.h"
 
 #import "keychain/analytics/CKKSLaunchSequence.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
@@ -56,6 +57,7 @@
 #import "keychain/ot/OTDetermineHSA2AccountStatusOperation.h"
 #import "keychain/ot/OTDeviceInformationAdapter.h"
 #import "keychain/ot/OTEnsureOctagonKeyConsistency.h"
+#import "keychain/ot/OTPreloadOctagonKeysOperation.h"
 #import "keychain/ot/OTEpochOperation.h"
 #import "keychain/ot/OTEstablishOperation.h"
 #import "keychain/ot/OTFetchViewsOperation.h"
@@ -64,6 +66,7 @@
 #import "keychain/ot/OTLeaveCliqueOperation.h"
 #import "keychain/ot/OTLocalCKKSResetOperation.h"
 #import "keychain/ot/OTLocalCuttlefishReset.h"
+#import "keychain/ot/OTModifyUserControllableViewStatusOperation.h"
 #import "keychain/ot/OTOperationDependencies.h"
 #import "keychain/ot/OTPrepareOperation.h"
 #import "keychain/ot/OTRemovePeersOperation.h"
@@ -107,8 +110,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
 @interface OTCuttlefishContext () <OTCuttlefishAccountStateHolderNotifier>
 {
-    NSData* _vouchData;
-    NSData* _vouchSig;
     NSString* _bottleID;
     NSString* _bottleSalt;
     NSData* _entropy;
@@ -127,6 +128,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 @property CKKSCondition *cloudKitAccountStateKnown;
 
 @property CKKSNearFutureScheduler* suggestTLKUploadNotifier;
+@property CKKSNearFutureScheduler* requestPolicyCheckNotifier;
+
+@property OctagonAPSReceiver* apsReceiver;
 
 // Make writable
 @property (nullable) CKKSViewManager* viewManager;
@@ -134,7 +138,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 // Dependencies (for injection)
 @property id<OTSOSAdapter> sosAdapter;
 @property id<CKKSPeerProvider> octagonAdapter;
-@property (readonly) Class<OctagonAPSConnection> apsConnectionClass;
 @property (readonly) Class<SecEscrowRequestable> escrowRequestClass;
 
 @property (nonatomic) BOOL initialBecomeUntrustedPosted;
@@ -162,11 +165,14 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         _containerName = containerName;
         _contextID = contextID;
 
+        _apsReceiver = [OctagonAPSReceiver receiverForNamedDelegatePort:SecCKKSAPSNamedPort
+                                                     apsConnectionClass:apsConnectionClass];
+        [_apsReceiver registerCuttlefishReceiver:self forContainerName:self.containerName];
+
         _viewManager = viewManager;
 
         _initialBecomeUntrustedPosted = NO;
 
-        _apsConnectionClass = apsConnectionClass;
         _launchSequence = [[CKKSLaunchSequence alloc] initWithRocketName:@"com.apple.octagon.launch"];
 
         _queue = dispatch_queue_create("com.apple.security.otcuttlefishcontext", DISPATCH_QUEUE_SERIAL);
@@ -212,6 +218,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                                                 secnotice("octagon-ckks", "Adding flag for CKKS TLK upload");
                                                                                 [self.stateMachine handleFlag:OctagonFlagCKKSRequestsTLKUpload];
                                                                             }];
+
+        _requestPolicyCheckNotifier = [[CKKSNearFutureScheduler alloc] initWithName:@"octagon-policy-check"
+                                                                              delay:500*NSEC_PER_MSEC
+                                                                   keepProcessAlive:false
+                                                          dependencyDescriptionCode:0 block:^{
+            STRONGIFY(self);
+            secnotice("octagon-ckks", "Adding flag for CKKS policy check");
+            [self.stateMachine handleFlag:OctagonFlagCKKSRequestsPolicyCheck];
+        }];
     }
     return self;
 }
@@ -398,7 +413,11 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     }
 
     [self.stateMachine handleFlag:OctagonFlagAccountIsAvailable];
-    
+
+    if(OctagonIsOptimizationEnabled()){
+        [self.stateMachine handleFlag:OctagonFlagWarmEscrowRecordCache];
+    }
+
     if(localError) {
         if(error) {
             *error = localError;
@@ -547,11 +566,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
 - (void)localReset:(nonnull void (^)(NSError * _Nullable))reply
 {
-    OTLocalResetOperation* pendingOp = [[OTLocalResetOperation alloc] init:self.containerName
-                                                       contextID:self.contextID
-                                                   intendedState:OctagonStateBecomeUntrusted
-                                                      errorState:OctagonStateError
-                                                   cuttlefishXPCWrapper:self.cuttlefishXPCWrapper];
+    OTLocalResetOperation* pendingOp = [[OTLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                                             intendedState:OctagonStateInitializing
+                                                                                errorState:OctagonStateError];
 
     NSMutableSet* sourceStates = [NSMutableSet setWithArray: OctagonStateMap().allKeys];
     [self.stateMachine doSimpleStateMachineRPC:@"local-reset" op:pendingOp sourceStates:sourceStates reply:reply];
@@ -715,8 +732,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 {
     dispatch_assert_queue(self.queue);
 
-    WEAKIFY(self);
-
     [self.launchSequence addEvent:currentState];
 
     // If We're initializing, or there was some recent update to the account state,
@@ -749,7 +764,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     }
 
     if([currentState isEqualToString:OctagonStateCloudKitNewlyAvailable]) {
-        return [self cloudKitAccountNewlyAvailableOperation];
+        OctagonFlag* warmEscrowCache = nil;
+        if([flags _onqueueContains:OctagonFlagWarmEscrowRecordCache] && OctagonIsOptimizationEnabled()) {
+            [flags _onqueueRemoveFlag:OctagonFlagWarmEscrowRecordCache];
+            warmEscrowCache = OctagonFlagWarmEscrowRecordCache;
+        }
+        return [self cloudKitAccountNewlyAvailableOperation:warmEscrowCache];
     }
 
     if([currentState isEqualToString:OctagonStateDetermineCDPState]) {
@@ -848,6 +868,31 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                      intendedState:OctagonStateBecomeReady
                                                         errorState:OctagonStateError];
     }
+
+    if([currentState isEqualToString:OctagonStateEnableUserControllableViews]) {
+        return [[OTModifyUserControllableViewStatusOperation alloc] initWithDependencies:self.operationDependencies
+                                                                      intendedViewStatus:TPPBPeerStableInfo_UserControllableViewStatus_ENABLED
+                                                                           intendedState:OctagonStateBecomeReady
+                                                                        peerMissingState:OctagonStateReadyUpdated
+                                                                                errorState:OctagonStateBecomeReady];
+    }
+
+    if([currentState isEqualToString:OctagonStateDisableUserControllableViews]) {
+        return [[OTModifyUserControllableViewStatusOperation alloc] initWithDependencies:self.operationDependencies
+                                                                      intendedViewStatus:TPPBPeerStableInfo_UserControllableViewStatus_DISABLED
+                                                                           intendedState:OctagonStateBecomeReady
+                                                                        peerMissingState:OctagonStateReadyUpdated
+                                                                              errorState:OctagonStateBecomeReady];
+    }
+
+    if([currentState isEqualToString:OctagonStateSetUserControllableViewsToPeerConsensus]) {
+        // Setting the status to FOLLOWING will either enable or disable the value, depending on our peers.
+        return [[OTModifyUserControllableViewStatusOperation alloc] initWithDependencies:self.operationDependencies
+                                                                      intendedViewStatus:TPPBPeerStableInfo_UserControllableViewStatus_FOLLOWING
+                                                                           intendedState:OctagonStateBecomeReady
+                                                                        peerMissingState:OctagonStateReadyUpdated
+                                                                              errorState:OctagonStateBecomeReady];
+    }
     
     if([currentState isEqualToString:OctagonStateNoAccount]) {
         // We only want to move out of untrusted if something useful has happened!
@@ -885,6 +930,17 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
             }
         }
 
+        if([flags _onqueueContains:OctagonFlagAttemptSOSConsistency]) {
+            [flags _onqueueRemoveFlag:OctagonFlagAttemptSOSConsistency];
+            if(self.sosAdapter.sosEnabled) {
+                secnotice("octagon", "Attempting SOS upgrade again (due to a consistency notification)");
+                return [OctagonStateTransitionOperation named:@"attempt-sos-upgrade"
+                                                     entering:OctagonStateAttemptSOSUpgrade];
+            } else {
+                secnotice("octagon", "Someone would like us to check SOS consistency, but this platform doesn't support SOS.");
+            }
+        }
+
         if([flags _onqueueContains:OctagonFlagCuttlefishNotification]) {
             [flags _onqueueRemoveFlag:OctagonFlagCuttlefishNotification];
             secnotice("octagon", "Updating TPH (while untrusted) due to push");
@@ -915,69 +971,19 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     if([currentState isEqualToString:OctagonStateDetermineiCloudAccountState]) {
         secnotice("octagon", "Determine iCloud account status");
 
-        // TODO replace with OTDetermineHSA2AccountStatusOperation in <rdar://problem/54094162> Octagon: ensure Octagon operations can't occur on SA accounts
-        return [OctagonStateTransitionOperation named:@"octagon-determine-icloud-state"
-                                            intending:OctagonStateNoAccount
-                                           errorState:OctagonStateError
-                                  withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
-            STRONGIFY(self);
-
-            NSError *authKitError = nil;
-            NSString* primaryAccountAltDSID = [self.authKitAdapter primaryiCloudAccountAltDSID:&authKitError];
-
-            dispatch_sync(self.queue, ^{
-                NSError* error = nil;
-
-                if(primaryAccountAltDSID != nil) {
-                    secnotice("octagon", "iCloud account is present; checking HSA2 status");
-
-                    bool hsa2 = [self.authKitAdapter accountIsHSA2ByAltDSID:primaryAccountAltDSID];
-                    secnotice("octagon", "HSA2 is %@", hsa2 ? @"enabled" : @"disabled");
-
-                    [self.accountMetadataStore _onqueuePersistAccountChanges:^OTAccountMetadataClassC *(OTAccountMetadataClassC * metadata) {
-                        if(hsa2) {
-                            metadata.icloudAccountState = OTAccountMetadataClassC_AccountState_ACCOUNT_AVAILABLE;
-                        } else {
-                            metadata.icloudAccountState = OTAccountMetadataClassC_AccountState_NO_ACCOUNT;
-                        }
-                        metadata.altDSID = primaryAccountAltDSID;
-                        return metadata;
-                    } error:&error];
-
-                    // If there's an HSA2 account, return to 'initializing' here, as we want to centralize decisions on what to do next
-                    if(hsa2) {
-                        op.nextState = OctagonStateInitializing;
-                    } else {
-                        [self.accountStateTracker setHSA2iCloudAccountStatus:CKKSAccountStatusNoAccount];
-                        op.nextState = OctagonStateWaitForHSA2;
-                    }
-
-                } else {
-                    secnotice("octagon", "iCloud account is not present: %@", authKitError);
-
-                    [self.accountMetadataStore _onqueuePersistAccountChanges:^OTAccountMetadataClassC *(OTAccountMetadataClassC * metadata) {
-                        metadata.icloudAccountState = OTAccountMetadataClassC_AccountState_NO_ACCOUNT;
-                        metadata.altDSID = nil;
-                        return metadata;
-                    } error:&error];
-
-                    op.nextState = OctagonStateNoAccount;
-                }
-
-                if(error) {
-                    secerror("octagon: unable to save new account state: %@", error);
-                }
-            });
-        }];
+        // If there's an HSA2 account, return to 'initializing' here, as we want to centralize decisions on what to do next
+        return [[OTDetermineHSA2AccountStatusOperation alloc] initWithDependencies:self.operationDependencies
+                                                                       stateIfHSA2:OctagonStateInitializing
+                                                                    stateIfNotHSA2:OctagonStateWaitForHSA2
+                                                                  stateIfNoAccount:OctagonStateNoAccount
+                                                                        errorState:OctagonStateError];
     }
 
     if([currentState isEqualToString:OctagonStateNoAccountDoReset]) {
         secnotice("octagon", "Attempting local-reset as part of signout");
-        return [[OTLocalResetOperation alloc] init:self.containerName
-                                         contextID:self.contextID
-                                     intendedState:OctagonStateNoAccount
-                                        errorState:OctagonStateNoAccount
-                              cuttlefishXPCWrapper:self.cuttlefishXPCWrapper];
+        return [[OTLocalResetOperation alloc] initWithDependencies:self.operationDependencies
+                                                     intendedState:OctagonStateNoAccount
+                                                        errorState:OctagonStateNoAccount];
     }
 
     if([currentState isEqualToString:OctagonStateEnsureConsistency]) {
@@ -993,6 +999,18 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                              entering:OctagonStateBecomeReady];
     }
 
+    if([currentState isEqualToString:OctagonStateBottlePreloadOctagonKeysInSOS]) {
+        secnotice("octagon", "Preloading Octagon Keys on the SOS Account");
+        if(self.sosAdapter.sosEnabled) {
+            return [[OTPreloadOctagonKeysOperation alloc] initWithDependencies:self.operationDependencies
+                                                                 intendedState:OctagonStateBecomeReady
+                                                                    errorState:OctagonStateBecomeReady];
+        }
+        // Add further consistency checks here.
+        return [OctagonStateTransitionOperation named:@"no-preload-octagon-key"
+                                             entering:OctagonStateBecomeReady];
+    }
+
     if([currentState isEqualToString:OctagonStateEnsureUpdatePreapprovals]) {
         secnotice("octagon", "SOS is enabled; ensuring preapprovals are correct");
         return [[OTSOSUpdatePreapprovalsOperation alloc] initWithDependencies:self.operationDependencies
@@ -1001,6 +1019,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                                    errorState:OctagonStateBecomeReady];
     }
 
+    if([currentState isEqualToString:OctagonStateAttemptSOSUpgradeDetermineCDPState]) {
+        return [[OTDetermineCDPBitStatusOperation alloc] initWithDependencies:self.operationDependencies
+                                                                intendedState:OctagonStateAttemptSOSUpgrade
+                                                                   errorState:OctagonStateWaitForCDP];
+    }
+
     if([currentState isEqualToString:OctagonStateAttemptSOSUpgrade] && OctagonPerformSOSUpgrade()) {
         secnotice("octagon", "Investigating SOS status");
         return [[OTSOSUpgradeOperation alloc] initWithDependencies:self.operationDependencies
@@ -1041,43 +1065,20 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                           epoch:1];
 
     } else if([currentState isEqualToString:OctagonStateBottleJoinVouchWithBottle]) {
-        // <rdar://problem/57768490> Octagon: ensure we use appropriate CKKS policy when joining octagon with future policy
-        // When we join with a bottle, we need to be sure that we've found all the TLKShares that we can reasonably unpack via the bottle
-
-        OTVouchWithBottleOperation* pendingOp  = [[OTVouchWithBottleOperation alloc] initWithDependencies:self.operationDependencies
-                                                                                            intendedState:OctagonStateInitiatorSetCDPBit
-                                                                                               errorState:OctagonStateBecomeUntrusted
-                                                                                                 bottleID:_bottleID
-                                                                                                  entropy:_entropy
-                                                                                               bottleSalt:_bottleSalt];
-
-        CKKSResultOperation* callback = [CKKSResultOperation named:@"vouchWithBottle-callback"
-                                                         withBlock:^{
-                                                             secnotice("otrpc", "Returning a vouch with bottle call: %@, %@  %@", pendingOp.voucher, pendingOp.voucherSig, pendingOp.error);
-                                                             self->_vouchSig = pendingOp.voucherSig;
-                                                             self->_vouchData = pendingOp.voucher;
-                                                         }];
-        [callback addDependency:pendingOp];
-        [self.operationQueue addOperation: callback];
-
-        return pendingOp;
+        return [[OTVouchWithBottleOperation alloc] initWithDependencies:self.operationDependencies
+                                                          intendedState:OctagonStateInitiatorSetCDPBit
+                                                             errorState:OctagonStateBecomeUntrusted
+                                                               bottleID:_bottleID
+                                                                entropy:_entropy
+                                                             bottleSalt:_bottleSalt
+                                                            saveVoucher:YES];
 
     } else if([currentState isEqualToString:OctagonStateVouchWithRecoveryKey]) {
-        OTVouchWithRecoveryKeyOperation* pendingOp  = [[OTVouchWithRecoveryKeyOperation alloc] initWithDependencies:self.operationDependencies
-                                                                                            intendedState:OctagonStateInitiatorSetCDPBit
-                                                                                               errorState:OctagonStateBecomeUntrusted
-                                                                                                 recoveryKey:_recoveryKey];
-
-        CKKSResultOperation* callback = [CKKSResultOperation named:@"vouchWithRecoveryKey-callback"
-                                                         withBlock:^{
-                                                             secnotice("otrpc", "Returning a vouch with recovery key call: %@, %@  %@", pendingOp.voucher, pendingOp.voucherSig, pendingOp.error);
-                                                             self->_vouchSig = pendingOp.voucherSig;
-                                                             self->_vouchData = pendingOp.voucher;
-                                                         }];
-        [callback addDependency:pendingOp];
-        [self.operationQueue addOperation: callback];
-
-        return pendingOp;
+        return [[OTVouchWithRecoveryKeyOperation alloc] initWithDependencies:self.operationDependencies
+                                                               intendedState:OctagonStateInitiatorSetCDPBit
+                                                                  errorState:OctagonStateBecomeUntrusted
+                                                                 recoveryKey:_recoveryKey
+                                                                 saveVoucher:YES];
 
     } else if([currentState isEqualToString:OctagonStateInitiatorSetCDPBit]) {
         return [[OTSetCDPBitOperation alloc] initWithDependencies:self.operationDependencies
@@ -1094,13 +1095,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         return op;
 
     } else if ([currentState isEqualToString:OctagonStateInitiatorJoin]){
-        OTJoinWithVoucherOperation* op  = [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies
-                                                                                     intendedState:OctagonStateBecomeReady
-                                                                                 ckksConflictState:OctagonStateInitiatorJoinCKKSReset
-                                                                                        errorState:OctagonStateBecomeUntrusted
-                                                                                       voucherData:_vouchData
-                                                                                        voucherSig:_vouchSig];
-        return op;
+       return [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies
+                                                         intendedState:OctagonStateBottlePreloadOctagonKeysInSOS
+                                                     ckksConflictState:OctagonStateInitiatorJoinCKKSReset
+                                                            errorState:OctagonStateBecomeUntrusted];
 
     } else if([currentState isEqualToString:OctagonStateInitiatorJoinCKKSReset]) {
         return [[OTLocalCKKSResetOperation alloc] initWithDependencies:self.operationDependencies
@@ -1109,11 +1107,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
     } else if ([currentState isEqualToString:OctagonStateInitiatorJoinAfterCKKSReset]){
         return [[OTJoinWithVoucherOperation alloc] initWithDependencies:self.operationDependencies
-                                                          intendedState:OctagonStateBecomeReady
+                                                          intendedState:OctagonStateBottlePreloadOctagonKeysInSOS
                                                       ckksConflictState:OctagonStateBecomeUntrusted
-                                                             errorState:OctagonStateBecomeUntrusted
-                                                            voucherData:_vouchData
-                                                             voucherSig:_vouchSig];
+                                                             errorState:OctagonStateBecomeUntrusted];
 
     } else if([currentState isEqualToString:OctagonStateResetBecomeUntrusted]) {
         return [self becomeUntrustedOperation:OctagonStateResetAndEstablish];
@@ -1128,8 +1124,8 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
     } else if([currentState isEqualToString:OctagonStateResetAnyMissingTLKCKKSViews]) {
         return [[OTResetCKKSZonesLackingTLKsOperation alloc] initWithDependencies:self.operationDependencies
-                                                           intendedState:OctagonStateEstablishEnableCDPBit
-                                                              errorState:OctagonStateError];
+                                                                    intendedState:OctagonStateEstablishEnableCDPBit
+                                                                       errorState:OctagonStateError];
 
     } else if([currentState isEqualToString:OctagonStateEstablishEnableCDPBit]) {
         return [[OTSetCDPBitOperation alloc] initWithDependencies:self.operationDependencies
@@ -1181,6 +1177,17 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                       intendedState: OctagonStateBecomeUntrusted
                                                          errorState: OctagonStateBecomeUntrusted];
 
+    } else if([currentState isEqualToString:OctagonStateWaitForClassCUnlock]) {
+        if([flags _onqueueContains:OctagonFlagUnlocked]) {
+            [flags _onqueueRemoveFlag:OctagonFlagUnlocked];
+            return [OctagonStateTransitionOperation named:[NSString stringWithFormat:@"%@", @"initializing-after-initial-unlock"]
+                                                 entering:OctagonStateInitializing];
+        }
+
+        [pendingFlagHandler _onqueueHandlePendingFlag:[[OctagonPendingFlag alloc] initWithFlag:OctagonFlagUnlocked
+                                                                                    conditions:OctagonPendingConditionsDeviceUnlocked]];
+        return nil;
+
     } else if([currentState isEqualToString: OctagonStateWaitForUnlock]) {
         if([flags _onqueueContains:OctagonFlagUnlocked]) {
             [flags _onqueueRemoveFlag:OctagonFlagUnlocked];
@@ -1206,6 +1213,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies
                                                             intendedState:OctagonStateReady
                                                         ckksConflictState:OctagonStateAssistCKKSTLKUploadCKKSReset
+                                                         peerMissingState:OctagonStateReadyUpdated
                                                                errorState:OctagonStateReady];
 
     } else if([currentState isEqualToString:OctagonStateAssistCKKSTLKUploadCKKSReset]) {
@@ -1218,20 +1226,51 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         return [[OTUploadNewCKKSTLKsOperation alloc] initWithDependencies:self.operationDependencies
                                                             intendedState:OctagonStateReady
                                                         ckksConflictState:OctagonStateReady
+                                                         peerMissingState:OctagonStateReadyUpdated
                                                                errorState:OctagonStateReady];
 
     } else if([currentState isEqualToString:OctagonStateReady]) {
+        if([flags _onqueueContains:OctagonFlagCuttlefishNotification]) {
+            [flags _onqueueRemoveFlag:OctagonFlagCuttlefishNotification];
+            secnotice("octagon", "Updating TPH (while ready) due to push");
+            return [OctagonStateTransitionOperation named:@"octagon-update"
+                                                 entering:OctagonStateReadyUpdated];
+        }
+
         if([flags _onqueueContains:OctagonFlagCKKSRequestsTLKUpload]) {
             [flags _onqueueRemoveFlag:OctagonFlagCKKSRequestsTLKUpload];
             return [OctagonStateTransitionOperation named:@"ckks-assist"
                                                  entering:OctagonStateAssistCKKSTLKUpload];
         }
 
-        if([flags _onqueueContains:OctagonFlagCuttlefishNotification]) {
-            [flags _onqueueRemoveFlag:OctagonFlagCuttlefishNotification];
-            secnotice("octagon", "Updating TPH (while ready) due to push");
-            return [OctagonStateTransitionOperation named:@"octagon-update"
-                                                 entering:OctagonStateReadyUpdated];
+        if([flags _onqueueContains:OctagonFlagAttemptBottleTLKExtraction]) {
+            [flags _onqueueRemoveFlag:OctagonFlagAttemptBottleTLKExtraction];
+            if(_bottleID && _entropy && _bottleSalt) {
+                // Reuse the vouch-with-bottle operation. That'll make us a new voucher, but as a side effect, it will extract TLKs.
+                return [[OTVouchWithBottleOperation alloc] initWithDependencies:self.operationDependencies
+                                                                  intendedState:OctagonStateBecomeReady
+                                                                     errorState:OctagonStateBecomeReady
+                                                                       bottleID:_bottleID
+                                                                        entropy:_entropy
+                                                                     bottleSalt:_bottleSalt
+                                                                    saveVoucher:NO];
+            } else {
+                secnotice("octagon", "Received an suggestion to retry TLK extraction via bottle, but have no entropy stashed");
+            }
+        }
+
+        if([flags _onqueueContains:OctagonFlagAttemptRecoveryKeyTLKExtraction]) {
+            [flags _onqueueRemoveFlag:OctagonFlagAttemptRecoveryKeyTLKExtraction];
+            if(_recoveryKey) {
+                // Reuse the vouch-with-rk operation. That'll make us a new voucher, but as a side effect, it will extract TLKs.
+                return [[OTVouchWithRecoveryKeyOperation alloc] initWithDependencies:self.operationDependencies
+                                                                       intendedState:OctagonStateBecomeReady
+                                                                          errorState:OctagonStateBecomeReady
+                                                                         recoveryKey:_recoveryKey
+                                                                         saveVoucher:NO];
+            } else {
+                secnotice("octagon", "Received an suggestion to retry TLK extraction via RK, but have no recovery key stashed");
+            }
         }
 
         if([flags _onqueueContains:OctagonFlagFetchAuthKitMachineIDList]) {
@@ -1269,6 +1308,27 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
             }
         }
 
+        if([flags _onqueueContains:OctagonFlagAttemptUserControllableViewStatusUpgrade]) {
+            [flags _onqueueRemoveFlag:OctagonFlagAttemptUserControllableViewStatusUpgrade];
+            secnotice("octagon", "Attempting user-view control upgrade");
+            return [OctagonStateTransitionOperation named:@"attempt-user-view-upgrade"
+                                                 entering:OctagonStateSetUserControllableViewsToPeerConsensus];
+        }
+
+        if([flags _onqueueContains:OctagonFlagCKKSRequestsPolicyCheck]) {
+            [flags _onqueueRemoveFlag:OctagonFlagCKKSRequestsPolicyCheck];
+            secnotice("octagon", "Updating CKKS policy");
+            return [OctagonStateTransitionOperation named:@"ckks-policy-update"
+                                                 entering:OctagonStateReadyUpdated];
+        }
+
+        if([flags _onqueueContains:OctagonFlagCKKSViewSetChanged]) {
+            // We want to tell CKKS that we're trusted again.
+            [flags _onqueueRemoveFlag:OctagonFlagCKKSViewSetChanged];
+            return [OctagonStateTransitionOperation named:@"ckks-update-trust"
+                                                 entering:OctagonStateBecomeReady];
+        }
+
         if([flags _onqueueContains:OctagonFlagAccountIsAvailable]) {
             // We're in ready--we already know the account is available
             secnotice("octagon", "Removing 'account is available' flag");
@@ -1287,7 +1347,6 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
             [flags _onqueueRemoveFlag:OctagonFlagCDPEnabled];
         }
 
-        secnotice("octagon", "Entering state ready");
         [[CKKSAnalytics logger] setDateProperty:[NSDate date] forKey:OctagonAnalyticsLastKeystateReady];
         [self.launchSequence launch];
         return nil;
@@ -1319,7 +1378,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                   OTAccountMetadataClassC* account = [self.accountMetadataStore loadOrCreateAccountMetadata:&localError];
                                   if(localError && [self.lockStateTracker isLockedError:localError]){
                                       secnotice("octagon", "Device is locked! pending initialization on unlock");
-                                      op.nextState = OctagonStateWaitForUnlock;
+                                      // Since we can't load a class C item, we go to a different waitforunlock state.
+                                      // That way, we'll be less likely for an RPC to break us.
+                                      op.nextState = OctagonStateWaitForClassCUnlock;
                                       return;
                                   }
 
@@ -1336,6 +1397,20 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                       // This seems an odd place to do this, but CKKS currently also tracks the CloudKit account state.
                                       // Since we think we have an HSA2 account, let CKKS figure out its own CloudKit state
                                       secnotice("octagon-ckks", "Initializing CKKS views");
+                                      [self.cuttlefishXPCWrapper fetchCurrentPolicyWithContainer:self.containerName
+                                                                                         context:self.contextID
+                                                                                 modelIDOverride:self.deviceAdapter.modelID
+                                                                                           reply:^(TPSyncingPolicy * _Nullable syncingPolicy,
+                                                                                                   TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers,
+                                                                                                   NSError * _Nullable policyError) {
+                                          if(!syncingPolicy || policyError) {
+                                              secnotice("octagon-ckks", "Unable to fetch initial syncing policy: %@", policyError);
+                                          } else {
+                                              secnotice("octagon-ckks", "Fetched initial syncing policy: %@", syncingPolicy);
+                                              [self.viewManager setCurrentSyncingPolicy:syncingPolicy];
+                                          }
+                                      }];
+
                                       [self.viewManager createViews];
                                       [self.viewManager beginCloudKitOperationOfAllViews];
 
@@ -1383,7 +1458,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                         intending:OctagonStateCuttlefishTrustCheck
                                        errorState:OctagonStatePostRepairCFU
                               withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
-                                  [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, BOOL hasIdentity, NSError *trustFromTPHError) {
+                                  [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, BOOL hasIdentity, BOOL isLocked, NSError *trustFromTPHError) {
 
                                       [[CKKSAnalytics logger] logResultForEvent:OctagonEventTPHHealthCheckStatus hardFailure:false result:trustFromTPHError];
                                       if(trustFromTPHError) {
@@ -1391,7 +1466,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                           op.error = trustFromTPHError;
                                           op.nextState = OctagonStateError;
                                       } else {
-                                          if(hasIdentity == NO) {
+                                          if (isLocked == YES) {
+                                              op.nextState = OctagonStateWaitForUnlock;
+                                              secnotice("octagon-health", "TPH says device is locked!");
+                                          } else if (hasIdentity == NO) {
                                               op.nextState = OctagonStateUntrusted;
                                           } else if(hasIdentity == YES && status == CliqueStatusIn){
                                               secnotice("octagon-health", "TPH says we're trusted and in");
@@ -1440,8 +1518,8 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                              if(shouldPost) {
                                                                  secnotice("octagon-health", "Posting Escrow CFU");
                                                                  NSError* postEscrowCFUError = nil;
-                                                                 [self postConfirmPasscodeCFU:&postEscrowCFUError];
-                                                                 if(postEscrowCFUError) {
+                                                                 BOOL ret = [self postConfirmPasscodeCFU:&postEscrowCFUError];
+                                                                 if(!ret) {
                                                                      op.error = postEscrowCFUError;
                                                                  }
                                                              } else {
@@ -1468,31 +1546,54 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                         intending:OctagonStateUntrusted
                                        errorState:OctagonStateError
                               withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
+        __block BOOL deviceIsLocked = NO;
         [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status,
                                                             BOOL posted,
                                                             BOOL hasIdentity,
+                                                            BOOL isLocked,
                                                             NSError * _Nullable postError) {
             if(postError) {
                 secerror("ocagon-health: failed to post repair cfu via state machine: %@", postError);
+            } else if (isLocked) {
+                deviceIsLocked = isLocked;
+                secnotice("octagon-health", "device is locked, not posting cfu");
             } else {
                 secnotice("octagon-health", "posted repair cfu via state machine");
             }
         }];
-        op.nextState = OctagonStateUntrusted;
+        if (deviceIsLocked == YES) {
+            op.nextState = OctagonStateWaitForUnlock;
+        } else {
+            op.nextState = OctagonStateUntrusted;
+        }
       }];
 }
 
-- (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)cloudKitAccountNewlyAvailableOperation
+- (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)cloudKitAccountNewlyAvailableOperation:(OctagonFlag*)warmEscrowCache
 {
     WEAKIFY(self);
+
     return [OctagonStateTransitionOperation named:@"octagon-icloud-account-available"
                                         intending:OctagonStateDetermineCDPState
                                        errorState:OctagonStateError
                               withBlockTakingSelf:^(OctagonStateTransitionOperation * _Nonnull op) {
                                   STRONGIFY(self);
-                                  // Register with APS, but don't bother to wait until it's complete.
                                   secnotice("octagon", "iCloud sign in occurred. Attemping to register with APS...");
-
+                                  // Check if escrow fetch flag is set to warm up the escrow cache
+                                  if(warmEscrowCache != nil && OctagonIsOptimizationEnabled()) {
+                                      secnotice("octagon-warm-escrowcache", "Beginning fetching escrow records to warm up the escrow cache in TPH");
+                                      dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
+                                          STRONGIFY(self);
+                                          [self rpcFetchAllViableEscrowRecords:NO reply:^(NSArray<NSData *> *records, NSError *error) {
+                                              if(error){
+                                                  secerror("octagon-warm-escrowcache: failed to fetch escrow records, %@", error);
+                                              } else {
+                                                  secnotice("octagon-warm-escrowcache", "Successfully fetched escrow records");
+                                              }
+                                          }];
+                                      });
+                                  }
+                                  // Register with APS, but don't bother to wait until it's complete.
                                   CKContainer* ckContainer = [CKContainer containerWithIdentifier:self.containerName];
                                   [ckContainer serverPreferredPushEnvironmentWithCompletionHandler: ^(NSString *apsPushEnvString, NSError *error) {
                                       STRONGIFY(self);
@@ -1507,10 +1608,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                       } else {
                                           secnotice("octagonpush", "Registering for environment '%@'", apsPushEnvString);
 
-                                          OctagonAPSReceiver* aps = [OctagonAPSReceiver receiverForEnvironment:apsPushEnvString
-                                                                                             namedDelegatePort:SecCKKSAPSNamedPort
-                                                                                            apsConnectionClass:self.apsConnectionClass];
-                                          [aps registerCuttlefishReceiver:self forContainerName:self.containerName];
+                                          [self.apsReceiver registerForEnvironment:apsPushEnvString];
                                       }
                                   }];
 
@@ -1531,6 +1629,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                         NSString* egoPeerID,
                                         NSDictionary<NSString*, NSNumber*>* _Nullable peerCountByModelID,
                                         BOOL isExcluded,
+                                        BOOL isLocked,
                                         NSError * _Nullable error) {
         BOOL hasIdentity = egoPeerID != nil;
         secnotice("octagon-health", "repairAccountIfTrustedByTPHWithIntendedState status: %ld, peerID: %@, isExcluded: %d error: %@", (long)status, egoPeerID, isExcluded, error);
@@ -1541,6 +1640,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
             return;
         }
 
+        if (isLocked) {
+            secnotice("octagon-health", "device is locked");
+            nextState = OctagonStateWaitForUnlock;
+            return;
+        }
+        
         if(OctagonAuthoritativeTrustIsEnabled() && hasIdentity && status == CliqueStatusIn) {
             secnotice("octagon-health", "TPH believes we're trusted, accepting ego peerID as %@", egoPeerID);
 
@@ -1567,7 +1672,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     return nextState;
 }
 
-- (void)checkTrustStatusAndPostRepairCFUIfNecessary:(void (^ _Nullable)(CliqueStatus status, BOOL posted, BOOL hasIdentity, NSError * _Nullable error))reply
+- (void)checkTrustStatusAndPostRepairCFUIfNecessary:(void (^ _Nullable)(CliqueStatus status, BOOL posted, BOOL hasIdentity, BOOL isLocked, NSError * _Nullable error))reply
 {
     WEAKIFY(self);
     OTOperationConfiguration *configuration = [[OTOperationConfiguration alloc] init];
@@ -1575,6 +1680,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                NSString* _Nullable egoPeerID,
                                                NSDictionary<NSString*, NSNumber*>* _Nullable peerCountByModelID,
                                                BOOL isExcluded,
+                                               BOOL isLocked,
                                                NSError * _Nullable error) {
         STRONGIFY(self);
 
@@ -1582,7 +1688,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
         BOOL hasIdentity = egoPeerID != nil;
         if (error && error.code != errSecInteractionNotAllowed) {
-            reply(status, NO, hasIdentity, error);
+            reply(status, NO, hasIdentity, isLocked, error);
+            return;
+        }
+
+        if (isLocked) {
+            secnotice("octagon", "device is locked; not posting CFU");
+            reply(status, NO, hasIdentity, isLocked, error);
             return;
         }
 
@@ -1605,7 +1717,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         }
         if(!phonePeerPresent) {
             secnotice("octagon", "No iOS peers in account; not posting CFU");
-            reply(status, NO, hasIdentity, nil);
+            reply(status, NO, hasIdentity, isLocked, nil);
             return;
         }
 #endif
@@ -1631,7 +1743,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
                 if(circleError && [circleError.domain isEqualToString:(__bridge NSString*)kSOSErrorDomain] && circleError.code == kSOSErrorNotReady) {
                     secnotice("octagon", "SOS is not ready, not posting CFU until it becomes so");
-                    reply(status, NO, hasIdentity, nil);
+                    reply(status, NO, hasIdentity, isLocked, nil);
                     return;
 
                 } else if(circleError) {
@@ -1640,7 +1752,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
                 } else if(sosStatus == kSOSCCInCircle) {
                     secnotice("octagon", "SOS is InCircle, not posting CFU");
-                    reply(status, NO, hasIdentity, nil);
+                    reply(status, NO, hasIdentity, isLocked, nil);
                     return;
                 } else {
                     secnotice("octagon", "SOS is %@, posting CFU", (__bridge NSString*)SOSCCGetStatusDescription(sosStatus));
@@ -1651,10 +1763,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         if(OctagonAuthoritativeTrustIsEnabled() && (status == CliqueStatusNotIn || status == CliqueStatusAbsent || isExcluded)) {
             NSError* localError = nil;
             BOOL posted = [self postRepairCFU:&localError];
-            reply(status, posted, hasIdentity, localError);
+            reply(status, posted, hasIdentity, isLocked, localError);
             return;
         }
-        reply(status, NO, hasIdentity, nil);
+        reply(status, NO, hasIdentity, isLocked, nil);
         return;
     }];
 }
@@ -1699,16 +1811,26 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                       [self.accountStateTracker triggerOctagonStatusFetch];
                                   }
 
-                                  [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, BOOL hasIdentity, NSError * _Nullable postError) {
+                                  __block BOOL deviceIsLocked = NO;
+                                  [self checkTrustStatusAndPostRepairCFUIfNecessary:^(CliqueStatus status, BOOL posted, BOOL hasIdentity, BOOL isLocked, NSError * _Nullable postError) {
 
                                       [[CKKSAnalytics logger] logResultForEvent:OctagonEventCheckTrustForCFU hardFailure:false result:postError];
                                       if(postError){
                                           secerror("octagon: cfu failed to post");
+                                      } else if (isLocked == YES) {
+                                          deviceIsLocked = isLocked;
+                                          secerror("octagon: device is locked, not posting cfu");
                                       } else {
                                           secnotice("octagon", "clique status: %@, posted cfu: %d", OTCliqueStatusToString(status), !!posted);
                                       }
                                   }];
 
+                                  if (deviceIsLocked == YES) {
+                                      secnotice("octagon", "device is locked, state moving to wait for unlock");
+                                      op.nextState = OctagonStateWaitForUnlock;
+                                      return;
+                                  }
+
                                   [self.accountMetadataStore persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
                                       metadata.trustState = OTAccountMetadataClassC_TrustState_UNTRUSTED;
                                       return metadata;
@@ -1727,6 +1849,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                       [view endTrustedOperation];
                                   }
 
+                                  // We are no longer in a CKKS4All world. Tell SOS!
+                                  if(self.sosAdapter.sosEnabled) {
+                                      NSError* soserror = nil;
+                                      [self.sosAdapter updateCKKS4AllStatus:NO error:&soserror];
+                                      if(soserror) {
+                                          secnotice("octagon-ckks", "Unable to disable the CKKS4All status in SOS: %@", soserror);
+                                      }
+                                  }
+
                                   /*
                                    * Initial notification that we let the world know that trust is up and doing something
                                    */
@@ -1761,13 +1892,12 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         __block NSString* peerID = nil;
         NSError* localError = nil;
 
-        __block NSSet<NSString*>* viewList = nil;
-        __block TPPolicy* policy = nil;
+        __block TPSyncingPolicy* policy = nil;
 
         [self.accountMetadataStore persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
             peerID = metadata.peerID;
-            viewList = metadata.syncingViews.count > 0 ? [NSSet setWithArray:metadata.syncingViews] : nil;
-            policy = metadata.hasSyncingPolicy ? [metadata getTPPolicy] : nil;
+
+            policy = metadata.hasSyncingPolicy ? [metadata getTPSyncingPolicy] : nil;
 
             if(metadata.attemptedJoin == OTAccountMetadataClassC_AttemptedAJoinState_ATTEMPTED) {
                 return nil;
@@ -1778,17 +1908,37 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
 
         if(!peerID || localError) {
             secerror("octagon-ckks: No peer ID to pass to CKKS. Syncing will be disabled.");
-        } else if(!viewList || !policy) {
+        } else if(!policy) {
             secerror("octagon-ckks: No memoized CKKS policy, re-fetching");
             op.nextState = OctagonStateRefetchCKKSPolicy;
             return;
 
         } else {
-            secnotice("octagon-ckks", "Initializing CKKS views with view list %@ and policy %@", viewList, policy);
-            [self.viewManager setSyncingViews:viewList
-                                sortingPolicy:policy];
+            if(policy.syncUserControllableViews == TPPBPeerStableInfo_UserControllableViewStatus_UNKNOWN) {
+                secnotice("octagon-ckks", "Memoized CKKS policy has no opinion of user-controllable view status");
+                // Suggest the update, whenever possible
+                OctagonPendingFlag* pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptUserControllableViewStatusUpgrade
+                                                                                conditions:OctagonPendingConditionsDeviceUnlocked];
+                [self.stateMachine handlePendingFlag:pendingFlag];
+            } else {
+                // We are now in a CKKS4All world. Tell SOS!
+                if(self.sosAdapter.sosEnabled) {
+                    NSError* soserror = nil;
+                    [self.sosAdapter updateCKKS4AllStatus:YES error:&soserror];
+                    if(soserror) {
+                        secnotice("octagon-ckks", "Unable to enable the CKKS4All status in SOS: %@", soserror);
+                    }
+                }
+            }
+
+            secnotice("octagon-ckks", "Initializing CKKS views with policy %@: %@", policy, policy.viewList);
 
-            OctagonCKKSPeerAdapter* octagonAdapter = [[OctagonCKKSPeerAdapter alloc] initWithPeerID:peerID operationDependencies:[self operationDependencies]];
+            [self.viewManager setCurrentSyncingPolicy:policy];
+
+            OctagonCKKSPeerAdapter* octagonAdapter = [[OctagonCKKSPeerAdapter alloc] initWithPeerID:peerID
+                                                                                      containerName:self.containerName
+                                                                                          contextID:self.contextID
+                                                                                      cuttlefishXPC:self.cuttlefishXPCWrapper];
 
             // This octagon adapter must be able to load the self peer keys, or we're in trouble.
             NSError* egoPeerKeysError = nil;
@@ -1824,7 +1974,8 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                 }
 
                 [view beginTrustedOperation:peerProviders
-                           suggestTLKUpload:self.suggestTLKUploadNotifier];
+                           suggestTLKUpload:self.suggestTLKUploadNotifier
+                         requestPolicyCheck:self.requestPolicyCheckNotifier];
             }
         }
         [self notifyTrustChanged:OTAccountMetadataClassC_TrustState_TRUSTED];
@@ -1875,7 +2026,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     }
     if (ckDeviceId) {
         NSString *selfDeviceID = self.viewManager.accountTracker.ckdeviceID;
-        if (![selfDeviceID isEqualToString:serialNumber]) {
+        if (serialNumber == nil || ![selfDeviceID isEqualToString:serialNumber]) {
             secnotice("octagon", "TTR request not for me (deviceId)");
             return;
         }
@@ -1999,7 +2150,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     if(accountMetadata.lastHealthCheckup == 0) {
         return nil;
     }
-    return [[NSDate alloc] initWithTimeIntervalSince1970: accountMetadata.lastHealthCheckup];
+    return [[NSDate alloc] initWithTimeIntervalSince1970: ((NSTimeInterval)accountMetadata.lastHealthCheckup) / 1000.0];
 }
 
 - (void)requestTrustedDeviceListRefresh
@@ -2086,6 +2237,21 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
             haveAccount = false;
         }
     });
+
+    if(!haveAccount) {
+        // Right after account sign-in, it's possible that the CK account exists, but that we just haven't learned about
+        // it yet, and still have the 'no account' state cached. So, let's check in...
+        secnotice("octagon-ck", "No CK account present. Attempting to refetch CK account status...");
+        if(![self.accountStateTracker notifyCKAccountStatusChangeAndWait:timeout]) {
+            secnotice("octagon-ck", "Fetching new CK account status did not complete in time");
+        }
+
+        // After the above call finishes, we should have a fresh value in self.cloudKitAccountInfo
+        dispatch_sync(self.queue, ^{
+            haveAccount = self.cloudKitAccountInfo.accountStatus == CKKSAccountStatusAvailable;
+        });
+        secnotice("octagon-ck", "After refetch, CK account status is %@", haveAccount ? @"present" : @"missing");
+    }
     return haveAccount ? CKKSAccountStatusAvailable : CKKSAccountStatusNoAccount;
 }
 
@@ -2156,10 +2322,10 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     return;
 }
 
--(void)joinWithBottle:(NSString*)bottleID
-              entropy:(NSData *)entropy
-           bottleSalt:(NSString *)bottleSalt
-                reply:(void (^)(NSError * _Nullable error))reply
+- (void)joinWithBottle:(NSString*)bottleID
+               entropy:(NSData *)entropy
+            bottleSalt:(NSString *)bottleSalt
+                 reply:(void (^)(NSError * _Nullable error))reply
 {
     _bottleID = bottleID;
     _entropy = entropy;
@@ -2213,19 +2379,22 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     return @{
         OctagonStateInitiatorSetCDPBit: @{
             OctagonStateInitiatorUpdateDeviceList: @{
-                OctagonStateInitiatorJoin: @{
-                    OctagonStateBecomeReady: @{
-                        OctagonStateReady: [OctagonStateTransitionPathStep success],
-                    },
-
-                    OctagonStateInitiatorJoinCKKSReset: @{
-                        OctagonStateInitiatorJoinAfterCKKSReset: @{
-                            OctagonStateBecomeReady: @{
-                                OctagonStateReady: [OctagonStateTransitionPathStep success]
+                    OctagonStateInitiatorJoin: @{
+                            OctagonStateBottlePreloadOctagonKeysInSOS: @{
+                                    OctagonStateBecomeReady: @{
+                                            OctagonStateReady: [OctagonStateTransitionPathStep success],
+                                    },
+                            },
+                            OctagonStateInitiatorJoinCKKSReset: @{
+                                            OctagonStateInitiatorJoinAfterCKKSReset: @{
+                                                    OctagonStateBottlePreloadOctagonKeysInSOS: @{
+                                                            OctagonStateBecomeReady: @{
+                                                                    OctagonStateReady: [OctagonStateTransitionPathStep success]
+                                                            },
+                                                    },
+                                            },
                             },
-                        },
                     },
-                },
             },
         },
     };
@@ -2236,15 +2405,24 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
           reply:(void (^)(NSError * _Nullable error))reply
 {
 
-    _vouchData = vouchData;
-    _vouchSig = vouchSig;
-
     if ([self checkForCKAccount:nil] != CKKSAccountStatusAvailable) {
         secnotice("octagon", "No cloudkit account present");
         reply([self errorNoiCloudAccount]);
         return;
     }
 
+    NSError* metadataError = nil;
+    [self.accountMetadataStore persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
+        metadata.voucher = vouchData;
+        metadata.voucherSignature = vouchSig;
+        return metadata;
+    } error:&metadataError];
+    if(metadataError) {
+        secnotice("octagon", "Unable to save voucher for joining: %@", metadataError);
+        reply(metadataError);
+        return;
+    }
+
     NSMutableSet* sourceStates = [NSMutableSet setWithObject:OctagonStateInitiatorAwaitingVoucher];
 
     OctagonStateTransitionPath* path = [OctagonStateTransitionPath pathFromDictionary:[self joinStatePathDictionary]];
@@ -2369,8 +2547,9 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     }
 
     result[@"CoreFollowUp"] = [self.followupHandler sysdiagnoseStatus];
-    result[@"lastOctagonPush"] = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastOctagonPush];
 
+    result[@"lastOctagonPush"] = [[CKKSAnalytics logger] datePropertyForKey:CKKSAnalyticsLastOctagonPush];
+    result[@"pushEnvironments"] = [self.apsReceiver registeredPushEnvironments];
 
     [self.cuttlefishXPCWrapper dumpWithContainer:self.containerName
                                          context:self.contextID
@@ -2467,6 +2646,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                              NSString* egoPeerID,
                                              NSDictionary<NSString*, NSNumber*>* _Nullable peerCountByModelID,
                                              BOOL isExcluded,
+                                             BOOL isLocked,
                                              NSError *error))reply
 {
     CliqueStatus status = CliqueStatusAbsent;
@@ -2477,8 +2657,8 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         status = CliqueStatusNotIn;
     }
 
-    secnotice("octagon", "returning cached clique status: %@", OTCliqueStatusToString(status));
-    reply(status, account.peerID, nil, NO, NULL);
+    secinfo("octagon", "returning cached clique status: %@", OTCliqueStatusToString(status));
+    reply(status, account.peerID, nil, NO, NO, NULL);
 }
 
 
@@ -2487,6 +2667,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                  NSString* _Nullable peerID,
                                  NSDictionary<NSString*, NSNumber*>* _Nullable peerCountByModelID,
                                  BOOL isExcluded,
+                                 BOOL isLocked,
                                  NSError *error))reply
 {
     __block NSError* localError = nil;
@@ -2494,13 +2675,13 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     OTAccountMetadataClassC* account = [self.accountMetadataStore loadOrCreateAccountMetadata:&localError];
     if(localError && [self.lockStateTracker isLockedError:localError]){
         secnotice("octagon", "Device is locked! pending initialization on unlock");
-        reply(CliqueStatusError, nil, nil, NO, localError);
+        reply(CliqueStatusError, nil, nil, NO, NO, localError);
         return;
     }
 
     if(account.icloudAccountState == OTAccountMetadataClassC_AccountState_NO_ACCOUNT) {
         secnotice("octagon", "no account! returning clique status 'no account'");
-        reply(CliqueStatusNoCloudKitAccount, nil, nil, NO, NULL);
+        reply(CliqueStatusNoCloudKitAccount, nil, nil, NO, NO, NULL);
         return;
     }
 
@@ -2512,7 +2693,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     CKKSAccountStatus ckAccountStatus = [self checkForCKAccount:configuration];
     if(ckAccountStatus == CKKSAccountStatusNoAccount) {
         secnotice("octagon", "No cloudkit account present");
-        reply(CliqueStatusNoCloudKitAccount, nil, nil, NO, NULL);
+        reply(CliqueStatusNoCloudKitAccount, nil, nil, NO, NO, NULL);
         return;
     } else if(ckAccountStatus == CKKSAccountStatusUnknown) {
         secnotice("octagon", "Unknown cloudkit account status, returning cached trust value");
@@ -2524,6 +2705,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     __block NSDictionary<NSString*, NSNumber*>* peerModelCounts = nil;
     __block BOOL excluded = NO;
     __block CliqueStatus trustStatus = CliqueStatusError;
+    __block BOOL isLocked = NO;
 
     [self.cuttlefishXPCWrapper trustStatusWithContainer:self.containerName
                                                 context:self.contextID
@@ -2533,6 +2715,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         peerID = egoStatus.egoPeerID;
         excluded = egoStatus.isExcluded;
         peerModelCounts = egoStatus.viablePeerCountsByModelID;
+        isLocked = egoStatus.isLocked;
         localError = xpcError;
 
         if(xpcError) {
@@ -2573,7 +2756,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         }
     }];
 
-    reply(trustStatus, peerID, peerModelCounts, excluded, localError);
+    reply(trustStatus, peerID, peerModelCounts, excluded, isLocked, localError);
 }
 
 - (void)rpcFetchAllViableBottles:(void (^)(NSArray<NSString*>* _Nullable sortedBottleIDs, NSArray<NSString*>* _Nullable sortedPartialEscrowRecordIDs, NSError* _Nullable error))reply
@@ -2599,6 +2782,51 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         }];
 }
 
+- (void)rpcFetchAllViableEscrowRecords:(BOOL)forceFetch reply:(void (^)(NSArray<NSData*>* _Nullable records,
+                                                 NSError* _Nullable error))reply
+{
+    if ([self checkForCKAccount:nil] != CKKSAccountStatusAvailable) {
+        secnotice("octagon", "No cloudkit account present");
+        reply(NULL, [self errorNoiCloudAccount]);
+        return;
+    }
+
+    // As this isn't a state-modifying operation, we don't need to go through the state machine.
+    [self.cuttlefishXPCWrapper fetchViableEscrowRecordsWithContainer:self.containerName
+                                                             context:self.contextID
+                                                          forceFetch:(BOOL)forceFetch
+                                                               reply:^(NSArray<NSData *> * _Nullable records, NSError * _Nullable error) {
+        if(error){
+            secerror("octagon: error fetching all viable escrow records: %@", error);
+            reply(nil, error);
+        }else{
+            secnotice("octagon", "fetched escrow records: %@", records);
+
+            reply(records, error);
+        }
+    }];
+}
+
+- (void)rpcInvalidateEscrowCache:(void (^)(NSError* _Nullable error))reply
+{
+    if ([self checkForCKAccount:nil] != CKKSAccountStatusAvailable) {
+        secnotice("octagon", "No cloudkit account present");
+        reply([self errorNoiCloudAccount]);
+        return;
+    }
+
+    // As this isn't a state-modifying operation, we don't need to go through the state machine.
+    [self.cuttlefishXPCWrapper removeEscrowCacheWithContainer:self.containerName context:self.contextID reply:^(NSError * _Nullable removeError) {
+        if (removeError){
+            secerror("octagon: failed to remove escrow cache: %@", removeError);
+            reply(removeError);
+        } else{
+            secnotice("octagon", "successfully removed escrow cache");
+            reply(nil);
+        }
+    }];
+}
+
 - (void)fetchEscrowContents:(void (^)(NSData* _Nullable entropy,
                                       NSString* _Nullable bottleID,
                                       NSData* _Nullable signingPublicKey,
@@ -2659,10 +2887,127 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                           reply:reply];
 }
 
-#pragma mark --- Testing
-- (void) setAccountStateHolder:(OTCuttlefishAccountStateHolder*)accountMetadataStore
+- (void)rpcFetchUserControllableViewsSyncingStatus:(void (^)(BOOL areSyncing, NSError* _Nullable error))reply
+{
+    if(self.viewManager.policy) {
+        BOOL syncing = self.viewManager.policy.syncUserControllableViewsAsBoolean;
+
+        secnotice("octagon-ckks", "Returning user-controllable status as %@ (%@)",
+                  syncing ? @"enabled" : @"disabled",
+                  TPPBPeerStableInfo_UserControllableViewStatusAsString(self.viewManager.policy.syncUserControllableViews));
+
+        reply(syncing, nil);
+        return;
+    }
+
+    // No loaded policy? Let's trigger a fetch.
+    [self rpcRefetchCKKSPolicy:^(NSError * _Nullable error) {
+        if(error) {
+            secnotice("octagon-ckks", "Failed to fetch policy: %@", error);
+            reply(NO, error);
+            return;
+        }
+
+        if(self.viewManager.policy) {
+            BOOL syncing = self.viewManager.policy.syncUserControllableViewsAsBoolean;
+
+            secnotice("octagon-ckks", "Returning user-controllable status as %@ (%@)",
+                      syncing ? @"enabled" : @"disabled",
+                      TPPBPeerStableInfo_UserControllableViewStatusAsString(self.viewManager.policy.syncUserControllableViews));
+
+            reply(syncing, nil);
+            return;
+
+        } else {
+            // The tests sometimes don't have a viewManager. If we're in the tests, try this last-ditch effort:
+            if(SecCKKSTestsEnabled()) {
+                NSError* metadataError = nil;
+                OTAccountMetadataClassC* accountState = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError];
+                if(metadataError) {
+                    secnotice("octagon-ckks", "Error fetching acount state: %@", metadataError);
+                }
+                TPSyncingPolicy* policy = [accountState getTPSyncingPolicy];
+                if(policy) {
+                    BOOL syncing = policy.syncUserControllableViewsAsBoolean;
+                    secnotice("octagon-ckks", "Returning user-controllable status (fetched from account state) as %@ (%@)",
+                              syncing ? @"enabled" : @"disabled",
+                              TPPBPeerStableInfo_UserControllableViewStatusAsString(self.viewManager.policy.syncUserControllableViews));
+                    reply(syncing, nil);
+                    return;
+                }
+            }
+
+            secnotice("octagon-ckks", "Policy missing even after a refetch?");
+            reply(NO, [NSError errorWithDomain:OctagonErrorDomain
+                                          code:OTErrorSyncPolicyMissing
+                                   description:@"Sync policy is missing even after refetching"]);
+            return;
+        }
+    }];
+}
+
+- (void)rpcSetUserControllableViewsSyncingStatus:(BOOL)status reply:(void (^)(BOOL areSyncing, NSError* _Nullable error))reply
 {
-    self.accountMetadataStore = accountMetadataStore;
+#if TARGET_OS_TV
+    // TVs can't set this value.
+    secnotice("octagon-ckks", "Rejecting set of user-controllable sync status due to platform");
+    reply(NO, [NSError errorWithDomain:OctagonErrorDomain
+                                  code:OTErrorNotSupported
+                           description:@"This platform does not support setting the user-controllable view syncing status"]);
+#else
+
+    OctagonState* firstState = status ? OctagonStateEnableUserControllableViews : OctagonStateDisableUserControllableViews;
+
+    secnotice("octagon-ckks", "Settting user-controllable sync status as '%@'", status ? @"enabled" : @"disabled");
+
+    [self.stateMachine doWatchedStateMachineRPC:@"octagon-set-policy"
+                                   sourceStates:[NSMutableSet setWithArray: @[OctagonStateReady]]
+                                           path:[OctagonStateTransitionPath pathFromDictionary:@{
+                                               firstState: @{
+                                                       OctagonStateBecomeReady: @{
+                                                               OctagonStateReady: [OctagonStateTransitionPathStep success],
+                                                       },
+                                               },
+                                           }]
+                                          reply:^(NSError * _Nullable error) {
+        if(error) {
+            secnotice("octagon-ckks", "Failed to set sync policy to '%@': %@", status ? @"enabled" : @"disabled", error);
+            reply(NO, error);
+            return;
+        }
+
+        if(self.viewManager.policy) {
+            BOOL finalStatus = self.viewManager.policy.syncUserControllableViewsAsBoolean;
+            secnotice("octagon-ckks", "User-controllable sync status is set as '%@'", finalStatus ? @"enabled" : @"disabled");
+            reply(finalStatus, nil);
+            return;
+        }
+
+        // The tests sometimes don't have a viewManager. If we're in the tests, try this last-ditch effort:
+        if(SecCKKSTestsEnabled()) {
+            NSError* metadataError = nil;
+            OTAccountMetadataClassC* accountState = [self.accountMetadataStore loadOrCreateAccountMetadata:&metadataError];
+            if(metadataError) {
+                secnotice("octagon-ckks", "Error fetching acount state: %@", metadataError);
+            }
+            TPSyncingPolicy* policy = [accountState getTPSyncingPolicy];
+            if(policy) {
+                BOOL syncing = policy.syncUserControllableViewsAsBoolean;
+                secnotice("octagon-ckks", "Returning user-controllable status (fetched from account state) as %@ (%@)",
+                          syncing ? @"enabled" : @"disabled",
+                          TPPBPeerStableInfo_UserControllableViewStatusAsString(self.viewManager.policy.syncUserControllableViews));
+                reply(syncing, nil);
+                return;
+            }
+        }
+
+        secnotice("octagon-ckks", "Policy missing even after a refetch?");
+        reply(NO, [NSError errorWithDomain:OctagonErrorDomain
+                                      code:OTErrorSyncPolicyMissing
+                               description:@"Sync policy is missing even after refetching"]);
+        return;
+    }];
+#endif
 }
 
 #pragma mark --- Health Checker
@@ -2735,17 +3080,16 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
     return YES;
 }
 
-- (void)postConfirmPasscodeCFU:(NSError**)error
+- (BOOL)postConfirmPasscodeCFU:(NSError**)error
 {
+    BOOL ret = NO;
     NSError* localError = nil;
-    [self.followupHandler postFollowUp:OTFollowupContextTypeOfflinePasscodeChange error:&localError];
+    ret = [self.followupHandler postFollowUp:OTFollowupContextTypeOfflinePasscodeChange error:&localError];
     if(localError){
         secerror("octagon-health: CoreCDP offline passcode change failed: %@", localError);
         *error = localError;
     }
-    else{
-        secnotice("octagon-health", "CoreCDP offline passcode change success");
-    }
+    return ret;
 }
 
 - (void)checkOctagonHealth:(BOOL)skipRateLimitingCheck reply:(void (^)(NSError * _Nullable error))reply
@@ -2772,6 +3116,7 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                                                    OctagonStateHealthCheckReset: [OctagonStateTransitionPathStep success],
                                                                    OctagonStateHealthCheckLeaveClique: [OctagonStateTransitionPathStep success],
                                                                },
+                                                               OctagonStateWaitForUnlock: [OctagonStateTransitionPathStep success],
                                                            },
                                                        },
                                                        OctagonStateWaitForCDP: [OctagonStateTransitionPathStep success],
@@ -2782,52 +3127,27 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
                                           reply:reply];
 }
 
-- (void)attemptSOSUpgrade:(void (^)(NSError* _Nullable error))reply
-{
-    secnotice("octagon-sos", "attempting to perform an sos upgrade");
-
-    if ([self checkForCKAccount:nil] != CKKSAccountStatusAvailable) {
-        secnotice("octagon-sos", "No cloudkit account present");
-        reply([self errorNoiCloudAccount]);
-        return;
-    }
-
-    NSSet* sourceStates = [NSSet setWithArray: @[OctagonStateUntrusted]];
-
-    OTSOSUpgradeOperation *pendingOp = [[OTSOSUpgradeOperation alloc] initWithDependencies:self.operationDependencies
-                                                                             intendedState:OctagonStateBecomeReady
-                                                                         ckksConflictState:OctagonStateBecomeUntrusted
-                                                                                errorState:OctagonStateBecomeUntrusted
-                                                                                deviceInfo:self.prepareInformation
-                                                                            policyOverride:self.policyOverride];
-
-    OctagonStateTransitionRequest<OTSOSUpgradeOperation*>* request = [[OctagonStateTransitionRequest alloc] init:@"attempt-sos-upgrade"
-                                                                                                    sourceStates:sourceStates
-                                                                                                     serialQueue:self.queue
-                                                                                                         timeout:OctagonStateTransitionDefaultTimeout
-                                                                                                    transitionOp:pendingOp];
-
-    CKKSResultOperation* callback = [CKKSResultOperation named:@"sos-upgrade-callback"
-                                                     withBlock:^{
-                                                         secnotice("otrpc", "Returning from an sos upgrade attempt: %@", pendingOp.error);
-                                                         [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreapprovedJoinAfterPairing hardFailure:false result:pendingOp.error];
-                                                         reply(pendingOp.error);
-                                                     }];
-
-    [callback addDependency:pendingOp];
-    [self.operationQueue addOperation: callback];
-    
-    [self.stateMachine handleExternalRequest:request];
-}
-
 - (void)waitForOctagonUpgrade:(void (^)(NSError* error))reply
 {
     secnotice("octagon-sos", "waitForOctagonUpgrade");
 
+    NSError* localError = nil;
+
     if (!self.sosAdapter.sosEnabled) {
         secnotice("octagon-sos", "sos not enabled, nothing to do for waitForOctagonUpgrade");
         reply(nil);
         return;
+    } else if ([self.sosAdapter circleStatus:&localError] != kSOSCCInCircle) {
+        secnotice("octagon-sos", "SOS circle status: %d, cannot perform sos upgrade", [self.sosAdapter circleStatus:&localError]);
+        if (localError == nil) {
+            localError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorNoCircle userInfo:@{NSLocalizedDescriptionKey : @"Not in circle"}];
+        } else {
+            secerror("octagon-sos: error retrieving circle status: %@", localError);
+        }
+        reply(localError);
+        return;
+    } else {
+        secnotice("octagon-sos", "in sos circle!, attempting upgrade");
     }
 
     if ([self.stateMachine isPaused]) {
@@ -2846,12 +3166,15 @@ static dispatch_time_t OctagonStateTransitionDefaultTimeout = 10*NSEC_PER_SEC;
         }
     }
 
-    NSSet* sourceStates = [NSSet setWithArray: @[OctagonStateUntrusted]];
+    NSSet* sourceStates = [NSSet setWithArray: @[OctagonStateWaitForCDP,
+                                                 OctagonStateUntrusted]];
 
     OctagonStateTransitionPath* path = [OctagonStateTransitionPath pathFromDictionary:@{
-        OctagonStateAttemptSOSUpgrade: @{
-            OctagonStateBecomeReady: @{
-                OctagonStateReady: [OctagonStateTransitionPathStep success],
+        OctagonStateAttemptSOSUpgradeDetermineCDPState: @{
+            OctagonStateAttemptSOSUpgrade: @{
+                OctagonStateBecomeReady: @{
+                    OctagonStateReady: [OctagonStateTransitionPathStep success],
+                },
             },
         },
     }];
index d391c48fd71feaa2224885b9671c64c7c0ea1b24..952a1bd55853c6ef434904c222c37ce04ad1ba00 100644 (file)
@@ -36,11 +36,8 @@ extern NSString* const OctagonEventAttributeTimeSinceLastPostedFollowUp;
 
 extern NSString* OTCKContainerName;
 extern NSString* const CuttlefishTrustZone;
-extern NSString* const CuttlefishErrorDomain;
 extern NSString* const TrustedPeersHelperErrorDomain;
 
-extern NSString* const CuttlefishErrorRetryAfterKey;
-
 /* Octagon Errors */
 typedef NS_ERROR_ENUM(OctagonErrorDomain, OctagonError) {
     //OTErrorNoColumn                         = 1,
@@ -91,6 +88,7 @@ typedef NS_ERROR_ENUM(OctagonErrorDomain, OctagonError) {
     OTAuthKitMachineIDMissing               = 46,
     OTAuthKitPrimaryAccountHaveNoDSID       = 47,
     OTErrorFailedToLeaveClique              = 48,
+    OTErrorSyncPolicyMissing                = 49,
 };
 
 #define OTMasterSecretLength 72
@@ -100,6 +98,7 @@ typedef NS_ENUM(NSInteger, TrustedPeersHelperErrorCode) {
     TrustedPeersHelperErrorNoPeersPreapprovePreparedIdentity = 14,
     TrustedPeersHelperErrorCodeUntrustedRecoveryKeys    = 32,
     TrustedPeersHelperErrorCodeNotEnrolled   = 34,
+    TrustedPeersHelperErrorNoPeersPreapprovedBySelf = 47,
 };
 
 // See cuttlefish/CuttlefishService/Sources/CuttlefishService/CuttlefishError.swift
@@ -127,6 +126,9 @@ typedef NS_ENUM(NSInteger, CuttlefishErrorCode) {
     CuttlefishErrorPreflightGraphValidationError = 1022,
     CuttlefishErrorKeyHierarchyAlreadyExists = 1033,
     CuttlefishErrorDuplicatePeerIdUnderConsideration = 1034,
+    CuttlefishErrorIneligibleExclusionDenied = 1035,
+    CuttlefishErrorMultiplePreapprovedJoinDenied = 1036,
+    CuttlefishErrorUpdateTrustPeerNotFound = 1037,
 };
 
 NS_ASSUME_NONNULL_END
index 0aa95a3655a09393964f580a82e78b27e39df391..476426ddd286b88246e644baf6f48172f893bd65 100644 (file)
@@ -31,7 +31,5 @@ NSString* const OctagonEventAttributeTimeSinceLastPostedFollowUp = @"TimeSinceLa
 
 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";
index 8ad69c12564511380676163f161e7d0b7c08a031..b776287b459124f4891c9a7fb74b6d10bd1c7d65 100644 (file)
@@ -57,7 +57,7 @@
     OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&localError];
     if(localError && [self.deps.lockStateTracker isLockedError:localError]) {
         secnotice("octagon-cdp-status", "Device is locked! restarting on unlock");
-        self.nextState = OctagonStateWaitForUnlock;
+        self.nextState = OctagonStateWaitForClassCUnlock;
         return;
     }
 
index 43279916c473e42eb1c13bac870fd01fa88b0bd7..f283c9507d605c6c6ad96628446d3b3b5d4ed189 100644 (file)
@@ -19,7 +19,7 @@ NS_ASSUME_NONNULL_BEGIN
 - (NSString*)osVersion;
 
 /* Returns the serial number as a string. */
-- (NSString*)serialNumber;
+- (NSString* _Nullable)serialNumber;
 
 /* register for deviceName updates */
 - (void)registerForDeviceNameUpdates:(id<OTDeviceInformationNameUpdateListener>)listener;
index acd71ebeab5b25eefd95a6f6d6f68b2f08a78735..9e8cf9903768ca03d4c75ffc3f224147b62260d8 100644 (file)
@@ -107,7 +107,7 @@ static void updateDeviceNameChanges(SCDynamicStoreRef store, CFArrayRef keys, vo
 
 #else
 
-- (NSString*)serialNumber
+- (NSString* _Nullable)serialNumber
 {
     io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
     if (platformExpert == MACH_PORT_NULL) {
index bb86a39c226d4e834c04396570f7f13fcd458b1d..965fb86369770402ee48fc65c1641107463d27a7 100644 (file)
         return;
     }
 
-    OctagonCKKSPeerAdapter* octagonAdapter = [[OctagonCKKSPeerAdapter alloc] initWithPeerID:octagonPeerID operationDependencies:self.deps];
+    OctagonCKKSPeerAdapter* octagonAdapter = [[OctagonCKKSPeerAdapter alloc] initWithPeerID:octagonPeerID
+                                                                              containerName:self.deps.containerName
+                                                                                  contextID:self.deps.contextID
+                                                                              cuttlefishXPC:self.deps.cuttlefishXPCWrapper];
+
+    secnotice("octagon", "Fetched SOS Self! Fetching Octagon Adapter now: %@", octagonAdapter);
 
     NSError* fetchSelfPeersError = nil;
     CKKSSelves *selfPeers = [octagonAdapter fetchSelfPeers:&fetchSelfPeersError];
+
     if((!selfPeers) || fetchSelfPeersError) {
         secnotice("octagon", "failed to retrieve self peers: %@", fetchSelfPeersError);
         self.error = fetchSelfPeersError;
     if(![octagonSigningKeyData isEqualToData:sosSigningKeyData] || ![octagonEncryptionKeyData isEqualToData:sosEncryptionKeyData]) {
         secnotice("octagon", "SOS and Octagon signing keys do NOT match! updating SOS");
         NSError* updateError = nil;
-        [self.deps.sosAdapter updateOctagonKeySetWithAccount:currentSelfPeer error:&updateError];
-        if(updateError) {
+        BOOL ret = [self.deps.sosAdapter updateOctagonKeySetWithAccount:currentSelfPeer error:&updateError];
+        if(!ret) {
             self.error = updateError;
             [self runBeforeGroupFinished:self.finishOp];
             return;
index 0acbd9ffe885ed5f0cedc167c69dba5e01228ba6..93c6689c0fadaff2870ece8f7d436e86094fbac9 100644 (file)
@@ -75,7 +75,8 @@
     [self dependOnBeforeGroupFinished:self.finishedOp];
 
     // First, interrogate CKKS views, and see when they have a TLK proposal.
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.operationDependencies];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.operationDependencies
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"establish-with-keys"
                                                                    ckksKeys:viewKeySets
                                                                   tlkShares:pendingTLKShares
                                                             preapprovedKeys:publicSigningSPKIs
-                                                                      reply:^(NSString * _Nullable peerID, NSArray<CKRecord*>* _Nullable keyHierarchyRecords, NSError * _Nullable error) {
+                                                                      reply:^(NSString * _Nullable peerID,
+                                                                              NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                                                              TPSyncingPolicy* _Nullable syncingPolicy,
+                                                                              NSError * _Nullable error) {
             STRONGIFY(self);
 
             [[CKKSAnalytics logger] logResultForEvent:OctagonEventEstablishIdentity hardFailure:true result:error];
 
             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];
+                metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED;
+                metadata.peerID = peerID;
+                [metadata setTPSyncingPolicy:syncingPolicy];
+                return metadata;
+            } error:&localError];
+
             if(!persisted || localError) {
                 secnotice("octagon", "Couldn't persist results: %@", localError);
                 self.error = localError;
                 self.nextState = self.intendedState;
             }
 
+            [self.operationDependencies.viewManager setCurrentSyncingPolicy:syncingPolicy];
+
             // Tell CKKS about our shiny new records!
             for (id key in self.operationDependencies.viewManager.views) {
                 CKKSKeychainView* view = self.operationDependencies.viewManager.views[key];
index 5bd5a0ee63779e782289e23ef60f9c925189f6e1..bb2e1d98e75e542b703272201da28c343732e80f 100644 (file)
@@ -2,6 +2,7 @@
 #if OCTAGON
 
 #import <Foundation/Foundation.h>
+#import <dispatch/dispatch.h>
 
 #import "keychain/ckks/CKKSGroupOperation.h"
 #import "keychain/ckks/CKKSKeychainBackedKey.h"
@@ -24,7 +25,15 @@ NS_ASSUME_NONNULL_BEGIN
 // Any new TLKShares that CKKS suggested we upload along with this keyset
 @property NSArray<CKKSTLKShare*>* pendingTLKShares;
 
-- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies;
+// Any views that didn't provide a keyset within time
+@property NSSet<NSString*>* viewsTimedOutWithoutKeysets;
+
+// Set this to configure how long to wait for CKKS to resonse
+@property dispatch_time_t desiredTimeout;
+
+- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                       refetchNeeded:(BOOL)refetchNeeded;
+;
 - (instancetype)initWithViews:(NSSet<CKKSKeychainView*>*)views;
 @end
 
index 13613b2e5d21ce86a0103bb4285d2d620df2f35e..7380f780f6d7566e1fd5e83aa69de7dfc4d8c271 100644 (file)
@@ -8,11 +8,14 @@
 @interface OTFetchCKKSKeysOperation ()
 @property NSSet<CKKSKeychainView*>* views;
 @property CKKSViewManager* manager;
+
+@property BOOL fetchBeforeGettingKeyset;
 @end
 
 @implementation OTFetchCKKSKeysOperation
 
 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                       refetchNeeded:(BOOL)refetchNeeded
 {
     if((self = [super init])) {
         _manager = dependencies.viewManager;
         _tlkShares = @[];
         _pendingTLKShares = @[];
         _incompleteKeySets = @[];
+
+        _desiredTimeout = SecCKKSTestsEnabled() ? 5*NSEC_PER_SEC : 15*NSEC_PER_SEC;
+
+        _fetchBeforeGettingKeyset = refetchNeeded;
+
+        _viewsTimedOutWithoutKeysets = [NSSet set];
     }
     return self;
 }
         _tlkShares = @[];
         _pendingTLKShares = @[];
         _incompleteKeySets = @[];
+
+        _desiredTimeout = SecCKKSTestsEnabled() ? 5*NSEC_PER_SEC : 15*NSEC_PER_SEC;
+
+        _fetchBeforeGettingKeyset = NO;
+
+        _viewsTimedOutWithoutKeysets = [NSSet set];
     }
     return self;
 }
 
     for (CKKSKeychainView* view in self.views) {
         secnotice("octagon-ckks", "Waiting for %@", view);
-        [keyOps addObject:[[view findKeySet] timeout:45*NSEC_PER_SEC]];
+        [keyOps addObject:[[view findKeySet:self.fetchBeforeGettingKeyset] timeout:self.desiredTimeout]];
     }
 
     WEAKIFY(self);
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"proceed-with-ckks-keys"
                                                             withBlock:^{
-                                                                STRONGIFY(self);
-
-                                                                NSMutableArray<CKKSKeychainBackedKeySet*>* viewKeySets = [NSMutableArray array];
-                                                                NSMutableArray<CKKSCurrentKeySet*>* ckksBrokenKeySets = [NSMutableArray array];
-                                                                NSMutableArray<CKKSTLKShare*>* tlkShares = [NSMutableArray array];
-                                                                NSMutableArray<CKKSTLKShare*>* pendingTLKShares = [NSMutableArray array];
-
-                                                                for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in keyOps) {
-                                                                    if(op.error) {
-                                                                        secnotice("octagon-ckks", "No keys for zone %@: %@", op.zoneName, op.error);
-                                                                        continue;
-                                                                    }
-
-                                                                    NSError* localerror = nil;
-                                                                    CKKSKeychainBackedKeySet* keyset = [op.keyset asKeychainBackedSet:&localerror];
-
-                                                                    if(keyset) {
-                                                                        secnotice("octagon-ckks", "Have proposed keys: %@", op.keyset);
-                                                                        [viewKeySets addObject:keyset];
-                                                                    } else {
-                                                                        secnotice("octagon-ckks", "Unable to convert proposed keys: %@ %@", op.keyset, localerror);
-                                                                        if(op.keyset) {
-                                                                            [ckksBrokenKeySets addObject:op.keyset];
-                                                                        }
-                                                                    }
-
-                                                                    for(CKKSTLKShareRecord* tlkShareRecord in op.keyset.tlkShares) {
-                                                                        [tlkShares addObject:tlkShareRecord.share];
-                                                                    }
-                                                                    secnotice("octagon-ckks", "Have %u tlk shares", (uint32_t)op.keyset.tlkShares.count);
-
-                                                                    for(CKKSTLKShareRecord* tlkShareRecord in op.keyset.pendingTLKShares) {
-                                                                        [pendingTLKShares addObject:tlkShareRecord.share];
-                                                                    }
-                                                                    secnotice("octagon-ckks", "Have %u pending tlk shares", (uint32_t)op.keyset.pendingTLKShares.count);
-                                                                }
-
-                                                                self.viewKeySets = viewKeySets;
-                                                                self.incompleteKeySets = ckksBrokenKeySets;
-                                                                self.tlkShares = tlkShares;
-                                                                self.pendingTLKShares = pendingTLKShares;
-
-                                                                secnotice("octagon-ckks", "Fetched %d key sets, %d broken key sets, %d tlk shares, and %d pendingTLKShares",
-                                                                          (int)self.viewKeySets.count,
-                                                                          (int)self.incompleteKeySets.count,
-                                                                          (int)self.tlkShares.count,
-                                                                          (int)self.pendingTLKShares.count);
-                                                            }];
+        STRONGIFY(self);
+
+        NSMutableArray<CKKSKeychainBackedKeySet*>* viewKeySets = [NSMutableArray array];
+        NSMutableArray<CKKSCurrentKeySet*>* ckksBrokenKeySets = [NSMutableArray array];
+        NSMutableArray<CKKSTLKShare*>* tlkShares = [NSMutableArray array];
+        NSMutableArray<CKKSTLKShare*>* pendingTLKShares = [NSMutableArray array];
+
+        NSMutableSet<NSString*>* viewsMIA = [NSMutableSet set];
+
+        for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in keyOps) {
+            if(op.error) {
+                secnotice("octagon-ckks", "No keys for zone %@: %@", op.zoneName, op.error);
+
+                if([op.error.domain isEqualToString:CKKSResultErrorDomain] && op.error.code == CKKSResultTimedOut) {
+                    [viewsMIA addObject:op.zoneName];
+                }
+                continue;
+            }
+
+            NSError* localerror = nil;
+            CKKSCurrentKeySet* keyset = op.keyset;
+            CKKSKeychainBackedKeySet* keychainBackedKeyset = [keyset asKeychainBackedSet:&localerror];
+
+            if(keychainBackedKeyset) {
+                secnotice("octagon-ckks", "Have proposed keys: %@", keyset);
+                [viewKeySets addObject:keychainBackedKeyset];
+            } else {
+                if(keyset) {
+                    secnotice("octagon-ckks", "Unable to convert proposed keys: %@ %@", keyset, localerror);
+                    [ckksBrokenKeySets addObject:op.keyset];
+                }
+            }
+
+            for(CKKSTLKShareRecord* tlkShareRecord in op.keyset.tlkShares) {
+                [tlkShares addObject:tlkShareRecord.share];
+            }
+
+            for(CKKSTLKShareRecord* tlkShareRecord in op.keyset.pendingTLKShares) {
+                [pendingTLKShares addObject:tlkShareRecord.share];
+            }
+            secnotice("octagon-ckks", "Have %u tlk shares, %u pending tlk shares",
+                      (uint32_t)op.keyset.tlkShares.count,
+                      (uint32_t)op.keyset.pendingTLKShares.count);
+        }
+
+        self.viewKeySets = viewKeySets;
+        self.incompleteKeySets = ckksBrokenKeySets;
+        self.tlkShares = tlkShares;
+        self.pendingTLKShares = pendingTLKShares;
+        self.viewsTimedOutWithoutKeysets = viewsMIA;
+
+        secnotice("octagon-ckks", "Fetched %d key sets, %d broken key sets, %d tlk shares, %d pendingTLKShares, and %d views timing out",
+                  (int)self.viewKeySets.count,
+                  (int)self.incompleteKeySets.count,
+                  (int)self.tlkShares.count,
+                  (int)self.pendingTLKShares.count,
+                  (int)self.viewsTimedOutWithoutKeysets.count);
+    }];
 
     for(CKKSResultOperation<CKKSKeySetProviderOperationProtocol>* op in keyOps) {
         [proceedWithKeys addDependency: op];
index 3b63b205451684b52ebd62021a1afc788236163f..c7cbdacf443aedbc047ef926beb45a2266563f08 100644 (file)
@@ -57,8 +57,9 @@
     WEAKIFY(self);
     [self.deps.cuttlefishXPCWrapper fetchCurrentPolicyWithContainer:self.deps.containerName
                                                             context:self.deps.contextID
-                                                              reply:^(NSSet<NSString*>* _Nullable viewList,
-                                                                      TPPolicy* _Nullable policy,
+                                                    modelIDOverride:nil
+                                                              reply:^(TPSyncingPolicy* _Nullable syncingPolicy,
+                                                                      TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers,
                                                                       NSError* _Nullable error) {
         STRONGIFY(self);
         [[CKKSAnalytics logger] logResultForEvent:OctagonEventFetchViews hardFailure:true result:error];
             return;
         }
 
-        secnotice("octagon-ckks", "Received policy %@ with view list: %@", policy, viewList);
+        secnotice("octagon-ckks", "Received syncing policy %@ with view list: %@", syncingPolicy, syncingPolicy.viewList);
         // Write them down before continuing
 
         NSError* stateError = nil;
         [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
-            metadata.syncingViews = [viewList mutableCopy];
-            [metadata setTPPolicy:policy];
+            [metadata setTPSyncingPolicy:syncingPolicy];
             return metadata;
         } error:&stateError];
 
@@ -85,7 +85,7 @@
             return;
         }
 
-        [self.deps.viewManager setSyncingViews:viewList sortingPolicy:policy];
+        [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
 
         self.nextState = self.intendedState;
     }];
index a70959290dc6543b64214e10eef38ec0d9c855bf..073d2bd202337e6bc618ca20bfdc9be515f04f18 100644 (file)
@@ -55,7 +55,7 @@ NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType);
 - (BOOL)clearFollowUp:(OTFollowupContextType)contextType
                 error:(NSError **)error;
 
-- (NSDictionary *)sysdiagnoseStatus;
+- (NSDictionary *_Nullable)sysdiagnoseStatus;
 - (NSDictionary<NSString*,NSNumber*> *)sfaStatus;
 @end
 
index 649dc59d0437b7aa9e32b23295f77d46b0035f0e..5c58c5a8e467fb1fa60d5500d8baf1dd23c748f0 100644 (file)
@@ -133,7 +133,7 @@ NSString* OTFollowupContextTypeToString(OTFollowupContextType contextType)
 }
 
 
-- (NSDictionary *)sysdiagnoseStatus
+- (NSDictionary *_Nullable)sysdiagnoseStatus
 {
     NSMutableDictionary *pendingCFUs = nil;
 
index c5a9addba3b2b28c740c74c077a170df6e2f4538..325bf4b96e9f12a0406ca725383d0ba773abdcce 100644 (file)
@@ -38,14 +38,12 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
                        intendedState:(OctagonState*)intendedState
                    ckksConflictState:(OctagonState*)ckksConflictState
-                          errorState:(OctagonState*)errorState
-                         voucherData:(NSData*)voucherData
-                          voucherSig:(NSData*)voucherSig;
+                          errorState:(OctagonState*)errorState;
 
-@property (nonatomic) NSData* voucherData;
-@property (nonatomic) NSData* voucherSig;
+@property (nullable) NSData* voucherData;
+@property (nullable) NSData* voucherSig;
 
-@property (nonatomic) NSString* peerID;
+@property (nullable) NSString* peerID;
 
 @end
 
index 6a7c5b97970d8febebcda9e4c2be17c0294138e8..d2d6a33258703780fa85ffd2fa231901f39de54b 100644 (file)
@@ -53,8 +53,6 @@
                        intendedState:(OctagonState*)intendedState
                    ckksConflictState:(OctagonState*)ckksConflictState
                           errorState:(OctagonState*)errorState
-                         voucherData:(NSData*)voucherData
-                          voucherSig:(NSData*)voucherSig
 {
     if((self = [super init])) {
         _deps = dependencies;
         _nextState = errorState;
         _ckksConflictState = ckksConflictState;
 
-        _voucherData = voucherData;
-        _voucherSig = voucherSig;
+        _peerID = nil;
+        _voucherData = nil;
+        _voucherSig = nil;
     }
     return self;
 }
 
 - (void)groupStart
 {
-    secnotice("octagon", "joining");
+    // Load the voucher from the state handler
+    NSError* error = nil;
+    OTAccountMetadataClassC* metadata = [self.deps.stateHolder loadOrCreateAccountMetadata:&error];
+
+    if(!metadata.voucher || !metadata.voucherSignature || error) {
+        secnotice("octagon", "No voucher available: %@", error);
+        self.error = error;
+        return;
+    }
+
+    self.voucherData = metadata.voucher;
+    self.voucherSig = metadata.voucherSignature;
+
+    secnotice("octagon", "joining with a voucher: %@", self.voucherData);
 
     self.finishedOp = [[NSOperation alloc] init];
     [self dependOnBeforeGroupFinished:self.finishedOp];
 
     WEAKIFY(self);
 
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:NO];
+    // We only care about TLKs that are ready for upload. Don't wait long.
+    fetchKeysOp.desiredTimeout = 2*NSEC_PER_SEC;
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"vouch-with-keys"
                                       preapprovedKeys:publicSigningSPKIs
                                                 reply:^(NSString * _Nullable peerID,
                                                         NSArray<CKRecord*>* keyHierarchyRecords,
-                                                        NSSet<NSString*>* _Nullable syncingViews,
-                                                        TPPolicy* _Nullable syncingPolicy,
+                                                        TPSyncingPolicy* _Nullable syncingPolicy,
                                                         NSError * _Nullable error) {
             STRONGIFY(self);
             if(error){
 
                 [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventJoinWithVoucher];
 
-                [self.deps.viewManager setSyncingViews:syncingViews sortingPolicy:syncingPolicy];
+                [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
 
                 NSError* localError = nil;
                 BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
                     metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED;
                     metadata.peerID = peerID;
-                    metadata.syncingViews = [syncingViews mutableCopy];
-                    [metadata setTPPolicy:syncingPolicy];
+
+                    metadata.voucher = nil;
+                    metadata.voucherSignature = nil;
+
+                    [metadata setTPSyncingPolicy:syncingPolicy];
                     return metadata;
                 } error:&localError];
                 if(!persisted || localError) {
index f744254011168cc32a951a6ed7f0c45485309cd2..e0150f3a37ebddd52c4b50f3e9e58b92a6f3ba59 100644 (file)
@@ -42,8 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
                                epoch:(uint64_t)epoch
                          isInitiator:(BOOL)isInitiator
 {
-    self = [super init];
-    if (self){
+    if ((self = [super init])) {
         self.protocolType = protocolType;
         self.uniqueDeviceID = uniqueDeviceID;
         self.uniqueClientID = uniqueClientID;
@@ -71,8 +70,7 @@ NS_ASSUME_NONNULL_BEGIN
 }
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)decoder {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _protocolType = [decoder decodeObjectOfClass:[NSString class] forKey:@"protocolType"];
         _uniqueClientID = [decoder decodeObjectOfClass:[NSString class] forKey:@"uniqueClientID"];
         _uniqueDeviceID = [decoder decodeObjectOfClass:[NSString class] forKey:@"uniqueDeviceID"];
index 90011df7c136f6f20a311aab94a65f2153a0b547..65f7c0df55301f163f28939f9e22ca33ebe6d4f4 100644 (file)
 
 #import "keychain/ckks/CKKSGroupOperation.h"
 #import "keychain/ot/OctagonStateMachineHelpers.h"
-#import "keychain/ot/CuttlefishXPCWrapper.h"
+#import "keychain/ot/OTOperationDependencies.h"
+
+@class OTOperationDependencies;
 
 NS_ASSUME_NONNULL_BEGIN
 
 @interface OTLocalResetOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
 
-- (instancetype)init:(NSString*)containerName
-           contextID:(NSString*)contextID
-       intendedState:(OctagonState*)intendedState
-          errorState:(OctagonState*)errorState
-cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper;
+- (instancetype)initWithDependencies:(OTOperationDependencies*)deps
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
 @end
 
 NS_ASSUME_NONNULL_END
index 30cd3608d24eb16dbfa35ccf9a5abc5def8dcbe5..7fcf57e6834a4686f19837c0352ffe0454438da2 100644 (file)
@@ -30,9 +30,8 @@
 #import "utilities/debugging.h"
 
 @interface OTLocalResetOperation ()
-@property NSString* containerName;
-@property NSString* contextID;
-@property CuttlefishXPCWrapper* cuttlefishXPCWrapper;
+@property OTOperationDependencies* deps;
+
 @property NSOperation* finishedOp;
 @end
 
 @synthesize intendedState = _intendedState;
 @synthesize nextState = _nextState;
 
-- (instancetype)init:(NSString*)containerName
-           contextID:(NSString*)contextID
-       intendedState:(OctagonState*)intendedState
-          errorState:(OctagonState*)errorState
-cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
+- (instancetype)initWithDependencies:(OTOperationDependencies *)deps
+                       intendedState:(OctagonState *)intendedState
+                          errorState:(OctagonState *)errorState
 {
     if((self = [super init])) {
         _intendedState = intendedState;
         _nextState = errorState;
 
-        _containerName = containerName;
-        _contextID = contextID;
-        _cuttlefishXPCWrapper = cuttlefishXPCWrapper;
+        _deps = deps;
     }
     return self;
 }
@@ -65,16 +60,34 @@ cuttlefishXPCWrapper:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
     [self dependOnBeforeGroupFinished:self.finishedOp];
 
     WEAKIFY(self);
-    [self.cuttlefishXPCWrapper localResetWithContainer:self.containerName
-                                               context:self.contextID
-                                                 reply:^(NSError * _Nullable error) {
+    [self.deps.cuttlefishXPCWrapper localResetWithContainer:self.deps.containerName
+                                                    context:self.deps.contextID
+                                                      reply:^(NSError * _Nullable error) {
             STRONGIFY(self);
             if(error) {
-                secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.containerName, self.contextID, error);
+                secnotice("octagon", "Unable to reset local cuttlefish for (%@,%@): %@", self.deps.containerName, self.deps.contextID, error);
                 self.error = error;
             } else {
                 secnotice("octagon", "Successfully reset local cuttlefish");
-                self.nextState = self.intendedState;
+
+                NSError* localError = nil;
+                [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
+                    metadata.trustState = OTAccountMetadataClassC_TrustState_UNKNOWN;
+                    metadata.peerID = nil;
+                    metadata.syncingPolicy = nil;
+
+                    // Don't touch the CDP or account states; those can carry over
+
+                    return metadata;
+                } error:&localError];
+
+                if(localError) {
+                    secnotice("octagon", "Error resetting local account state: %@", localError);
+
+                } else {
+                    secnotice("octagon", "Successfully reset local account state");
+                    self.nextState = self.intendedState;
+                }
             }
 
             [self runBeforeGroupFinished:self.finishedOp];
index d8fcd385e5a205d74de85e5e4c407b5c6dd0e9c4..662362eafdf031f50f8953bdc839edfa3f187774 100644 (file)
@@ -148,6 +148,10 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithSOSAdapter:(id<OTSOSAdapter>)sosAdapter
                   lockStateTracker:(CKKSLockStateTracker*)lockStateTracker
          cloudKitClassDependencies:(CKKSCloudKitClassDependencies*)cloudKitClassDependencies;
+
+- (void)invalidateEscrowCache:(NSString * _Nullable)containerName
+                    contextID:(NSString*)contextID
+                        reply:(nonnull void (^)(NSError * _Nullable error))reply;
 @end
 
 NS_ASSUME_NONNULL_END
index 79d43f93ed5f809909507c2de1a98175a90f1650..20359984ed5a520f29669825eaf25ffe567e03b7 100644 (file)
@@ -270,6 +270,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
         return nil;
     }
 
+    if([CKDatabase class] == nil) {
+        // CloudKit is not linked. We cannot bring Octagon up.
+        secerror("Octagon: CloudKit.framework appears to not be linked. Cannot create an Octagon manager (on pain of crash).");
+        return nil;
+    }
+
     return [self resetManager:false to:nil];
 }
 
@@ -674,6 +680,7 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
                                                       NSString * _Nullable peerID,
                                                       NSDictionary<NSString *,NSNumber *> * _Nullable peerCountByModelID,
                                                       BOOL isExcluded,
+                                                      BOOL isLocked,
                                                       NSError * _Nullable error) {
         // Our clients don't need the whole breakout of peers, so just count for them
         long peerCount = 0;
@@ -716,6 +723,7 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
                                                   NSString* egoPeerID,
                                                   NSDictionary<NSString *,NSNumber *> * _Nullable peerCountByModelID,
                                                   BOOL isExcluded,
+                                                  BOOL isLocked,
                                                   NSError * _Nullable error) {
         reply(status, error);
     }];
@@ -1022,6 +1030,9 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
         values[OctagonAnalyticCDPBitStatus] = metadata? @(metadata.cdpState) : nil;
         values[OctagonAnalyticsTrustState] = metadata ? @(metadata.trustState) : nil;
 
+        TPSyncingPolicy* syncingPolicy = [metadata getTPSyncingPolicy];
+        values[OctagonAnalyticsUserControllableViewsSyncing] = syncingPolicy ? @(syncingPolicy.syncUserControllableViewsAsBoolean) : nil;
+
         NSDate* healthCheck = [cuttlefishContext currentMemoizedLastHealthCheck];
         values[OctagonAnalyticsLastHealthCheck] = @([CKKSAnalytics fuzzyDaysSinceDate:healthCheck]);
 
@@ -1147,7 +1158,7 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
     SFAnalyticsActivityTracker *tracker = [[self.loggerClass logger] startLogSystemMetricsForActivityNamed:OctagonActivitySetRecoveryKey];
 
     if (!self.sosEnabledForPlatform) {
-        secnotice("octagon-recovery", "Device is considered a limited peer, cannot enroll recovery key in Octagon");
+        secnotice("octagon-recovery", "Device does not participate in SOS; cannot enroll recovery key in Octagon");
         NSError* notFullPeerError = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorLimitedPeer userInfo:@{NSLocalizedDescriptionKey : @"Device is considered a limited peer, cannot enroll recovery key in Octagon"}];
         [tracker stopWithEvent:OctagonEventRecoveryKey result:notFullPeerError];
         reply(notFullPeerError);
@@ -1218,7 +1229,16 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
     [cfshContext joinWithRecoveryKey:recoveryKey reply:^(NSError *error) {
         if ((error.code == TrustedPeersHelperErrorCodeNotEnrolled || error.code == TrustedPeersHelperErrorCodeUntrustedRecoveryKeys)
             && [error.domain isEqualToString:TrustedPeersHelperErrorDomain]){
-            // If we hit either of these errors, let's reset and establish octagon then enroll this recovery key in the new circle
+            // If we hit either of these errors, and the local device thinks it should be able to set a recovery key,
+            // let's reset and establish octagon then enroll this recovery key in the new circle
+
+            if (!self.sosEnabledForPlatform) {
+                secerror("octagon: recovery key is not enrolled in octagon, and current device can't set recovery keys");
+                [tracker stopWithEvent:OctagonEventJoinRecoveryKeyCircleResetFailed result:error];
+                reply(error);
+                return;
+            }
+
             secerror("octagon, recovery key is not enrolled in octagon, resetting octagon circle");
             [[self.loggerClass logger] logResultForEvent:OctagonEventJoinRecoveryKeyCircleReset hardFailure:NO result:error];
 
@@ -1231,25 +1251,19 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
                 } else {
                     // Now enroll the recovery key
                     secnotice("octagon", "attempting enrolling recovery key");
-                    if (self.sosEnabledForPlatform) {
-                        [self createRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:^(NSError *enrollError) {
-                            if(enrollError){
-                                secerror("octagon, failed to enroll new recovery key: %@", enrollError);
-                                [tracker stopWithEvent:OctagonEventJoinRecoveryKeyEnrollFailed result:enrollError];
-                                reply(enrollError);
-                                return;
-                            }else{
-                                secnotice("octagon", "successfully enrolled recovery key");
-                                [tracker stopWithEvent:OctagonEventRecoveryKey result:nil];
-                                reply (nil);
-                                return;
-                            }
-                        }];
-                    } else {
-                        secnotice("octagon", "Limited Peer, can't enroll recovery key");
-                        reply (nil);
-                        return;
-                    }
+                    [self createRecoveryKey:containerName contextID:contextID recoveryKey:recoveryKey reply:^(NSError *enrollError) {
+                        if(enrollError){
+                            secerror("octagon, failed to enroll new recovery key: %@", enrollError);
+                            [tracker stopWithEvent:OctagonEventJoinRecoveryKeyEnrollFailed result:enrollError];
+                            reply(enrollError);
+                            return;
+                        }else{
+                            secnotice("octagon", "successfully enrolled recovery key");
+                            [tracker stopWithEvent:OctagonEventRecoveryKey result:nil];
+                            reply (nil);
+                            return;
+                        }
+                    }];
                 }
             }];
         } else {
@@ -1324,27 +1338,12 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
     return true;
 }
 
-- (void)attemptSosUpgrade:(NSString* _Nullable)containerName
-                  context:(NSString*)context
-                    reply:(void (^)(NSError* error))reply
-
-{
-    secnotice("octagon-sos", "Attempting sos upgrade");
-    OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:context];
-
-    [cfshContext startOctagonStateMachine];
-
-    [cfshContext attemptSOSUpgrade:^(NSError *error) {
-        reply(error);
-    }];
-}
-
 - (void)waitForOctagonUpgrade:(NSString* _Nullable)containerName
                       context:(NSString*)context
                         reply:(void (^)(NSError* error))reply
 
 {
-    secnotice("octagon-sos", "waitForOctagonUpgrade");
+    secnotice("octagon-sos", "Attempting wait for octagon upgrade");
     OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:context];
 
     [cfshContext startOctagonStateMachine];
@@ -1382,8 +1381,6 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
                   contextName:(NSString *)contextName
                         reply:(void (^)(NSError *error))reply
 {
-    OTCuttlefishContext *cuttlefishContext = [self contextForContainerName:containerName contextID:contextName];
-
     NSString* metricName = [NSString stringWithFormat:@"%@%@", OctagonAnalyticsCDPStateRun, type];
     NSString* countName = [NSString stringWithFormat:@"%@%@Tries", OctagonAnalyticsCDPStateRun, type];
 
@@ -1436,7 +1433,6 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
     }];
 }
 
-
 - (void)getCDPStatus:(NSString * _Nullable)containerName
            contextID:(nonnull NSString *)contextID
                reply:(nonnull void (^)(OTCDPStatus, NSError * _Nullable))reply {
@@ -1485,6 +1481,117 @@ static NSString* const kOTRampZoneName = @"metadata_zone";
     reply(localError);
 }
 
+- (void)fetchEscrowRecords:(NSString * _Nullable)containerName
+                 contextID:(NSString*)contextID
+                forceFetch:(BOOL)forceFetch
+                     reply:(nonnull void (^)(NSArray<NSData *> * _Nullable records,
+                                             NSError * _Nullable error))reply {
+
+    secnotice("octagon-fetch-escrow-records", "fetching records");
+    if(!containerName) {
+        containerName = OTCKContainerName;
+    }
+
+    OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID];
+
+    if(!cfshContext) {
+        reply(nil, [NSError errorWithDomain:OctagonErrorDomain
+                                       code:OTErrorNoSuchContext
+                                description:[NSString stringWithFormat:@"No context for (%@,%@)", containerName, contextID]]);
+        return;
+    }
+
+    [cfshContext rpcFetchAllViableEscrowRecords:forceFetch reply:^(NSArray<NSData *> * _Nullable records, NSError * _Nullable error) {
+        if(error) {
+            secerror("octagon-fetch-escrow-records: error fetching records: %@", error);
+            reply(nil, error);
+            return;
+        }
+        secnotice("octagon-fetch-escrow-records", "successfully fetched records");
+        reply(records, nil);
+    }];
+}
+
+- (void)invalidateEscrowCache:(NSString * _Nullable)containerName
+                    contextID:(NSString*)contextID
+                        reply:(nonnull void (^)(NSError * _Nullable error))reply {
+
+    secnotice("octagon-remove-escrow-cache", "beginning removing escrow cache!");
+    if(!containerName) {
+        containerName = OTCKContainerName;
+    }
+
+    OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID];
+
+    if(!cfshContext) {
+        reply([NSError errorWithDomain:OctagonErrorDomain
+                                  code:OTErrorNoSuchContext
+                           description:[NSString stringWithFormat:@"No context for (%@,%@)", containerName, contextID]]);
+        return;
+    }
+
+    [cfshContext rpcInvalidateEscrowCache:^(NSError * _Nullable invalidateError) {
+        if(invalidateError) {
+            secerror("octagon-remove-escrow-cache: error invalidating escrow cache: %@", invalidateError);
+            reply(invalidateError);
+            return;
+        }
+        secnotice("octagon-remove-escrow-caches", "successfully invalidated escrow cache");
+        reply(nil);
+    }];
+}
+
+- (void)setUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                 contextID:(NSString*)contextID
+                                   enabled:(BOOL)enabled
+                                     reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
+{
+    OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID];
+
+    if(!cfshContext) {
+        reply(NO, [NSError errorWithDomain:OctagonErrorDomain
+                                      code:OTErrorNoSuchContext
+                               description:[NSString stringWithFormat:@"No context for (%@,%@)", containerName, contextID]]);
+        return;
+    }
+
+    [cfshContext rpcSetUserControllableViewsSyncingStatus:enabled reply:^(BOOL areSyncing, NSError * _Nullable error) {
+        if(error) {
+            secerror("octagon-user-controllable-views: error setting status: %@", error);
+            reply(NO, error);
+            return;
+        }
+
+        secnotice("octagon-user-controllable-views", "successfully set status to: %@", areSyncing ? @"enabled" : @"paused");
+        reply(areSyncing, nil);
+    }];
+}
+
+- (void)fetchUserControllableViewsSyncStatus:(NSString* _Nullable)containerName
+                                   contextID:(NSString*)contextID
+                                       reply:(void (^)(BOOL nowSyncing, NSError* _Nullable error))reply
+{
+    OTCuttlefishContext* cfshContext = [self contextForContainerName:containerName contextID:contextID];
+
+    if(!cfshContext) {
+        reply(NO, [NSError errorWithDomain:OctagonErrorDomain
+                                      code:OTErrorNoSuchContext
+                               description:[NSString stringWithFormat:@"No context for (%@,%@)", containerName, contextID]]);
+        return;
+    }
+
+    [cfshContext rpcFetchUserControllableViewsSyncingStatus:^(BOOL areSyncing, NSError * _Nullable error) {
+        if(error) {
+            secerror("octagon-user-controllable-views: error fetching status: %@", error);
+            reply(NO, error);
+            return;
+        }
+
+        secerror("octagon-user-controllable-views: succesfully fetched status as: %@", areSyncing ? @"enabled" : @"paused");
+        reply(areSyncing, nil);
+    }];
+}
+
 @end
 
 #endif
diff --git a/keychain/ot/OTModifyUserControllableViewStatusOperation.h b/keychain/ot/OTModifyUserControllableViewStatusOperation.h
new file mode 100644 (file)
index 0000000..17ccd75
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 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 <Foundation/Foundation.h>
+
+#import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ot/OTOperationDependencies.h"
+#import "keychain/ot/OTOperationDependencies.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OTModifyUserControllableViewStatusOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+
+// Pass 'unknown' to intendedViewStatus to set your peer view status to the opinion of your peers
+- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                  intendedViewStatus:(TPPBPeerStableInfo_UserControllableViewStatus)intendedViewStatus
+                       intendedState:(OctagonState*)intendedState
+                    peerMissingState:(OctagonState*)peerMissingState
+                          errorState:(OctagonState*)errorState;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ot/OTModifyUserControllableViewStatusOperation.m b/keychain/ot/OTModifyUserControllableViewStatusOperation.m
new file mode 100644 (file)
index 0000000..c0e77b2
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2020 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 <TrustedPeers/TrustedPeers.h>
+#import "keychain/ckks/CKKSAnalytics.h"
+#import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
+#import "keychain/ot/OTModifyUserControllableViewStatusOperation.h"
+#import "keychain/ot/OTStates.h"
+#import "keychain/ot/ObjCImprovements.h"
+#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
+
+@interface OTModifyUserControllableViewStatusOperation ()
+@property OTOperationDependencies* deps;
+
+@property OctagonState* peerMissingState;
+
+@property TPPBPeerStableInfo_UserControllableViewStatus intendedViewStatus;
+@end
+
+@implementation OTModifyUserControllableViewStatusOperation
+@synthesize intendedState = _intendedState;
+@synthesize nextState = _nextState;
+
+- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                  intendedViewStatus:(TPPBPeerStableInfo_UserControllableViewStatus)intendedViewStatus
+                       intendedState:(OctagonState*)intendedState
+                    peerMissingState:(OctagonState*)peerMissingState
+                          errorState:(OctagonState*)errorState
+{
+    if ((self = [super init])) {
+        _deps = dependencies;
+
+        _intendedViewStatus = intendedViewStatus;
+
+        _intendedState = intendedState;
+        _peerMissingState = peerMissingState;
+        _nextState = errorState;
+    }
+    return self;
+}
+
+- (void)groupStart
+{
+
+    if(self.intendedViewStatus == TPPBPeerStableInfo_UserControllableViewStatus_FOLLOWING) {
+#if TARGET_OS_WATCH || TARGET_OS_TV
+        // Watches and TVs want to be able to set the FOLLOWING state
+        [self performWithStatus:self.intendedViewStatus];
+#else
+        // For other platforms, we want to determine the actual state by asking
+        WEAKIFY(self);
+
+        // Should we ask SOS? Or Octagon?
+        if(self.deps.sosAdapter.sosEnabled) {
+            NSError* error = nil;
+            BOOL safariViewEnabled = [self.deps.sosAdapter safariViewSyncingEnabled:&error];
+
+            if(error) {
+                secerror("octagon-ckks: Unable to fetch SOS Safari view status: %@", error);
+                self.error = error;
+                return;
+            }
+
+            secnotice("octagon-ckks", "Currently SOS believes the safari view is '%@'", safariViewEnabled ? @"enabled" : @"disabled");
+
+            TPPBPeerStableInfo_UserControllableViewStatus status = safariViewEnabled ?
+                TPPBPeerStableInfo_UserControllableViewStatus_ENABLED :
+                TPPBPeerStableInfo_UserControllableViewStatus_DISABLED;
+
+            [self performWithStatus:status];
+            return;
+        }
+
+        secnotice("octagon-ckks", "Determining peers' user-controllable views policy");
+
+        [self.deps.cuttlefishXPCWrapper fetchCurrentPolicyWithContainer:self.deps.containerName
+                                                                context:self.deps.contextID
+                                                        modelIDOverride:nil
+                                                                  reply:^(TPSyncingPolicy* _Nullable syncingPolicy,
+                                                                          TPPBPeerStableInfo_UserControllableViewStatus userControllableViewStatusOfPeers,
+                                                                          NSError* _Nullable error) {
+            STRONGIFY(self);
+
+            if(error) {
+                secnotice("octagon-ckks", "Determining peers' user-controllable views policy failed: %@", error);
+                self.error = error;
+                return;
+            }
+
+            secnotice("octagon-ckks", "Retrieved peers' user-controllable views policy as: %@",
+                      TPPBPeerStableInfo_UserControllableViewStatusAsString(userControllableViewStatusOfPeers));
+
+            [self performWithStatus:userControllableViewStatusOfPeers];
+            return;
+        }];
+#endif
+
+    } else {
+        [self performWithStatus:self.intendedViewStatus];
+    }
+}
+
+- (void)performWithStatus:(TPPBPeerStableInfo_UserControllableViewStatus)intendedViewStatus
+{
+    WEAKIFY(self);
+
+    secnotice("octagon-ckks", "Setting user-controllable views to %@", TPPBPeerStableInfo_UserControllableViewStatusAsString(self.intendedViewStatus));
+
+    [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
+                                                context:self.deps.contextID
+                                             deviceName:nil
+                                           serialNumber:nil
+                                              osVersion:nil
+                                          policyVersion:nil
+                                          policySecrets:nil
+                              syncUserControllableViews:[NSNumber numberWithInt:intendedViewStatus]
+                                                  reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, NSError* error) {
+        STRONGIFY(self);
+        if(error || !syncingPolicy) {
+            secerror("octagon-ckks: setting user-controllable views status errored: %@", error);
+            self.error = error;
+
+            if([self.deps.lockStateTracker isLockedError:self.error]) {
+                secnotice("octagon-ckks", "Updating user-controllable view status failed because of lock state, will retry once unlocked: %@", self.error);
+                OctagonPendingFlag* pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptUserControllableViewStatusUpgrade
+                                                                                conditions:OctagonPendingConditionsDeviceUnlocked];
+
+                [self.deps.flagHandler handlePendingFlag:pendingFlag];
+            }
+            if(peerState.peerStatus & (TPPeerStatusExcluded | TPPeerStatusUnknown)) {
+                secnotice("octagon-ckks", "Updating user-controllable view status failed because our self peer is excluded or missing");
+                self.nextState = self.peerMissingState;
+            }
+            return;
+        }
+
+        secnotice("octagon-ckks", "Received syncing policy %@ with view list: %@", syncingPolicy, syncingPolicy.viewList);
+
+        NSError* stateError = nil;
+        [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
+            [metadata setTPSyncingPolicy:syncingPolicy];
+            return metadata;
+        } error:&stateError];
+
+        if(stateError) {
+            secerror("octagon: failed to save policy+views: %@", stateError);
+            self.error = stateError;
+            return;
+        }
+
+        [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
+
+        self.nextState = self.intendedState;
+    }];
+}
+
+@end
+
+#endif // OCTAGON
diff --git a/keychain/ot/OTPreloadOctagonKeysOperation.h b/keychain/ot/OTPreloadOctagonKeysOperation.h
new file mode 100644 (file)
index 0000000..cd2e7a6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 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 <Foundation/Foundation.h>
+
+#import "keychain/ckks/CKKSGroupOperation.h"
+#import "keychain/ot/OctagonStateMachineHelpers.h"
+#import "keychain/ot/OTOperationDependencies.h"
+
+@class OTCuttlefishContext;
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface OTPreloadOctagonKeysOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property OctagonState* nextState;
+- (instancetype)init NS_UNAVAILABLE;
+- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+#endif // OCTAGON
diff --git a/keychain/ot/OTPreloadOctagonKeysOperation.m b/keychain/ot/OTPreloadOctagonKeysOperation.m
new file mode 100644 (file)
index 0000000..58952f9
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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@
+ */
+
+#if OCTAGON
+
+#import <utilities/debugging.h>
+
+#import <SecurityFoundation/SecurityFoundation.h>
+#import "keychain/ot/OTPreloadOctagonKeysOperation.h"
+#import "keychain/ot/OTClientStateMachine.h"
+#import "keychain/ot/OTCuttlefishContext.h"
+#import "keychain/ot/OTFetchCKKSKeysOperation.h"
+#import "keychain/ot/OTDefines.h"
+#import "keychain/ot/OTConstants.h"
+#import "keychain/ot/OctagonCKKSPeerAdapter.h"
+#import "utilities/debugging.h"
+#import <Security/SecKey.h>
+#import <Security/SecKeyPriv.h>
+
+#import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
+#import "keychain/ot/ObjCImprovements.h"
+#import "keychain/securityd/SOSCloudCircleServer.h"
+
+@interface OTPreloadOctagonKeysOperation ()
+@property OTOperationDependencies* deps;
+
+@property NSOperation* finishOp;
+@end
+
+@implementation OTPreloadOctagonKeysOperation
+@synthesize intendedState = _intendedState;
+
+- (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
+                       intendedState:(OctagonState*)intendedState
+                          errorState:(OctagonState*)errorState
+{
+    if((self = [super init])) {
+        _deps = dependencies;
+        _intendedState = intendedState;
+        _nextState = errorState;
+    }
+    return self;
+}
+
+- (void)groupStart
+{
+    secnotice("octagon-preload-keys", "Beginning operation that preloads the SOSAccount with newly created Octagon Keys");
+
+    self.finishOp = [[NSOperation alloc] init];
+    [self dependOnBeforeGroupFinished:self.finishOp];
+
+    if(!self.deps.sosAdapter.sosEnabled) {
+        self.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorSOSAdapter userInfo:@{NSLocalizedDescriptionKey : @"sos adapter not enabled"}];
+        [self runBeforeGroupFinished:self.finishOp];
+        return;
+    }
+
+    NSError* fetchSelfPeersError = nil;
+    CKKSSelves *selfPeers = [self.deps.octagonAdapter fetchSelfPeers:&fetchSelfPeersError];
+    if((!selfPeers) || fetchSelfPeersError) {
+        secnotice("octagon-preload-keys", "failed to retrieve self peers: %@", fetchSelfPeersError);
+        self.error = fetchSelfPeersError;
+        [self runBeforeGroupFinished:self.finishOp];
+        return;
+    }
+
+    id<CKKSSelfPeer> currentSelfPeer = selfPeers.currentSelf;
+    if(currentSelfPeer == nil) {
+        secnotice("octagon-preload-keys", "failed to retrieve current self");
+        self.error = [NSError errorWithDomain:OctagonErrorDomain code:OTErrorOctagonAdapter userInfo: @{ NSLocalizedDescriptionKey : @"failed to retrieve current self"}];
+        [self runBeforeGroupFinished:self.finishOp];
+        return;
+    }
+
+    NSError* updateError = nil;
+    BOOL ret = [self.deps.sosAdapter preloadOctagonKeySetOnAccount:currentSelfPeer error:&updateError];
+    if(!ret) {
+        self.error = updateError;
+        [self runBeforeGroupFinished:self.finishOp];
+        return;
+    }
+
+    self.nextState = self.intendedState;
+    [self runBeforeGroupFinished:self.finishOp];
+}
+
+@end
+
+#endif // OCTAGON
index d0e0ca45c8434360efa9f5778193b07b3d8e5e12..f6de077b91eea14257148cac0135e891fe4db245 100644 (file)
         secerror("octagon: failed to save 'attempted join' state: %@", persistError);
     }
 
+    // Note: we pass syncUserControllableViews as FOLLOWING here, with the intention that
+    // it will be set later, when this peer decides who it trusts and accepts their value.
+
     [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName
                                                  context:self.deps.contextID
                                                    epoch:self.epoch
                                                osVersion:self.deviceInfo.osVersion
                                            policyVersion:self.policyOverride
                                            policySecrets:nil
+                               syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_FOLLOWING
                              signingPrivKeyPersistentRef:signingKeyPersistRef
                                  encPrivKeyPersistentRef:encryptionKeyPersistRef
                                                    reply:^(NSString * _Nullable peerID,
                                                            NSData * _Nullable permanentInfoSig,
                                                            NSData * _Nullable stableInfo,
                                                            NSData * _Nullable stableInfoSig,
-                                                           NSSet<NSString*>* _Nullable syncingViews,
-                                                           TPPolicy* _Nullable syncingPolicy,
+                                                           TPSyncingPolicy* _Nullable syncingPolicy,
                                                            NSError * _Nullable error) {
             STRONGIFY(self);
             [[CKKSAnalytics logger] logResultForEvent:OctagonEventPrepareIdentity hardFailure:true result:error];
 
                 NSError* localError = nil;
 
-                secnotice("octagon-ckks", "New syncing policy: %@ views: %@", syncingPolicy, syncingViews);
+                secnotice("octagon-ckks", "New syncing policy: %@ views: %@", syncingPolicy, syncingPolicy.viewList);
 
                 BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
                     metadata.peerID = peerID;
-                    metadata.syncingViews = [syncingViews mutableCopy];
-                    [metadata setTPPolicy:syncingPolicy];
 
+                    [metadata setTPSyncingPolicy:syncingPolicy];
                     return metadata;
                 } error:&localError];
 
                 }
 
                 // Let CKKS know of the new policy, so it can spin up
-                [self.deps.viewManager setSyncingViews:syncingViews sortingPolicy:syncingPolicy];
+                [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
 
                 self.nextState = self.intendedState;
                 [self runBeforeGroupFinished:self.finishedOp];
index 11fdfedbbd705398c156aecbac50595bac352057..72a7d8c3b555164278517123aaae813e49b24edb 100644 (file)
@@ -87,8 +87,7 @@ static NSString* kRampPriorityKey =         @"RampPriority";
 fetchRecordRecordsOperationClass:(Class<CKKSFetchRecordsOperation>) fetchRecordRecordsOperationClass
 
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         _container = container;
         _recordName = [recordName copy];
         _localSettingName = [localSettingName copy];
index 0f2dbc3879e9d7c59255dac8459f5fca68cc6d64..84883ebf552cca9bba34d8564ad7e5504bf657ca 100644 (file)
@@ -49,7 +49,8 @@
     }];
     [self dependOnBeforeGroupFinished:self.finishedOp];
 
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"continue-ckks-resets"
             if(incompleteKeySet.currentTLKPointer != nil &&
                incompleteKeySet.tlk == nil) {
 
-                BOOL otherDevicesAlive = [viewMatchingSet otherDevicesReportHavingTLKs:incompleteKeySet];
-                if(otherDevicesAlive) {
-                    secnotice("octagon-ckks", "Recently active devices claim to have TLK from key set %@; not scheduling for reset", incompleteKeySet);
-                } else {
-                    secnotice("octagon-ckks", "Key set %@ has no TLK; scheduling for reset", incompleteKeySet);
-                    [viewsToReset addObject:viewMatchingSet];
-                }
+                // We used to not reset the TLKs if there was a recent device claiming to have them, but
+                // in our Octagon-primary world, an Octagon reset should take precedence over existing Cloud-based data
+                secnotice("octagon-ckks", "Key set %@ has no TLK; scheduling for reset", incompleteKeySet);
+                [viewsToReset addObject:viewMatchingSet];
             }
         } else {
             secnotice("octagon-ckks", "Error loading key set %@; not attempting reset", incompleteKeySet);
 
         // Use an intermediary operation, just to ensure we have a timeout
         CKKSResultOperation* waitOp = [CKKSResultOperation named:[NSString stringWithFormat:@"wait-for-%@", view.zoneName]
-                                                       withBlock:^{}];
+                                                       withBlock:^{
+            secnotice("octagon-ckks", "Successfully reset %@", view);
+        }];
         [waitOp timeout:120*NSEC_PER_SEC];
         [waitOp addDependency:op];
         [self.operationQueue addOperation:waitOp];
index 976476e1bdd3c3e745fa41b29315fea8279df4a1..0403f382bbd8b08bd694a7c3596a211c3c14047f 100644 (file)
@@ -12,7 +12,11 @@ NS_ASSUME_NONNULL_BEGIN
 - (SOSCCStatus)circleStatus:(NSError**)error;
 - (id<CKKSSelfPeer> _Nullable)currentSOSSelf:(NSError**)error;
 - (NSSet<id<CKKSRemotePeerProtocol>>* _Nullable)fetchTrustedPeers:(NSError**)error;
-- (void)updateOctagonKeySetWithAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error;
+- (BOOL)updateOctagonKeySetWithAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error;
+- (BOOL)preloadOctagonKeySetOnAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error;
+- (BOOL)updateCKKS4AllStatus:(BOOL)status error:(NSError**)error;
+
+- (BOOL)safariViewSyncingEnabled:(NSError**)error __attribute__((swift_error(nonnull_error)));
 @end
 
 @interface OTSOSActualAdapter : NSObject <OTSOSAdapter>
index 4513d980a57c6d650f62975f064fc138551a162d..51ec88647621bfe5929a1e9aabade38983b946b2 100644 (file)
     return peerSet;
 }
 
-- (void)updateOctagonKeySetWithAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error {
+
+- (BOOL)preloadOctagonKeySetOnAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error {
+    // in case we don't have the keys, don't try to update them
+    if (currentSelfPeer.publicSigningKey.secKey == NULL || currentSelfPeer.publicEncryptionKey.secKey == NULL) {
+        secnotice("octagon-preload-keys", "no octagon keys available skipping updating SOS record");
+        return YES;
+    }
+
+    __block CFDataRef signingFullKey = CFBridgingRetain(currentSelfPeer.signingKey.keyData);
+    __block CFDataRef encryptionFullKey = CFBridgingRetain(currentSelfPeer.encryptionKey.keyData);
+    __block SecKeyRef octagonSigningPubSecKey = CFRetainSafe(currentSelfPeer.publicSigningKey.secKey);
+    __block SecKeyRef octagonEncryptionPubSecKey = CFRetainSafe(currentSelfPeer.publicEncryptionKey.secKey);
+    __block SecKeyRef signingFullKeyRef = CFRetainSafe(currentSelfPeer.signingKey.secKey);
+    __block SecKeyRef encryptionFullKeyRef = CFRetainSafe(currentSelfPeer.encryptionKey.secKey);
+
+    SFAnalyticsActivityTracker *tracker = [[[CKKSAnalytics class] logger] startLogSystemMetricsForActivityNamed:OctagonSOSAdapterUpdateKeys];
+
+    __block BOOL ret;
+    __block NSError *localError = nil;
+
+    /* WARNING! Please be very very careful passing keys to this routine.  Note the slightly different variations of keys*/
+    SOSCCPerformPreloadOfAllOctagonKeys(signingFullKey, encryptionFullKey,
+                                        signingFullKeyRef, encryptionFullKeyRef,
+                                        octagonSigningPubSecKey, octagonEncryptionPubSecKey,
+                                       ^(CFErrorRef cferror) {
+                                           [tracker stopWithEvent: OctagonSOSAdapterUpdateKeys result:(__bridge NSError * _Nullable)(cferror)];
+                                           if(cferror) {
+                                               secerror("octagon-preload-keys: failed to preload Octagon keys in SOS:%@", cferror);
+                                               ret = NO;
+                                               localError = (__bridge NSError *)cferror;
+                                           } else {
+                                               ret = YES;
+                                               secnotice("octagon-preload-keys", "successfully preloaded Octagon keys in SOS!");
+                                           }
+                                           CFRelease(signingFullKey);
+                                           CFRelease(encryptionFullKey);
+                                           CFRelease(octagonSigningPubSecKey);
+                                           CFRelease(octagonEncryptionPubSecKey);
+                                           CFRelease(signingFullKeyRef);
+                                           CFRelease(encryptionFullKeyRef);
+                                       });
+    if (error) {
+        *error = localError;
+    }
+    return ret;
+
+}
+
+- (BOOL)updateOctagonKeySetWithAccount:(id<CKKSSelfPeer>)currentSelfPeer error:(NSError**)error {
 
     // in case we don't have the keys, don't try to update them
     if (currentSelfPeer.publicSigningKey.secKey == NULL || currentSelfPeer.publicEncryptionKey.secKey == NULL) {
         secnotice("octagon-sos", "no octagon keys available skipping updating SOS record");
-        return;
+        return YES;
     }
 
     __block CFDataRef signingFullKey = CFBridgingRetain(currentSelfPeer.signingKey.keyData);
 
     SFAnalyticsActivityTracker *tracker = [[[CKKSAnalytics class] logger] startLogSystemMetricsForActivityNamed:OctagonSOSAdapterUpdateKeys];
 
+    __block BOOL ret;
+    __block NSError *localError = nil;
+
     /* WARNING! Please be very very careful passing keys to this routine.  Note the slightly different variations of keys*/
     SOSCCPerformUpdateOfAllOctagonKeys(signingFullKey, encryptionFullKey,
                                        signingPublicKey, encryptionPublicKey,
                                        octagonSigningPubSecKey, octagonEncryptionPubSecKey,
-                                       ^(CFErrorRef error) {
-                                           [tracker stopWithEvent: OctagonSOSAdapterUpdateKeys result:(__bridge NSError * _Nullable)(error)];
-                                           if(error){
-                                               secerror("octagon-sos: failed to update Octagon keys in SOS:%@", error);
-                                           }else {
+                                       ^(CFErrorRef cferror) {
+                                           [tracker stopWithEvent: OctagonSOSAdapterUpdateKeys result:(__bridge NSError * _Nullable)(cferror)];
+                                           if(cferror) {
+                                               secerror("octagon-sos: failed to update Octagon keys in SOS:%@", cferror);
+                                               ret = NO;
+                                               localError = (__bridge NSError *)cferror;
+                                           } else {
+                                               ret = YES;
                                                secnotice("octagon-sos", "successfully updated Octagon keys in SOS!");
                                            }
                                            CFRelease(signingFullKey);
                                            CFRelease(octagonSigningPubSecKey);
                                            CFRelease(octagonEncryptionPubSecKey);
                                        });
+    if (error) {
+        *error = localError;
+    }
+    return ret;
+}
+
+- (BOOL)updateCKKS4AllStatus:(BOOL)status error:(NSError**)error
+{
+    CFErrorRef cferror = nil;
+    bool result = SOSCCSetCKKS4AllStatus(status, &cferror);
+
+    NSError* localerror = CFBridgingRelease(cferror);
+
+    if(!result || localerror) {
+        secerror("octagon-sos: failed to update CKKS4All status in SOS: %@", localerror);
+    } else {
+        secnotice("octagon-sos", "successfully updated CKKS4All status in SOS to '%@'", status ? @"supported" : @"not supported");
+    }
+
+    if(error && localerror) {
+        *error = localerror;
+    }
+    return result;
 }
 
 - (void)registerForPeerChangeUpdates:(nonnull id<CKKSPeerUpdateListener>)listener {
 
     return result;
 }
+
+- (BOOL)safariViewSyncingEnabled:(NSError**)error
+{
+    CFErrorRef viewCFError = NULL;
+    SOSViewResultCode result = SOSCCView(kSOSViewAutofillPasswords, kSOSCCViewQuery, &viewCFError);
+
+    if(viewCFError) {
+        if(error) {
+            *error = CFBridgingRelease(viewCFError);
+        } else {
+            CFReleaseNull(viewCFError);
+        }
+        return NO;
+    }
+
+    return result == kSOSCCViewMember;
+}
 @end
 
 @implementation OTSOSMissingAdapter
     return nil;
 }
 
-- (void)updateOctagonKeySetWithAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
+- (BOOL)updateOctagonKeySetWithAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
     if(error) {
         *error = [NSError errorWithDomain:NSOSStatusErrorDomain
                                      code:errSecUnimplemented
                               description:@"SOS unsupported on this platform"];
     }
+    return NO;
+}
+
+- (BOOL)updateCKKS4AllStatus:(BOOL)status error:(NSError**)error
+{
+    if(error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                     code:errSecUnimplemented
+                              description:@"SOS unsupported on this platform"];
+    }
+    return NO;
 }
 
 - (CKKSSelves * _Nullable)fetchSelfPeers:(NSError * _Nullable __autoreleasing * _Nullable)error
                                                          trustedPeersError:unimplementedError];
 }
 
+- (BOOL)safariViewSyncingEnabled:(NSError**)error
+{
+    return NO;
+}
+
+- (BOOL)preloadOctagonKeySetOnAccount:(nonnull id<CKKSSelfPeer>)currentSelfPeer error:(NSError *__autoreleasing  _Nullable * _Nullable)error {
+    if(error) {
+        *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                     code:errSecUnimplemented
+                              description:@"SOS unsupported on this platform"];
+    }
+    return NO;
+}
+
 @end
 
 @implementation OTSOSAdapterHelpers
index 4972beed2305332ca777cabbd32e316de5567f7e..a7df524a9f22cc1c106d88d4b5fe4166ceddbe21 100644 (file)
@@ -34,6 +34,8 @@
 @property NSOperation* finishedOp;
 
 @property OTUpdateTrustedDeviceListOperation* updateOp;
+
+@property (nullable) NSArray<NSData*>* peerPreapprovedSPKIs;
 @end
 
 @implementation OTSOSUpgradeOperation
                 fatal = true;
             }
 
+            if([self.error.domain isEqualToString:TrustedPeersHelperErrorDomain] && self.error.code == TrustedPeersHelperErrorNoPeersPreapprovedBySelf) {
+                secnotice("octagon-sos", "SOS upgrade error is 'we don't preapprove anyone'; retrying immediately is useless: %@", self.error);
+                fatal = true;
+            }
+
             if(!fatal) {
                 secnotice("octagon-sos", "SOS upgrade error is not fatal: requesting retry in %0.2fs: %@", delay, self.error);
                 [self.deps.flagHandler handlePendingFlag:[[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptSOSUpgrade
     }];
     [self dependOnBeforeGroupFinished:self.finishedOp];
 
+    secnotice("octagon-sos", "Fetching trusted peers from SOS");
+
+    NSError* sosPreapprovalError = nil;
+    self.peerPreapprovedSPKIs = [OTSOSAdapterHelpers peerPublicSigningKeySPKIsForCircle:self.deps.sosAdapter error:&sosPreapprovalError];
+
+    if(self.peerPreapprovedSPKIs) {
+        secnotice("octagon-sos", "SOS preapproved keys are %@", self.peerPreapprovedSPKIs);
+    } else {
+        secnotice("octagon-sos", "Unable to fetch SOS preapproved keys: %@", sosPreapprovalError);
+        self.error = sosPreapprovalError;
+        [self runBeforeGroupFinished:self.finishedOp];
+        return;
+    }
+
     NSString* bottleSalt = nil;
     NSError *authKitError = nil;
 
         }
     }
 
+    NSError* sosViewError = nil;
+    BOOL safariViewEnabled = [self.deps.sosAdapter safariViewSyncingEnabled:&sosViewError];
+    if(sosViewError) {
+        secnotice("octagon-sos", "Unable to check safari view status: %@", sosViewError);
+    }
+
+    secnotice("octagon-sos", "Safari view is: %@", safariViewEnabled ? @"enabled" : @"disabled");
+
     [self.deps.cuttlefishXPCWrapper prepareWithContainer:self.deps.containerName
                                                  context:self.deps.contextID
                                                    epoch:self.deviceInfo.epoch
                                                osVersion:self.deviceInfo.osVersion
                                            policyVersion:self.policyOverride
                                            policySecrets:nil
+                               syncUserControllableViews:safariViewEnabled ?
+                                                            TPPBPeerStableInfo_UserControllableViewStatus_ENABLED :
+                                                            TPPBPeerStableInfo_UserControllableViewStatus_DISABLED
                              signingPrivKeyPersistentRef:signingKeyPersistRef
                                  encPrivKeyPersistentRef:encryptionKeyPersistRef
                                                    reply:^(NSString * _Nullable peerID,
                                                            NSData * _Nullable permanentInfoSig,
                                                            NSData * _Nullable stableInfo,
                                                            NSData * _Nullable stableInfoSig,
-                                                           NSSet<NSString*>* syncingViews,
-                                                           TPPolicy* _Nullable syncingPolicy,
+                                                           TPSyncingPolicy* _Nullable syncingPolicy,
                                                            NSError * _Nullable error) {
             STRONGIFY(self);
 
 
             NSError* localError = nil;
             BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
-                metadata.syncingViews = [syncingViews mutableCopy];
-                [metadata setTPPolicy:syncingPolicy];
+                [metadata setTPSyncingPolicy:syncingPolicy];
                 return metadata;
             } error:&localError];
 
                 return;
             }
 
-            [self.deps.viewManager setSyncingViews:syncingViews sortingPolicy:syncingPolicy];
+            [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
 
             [self afterPrepare];
         }];
     WEAKIFY(self);
     [self.deps.cuttlefishXPCWrapper preflightPreapprovedJoinWithContainer:self.deps.containerName
                                                                   context:self.deps.contextID
+                                                          preapprovedKeys:self.peerPreapprovedSPKIs
                                                                     reply:^(BOOL launchOkay, NSError * _Nullable error) {
             STRONGIFY(self);
 
-            // Preflight preapprovedjoin should return the policy used by the peers we eventually will trust
-            // <rdar://problem/57768490> Octagon: ensure we use appropriate CKKS policy when joining octagon with future policy
-
             [[CKKSAnalytics logger] logResultForEvent:OctagonEventUpgradePreflightPreapprovedJoin hardFailure:true result:error];
             if(error) {
                 secerror("octagon-sos: preflightPreapprovedJoin failed: %@", error);
 {
     WEAKIFY(self);
 
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
     
     secnotice("octagon-sos", "Fetching keys from CKKS");
 {
     WEAKIFY(self);
 
-    secnotice("octagon-sos", "Fetching trusted peers from SOS");
-
-    NSArray<NSData*>* publicSigningSPKIs = nil;
-    if(self.deps.sosAdapter.sosEnabled) {
-        NSError* sosPreapprovalError = nil;
-        publicSigningSPKIs = [OTSOSAdapterHelpers peerPublicSigningKeySPKIsForCircle:self.deps.sosAdapter error:&sosPreapprovalError];
-
-        if(publicSigningSPKIs) {
-            secnotice("octagon-sos", "SOS preapproved keys are %@", publicSigningSPKIs);
-        } else {
-            secnotice("octagon-sos", "Unable to fetch SOS preapproved keys: %@", sosPreapprovalError);
-        }
-
-    } else {
-        secnotice("octagon-sos", "SOS not enabled; no preapproved keys");
-    }
-
-    secnotice("octagon-sos", "Beginning SOS upgrade with %d key sets and %d SOS peers", (int)viewKeySets.count, (int)publicSigningSPKIs.count);
+    secnotice("octagon-sos", "Beginning SOS upgrade with %d key sets and %d SOS peers", (int)viewKeySets.count, (int)self.peerPreapprovedSPKIs.count);
 
     [self.deps.cuttlefishXPCWrapper attemptPreapprovedJoinWithContainer:self.deps.containerName
                                                                 context:self.deps.contextID
                                                                ckksKeys:viewKeySets
                                                               tlkShares:pendingTLKShares
-                                                        preapprovedKeys:publicSigningSPKIs
+                                                        preapprovedKeys:self.peerPreapprovedSPKIs
                                                                   reply:^(NSString * _Nullable peerID,
                                                                           NSArray<CKRecord*>* keyHierarchyRecords,
-                                                                          NSSet<NSString*>* _Nullable syncingViewList,
-                                                                          TPPolicy* _Nullable syncingPolicy,
+                                                                          TPSyncingPolicy* _Nullable syncingPolicy,
                                                                           NSError * _Nullable error) {
         STRONGIFY(self);
 
         [self requestSilentEscrowUpdate];
 
         secerror("octagon-sos: attemptPreapprovedJoin succeded");
-        [self.deps.viewManager setSyncingViews:syncingViewList sortingPolicy:syncingPolicy];
+        [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy];
 
         NSError* localError = nil;
         BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC *  _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
             metadata.trustState = OTAccountMetadataClassC_TrustState_TRUSTED;
             metadata.peerID = peerID;
-            metadata.syncingViews = [syncingViewList mutableCopy];
-            [metadata setTPPolicy:syncingPolicy];
 
+            [metadata setTPSyncingPolicy:syncingPolicy];
             return metadata;
         } error:&localError];
 
index 4761d52582f357f310898140312b1b0392faecf0..b66d44a25e41e8181657e3af61b24b0e454c864c 100644 (file)
@@ -81,7 +81,8 @@
 
     WEAKIFY(self);
 
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"setting-recovery-tlks"
                                                     recoveryKey:self.recoveryKey
                                                            salt:salt
                                                        ckksKeys:viewKeySets
-                                                          reply:^(NSError * _Nullable setError) {
+                                                          reply:^(NSArray<CKRecord*>* _Nullable keyHierarchyRecords,
+                                                                  NSError * _Nullable setError) {
             STRONGIFY(self);
             if(setError){
                 [[CKKSAnalytics logger] logResultForEvent:OctagonEventSetRecoveryKey hardFailure:true result:setError];
                 [self runBeforeGroupFinished:self.finishOp];
             } else {
                 secnotice("octagon", "successfully set recovery key");
+
+                for (id key in self.deps.viewManager.views) {
+                    CKKSKeychainView* view = self.deps.viewManager.views[key];
+                    secnotice("octagon-ckks", "Providing setRecoveryKey() records to %@", view);
+                    [view receiveTLKUploadRecords:keyHierarchyRecords];
+                }
                 [self runBeforeGroupFinished:self.finishOp];
             }
         }];
index 52cee05b3794758fec6348b13a43ed860e5918b9..1025071344d6af542892b946e008391ee544a517 100644 (file)
@@ -45,6 +45,9 @@ extern OctagonState* const OctagonStateBecomeUntrusted;
 // WaitForUnlock indicates that Octagon is waiting for the device to unlock before attempting the pended operation
 extern OctagonState* const OctagonStateWaitForUnlock;
 
+// Similar to the above, but we can't even be sure there's an account until the device unlocks for the first time.
+extern OctagonState* const OctagonStateWaitForClassCUnlock;
+
 // 'ready' indicates that this machine believes it is trusted by its peers
 // and has no pending things to do.
 extern OctagonState* const OctagonStateReady;
@@ -55,6 +58,11 @@ extern OctagonState* const OctagonStateBecomeReady;
 // BecomeReady might go here, if it's not actually ready
 extern OctagonState* const OctagonStateRefetchCKKSPolicy;
 
+// Used in RPCs to set CKKS sync status
+extern OctagonState* const OctagonStateEnableUserControllableViews;
+extern OctagonState* const OctagonStateDisableUserControllableViews;
+extern OctagonState* const OctagonStateSetUserControllableViewsToPeerConsensus;
+
 // Enter this state if you'd like the state machine to double-check everything
 extern OctagonState* const OctagonStateEnsureConsistency;
 extern OctagonState* const OctagonStateEnsureOctagonKeysAreConsistent;
@@ -83,6 +91,7 @@ extern OctagonState* const OctagonStateDeviceListUpdated;
 
 /* used for join with bottle */
 extern OctagonState* const OctagonStateBottleJoinCreateIdentity;
+extern OctagonState* const OctagonStateBottlePreloadOctagonKeysInSOS;
 
 /* used for join with recovery key */
 extern OctagonState* const OctagonStateCreateIdentityForRecoveryKey;
@@ -129,6 +138,7 @@ extern OctagonState* const OctagonStateUpdateSOSPreapprovals;
 extern OctagonState* const OctagonStateError;
 extern OctagonState* const OctagonStateDisabled;
 
+extern OctagonState* const OctagonStateAttemptSOSUpgradeDetermineCDPState;
 extern OctagonState* const OctagonStateAttemptSOSUpgrade;
 extern OctagonState* const OctagonStateSOSUpgradeCKKSReset;
 extern OctagonState* const OctagonStateSOSUpgradeAfterCKKSReset;
@@ -170,6 +180,10 @@ extern OctagonFlag* const OctagonFlagIDMSLevelChanged;
 extern OctagonFlag* const OctagonFlagEgoPeerPreapproved;
 
 extern OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload;
+extern OctagonFlag* const OctagonFlagCKKSRequestsPolicyCheck;
+
+// Set by Octagon when the CKKS view set has changed. Indicates a need to re-tell CKKS if it's trusted or not.
+extern OctagonFlag* const OctagonFlagCKKSViewSetChanged;
 
 // We've received a change notification from cuttlefish; we should probably see what's new
 extern OctagonFlag* const OctagonFlagCuttlefishNotification NS_SWIFT_NAME(OctagonFlagCuttlefishNotification);
@@ -187,6 +201,12 @@ extern OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals;
 extern OctagonFlag* const OctagonFlagAttemptSOSConsistency;
 
 extern OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation;
+extern OctagonFlag* const OctagonFlagWarmEscrowRecordCache;
+
+extern OctagonFlag* const OctagonFlagAttemptBottleTLKExtraction;
+extern OctagonFlag* const OctagonFlagAttemptRecoveryKeyTLKExtraction;
+
+extern OctagonFlag* const OctagonFlagAttemptUserControllableViewStatusUpgrade;
 
 
 NS_ASSUME_NONNULL_END
index 5db76711fa2a93c57ac4b4402e2c4fe9e5b2170c..340ee2215c4e2108a3adbbc5bb990a94f9df1489 100644 (file)
@@ -52,6 +52,10 @@ OctagonState* const OctagonStateRefetchCKKSPolicy = (OctagonState*) @"ckks_fetch
 OctagonState* const OctagonStateDetermineCDPState = (OctagonState*) @"check_cdp_state";
 OctagonState* const OctagonStateCheckTrustState = (OctagonState*) @"check_trust_state";
 
+OctagonState* const OctagonStateEnableUserControllableViews = (OctagonState*) @"ckks_set_user_controllable_views_on";
+OctagonState* const OctagonStateDisableUserControllableViews = (OctagonState*) @"ckks_set_user_controlable_views_off";
+OctagonState* const OctagonStateSetUserControllableViewsToPeerConsensus = (OctagonState*) @"ckks_set_user_controlable_views_peer_consensus";
+
 OctagonState* const OctagonStateUpdateSOSPreapprovals = (OctagonState*) @"update_sos_preapprovals";
 
 /*Piggybacking and ProximitySetup as Initiator Octagon only*/
@@ -66,6 +70,7 @@ OctagonState* const OctagonStateInitiatorJoinAfterCKKSReset = (OctagonState*)@"j
 OctagonState* const OctagonStateBottleJoinCreateIdentity = (OctagonState*)@"bottle_join_create_identity";
 OctagonState* const OctagonStateBottleJoinVouchWithBottle = (OctagonState*)@"bottle_join_vouch_with_bottle";
 OctagonState* const OctagonStateCreateIdentityForRecoveryKey = (OctagonState*)@"vouchWithRecovery";
+OctagonState* const OctagonStateBottlePreloadOctagonKeysInSOS = (OctagonState*)@"bottle_preload_octagon_keys_in_sos";
 
 /* used in resotre (join with recovery key)*/
 OctagonState* const OctagonStateVouchWithRecoveryKey = (OctagonState*)@"vouchWithRecoveryKey";
@@ -84,6 +89,8 @@ OctagonState* const OctagonStateError = (OctagonState*) @"error";
 OctagonState* const OctagonStateDisabled = (OctagonState*) @"disabled";
 
 OctagonState* const OctagonStateDetermineiCloudAccountState = (OctagonState*) @"determine_icloud_account";
+
+OctagonState* const OctagonStateAttemptSOSUpgradeDetermineCDPState = (OctagonState*) @"sosupgrade_cdp_check";
 OctagonState* const OctagonStateAttemptSOSUpgrade = (OctagonState*) @"sosupgrade";
 OctagonState* const OctagonStateSOSUpgradeCKKSReset = (OctagonState*) @"sosupgrade_ckks_reset";
 OctagonState* const OctagonStateSOSUpgradeAfterCKKSReset = (OctagonState*) @"sosupgrade_after_ckks_reset";
@@ -112,6 +119,7 @@ OctagonState* const OctagonStateHealthCheckReset = (OctagonState*) @"health_chec
 OctagonState* const OctagonStateNoAccountDoReset = (OctagonState*) @"no_account_do_reset";
 
 OctagonState* const OctagonStateWaitForUnlock = (OctagonState*) @"wait_for_unlock";
+OctagonState* const OctagonStateWaitForClassCUnlock = (OctagonState*) @"wait_for_class_c_unlock";
 
 OctagonState* const OctagonStateAssistCKKSTLKUpload = (OctagonState*) @"assist_ckks_tlk_upload";
 OctagonState* const OctagonStateAssistCKKSTLKUploadCKKSReset = (OctagonState*) @"assist_ckks_tlk_upload_ckks_reset";
@@ -199,6 +207,12 @@ NSDictionary<OctagonState*, NSNumber*>* OctagonStateMap(void) {
                 OctagonStateCDPHealthCheck:                     @58U,
                 OctagonStateHealthCheckLeaveClique:             @59U,
                 OctagonStateRefetchCKKSPolicy:                  @60U,
+                OctagonStateEnableUserControllableViews:        @61U,
+                OctagonStateDisableUserControllableViews:       @62U,
+                OctagonStateSetUserControllableViewsToPeerConsensus: @63U,
+                OctagonStateWaitForClassCUnlock:                @64U,
+                OctagonStateBottlePreloadOctagonKeysInSOS:      @65U,
+                OctagonStateAttemptSOSUpgradeDetermineCDPState: @66U,
             };
     });
     return map;
@@ -231,6 +245,9 @@ NSSet<OctagonState*>* OctagonInAccountStates(void)
         [sourceStates removeObject:OctagonStateCloudKitNewlyAvailable];
         [sourceStates removeObject:OctagonStateWaitForHSA2];
 
+        // If the device hasn't unlocked yet, we don't know what we wrote down for iCloud account status
+        [sourceStates removeObject:OctagonStateWaitForClassCUnlock];
+
         s = sourceStates;
     });
     return s;
@@ -258,7 +275,9 @@ NSSet<OctagonState *>* OctagonHealthSourceStates(void)
 // Flags
 OctagonFlag* const OctagonFlagIDMSLevelChanged = (OctagonFlag*) @"idms_level";
 OctagonFlag* const OctagonFlagEgoPeerPreapproved = (OctagonFlag*) @"preapproved";
-OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload  = (OctagonFlag*) @"tlk_upload_needed";
+OctagonFlag* const OctagonFlagCKKSRequestsTLKUpload = (OctagonFlag*) @"tlk_upload_needed";
+OctagonFlag* const OctagonFlagCKKSRequestsPolicyCheck = (OctagonFlag*) @"policy_check_needed";;
+OctagonFlag* const OctagonFlagCKKSViewSetChanged = (OctagonFlag*) @"ckks_views_changed";
 OctagonFlag* const OctagonFlagCuttlefishNotification = (OctagonFlag*) @"recd_push";
 OctagonFlag* const OctagonFlagAccountIsAvailable = (OctagonFlag*)@"account_available";
 OctagonFlag* const OctagonFlagCDPEnabled = (OctagonFlag*) @"cdp_enabled";
@@ -268,6 +287,11 @@ OctagonFlag* const OctagonFlagUnlocked = (OctagonFlag*)@"unlocked";
 OctagonFlag* const OctagonFlagAttemptSOSUpdatePreapprovals = (OctagonFlag*)@"attempt_sos_update_preapprovals";
 OctagonFlag* const OctagonFlagAttemptSOSConsistency = (OctagonFlag*)@"attempt_sos_consistency";
 OctagonFlag* const OctagonFlagEscrowRequestInformCloudServicesOperation = (OctagonFlag*)@"escrowrequest_inform_cloudservices";
+OctagonFlag* const OctagonFlagWarmEscrowRecordCache = (OctagonFlag*)@"warm_escrow_cache";
+OctagonFlag* const OctagonFlagAttemptBottleTLKExtraction = (OctagonFlag*)@"retry_bottle_tlk_extraction";
+OctagonFlag* const OctagonFlagAttemptRecoveryKeyTLKExtraction = (OctagonFlag*)@"retry_rk_tlk_extraction";
+
+OctagonFlag* const OctagonFlagAttemptUserControllableViewStatusUpgrade = (OctagonFlag*)@"attempt_ucv_upgrade";
 
 NSSet<OctagonFlag *>* AllOctagonFlags(void)
 {
@@ -279,6 +303,8 @@ NSSet<OctagonFlag *>* AllOctagonFlags(void)
         [flags addObject:OctagonFlagIDMSLevelChanged];
         [flags addObject:OctagonFlagEgoPeerPreapproved];
         [flags addObject:OctagonFlagCKKSRequestsTLKUpload];
+        [flags addObject:OctagonFlagCKKSRequestsPolicyCheck];
+        [flags addObject:OctagonFlagCKKSViewSetChanged];
         [flags addObject:OctagonFlagCuttlefishNotification];
         [flags addObject:OctagonFlagAccountIsAvailable];
         [flags addObject:OctagonFlagCDPEnabled];
@@ -287,6 +313,10 @@ NSSet<OctagonFlag *>* AllOctagonFlags(void)
         [flags addObject:OctagonFlagUnlocked];
         [flags addObject:OctagonFlagAttemptSOSUpdatePreapprovals];
         [flags addObject:OctagonFlagAttemptSOSConsistency];
+        [flags addObject:OctagonFlagWarmEscrowRecordCache];
+        [flags addObject:OctagonFlagAttemptUserControllableViewStatusUpgrade];
+        [flags addObject:OctagonFlagAttemptBottleTLKExtraction];
+        [flags addObject:OctagonFlagAttemptRecoveryKeyTLKExtraction];
 
         f = flags;
     });
index c31589f0fa212ac22755494fcfbcfbe4b0aedf32..1dec19cebd1ec109d72ea59ec39f7edea6a24f66 100644 (file)
                                               osVersion:self.deps.deviceInformationAdapter.osVersion
                                           policyVersion:nil
                                           policySecrets:nil
-                                                  reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) {
+                              syncUserControllableViews:nil
+                                                  reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, 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
-                // <rdar://problem/50190005> Octagon: handle lock state errors in update()
-                self.nextState = self.intendedState;
+                if ([error isCuttlefishError:CuttlefishErrorUpdateTrustPeerNotFound]) {
+                    secnotice("octagon-ckks", "Cuttlefish reports we no longer exist.");
+                    self.nextState = self.peerUnknownState;
+                } else {
+                    // On an error, for now, go back to the intended state
+                    // <rdar://problem/50190005> Octagon: handle lock state errors in update()
+                    self.nextState = self.intendedState;
+                }
                 [self runBeforeGroupFinished:self.finishedOp];
                 return;
             }
 
-            secnotice("octagon", "update complete: %@", peerState);
+            secnotice("octagon", "update complete: %@, %@", peerState, syncingPolicy);
+
+            NSError* localError = nil;
+            BOOL persisted = [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
+                [metadata setTPSyncingPolicy:syncingPolicy];
+                return metadata;
+            } error:&localError];
+            if(!persisted || localError) {
+                secerror("octagon: Unable to save new syncing state: %@", localError);
+
+            } else {
+                // After an update(), we're sure that we have a fresh policy
+                BOOL viewSetChanged = [self.deps.viewManager setCurrentSyncingPolicy:syncingPolicy policyIsFresh:YES];
+                if(viewSetChanged) {
+                    [self.deps.flagHandler handleFlag:OctagonFlagCKKSViewSetChanged];
+                }
+            }
 
             if(peerState.identityIsPreapproved) {
                 secnotice("octagon-sos", "Self peer is now preapproved!");
                 [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList];
             }
 
-            if(peerState.peerStatus & TPPeerStatusExcluded) {
+            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 '%@''", peerState.peerID, self.peerUnknownState);
-                self.nextState = self.peerUnknownState;
-
+                if (peerState.identityIsPreapproved) {
+                    secnotice("octagon", "Self peer (%@) is excluded but is preapproved, moving to sosuprade", peerState.peerID);
+                    self.nextState = OctagonStateAttemptSOSUpgrade;
+                } else {
+                    secnotice("octagon", "Self peer (%@) is unknown; moving to '%@''", peerState.peerID, self.peerUnknownState);
+                    self.nextState = self.peerUnknownState;
+                }
             } else {
                 self.nextState = self.intendedState;
             }
index 0e6cb278527e6f436e0270c8721765d3d888b44e..ca7d5f7d03c28b65d63bf8474b1a078c76257578 100644 (file)
 
     [self.deps.authKitAdapter fetchCurrentDeviceList:^(NSSet<NSString *> * _Nullable machineIDs, NSError * _Nullable error) {
         STRONGIFY(self);
-        if(!machineIDs || error) {
+
+        if (error) {
             secerror("octagon-authkit: Unable to fetch machine ID list: %@", error);
+            [self fetchCurrentDeviceListAfterCuttlefishUpdate:isAccountDemo];
+        } else if (!machineIDs) {
+            secerror("octagon-authkit: empty machine id list");
             if (self.logForUpgrade) {
                 [[CKKSAnalytics logger] logRecoverableError:error
                                                    forEvent:OctagonEventUpgradeFetchDeviceIDs
     }];
 }
 
+- (void)fetchCurrentDeviceListAfterCuttlefishUpdate:(BOOL)isAccountDemo
+{
+    secnotice("octagon-authkit", "beginning update trust fetch");
+
+    WEAKIFY(self);
+    [self.deps.cuttlefishXPCWrapper updateWithContainer:self.deps.containerName
+                                                context:self.deps.contextID
+                                             deviceName:nil
+                                           serialNumber:nil
+                                              osVersion:nil
+                                          policyVersion:nil
+                                          policySecrets:nil
+                              syncUserControllableViews:nil
+                                                  reply:^(TrustedPeersHelperPeerState* peerState, TPSyncingPolicy* syncingPolicy, NSError* error) {
+        STRONGIFY(self);
+        if(error) {
+            secerror("octagon-authkit: fetching updates from cuttlefish failed: %@", error);
+            self.error = error;
+
+            if([self.deps.lockStateTracker isLockedError:self.error]) {
+                secnotice("octagon-authkit", "Feching changes from Cuttlefish failed because of lock state, will retry once unlocked: %@", self.error);
+                OctagonPendingFlag* pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagFetchAuthKitMachineIDList
+                                                                                conditions:OctagonPendingConditionsDeviceUnlocked];
+
+                [self.deps.flagHandler handlePendingFlag:pendingFlag];
+            }
+            
+            [self runBeforeGroupFinished:self.finishedOp];
+            return;
+        }
+        secnotice("octagon-authkit", "re-attempting fetching current device list");
+
+        [self.deps.authKitAdapter fetchCurrentDeviceList:^(NSSet<NSString *> * _Nullable machineIDs, NSError * _Nullable error) {
+            STRONGIFY(self);
+            if(!machineIDs || error) {
+                secerror("octagon-authkit: STILL unable to fetch machine ID list: %@", error);
+                if (self.logForUpgrade) {
+                    [[CKKSAnalytics logger] logRecoverableError:error
+                                                       forEvent:OctagonEventUpgradeFetchDeviceIDs
+                                                 withAttributes:NULL];
+                }
+                self.error = error;
+                [self runBeforeGroupFinished:self.finishedOp];
+
+            } else {
+                if (self.logForUpgrade) {
+                    [[CKKSAnalytics logger] logSuccessForEventNamed:OctagonEventUpgradeFetchDeviceIDs];
+                }
+                [self afterAuthKitFetch:machineIDs accountIsDemo:isAccountDemo];
+            }
+        }];
+    }];
+}
+
 - (void)afterAuthKitFetch:(NSSet<NSString *>*)allowedMachineIDs accountIsDemo:(BOOL)accountIsDemo
 {
     WEAKIFY(self);
index 3feeab6a700b584344d11955292d972a069e60cd..205e130edbd1110fc2201dbe2e0ec8e12a9cc514 100644 (file)
@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
                        intendedState:(OctagonState*)intendedState
                    ckksConflictState:(OctagonState*)ckksConflictState
+                    peerMissingState:(OctagonState*)peerMissingState
                           errorState:(OctagonState*)errorState;
 
 @property OctagonState* nextState;
index 5c74b845e008e71f619863b04cb38a006ca89850..15968b1baace94bf6035eee37799fc165366edf1 100644 (file)
@@ -8,6 +8,7 @@
 #import "keychain/ot/OTUploadNewCKKSTLKsOperation.h"
 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
 #import "keychain/ot/OTFetchCKKSKeysOperation.h"
+#import "keychain/ot/OTStates.h"
 #import "keychain/ckks/CKKSCurrentKeyPointer.h"
 #import "keychain/ckks/CKKSKeychainView.h"
 #import "keychain/ckks/CKKSNearFutureScheduler.h"
@@ -20,6 +21,7 @@
 @property OTOperationDependencies* deps;
 
 @property OctagonState* ckksConflictState;
+@property OctagonState* peerMissingState;
 
 @property NSOperation* finishedOp;
 @end
@@ -30,6 +32,7 @@
 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
                        intendedState:(OctagonState*)intendedState
                    ckksConflictState:(OctagonState*)ckksConflictState
+                    peerMissingState:(OctagonState*)peerMissingState
                           errorState:(OctagonState*)errorState
 {
     if((self = [super init])) {
@@ -37,6 +40,7 @@
 
         _intendedState = intendedState;
         _ckksConflictState = ckksConflictState;
+        _peerMissingState = peerMissingState;
         _nextState = errorState;
     }
     return self;
@@ -44,7 +48,7 @@
 
 - (void)groupStart
 {
-    secnotice("octagon", "Beginning to upload any pending CKKS tlks operation");
+    secnotice("octagon", "Beginning an operation to upload any pending CKKS tlks");
 
     WEAKIFY(self);
 
@@ -53,8 +57,7 @@
     // One (or more) of our sub-CKKSes believes it needs to upload new TLKs.
     CKKSViewManager* viewManager = self.deps.viewManager;
     for(CKKSKeychainView* view in viewManager.currentViews) {
-        if([view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKUpload] ||
-           [view.keyHierarchyState isEqualToString:SecCKKSZoneKeyStateWaitForTLKCreation]) {
+        if([view requiresTLKUpload]) {
             secnotice("octagon-ckks", "CKKS view %@ needs TLK uploads!", view);
             [viewsToUpload addObject: view];
         }
                 if ([error isCuttlefishError:CuttlefishErrorKeyHierarchyAlreadyExists]) {
                     secnotice("octagon-ckks", "A CKKS key hierarchy is out of date; moving to '%@'", self.ckksConflictState);
                     self.nextState = self.ckksConflictState;
+                } else if ([error isCuttlefishError:CuttlefishErrorUpdateTrustPeerNotFound]) {
+                    secnotice("octagon-ckks", "Cuttlefish reports we no longer exist.");
+                    self.nextState = self.peerMissingState;
+                    self.error = error;
+
                 } else {
                     secerror("octagon: Error calling tlk upload: %@", error);
                     self.error = error;
index dc3ef075a560e2774ed449978c767bdf3d3718e3..f9960c81e87111da833fe69c2b7ba18ddf44626e 100644 (file)
@@ -41,7 +41,8 @@ NS_ASSUME_NONNULL_BEGIN
                               errorState:(OctagonState*)errorState
                             bottleID:(NSString*)bottleID
                              entropy:(NSData*)entropy
-                          bottleSalt:(NSString*)bottleSalt;
+                          bottleSalt:(NSString*)bottleSalt
+                         saveVoucher:(BOOL)saveVoucher;
 
 @property (weak) OTCuttlefishContext* cuttlefishContext;
 @property (nonatomic) NSString* bottleID;
@@ -50,6 +51,9 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property (nonatomic) NSData* voucher;
 @property (nonatomic) NSData* voucherSig;
+
+// Controls whether or not to save the received voucher in the state handler.
+@property (readonly) BOOL saveVoucher;
 @end
 
 NS_ASSUME_NONNULL_END
index d47c452d62cef4191d68547b039fb3271ae4f8ce..da298b6d9bc6b83b1d04e61544ec09d2d92908d8 100644 (file)
@@ -29,6 +29,7 @@
 #import "keychain/ot/OTClientStateMachine.h"
 #import "keychain/ot/OTCuttlefishContext.h"
 #import "keychain/ot/OTFetchCKKSKeysOperation.h"
+#import "keychain/ot/OTStates.h"
 
 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
 #import "keychain/ot/ObjCImprovements.h"
@@ -48,6 +49,7 @@
                             bottleID:(NSString*)bottleID
                              entropy:(NSData*)entropy
                           bottleSalt:(NSString*)bottleSalt
+                         saveVoucher:(BOOL)saveVoucher
 {
     if((self = [super init])) {
         _deps = dependencies;
@@ -57,6 +59,8 @@
         _bottleID = bottleID;
         _entropy = entropy;
         _bottleSalt = bottleSalt;
+
+        _saveVoucher = saveVoucher;
     }
     return self;
 }
                                                                   context:self.deps.contextID
                                                                  bottleID:self.bottleID
                                                                     reply:^(NSString * _Nullable peerID,
-                                                                            NSSet<NSString*>* peerSyncingViews,
-                                                                            TPPolicy* peerSyncingPolicy,
+                                                                            TPSyncingPolicy* peerSyncingPolicy,
+                                                                            BOOL refetchWasNeeded,
                                                                             NSError * _Nullable error) {
         STRONGIFY(self);
         [[CKKSAnalytics logger] logResultForEvent:OctagonEventPreflightVouchWithBottle hardFailure:true result:error];
 
         // Tell CKKS to spin up the new views and policy
         // But, do not persist this view set! We'll do that when we actually manager to join
-        [self.deps.viewManager setSyncingViews:peerSyncingViews sortingPolicy:peerSyncingPolicy];
+        [self.deps.viewManager setCurrentSyncingPolicy:peerSyncingPolicy];
 
-        [self proceedWithPeerID:peerID];
+        [self proceedWithPeerID:peerID refetchWasNeeded:refetchWasNeeded];
     }];
 }
 
-- (void)proceedWithPeerID:(NSString*)peerID
+- (void)proceedWithPeerID:(NSString*)peerID refetchWasNeeded:(BOOL)refetchWasNeeded
 {
     WEAKIFY(self);
 
     // After a vouch, we also want to acquire all TLKs that the bottled peer might have had
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:refetchWasNeeded];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"bottle-tlks"
             }
         }
 
+        if(fetchKeysOp.viewsTimedOutWithoutKeysets.count > 0) {
+            // At least one view failed to find a keyset in time.
+            // Set up a retry with this bottle, once CKKS is done fetching
+            secnotice("octagon", "Timed out fetching key hierarchy for CKKS views; marking for TLK recovery follow up: %@", fetchKeysOp.viewsTimedOutWithoutKeysets);
+            OctagonPendingFlag* flag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptBottleTLKExtraction
+                                                                          after:self.deps.viewManager.zoneChangeFetcher.inflightFetch];
+            [self.deps.flagHandler handlePendingFlag:flag];
+        }
+
         [self proceedWithKeys:fetchKeysOp.viewKeySets filteredTLKShares:filteredTLKShares];
     }];
 
             }
             [self noteMetric:OctagonAnalyticsBottledTLKUniqueViewCount count:views.count];
 
-            secnotice("octagon", "Received bottle voucher");
-
             self.voucher = voucher;
             self.voucherSig = voucherSig;
+
+            if(self.saveVoucher) {
+                secnotice("octagon", "Saving voucher for later use...");
+                NSError* saveError = nil;
+                [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
+                    metadata.voucher = voucher;
+                    metadata.voucherSignature = voucherSig;
+                    return metadata;
+                } error:&saveError];
+                if(saveError) {
+                    secnotice("octagon", "unable to save voucher: %@", saveError);
+                    [self runBeforeGroupFinished:self.finishedOp];
+                    return;
+                }
+            }
+
+            secnotice("octagon", "Successfully vouched with a bottle: %@, %@", voucher, voucherSig);
             self.nextState = self.intendedState;
             [self runBeforeGroupFinished:self.finishedOp];
         }];
index 1203d7156f61f819d0bf58aa51b380adc79cb4da..ba3f884a588d34189961ebf59d1e2d46d2b2cd50 100644 (file)
@@ -39,12 +39,16 @@ NS_ASSUME_NONNULL_BEGIN
 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
                        intendedState:(OctagonState*)intendedState
                           errorState:(OctagonState*)errorState
-                         recoveryKey:(NSString*)recoveryKey;
+                         recoveryKey:(NSString*)recoveryKey
+                         saveVoucher:(BOOL)saveVoucher;
 
 @property (weak) OTCuttlefishContext* cuttlefishContext;
 
 @property (nonatomic) NSData* voucher;
 @property (nonatomic) NSData* voucherSig;
+
+// Controls whether or not to save the received voucher in the state handler.
+@property (readonly) BOOL saveVoucher;
 @end
 
 NS_ASSUME_NONNULL_END
index 24809b5c5a3d29609a5e27c050a83844c3d52104..89012c95501ff9bf41e5e5174cefa25d2498db1d 100644 (file)
@@ -29,6 +29,7 @@
 #import "keychain/ot/OTClientStateMachine.h"
 #import "keychain/ot/OTCuttlefishContext.h"
 #import "keychain/ot/OTFetchCKKSKeysOperation.h"
+#import "keychain/ot/OTStates.h"
 
 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
 #import "keychain/ot/ObjCImprovements.h"
@@ -49,6 +50,7 @@
                        intendedState:(OctagonState*)intendedState
                           errorState:(OctagonState*)errorState
                          recoveryKey:(NSString*)recoveryKey
+                         saveVoucher:(BOOL)saveVoucher
 {
     if((self = [super init])) {
         _deps = dependencies;
@@ -56,6 +58,8 @@
         _nextState = errorState;
 
         _recoveryKey = recoveryKey;
+
+        _saveVoucher = saveVoucher;
     }
     return self;
 }
@@ -92,8 +96,7 @@
                                                                    recoveryKey:self.recoveryKey
                                                                           salt:self.salt
                                                                     reply:^(NSString * _Nullable recoveryKeyID,
-                                                                            NSSet<NSString*>* peerSyncingViews,
-                                                                            TPPolicy* peerSyncingPolicy,
+                                                                            TPSyncingPolicy* _Nullable peerSyncingPolicy,
                                                                             NSError * _Nullable error) {
         STRONGIFY(self);
         [[CKKSAnalytics logger] logResultForEvent:OctagonEventPreflightVouchWithRecoveryKey hardFailure:true result:error];
 
         // Tell CKKS to spin up the new views and policy
         // But, do not persist this view set! We'll do that when we actually manage to join
-        [self.deps.viewManager setSyncingViews:peerSyncingViews sortingPolicy:peerSyncingPolicy];
+        [self.deps.viewManager setCurrentSyncingPolicy:peerSyncingPolicy];
 
         [self proceedWithRecoveryKeyID:recoveryKeyID];
     }];
     WEAKIFY(self);
 
     // After a vouch, we also want to acquire all TLKs that the bottled peer might have had
-    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps];
+    OTFetchCKKSKeysOperation* fetchKeysOp = [[OTFetchCKKSKeysOperation alloc] initWithDependencies:self.deps
+                                                                                     refetchNeeded:NO];
     [self runBeforeGroupFinished:fetchKeysOp];
 
     CKKSResultOperation* proceedWithKeys = [CKKSResultOperation named:@"recovery-tlks"
             }
         }
 
+        if(fetchKeysOp.viewsTimedOutWithoutKeysets.count > 0) {
+            // At least one view failed to find a keyset in time.
+            // Set up a retry with this recovery key, once CKKS is done fetching
+            secnotice("octagon", "Timed out fetching key hierarchy for CKKS views; marking for TLK recovery follow up: %@", fetchKeysOp.viewsTimedOutWithoutKeysets);
+            OctagonPendingFlag* flag = [[OctagonPendingFlag alloc] initWithFlag:OctagonFlagAttemptRecoveryKeyTLKExtraction
+                                                                          after:self.deps.viewManager.zoneChangeFetcher.inflightFetch];
+            [self.deps.flagHandler handlePendingFlag:flag];
+        }
+
         [self proceedWithKeys:fetchKeysOp.viewKeySets tlkShares:filteredTLKShares salt:self.salt];
     }];
 
             }
             self.voucher = voucher;
             self.voucherSig = voucherSig;
+
+            if(self.saveVoucher) {
+                secnotice("octagon", "Saving voucher for later use...");
+                NSError* saveError = nil;
+                [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nullable(OTAccountMetadataClassC * _Nonnull metadata) {
+                    metadata.voucher = voucher;
+                    metadata.voucherSignature = voucherSig;
+                    return metadata;
+                } error:&saveError];
+                if(saveError) {
+                    secnotice("octagon", "unable to save voucher: %@", saveError);
+                    [self runBeforeGroupFinished:self.finishOp];
+                    return;
+                }
+            }
+
+            secnotice("octagon", "Successfully vouched with a recovery key: %@, %@", voucher, voucherSig);
             self.nextState = self.intendedState;
             [self runBeforeGroupFinished:self.finishOp];
         }];
index 4936cc22c7b4627c50a295745bd1d37c455a1672..ead418ae756c0ad9302b17dbacd705ce7dacbdf5 100644 (file)
@@ -2,8 +2,9 @@
 #if OCTAGON
 
 #import <Foundation/Foundation.h>
-#import "keychain/ot/OTOperationDependencies.h"
 #import "keychain/ckks/CKKSPeer.h"
+#import "keychain/ckks/CKKSPeerProvider.h"
+#import "keychain/ot/CuttlefishXPCWrapper.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -19,10 +20,15 @@ NS_ASSUME_NONNULL_BEGIN
 @interface OctagonCKKSPeerAdapter : NSObject  <CKKSPeerProvider>
 
 @property (nullable) NSString* peerID;
-@property OTOperationDependencies* deps;
+@property (readonly) CuttlefishXPCWrapper* cuttlefishXPCWrapper;
+@property (readonly) NSString* containerName;
+@property (readonly) NSString* contextID;
 
 - (instancetype)init NS_UNAVAILABLE;
-- (instancetype)initWithPeerID:(NSString*)peerID operationDependencies:(OTOperationDependencies*)deps;
+- (instancetype)initWithPeerID:(NSString*)peerID
+                 containerName:(NSString*)containerName
+                     contextID:(NSString*)contextID
+                 cuttlefishXPC:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper;
 @end
 
 NS_ASSUME_NONNULL_END
index b7707e9eadaae52277469ecd0088bace1a6874c9..b664f8c7ee9e3c56e550ffe185f81fc2e8808322 100644 (file)
 @synthesize essential = _essential;
 @synthesize providerID = _providerID;
 
-- (instancetype)initWithPeerID:(NSString*)peerID operationDependencies:(OTOperationDependencies*)deps
+
+- (instancetype)initWithPeerID:(NSString*)peerID
+                 containerName:(NSString*)containerName
+                     contextID:(NSString*)contextID
+                 cuttlefishXPC:(CuttlefishXPCWrapper*)cuttlefishXPCWrapper
 {
     if((self = [super init])) {
         _providerID = [NSString stringWithFormat:@"[OctagonCKKSPeerAdapter:%@]", peerID];
         _peerID = peerID;
-        _deps = deps;
+
+        _containerName = containerName;
+        _contextID = contextID;
+        _cuttlefishXPCWrapper = cuttlefishXPCWrapper;
 
         _peerChangeListeners = [[CKKSListenerCollection alloc] initWithName:@"ckks-sos"];
 
     __block NSMutableSet<id<CKKSRemotePeerProtocol>> * peers = nil;
 
     WEAKIFY(self);
-    [self.deps.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.deps.containerName
-                                                         context:self.deps.contextID
-                                                           reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
-                                                                   NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
-                                                                   NSError * _Nullable operror) {
+    [self.cuttlefishXPCWrapper fetchTrustStateWithContainer:self.containerName
+                                                    context:self.contextID
+                                                      reply:^(TrustedPeersHelperPeerState * _Nullable selfPeerState,
+                                                              NSArray<TrustedPeersHelperPeer *> * _Nullable trustedPeers,
+                                                              NSError * _Nullable operror) {
             STRONGIFY(self);
             if(operror) {
-                secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.deps.containerName, self.deps.contextID, operror);
+                secnotice("octagon", "Unable to fetch trusted peers for (%@,%@): %@", self.containerName, self.contextID, operror);
                 localerror = operror;
 
             } else {
                                                                   encryptionPublicKey:encryptionKey
                                                                      signingPublicKey:signingKey
                                                                              viewList:peer.viewList];
-                    secnotice("octagon", "Have trusted peer %@", ckkspeer);
-
                     [peers addObject:ckkspeer];
                 }
             }
index 9fe406bf74f4f9510a9288437f3ce9c897ec4c9e..254d3278b9de24727925472f1706aa963ea0817d 100644 (file)
@@ -79,7 +79,7 @@
     if(localError) {
         if([self.deps.lockStateTracker isLockedError:localError]) {
             secerror("octagon-consistency: Unable to fetch current account state due to lock state: %@", localError);
-            self.nextState = OctagonStateWaitForUnlock;
+            self.nextState = OctagonStateWaitForClassCUnlock;
             [self runBeforeGroupFinished:self.finishedOp];
             return;
         }
         if(!persisted || localError) {
             if([self.deps.lockStateTracker isLockedError:localError]) {
                 secerror("octagon-consistency: Unable to save new account state due to lock state: %@", localError);
-                self.nextState = OctagonStateWaitForUnlock;
+                self.nextState = OctagonStateWaitForClassCUnlock;
                 [self runBeforeGroupFinished:self.finishedOp];
                 return;
             }
index 9d67c8373e0edb001498fb0fb470409e6bf10daf..973504222701ecfca0381f417ce9965db9e4beee 100644 (file)
         return NO;
     }
     
-    secnotice("octagon", "received connection from client pid %d", [newConnection processIdentifier]);
+    secinfo("octagon", "received connection from client pid %d", [newConnection processIdentifier]);
     newConnection.exportedInterface = OTSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(OTControlProtocol)]);
     newConnection.exportedObject = [OctagonXPCEntitlementChecker createWithManager:[OTManager manager] entitlementBearer:newConnection];
 
index b42fc44707d443822bdfdaf22db3b41d9026c508..455ee7959bd22f90087accfe1bcaee358a148a56 100644 (file)
@@ -22,9 +22,9 @@
         _flagConditions = [[NSMutableDictionary alloc] init];
         _allowableFlags = possibleFlags;
 
-        [possibleFlags enumerateObjectsUsingBlock:^(OctagonState * _Nonnull obj, BOOL * _Nonnull stop) {
-            self.flagConditions[obj] = [[CKKSCondition alloc] init];
-        }];
+        for(OctagonFlag* flag in possibleFlags) {
+            self.flagConditions[flag] = [[CKKSCondition alloc] init];
+        }
     }
     return self;
 }
index a130fcefe04560f3eb3d57933da88e4070e3f6cc..09794be4499d2b0621c335e60dbe97f6571681eb 100644 (file)
@@ -25,8 +25,11 @@ NSString* OctagonPendingConditionsToString(OctagonPendingConditions cond);
 
 @property (readonly) OctagonPendingConditions conditions;
 
+@property (nullable) NSOperation* afterOperation;
+
 - (instancetype)initWithFlag:(OctagonFlag*)flag delayInSeconds:(NSTimeInterval)delay;
 - (instancetype)initWithFlag:(OctagonFlag*)flag conditions:(OctagonPendingConditions)conditions;
+- (instancetype)initWithFlag:(OctagonFlag*)flag after:(NSOperation*)op;
 @end
 
 NS_ASSUME_NONNULL_END
index d192ae41a325c5644a5f37e0b8c65a8ccc881e53..20467870839039b8717349608a2746cc4407ea69 100644 (file)
@@ -21,6 +21,7 @@ NSString* OctagonPendingConditionsToString(OctagonPendingConditions cond)
     if ((self = [super init])) {
         _flag = flag;
         _fireTime = [NSDate dateWithTimeIntervalSinceNow:delay];
+        _afterOperation = nil;
         _conditions = 0;
     }
     return self;
@@ -32,14 +33,28 @@ NSString* OctagonPendingConditionsToString(OctagonPendingConditions cond)
     if ((self = [super init])) {
         _flag = flag;
         _fireTime = nil;
+        _afterOperation = nil;
         _conditions = conditions;
     }
     return self;
 }
 
+- (instancetype)initWithFlag:(OctagonFlag*)flag after:(NSOperation*)op
+{
+    if ((self = [super init])) {
+        _flag = flag;
+        _fireTime = nil;
+        _afterOperation = op;
+        _conditions = 0;
+    }
+    return self;
+}
+
 - (NSString*)description {
     if(self.fireTime) {
         return [NSString stringWithFormat:@"<OctagonPendingFlag: %@: %@>", self.flag, self.fireTime];
+    } else if(self.afterOperation) {
+        return [NSString stringWithFormat:@"<OctagonPendingFlag: %@: %@>", self.flag, self.afterOperation];
     } else {
         return [NSString stringWithFormat:@"<OctagonPendingFlag: %@: %@>", self.flag, OctagonPendingConditionsToString(self.conditions)];
     }
index 4aeabe1cb0852f12c1608b575bb6a8d9c168a706..d463578cb7d72b89db8f976c3bea85ccc2f21d90 100644 (file)
@@ -33,6 +33,9 @@ NS_ASSUME_NONNULL_BEGIN
 @protocol OctagonStateFlagHandler
 - (void)handleFlag:(OctagonFlag*)flag;
 - (void)handlePendingFlag:(OctagonPendingFlag*)pendingFlag;
+
+// If you've truly broken your queue ordering, then call this from whatever queue your flag handler is using.
+- (void)_onqueueHandleFlag:(OctagonFlag*)flag;
 @end
 
 @interface OctagonStateMachine : NSObject <OctagonStateFlagHandler, OctagonStateOnqueuePendingFlagHandler>
@@ -70,6 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
 
 // This will set the given flag, and ensure that the state machine spins to handle it.
 - (void)handleFlag:(OctagonFlag*)flag;
+- (void)_onqueueHandleFlag:(OctagonFlag*)flag;
 
 // This will schedule the flag for future addition
 - (void)handlePendingFlag:(OctagonPendingFlag *)pendingFlag;
@@ -80,17 +84,19 @@ NS_ASSUME_NONNULL_BEGIN
 - (void)disablePendingFlags;
 
 - (void)handleExternalRequest:(OctagonStateTransitionRequest<CKKSResultOperation<OctagonStateTransitionOperationProtocol>*>*)request;
+
 - (void)registerStateTransitionWatcher:(OctagonStateTransitionWatcher*)watcher;
+- (void)registerMultiStateArrivalWatcher:(OctagonStateMultiStateArrivalWatcher*)watcher;
 
 - (void)doSimpleStateMachineRPC:(NSString*)name
                              op:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)op
                    sourceStates:(NSSet<OctagonState*>*)sourceStates
                           reply:(nonnull void (^)(NSError * _Nullable))reply;
 
-- (void)doWatchedStateMachineRPC:(NSString*)name
-                    sourceStates:(NSSet<OctagonState*>*)sourceStates
-                            path:(OctagonStateTransitionPath*)path
-                           reply:(nonnull void (^)(NSError *error))reply;
+- (CKKSResultOperation*)doWatchedStateMachineRPC:(NSString*)name
+                                    sourceStates:(NSSet<OctagonState*>*)sourceStates
+                                            path:(OctagonStateTransitionPath*)path
+                                           reply:(nonnull void (^)(NSError *error))reply;
 - (void)setWatcherTimeout:(uint64_t)timeout;
 - (BOOL)isPaused;
 
index 3e4f4efe3381e06621d44846d392832b83b5425c..c470bda2f43bdd44a60563e6e47c1568ccc0010b 100644 (file)
@@ -39,7 +39,7 @@ format,
 @property (nullable) CKKSResultOperation* nextStateMachineCycleOperation;
 
 @property NSMutableArray<OctagonStateTransitionRequest<CKKSResultOperation<OctagonStateTransitionOperationProtocol>*>*>* stateMachineRequests;
-@property NSMutableArray<OctagonStateTransitionWatcher*>* stateMachineWatchers;
+@property NSMutableArray<id<OctagonStateTransitionWatcherProtocol>>* stateMachineWatchers;
 
 @property BOOL halted;
 @property bool allowPendingFlags;
@@ -246,7 +246,7 @@ format,
                       op,
                       op.error ?: @"(no error)");
 
-            for(OctagonStateTransitionWatcher* watcher in self.stateMachineWatchers) {
+            for(id<OctagonStateTransitionWatcherProtocol> watcher in self.stateMachineWatchers) {
                 statemachinelog("state", "notifying watcher: %@", watcher);
                 [watcher onqueueHandleTransition:op];
             }
@@ -286,11 +286,18 @@ format,
 - (void)handleFlag:(OctagonFlag*)flag
 {
     dispatch_sync(self.queue, ^{
-        [self.currentFlags _onqueueSetFlag:flag];
-        [self _onqueuePokeStateMachine];
+        [self _onqueueHandleFlag:flag];
     });
 }
 
+
+- (void)_onqueueHandleFlag:(OctagonFlag*)flag
+{
+    dispatch_assert_queue(self.queue);
+    [self.currentFlags _onqueueSetFlag:flag];
+    [self _onqueuePokeStateMachine];
+}
+
 - (void)handlePendingFlag:(OctagonPendingFlag *)pendingFlag {
     dispatch_sync(self.queue, ^{
         [self _onqueueHandlePendingFlag:pendingFlag];
@@ -310,6 +317,20 @@ format,
         self.currentConditions &= ~recheck;
     }
 
+    if(pendingFlag.afterOperation) {
+        WEAKIFY(self);
+        NSOperation* after = [NSBlockOperation blockOperationWithBlock:^{
+            STRONGIFY(self);
+            dispatch_sync(self.queue, ^{
+                statemachinelog("pending-flag", "Finished waiting for operation");
+                [self _onqueueSendAnyPendingFlags];
+            });
+        }];
+
+        [after addNullableDependency:pendingFlag.afterOperation];
+        [self.operationQueue addOperation:after];
+    }
+
     [self _onqueueRecheckConditions];
     [self _onqueueSendAnyPendingFlags];
 }
@@ -409,6 +430,14 @@ format,
             }
         }
 
+        if(pendingFlag.afterOperation) {
+            if(![pendingFlag.afterOperation isFinished]) {
+                send = false;
+            } else {
+                statemachinelog("pending-flag", "Operation has ended for pending flag %@: %@", pendingFlag.flag, pendingFlag.afterOperation);
+            }
+        }
+
         if(pendingFlag.conditions != 0x0) {
             // Also, send the flag if the conditions are right
             if((pendingFlag.conditions & self.currentConditions) == pendingFlag.conditions) {
@@ -485,6 +514,7 @@ format,
     });
 }
 
+
 - (void)registerStateTransitionWatcher:(OctagonStateTransitionWatcher*)watcher
 {
     dispatch_sync(self.queue, ^{
@@ -493,6 +523,18 @@ format,
     });
 }
 
+- (void)registerMultiStateArrivalWatcher:(OctagonStateMultiStateArrivalWatcher*)watcher
+{
+    dispatch_sync(self.queue, ^{
+        if([watcher.states containsObject:self.currentState]) {
+            [watcher onqueueEnterState:self.currentState];
+        } else {
+            [self.stateMachineWatchers addObject:watcher];
+            [self _onqueuePokeStateMachine];
+        }
+    });
+}
+
 #pragma mark - RPC Helpers
 
 - (void)doSimpleStateMachineRPC:(NSString*)name
@@ -525,10 +567,10 @@ format,
     self.timeout = timeout;
 }
 
-- (void)doWatchedStateMachineRPC:(NSString*)name
-                    sourceStates:(NSSet<OctagonState*>*)sourceStates
-                            path:(OctagonStateTransitionPath*)path
-                           reply:(nonnull void (^)(NSError *error))reply
+- (CKKSResultOperation*)doWatchedStateMachineRPC:(NSString*)name
+                                    sourceStates:(NSSet<OctagonState*>*)sourceStates
+                                            path:(OctagonStateTransitionPath*)path
+                                           reply:(nonnull void (^)(NSError *error))reply
 {
     statemachinelog("state-rpc", "Beginning a '%@' rpc", name);
 
@@ -551,18 +593,21 @@ format,
 
     [self registerStateTransitionWatcher:watcher];
 
-    WEAKIFY(self);
     CKKSResultOperation* replyOp = [CKKSResultOperation named:[NSString stringWithFormat: @"%@-callback", name]
-                                                    withBlock:^{
-                                                        STRONGIFY(self);
-                                                        statemachinelog("state-rpc", "Returning '%@' result: %@", name, watcher.result.error ?: @"no error");
-                                                        reply(watcher.result.error);
-                                                    }];
+                                          withBlockTakingSelf:^(CKKSResultOperation * _Nonnull op) {
+        statemachinelog("state-rpc", "Returning '%@' result: %@", name, watcher.result.error ?: @"no error");
+        if(reply) {
+            reply(watcher.result.error);
+        }
+        op.error = watcher.result.error;
+    }];
+
     [replyOp addDependency:watcher.result];
     [self.operationQueue addOperation:replyOp];
 
 
     [self handleExternalRequest:request];
+    return replyOp;
 }
 
 @end
index d936223de07bbf98534701a6e96554353041b171..886eed855817de69d1b3d2f2c9230018133191f7 100644 (file)
@@ -25,6 +25,7 @@
 
 #import <Foundation/Foundation.h>
 #import "keychain/ckks/CKKSResultOperation.h"
+#import "keychain/ckks/CKKSGroupOperation.h"
 #import "keychain/ckks/CKKSAnalytics.h"
 
 NS_ASSUME_NONNULL_BEGIN
@@ -66,6 +67,17 @@ extern OctagonState* const OctagonStateMachineHalted;
              entering:(OctagonState*)intendedState NS_SWIFT_NAME(init(name:entering:));
 @end
 
+// Just like OctagonStateTransitionOperation, but as a Group Operation
+@interface OctagonStateTransitionGroupOperation : CKKSGroupOperation <OctagonStateTransitionOperationProtocol>
+@property OctagonState* nextState;
+@property (readonly) OctagonState* intendedState;
+
++ (instancetype)named:(NSString*)name
+            intending:(OctagonState*)intendedState
+           errorState:(OctagonState*)errorState
+  withBlockTakingSelf:(void(^)(OctagonStateTransitionGroupOperation* op))block;
+@end
+
 
 @interface OctagonStateTransitionRequest<__covariant OperationType : CKKSResultOperation<OctagonStateTransitionOperationProtocol>*> : NSObject
 @property (readonly) NSString* name;
index a2362e3215e558babd39c52564a6bb9daa5f85f8..c20803f71efc42f4db49815ea9d4135a1b6067a6 100644 (file)
@@ -32,7 +32,9 @@
 OctagonState* const OctagonStateMachineNotStarted = (OctagonState*) @"not_started";
 OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted";
 
-@implementation OctagonStateTransitionOperation : CKKSResultOperation
+#pragma mark -- OctagonStateTransitionOperation
+
+@implementation OctagonStateTransitionOperation
 - (instancetype)initIntending:(OctagonState*)intendedState
                    errorState:(OctagonState*)errorState
 {
@@ -75,6 +77,43 @@ OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted";
 
 @end
 
+#pragma mark -- OctagonStateTransitionGroupOperation
+
+@implementation OctagonStateTransitionGroupOperation
+- (instancetype)initIntending:(OctagonState*)intendedState
+                   errorState:(OctagonState*)errorState
+{
+    if((self = [super init])) {
+        _nextState = errorState;
+        _intendedState = intendedState;
+    }
+    return self;
+}
+
+- (NSString*)description
+{
+    return [NSString stringWithFormat:@"<OctagonStateTransitionGroupOperation(%@): intended:%@ actual:%@>", self.name, self.intendedState, self.nextState];
+}
+
++ (instancetype)named:(NSString*)name
+            intending:(OctagonState*)intendedState
+           errorState:(OctagonState*)errorState
+  withBlockTakingSelf:(void(^)(OctagonStateTransitionGroupOperation* op))block
+{
+    OctagonStateTransitionGroupOperation* op = [[self alloc] initIntending:intendedState
+                                                                errorState:errorState];
+    WEAKIFY(op);
+    [op runBeforeGroupFinished:[NSBlockOperation blockOperationWithBlock:^{
+        STRONGIFY(op);
+        block(op);
+    }]];
+    op.name = name;
+    return op;
+}
+@end
+
+#pragma mark -- OctagonStateTransitionRequest
+
 @interface OctagonStateTransitionRequest ()
 @property dispatch_queue_t queue;
 @property bool timeoutCanOccur;
@@ -104,7 +143,7 @@ OctagonState* const OctagonStateMachineHalted = (OctagonState*) @"halted";
 
 - (NSString*)description
 {
-    return [NSString stringWithFormat:@"<OctagonStateTransitionRequest: %@ %@ %@>", self.name, self.transitionOperation, self.sourceStates];
+    return [NSString stringWithFormat:@"<OctagonStateTransitionRequest: %@ %@ sources:%d>", self.name, self.transitionOperation, (unsigned int)[self.sourceStates count]];
 }
 
 - (CKKSResultOperation<OctagonStateTransitionOperationProtocol>* _Nullable)_onqueueStart
index afa3084444d3a0b93f57ca5bafd86fe7b99c3ff6..806da455b612967dbe6c11484382703943caaad3 100644 (file)
@@ -44,7 +44,13 @@ NS_ASSUME_NONNULL_BEGIN
 @end
 
 
-@interface OctagonStateTransitionWatcher : NSObject
+
+@protocol OctagonStateTransitionWatcherProtocol
+@property (readonly) CKKSResultOperation* result;
+- (void)onqueueHandleTransition:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)attempt;
+@end
+
+@interface OctagonStateTransitionWatcher : NSObject <OctagonStateTransitionWatcherProtocol>
 @property (readonly) NSString* name;
 @property (readonly) CKKSResultOperation* result;
 @property (readonly) OctagonStateTransitionPath* intendedPath;
@@ -57,7 +63,22 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (instancetype)timeout:(dispatch_time_t)timeout;
 
-- (void)onqueueHandleTransition:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)attempt;
+@end
+
+// Reports on if any of the given states are entered
+@interface OctagonStateMultiStateArrivalWatcher : NSObject <OctagonStateTransitionWatcherProtocol>
+@property (readonly) NSString* name;
+@property (readonly) CKKSResultOperation* result;
+@property (readonly) NSSet<OctagonState*>* states;
+
+- (instancetype)initNamed:(NSString*)name
+              serialQueue:(dispatch_queue_t)queue
+                   states:(NSSet<OctagonState*>*)states;
+
+// Called by the state machine if it's already in a state at registration time
+- (void)onqueueEnterState:(OctagonState*)state;
+
+- (instancetype)timeout:(dispatch_time_t)timeout;
 @end
 
 NS_ASSUME_NONNULL_END
index d7e8680882a00878c49a624ad54ebdeec0a66bf5..e7a819f27c7dc8d0c3a5f8b86b32fda4eef1089c 100644 (file)
 
 @end
 
+#pragma mark - OctagonStateMultiStateArrivalWatcher
+
+@interface OctagonStateMultiStateArrivalWatcher ()
+@property BOOL completed;
+@property NSOperationQueue* operationQueue;
+
+@property (nullable) CKKSResultOperation* initialTimeoutListenerOp;
+
+@property bool timeoutCanOccur;
+@property dispatch_queue_t queue;
+@end
+
+
+@implementation OctagonStateMultiStateArrivalWatcher
+- (instancetype)initNamed:(NSString*)name
+              serialQueue:(dispatch_queue_t)queue
+                   states:(NSSet<OctagonState*>*)states
+{
+    if((self = [super init])) {
+        _name = name;
+        _states = states;
+
+        _result = [CKKSResultOperation named:[NSString stringWithFormat:@"watcher-%@", name] withBlock:^{}];
+        _operationQueue = [[NSOperationQueue alloc] init];
+
+        _queue = queue;
+        _timeoutCanOccur = true;
+
+        _completed = NO;
+    }
+    return self;
+}
+
+- (void)onqueueHandleTransition:(CKKSResultOperation<OctagonStateTransitionOperationProtocol>*)attempt
+{
+    dispatch_assert_queue(self.queue);
+    [self onqueueEnterState:attempt.nextState];
+}
+
+- (void)onqueueEnterState:(OctagonState*)state
+{
+    if(!self.completed) {
+        if([self.states containsObject:state]) {
+            [self onqueueStartFinishOperation];
+        }
+    }
+}
+
+- (void)_onqueuePerformTimeoutWithUnderlyingError
+{
+    dispatch_assert_queue(self.queue);
+
+    if(self.timeoutCanOccur) {
+        self.timeoutCanOccur = false;
+
+        NSString* description = [NSString stringWithFormat:@"Operation(%@) timed out waiting to start for any state in [%@]",
+                                 self.name,
+                                 self.states];
+
+        self.result.error = [NSError errorWithDomain:CKKSResultErrorDomain
+                                                code:CKKSResultTimedOut
+                                         description:description];
+        [self onqueueStartFinishOperation];
+    }
+}
+
+- (instancetype)timeout:(dispatch_time_t)timeout
+{
+    WEAKIFY(self);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeout), self.queue, ^{
+        STRONGIFY(self);
+        [self _onqueuePerformTimeoutWithUnderlyingError];
+    });
+
+    return self;
+}
+
+- (void)onqueueStartFinishOperation {
+    dispatch_assert_queue(self.queue);
+
+    self.timeoutCanOccur = false;
+    [self.operationQueue addOperation:self.result];
+    self.completed = TRUE;
+}
+@end
+
+
 #endif
index b60e47eafb7d1606762febb8b9f2d15c4d9e74b3..015ea20b9f4a3db259e000d4e26b612cc7185a46 100644 (file)
@@ -15,10 +15,10 @@ NS_ASSUME_NONNULL_BEGIN
 + (OTAccountMetadataClassC* _Nullable)loadFromKeychainForContainer:(NSString*)containerName contextID:(NSString*)contextID error:(NSError**)error;
 @end
 
-@class TPPolicy;
+@class TPSyncingPolicy;
 @interface OTAccountMetadataClassC (NSSecureCodingSupport)
-- (void)setTPPolicy:(TPPolicy* _Nullable)policy;
-- (TPPolicy* _Nullable)getTPPolicy;
+- (void)setTPSyncingPolicy:(TPSyncingPolicy* _Nullable)policy;
+- (TPSyncingPolicy* _Nullable)getTPSyncingPolicy;
 @end
 
 NS_ASSUME_NONNULL_END
index ced8b4d28cacddbe96ea6f4540944e4e09aac4b4..11731a477f5280a90aef7bc7ed2e641e08efbd91 100644 (file)
@@ -12,7 +12,7 @@
 
 #import "keychain/ot/OTDefines.h"
 #import "keychain/ot/OTConstants.h"
-#import <TrustedPeers/TPPolicy.h>
+#import <TrustedPeers/TPSyncingPolicy.h>
 
 @implementation OTAccountMetadataClassC (KeychainSupport)
 
 
 #pragma mark - Field Coding support
 
-- (void)setTPPolicy:(TPPolicy*)policy
+- (void)setTPSyncingPolicy:(TPSyncingPolicy*)policy
 {
     if(policy) {
         NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initRequiringSecureCoding:YES];
     }
 }
 
-- (TPPolicy* _Nullable)getTPPolicy
+- (TPSyncingPolicy* _Nullable)getTPSyncingPolicy
 {
     NSKeyedUnarchiver *coder = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.syncingPolicy error:nil];
-    TPPolicy* policy = [[TPPolicy alloc] initWithCoder:coder];
+    TPSyncingPolicy* policy = [[TPSyncingPolicy alloc] initWithCoder:coder];
     [coder finishDecoding];
 
     return policy;
index 204e720cd287b2a972024b4c61d5c792f2caa00f..e69060b8b09905d045ea3aa76cd2155c686fd4ba 100644 (file)
@@ -4,16 +4,12 @@
 #ifndef OctagonEscrowRecoverer_h
 #define OctagonEscrowRecoverer_h
 
-#import <CloudServices/SecureBackup.h>
-
 @protocol OctagonEscrowRecovererPrococol <NSObject>
 - (NSError*)recoverWithInfo:(NSDictionary*)info results:(NSDictionary**)results;
+- (NSError *)getAccountInfoWithInfo:(NSDictionary *)info results:(NSDictionary**)results;
 - (NSError *)disableWithInfo:(NSDictionary *)info;
 @end
 
-@interface SecureBackup (OctagonProtocolConformance) <OctagonEscrowRecovererPrococol>
-@end
-
 #endif /* OctagonEscrowRecoverer_h */
 
 #endif // OCTAGON
index d706b6d9dde4d2574e9427c146f4e566c3d0d822..8bf438e2b1abf90505db451eff2618b260b13e1f 100644 (file)
@@ -55,7 +55,14 @@ message AccountMetadataClassC {
 
     optional CDPState cdpState = 8;
 
-    // These store the current policy and view list, so that we don't need to re-ask TPH every time
-    optional bytes syncingPolicy = 9;
-    repeated string syncingView = 10;
+    // Used during development
+    //reserved 9;
+    //reserved 10;
+
+    // This holds the current syncing policy for the local peer, including the view list.
+    optional bytes syncingPolicy = 11;
+
+    // This might contain a voucher for use in joining Octagon.
+    optional bytes voucher = 12;
+    optional bytes voucherSignature = 13;
 }
diff --git a/keychain/ot/proto/OTCDPRecoveryInformation.proto b/keychain/ot/proto/OTCDPRecoveryInformation.proto
new file mode 100644 (file)
index 0000000..04f28db
--- /dev/null
@@ -0,0 +1,37 @@
+syntax = "proto2";
+
+option objc_class_naming = "extended";
+
+package OT;
+import "OTEscrowRecord.proto";
+
+message CDPRecoveryInformation {
+    optional string recovery_secret = 1;
+    optional bool use_cached_secret = 2;
+    optional string recovery_key = 3;
+    optional bool use_previously_cached_recovery_key = 4;
+    optional bool silent_recovery_attempt = 5;
+    optional bool contains_icdp_data = 6;
+    optional bool uses_multiple_icsc = 7;
+}
+
+message EscrowAuthenticationInformation {
+    optional string authentication_password = 1;
+    optional string authentication_dsid = 2;
+    optional string authentication_appleid = 3;
+    optional string fmip_uuid = 4;
+    optional bool fmip_recovery = 5;
+    optional bool idms_recovery = 6;
+    optional string authentication_auth_token = 7;
+    optional string authentication_escrowproxy_url = 8;
+    optional string authentication_icloud_environment = 9;
+}
+
+message ICDPRecordContext {
+    optional CDPRecoveryInformation cdpInfo = 1;
+    optional EscrowAuthenticationInformation authInfo = 2;
+}
+message ICDPRecordSilentContext {
+    optional CDPRecoveryInformation cdpInfo = 1;
+    optional EscrowAuthenticationInformation authInfo = 2;
+}
diff --git a/keychain/ot/proto/OTEscrowRecord.proto b/keychain/ot/proto/OTEscrowRecord.proto
new file mode 100644 (file)
index 0000000..3da70f0
--- /dev/null
@@ -0,0 +1,74 @@
+syntax = "proto2";
+
+option objc_class_naming = "extended";
+
+package OT;
+
+message EscrowRecord {
+    optional uint64 creation_date = 1;
+    optional uint64 remaining_attempts = 2;
+    message Metadata {
+        optional bytes backup_keybag_digest = 1;
+        message ClientMetadata {
+            optional uint64 secure_backup_metadata_timestamp = 1;
+            optional uint64 secure_backup_numeric_passphrase_length = 2;
+            optional uint64 secure_backup_uses_complex_passphrase = 3;
+            optional uint64 secure_backup_uses_numeric_passphrase = 4;
+            optional string device_color = 5;
+            optional string device_enclosure_color = 6;
+            optional string device_mid = 7;
+            optional string device_model = 8;
+            optional string device_model_class = 9;
+            optional string device_model_version = 10;
+            optional string device_name = 11;
+            optional uint64 device_platform = 12;
+        }
+        optional ClientMetadata client_metadata = 2;
+        optional uint64 secure_backup_uses_multiple_icscs = 3;
+        optional string bottle_id = 4;
+        optional uint64 secure_backup_timestamp = 5;
+        optional bytes escrowed_spki = 6;
+        optional bytes peer_info = 7;
+        optional string bottle_validity = 8;
+        optional string serial = 9;
+    }
+    optional Metadata escrow_information_metadata = 3;
+    optional string label = 4;
+    // optional reserved string reserved5 = 5;
+    // optional reserved string reserved6 = 6;
+    // optional reserved string reserved7 = 7;
+    // optional reserved string reserved8 = 8;
+
+    optional uint64 silent_attempt_allowed = 9;
+
+    enum RecordStatus {
+        RECORD_STATUS_VALID = 0;
+        RECORD_STATUS_INVALID = 1;
+    }
+
+    optional RecordStatus record_status = 10;
+    optional string record_id = 11;
+
+    enum RecoveryStatus {
+        RECOVERY_STATUS_VALID = 0;
+        RECOVERY_STATUS_SOFT_LIMIT_REACHED = 1;
+        RECOVERY_STATUS_HARD_LIMIT_REACHED = 2;
+    }
+    optional RecoveryStatus recovery_status = 12;
+    optional uint64 cool_off_end = 13;
+    optional string serial_number = 14;
+
+    enum RecordViability {
+        RECORD_VIABILITY_FULLY_VIABLE = 0;
+        RECORD_VIABILITY_PARTIALLY_VIABLE = 1;
+        RECORD_VIABILITY_LEGACY = 2;
+    }
+    optional RecordViability record_viability = 15;
+
+    enum SOSViability {
+        SOS_VIABLE_UNKNOWN = 0;
+        SOS_VIABLE = 1;
+        SOS_NOT_VIABLE = 2;
+    }
+    optional SOSViability viability_status = 16;
+}
index edc46473cb5b85b2d0dff5c37c6055e138e9aadb..d6e3fe6352ac7a73bb63e061cba63283ec3e420e 100644 (file)
@@ -28,6 +28,19 @@ option objc_class_visibility = "hidden";
 
 package OT;
 
+enum SupportType {
+    unknown = 0;
+    supported = 1;
+    not_supported = 2;
+}
+
+message supportSOSMessage {
+    optional SupportType supported = 1;
+}
+
+message supportOctagonMessage {
+    optional SupportType supported = 1;
+}
 
 message SponsorToApplicantRound1M2 {
     optional uint64 epoch = 1;
@@ -54,4 +67,6 @@ message PairingMessage {
     optional SponsorToApplicantRound2M2 voucher = 3;
     // <rdar://problem/55465193> reserved is not a keyword (it should be)
     // reserved 4;
+    optional supportOctagonMessage supportsOctagon = 5;
+    optional supportSOSMessage supportsSOS = 6;
 }
index 295d83b6cf0ea23239965667a2df898a5226569a..1f645a69001ee4e1d449100a1c497e7c22c33a6c 100644 (file)
@@ -138,8 +138,9 @@ __attribute__((visibility("hidden")))
     OTAccountMetadataClassC_AccountState _icloudAccountState;
     NSString *_peerID;
     NSData *_syncingPolicy;
-    NSMutableArray<NSString *> *_syncingViews;
     OTAccountMetadataClassC_TrustState _trustState;
+    NSData *_voucher;
+    NSData *_voucherSignature;
     struct {
         int epoch:1;
         int lastHealthCheckup:1;
@@ -185,15 +186,20 @@ __attribute__((visibility("hidden")))
 - (OTAccountMetadataClassC_CDPState)StringAsCdpState:(NSString *)str;
 
 @property (nonatomic, readonly) BOOL hasSyncingPolicy;
-/** These store the current policy and view list, so that we don't need to re-ask TPH every time */
+/**
+ * Used during development
+ * reserved 9;
+ * reserved 10;
+ * This holds the current syncing policy for the local peer, including the view list.
+ */
 @property (nonatomic, retain) NSData *syncingPolicy;
 
-@property (nonatomic, retain) NSMutableArray<NSString *> *syncingViews;
-- (void)clearSyncingViews;
-- (void)addSyncingView:(NSString *)i;
-- (NSUInteger)syncingViewsCount;
-- (NSString *)syncingViewAtIndex:(NSUInteger)idx;
-+ (Class)syncingViewType;
+@property (nonatomic, readonly) BOOL hasVoucher;
+/** This might contain a voucher for use in joining Octagon. */
+@property (nonatomic, retain) NSData *voucher;
+
+@property (nonatomic, readonly) BOOL hasVoucherSignature;
+@property (nonatomic, retain) NSData *voucherSignature;
 
 // Performs a shallow copy into other
 - (void)copyTo:(OTAccountMetadataClassC *)other;
index 40c4de4635ecb300cc3c5dfa2ff7f031cf254e15..5dbcb98fdabd280e2eef5b2c22ced0a20adbda25 100644 (file)
     return _syncingPolicy != nil;
 }
 @synthesize syncingPolicy = _syncingPolicy;
-@synthesize syncingViews = _syncingViews;
-- (void)clearSyncingViews
+- (BOOL)hasVoucher
 {
-    [_syncingViews removeAllObjects];
+    return _voucher != nil;
 }
-- (void)addSyncingView:(NSString *)i
+@synthesize voucher = _voucher;
+- (BOOL)hasVoucherSignature
 {
-    if (!_syncingViews)
-    {
-        _syncingViews = [[NSMutableArray alloc] init];
-    }
-    [_syncingViews addObject:i];
-}
-- (NSUInteger)syncingViewsCount
-{
-    return [_syncingViews count];
-}
-- (NSString *)syncingViewAtIndex:(NSUInteger)idx
-{
-    return [_syncingViews objectAtIndex:idx];
-}
-+ (Class)syncingViewType
-{
-    return [NSString class];
+    return _voucherSignature != nil;
 }
+@synthesize voucherSignature = _voucherSignature;
 
 - (NSString *)description
 {
     {
         [dict setObject:self->_syncingPolicy forKey:@"syncingPolicy"];
     }
-    if (self->_syncingViews)
+    if (self->_voucher)
+    {
+        [dict setObject:self->_voucher forKey:@"voucher"];
+    }
+    if (self->_voucherSignature)
     {
-        [dict setObject:self->_syncingViews forKey:@"syncingView"];
+        [dict setObject:self->_voucherSignature forKey:@"voucherSignature"];
     }
     return dict;
 }
@@ -301,19 +290,22 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
                 self->_cdpState = PBReaderReadInt32(reader);
             }
             break;
-            case 9 /* syncingPolicy */:
+            case 11 /* syncingPolicy */:
             {
                 NSData *new_syncingPolicy = PBReaderReadData(reader);
                 self->_syncingPolicy = new_syncingPolicy;
             }
             break;
-            case 10 /* syncingViews */:
+            case 12 /* voucher */:
             {
-                NSString *new_syncingViews = PBReaderReadString(reader);
-                if (new_syncingViews)
-                {
-                    [self addSyncingView:new_syncingViews];
-                }
+                NSData *new_voucher = PBReaderReadData(reader);
+                self->_voucher = new_voucher;
+            }
+            break;
+            case 13 /* voucherSignature */:
+            {
+                NSData *new_voucherSignature = PBReaderReadData(reader);
+                self->_voucherSignature = new_voucherSignature;
             }
             break;
             default:
@@ -391,14 +383,21 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
     {
         if (self->_syncingPolicy)
         {
-            PBDataWriterWriteDataField(writer, self->_syncingPolicy, 9);
+            PBDataWriterWriteDataField(writer, self->_syncingPolicy, 11);
         }
     }
-    /* syncingViews */
+    /* voucher */
     {
-        for (NSString *s_syncingViews in self->_syncingViews)
+        if (self->_voucher)
         {
-            PBDataWriterWriteStringField(writer, s_syncingViews, 10);
+            PBDataWriterWriteDataField(writer, self->_voucher, 12);
+        }
+    }
+    /* voucherSignature */
+    {
+        if (self->_voucherSignature)
+        {
+            PBDataWriterWriteDataField(writer, self->_voucherSignature, 13);
         }
     }
 }
@@ -447,14 +446,13 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
     {
         other.syncingPolicy = _syncingPolicy;
     }
-    if ([self syncingViewsCount])
+    if (_voucher)
     {
-        [other clearSyncingViews];
-        NSUInteger syncingViewsCnt = [self syncingViewsCount];
-        for (NSUInteger i = 0; i < syncingViewsCnt; i++)
-        {
-            [other addSyncingView:[self syncingViewAtIndex:i]];
-        }
+        other.voucher = _voucher;
+    }
+    if (_voucherSignature)
+    {
+        other.voucherSignature = _voucherSignature;
     }
 }
 
@@ -494,11 +492,8 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
         copy->_has.cdpState = YES;
     }
     copy->_syncingPolicy = [_syncingPolicy copyWithZone:zone];
-    for (NSString *v in _syncingViews)
-    {
-        NSString *vCopy = [v copyWithZone:zone];
-        [copy addSyncingView:vCopy];
-    }
+    copy->_voucher = [_voucher copyWithZone:zone];
+    copy->_voucherSignature = [_voucherSignature copyWithZone:zone];
     return copy;
 }
 
@@ -525,7 +520,9 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
     &&
     ((!self->_syncingPolicy && !other->_syncingPolicy) || [self->_syncingPolicy isEqual:other->_syncingPolicy])
     &&
-    ((!self->_syncingViews && !other->_syncingViews) || [self->_syncingViews isEqual:other->_syncingViews])
+    ((!self->_voucher && !other->_voucher) || [self->_voucher isEqual:other->_voucher])
+    &&
+    ((!self->_voucherSignature && !other->_voucherSignature) || [self->_voucherSignature isEqual:other->_voucherSignature])
     ;
 }
 
@@ -551,7 +548,9 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
     ^
     [self->_syncingPolicy hash]
     ^
-    [self->_syncingViews hash]
+    [self->_voucher hash]
+    ^
+    [self->_voucherSignature hash]
     ;
 }
 
@@ -599,9 +598,13 @@ BOOL OTAccountMetadataClassCReadFrom(__unsafe_unretained OTAccountMetadataClassC
     {
         [self setSyncingPolicy:other->_syncingPolicy];
     }
-    for (NSString *iter_syncingViews in other->_syncingViews)
+    if (other->_voucher)
+    {
+        [self setVoucher:other->_voucher];
+    }
+    if (other->_voucherSignature)
     {
-        [self addSyncingView:iter_syncingViews];
+        [self setVoucherSignature:other->_voucherSignature];
     }
 }
 
diff --git a/keychain/ot/proto/generated_source/OTCDPRecoveryInformation.h b/keychain/ot/proto/generated_source/OTCDPRecoveryInformation.h
new file mode 100644 (file)
index 0000000..2e070ea
--- /dev/null
@@ -0,0 +1,66 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define OTCDPRECOVERYINFORMATION_FUNCTION extern "C"
+#else
+#define OTCDPRECOVERYINFORMATION_FUNCTION extern
+#endif
+
+@interface OTCDPRecoveryInformation : PBCodable <NSCopying>
+{
+    NSString *_recoveryKey;
+    NSString *_recoverySecret;
+    BOOL _containsIcdpData;
+    BOOL _silentRecoveryAttempt;
+    BOOL _useCachedSecret;
+    BOOL _usePreviouslyCachedRecoveryKey;
+    BOOL _usesMultipleIcsc;
+    struct {
+        int containsIcdpData:1;
+        int silentRecoveryAttempt:1;
+        int useCachedSecret:1;
+        int usePreviouslyCachedRecoveryKey:1;
+        int usesMultipleIcsc:1;
+    } _has;
+}
+
+
+@property (nonatomic, readonly) BOOL hasRecoverySecret;
+@property (nonatomic, retain) NSString *recoverySecret;
+
+@property (nonatomic) BOOL hasUseCachedSecret;
+@property (nonatomic) BOOL useCachedSecret;
+
+@property (nonatomic, readonly) BOOL hasRecoveryKey;
+@property (nonatomic, retain) NSString *recoveryKey;
+
+@property (nonatomic) BOOL hasUsePreviouslyCachedRecoveryKey;
+@property (nonatomic) BOOL usePreviouslyCachedRecoveryKey;
+
+@property (nonatomic) BOOL hasSilentRecoveryAttempt;
+@property (nonatomic) BOOL silentRecoveryAttempt;
+
+@property (nonatomic) BOOL hasContainsIcdpData;
+@property (nonatomic) BOOL containsIcdpData;
+
+@property (nonatomic) BOOL hasUsesMultipleIcsc;
+@property (nonatomic) BOOL usesMultipleIcsc;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTCDPRecoveryInformation *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTCDPRecoveryInformation *)other;
+
+OTCDPRECOVERYINFORMATION_FUNCTION BOOL OTCDPRecoveryInformationReadFrom(__unsafe_unretained OTCDPRecoveryInformation *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTCDPRecoveryInformation.m b/keychain/ot/proto/generated_source/OTCDPRecoveryInformation.m
new file mode 100644 (file)
index 0000000..242d163
--- /dev/null
@@ -0,0 +1,409 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import "OTCDPRecoveryInformation.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTCDPRecoveryInformation
+
+- (BOOL)hasRecoverySecret
+{
+    return _recoverySecret != nil;
+}
+@synthesize recoverySecret = _recoverySecret;
+@synthesize useCachedSecret = _useCachedSecret;
+- (void)setUseCachedSecret:(BOOL)v
+{
+    _has.useCachedSecret = YES;
+    _useCachedSecret = v;
+}
+- (void)setHasUseCachedSecret:(BOOL)f
+{
+    _has.useCachedSecret = f;
+}
+- (BOOL)hasUseCachedSecret
+{
+    return _has.useCachedSecret != 0;
+}
+- (BOOL)hasRecoveryKey
+{
+    return _recoveryKey != nil;
+}
+@synthesize recoveryKey = _recoveryKey;
+@synthesize usePreviouslyCachedRecoveryKey = _usePreviouslyCachedRecoveryKey;
+- (void)setUsePreviouslyCachedRecoveryKey:(BOOL)v
+{
+    _has.usePreviouslyCachedRecoveryKey = YES;
+    _usePreviouslyCachedRecoveryKey = v;
+}
+- (void)setHasUsePreviouslyCachedRecoveryKey:(BOOL)f
+{
+    _has.usePreviouslyCachedRecoveryKey = f;
+}
+- (BOOL)hasUsePreviouslyCachedRecoveryKey
+{
+    return _has.usePreviouslyCachedRecoveryKey != 0;
+}
+@synthesize silentRecoveryAttempt = _silentRecoveryAttempt;
+- (void)setSilentRecoveryAttempt:(BOOL)v
+{
+    _has.silentRecoveryAttempt = YES;
+    _silentRecoveryAttempt = v;
+}
+- (void)setHasSilentRecoveryAttempt:(BOOL)f
+{
+    _has.silentRecoveryAttempt = f;
+}
+- (BOOL)hasSilentRecoveryAttempt
+{
+    return _has.silentRecoveryAttempt != 0;
+}
+@synthesize containsIcdpData = _containsIcdpData;
+- (void)setContainsIcdpData:(BOOL)v
+{
+    _has.containsIcdpData = YES;
+    _containsIcdpData = v;
+}
+- (void)setHasContainsIcdpData:(BOOL)f
+{
+    _has.containsIcdpData = f;
+}
+- (BOOL)hasContainsIcdpData
+{
+    return _has.containsIcdpData != 0;
+}
+@synthesize usesMultipleIcsc = _usesMultipleIcsc;
+- (void)setUsesMultipleIcsc:(BOOL)v
+{
+    _has.usesMultipleIcsc = YES;
+    _usesMultipleIcsc = v;
+}
+- (void)setHasUsesMultipleIcsc:(BOOL)f
+{
+    _has.usesMultipleIcsc = f;
+}
+- (BOOL)hasUsesMultipleIcsc
+{
+    return _has.usesMultipleIcsc != 0;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_recoverySecret)
+    {
+        [dict setObject:self->_recoverySecret forKey:@"recovery_secret"];
+    }
+    if (self->_has.useCachedSecret)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_useCachedSecret] forKey:@"use_cached_secret"];
+    }
+    if (self->_recoveryKey)
+    {
+        [dict setObject:self->_recoveryKey forKey:@"recovery_key"];
+    }
+    if (self->_has.usePreviouslyCachedRecoveryKey)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_usePreviouslyCachedRecoveryKey] forKey:@"use_previously_cached_recovery_key"];
+    }
+    if (self->_has.silentRecoveryAttempt)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_silentRecoveryAttempt] forKey:@"silent_recovery_attempt"];
+    }
+    if (self->_has.containsIcdpData)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_containsIcdpData] forKey:@"contains_icdp_data"];
+    }
+    if (self->_has.usesMultipleIcsc)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_usesMultipleIcsc] forKey:@"uses_multiple_icsc"];
+    }
+    return dict;
+}
+
+BOOL OTCDPRecoveryInformationReadFrom(__unsafe_unretained OTCDPRecoveryInformation *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* recoverySecret */:
+            {
+                NSString *new_recoverySecret = PBReaderReadString(reader);
+                self->_recoverySecret = new_recoverySecret;
+            }
+            break;
+            case 2 /* useCachedSecret */:
+            {
+                self->_has.useCachedSecret = YES;
+                self->_useCachedSecret = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 3 /* recoveryKey */:
+            {
+                NSString *new_recoveryKey = PBReaderReadString(reader);
+                self->_recoveryKey = new_recoveryKey;
+            }
+            break;
+            case 4 /* usePreviouslyCachedRecoveryKey */:
+            {
+                self->_has.usePreviouslyCachedRecoveryKey = YES;
+                self->_usePreviouslyCachedRecoveryKey = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 5 /* silentRecoveryAttempt */:
+            {
+                self->_has.silentRecoveryAttempt = YES;
+                self->_silentRecoveryAttempt = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 6 /* containsIcdpData */:
+            {
+                self->_has.containsIcdpData = YES;
+                self->_containsIcdpData = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 7 /* usesMultipleIcsc */:
+            {
+                self->_has.usesMultipleIcsc = YES;
+                self->_usesMultipleIcsc = PBReaderReadBOOL(reader);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTCDPRecoveryInformationReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* recoverySecret */
+    {
+        if (self->_recoverySecret)
+        {
+            PBDataWriterWriteStringField(writer, self->_recoverySecret, 1);
+        }
+    }
+    /* useCachedSecret */
+    {
+        if (self->_has.useCachedSecret)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_useCachedSecret, 2);
+        }
+    }
+    /* recoveryKey */
+    {
+        if (self->_recoveryKey)
+        {
+            PBDataWriterWriteStringField(writer, self->_recoveryKey, 3);
+        }
+    }
+    /* usePreviouslyCachedRecoveryKey */
+    {
+        if (self->_has.usePreviouslyCachedRecoveryKey)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_usePreviouslyCachedRecoveryKey, 4);
+        }
+    }
+    /* silentRecoveryAttempt */
+    {
+        if (self->_has.silentRecoveryAttempt)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_silentRecoveryAttempt, 5);
+        }
+    }
+    /* containsIcdpData */
+    {
+        if (self->_has.containsIcdpData)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_containsIcdpData, 6);
+        }
+    }
+    /* usesMultipleIcsc */
+    {
+        if (self->_has.usesMultipleIcsc)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_usesMultipleIcsc, 7);
+        }
+    }
+}
+
+- (void)copyTo:(OTCDPRecoveryInformation *)other
+{
+    if (_recoverySecret)
+    {
+        other.recoverySecret = _recoverySecret;
+    }
+    if (self->_has.useCachedSecret)
+    {
+        other->_useCachedSecret = _useCachedSecret;
+        other->_has.useCachedSecret = YES;
+    }
+    if (_recoveryKey)
+    {
+        other.recoveryKey = _recoveryKey;
+    }
+    if (self->_has.usePreviouslyCachedRecoveryKey)
+    {
+        other->_usePreviouslyCachedRecoveryKey = _usePreviouslyCachedRecoveryKey;
+        other->_has.usePreviouslyCachedRecoveryKey = YES;
+    }
+    if (self->_has.silentRecoveryAttempt)
+    {
+        other->_silentRecoveryAttempt = _silentRecoveryAttempt;
+        other->_has.silentRecoveryAttempt = YES;
+    }
+    if (self->_has.containsIcdpData)
+    {
+        other->_containsIcdpData = _containsIcdpData;
+        other->_has.containsIcdpData = YES;
+    }
+    if (self->_has.usesMultipleIcsc)
+    {
+        other->_usesMultipleIcsc = _usesMultipleIcsc;
+        other->_has.usesMultipleIcsc = YES;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTCDPRecoveryInformation *copy = [[[self class] allocWithZone:zone] init];
+    copy->_recoverySecret = [_recoverySecret copyWithZone:zone];
+    if (self->_has.useCachedSecret)
+    {
+        copy->_useCachedSecret = _useCachedSecret;
+        copy->_has.useCachedSecret = YES;
+    }
+    copy->_recoveryKey = [_recoveryKey copyWithZone:zone];
+    if (self->_has.usePreviouslyCachedRecoveryKey)
+    {
+        copy->_usePreviouslyCachedRecoveryKey = _usePreviouslyCachedRecoveryKey;
+        copy->_has.usePreviouslyCachedRecoveryKey = YES;
+    }
+    if (self->_has.silentRecoveryAttempt)
+    {
+        copy->_silentRecoveryAttempt = _silentRecoveryAttempt;
+        copy->_has.silentRecoveryAttempt = YES;
+    }
+    if (self->_has.containsIcdpData)
+    {
+        copy->_containsIcdpData = _containsIcdpData;
+        copy->_has.containsIcdpData = YES;
+    }
+    if (self->_has.usesMultipleIcsc)
+    {
+        copy->_usesMultipleIcsc = _usesMultipleIcsc;
+        copy->_has.usesMultipleIcsc = YES;
+    }
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTCDPRecoveryInformation *other = (OTCDPRecoveryInformation *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((!self->_recoverySecret && !other->_recoverySecret) || [self->_recoverySecret isEqual:other->_recoverySecret])
+    &&
+    ((self->_has.useCachedSecret && other->_has.useCachedSecret && ((self->_useCachedSecret && other->_useCachedSecret) || (!self->_useCachedSecret && !other->_useCachedSecret))) || (!self->_has.useCachedSecret && !other->_has.useCachedSecret))
+    &&
+    ((!self->_recoveryKey && !other->_recoveryKey) || [self->_recoveryKey isEqual:other->_recoveryKey])
+    &&
+    ((self->_has.usePreviouslyCachedRecoveryKey && other->_has.usePreviouslyCachedRecoveryKey && ((self->_usePreviouslyCachedRecoveryKey && other->_usePreviouslyCachedRecoveryKey) || (!self->_usePreviouslyCachedRecoveryKey && !other->_usePreviouslyCachedRecoveryKey))) || (!self->_has.usePreviouslyCachedRecoveryKey && !other->_has.usePreviouslyCachedRecoveryKey))
+    &&
+    ((self->_has.silentRecoveryAttempt && other->_has.silentRecoveryAttempt && ((self->_silentRecoveryAttempt && other->_silentRecoveryAttempt) || (!self->_silentRecoveryAttempt && !other->_silentRecoveryAttempt))) || (!self->_has.silentRecoveryAttempt && !other->_has.silentRecoveryAttempt))
+    &&
+    ((self->_has.containsIcdpData && other->_has.containsIcdpData && ((self->_containsIcdpData && other->_containsIcdpData) || (!self->_containsIcdpData && !other->_containsIcdpData))) || (!self->_has.containsIcdpData && !other->_has.containsIcdpData))
+    &&
+    ((self->_has.usesMultipleIcsc && other->_has.usesMultipleIcsc && ((self->_usesMultipleIcsc && other->_usesMultipleIcsc) || (!self->_usesMultipleIcsc && !other->_usesMultipleIcsc))) || (!self->_has.usesMultipleIcsc && !other->_has.usesMultipleIcsc))
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    [self->_recoverySecret hash]
+    ^
+    (self->_has.useCachedSecret ? PBHashInt((NSUInteger)self->_useCachedSecret) : 0)
+    ^
+    [self->_recoveryKey hash]
+    ^
+    (self->_has.usePreviouslyCachedRecoveryKey ? PBHashInt((NSUInteger)self->_usePreviouslyCachedRecoveryKey) : 0)
+    ^
+    (self->_has.silentRecoveryAttempt ? PBHashInt((NSUInteger)self->_silentRecoveryAttempt) : 0)
+    ^
+    (self->_has.containsIcdpData ? PBHashInt((NSUInteger)self->_containsIcdpData) : 0)
+    ^
+    (self->_has.usesMultipleIcsc ? PBHashInt((NSUInteger)self->_usesMultipleIcsc) : 0)
+    ;
+}
+
+- (void)mergeFrom:(OTCDPRecoveryInformation *)other
+{
+    if (other->_recoverySecret)
+    {
+        [self setRecoverySecret:other->_recoverySecret];
+    }
+    if (other->_has.useCachedSecret)
+    {
+        self->_useCachedSecret = other->_useCachedSecret;
+        self->_has.useCachedSecret = YES;
+    }
+    if (other->_recoveryKey)
+    {
+        [self setRecoveryKey:other->_recoveryKey];
+    }
+    if (other->_has.usePreviouslyCachedRecoveryKey)
+    {
+        self->_usePreviouslyCachedRecoveryKey = other->_usePreviouslyCachedRecoveryKey;
+        self->_has.usePreviouslyCachedRecoveryKey = YES;
+    }
+    if (other->_has.silentRecoveryAttempt)
+    {
+        self->_silentRecoveryAttempt = other->_silentRecoveryAttempt;
+        self->_has.silentRecoveryAttempt = YES;
+    }
+    if (other->_has.containsIcdpData)
+    {
+        self->_containsIcdpData = other->_containsIcdpData;
+        self->_has.containsIcdpData = YES;
+    }
+    if (other->_has.usesMultipleIcsc)
+    {
+        self->_usesMultipleIcsc = other->_usesMultipleIcsc;
+        self->_has.usesMultipleIcsc = YES;
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.h b/keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.h
new file mode 100644 (file)
index 0000000..1956fd4
--- /dev/null
@@ -0,0 +1,71 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define OTESCROWAUTHENTICATIONINFORMATION_FUNCTION extern "C"
+#else
+#define OTESCROWAUTHENTICATIONINFORMATION_FUNCTION extern
+#endif
+
+@interface OTEscrowAuthenticationInformation : PBCodable <NSCopying>
+{
+    NSString *_authenticationAppleid;
+    NSString *_authenticationAuthToken;
+    NSString *_authenticationDsid;
+    NSString *_authenticationEscrowproxyUrl;
+    NSString *_authenticationIcloudEnvironment;
+    NSString *_authenticationPassword;
+    NSString *_fmipUuid;
+    BOOL _fmipRecovery;
+    BOOL _idmsRecovery;
+    struct {
+        int fmipRecovery:1;
+        int idmsRecovery:1;
+    } _has;
+}
+
+
+@property (nonatomic, readonly) BOOL hasAuthenticationPassword;
+@property (nonatomic, retain) NSString *authenticationPassword;
+
+@property (nonatomic, readonly) BOOL hasAuthenticationDsid;
+@property (nonatomic, retain) NSString *authenticationDsid;
+
+@property (nonatomic, readonly) BOOL hasAuthenticationAppleid;
+@property (nonatomic, retain) NSString *authenticationAppleid;
+
+@property (nonatomic, readonly) BOOL hasFmipUuid;
+@property (nonatomic, retain) NSString *fmipUuid;
+
+@property (nonatomic) BOOL hasFmipRecovery;
+@property (nonatomic) BOOL fmipRecovery;
+
+@property (nonatomic) BOOL hasIdmsRecovery;
+@property (nonatomic) BOOL idmsRecovery;
+
+@property (nonatomic, readonly) BOOL hasAuthenticationAuthToken;
+@property (nonatomic, retain) NSString *authenticationAuthToken;
+
+@property (nonatomic, readonly) BOOL hasAuthenticationEscrowproxyUrl;
+@property (nonatomic, retain) NSString *authenticationEscrowproxyUrl;
+
+@property (nonatomic, readonly) BOOL hasAuthenticationIcloudEnvironment;
+@property (nonatomic, retain) NSString *authenticationIcloudEnvironment;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTEscrowAuthenticationInformation *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTEscrowAuthenticationInformation *)other;
+
+OTESCROWAUTHENTICATIONINFORMATION_FUNCTION BOOL OTEscrowAuthenticationInformationReadFrom(__unsafe_unretained OTEscrowAuthenticationInformation *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.m b/keychain/ot/proto/generated_source/OTEscrowAuthenticationInformation.m
new file mode 100644 (file)
index 0000000..c0b0c86
--- /dev/null
@@ -0,0 +1,434 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import "OTEscrowAuthenticationInformation.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTEscrowAuthenticationInformation
+
+- (BOOL)hasAuthenticationPassword
+{
+    return _authenticationPassword != nil;
+}
+@synthesize authenticationPassword = _authenticationPassword;
+- (BOOL)hasAuthenticationDsid
+{
+    return _authenticationDsid != nil;
+}
+@synthesize authenticationDsid = _authenticationDsid;
+- (BOOL)hasAuthenticationAppleid
+{
+    return _authenticationAppleid != nil;
+}
+@synthesize authenticationAppleid = _authenticationAppleid;
+- (BOOL)hasFmipUuid
+{
+    return _fmipUuid != nil;
+}
+@synthesize fmipUuid = _fmipUuid;
+@synthesize fmipRecovery = _fmipRecovery;
+- (void)setFmipRecovery:(BOOL)v
+{
+    _has.fmipRecovery = YES;
+    _fmipRecovery = v;
+}
+- (void)setHasFmipRecovery:(BOOL)f
+{
+    _has.fmipRecovery = f;
+}
+- (BOOL)hasFmipRecovery
+{
+    return _has.fmipRecovery != 0;
+}
+@synthesize idmsRecovery = _idmsRecovery;
+- (void)setIdmsRecovery:(BOOL)v
+{
+    _has.idmsRecovery = YES;
+    _idmsRecovery = v;
+}
+- (void)setHasIdmsRecovery:(BOOL)f
+{
+    _has.idmsRecovery = f;
+}
+- (BOOL)hasIdmsRecovery
+{
+    return _has.idmsRecovery != 0;
+}
+- (BOOL)hasAuthenticationAuthToken
+{
+    return _authenticationAuthToken != nil;
+}
+@synthesize authenticationAuthToken = _authenticationAuthToken;
+- (BOOL)hasAuthenticationEscrowproxyUrl
+{
+    return _authenticationEscrowproxyUrl != nil;
+}
+@synthesize authenticationEscrowproxyUrl = _authenticationEscrowproxyUrl;
+- (BOOL)hasAuthenticationIcloudEnvironment
+{
+    return _authenticationIcloudEnvironment != nil;
+}
+@synthesize authenticationIcloudEnvironment = _authenticationIcloudEnvironment;
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_authenticationPassword)
+    {
+        [dict setObject:self->_authenticationPassword forKey:@"authentication_password"];
+    }
+    if (self->_authenticationDsid)
+    {
+        [dict setObject:self->_authenticationDsid forKey:@"authentication_dsid"];
+    }
+    if (self->_authenticationAppleid)
+    {
+        [dict setObject:self->_authenticationAppleid forKey:@"authentication_appleid"];
+    }
+    if (self->_fmipUuid)
+    {
+        [dict setObject:self->_fmipUuid forKey:@"fmip_uuid"];
+    }
+    if (self->_has.fmipRecovery)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_fmipRecovery] forKey:@"fmip_recovery"];
+    }
+    if (self->_has.idmsRecovery)
+    {
+        [dict setObject:[NSNumber numberWithBool:self->_idmsRecovery] forKey:@"idms_recovery"];
+    }
+    if (self->_authenticationAuthToken)
+    {
+        [dict setObject:self->_authenticationAuthToken forKey:@"authentication_auth_token"];
+    }
+    if (self->_authenticationEscrowproxyUrl)
+    {
+        [dict setObject:self->_authenticationEscrowproxyUrl forKey:@"authentication_escrowproxy_url"];
+    }
+    if (self->_authenticationIcloudEnvironment)
+    {
+        [dict setObject:self->_authenticationIcloudEnvironment forKey:@"authentication_icloud_environment"];
+    }
+    return dict;
+}
+
+BOOL OTEscrowAuthenticationInformationReadFrom(__unsafe_unretained OTEscrowAuthenticationInformation *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* authenticationPassword */:
+            {
+                NSString *new_authenticationPassword = PBReaderReadString(reader);
+                self->_authenticationPassword = new_authenticationPassword;
+            }
+            break;
+            case 2 /* authenticationDsid */:
+            {
+                NSString *new_authenticationDsid = PBReaderReadString(reader);
+                self->_authenticationDsid = new_authenticationDsid;
+            }
+            break;
+            case 3 /* authenticationAppleid */:
+            {
+                NSString *new_authenticationAppleid = PBReaderReadString(reader);
+                self->_authenticationAppleid = new_authenticationAppleid;
+            }
+            break;
+            case 4 /* fmipUuid */:
+            {
+                NSString *new_fmipUuid = PBReaderReadString(reader);
+                self->_fmipUuid = new_fmipUuid;
+            }
+            break;
+            case 5 /* fmipRecovery */:
+            {
+                self->_has.fmipRecovery = YES;
+                self->_fmipRecovery = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 6 /* idmsRecovery */:
+            {
+                self->_has.idmsRecovery = YES;
+                self->_idmsRecovery = PBReaderReadBOOL(reader);
+            }
+            break;
+            case 7 /* authenticationAuthToken */:
+            {
+                NSString *new_authenticationAuthToken = PBReaderReadString(reader);
+                self->_authenticationAuthToken = new_authenticationAuthToken;
+            }
+            break;
+            case 8 /* authenticationEscrowproxyUrl */:
+            {
+                NSString *new_authenticationEscrowproxyUrl = PBReaderReadString(reader);
+                self->_authenticationEscrowproxyUrl = new_authenticationEscrowproxyUrl;
+            }
+            break;
+            case 9 /* authenticationIcloudEnvironment */:
+            {
+                NSString *new_authenticationIcloudEnvironment = PBReaderReadString(reader);
+                self->_authenticationIcloudEnvironment = new_authenticationIcloudEnvironment;
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTEscrowAuthenticationInformationReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* authenticationPassword */
+    {
+        if (self->_authenticationPassword)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationPassword, 1);
+        }
+    }
+    /* authenticationDsid */
+    {
+        if (self->_authenticationDsid)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationDsid, 2);
+        }
+    }
+    /* authenticationAppleid */
+    {
+        if (self->_authenticationAppleid)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationAppleid, 3);
+        }
+    }
+    /* fmipUuid */
+    {
+        if (self->_fmipUuid)
+        {
+            PBDataWriterWriteStringField(writer, self->_fmipUuid, 4);
+        }
+    }
+    /* fmipRecovery */
+    {
+        if (self->_has.fmipRecovery)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_fmipRecovery, 5);
+        }
+    }
+    /* idmsRecovery */
+    {
+        if (self->_has.idmsRecovery)
+        {
+            PBDataWriterWriteBOOLField(writer, self->_idmsRecovery, 6);
+        }
+    }
+    /* authenticationAuthToken */
+    {
+        if (self->_authenticationAuthToken)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationAuthToken, 7);
+        }
+    }
+    /* authenticationEscrowproxyUrl */
+    {
+        if (self->_authenticationEscrowproxyUrl)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationEscrowproxyUrl, 8);
+        }
+    }
+    /* authenticationIcloudEnvironment */
+    {
+        if (self->_authenticationIcloudEnvironment)
+        {
+            PBDataWriterWriteStringField(writer, self->_authenticationIcloudEnvironment, 9);
+        }
+    }
+}
+
+- (void)copyTo:(OTEscrowAuthenticationInformation *)other
+{
+    if (_authenticationPassword)
+    {
+        other.authenticationPassword = _authenticationPassword;
+    }
+    if (_authenticationDsid)
+    {
+        other.authenticationDsid = _authenticationDsid;
+    }
+    if (_authenticationAppleid)
+    {
+        other.authenticationAppleid = _authenticationAppleid;
+    }
+    if (_fmipUuid)
+    {
+        other.fmipUuid = _fmipUuid;
+    }
+    if (self->_has.fmipRecovery)
+    {
+        other->_fmipRecovery = _fmipRecovery;
+        other->_has.fmipRecovery = YES;
+    }
+    if (self->_has.idmsRecovery)
+    {
+        other->_idmsRecovery = _idmsRecovery;
+        other->_has.idmsRecovery = YES;
+    }
+    if (_authenticationAuthToken)
+    {
+        other.authenticationAuthToken = _authenticationAuthToken;
+    }
+    if (_authenticationEscrowproxyUrl)
+    {
+        other.authenticationEscrowproxyUrl = _authenticationEscrowproxyUrl;
+    }
+    if (_authenticationIcloudEnvironment)
+    {
+        other.authenticationIcloudEnvironment = _authenticationIcloudEnvironment;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTEscrowAuthenticationInformation *copy = [[[self class] allocWithZone:zone] init];
+    copy->_authenticationPassword = [_authenticationPassword copyWithZone:zone];
+    copy->_authenticationDsid = [_authenticationDsid copyWithZone:zone];
+    copy->_authenticationAppleid = [_authenticationAppleid copyWithZone:zone];
+    copy->_fmipUuid = [_fmipUuid copyWithZone:zone];
+    if (self->_has.fmipRecovery)
+    {
+        copy->_fmipRecovery = _fmipRecovery;
+        copy->_has.fmipRecovery = YES;
+    }
+    if (self->_has.idmsRecovery)
+    {
+        copy->_idmsRecovery = _idmsRecovery;
+        copy->_has.idmsRecovery = YES;
+    }
+    copy->_authenticationAuthToken = [_authenticationAuthToken copyWithZone:zone];
+    copy->_authenticationEscrowproxyUrl = [_authenticationEscrowproxyUrl copyWithZone:zone];
+    copy->_authenticationIcloudEnvironment = [_authenticationIcloudEnvironment copyWithZone:zone];
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTEscrowAuthenticationInformation *other = (OTEscrowAuthenticationInformation *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((!self->_authenticationPassword && !other->_authenticationPassword) || [self->_authenticationPassword isEqual:other->_authenticationPassword])
+    &&
+    ((!self->_authenticationDsid && !other->_authenticationDsid) || [self->_authenticationDsid isEqual:other->_authenticationDsid])
+    &&
+    ((!self->_authenticationAppleid && !other->_authenticationAppleid) || [self->_authenticationAppleid isEqual:other->_authenticationAppleid])
+    &&
+    ((!self->_fmipUuid && !other->_fmipUuid) || [self->_fmipUuid isEqual:other->_fmipUuid])
+    &&
+    ((self->_has.fmipRecovery && other->_has.fmipRecovery && ((self->_fmipRecovery && other->_fmipRecovery) || (!self->_fmipRecovery && !other->_fmipRecovery))) || (!self->_has.fmipRecovery && !other->_has.fmipRecovery))
+    &&
+    ((self->_has.idmsRecovery && other->_has.idmsRecovery && ((self->_idmsRecovery && other->_idmsRecovery) || (!self->_idmsRecovery && !other->_idmsRecovery))) || (!self->_has.idmsRecovery && !other->_has.idmsRecovery))
+    &&
+    ((!self->_authenticationAuthToken && !other->_authenticationAuthToken) || [self->_authenticationAuthToken isEqual:other->_authenticationAuthToken])
+    &&
+    ((!self->_authenticationEscrowproxyUrl && !other->_authenticationEscrowproxyUrl) || [self->_authenticationEscrowproxyUrl isEqual:other->_authenticationEscrowproxyUrl])
+    &&
+    ((!self->_authenticationIcloudEnvironment && !other->_authenticationIcloudEnvironment) || [self->_authenticationIcloudEnvironment isEqual:other->_authenticationIcloudEnvironment])
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    [self->_authenticationPassword hash]
+    ^
+    [self->_authenticationDsid hash]
+    ^
+    [self->_authenticationAppleid hash]
+    ^
+    [self->_fmipUuid hash]
+    ^
+    (self->_has.fmipRecovery ? PBHashInt((NSUInteger)self->_fmipRecovery) : 0)
+    ^
+    (self->_has.idmsRecovery ? PBHashInt((NSUInteger)self->_idmsRecovery) : 0)
+    ^
+    [self->_authenticationAuthToken hash]
+    ^
+    [self->_authenticationEscrowproxyUrl hash]
+    ^
+    [self->_authenticationIcloudEnvironment hash]
+    ;
+}
+
+- (void)mergeFrom:(OTEscrowAuthenticationInformation *)other
+{
+    if (other->_authenticationPassword)
+    {
+        [self setAuthenticationPassword:other->_authenticationPassword];
+    }
+    if (other->_authenticationDsid)
+    {
+        [self setAuthenticationDsid:other->_authenticationDsid];
+    }
+    if (other->_authenticationAppleid)
+    {
+        [self setAuthenticationAppleid:other->_authenticationAppleid];
+    }
+    if (other->_fmipUuid)
+    {
+        [self setFmipUuid:other->_fmipUuid];
+    }
+    if (other->_has.fmipRecovery)
+    {
+        self->_fmipRecovery = other->_fmipRecovery;
+        self->_has.fmipRecovery = YES;
+    }
+    if (other->_has.idmsRecovery)
+    {
+        self->_idmsRecovery = other->_idmsRecovery;
+        self->_has.idmsRecovery = YES;
+    }
+    if (other->_authenticationAuthToken)
+    {
+        [self setAuthenticationAuthToken:other->_authenticationAuthToken];
+    }
+    if (other->_authenticationEscrowproxyUrl)
+    {
+        [self setAuthenticationEscrowproxyUrl:other->_authenticationEscrowproxyUrl];
+    }
+    if (other->_authenticationIcloudEnvironment)
+    {
+        [self setAuthenticationIcloudEnvironment:other->_authenticationIcloudEnvironment];
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecord.h b/keychain/ot/proto/generated_source/OTEscrowRecord.h
new file mode 100644 (file)
index 0000000..54774d1
--- /dev/null
@@ -0,0 +1,207 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+@class OTEscrowRecordMetadata;
+
+typedef NS_ENUM(int32_t, OTEscrowRecord_RecordStatus) {
+    OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID = 0,
+    OTEscrowRecord_RecordStatus_RECORD_STATUS_INVALID = 1,
+};
+#ifdef __OBJC__
+NS_INLINE NSString *OTEscrowRecord_RecordStatusAsString(OTEscrowRecord_RecordStatus value)
+{
+    switch (value)
+    {
+        case OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID: return @"RECORD_STATUS_VALID";
+        case OTEscrowRecord_RecordStatus_RECORD_STATUS_INVALID: return @"RECORD_STATUS_INVALID";
+        default: return [NSString stringWithFormat:@"(unknown: %i)", value];
+    }
+}
+#endif /* __OBJC__ */
+#ifdef __OBJC__
+NS_INLINE OTEscrowRecord_RecordStatus StringAsOTEscrowRecord_RecordStatus(NSString *value)
+{
+    if ([value isEqualToString:@"RECORD_STATUS_VALID"]) return OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+    if ([value isEqualToString:@"RECORD_STATUS_INVALID"]) return OTEscrowRecord_RecordStatus_RECORD_STATUS_INVALID;
+    return OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+}
+#endif /* __OBJC__ */
+typedef NS_ENUM(int32_t, OTEscrowRecord_RecoveryStatus) {
+    OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_VALID = 0,
+    OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_SOFT_LIMIT_REACHED = 1,
+    OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_HARD_LIMIT_REACHED = 2,
+};
+#ifdef __OBJC__
+NS_INLINE NSString *OTEscrowRecord_RecoveryStatusAsString(OTEscrowRecord_RecoveryStatus value)
+{
+    switch (value)
+    {
+        case OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_VALID: return @"RECOVERY_STATUS_VALID";
+        case OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_SOFT_LIMIT_REACHED: return @"RECOVERY_STATUS_SOFT_LIMIT_REACHED";
+        case OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_HARD_LIMIT_REACHED: return @"RECOVERY_STATUS_HARD_LIMIT_REACHED";
+        default: return [NSString stringWithFormat:@"(unknown: %i)", value];
+    }
+}
+#endif /* __OBJC__ */
+#ifdef __OBJC__
+NS_INLINE OTEscrowRecord_RecoveryStatus StringAsOTEscrowRecord_RecoveryStatus(NSString *value)
+{
+    if ([value isEqualToString:@"RECOVERY_STATUS_VALID"]) return OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_VALID;
+    if ([value isEqualToString:@"RECOVERY_STATUS_SOFT_LIMIT_REACHED"]) return OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_SOFT_LIMIT_REACHED;
+    if ([value isEqualToString:@"RECOVERY_STATUS_HARD_LIMIT_REACHED"]) return OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_HARD_LIMIT_REACHED;
+    return OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_VALID;
+}
+#endif /* __OBJC__ */
+typedef NS_ENUM(int32_t, OTEscrowRecord_RecordViability) {
+    OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE = 0,
+    OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE = 1,
+    OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY = 2,
+};
+#ifdef __OBJC__
+NS_INLINE NSString *OTEscrowRecord_RecordViabilityAsString(OTEscrowRecord_RecordViability value)
+{
+    switch (value)
+    {
+        case OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE: return @"RECORD_VIABILITY_FULLY_VIABLE";
+        case OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE: return @"RECORD_VIABILITY_PARTIALLY_VIABLE";
+        case OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY: return @"RECORD_VIABILITY_LEGACY";
+        default: return [NSString stringWithFormat:@"(unknown: %i)", value];
+    }
+}
+#endif /* __OBJC__ */
+#ifdef __OBJC__
+NS_INLINE OTEscrowRecord_RecordViability StringAsOTEscrowRecord_RecordViability(NSString *value)
+{
+    if ([value isEqualToString:@"RECORD_VIABILITY_FULLY_VIABLE"]) return OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE;
+    if ([value isEqualToString:@"RECORD_VIABILITY_PARTIALLY_VIABLE"]) return OTEscrowRecord_RecordViability_RECORD_VIABILITY_PARTIALLY_VIABLE;
+    if ([value isEqualToString:@"RECORD_VIABILITY_LEGACY"]) return OTEscrowRecord_RecordViability_RECORD_VIABILITY_LEGACY;
+    return OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE;
+}
+#endif /* __OBJC__ */
+typedef NS_ENUM(int32_t, OTEscrowRecord_SOSViability) {
+    OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN = 0,
+    OTEscrowRecord_SOSViability_SOS_VIABLE = 1,
+    OTEscrowRecord_SOSViability_SOS_NOT_VIABLE = 2,
+};
+#ifdef __OBJC__
+NS_INLINE NSString *OTEscrowRecord_SOSViabilityAsString(OTEscrowRecord_SOSViability value)
+{
+    switch (value)
+    {
+        case OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN: return @"SOS_VIABLE_UNKNOWN";
+        case OTEscrowRecord_SOSViability_SOS_VIABLE: return @"SOS_VIABLE";
+        case OTEscrowRecord_SOSViability_SOS_NOT_VIABLE: return @"SOS_NOT_VIABLE";
+        default: return [NSString stringWithFormat:@"(unknown: %i)", value];
+    }
+}
+#endif /* __OBJC__ */
+#ifdef __OBJC__
+NS_INLINE OTEscrowRecord_SOSViability StringAsOTEscrowRecord_SOSViability(NSString *value)
+{
+    if ([value isEqualToString:@"SOS_VIABLE_UNKNOWN"]) return OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN;
+    if ([value isEqualToString:@"SOS_VIABLE"]) return OTEscrowRecord_SOSViability_SOS_VIABLE;
+    if ([value isEqualToString:@"SOS_NOT_VIABLE"]) return OTEscrowRecord_SOSViability_SOS_NOT_VIABLE;
+    return OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN;
+}
+#endif /* __OBJC__ */
+
+#ifdef __cplusplus
+#define OTESCROWRECORD_FUNCTION extern "C"
+#else
+#define OTESCROWRECORD_FUNCTION extern
+#endif
+
+@interface OTEscrowRecord : PBCodable <NSCopying>
+{
+    uint64_t _coolOffEnd;
+    uint64_t _creationDate;
+    uint64_t _remainingAttempts;
+    uint64_t _silentAttemptAllowed;
+    OTEscrowRecordMetadata *_escrowInformationMetadata;
+    NSString *_label;
+    NSString *_recordId;
+    OTEscrowRecord_RecordStatus _recordStatus;
+    OTEscrowRecord_RecordViability _recordViability;
+    OTEscrowRecord_RecoveryStatus _recoveryStatus;
+    NSString *_serialNumber;
+    OTEscrowRecord_SOSViability _viabilityStatus;
+    struct {
+        int coolOffEnd:1;
+        int creationDate:1;
+        int remainingAttempts:1;
+        int silentAttemptAllowed:1;
+        int recordStatus:1;
+        int recordViability:1;
+        int recoveryStatus:1;
+        int viabilityStatus:1;
+    } _has;
+}
+
+
+@property (nonatomic) BOOL hasCreationDate;
+@property (nonatomic) uint64_t creationDate;
+
+@property (nonatomic) BOOL hasRemainingAttempts;
+@property (nonatomic) uint64_t remainingAttempts;
+
+@property (nonatomic, readonly) BOOL hasEscrowInformationMetadata;
+@property (nonatomic, retain) OTEscrowRecordMetadata *escrowInformationMetadata;
+
+@property (nonatomic, readonly) BOOL hasLabel;
+@property (nonatomic, retain) NSString *label;
+
+@property (nonatomic) BOOL hasSilentAttemptAllowed;
+/**
+ * optional reserved string reserved5 = 5;
+ * optional reserved string reserved6 = 6;
+ * optional reserved string reserved7 = 7;
+ * optional reserved string reserved8 = 8;
+ */
+@property (nonatomic) uint64_t silentAttemptAllowed;
+
+@property (nonatomic) BOOL hasRecordStatus;
+@property (nonatomic) OTEscrowRecord_RecordStatus recordStatus;
+- (NSString *)recordStatusAsString:(OTEscrowRecord_RecordStatus)value;
+- (OTEscrowRecord_RecordStatus)StringAsRecordStatus:(NSString *)str;
+
+@property (nonatomic, readonly) BOOL hasRecordId;
+@property (nonatomic, retain) NSString *recordId;
+
+@property (nonatomic) BOOL hasRecoveryStatus;
+@property (nonatomic) OTEscrowRecord_RecoveryStatus recoveryStatus;
+- (NSString *)recoveryStatusAsString:(OTEscrowRecord_RecoveryStatus)value;
+- (OTEscrowRecord_RecoveryStatus)StringAsRecoveryStatus:(NSString *)str;
+
+@property (nonatomic) BOOL hasCoolOffEnd;
+@property (nonatomic) uint64_t coolOffEnd;
+
+@property (nonatomic, readonly) BOOL hasSerialNumber;
+@property (nonatomic, retain) NSString *serialNumber;
+
+@property (nonatomic) BOOL hasRecordViability;
+@property (nonatomic) OTEscrowRecord_RecordViability recordViability;
+- (NSString *)recordViabilityAsString:(OTEscrowRecord_RecordViability)value;
+- (OTEscrowRecord_RecordViability)StringAsRecordViability:(NSString *)str;
+
+@property (nonatomic) BOOL hasViabilityStatus;
+@property (nonatomic) OTEscrowRecord_SOSViability viabilityStatus;
+- (NSString *)viabilityStatusAsString:(OTEscrowRecord_SOSViability)value;
+- (OTEscrowRecord_SOSViability)StringAsViabilityStatus:(NSString *)str;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTEscrowRecord *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTEscrowRecord *)other;
+
+OTESCROWRECORD_FUNCTION BOOL OTEscrowRecordReadFrom(__unsafe_unretained OTEscrowRecord *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecord.m b/keychain/ot/proto/generated_source/OTEscrowRecord.m
new file mode 100644 (file)
index 0000000..1650cf9
--- /dev/null
@@ -0,0 +1,695 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import "OTEscrowRecord.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#import "OTEscrowRecordMetadata.h"
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTEscrowRecord
+
+@synthesize creationDate = _creationDate;
+- (void)setCreationDate:(uint64_t)v
+{
+    _has.creationDate = YES;
+    _creationDate = v;
+}
+- (void)setHasCreationDate:(BOOL)f
+{
+    _has.creationDate = f;
+}
+- (BOOL)hasCreationDate
+{
+    return _has.creationDate != 0;
+}
+@synthesize remainingAttempts = _remainingAttempts;
+- (void)setRemainingAttempts:(uint64_t)v
+{
+    _has.remainingAttempts = YES;
+    _remainingAttempts = v;
+}
+- (void)setHasRemainingAttempts:(BOOL)f
+{
+    _has.remainingAttempts = f;
+}
+- (BOOL)hasRemainingAttempts
+{
+    return _has.remainingAttempts != 0;
+}
+- (BOOL)hasEscrowInformationMetadata
+{
+    return _escrowInformationMetadata != nil;
+}
+@synthesize escrowInformationMetadata = _escrowInformationMetadata;
+- (BOOL)hasLabel
+{
+    return _label != nil;
+}
+@synthesize label = _label;
+@synthesize silentAttemptAllowed = _silentAttemptAllowed;
+- (void)setSilentAttemptAllowed:(uint64_t)v
+{
+    _has.silentAttemptAllowed = YES;
+    _silentAttemptAllowed = v;
+}
+- (void)setHasSilentAttemptAllowed:(BOOL)f
+{
+    _has.silentAttemptAllowed = f;
+}
+- (BOOL)hasSilentAttemptAllowed
+{
+    return _has.silentAttemptAllowed != 0;
+}
+@synthesize recordStatus = _recordStatus;
+- (OTEscrowRecord_RecordStatus)recordStatus
+{
+    return _has.recordStatus ? _recordStatus : OTEscrowRecord_RecordStatus_RECORD_STATUS_VALID;
+}
+- (void)setRecordStatus:(OTEscrowRecord_RecordStatus)v
+{
+    _has.recordStatus = YES;
+    _recordStatus = v;
+}
+- (void)setHasRecordStatus:(BOOL)f
+{
+    _has.recordStatus = f;
+}
+- (BOOL)hasRecordStatus
+{
+    return _has.recordStatus != 0;
+}
+- (NSString *)recordStatusAsString:(OTEscrowRecord_RecordStatus)value
+{
+    return OTEscrowRecord_RecordStatusAsString(value);
+}
+- (OTEscrowRecord_RecordStatus)StringAsRecordStatus:(NSString *)str
+{
+    return StringAsOTEscrowRecord_RecordStatus(str);
+}
+- (BOOL)hasRecordId
+{
+    return _recordId != nil;
+}
+@synthesize recordId = _recordId;
+@synthesize recoveryStatus = _recoveryStatus;
+- (OTEscrowRecord_RecoveryStatus)recoveryStatus
+{
+    return _has.recoveryStatus ? _recoveryStatus : OTEscrowRecord_RecoveryStatus_RECOVERY_STATUS_VALID;
+}
+- (void)setRecoveryStatus:(OTEscrowRecord_RecoveryStatus)v
+{
+    _has.recoveryStatus = YES;
+    _recoveryStatus = v;
+}
+- (void)setHasRecoveryStatus:(BOOL)f
+{
+    _has.recoveryStatus = f;
+}
+- (BOOL)hasRecoveryStatus
+{
+    return _has.recoveryStatus != 0;
+}
+- (NSString *)recoveryStatusAsString:(OTEscrowRecord_RecoveryStatus)value
+{
+    return OTEscrowRecord_RecoveryStatusAsString(value);
+}
+- (OTEscrowRecord_RecoveryStatus)StringAsRecoveryStatus:(NSString *)str
+{
+    return StringAsOTEscrowRecord_RecoveryStatus(str);
+}
+@synthesize coolOffEnd = _coolOffEnd;
+- (void)setCoolOffEnd:(uint64_t)v
+{
+    _has.coolOffEnd = YES;
+    _coolOffEnd = v;
+}
+- (void)setHasCoolOffEnd:(BOOL)f
+{
+    _has.coolOffEnd = f;
+}
+- (BOOL)hasCoolOffEnd
+{
+    return _has.coolOffEnd != 0;
+}
+- (BOOL)hasSerialNumber
+{
+    return _serialNumber != nil;
+}
+@synthesize serialNumber = _serialNumber;
+@synthesize recordViability = _recordViability;
+- (OTEscrowRecord_RecordViability)recordViability
+{
+    return _has.recordViability ? _recordViability : OTEscrowRecord_RecordViability_RECORD_VIABILITY_FULLY_VIABLE;
+}
+- (void)setRecordViability:(OTEscrowRecord_RecordViability)v
+{
+    _has.recordViability = YES;
+    _recordViability = v;
+}
+- (void)setHasRecordViability:(BOOL)f
+{
+    _has.recordViability = f;
+}
+- (BOOL)hasRecordViability
+{
+    return _has.recordViability != 0;
+}
+- (NSString *)recordViabilityAsString:(OTEscrowRecord_RecordViability)value
+{
+    return OTEscrowRecord_RecordViabilityAsString(value);
+}
+- (OTEscrowRecord_RecordViability)StringAsRecordViability:(NSString *)str
+{
+    return StringAsOTEscrowRecord_RecordViability(str);
+}
+@synthesize viabilityStatus = _viabilityStatus;
+- (OTEscrowRecord_SOSViability)viabilityStatus
+{
+    return _has.viabilityStatus ? _viabilityStatus : OTEscrowRecord_SOSViability_SOS_VIABLE_UNKNOWN;
+}
+- (void)setViabilityStatus:(OTEscrowRecord_SOSViability)v
+{
+    _has.viabilityStatus = YES;
+    _viabilityStatus = v;
+}
+- (void)setHasViabilityStatus:(BOOL)f
+{
+    _has.viabilityStatus = f;
+}
+- (BOOL)hasViabilityStatus
+{
+    return _has.viabilityStatus != 0;
+}
+- (NSString *)viabilityStatusAsString:(OTEscrowRecord_SOSViability)value
+{
+    return OTEscrowRecord_SOSViabilityAsString(value);
+}
+- (OTEscrowRecord_SOSViability)StringAsViabilityStatus:(NSString *)str
+{
+    return StringAsOTEscrowRecord_SOSViability(str);
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_has.creationDate)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_creationDate] forKey:@"creation_date"];
+    }
+    if (self->_has.remainingAttempts)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_remainingAttempts] forKey:@"remaining_attempts"];
+    }
+    if (self->_escrowInformationMetadata)
+    {
+        [dict setObject:[_escrowInformationMetadata dictionaryRepresentation] forKey:@"escrow_information_metadata"];
+    }
+    if (self->_label)
+    {
+        [dict setObject:self->_label forKey:@"label"];
+    }
+    if (self->_has.silentAttemptAllowed)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_silentAttemptAllowed] forKey:@"silent_attempt_allowed"];
+    }
+    if (self->_has.recordStatus)
+    {
+        [dict setObject:OTEscrowRecord_RecordStatusAsString(self->_recordStatus) forKey:@"record_status"];
+    }
+    if (self->_recordId)
+    {
+        [dict setObject:self->_recordId forKey:@"record_id"];
+    }
+    if (self->_has.recoveryStatus)
+    {
+        [dict setObject:OTEscrowRecord_RecoveryStatusAsString(self->_recoveryStatus) forKey:@"recovery_status"];
+    }
+    if (self->_has.coolOffEnd)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_coolOffEnd] forKey:@"cool_off_end"];
+    }
+    if (self->_serialNumber)
+    {
+        [dict setObject:self->_serialNumber forKey:@"serial_number"];
+    }
+    if (self->_has.recordViability)
+    {
+        [dict setObject:OTEscrowRecord_RecordViabilityAsString(self->_recordViability) forKey:@"record_viability"];
+    }
+    if (self->_has.viabilityStatus)
+    {
+        [dict setObject:OTEscrowRecord_SOSViabilityAsString(self->_viabilityStatus) forKey:@"viability_status"];
+    }
+    return dict;
+}
+
+BOOL OTEscrowRecordReadFrom(__unsafe_unretained OTEscrowRecord *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* creationDate */:
+            {
+                self->_has.creationDate = YES;
+                self->_creationDate = PBReaderReadUint64(reader);
+            }
+            break;
+            case 2 /* remainingAttempts */:
+            {
+                self->_has.remainingAttempts = YES;
+                self->_remainingAttempts = PBReaderReadUint64(reader);
+            }
+            break;
+            case 3 /* escrowInformationMetadata */:
+            {
+                OTEscrowRecordMetadata *new_escrowInformationMetadata = [[OTEscrowRecordMetadata alloc] init];
+                self->_escrowInformationMetadata = new_escrowInformationMetadata;
+                PBDataReaderMark mark_escrowInformationMetadata;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_escrowInformationMetadata);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTEscrowRecordMetadataReadFrom(new_escrowInformationMetadata, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_escrowInformationMetadata);
+            }
+            break;
+            case 4 /* label */:
+            {
+                NSString *new_label = PBReaderReadString(reader);
+                self->_label = new_label;
+            }
+            break;
+            case 9 /* silentAttemptAllowed */:
+            {
+                self->_has.silentAttemptAllowed = YES;
+                self->_silentAttemptAllowed = PBReaderReadUint64(reader);
+            }
+            break;
+            case 10 /* recordStatus */:
+            {
+                self->_has.recordStatus = YES;
+                self->_recordStatus = PBReaderReadInt32(reader);
+            }
+            break;
+            case 11 /* recordId */:
+            {
+                NSString *new_recordId = PBReaderReadString(reader);
+                self->_recordId = new_recordId;
+            }
+            break;
+            case 12 /* recoveryStatus */:
+            {
+                self->_has.recoveryStatus = YES;
+                self->_recoveryStatus = PBReaderReadInt32(reader);
+            }
+            break;
+            case 13 /* coolOffEnd */:
+            {
+                self->_has.coolOffEnd = YES;
+                self->_coolOffEnd = PBReaderReadUint64(reader);
+            }
+            break;
+            case 14 /* serialNumber */:
+            {
+                NSString *new_serialNumber = PBReaderReadString(reader);
+                self->_serialNumber = new_serialNumber;
+            }
+            break;
+            case 15 /* recordViability */:
+            {
+                self->_has.recordViability = YES;
+                self->_recordViability = PBReaderReadInt32(reader);
+            }
+            break;
+            case 16 /* viabilityStatus */:
+            {
+                self->_has.viabilityStatus = YES;
+                self->_viabilityStatus = PBReaderReadInt32(reader);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTEscrowRecordReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* creationDate */
+    {
+        if (self->_has.creationDate)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_creationDate, 1);
+        }
+    }
+    /* remainingAttempts */
+    {
+        if (self->_has.remainingAttempts)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_remainingAttempts, 2);
+        }
+    }
+    /* escrowInformationMetadata */
+    {
+        if (self->_escrowInformationMetadata != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_escrowInformationMetadata, 3);
+        }
+    }
+    /* label */
+    {
+        if (self->_label)
+        {
+            PBDataWriterWriteStringField(writer, self->_label, 4);
+        }
+    }
+    /* silentAttemptAllowed */
+    {
+        if (self->_has.silentAttemptAllowed)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_silentAttemptAllowed, 9);
+        }
+    }
+    /* recordStatus */
+    {
+        if (self->_has.recordStatus)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_recordStatus, 10);
+        }
+    }
+    /* recordId */
+    {
+        if (self->_recordId)
+        {
+            PBDataWriterWriteStringField(writer, self->_recordId, 11);
+        }
+    }
+    /* recoveryStatus */
+    {
+        if (self->_has.recoveryStatus)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_recoveryStatus, 12);
+        }
+    }
+    /* coolOffEnd */
+    {
+        if (self->_has.coolOffEnd)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_coolOffEnd, 13);
+        }
+    }
+    /* serialNumber */
+    {
+        if (self->_serialNumber)
+        {
+            PBDataWriterWriteStringField(writer, self->_serialNumber, 14);
+        }
+    }
+    /* recordViability */
+    {
+        if (self->_has.recordViability)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_recordViability, 15);
+        }
+    }
+    /* viabilityStatus */
+    {
+        if (self->_has.viabilityStatus)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_viabilityStatus, 16);
+        }
+    }
+}
+
+- (void)copyTo:(OTEscrowRecord *)other
+{
+    if (self->_has.creationDate)
+    {
+        other->_creationDate = _creationDate;
+        other->_has.creationDate = YES;
+    }
+    if (self->_has.remainingAttempts)
+    {
+        other->_remainingAttempts = _remainingAttempts;
+        other->_has.remainingAttempts = YES;
+    }
+    if (_escrowInformationMetadata)
+    {
+        other.escrowInformationMetadata = _escrowInformationMetadata;
+    }
+    if (_label)
+    {
+        other.label = _label;
+    }
+    if (self->_has.silentAttemptAllowed)
+    {
+        other->_silentAttemptAllowed = _silentAttemptAllowed;
+        other->_has.silentAttemptAllowed = YES;
+    }
+    if (self->_has.recordStatus)
+    {
+        other->_recordStatus = _recordStatus;
+        other->_has.recordStatus = YES;
+    }
+    if (_recordId)
+    {
+        other.recordId = _recordId;
+    }
+    if (self->_has.recoveryStatus)
+    {
+        other->_recoveryStatus = _recoveryStatus;
+        other->_has.recoveryStatus = YES;
+    }
+    if (self->_has.coolOffEnd)
+    {
+        other->_coolOffEnd = _coolOffEnd;
+        other->_has.coolOffEnd = YES;
+    }
+    if (_serialNumber)
+    {
+        other.serialNumber = _serialNumber;
+    }
+    if (self->_has.recordViability)
+    {
+        other->_recordViability = _recordViability;
+        other->_has.recordViability = YES;
+    }
+    if (self->_has.viabilityStatus)
+    {
+        other->_viabilityStatus = _viabilityStatus;
+        other->_has.viabilityStatus = YES;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTEscrowRecord *copy = [[[self class] allocWithZone:zone] init];
+    if (self->_has.creationDate)
+    {
+        copy->_creationDate = _creationDate;
+        copy->_has.creationDate = YES;
+    }
+    if (self->_has.remainingAttempts)
+    {
+        copy->_remainingAttempts = _remainingAttempts;
+        copy->_has.remainingAttempts = YES;
+    }
+    copy->_escrowInformationMetadata = [_escrowInformationMetadata copyWithZone:zone];
+    copy->_label = [_label copyWithZone:zone];
+    if (self->_has.silentAttemptAllowed)
+    {
+        copy->_silentAttemptAllowed = _silentAttemptAllowed;
+        copy->_has.silentAttemptAllowed = YES;
+    }
+    if (self->_has.recordStatus)
+    {
+        copy->_recordStatus = _recordStatus;
+        copy->_has.recordStatus = YES;
+    }
+    copy->_recordId = [_recordId copyWithZone:zone];
+    if (self->_has.recoveryStatus)
+    {
+        copy->_recoveryStatus = _recoveryStatus;
+        copy->_has.recoveryStatus = YES;
+    }
+    if (self->_has.coolOffEnd)
+    {
+        copy->_coolOffEnd = _coolOffEnd;
+        copy->_has.coolOffEnd = YES;
+    }
+    copy->_serialNumber = [_serialNumber copyWithZone:zone];
+    if (self->_has.recordViability)
+    {
+        copy->_recordViability = _recordViability;
+        copy->_has.recordViability = YES;
+    }
+    if (self->_has.viabilityStatus)
+    {
+        copy->_viabilityStatus = _viabilityStatus;
+        copy->_has.viabilityStatus = YES;
+    }
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTEscrowRecord *other = (OTEscrowRecord *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((self->_has.creationDate && other->_has.creationDate && self->_creationDate == other->_creationDate) || (!self->_has.creationDate && !other->_has.creationDate))
+    &&
+    ((self->_has.remainingAttempts && other->_has.remainingAttempts && self->_remainingAttempts == other->_remainingAttempts) || (!self->_has.remainingAttempts && !other->_has.remainingAttempts))
+    &&
+    ((!self->_escrowInformationMetadata && !other->_escrowInformationMetadata) || [self->_escrowInformationMetadata isEqual:other->_escrowInformationMetadata])
+    &&
+    ((!self->_label && !other->_label) || [self->_label isEqual:other->_label])
+    &&
+    ((self->_has.silentAttemptAllowed && other->_has.silentAttemptAllowed && self->_silentAttemptAllowed == other->_silentAttemptAllowed) || (!self->_has.silentAttemptAllowed && !other->_has.silentAttemptAllowed))
+    &&
+    ((self->_has.recordStatus && other->_has.recordStatus && self->_recordStatus == other->_recordStatus) || (!self->_has.recordStatus && !other->_has.recordStatus))
+    &&
+    ((!self->_recordId && !other->_recordId) || [self->_recordId isEqual:other->_recordId])
+    &&
+    ((self->_has.recoveryStatus && other->_has.recoveryStatus && self->_recoveryStatus == other->_recoveryStatus) || (!self->_has.recoveryStatus && !other->_has.recoveryStatus))
+    &&
+    ((self->_has.coolOffEnd && other->_has.coolOffEnd && self->_coolOffEnd == other->_coolOffEnd) || (!self->_has.coolOffEnd && !other->_has.coolOffEnd))
+    &&
+    ((!self->_serialNumber && !other->_serialNumber) || [self->_serialNumber isEqual:other->_serialNumber])
+    &&
+    ((self->_has.recordViability && other->_has.recordViability && self->_recordViability == other->_recordViability) || (!self->_has.recordViability && !other->_has.recordViability))
+    &&
+    ((self->_has.viabilityStatus && other->_has.viabilityStatus && self->_viabilityStatus == other->_viabilityStatus) || (!self->_has.viabilityStatus && !other->_has.viabilityStatus))
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    (self->_has.creationDate ? PBHashInt((NSUInteger)self->_creationDate) : 0)
+    ^
+    (self->_has.remainingAttempts ? PBHashInt((NSUInteger)self->_remainingAttempts) : 0)
+    ^
+    [self->_escrowInformationMetadata hash]
+    ^
+    [self->_label hash]
+    ^
+    (self->_has.silentAttemptAllowed ? PBHashInt((NSUInteger)self->_silentAttemptAllowed) : 0)
+    ^
+    (self->_has.recordStatus ? PBHashInt((NSUInteger)self->_recordStatus) : 0)
+    ^
+    [self->_recordId hash]
+    ^
+    (self->_has.recoveryStatus ? PBHashInt((NSUInteger)self->_recoveryStatus) : 0)
+    ^
+    (self->_has.coolOffEnd ? PBHashInt((NSUInteger)self->_coolOffEnd) : 0)
+    ^
+    [self->_serialNumber hash]
+    ^
+    (self->_has.recordViability ? PBHashInt((NSUInteger)self->_recordViability) : 0)
+    ^
+    (self->_has.viabilityStatus ? PBHashInt((NSUInteger)self->_viabilityStatus) : 0)
+    ;
+}
+
+- (void)mergeFrom:(OTEscrowRecord *)other
+{
+    if (other->_has.creationDate)
+    {
+        self->_creationDate = other->_creationDate;
+        self->_has.creationDate = YES;
+    }
+    if (other->_has.remainingAttempts)
+    {
+        self->_remainingAttempts = other->_remainingAttempts;
+        self->_has.remainingAttempts = YES;
+    }
+    if (self->_escrowInformationMetadata && other->_escrowInformationMetadata)
+    {
+        [self->_escrowInformationMetadata mergeFrom:other->_escrowInformationMetadata];
+    }
+    else if (!self->_escrowInformationMetadata && other->_escrowInformationMetadata)
+    {
+        [self setEscrowInformationMetadata:other->_escrowInformationMetadata];
+    }
+    if (other->_label)
+    {
+        [self setLabel:other->_label];
+    }
+    if (other->_has.silentAttemptAllowed)
+    {
+        self->_silentAttemptAllowed = other->_silentAttemptAllowed;
+        self->_has.silentAttemptAllowed = YES;
+    }
+    if (other->_has.recordStatus)
+    {
+        self->_recordStatus = other->_recordStatus;
+        self->_has.recordStatus = YES;
+    }
+    if (other->_recordId)
+    {
+        [self setRecordId:other->_recordId];
+    }
+    if (other->_has.recoveryStatus)
+    {
+        self->_recoveryStatus = other->_recoveryStatus;
+        self->_has.recoveryStatus = YES;
+    }
+    if (other->_has.coolOffEnd)
+    {
+        self->_coolOffEnd = other->_coolOffEnd;
+        self->_has.coolOffEnd = YES;
+    }
+    if (other->_serialNumber)
+    {
+        [self setSerialNumber:other->_serialNumber];
+    }
+    if (other->_has.recordViability)
+    {
+        self->_recordViability = other->_recordViability;
+        self->_has.recordViability = YES;
+    }
+    if (other->_has.viabilityStatus)
+    {
+        self->_viabilityStatus = other->_viabilityStatus;
+        self->_has.viabilityStatus = YES;
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h b/keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h
new file mode 100644 (file)
index 0000000..1d75c3a
--- /dev/null
@@ -0,0 +1,73 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+@class OTEscrowRecordMetadataClientMetadata;
+
+#ifdef __cplusplus
+#define OTESCROWRECORDMETADATA_FUNCTION extern "C"
+#else
+#define OTESCROWRECORDMETADATA_FUNCTION extern
+#endif
+
+@interface OTEscrowRecordMetadata : PBCodable <NSCopying>
+{
+    uint64_t _secureBackupTimestamp;
+    uint64_t _secureBackupUsesMultipleIcscs;
+    NSData *_backupKeybagDigest;
+    NSString *_bottleId;
+    NSString *_bottleValidity;
+    OTEscrowRecordMetadataClientMetadata *_clientMetadata;
+    NSData *_escrowedSpki;
+    NSData *_peerInfo;
+    NSString *_serial;
+    struct {
+        int secureBackupTimestamp:1;
+        int secureBackupUsesMultipleIcscs:1;
+    } _has;
+}
+
+
+@property (nonatomic, readonly) BOOL hasBackupKeybagDigest;
+@property (nonatomic, retain) NSData *backupKeybagDigest;
+
+@property (nonatomic, readonly) BOOL hasClientMetadata;
+@property (nonatomic, retain) OTEscrowRecordMetadataClientMetadata *clientMetadata;
+
+@property (nonatomic) BOOL hasSecureBackupUsesMultipleIcscs;
+@property (nonatomic) uint64_t secureBackupUsesMultipleIcscs;
+
+@property (nonatomic, readonly) BOOL hasBottleId;
+@property (nonatomic, retain) NSString *bottleId;
+
+@property (nonatomic) BOOL hasSecureBackupTimestamp;
+@property (nonatomic) uint64_t secureBackupTimestamp;
+
+@property (nonatomic, readonly) BOOL hasEscrowedSpki;
+@property (nonatomic, retain) NSData *escrowedSpki;
+
+@property (nonatomic, readonly) BOOL hasPeerInfo;
+@property (nonatomic, retain) NSData *peerInfo;
+
+@property (nonatomic, readonly) BOOL hasBottleValidity;
+@property (nonatomic, retain) NSString *bottleValidity;
+
+@property (nonatomic, readonly) BOOL hasSerial;
+@property (nonatomic, retain) NSString *serial;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTEscrowRecordMetadata *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTEscrowRecordMetadata *)other;
+
+OTESCROWRECORDMETADATA_FUNCTION BOOL OTEscrowRecordMetadataReadFrom(__unsafe_unretained OTEscrowRecordMetadata *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecordMetadata.m b/keychain/ot/proto/generated_source/OTEscrowRecordMetadata.m
new file mode 100644 (file)
index 0000000..ca48c52
--- /dev/null
@@ -0,0 +1,452 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import "OTEscrowRecordMetadata.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#import "OTEscrowRecordMetadataClientMetadata.h"
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTEscrowRecordMetadata
+
+- (BOOL)hasBackupKeybagDigest
+{
+    return _backupKeybagDigest != nil;
+}
+@synthesize backupKeybagDigest = _backupKeybagDigest;
+- (BOOL)hasClientMetadata
+{
+    return _clientMetadata != nil;
+}
+@synthesize clientMetadata = _clientMetadata;
+@synthesize secureBackupUsesMultipleIcscs = _secureBackupUsesMultipleIcscs;
+- (void)setSecureBackupUsesMultipleIcscs:(uint64_t)v
+{
+    _has.secureBackupUsesMultipleIcscs = YES;
+    _secureBackupUsesMultipleIcscs = v;
+}
+- (void)setHasSecureBackupUsesMultipleIcscs:(BOOL)f
+{
+    _has.secureBackupUsesMultipleIcscs = f;
+}
+- (BOOL)hasSecureBackupUsesMultipleIcscs
+{
+    return _has.secureBackupUsesMultipleIcscs != 0;
+}
+- (BOOL)hasBottleId
+{
+    return _bottleId != nil;
+}
+@synthesize bottleId = _bottleId;
+@synthesize secureBackupTimestamp = _secureBackupTimestamp;
+- (void)setSecureBackupTimestamp:(uint64_t)v
+{
+    _has.secureBackupTimestamp = YES;
+    _secureBackupTimestamp = v;
+}
+- (void)setHasSecureBackupTimestamp:(BOOL)f
+{
+    _has.secureBackupTimestamp = f;
+}
+- (BOOL)hasSecureBackupTimestamp
+{
+    return _has.secureBackupTimestamp != 0;
+}
+- (BOOL)hasEscrowedSpki
+{
+    return _escrowedSpki != nil;
+}
+@synthesize escrowedSpki = _escrowedSpki;
+- (BOOL)hasPeerInfo
+{
+    return _peerInfo != nil;
+}
+@synthesize peerInfo = _peerInfo;
+- (BOOL)hasBottleValidity
+{
+    return _bottleValidity != nil;
+}
+@synthesize bottleValidity = _bottleValidity;
+- (BOOL)hasSerial
+{
+    return _serial != nil;
+}
+@synthesize serial = _serial;
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_backupKeybagDigest)
+    {
+        [dict setObject:self->_backupKeybagDigest forKey:@"backup_keybag_digest"];
+    }
+    if (self->_clientMetadata)
+    {
+        [dict setObject:[_clientMetadata dictionaryRepresentation] forKey:@"client_metadata"];
+    }
+    if (self->_has.secureBackupUsesMultipleIcscs)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupUsesMultipleIcscs] forKey:@"secure_backup_uses_multiple_icscs"];
+    }
+    if (self->_bottleId)
+    {
+        [dict setObject:self->_bottleId forKey:@"bottle_id"];
+    }
+    if (self->_has.secureBackupTimestamp)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupTimestamp] forKey:@"secure_backup_timestamp"];
+    }
+    if (self->_escrowedSpki)
+    {
+        [dict setObject:self->_escrowedSpki forKey:@"escrowed_spki"];
+    }
+    if (self->_peerInfo)
+    {
+        [dict setObject:self->_peerInfo forKey:@"peer_info"];
+    }
+    if (self->_bottleValidity)
+    {
+        [dict setObject:self->_bottleValidity forKey:@"bottle_validity"];
+    }
+    if (self->_serial)
+    {
+        [dict setObject:self->_serial forKey:@"serial"];
+    }
+    return dict;
+}
+
+BOOL OTEscrowRecordMetadataReadFrom(__unsafe_unretained OTEscrowRecordMetadata *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* backupKeybagDigest */:
+            {
+                NSData *new_backupKeybagDigest = PBReaderReadData(reader);
+                self->_backupKeybagDigest = new_backupKeybagDigest;
+            }
+            break;
+            case 2 /* clientMetadata */:
+            {
+                OTEscrowRecordMetadataClientMetadata *new_clientMetadata = [[OTEscrowRecordMetadataClientMetadata alloc] init];
+                self->_clientMetadata = new_clientMetadata;
+                PBDataReaderMark mark_clientMetadata;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_clientMetadata);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTEscrowRecordMetadataClientMetadataReadFrom(new_clientMetadata, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_clientMetadata);
+            }
+            break;
+            case 3 /* secureBackupUsesMultipleIcscs */:
+            {
+                self->_has.secureBackupUsesMultipleIcscs = YES;
+                self->_secureBackupUsesMultipleIcscs = PBReaderReadUint64(reader);
+            }
+            break;
+            case 4 /* bottleId */:
+            {
+                NSString *new_bottleId = PBReaderReadString(reader);
+                self->_bottleId = new_bottleId;
+            }
+            break;
+            case 5 /* secureBackupTimestamp */:
+            {
+                self->_has.secureBackupTimestamp = YES;
+                self->_secureBackupTimestamp = PBReaderReadUint64(reader);
+            }
+            break;
+            case 6 /* escrowedSpki */:
+            {
+                NSData *new_escrowedSpki = PBReaderReadData(reader);
+                self->_escrowedSpki = new_escrowedSpki;
+            }
+            break;
+            case 7 /* peerInfo */:
+            {
+                NSData *new_peerInfo = PBReaderReadData(reader);
+                self->_peerInfo = new_peerInfo;
+            }
+            break;
+            case 8 /* bottleValidity */:
+            {
+                NSString *new_bottleValidity = PBReaderReadString(reader);
+                self->_bottleValidity = new_bottleValidity;
+            }
+            break;
+            case 9 /* serial */:
+            {
+                NSString *new_serial = PBReaderReadString(reader);
+                self->_serial = new_serial;
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTEscrowRecordMetadataReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* backupKeybagDigest */
+    {
+        if (self->_backupKeybagDigest)
+        {
+            PBDataWriterWriteDataField(writer, self->_backupKeybagDigest, 1);
+        }
+    }
+    /* clientMetadata */
+    {
+        if (self->_clientMetadata != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_clientMetadata, 2);
+        }
+    }
+    /* secureBackupUsesMultipleIcscs */
+    {
+        if (self->_has.secureBackupUsesMultipleIcscs)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupUsesMultipleIcscs, 3);
+        }
+    }
+    /* bottleId */
+    {
+        if (self->_bottleId)
+        {
+            PBDataWriterWriteStringField(writer, self->_bottleId, 4);
+        }
+    }
+    /* secureBackupTimestamp */
+    {
+        if (self->_has.secureBackupTimestamp)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupTimestamp, 5);
+        }
+    }
+    /* escrowedSpki */
+    {
+        if (self->_escrowedSpki)
+        {
+            PBDataWriterWriteDataField(writer, self->_escrowedSpki, 6);
+        }
+    }
+    /* peerInfo */
+    {
+        if (self->_peerInfo)
+        {
+            PBDataWriterWriteDataField(writer, self->_peerInfo, 7);
+        }
+    }
+    /* bottleValidity */
+    {
+        if (self->_bottleValidity)
+        {
+            PBDataWriterWriteStringField(writer, self->_bottleValidity, 8);
+        }
+    }
+    /* serial */
+    {
+        if (self->_serial)
+        {
+            PBDataWriterWriteStringField(writer, self->_serial, 9);
+        }
+    }
+}
+
+- (void)copyTo:(OTEscrowRecordMetadata *)other
+{
+    if (_backupKeybagDigest)
+    {
+        other.backupKeybagDigest = _backupKeybagDigest;
+    }
+    if (_clientMetadata)
+    {
+        other.clientMetadata = _clientMetadata;
+    }
+    if (self->_has.secureBackupUsesMultipleIcscs)
+    {
+        other->_secureBackupUsesMultipleIcscs = _secureBackupUsesMultipleIcscs;
+        other->_has.secureBackupUsesMultipleIcscs = YES;
+    }
+    if (_bottleId)
+    {
+        other.bottleId = _bottleId;
+    }
+    if (self->_has.secureBackupTimestamp)
+    {
+        other->_secureBackupTimestamp = _secureBackupTimestamp;
+        other->_has.secureBackupTimestamp = YES;
+    }
+    if (_escrowedSpki)
+    {
+        other.escrowedSpki = _escrowedSpki;
+    }
+    if (_peerInfo)
+    {
+        other.peerInfo = _peerInfo;
+    }
+    if (_bottleValidity)
+    {
+        other.bottleValidity = _bottleValidity;
+    }
+    if (_serial)
+    {
+        other.serial = _serial;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTEscrowRecordMetadata *copy = [[[self class] allocWithZone:zone] init];
+    copy->_backupKeybagDigest = [_backupKeybagDigest copyWithZone:zone];
+    copy->_clientMetadata = [_clientMetadata copyWithZone:zone];
+    if (self->_has.secureBackupUsesMultipleIcscs)
+    {
+        copy->_secureBackupUsesMultipleIcscs = _secureBackupUsesMultipleIcscs;
+        copy->_has.secureBackupUsesMultipleIcscs = YES;
+    }
+    copy->_bottleId = [_bottleId copyWithZone:zone];
+    if (self->_has.secureBackupTimestamp)
+    {
+        copy->_secureBackupTimestamp = _secureBackupTimestamp;
+        copy->_has.secureBackupTimestamp = YES;
+    }
+    copy->_escrowedSpki = [_escrowedSpki copyWithZone:zone];
+    copy->_peerInfo = [_peerInfo copyWithZone:zone];
+    copy->_bottleValidity = [_bottleValidity copyWithZone:zone];
+    copy->_serial = [_serial copyWithZone:zone];
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTEscrowRecordMetadata *other = (OTEscrowRecordMetadata *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((!self->_backupKeybagDigest && !other->_backupKeybagDigest) || [self->_backupKeybagDigest isEqual:other->_backupKeybagDigest])
+    &&
+    ((!self->_clientMetadata && !other->_clientMetadata) || [self->_clientMetadata isEqual:other->_clientMetadata])
+    &&
+    ((self->_has.secureBackupUsesMultipleIcscs && other->_has.secureBackupUsesMultipleIcscs && self->_secureBackupUsesMultipleIcscs == other->_secureBackupUsesMultipleIcscs) || (!self->_has.secureBackupUsesMultipleIcscs && !other->_has.secureBackupUsesMultipleIcscs))
+    &&
+    ((!self->_bottleId && !other->_bottleId) || [self->_bottleId isEqual:other->_bottleId])
+    &&
+    ((self->_has.secureBackupTimestamp && other->_has.secureBackupTimestamp && self->_secureBackupTimestamp == other->_secureBackupTimestamp) || (!self->_has.secureBackupTimestamp && !other->_has.secureBackupTimestamp))
+    &&
+    ((!self->_escrowedSpki && !other->_escrowedSpki) || [self->_escrowedSpki isEqual:other->_escrowedSpki])
+    &&
+    ((!self->_peerInfo && !other->_peerInfo) || [self->_peerInfo isEqual:other->_peerInfo])
+    &&
+    ((!self->_bottleValidity && !other->_bottleValidity) || [self->_bottleValidity isEqual:other->_bottleValidity])
+    &&
+    ((!self->_serial && !other->_serial) || [self->_serial isEqual:other->_serial])
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    [self->_backupKeybagDigest hash]
+    ^
+    [self->_clientMetadata hash]
+    ^
+    (self->_has.secureBackupUsesMultipleIcscs ? PBHashInt((NSUInteger)self->_secureBackupUsesMultipleIcscs) : 0)
+    ^
+    [self->_bottleId hash]
+    ^
+    (self->_has.secureBackupTimestamp ? PBHashInt((NSUInteger)self->_secureBackupTimestamp) : 0)
+    ^
+    [self->_escrowedSpki hash]
+    ^
+    [self->_peerInfo hash]
+    ^
+    [self->_bottleValidity hash]
+    ^
+    [self->_serial hash]
+    ;
+}
+
+- (void)mergeFrom:(OTEscrowRecordMetadata *)other
+{
+    if (other->_backupKeybagDigest)
+    {
+        [self setBackupKeybagDigest:other->_backupKeybagDigest];
+    }
+    if (self->_clientMetadata && other->_clientMetadata)
+    {
+        [self->_clientMetadata mergeFrom:other->_clientMetadata];
+    }
+    else if (!self->_clientMetadata && other->_clientMetadata)
+    {
+        [self setClientMetadata:other->_clientMetadata];
+    }
+    if (other->_has.secureBackupUsesMultipleIcscs)
+    {
+        self->_secureBackupUsesMultipleIcscs = other->_secureBackupUsesMultipleIcscs;
+        self->_has.secureBackupUsesMultipleIcscs = YES;
+    }
+    if (other->_bottleId)
+    {
+        [self setBottleId:other->_bottleId];
+    }
+    if (other->_has.secureBackupTimestamp)
+    {
+        self->_secureBackupTimestamp = other->_secureBackupTimestamp;
+        self->_has.secureBackupTimestamp = YES;
+    }
+    if (other->_escrowedSpki)
+    {
+        [self setEscrowedSpki:other->_escrowedSpki];
+    }
+    if (other->_peerInfo)
+    {
+        [self setPeerInfo:other->_peerInfo];
+    }
+    if (other->_bottleValidity)
+    {
+        [self setBottleValidity:other->_bottleValidity];
+    }
+    if (other->_serial)
+    {
+        [self setSerial:other->_serial];
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h b/keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h
new file mode 100644 (file)
index 0000000..6b913b4
--- /dev/null
@@ -0,0 +1,86 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define OTESCROWRECORDMETADATACLIENTMETADATA_FUNCTION extern "C"
+#else
+#define OTESCROWRECORDMETADATACLIENTMETADATA_FUNCTION extern
+#endif
+
+@interface OTEscrowRecordMetadataClientMetadata : PBCodable <NSCopying>
+{
+    uint64_t _devicePlatform;
+    uint64_t _secureBackupMetadataTimestamp;
+    uint64_t _secureBackupNumericPassphraseLength;
+    uint64_t _secureBackupUsesComplexPassphrase;
+    uint64_t _secureBackupUsesNumericPassphrase;
+    NSString *_deviceColor;
+    NSString *_deviceEnclosureColor;
+    NSString *_deviceMid;
+    NSString *_deviceModel;
+    NSString *_deviceModelClass;
+    NSString *_deviceModelVersion;
+    NSString *_deviceName;
+    struct {
+        int devicePlatform:1;
+        int secureBackupMetadataTimestamp:1;
+        int secureBackupNumericPassphraseLength:1;
+        int secureBackupUsesComplexPassphrase:1;
+        int secureBackupUsesNumericPassphrase:1;
+    } _has;
+}
+
+
+@property (nonatomic) BOOL hasSecureBackupMetadataTimestamp;
+@property (nonatomic) uint64_t secureBackupMetadataTimestamp;
+
+@property (nonatomic) BOOL hasSecureBackupNumericPassphraseLength;
+@property (nonatomic) uint64_t secureBackupNumericPassphraseLength;
+
+@property (nonatomic) BOOL hasSecureBackupUsesComplexPassphrase;
+@property (nonatomic) uint64_t secureBackupUsesComplexPassphrase;
+
+@property (nonatomic) BOOL hasSecureBackupUsesNumericPassphrase;
+@property (nonatomic) uint64_t secureBackupUsesNumericPassphrase;
+
+@property (nonatomic, readonly) BOOL hasDeviceColor;
+@property (nonatomic, retain) NSString *deviceColor;
+
+@property (nonatomic, readonly) BOOL hasDeviceEnclosureColor;
+@property (nonatomic, retain) NSString *deviceEnclosureColor;
+
+@property (nonatomic, readonly) BOOL hasDeviceMid;
+@property (nonatomic, retain) NSString *deviceMid;
+
+@property (nonatomic, readonly) BOOL hasDeviceModel;
+@property (nonatomic, retain) NSString *deviceModel;
+
+@property (nonatomic, readonly) BOOL hasDeviceModelClass;
+@property (nonatomic, retain) NSString *deviceModelClass;
+
+@property (nonatomic, readonly) BOOL hasDeviceModelVersion;
+@property (nonatomic, retain) NSString *deviceModelVersion;
+
+@property (nonatomic, readonly) BOOL hasDeviceName;
+@property (nonatomic, retain) NSString *deviceName;
+
+@property (nonatomic) BOOL hasDevicePlatform;
+@property (nonatomic) uint64_t devicePlatform;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTEscrowRecordMetadataClientMetadata *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTEscrowRecordMetadataClientMetadata *)other;
+
+OTESCROWRECORDMETADATACLIENTMETADATA_FUNCTION BOOL OTEscrowRecordMetadataClientMetadataReadFrom(__unsafe_unretained OTEscrowRecordMetadataClientMetadata *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.m b/keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.m
new file mode 100644 (file)
index 0000000..6b27339
--- /dev/null
@@ -0,0 +1,584 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTEscrowRecord.proto
+
+#import "OTEscrowRecordMetadataClientMetadata.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTEscrowRecordMetadataClientMetadata
+
+@synthesize secureBackupMetadataTimestamp = _secureBackupMetadataTimestamp;
+- (void)setSecureBackupMetadataTimestamp:(uint64_t)v
+{
+    _has.secureBackupMetadataTimestamp = YES;
+    _secureBackupMetadataTimestamp = v;
+}
+- (void)setHasSecureBackupMetadataTimestamp:(BOOL)f
+{
+    _has.secureBackupMetadataTimestamp = f;
+}
+- (BOOL)hasSecureBackupMetadataTimestamp
+{
+    return _has.secureBackupMetadataTimestamp != 0;
+}
+@synthesize secureBackupNumericPassphraseLength = _secureBackupNumericPassphraseLength;
+- (void)setSecureBackupNumericPassphraseLength:(uint64_t)v
+{
+    _has.secureBackupNumericPassphraseLength = YES;
+    _secureBackupNumericPassphraseLength = v;
+}
+- (void)setHasSecureBackupNumericPassphraseLength:(BOOL)f
+{
+    _has.secureBackupNumericPassphraseLength = f;
+}
+- (BOOL)hasSecureBackupNumericPassphraseLength
+{
+    return _has.secureBackupNumericPassphraseLength != 0;
+}
+@synthesize secureBackupUsesComplexPassphrase = _secureBackupUsesComplexPassphrase;
+- (void)setSecureBackupUsesComplexPassphrase:(uint64_t)v
+{
+    _has.secureBackupUsesComplexPassphrase = YES;
+    _secureBackupUsesComplexPassphrase = v;
+}
+- (void)setHasSecureBackupUsesComplexPassphrase:(BOOL)f
+{
+    _has.secureBackupUsesComplexPassphrase = f;
+}
+- (BOOL)hasSecureBackupUsesComplexPassphrase
+{
+    return _has.secureBackupUsesComplexPassphrase != 0;
+}
+@synthesize secureBackupUsesNumericPassphrase = _secureBackupUsesNumericPassphrase;
+- (void)setSecureBackupUsesNumericPassphrase:(uint64_t)v
+{
+    _has.secureBackupUsesNumericPassphrase = YES;
+    _secureBackupUsesNumericPassphrase = v;
+}
+- (void)setHasSecureBackupUsesNumericPassphrase:(BOOL)f
+{
+    _has.secureBackupUsesNumericPassphrase = f;
+}
+- (BOOL)hasSecureBackupUsesNumericPassphrase
+{
+    return _has.secureBackupUsesNumericPassphrase != 0;
+}
+- (BOOL)hasDeviceColor
+{
+    return _deviceColor != nil;
+}
+@synthesize deviceColor = _deviceColor;
+- (BOOL)hasDeviceEnclosureColor
+{
+    return _deviceEnclosureColor != nil;
+}
+@synthesize deviceEnclosureColor = _deviceEnclosureColor;
+- (BOOL)hasDeviceMid
+{
+    return _deviceMid != nil;
+}
+@synthesize deviceMid = _deviceMid;
+- (BOOL)hasDeviceModel
+{
+    return _deviceModel != nil;
+}
+@synthesize deviceModel = _deviceModel;
+- (BOOL)hasDeviceModelClass
+{
+    return _deviceModelClass != nil;
+}
+@synthesize deviceModelClass = _deviceModelClass;
+- (BOOL)hasDeviceModelVersion
+{
+    return _deviceModelVersion != nil;
+}
+@synthesize deviceModelVersion = _deviceModelVersion;
+- (BOOL)hasDeviceName
+{
+    return _deviceName != nil;
+}
+@synthesize deviceName = _deviceName;
+@synthesize devicePlatform = _devicePlatform;
+- (void)setDevicePlatform:(uint64_t)v
+{
+    _has.devicePlatform = YES;
+    _devicePlatform = v;
+}
+- (void)setHasDevicePlatform:(BOOL)f
+{
+    _has.devicePlatform = f;
+}
+- (BOOL)hasDevicePlatform
+{
+    return _has.devicePlatform != 0;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_has.secureBackupMetadataTimestamp)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupMetadataTimestamp] forKey:@"secure_backup_metadata_timestamp"];
+    }
+    if (self->_has.secureBackupNumericPassphraseLength)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupNumericPassphraseLength] forKey:@"secure_backup_numeric_passphrase_length"];
+    }
+    if (self->_has.secureBackupUsesComplexPassphrase)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupUsesComplexPassphrase] forKey:@"secure_backup_uses_complex_passphrase"];
+    }
+    if (self->_has.secureBackupUsesNumericPassphrase)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_secureBackupUsesNumericPassphrase] forKey:@"secure_backup_uses_numeric_passphrase"];
+    }
+    if (self->_deviceColor)
+    {
+        [dict setObject:self->_deviceColor forKey:@"device_color"];
+    }
+    if (self->_deviceEnclosureColor)
+    {
+        [dict setObject:self->_deviceEnclosureColor forKey:@"device_enclosure_color"];
+    }
+    if (self->_deviceMid)
+    {
+        [dict setObject:self->_deviceMid forKey:@"device_mid"];
+    }
+    if (self->_deviceModel)
+    {
+        [dict setObject:self->_deviceModel forKey:@"device_model"];
+    }
+    if (self->_deviceModelClass)
+    {
+        [dict setObject:self->_deviceModelClass forKey:@"device_model_class"];
+    }
+    if (self->_deviceModelVersion)
+    {
+        [dict setObject:self->_deviceModelVersion forKey:@"device_model_version"];
+    }
+    if (self->_deviceName)
+    {
+        [dict setObject:self->_deviceName forKey:@"device_name"];
+    }
+    if (self->_has.devicePlatform)
+    {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:self->_devicePlatform] forKey:@"device_platform"];
+    }
+    return dict;
+}
+
+BOOL OTEscrowRecordMetadataClientMetadataReadFrom(__unsafe_unretained OTEscrowRecordMetadataClientMetadata *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* secureBackupMetadataTimestamp */:
+            {
+                self->_has.secureBackupMetadataTimestamp = YES;
+                self->_secureBackupMetadataTimestamp = PBReaderReadUint64(reader);
+            }
+            break;
+            case 2 /* secureBackupNumericPassphraseLength */:
+            {
+                self->_has.secureBackupNumericPassphraseLength = YES;
+                self->_secureBackupNumericPassphraseLength = PBReaderReadUint64(reader);
+            }
+            break;
+            case 3 /* secureBackupUsesComplexPassphrase */:
+            {
+                self->_has.secureBackupUsesComplexPassphrase = YES;
+                self->_secureBackupUsesComplexPassphrase = PBReaderReadUint64(reader);
+            }
+            break;
+            case 4 /* secureBackupUsesNumericPassphrase */:
+            {
+                self->_has.secureBackupUsesNumericPassphrase = YES;
+                self->_secureBackupUsesNumericPassphrase = PBReaderReadUint64(reader);
+            }
+            break;
+            case 5 /* deviceColor */:
+            {
+                NSString *new_deviceColor = PBReaderReadString(reader);
+                self->_deviceColor = new_deviceColor;
+            }
+            break;
+            case 6 /* deviceEnclosureColor */:
+            {
+                NSString *new_deviceEnclosureColor = PBReaderReadString(reader);
+                self->_deviceEnclosureColor = new_deviceEnclosureColor;
+            }
+            break;
+            case 7 /* deviceMid */:
+            {
+                NSString *new_deviceMid = PBReaderReadString(reader);
+                self->_deviceMid = new_deviceMid;
+            }
+            break;
+            case 8 /* deviceModel */:
+            {
+                NSString *new_deviceModel = PBReaderReadString(reader);
+                self->_deviceModel = new_deviceModel;
+            }
+            break;
+            case 9 /* deviceModelClass */:
+            {
+                NSString *new_deviceModelClass = PBReaderReadString(reader);
+                self->_deviceModelClass = new_deviceModelClass;
+            }
+            break;
+            case 10 /* deviceModelVersion */:
+            {
+                NSString *new_deviceModelVersion = PBReaderReadString(reader);
+                self->_deviceModelVersion = new_deviceModelVersion;
+            }
+            break;
+            case 11 /* deviceName */:
+            {
+                NSString *new_deviceName = PBReaderReadString(reader);
+                self->_deviceName = new_deviceName;
+            }
+            break;
+            case 12 /* devicePlatform */:
+            {
+                self->_has.devicePlatform = YES;
+                self->_devicePlatform = PBReaderReadUint64(reader);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTEscrowRecordMetadataClientMetadataReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* secureBackupMetadataTimestamp */
+    {
+        if (self->_has.secureBackupMetadataTimestamp)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupMetadataTimestamp, 1);
+        }
+    }
+    /* secureBackupNumericPassphraseLength */
+    {
+        if (self->_has.secureBackupNumericPassphraseLength)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupNumericPassphraseLength, 2);
+        }
+    }
+    /* secureBackupUsesComplexPassphrase */
+    {
+        if (self->_has.secureBackupUsesComplexPassphrase)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupUsesComplexPassphrase, 3);
+        }
+    }
+    /* secureBackupUsesNumericPassphrase */
+    {
+        if (self->_has.secureBackupUsesNumericPassphrase)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_secureBackupUsesNumericPassphrase, 4);
+        }
+    }
+    /* deviceColor */
+    {
+        if (self->_deviceColor)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceColor, 5);
+        }
+    }
+    /* deviceEnclosureColor */
+    {
+        if (self->_deviceEnclosureColor)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceEnclosureColor, 6);
+        }
+    }
+    /* deviceMid */
+    {
+        if (self->_deviceMid)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceMid, 7);
+        }
+    }
+    /* deviceModel */
+    {
+        if (self->_deviceModel)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceModel, 8);
+        }
+    }
+    /* deviceModelClass */
+    {
+        if (self->_deviceModelClass)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceModelClass, 9);
+        }
+    }
+    /* deviceModelVersion */
+    {
+        if (self->_deviceModelVersion)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceModelVersion, 10);
+        }
+    }
+    /* deviceName */
+    {
+        if (self->_deviceName)
+        {
+            PBDataWriterWriteStringField(writer, self->_deviceName, 11);
+        }
+    }
+    /* devicePlatform */
+    {
+        if (self->_has.devicePlatform)
+        {
+            PBDataWriterWriteUint64Field(writer, self->_devicePlatform, 12);
+        }
+    }
+}
+
+- (void)copyTo:(OTEscrowRecordMetadataClientMetadata *)other
+{
+    if (self->_has.secureBackupMetadataTimestamp)
+    {
+        other->_secureBackupMetadataTimestamp = _secureBackupMetadataTimestamp;
+        other->_has.secureBackupMetadataTimestamp = YES;
+    }
+    if (self->_has.secureBackupNumericPassphraseLength)
+    {
+        other->_secureBackupNumericPassphraseLength = _secureBackupNumericPassphraseLength;
+        other->_has.secureBackupNumericPassphraseLength = YES;
+    }
+    if (self->_has.secureBackupUsesComplexPassphrase)
+    {
+        other->_secureBackupUsesComplexPassphrase = _secureBackupUsesComplexPassphrase;
+        other->_has.secureBackupUsesComplexPassphrase = YES;
+    }
+    if (self->_has.secureBackupUsesNumericPassphrase)
+    {
+        other->_secureBackupUsesNumericPassphrase = _secureBackupUsesNumericPassphrase;
+        other->_has.secureBackupUsesNumericPassphrase = YES;
+    }
+    if (_deviceColor)
+    {
+        other.deviceColor = _deviceColor;
+    }
+    if (_deviceEnclosureColor)
+    {
+        other.deviceEnclosureColor = _deviceEnclosureColor;
+    }
+    if (_deviceMid)
+    {
+        other.deviceMid = _deviceMid;
+    }
+    if (_deviceModel)
+    {
+        other.deviceModel = _deviceModel;
+    }
+    if (_deviceModelClass)
+    {
+        other.deviceModelClass = _deviceModelClass;
+    }
+    if (_deviceModelVersion)
+    {
+        other.deviceModelVersion = _deviceModelVersion;
+    }
+    if (_deviceName)
+    {
+        other.deviceName = _deviceName;
+    }
+    if (self->_has.devicePlatform)
+    {
+        other->_devicePlatform = _devicePlatform;
+        other->_has.devicePlatform = YES;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTEscrowRecordMetadataClientMetadata *copy = [[[self class] allocWithZone:zone] init];
+    if (self->_has.secureBackupMetadataTimestamp)
+    {
+        copy->_secureBackupMetadataTimestamp = _secureBackupMetadataTimestamp;
+        copy->_has.secureBackupMetadataTimestamp = YES;
+    }
+    if (self->_has.secureBackupNumericPassphraseLength)
+    {
+        copy->_secureBackupNumericPassphraseLength = _secureBackupNumericPassphraseLength;
+        copy->_has.secureBackupNumericPassphraseLength = YES;
+    }
+    if (self->_has.secureBackupUsesComplexPassphrase)
+    {
+        copy->_secureBackupUsesComplexPassphrase = _secureBackupUsesComplexPassphrase;
+        copy->_has.secureBackupUsesComplexPassphrase = YES;
+    }
+    if (self->_has.secureBackupUsesNumericPassphrase)
+    {
+        copy->_secureBackupUsesNumericPassphrase = _secureBackupUsesNumericPassphrase;
+        copy->_has.secureBackupUsesNumericPassphrase = YES;
+    }
+    copy->_deviceColor = [_deviceColor copyWithZone:zone];
+    copy->_deviceEnclosureColor = [_deviceEnclosureColor copyWithZone:zone];
+    copy->_deviceMid = [_deviceMid copyWithZone:zone];
+    copy->_deviceModel = [_deviceModel copyWithZone:zone];
+    copy->_deviceModelClass = [_deviceModelClass copyWithZone:zone];
+    copy->_deviceModelVersion = [_deviceModelVersion copyWithZone:zone];
+    copy->_deviceName = [_deviceName copyWithZone:zone];
+    if (self->_has.devicePlatform)
+    {
+        copy->_devicePlatform = _devicePlatform;
+        copy->_has.devicePlatform = YES;
+    }
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTEscrowRecordMetadataClientMetadata *other = (OTEscrowRecordMetadataClientMetadata *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((self->_has.secureBackupMetadataTimestamp && other->_has.secureBackupMetadataTimestamp && self->_secureBackupMetadataTimestamp == other->_secureBackupMetadataTimestamp) || (!self->_has.secureBackupMetadataTimestamp && !other->_has.secureBackupMetadataTimestamp))
+    &&
+    ((self->_has.secureBackupNumericPassphraseLength && other->_has.secureBackupNumericPassphraseLength && self->_secureBackupNumericPassphraseLength == other->_secureBackupNumericPassphraseLength) || (!self->_has.secureBackupNumericPassphraseLength && !other->_has.secureBackupNumericPassphraseLength))
+    &&
+    ((self->_has.secureBackupUsesComplexPassphrase && other->_has.secureBackupUsesComplexPassphrase && self->_secureBackupUsesComplexPassphrase == other->_secureBackupUsesComplexPassphrase) || (!self->_has.secureBackupUsesComplexPassphrase && !other->_has.secureBackupUsesComplexPassphrase))
+    &&
+    ((self->_has.secureBackupUsesNumericPassphrase && other->_has.secureBackupUsesNumericPassphrase && self->_secureBackupUsesNumericPassphrase == other->_secureBackupUsesNumericPassphrase) || (!self->_has.secureBackupUsesNumericPassphrase && !other->_has.secureBackupUsesNumericPassphrase))
+    &&
+    ((!self->_deviceColor && !other->_deviceColor) || [self->_deviceColor isEqual:other->_deviceColor])
+    &&
+    ((!self->_deviceEnclosureColor && !other->_deviceEnclosureColor) || [self->_deviceEnclosureColor isEqual:other->_deviceEnclosureColor])
+    &&
+    ((!self->_deviceMid && !other->_deviceMid) || [self->_deviceMid isEqual:other->_deviceMid])
+    &&
+    ((!self->_deviceModel && !other->_deviceModel) || [self->_deviceModel isEqual:other->_deviceModel])
+    &&
+    ((!self->_deviceModelClass && !other->_deviceModelClass) || [self->_deviceModelClass isEqual:other->_deviceModelClass])
+    &&
+    ((!self->_deviceModelVersion && !other->_deviceModelVersion) || [self->_deviceModelVersion isEqual:other->_deviceModelVersion])
+    &&
+    ((!self->_deviceName && !other->_deviceName) || [self->_deviceName isEqual:other->_deviceName])
+    &&
+    ((self->_has.devicePlatform && other->_has.devicePlatform && self->_devicePlatform == other->_devicePlatform) || (!self->_has.devicePlatform && !other->_has.devicePlatform))
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    (self->_has.secureBackupMetadataTimestamp ? PBHashInt((NSUInteger)self->_secureBackupMetadataTimestamp) : 0)
+    ^
+    (self->_has.secureBackupNumericPassphraseLength ? PBHashInt((NSUInteger)self->_secureBackupNumericPassphraseLength) : 0)
+    ^
+    (self->_has.secureBackupUsesComplexPassphrase ? PBHashInt((NSUInteger)self->_secureBackupUsesComplexPassphrase) : 0)
+    ^
+    (self->_has.secureBackupUsesNumericPassphrase ? PBHashInt((NSUInteger)self->_secureBackupUsesNumericPassphrase) : 0)
+    ^
+    [self->_deviceColor hash]
+    ^
+    [self->_deviceEnclosureColor hash]
+    ^
+    [self->_deviceMid hash]
+    ^
+    [self->_deviceModel hash]
+    ^
+    [self->_deviceModelClass hash]
+    ^
+    [self->_deviceModelVersion hash]
+    ^
+    [self->_deviceName hash]
+    ^
+    (self->_has.devicePlatform ? PBHashInt((NSUInteger)self->_devicePlatform) : 0)
+    ;
+}
+
+- (void)mergeFrom:(OTEscrowRecordMetadataClientMetadata *)other
+{
+    if (other->_has.secureBackupMetadataTimestamp)
+    {
+        self->_secureBackupMetadataTimestamp = other->_secureBackupMetadataTimestamp;
+        self->_has.secureBackupMetadataTimestamp = YES;
+    }
+    if (other->_has.secureBackupNumericPassphraseLength)
+    {
+        self->_secureBackupNumericPassphraseLength = other->_secureBackupNumericPassphraseLength;
+        self->_has.secureBackupNumericPassphraseLength = YES;
+    }
+    if (other->_has.secureBackupUsesComplexPassphrase)
+    {
+        self->_secureBackupUsesComplexPassphrase = other->_secureBackupUsesComplexPassphrase;
+        self->_has.secureBackupUsesComplexPassphrase = YES;
+    }
+    if (other->_has.secureBackupUsesNumericPassphrase)
+    {
+        self->_secureBackupUsesNumericPassphrase = other->_secureBackupUsesNumericPassphrase;
+        self->_has.secureBackupUsesNumericPassphrase = YES;
+    }
+    if (other->_deviceColor)
+    {
+        [self setDeviceColor:other->_deviceColor];
+    }
+    if (other->_deviceEnclosureColor)
+    {
+        [self setDeviceEnclosureColor:other->_deviceEnclosureColor];
+    }
+    if (other->_deviceMid)
+    {
+        [self setDeviceMid:other->_deviceMid];
+    }
+    if (other->_deviceModel)
+    {
+        [self setDeviceModel:other->_deviceModel];
+    }
+    if (other->_deviceModelClass)
+    {
+        [self setDeviceModelClass:other->_deviceModelClass];
+    }
+    if (other->_deviceModelVersion)
+    {
+        [self setDeviceModelVersion:other->_deviceModelVersion];
+    }
+    if (other->_deviceName)
+    {
+        [self setDeviceName:other->_deviceName];
+    }
+    if (other->_has.devicePlatform)
+    {
+        self->_devicePlatform = other->_devicePlatform;
+        self->_has.devicePlatform = YES;
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTGlobalEnums.h b/keychain/ot/proto/generated_source/OTGlobalEnums.h
new file mode 100644 (file)
index 0000000..b491935
--- /dev/null
@@ -0,0 +1,43 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTPairingMessage.proto
+
+#include <stdint.h>
+#ifdef __OBJC__
+#include <Foundation/Foundation.h>
+#endif
+
+#ifndef NS_ENUM
+#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum))
+#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
+#else
+#define NS_ENUM(_type, _name) _type _name; enum
+#endif
+#endif // !defined(NS_ENUM)
+
+typedef NS_ENUM(int32_t, OTSupportType) {
+    OTSupportType_unknown = 0,
+    OTSupportType_supported = 1,
+    OTSupportType_not_supported = 2,
+};
+#ifdef __OBJC__
+NS_INLINE NSString *OTSupportTypeAsString(OTSupportType value)
+{
+    switch (value)
+    {
+        case OTSupportType_unknown: return @"unknown";
+        case OTSupportType_supported: return @"supported";
+        case OTSupportType_not_supported: return @"not_supported";
+        default: return [NSString stringWithFormat:@"(unknown: %i)", value];
+    }
+}
+#endif /* __OBJC__ */
+#ifdef __OBJC__
+NS_INLINE OTSupportType StringAsOTSupportType(NSString *value)
+{
+    if ([value isEqualToString:@"unknown"]) return OTSupportType_unknown;
+    if ([value isEqualToString:@"supported"]) return OTSupportType_supported;
+    if ([value isEqualToString:@"not_supported"]) return OTSupportType_not_supported;
+    return OTSupportType_unknown;
+}
+#endif /* __OBJC__ */
diff --git a/keychain/ot/proto/generated_source/OTICDPRecordContext.h b/keychain/ot/proto/generated_source/OTICDPRecordContext.h
new file mode 100644 (file)
index 0000000..08fac60
--- /dev/null
@@ -0,0 +1,42 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+@class OTCDPRecoveryInformation;
+@class OTEscrowAuthenticationInformation;
+
+#ifdef __cplusplus
+#define OTICDPRECORDCONTEXT_FUNCTION extern "C"
+#else
+#define OTICDPRECORDCONTEXT_FUNCTION extern
+#endif
+
+@interface OTICDPRecordContext : PBCodable <NSCopying>
+{
+    OTEscrowAuthenticationInformation *_authInfo;
+    OTCDPRecoveryInformation *_cdpInfo;
+}
+
+
+@property (nonatomic, readonly) BOOL hasCdpInfo;
+@property (nonatomic, retain) OTCDPRecoveryInformation *cdpInfo;
+
+@property (nonatomic, readonly) BOOL hasAuthInfo;
+@property (nonatomic, retain) OTEscrowAuthenticationInformation *authInfo;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTICDPRecordContext *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTICDPRecordContext *)other;
+
+OTICDPRECORDCONTEXT_FUNCTION BOOL OTICDPRecordContextReadFrom(__unsafe_unretained OTICDPRecordContext *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTICDPRecordContext.m b/keychain/ot/proto/generated_source/OTICDPRecordContext.m
new file mode 100644 (file)
index 0000000..1d74b15
--- /dev/null
@@ -0,0 +1,194 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import "OTICDPRecordContext.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#import "OTCDPRecoveryInformation.h"
+#import "OTEscrowAuthenticationInformation.h"
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTICDPRecordContext
+
+- (BOOL)hasCdpInfo
+{
+    return _cdpInfo != nil;
+}
+@synthesize cdpInfo = _cdpInfo;
+- (BOOL)hasAuthInfo
+{
+    return _authInfo != nil;
+}
+@synthesize authInfo = _authInfo;
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_cdpInfo)
+    {
+        [dict setObject:[_cdpInfo dictionaryRepresentation] forKey:@"cdpInfo"];
+    }
+    if (self->_authInfo)
+    {
+        [dict setObject:[_authInfo dictionaryRepresentation] forKey:@"authInfo"];
+    }
+    return dict;
+}
+
+BOOL OTICDPRecordContextReadFrom(__unsafe_unretained OTICDPRecordContext *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* cdpInfo */:
+            {
+                OTCDPRecoveryInformation *new_cdpInfo = [[OTCDPRecoveryInformation alloc] init];
+                self->_cdpInfo = new_cdpInfo;
+                PBDataReaderMark mark_cdpInfo;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_cdpInfo);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTCDPRecoveryInformationReadFrom(new_cdpInfo, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_cdpInfo);
+            }
+            break;
+            case 2 /* authInfo */:
+            {
+                OTEscrowAuthenticationInformation *new_authInfo = [[OTEscrowAuthenticationInformation alloc] init];
+                self->_authInfo = new_authInfo;
+                PBDataReaderMark mark_authInfo;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_authInfo);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTEscrowAuthenticationInformationReadFrom(new_authInfo, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_authInfo);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTICDPRecordContextReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* cdpInfo */
+    {
+        if (self->_cdpInfo != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_cdpInfo, 1);
+        }
+    }
+    /* authInfo */
+    {
+        if (self->_authInfo != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_authInfo, 2);
+        }
+    }
+}
+
+- (void)copyTo:(OTICDPRecordContext *)other
+{
+    if (_cdpInfo)
+    {
+        other.cdpInfo = _cdpInfo;
+    }
+    if (_authInfo)
+    {
+        other.authInfo = _authInfo;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTICDPRecordContext *copy = [[[self class] allocWithZone:zone] init];
+    copy->_cdpInfo = [_cdpInfo copyWithZone:zone];
+    copy->_authInfo = [_authInfo copyWithZone:zone];
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTICDPRecordContext *other = (OTICDPRecordContext *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((!self->_cdpInfo && !other->_cdpInfo) || [self->_cdpInfo isEqual:other->_cdpInfo])
+    &&
+    ((!self->_authInfo && !other->_authInfo) || [self->_authInfo isEqual:other->_authInfo])
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    [self->_cdpInfo hash]
+    ^
+    [self->_authInfo hash]
+    ;
+}
+
+- (void)mergeFrom:(OTICDPRecordContext *)other
+{
+    if (self->_cdpInfo && other->_cdpInfo)
+    {
+        [self->_cdpInfo mergeFrom:other->_cdpInfo];
+    }
+    else if (!self->_cdpInfo && other->_cdpInfo)
+    {
+        [self setCdpInfo:other->_cdpInfo];
+    }
+    if (self->_authInfo && other->_authInfo)
+    {
+        [self->_authInfo mergeFrom:other->_authInfo];
+    }
+    else if (!self->_authInfo && other->_authInfo)
+    {
+        [self setAuthInfo:other->_authInfo];
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTICDPRecordSilentContext.h b/keychain/ot/proto/generated_source/OTICDPRecordSilentContext.h
new file mode 100644 (file)
index 0000000..5576e3f
--- /dev/null
@@ -0,0 +1,42 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+@class OTCDPRecoveryInformation;
+@class OTEscrowAuthenticationInformation;
+
+#ifdef __cplusplus
+#define OTICDPRECORDSILENTCONTEXT_FUNCTION extern "C"
+#else
+#define OTICDPRECORDSILENTCONTEXT_FUNCTION extern
+#endif
+
+@interface OTICDPRecordSilentContext : PBCodable <NSCopying>
+{
+    OTEscrowAuthenticationInformation *_authInfo;
+    OTCDPRecoveryInformation *_cdpInfo;
+}
+
+
+@property (nonatomic, readonly) BOOL hasCdpInfo;
+@property (nonatomic, retain) OTCDPRecoveryInformation *cdpInfo;
+
+@property (nonatomic, readonly) BOOL hasAuthInfo;
+@property (nonatomic, retain) OTEscrowAuthenticationInformation *authInfo;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTICDPRecordSilentContext *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTICDPRecordSilentContext *)other;
+
+OTICDPRECORDSILENTCONTEXT_FUNCTION BOOL OTICDPRecordSilentContextReadFrom(__unsafe_unretained OTICDPRecordSilentContext *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTICDPRecordSilentContext.m b/keychain/ot/proto/generated_source/OTICDPRecordSilentContext.m
new file mode 100644 (file)
index 0000000..4d8e4f6
--- /dev/null
@@ -0,0 +1,194 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTCDPRecoveryInformation.proto
+
+#import "OTICDPRecordSilentContext.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#import "OTCDPRecoveryInformation.h"
+#import "OTEscrowAuthenticationInformation.h"
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTICDPRecordSilentContext
+
+- (BOOL)hasCdpInfo
+{
+    return _cdpInfo != nil;
+}
+@synthesize cdpInfo = _cdpInfo;
+- (BOOL)hasAuthInfo
+{
+    return _authInfo != nil;
+}
+@synthesize authInfo = _authInfo;
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_cdpInfo)
+    {
+        [dict setObject:[_cdpInfo dictionaryRepresentation] forKey:@"cdpInfo"];
+    }
+    if (self->_authInfo)
+    {
+        [dict setObject:[_authInfo dictionaryRepresentation] forKey:@"authInfo"];
+    }
+    return dict;
+}
+
+BOOL OTICDPRecordSilentContextReadFrom(__unsafe_unretained OTICDPRecordSilentContext *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* cdpInfo */:
+            {
+                OTCDPRecoveryInformation *new_cdpInfo = [[OTCDPRecoveryInformation alloc] init];
+                self->_cdpInfo = new_cdpInfo;
+                PBDataReaderMark mark_cdpInfo;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_cdpInfo);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTCDPRecoveryInformationReadFrom(new_cdpInfo, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_cdpInfo);
+            }
+            break;
+            case 2 /* authInfo */:
+            {
+                OTEscrowAuthenticationInformation *new_authInfo = [[OTEscrowAuthenticationInformation alloc] init];
+                self->_authInfo = new_authInfo;
+                PBDataReaderMark mark_authInfo;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_authInfo);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTEscrowAuthenticationInformationReadFrom(new_authInfo, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_authInfo);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTICDPRecordSilentContextReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* cdpInfo */
+    {
+        if (self->_cdpInfo != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_cdpInfo, 1);
+        }
+    }
+    /* authInfo */
+    {
+        if (self->_authInfo != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_authInfo, 2);
+        }
+    }
+}
+
+- (void)copyTo:(OTICDPRecordSilentContext *)other
+{
+    if (_cdpInfo)
+    {
+        other.cdpInfo = _cdpInfo;
+    }
+    if (_authInfo)
+    {
+        other.authInfo = _authInfo;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTICDPRecordSilentContext *copy = [[[self class] allocWithZone:zone] init];
+    copy->_cdpInfo = [_cdpInfo copyWithZone:zone];
+    copy->_authInfo = [_authInfo copyWithZone:zone];
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTICDPRecordSilentContext *other = (OTICDPRecordSilentContext *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((!self->_cdpInfo && !other->_cdpInfo) || [self->_cdpInfo isEqual:other->_cdpInfo])
+    &&
+    ((!self->_authInfo && !other->_authInfo) || [self->_authInfo isEqual:other->_authInfo])
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    [self->_cdpInfo hash]
+    ^
+    [self->_authInfo hash]
+    ;
+}
+
+- (void)mergeFrom:(OTICDPRecordSilentContext *)other
+{
+    if (self->_cdpInfo && other->_cdpInfo)
+    {
+        [self->_cdpInfo mergeFrom:other->_cdpInfo];
+    }
+    else if (!self->_cdpInfo && other->_cdpInfo)
+    {
+        [self setCdpInfo:other->_cdpInfo];
+    }
+    if (self->_authInfo && other->_authInfo)
+    {
+        [self->_authInfo mergeFrom:other->_authInfo];
+    }
+    else if (!self->_authInfo && other->_authInfo)
+    {
+        [self setAuthInfo:other->_authInfo];
+    }
+}
+
+@end
+
index e8c27edd467aa87ceb37f9c272a60bb8775b1c4f..ba31f284e5e7ad03f856aec1f012960df7a34c4b 100644 (file)
@@ -5,9 +5,11 @@
 #import <Foundation/Foundation.h>
 #import <ProtocolBuffer/PBCodable.h>
 
-@class OTSponsorToApplicantRound1M2;
 @class OTApplicantToSponsorRound2M1;
+@class OTSponsorToApplicantRound1M2;
 @class OTSponsorToApplicantRound2M2;
+@class OTSupportOctagonMessage;
+@class OTSupportSOSMessage;
 
 #ifdef __cplusplus
 #define OTPAIRINGMESSAGE_FUNCTION extern "C" __attribute__((visibility("hidden")))
@@ -24,6 +26,8 @@ __attribute__((visibility("hidden")))
 {
     OTSponsorToApplicantRound1M2 *_epoch;
     OTApplicantToSponsorRound2M1 *_prepare;
+    OTSupportOctagonMessage *_supportsOctagon;
+    OTSupportSOSMessage *_supportsSOS;
     OTSponsorToApplicantRound2M2 *_voucher;
 }
 
@@ -37,6 +41,12 @@ __attribute__((visibility("hidden")))
 @property (nonatomic, readonly) BOOL hasVoucher;
 @property (nonatomic, retain) OTSponsorToApplicantRound2M2 *voucher;
 
+@property (nonatomic, readonly) BOOL hasSupportsOctagon;
+@property (nonatomic, retain) OTSupportOctagonMessage *supportsOctagon;
+
+@property (nonatomic, readonly) BOOL hasSupportsSOS;
+@property (nonatomic, retain) OTSupportSOSMessage *supportsSOS;
+
 // Performs a shallow copy into other
 - (void)copyTo:(OTPairingMessage *)other;
 
index a7c8f89b28faf48b41b3fb712869f50476e1e2cf..76cefe59a6d65111b6f6c37bdf1d00922b2847c4 100644 (file)
@@ -10,6 +10,8 @@
 #import "OTApplicantToSponsorRound2M1.h"
 #import "OTSponsorToApplicantRound1M2.h"
 #import "OTSponsorToApplicantRound2M2.h"
+#import "OTSupportOctagonMessage.h"
+#import "OTSupportSOSMessage.h"
 
 #if !__has_feature(objc_arc)
 # error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
     return _voucher != nil;
 }
 @synthesize voucher = _voucher;
+- (BOOL)hasSupportsOctagon
+{
+    return _supportsOctagon != nil;
+}
+@synthesize supportsOctagon = _supportsOctagon;
+- (BOOL)hasSupportsSOS
+{
+    return _supportsSOS != nil;
+}
+@synthesize supportsSOS = _supportsSOS;
 
 - (NSString *)description
 {
     {
         [dict setObject:[_voucher dictionaryRepresentation] forKey:@"voucher"];
     }
+    if (self->_supportsOctagon)
+    {
+        [dict setObject:[_supportsOctagon dictionaryRepresentation] forKey:@"supportsOctagon"];
+    }
+    if (self->_supportsSOS)
+    {
+        [dict setObject:[_supportsSOS dictionaryRepresentation] forKey:@"supportsSOS"];
+    }
     return dict;
 }
 
@@ -126,6 +146,42 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
                 PBReaderRecallMark(reader, &mark_voucher);
             }
             break;
+            case 5 /* supportsOctagon */:
+            {
+                OTSupportOctagonMessage *new_supportsOctagon = [[OTSupportOctagonMessage alloc] init];
+                self->_supportsOctagon = new_supportsOctagon;
+                PBDataReaderMark mark_supportsOctagon;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_supportsOctagon);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTSupportOctagonMessageReadFrom(new_supportsOctagon, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_supportsOctagon);
+            }
+            break;
+            case 6 /* supportsSOS */:
+            {
+                OTSupportSOSMessage *new_supportsSOS = [[OTSupportSOSMessage alloc] init];
+                self->_supportsSOS = new_supportsSOS;
+                PBDataReaderMark mark_supportsSOS;
+                BOOL markError = !PBReaderPlaceMark(reader, &mark_supportsSOS);
+                if (markError)
+                {
+                    return NO;
+                }
+                BOOL inError = !OTSupportSOSMessageReadFrom(new_supportsSOS, reader);
+                if (inError)
+                {
+                    return NO;
+                }
+                PBReaderRecallMark(reader, &mark_supportsSOS);
+            }
+            break;
             default:
                 if (!PBReaderSkipValueWithTag(reader, tag, aType))
                     return NO;
@@ -162,6 +218,20 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
             PBDataWriterWriteSubmessage(writer, self->_voucher, 3);
         }
     }
+    /* supportsOctagon */
+    {
+        if (self->_supportsOctagon != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_supportsOctagon, 5);
+        }
+    }
+    /* supportsSOS */
+    {
+        if (self->_supportsSOS != nil)
+        {
+            PBDataWriterWriteSubmessage(writer, self->_supportsSOS, 6);
+        }
+    }
 }
 
 - (void)copyTo:(OTPairingMessage *)other
@@ -178,6 +248,14 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
     {
         other.voucher = _voucher;
     }
+    if (_supportsOctagon)
+    {
+        other.supportsOctagon = _supportsOctagon;
+    }
+    if (_supportsSOS)
+    {
+        other.supportsSOS = _supportsSOS;
+    }
 }
 
 - (id)copyWithZone:(NSZone *)zone
@@ -186,6 +264,8 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
     copy->_epoch = [_epoch copyWithZone:zone];
     copy->_prepare = [_prepare copyWithZone:zone];
     copy->_voucher = [_voucher copyWithZone:zone];
+    copy->_supportsOctagon = [_supportsOctagon copyWithZone:zone];
+    copy->_supportsSOS = [_supportsSOS copyWithZone:zone];
     return copy;
 }
 
@@ -199,6 +279,10 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
     ((!self->_prepare && !other->_prepare) || [self->_prepare isEqual:other->_prepare])
     &&
     ((!self->_voucher && !other->_voucher) || [self->_voucher isEqual:other->_voucher])
+    &&
+    ((!self->_supportsOctagon && !other->_supportsOctagon) || [self->_supportsOctagon isEqual:other->_supportsOctagon])
+    &&
+    ((!self->_supportsSOS && !other->_supportsSOS) || [self->_supportsSOS isEqual:other->_supportsSOS])
     ;
 }
 
@@ -211,6 +295,10 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
     [self->_prepare hash]
     ^
     [self->_voucher hash]
+    ^
+    [self->_supportsOctagon hash]
+    ^
+    [self->_supportsSOS hash]
     ;
 }
 
@@ -240,6 +328,22 @@ BOOL OTPairingMessageReadFrom(__unsafe_unretained OTPairingMessage *self, __unsa
     {
         [self setVoucher:other->_voucher];
     }
+    if (self->_supportsOctagon && other->_supportsOctagon)
+    {
+        [self->_supportsOctagon mergeFrom:other->_supportsOctagon];
+    }
+    else if (!self->_supportsOctagon && other->_supportsOctagon)
+    {
+        [self setSupportsOctagon:other->_supportsOctagon];
+    }
+    if (self->_supportsSOS && other->_supportsSOS)
+    {
+        [self->_supportsSOS mergeFrom:other->_supportsSOS];
+    }
+    else if (!self->_supportsSOS && other->_supportsSOS)
+    {
+        [self setSupportsSOS:other->_supportsSOS];
+    }
 }
 
 @end
index 7a2aad454539966d6f429e6398b20843fd7a2383..43b7041812444a8a4f5faeab8593cdba350debef 100644 (file)
@@ -25,7 +25,7 @@
 }
 - (BOOL)hasEpoch
 {
-    return _has.epoch;
+    return _has.epoch != 0;
 }
 
 - (NSString *)description
diff --git a/keychain/ot/proto/generated_source/OTSupportOctagonMessage.h b/keychain/ot/proto/generated_source/OTSupportOctagonMessage.h
new file mode 100644 (file)
index 0000000..bfe58f0
--- /dev/null
@@ -0,0 +1,43 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTPairingMessage.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#import "OTGlobalEnums.h"
+
+#ifdef __cplusplus
+#define OTSUPPORTOCTAGONMESSAGE_FUNCTION extern "C" __attribute__((visibility("hidden")))
+#else
+#define OTSUPPORTOCTAGONMESSAGE_FUNCTION extern __attribute__((visibility("hidden")))
+#endif
+
+__attribute__((visibility("hidden")))
+@interface OTSupportOctagonMessage : PBCodable <NSCopying>
+{
+    OTSupportType _supported;
+    struct {
+        int supported:1;
+    } _has;
+}
+
+
+@property (nonatomic) BOOL hasSupported;
+@property (nonatomic) OTSupportType supported;
+- (NSString *)supportedAsString:(OTSupportType)value;
+- (OTSupportType)StringAsSupported:(NSString *)str;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTSupportOctagonMessage *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTSupportOctagonMessage *)other;
+
+OTSUPPORTOCTAGONMESSAGE_FUNCTION BOOL OTSupportOctagonMessageReadFrom(__unsafe_unretained OTSupportOctagonMessage *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTSupportOctagonMessage.m b/keychain/ot/proto/generated_source/OTSupportOctagonMessage.m
new file mode 100644 (file)
index 0000000..dceeaee
--- /dev/null
@@ -0,0 +1,151 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTPairingMessage.proto
+
+#import "OTSupportOctagonMessage.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTSupportOctagonMessage
+
+@synthesize supported = _supported;
+- (OTSupportType)supported
+{
+    return _has.supported ? _supported : OTSupportType_unknown;
+}
+- (void)setSupported:(OTSupportType)v
+{
+    _has.supported = YES;
+    _supported = v;
+}
+- (void)setHasSupported:(BOOL)f
+{
+    _has.supported = f;
+}
+- (BOOL)hasSupported
+{
+    return _has.supported != 0;
+}
+- (NSString *)supportedAsString:(OTSupportType)value
+{
+    return OTSupportTypeAsString(value);
+}
+- (OTSupportType)StringAsSupported:(NSString *)str
+{
+    return StringAsOTSupportType(str);
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_has.supported)
+    {
+        [dict setObject:OTSupportTypeAsString(self->_supported) forKey:@"supported"];
+    }
+    return dict;
+}
+
+BOOL OTSupportOctagonMessageReadFrom(__unsafe_unretained OTSupportOctagonMessage *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* supported */:
+            {
+                self->_has.supported = YES;
+                self->_supported = PBReaderReadInt32(reader);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTSupportOctagonMessageReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* supported */
+    {
+        if (self->_has.supported)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_supported, 1);
+        }
+    }
+}
+
+- (void)copyTo:(OTSupportOctagonMessage *)other
+{
+    if (self->_has.supported)
+    {
+        other->_supported = _supported;
+        other->_has.supported = YES;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTSupportOctagonMessage *copy = [[[self class] allocWithZone:zone] init];
+    if (self->_has.supported)
+    {
+        copy->_supported = _supported;
+        copy->_has.supported = YES;
+    }
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTSupportOctagonMessage *other = (OTSupportOctagonMessage *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((self->_has.supported && other->_has.supported && self->_supported == other->_supported) || (!self->_has.supported && !other->_has.supported))
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    (self->_has.supported ? PBHashInt((NSUInteger)self->_supported) : 0)
+    ;
+}
+
+- (void)mergeFrom:(OTSupportOctagonMessage *)other
+{
+    if (other->_has.supported)
+    {
+        self->_supported = other->_supported;
+        self->_has.supported = YES;
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTSupportSOSMessage.h b/keychain/ot/proto/generated_source/OTSupportSOSMessage.h
new file mode 100644 (file)
index 0000000..d998288
--- /dev/null
@@ -0,0 +1,43 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTPairingMessage.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#import "OTGlobalEnums.h"
+
+#ifdef __cplusplus
+#define OTSUPPORTSOSMESSAGE_FUNCTION extern "C" __attribute__((visibility("hidden")))
+#else
+#define OTSUPPORTSOSMESSAGE_FUNCTION extern __attribute__((visibility("hidden")))
+#endif
+
+__attribute__((visibility("hidden")))
+@interface OTSupportSOSMessage : PBCodable <NSCopying>
+{
+    OTSupportType _supported;
+    struct {
+        int supported:1;
+    } _has;
+}
+
+
+@property (nonatomic) BOOL hasSupported;
+@property (nonatomic) OTSupportType supported;
+- (NSString *)supportedAsString:(OTSupportType)value;
+- (OTSupportType)StringAsSupported:(NSString *)str;
+
+// Performs a shallow copy into other
+- (void)copyTo:(OTSupportSOSMessage *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(OTSupportSOSMessage *)other;
+
+OTSUPPORTSOSMESSAGE_FUNCTION BOOL OTSupportSOSMessageReadFrom(__unsafe_unretained OTSupportSOSMessage *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/ot/proto/generated_source/OTSupportSOSMessage.m b/keychain/ot/proto/generated_source/OTSupportSOSMessage.m
new file mode 100644 (file)
index 0000000..059472c
--- /dev/null
@@ -0,0 +1,151 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from OTPairingMessage.proto
+
+#import "OTSupportSOSMessage.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation OTSupportSOSMessage
+
+@synthesize supported = _supported;
+- (OTSupportType)supported
+{
+    return _has.supported ? _supported : OTSupportType_unknown;
+}
+- (void)setSupported:(OTSupportType)v
+{
+    _has.supported = YES;
+    _supported = v;
+}
+- (void)setHasSupported:(BOOL)f
+{
+    _has.supported = f;
+}
+- (BOOL)hasSupported
+{
+    return _has.supported != 0;
+}
+- (NSString *)supportedAsString:(OTSupportType)value
+{
+    return OTSupportTypeAsString(value);
+}
+- (OTSupportType)StringAsSupported:(NSString *)str
+{
+    return StringAsOTSupportType(str);
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_has.supported)
+    {
+        [dict setObject:OTSupportTypeAsString(self->_supported) forKey:@"supported"];
+    }
+    return dict;
+}
+
+BOOL OTSupportSOSMessageReadFrom(__unsafe_unretained OTSupportSOSMessage *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* supported */:
+            {
+                self->_has.supported = YES;
+                self->_supported = PBReaderReadInt32(reader);
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return OTSupportSOSMessageReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* supported */
+    {
+        if (self->_has.supported)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_supported, 1);
+        }
+    }
+}
+
+- (void)copyTo:(OTSupportSOSMessage *)other
+{
+    if (self->_has.supported)
+    {
+        other->_supported = _supported;
+        other->_has.supported = YES;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    OTSupportSOSMessage *copy = [[[self class] allocWithZone:zone] init];
+    if (self->_has.supported)
+    {
+        copy->_supported = _supported;
+        copy->_has.supported = YES;
+    }
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    OTSupportSOSMessage *other = (OTSupportSOSMessage *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((self->_has.supported && other->_has.supported && self->_supported == other->_supported) || (!self->_has.supported && !other->_has.supported))
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    (self->_has.supported ? PBHashInt((NSUInteger)self->_supported) : 0)
+    ;
+}
+
+- (void)mergeFrom:(OTSupportSOSMessage *)other
+{
+    if (other->_has.supported)
+    {
+        self->_supported = other->_supported;
+        self->_has.supported = YES;
+    }
+}
+
+@end
+
diff --git a/keychain/ot/proto/source/OTSOSMessage.h b/keychain/ot/proto/source/OTSOSMessage.h
deleted file mode 100644 (file)
index e515077..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// This file was automatically generated by protocompiler
-// DO NOT EDIT!
-// Compiled from OTPairingMessage.proto
-
-#import <Foundation/Foundation.h>
-#import <ProtocolBuffer/PBCodable.h>
-
-#ifdef __cplusplus
-#define OTSOSMESSAGE_FUNCTION extern "C" __attribute__((visibility("hidden")))
-#else
-#define OTSOSMESSAGE_FUNCTION extern __attribute__((visibility("hidden")))
-#endif
-
-__attribute__((visibility("hidden")))
-@interface OTSOSMessage : PBCodable <NSCopying>
-{
-    NSData *_circleBlob;
-    NSData *_credential;
-    NSData *_initialSyncItems;
-    NSData *_peerInfo;
-}
-
-
-@property (nonatomic, readonly) BOOL hasCredential;
-@property (nonatomic, retain) NSData *credential;
-
-@property (nonatomic, readonly) BOOL hasPeerInfo;
-@property (nonatomic, retain) NSData *peerInfo;
-
-@property (nonatomic, readonly) BOOL hasCircleBlob;
-@property (nonatomic, retain) NSData *circleBlob;
-
-@property (nonatomic, readonly) BOOL hasInitialSyncItems;
-@property (nonatomic, retain) NSData *initialSyncItems;
-
-// Performs a shallow copy into other
-- (void)copyTo:(OTSOSMessage *)other;
-
-// Performs a deep merge from other into self
-// If set in other, singular values in self are replaced in self
-// Singular composite values are recursively merged
-// Repeated values from other are appended to repeated values in self
-- (void)mergeFrom:(OTSOSMessage *)other;
-
-OTSOSMESSAGE_FUNCTION BOOL OTSOSMessageReadFrom(__unsafe_unretained OTSOSMessage *self, __unsafe_unretained PBDataReader *reader);
-
-@end
-
index 2b01e9a40562c44aa16f06c1052c6e47cf1afd13..3ecb9ff44b9ff5452282610679024f2b60803baa 100644 (file)
@@ -43,7 +43,24 @@ for x in ['TrustedPeersTests', 'TrustedPeersHelperUnitTests']:
     test_dictionary['WorkingDirectory'] = '/AppleInternal/XCTests/com.apple.security/'
 
     test_command = Foundation.NSMutableArray.array()
-    test_command.append('BATS_XCTEST_CMD {}.xctest'.format(x))
+    test_command.append('BATS_XCTEST_CMD')
+    test_command.append('{}.xctest'.format(x))
+    test_dictionary['Command'] = test_command
+
+    test_list.append(test_dictionary)
+
+
+for x in ['OctagonTrustTests']:
+
+    test_dictionary = Foundation.NSMutableDictionary.dictionary()
+    test_dictionary['TestName'] = x
+    test_dictionary['Timeout']= 1200
+    test_dictionary['ShowSubtestResults']= True
+    test_dictionary['WorkingDirectory'] = '/AppleInternal/XCTests/com.apple.security/'
+
+    test_command = Foundation.NSMutableArray.array()
+    test_command.append('BATS_XCTEST_CMD')
+    test_command.append('{}.xctest'.format(x))
     test_dictionary['Command'] = test_command
 
     test_list.append(test_dictionary)
@@ -58,7 +75,10 @@ for x in get_class_names():
     test_dictionary['WorkingDirectory'] = '/AppleInternal/XCTests/com.apple.security/'
 
     test_command = Foundation.NSMutableArray.array()
-    test_command.append('BATS_XCTEST_CMD -XCTest {} OctagonTests.xctest'.format(x))
+    test_command.append('BATS_XCTEST_CMD')
+    test_command.append('-XCTest')
+    test_command.append('{}'.format(x))
+    test_command.append('OctagonTests.xctest')
     test_dictionary['Command'] = test_command
 
     test_list.append(test_dictionary)
index 9ddd0d113986ba6f3ff19d2baa95efc65b8d9f66..f8391d9b2cefdd508c55478414abe230db3ac8c3 100644 (file)
@@ -1,3 +1,4 @@
 disabled_rules:
     - force_cast
     - force_try
+    - implicitly_unwrapped_optional
index 82e22519249dd8ef5c5b7f984622fa264c1278b5..5dd8c49c1b3270841f32ae296abf678ca3764e9c 100644 (file)
@@ -3,7 +3,6 @@ import XCTest
 #if OCTAGON
 
 class OctagonAccountMetadataClassCPersistenceTests: CloudKitKeychainSyncingMockXCTest {
-
     override static func setUp() {
         super.setUp()
 
@@ -147,7 +146,7 @@ class OctagonAccountMetadataClassCPersistenceTests: CloudKitKeychainSyncingMockX
         do {
             let state2 = try OTAccountMetadataClassC.loadFromKeychain(forContainer: OTCKContainerName, contextID: OTDefaultContext)
             XCTAssertNotNil(state2)
-            XCTAssertEqual(state2.peerID, nil, "peerID should be nil")
+            XCTAssertNil(state2.peerID, "peerID should be nil")
             XCTAssertEqual(state2.icloudAccountState, OTAccountMetadataClassC_AccountState.UNKNOWN, "account state should be OTAccountMetadataClassC_AccountState_UNKNOWN")
             XCTAssertEqual(state2.trustState, OTAccountMetadataClassC_TrustState.UNKNOWN, "trust state should be OTAccountMetadataClassC_TrustState_UNKNOWN")
         } catch {
diff --git a/keychain/ot/tests/octagon/OctagonPolicyTests.swift b/keychain/ot/tests/octagon/OctagonPolicyTests.swift
new file mode 100644 (file)
index 0000000..4152e8c
--- /dev/null
@@ -0,0 +1,57 @@
+import Foundation
+
+class OctagonPolicyTests: XCTestCase {
+    func prevailingPolicy() throws -> TPPolicy {
+        let policyDocument = builtInPolicyDocuments().filter { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }.first
+        XCTAssertNotNil(policyDocument, "Should have a prevailing policy document")
+
+        let policy = try policyDocument!.policy(withSecrets: [:], decrypter: Decrypter())
+        return policy
+    }
+
+    func testPrevailingPolicyHasModelsForAllViewRules() throws {
+        let policy = try self.prevailingPolicy()
+
+        // There's a rule for 'NotSynced', but we explicitly don't want to bring up that view
+        let viewsWithRules = Set(policy.keyViewMapping.compactMap { $0.view }).subtracting(Set(["NotSynced"]))
+        XCTAssertEqual(Set(policy.categoriesByView.keys),
+                       viewsWithRules,
+                       "Every view should have a rule")
+    }
+
+    func testPrevailingPolicyIntroducerGraphIsClosed() throws {
+        // Let's check that, for each model, introducing a new peer doesn't give them more introduction power
+        let policy = try self.prevailingPolicy()
+
+        policy.introducersByCategory.forEach { category, introducers in
+            let allowedIntroducers = Set(introducers)
+            let allAccessible = Set(allowedIntroducers.compactMap { category in policy.introducersByCategory[category] }.joined())
+
+            XCTAssertEqual(allowedIntroducers, allAccessible, "A device class shouldn't be able to introduce a peer which can introduce a peer that the original device couldn't introduce")
+        }
+    }
+
+    func testPrePolicyViews() throws {
+        let policy = try self.prevailingPolicy()
+
+        XCTAssert(policy.keyViewMapping.count >= 7, "Should always have 7 basic views")
+
+        let firstSevenRules = policy.keyViewMapping[..<7]
+
+        let firstSevenViews = firstSevenRules.compactMap { $0.view }
+        XCTAssertEqual(Set(firstSevenViews),
+                       Set(["ApplePay", "AutoUnlock", "Engram", "Health", "Home", "Manatee", "LimitedPeersAllowed"]),
+                       "First seven rules should be for prepolicy views")
+
+        // Now, ensure that the first seven rules match vwht only
+        firstSevenRules.forEach { viewRule in
+            XCTAssertNotNil(viewRule.view, "View rule should have a name")
+            XCTAssertNotNil(viewRule.matchingRule, "Rule should have a matching rule")
+            let rule = viewRule.matchingRule!
+
+            XCTAssertNotNil(rule.match, "Rule should have a match subrule")
+            XCTAssertEqual(rule.match.fieldName, "vwht", "Rule should match field vwht")
+            XCTAssertEqual(rule.match.regex, "^\(viewRule.view!)$", "Regex should match field name")
+        }
+    }
+}
index ef94770e4f37aeb4bee228d1344c3cf83bb94c67..874585e83ca99d962f88b8653665780b39044f5d 100644 (file)
@@ -12,24 +12,24 @@ class OTMockSecureBackup: NSObject, OctagonEscrowRecovererPrococol {
         super.init()
     }
 
-    func recover(withInfo info: [AnyHashable: Any]!,
-                 results: AutoreleasingUnsafeMutablePointer<NSDictionary?>!) -> Error! {
+    func recover(withInfo info: [AnyHashable: Any]?,
+                 results: AutoreleasingUnsafeMutablePointer<NSDictionary?>?) -> Error? {
         if self.bottleID == nil && self.entropy == nil {
-            results.pointee = [
+            results!.pointee = [
                 "bottleValid": "invalid",
             ]
         } else if self.bottleID == nil && self.entropy != nil {
-            results.pointee = [
+            results!.pointee = [
                 "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy],
                 "bottleValid": "invalid",
             ]
         } else if self.bottleID != nil && self.entropy == nil {
-            results.pointee = [
+            results!.pointee = [
                 "bottleID": self.bottleID!,
                 "bottleValid": "invalid",
             ]
         } else { //entropy and bottleID must exist, so its a good bottle.
-            results.pointee = [
+            results!.pointee = [
                 "bottleID": self.bottleID!,
                 "bottleValid": "valid",
                 "EscrowServiceEscrowData": ["BottledPeerEntropy": self.entropy],
@@ -41,6 +41,17 @@ class OTMockSecureBackup: NSObject, OctagonEscrowRecovererPrococol {
     func disable(withInfo info: [AnyHashable: Any]!) -> Error? {
         return nil
     }
+
+    @objc func getAccountInfo(withInfo info: [AnyHashable: Any]!, results: AutoreleasingUnsafeMutablePointer<NSDictionary?>!) -> Error? {
+        let recordData = accountInfoWithInfoSample.data(using: .utf8)!
+        var propertyListFormat = PropertyListSerialization.PropertyListFormat.xml
+        do {
+            results.pointee = try PropertyListSerialization.propertyList(from: recordData, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [String: AnyObject] as NSDictionary
+        } catch {
+            print("Error reading plist: \(error), format: \(propertyListFormat)")
+        }
+        return nil
+    }
 }
 
 class OTMockFollowUpController: NSObject, OctagonFollowUpControllerProtocol {
index fa1e3879f9f0c4688c82d88af017d47ca30a34c8..b19af22dbbb69657fc93cb847ee00e0b1050f4d9 100644 (file)
@@ -92,8 +92,8 @@ class OctagonAccountTests: OctagonTestsBase {
 
         self.wait(for: [quiescentExpectation], timeout: 10)
 
-        // CKKS should also be logged out, since Octagon believes there's no account
-        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
+        // Since there's no acocunt, CKKS shouldn't even have any views loaded
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have 0 CKKS views loaded")
     }
 
     func testNoAccountLeadsToInitialize() throws {
@@ -432,6 +432,19 @@ class OctagonAccountTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
     }
 
+    func testDetermineCDPStateFromSOSError() throws {
+        // If SOS reports that it doesn't have the user key, a circle might exist and it might not
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCError)
+        self.mockSOSAdapter.circleStatusError = NSError(domain: kSOSErrorDomain as String, code: kSOSErrorPublicKeyAbsent, userInfo: nil)
+
+        self.startCKAccountStatusMock()
+
+        // Octagon should discover the right CDP state, and end up in untrusted
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForCDP, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.fetchCDPStatus(context: self.cuttlefishContext), .unknown, "CDP status should be 'unknown'")
+    }
+
     func testSignOut() throws {
         self.startCKAccountStatusMock()
 
@@ -496,7 +509,7 @@ class OctagonAccountTests: OctagonTestsBase {
         //check trust status
         let checkTrustExpectation = self.expectation(description: "checkTrustExpectation callback occurs")
         let configuration = OTOperationConfiguration()
-        self.cuttlefishContext.rpcTrustStatus(configuration) { _, _, _, _, _ in
+        self.cuttlefishContext.rpcTrustStatus(configuration) { _, _, _, _, _, _ in
             checkTrustExpectation.fulfill()
         }
         self.wait(for: [checkTrustExpectation], timeout: 10)
@@ -562,7 +575,6 @@ class OctagonAccountTests: OctagonTestsBase {
         }
         self.wait(for: [joinWithBottleExpectation], timeout: 3)
     }
-
 }
 
 #endif
index 4888f6e160c442137e0f6159e8a40ad7d5e9ebe9..96b150165131111d0d692c291c8a8b289c00678d 100644 (file)
@@ -1,6 +1,63 @@
 #if OCTAGON
 
 class OctagonCKKSTests: OctagonTestsBase {
+    var previousKeychainAccessGroups: [String]!
+
+    override func setUp() {
+        // These tests would like to examine the behavior of a CKKS user-controlled-view
+        if self.mockDeviceInfo == nil {
+            let actualDeviceAdapter = OTDeviceInformationActualAdapter()
+            self.mockDeviceInfo = OTMockDeviceInfoAdapter(modelID: actualDeviceAdapter.modelID(),
+                                                          deviceName: actualDeviceAdapter.deviceName(),
+                                                          serialNumber: NSUUID().uuidString,
+                                                          osVersion: actualDeviceAdapter.osVersion())
+        }
+
+        if self.mockDeviceInfo.mockModelID.contains("AppleTV") {
+            self.intendedCKKSZones = Set([
+                CKRecordZone.ID(zoneName: "LimitedPeersAllowed"),
+            ])
+        } else {
+            self.intendedCKKSZones = Set([
+                CKRecordZone.ID(zoneName: "LimitedPeersAllowed"),
+                CKRecordZone.ID(zoneName: "Manatee"),
+                CKRecordZone.ID(zoneName: "Passwords"),
+                CKRecordZone.ID(zoneName: "SecureObjectSync"),
+                CKRecordZone.ID(zoneName: "Backstop"),
+            ])
+        }
+
+        super.setUp()
+
+        XCTAssertTrue(self.cuttlefishContext.viewManager!.useCKKSViewsFromPolicy(), "CKKS should be configured to listen to policy-based views")
+
+        // Allow ourselves to add safari items
+        self.previousKeychainAccessGroups = (SecAccessGroupsGetCurrent()?.takeUnretainedValue()) as? [String]
+        SecAccessGroupsSetCurrent((self.previousKeychainAccessGroups + ["com.apple.cfnetwork", "com.apple.sbd"]) as CFArray)
+    }
+
+    override func tearDown() {
+        SecAccessGroupsSetCurrent(self.previousKeychainAccessGroups as CFArray)
+        super.tearDown()
+    }
+
+    func testHandleSBDItemAddSort() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        #if os(tvOS)
+        // do not continue: TVs don't sync sos items.
+        #else
+
+        self.expectCKModifyItemRecords(1, currentKeyPointerRecords: 1, zoneID: CKRecordZone.ID(zoneName: "SecureObjectSync"))
+        self.addGenericPassword("asdf",
+                                account: "SBD-test",
+                                accessGroup: "com.apple.sbd")
+
+        self.verifyDatabaseMocks()
+        #endif // tvos test skip
+    }
+
     func testHandleCKKSKeyHierarchyConflictOnEstablish() throws {
         self.startCKAccountStatusMock()
 
@@ -64,6 +121,354 @@ class OctagonCKKSTests: OctagonTestsBase {
         self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
         self.verifyDatabaseMocks()
     }
+
+    func testUserControllableViewStatusAPI() throws {
+        self.startCKAccountStatusMock()
+
+        let establishExpectation = self.expectation(description: "establish")
+        self.fakeCuttlefishServer.establishListener = { request in
+            XCTAssertTrue(request.peer.hasStableInfoAndSig, "updateTrust request should have a stableInfo info")
+            let newStableInfo = request.peer.stableInfoAndSig.stableInfo()
+            #if os(tvOS) || os(watchOS)
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .FOLLOWING, "User-controllable views should be 'following'")
+            #else
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .DISABLED, "User-controllable views should be disabled")
+            #endif
+            establishExpectation.fulfill()
+            return nil
+        }
+
+        self.assertResetAndBecomeTrustedInDefaultContext()
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        self.wait(for: [establishExpectation], timeout: 10)
+        self.fakeCuttlefishServer.establishListener = nil
+
+        #if os(tvOS)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow")
+
+        XCTAssertTrue(self.injectedManager?.policy?.syncUserControllableViewsAsBoolean() ?? false, "CKKS should be syncing user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
+        // Watches won't ever disable the user views, so the API should fail
+        XCTAssertThrowsError(try clique.setUserControllableViewsSyncStatus(false), "Should be an error setting user-visible sync status")
+        XCTAssertThrowsError(try clique.setUserControllableViewsSyncStatus(true), "Should be an error setting user-visible sync status")
+
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow peer's opinions of sync user views")
+        XCTAssertTrue(self.injectedManager?.policy?.syncUserControllableViewsAsBoolean() ?? false, "CKKS should be syncing user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
+        #else
+
+        #if !os(watchOS)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .DISABLED, "CKKS should be configured to not sync user views")
+
+        // And disabling it again doesn't write to the server
+        self.assertModifyUserViewsWithNoPeerUpdate(clique: clique, intendedSyncStatus: false)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .DISABLED, "CKKS should be configured to not sync user views")
+        #else
+        // Watches, since some support this UI, and others don't, get special handling
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow")
+        XCTAssertTrue(self.injectedManager?.policy?.syncUserControllableViewsAsBoolean() ?? false, "CKKS should be syncing user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
+        self.assertModifyUserViews(clique: clique, intendedSyncStatus: false)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .DISABLED, "CKKS should be configured to not sync user views")
+        #endif // watchOS
+
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // Manatee items should upload
+        self.expectCKModifyItemRecords(1, currentKeyPointerRecords: 1, zoneID: self.manateeZoneID)
+        self.addGenericPassword("asdf", account: "account-delete-me", viewHint: "Manatee")
+        self.verifyDatabaseMocks()
+
+        // But Passwords items should not
+        self.addGenericPassword("asdf",
+                                account: "account-apple.com",
+                                access: kSecAttrAccessibleWhenUnlocked as String,
+                                viewHint: nil,
+                                accessGroup: "com.apple.cfnetwork",
+                                expecting: errSecSuccess,
+                                message: "Should be able to add a CFNetwork keychain item")
+        let passwordsView = self.injectedManager?.findView("Passwords")
+        XCTAssertNotNil(passwordsView, "Should have a passwords view")
+        passwordsView!.waitForOperations(of: CKKSOutgoingQueueOperation.self)
+
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // And how about enabling it? That should upload the password
+        self.expectCKModifyItemRecords(1, currentKeyPointerRecords: 1, zoneID: self.passwordsZoneID)
+        self.assertModifyUserViews(clique: clique, intendedSyncStatus: true)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .ENABLED, "CKKS should be configured to sync user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        self.verifyDatabaseMocks()
+
+        // And enabling it again doesn't write to the server
+        self.assertModifyUserViewsWithNoPeerUpdate(clique: clique, intendedSyncStatus: true)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .ENABLED, "CKKS should be configured to sync user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
+        // And we can turn it off again
+        self.assertModifyUserViews(clique: clique, intendedSyncStatus: false)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .DISABLED, "CKKS should be configured to not sync user views")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        #endif // !os(tvOS)
+    }
+
+    func testJoinFollowsUserViewStatus() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        #if os(tvOS)
+        // For tvs, this is always on
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
+        // Add a peer
+        let peer2Context = self.makeInitiatorContext(contextID: "peer2")
+        self.assertJoinViaEscrowRecovery(joiningContext: peer2Context, sponsor: self.cuttlefishContext)
+
+        // The new peer should automatically have turned on user view syncing
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2Context), status: true)
+
+        // TVs can't ever modify this value
+        let peer2Clique = self.cliqueFor(context: peer2Context)
+        XCTAssertThrowsError(try peer2Clique.setUserControllableViewsSyncStatus(false), "Should be an error setting user-visible sync status")
+        XCTAssertThrowsError(try peer2Clique.setUserControllableViewsSyncStatus(true), "Should be an error setting user-visible sync status")
+        self.assertFetchUserControllableViewsSyncStatus(clique: peer2Clique, status: true)
+
+        #elseif os(watchOS)
+        // Watches are following by default. Turn the status off for the rest of the test
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow")
+
+        self.assertModifyUserViews(clique: clique, intendedSyncStatus: false)
+        XCTAssertEqual(self.injectedManager?.policy?.syncUserControllableViews, .DISABLED, "CKKS should be configured to not sync user views")
+
+        // Add a peer
+        let peer2Context = self.makeInitiatorContext(contextID: "peer2")
+        self.assertJoinViaEscrowRecovery(joiningContext: peer2Context, sponsor: self.cuttlefishContext)
+
+        // A new watch peer will be FOLLOWING, so this API will return true
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2Context), status: true)
+
+        #else  // iOS, macOS
+
+        // By default, the sync status is "off"
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // Add a peer
+        let peer2Context = self.makeInitiatorContext(contextID: "peer2")
+        self.assertJoinViaEscrowRecovery(joiningContext: peer2Context, sponsor: self.cuttlefishContext)
+
+        // The new peer should automatically have disabled syncing
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2Context), status: false)
+
+        self.assertModifyUserViews(clique: self.cliqueFor(context: peer2Context), intendedSyncStatus: true)
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2Context), status: true)
+        #endif  // iOS, macOS
+
+        // And a third peer joins!
+        let peer3Context = self.makeInitiatorContext(contextID: "peer3", authKitAdapter: self.mockAuthKit3)
+        self.assertJoinViaEscrowRecovery(joiningContext: peer3Context, sponsor: peer2Context)
+
+        #if os(tvOS) || os(watchOS)
+        // Watches and TVs won't ever turn this off (without extra UI), so a freshly joined peer will report this status as true
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer3Context), status: true)
+        #else
+        // Peer3, by default, should have disabled the user controllable views (following peer1)
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer3Context), status: false)
+        #endif
+    }
+
+    func testUpgradePeerToHaveUserSyncableViewsOpinionViaAskingSOS() throws {
+        self.mockSOSAdapter.safariViewEnabled = true
+
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        #if os(tvOS) || os(watchOS)
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        #else
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+        #endif
+
+        // Now, fake that the peer no longer has this opinion:
+        do {
+            let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName,
+                                                            context: self.cuttlefishContext.contextID)
+
+            let (_, newSyncingPolicy, updateError) = container.updateSync(test: self,
+                                                                          syncUserControllableViews: .UNKNOWN)
+            XCTAssertNil(updateError, "Should be no error performing update")
+            XCTAssertNotNil(newSyncingPolicy, "Should have a syncing policy")
+            XCTAssertEqual(newSyncingPolicy?.syncUserControllableViews, .UNKNOWN, "Should now have 'unknown' user controlled views setting")
+
+            self.injectedManager?.setCurrentSyncingPolicy(newSyncingPolicy)
+
+            try self.cuttlefishContext.accountMetadataStore.persistAccountChanges { metadata in
+                metadata.setTPSyncingPolicy(newSyncingPolicy)
+                return metadata
+            }
+        }
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // Upon daemon restart, Octagon should notice and update its opinion
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            let newStableInfo = request.stableInfoAndSig.stableInfo()
+            #if os(tvOS) || os(watchOS)
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow peer's user views")
+            #else
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .ENABLED, "CKKS should be configured to sync user views (following SOS's lead)")
+            #endif
+            updateTrustExpectation.fulfill()
+            return nil
+        }
+
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(10 * NSEC_PER_SEC), "State machine should pause")
+    }
+
+    func testUpgradePeerToHaveUserSyncableViewsOpinionViaPeersOpinion() throws {
+        self.mockSOSAdapter.sosEnabled = false
+
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        #if os(tvOS) || os(watchOS)
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        #else
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+        #endif
+
+        // Now, fake that the peer no longer has this opinion:
+        do {
+            let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName,
+                                                            context: self.cuttlefishContext.contextID)
+
+            let (_, newSyncingPolicy, updateError) = container.updateSync(test: self,
+                                                                          syncUserControllableViews: .UNKNOWN)
+            XCTAssertNil(updateError, "Should be no error performing update")
+            XCTAssertNotNil(newSyncingPolicy, "Should have a syncing policy")
+            XCTAssertEqual(newSyncingPolicy?.syncUserControllableViews, .UNKNOWN, "Should now have 'unknown' user controlled views setting")
+
+            self.injectedManager?.setCurrentSyncingPolicy(newSyncingPolicy)
+
+            try self.cuttlefishContext.accountMetadataStore.persistAccountChanges { metadata in
+                metadata.setTPSyncingPolicy(newSyncingPolicy)
+                return metadata
+            }
+        }
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // Upon daemon restart, Octagon should notice and update its opinion
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            let newStableInfo = request.stableInfoAndSig.stableInfo()
+            #if os(tvOS) || os(watchOS)
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow peer's user views")
+            #else
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .DISABLED, "CKKS should be configured to disable user views, since no peers have it actively enabled")
+            #endif
+            updateTrustExpectation.fulfill()
+            return nil
+        }
+
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(0, self.cuttlefishContext.stateMachine.paused.wait(10 * NSEC_PER_SEC), "State machine should pause")
+    }
+
+    func testUpgradePeerToHaveUserSyncableViewsOpinionWhileLocked() throws {
+        self.mockSOSAdapter.safariViewEnabled = true
+
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        #if os(tvOS) || os(watchOS)
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        #else
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+        #endif
+
+        // Now, fake that the peer no longer has this opinion:
+        do {
+            let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName,
+                                                            context: self.cuttlefishContext.contextID)
+
+            let (_, newSyncingPolicy, updateError) = container.updateSync(test: self,
+                                                                          syncUserControllableViews: .UNKNOWN)
+            XCTAssertNil(updateError, "Should be no error performing update")
+            XCTAssertNotNil(newSyncingPolicy, "Should have a syncing policy")
+            XCTAssertEqual(newSyncingPolicy?.syncUserControllableViews, .UNKNOWN, "Should now have 'unknown' user controlled views setting")
+
+            self.injectedManager?.setCurrentSyncingPolicy(newSyncingPolicy)
+
+            try self.cuttlefishContext.accountMetadataStore.persistAccountChanges { metadata in
+                metadata.setTPSyncingPolicy(newSyncingPolicy)
+                return metadata
+            }
+        }
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+
+        // Upon daemon restart, Octagon should notice and update its opinion
+
+        self.aksLockState = true
+        self.lockStateTracker.recheck()
+
+        self.fakeCuttlefishServer.updateListener = { _ in
+            XCTFail("No update should happen while the device is locked")
+            return nil
+        }
+
+        // We should get to 'wait for unlock'
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 100 * NSEC_PER_SEC)
+
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            let newStableInfo = request.stableInfoAndSig.stableInfo()
+            #if os(tvOS) || os(watchOS)
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .FOLLOWING, "CKKS should be configured to follow peer's user views")
+            #else
+            XCTAssertEqual(newStableInfo.syncUserControllableViews, .ENABLED, "CKKS should be configured to sync user views (following SOS's lead)")
+            #endif
+            updateTrustExpectation.fulfill()
+            return nil
+        }
+
+        // and once we unlock, the update should go through
+        self.aksLockState = false
+        self.lockStateTracker.recheck()
+
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+    }
+
+    func testAssistCKKSTLKUploadWhenMissingFromOctagon() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        // Another peer resets Octagon, but we miss the push
+        let reset = self.makeInitiatorContext(contextID: "reset")
+        self.assertResetAndBecomeTrusted(context: reset)
+
+        // This should cause the original peer to notice that it's no longer trusted
+        self.silentZoneDeletesAllowed = true
+        self.resetAllCKKSViews()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 100 * NSEC_PER_SEC)
+    }
 }
 
 #endif // OCTAGON
index 67e9a8210021bd110ee37ba91c3fba6f3054f6b5..5cad6bd453708831a19fc5a4893a241dacdaa6b5 100644 (file)
@@ -48,7 +48,6 @@ class OctagonCKKSConfigurationTestsPolicyDisabled: OctagonTestsBase {
 
 class OctagonCKKSConfigurationTestsPolicyEnabled: OctagonTestsBase {
     override func setUp() {
-
         if self.mockDeviceInfo == nil {
             let actualDeviceAdapter = OTDeviceInformationActualAdapter()
             self.mockDeviceInfo = OTMockDeviceInfoAdapter(modelID: actualDeviceAdapter.modelID(),
@@ -69,18 +68,15 @@ class OctagonCKKSConfigurationTestsPolicyEnabled: OctagonTestsBase {
                 CKRecordZone.ID(zoneName: "ApplePay"),
                 CKRecordZone.ID(zoneName: "Applications"),
                 CKRecordZone.ID(zoneName: "AutoUnlock"),
-                // <rdar://problem/57771098> Octagon: create final policy for CKKS4All
-                // CKRecordZone.ID(zoneName: "Backstop"),
-                // <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-                CKRecordZone.ID(zoneName: "SafariCreditCards"),
+                CKRecordZone.ID(zoneName: "Backstop"),
+                CKRecordZone.ID(zoneName: "CreditCards"),
                 CKRecordZone.ID(zoneName: "DevicePairing"),
                 CKRecordZone.ID(zoneName: "Engram"),
                 CKRecordZone.ID(zoneName: "Health"),
                 CKRecordZone.ID(zoneName: "Home"),
                 CKRecordZone.ID(zoneName: "LimitedPeersAllowed"),
                 CKRecordZone.ID(zoneName: "Manatee"),
-                // <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-                CKRecordZone.ID(zoneName: "SafariPasswords"),
+                CKRecordZone.ID(zoneName: "Passwords"),
                 CKRecordZone.ID(zoneName: "ProtectedCloudStorage"),
                 CKRecordZone.ID(zoneName: "SecureObjectSync"),
                 CKRecordZone.ID(zoneName: "WiFi"),
@@ -100,25 +96,22 @@ class OctagonCKKSConfigurationTestsPolicyEnabled: OctagonTestsBase {
 
         #if !os(tvOS)
         let expected = Set<String>([
-                                    "ApplePay",
-                                    "Applications",
-                                    "AutoUnlock",
-                                    // <rdar://problem/57771098> Octagon: create final policy for CKKS4All
-                                    //"Backstop",
-                                    // <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-                                    "SafariCreditCards",
-                                    "DevicePairing",
-                                    "Engram",
-                                    "Health",
-                                    "Home",
-                                    "LimitedPeersAllowed",
-                                    "Manatee",
-                                    // <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-                                    "SafariPasswords",
-                                    "ProtectedCloudStorage",
-                                    "SecureObjectSync",
-                                    "WiFi",
-                                    ])
+            "ApplePay",
+            "Applications",
+            "AutoUnlock",
+            "Backstop",
+            "CreditCards",
+            "DevicePairing",
+            "Engram",
+            "Health",
+            "Home",
+            "LimitedPeersAllowed",
+            "Manatee",
+            "Passwords",
+            "ProtectedCloudStorage",
+            "SecureObjectSync",
+            "WiFi",
+        ])
         #else
         let expected = Set<String>(["LimitedPeersAllowed",
                                     "Home",
index fd35bd09f36b23d740b4a785d8ff42950ab179f9..812520c694de3c986ab848c62cc1e889ffc9a9f2 100644 (file)
@@ -42,8 +42,8 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
         self.cuttlefishContext.startOctagonStateMachine()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
 
-        // And CKKS should be in 'loggedout'
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
+        // And CKKS shouldn't be spun up
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have no CKKS views before CK login")
 
         // Account sign in occurs
         let newAltDSID = UUID().uuidString
@@ -188,7 +188,7 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC)
         self.assertNoAccount(context: self.cuttlefishContext)
 
-        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have no CKKS views in an SA 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
@@ -202,7 +202,7 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
         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)
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have no CKKS views in an SA account")
     }
 
     func testSAtoHSA2PromotionWithoutCloudKit() throws {
@@ -351,15 +351,16 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
         let statusexpectation = self.expectation(description: "trust status returns")
         let configuration = OTOperationConfiguration()
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
-        self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in
+        self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _, error in
             XCTAssertEqual(.noCloudKitAccount, egoStatus, "cliqueStatus should be 'no cloudkit account'")
+            XCTAssertNil(error, "should have no error fetching status")
             statusexpectation.fulfill()
         }
         self.wait(for: [statusexpectation], timeout: 10)
 
         self.assertNoAccount(context: self.cuttlefishContext)
 
-        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have no CKKS views")
     }
 
     func testStatusRPCsWithUnknownCloudKitAccount() throws {
@@ -367,7 +368,7 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
         let statusexpectation = self.expectation(description: "trust status returns")
         let configuration = OTOperationConfiguration()
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
-        self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in
+        self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _, _ in
             XCTAssertTrue([.absent].contains(egoStatus), "Self peer should be in the 'absent' state")
             statusexpectation.fulfill()
         }
@@ -425,6 +426,63 @@ class OctagonCloudKitAccountTests: OctagonTestsBase {
 
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
         self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
+
+        // Let Octagon know about the account status, so test teardown is fast
+        self.startCKAccountStatusMock()
+    }
+
+    func testReceiveOctagonAPICallBeforeCKAccountNotification() throws {
+        // Device is signed out of everything
+        self.mockAuthKit.altDSID = nil
+        self.accountStatus = .noAccount
+        self.startCKAccountStatusMock()
+
+        // Tell SOS that it is absent, so we don't enable CDP on bringup
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCCircleAbsent)
+
+        // With no account, Octagon should go directly into 'NoAccount'
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.injectedManager!.views.count, 0, "Should have no CKKS views before CK login")
+
+        // Account sign in occurs
+        let newAltDSID = UUID().uuidString
+        self.mockAuthKit.altDSID = newAltDSID
+        XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(newAltDSID), "Sign-in shouldn't error")
+
+        // Octagon should go into 'wait for cloudkit account'
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitingForCloudKitAccount, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
+
+        // RPCs should fail, since CK is not present
+        let fetchViableFailureExpectation = self.expectation(description: "fetchViableBottles callback occurs")
+        self.cuttlefishContext.rpcFetchAllViableBottles { _, _, error in
+            XCTAssertNotNil(error, "should be an error fetching viable bottles before CK is ready")
+
+            if let nserror = error as NSError? {
+                XCTAssertEqual(nserror.domain, OctagonErrorDomain, "Error should be from correct domain")
+                XCTAssertEqual(nserror.code, OctagonError.OTErrorNotSignedIn.rawValue, "Error should indicate no account present")
+            } else {
+                XCTFail("Unable to convert error to nserror")
+            }
+            fetchViableFailureExpectation.fulfill()
+        }
+        self.wait(for: [fetchViableFailureExpectation], timeout: 10)
+
+        // CK signs in, but we aren't yet notified about it
+        self.accountStatus = .available
+
+        // RPCs should cause Octagon to recheck the CK account status and wake up
+        // In particular, fetching all viable bottles should succeed, instead of erroring with 'no CK account'
+        let fetchViableExpectation = self.expectation(description: "fetchViableBottles callback occurs")
+        self.cuttlefishContext.rpcFetchAllViableBottles { _, _, error in
+            XCTAssertNil(error, "should be no error fetching viable bottles")
+            fetchViableExpectation.fulfill()
+        }
+        self.wait(for: [fetchViableExpectation], timeout: 10)
+
+        // With no SOS and no CDP, Octagon should wait for enablement
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForCDP, within: 10 * NSEC_PER_SEC)
     }
 }
 
index b639f749d35506a411d62da1b3857dab2cefe389..810b8e4153bb8a31d098f89cfa95e3d86b91dc5f 100644 (file)
@@ -22,8 +22,9 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -85,8 +86,9 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -118,7 +120,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
 
         // Since SOS isn't around to help, Octagon should post a CFU
         #if os(tvOS)
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), false, "Should not have posted a CFU on aTV (due to having no peers to join)")
+        XCTAssertFalse(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should not have posted a CFU on aTV (due to having no peers to join)")
         #else
         XCTAssertTrue(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "should have posted an repair CFU, as SOS can't help")
         #endif
@@ -150,8 +152,9 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -229,8 +232,9 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -323,12 +327,12 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
 
         // Now, a mac appears! macs cannot fix apple TVs.
         let mac = self.manager.context(forContainerName: OTCKContainerName,
-                                          contextID: "asdf",
-                                          sosAdapter: self.mockSOSAdapter,
-                                          authKitAdapter: self.mockAuthKit2,
-                                          lockStateTracker: self.lockStateTracker,
-                                          accountStateTracker: self.accountStateTracker,
-                                          deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iMac7,1", deviceName: "test-mac", serialNumber: "456", osVersion: "macOS (fake version)"))
+                                       contextID: "asdf",
+                                       sosAdapter: self.mockSOSAdapter,
+                                       authKitAdapter: self.mockAuthKit2,
+                                       lockStateTracker: self.lockStateTracker,
+                                       accountStateTracker: self.accountStateTracker,
+                                       deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iMac7,1", deviceName: "test-mac", serialNumber: "456", osVersion: "macOS (fake version)"))
         mac.startOctagonStateMachine()
 
         let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablishExpectation returns")
@@ -429,7 +433,7 @@ class OctagonCoreFollowUpTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
 
         #if os(tvOS)
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), false, "Should not have posted a CFU on aTV (due to having no peers to join)")
+        XCTAssertFalse(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should not have posted a CFU on aTV (due to having no peers to join)")
         #else
         XCTAssertTrue(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "should have posted an repair CFU, as SOS can't help")
         #endif
index 110b7e30ab4007d36afcd01a76189bbd8dd5ad2f..a0744ad97be93229786efb98715e4241e434717a 100644 (file)
@@ -80,7 +80,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // Then peer2 drops off the device list. Peer 1 should distrust peer2.
         let updateTrustExpectation = self.expectation(description: "updateTrust")
@@ -102,7 +102,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .excludes, target: peer2ID)),
-                     "peer 1 should distrust peer 2 after update")
+                      "peer 1 should distrust peer 2 after update")
     }
 
     func testNumberOfPeersInModel() throws {
@@ -148,7 +148,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // Then peer2 drops off the device list. Peer 1 should distrust peer2.
         let updateTrustExpectation = self.expectation(description: "updateTrust")
@@ -194,7 +194,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
         self.assertMIDList(context: self.cuttlefishContext,
                            allowed: self.mockAuthKit.currentDeviceList(),
                            disallowed: Set(),
@@ -231,7 +231,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
     }
 
     func testRemoveSelfWhenRemovedFromOnlySelfList() throws {
@@ -351,7 +351,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // We receive a 'remove' push for peer2's ID, but for the wrong DSID. The peer should do nothing useful.
         self.fakeCuttlefishServer.updateListener = { request in
@@ -365,7 +365,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         self.assertMIDList(context: self.cuttlefishContext,
                            allowed: self.mockAuthKit.currentDeviceList(),
@@ -390,7 +390,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // We receive a 'add' push for a new ID, but for the wrong DSID. The peer should do nothing useful.
         self.fakeCuttlefishServer.updateListener = { request in
@@ -405,7 +405,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // newMachineID should be on no lists
         self.assertMIDList(context: self.cuttlefishContext,
@@ -457,7 +457,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
                     //
                     machinemo.modified = Date(timeIntervalSinceNow: -60 * 60 * TimeInterval(72))
                     XCTAssertEqual(machinemo.status, Int64(TPMachineIDStatus.unknown.rawValue), "peer2's MID entry should be 'unknown'")
-                }
+            }
 
             XCTAssertTrue(foundPeer2, "Should have found an entry for peer2")
             try! container.moc.save()
@@ -490,7 +490,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
 
         // Then peer2 arrives on the device list. Peer 1 should update its dynamic info to no longer have a disposition for peer2.
         let updateTrustExpectation = self.expectation(description: "updateTrust")
@@ -575,7 +575,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.mockAuthKit.otherDevices.removeAll()
         self.mockAuthKit.isDemoAccount = true
         self.mockAuthKit2.isDemoAccount = true
-        
+
         XCTAssertEqual(self.mockAuthKit.currentDeviceList(), Set([self.mockAuthKit.currentMachineID]), "AuthKit should have exactly one device on the list")
         XCTAssertFalse(self.mockAuthKit.currentDeviceList().contains(self.mockAuthKit2.currentMachineID), "AuthKit should not already have device 2 on the list")
 
@@ -591,7 +591,7 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
         self.assertMIDList(context: self.cuttlefishContext,
                            allowed: self.mockAuthKit.currentDeviceList(),
                            disallowed: Set(),
@@ -628,9 +628,102 @@ class OctagonDeviceListTests: OctagonTestsBase {
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
-                     "peer 1 should trust peer 2 after update")
+                      "peer 1 should trust peer 2 after update")
     }
 
+    static func makeAuthKitError(code: Int) -> NSError {
+        let authkitError = CKPrettyError(domain: AKAppleIDAuthenticationErrorDomain,
+                                         code: code,
+                                         userInfo: nil)
+
+        return authkitError
+    }
+
+    func testRemovePeerWhenRemovedFromDeviceListAndAuthkitThrowsError() throws {
+        self.startCKAccountStatusMock()
+
+        XCTAssert(self.mockAuthKit.currentDeviceList().contains(self.mockAuthKit2.currentMachineID), "AuthKit should already have device 2 on the list")
+
+        let peer2ContextID = "joiner"
+        let peer1ID = self.assertResetAndBecomeTrustedInDefaultContext()
+
+        let joiningContext = self.makeInitiatorContext(contextID: peer2ContextID, authKitAdapter: self.mockAuthKit2)
+        let peer2ID = self.assertJoinViaEscrowRecovery(joiningContext: joiningContext, sponsor: self.cuttlefishContext)
+
+        // Now, tell peer1 about the change. It will trust the peer and upload some TLK shares
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
+        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
+                      "peer 1 should trust peer 2 after update")
+
+        // Then peer2 drops off the device list. Peer 1 should distrust peer2.
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            XCTAssertTrue(request.hasDynamicInfoAndSig, "updateTrust request should have a dynamic info")
+            let newDynamicInfo = TPPeerDynamicInfo(data: request.dynamicInfoAndSig.peerDynamicInfo,
+                                                   sig: request.dynamicInfoAndSig.sig)
+            XCTAssertNotNil(newDynamicInfo, "should be able to make a dynamic info from protobuf")
+
+            XCTAssertTrue(!(newDynamicInfo?.includedPeerIDs.contains(peer2ID) ?? true), "peer1 should no longer trust peer2")
+            updateTrustExpectation.fulfill()
+            return nil
+        }
+
+        self.mockAuthKit.removeAndSendNotification(machineID: try! self.mockAuthKit2.machineID())
+
+        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)
+
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .excludes, target: peer2ID)),
+                      "peer 1 should distrust peer 2 after update")
+
+        self.assertEnters(context: joiningContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+        //peer2 attempts to update trusted device list but hits an authkit error
+        //try bottle restore again
+        joiningContext.startOctagonStateMachine()
+
+        let sponsorPeerID = try self.cuttlefishContext.accountMetadataStore.loadOrCreateAccountMetadata().peerID
+        XCTAssertNotNil(sponsorPeerID, "sponsorPeerID should not be nil")
+        let entropy = try self.loadSecret(label: sponsorPeerID!)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        let altDSID = try joiningContext.authKitAdapter.primaryiCloudAccountAltDSID()
+        XCTAssertNotNil(altDSID, "Should have an altDSID")
+
+        let bottles = self.fakeCuttlefishServer.state.bottles.filter { $0.peerID == sponsorPeerID }
+        XCTAssertEqual(bottles.count, 1, "Should have a single bottle for the approving peer")
+        let bottle = bottles[0]
+
+        let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs")
+        joiningContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: altDSID) { error in
+            XCTAssertNil(error, "error should be nil")
+            joinWithBottleExpectation.fulfill()
+        }
+
+        self.assertEnters(context: joiningContext, state: OctagonStateInitiatorUpdateDeviceList, within: 10 * NSEC_PER_SEC)
+
+        let authKitError = OctagonDeviceListTests.makeAuthKitError(code: -7026)
+        self.mockAuthKit2.machineIDFetchErrors = [authKitError]
+        let updateTrustExpectationPeer2 = self.expectation(description: "updateTrustPeer2")
+        self.fakeCuttlefishServer.fetchChangesListener = { request in
+            self.mockAuthKit2.machineIDFetchErrors = []
+            updateTrustExpectationPeer2.fulfill()
+            self.fakeCuttlefishServer.fetchChangesListener = nil
+            return nil
+        }
+        self.wait(for: [updateTrustExpectationPeer2], timeout: 10)
+
+        self.wait(for: [joinWithBottleExpectation], timeout: 10)
+
+        self.assertConsidersSelfTrusted(context: joiningContext)
+
+        self.assertEnters(context: joiningContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+    }
 }
 
 #endif
index da28130fdf630882a853b68bf43987f93c098eaf..a909284c34195dfec7bd968d7b02a163d60b2fb2 100644 (file)
@@ -1,17 +1,15 @@
 #if OCTAGON
 
 class OctagonErrorHandlingTests: OctagonTestsBase {
-
     func testEstablishFailedError() throws {
         self.startCKAccountStatusMock()
 
         let establishExpectation = self.expectation(description: "establishExpectation")
 
-        self.fakeCuttlefishServer.establishListener = {  [unowned self] request in
+        self.fakeCuttlefishServer.establishListener = { [unowned self] request in
             self.fakeCuttlefishServer.establishListener = nil
 
-            self.fakeCuttlefishServer.establish(request) {
-                response, error in
+            self.fakeCuttlefishServer.establish(request) { response, error in
                 XCTAssertNil(error, "should be no error from establish")
                 XCTAssertNotNil(response, "should get a response from establish")
                 // drop the response on the floor
@@ -31,7 +29,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
 
         let establishExpectation = self.expectation(description: "establishExpectation")
 
-        self.fakeCuttlefishServer.establishListener = {  [unowned self] request in
+        self.fakeCuttlefishServer.establishListener = { [unowned self] request in
             self.fakeCuttlefishServer.establishListener = nil
             establishExpectation.fulfill()
 
@@ -51,7 +49,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
 
         var t0 = Date.distantPast
 
-        self.fakeCuttlefishServer.establishListener = {  [unowned self] request in
+        self.fakeCuttlefishServer.establishListener = { [unowned self] request in
             self.fakeCuttlefishServer.establishListener = nil
             establishExpectation.fulfill()
 
@@ -188,8 +186,8 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
         self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
 
         self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain,
-                code: CKError.networkUnavailable.rawValue,
-                userInfo: [CKErrorRetryAfterKey: 2]))
+                                                                   code: CKError.networkUnavailable.rawValue,
+                                                                   userInfo: [CKErrorRetryAfterKey: 2]))
 
         self.sendContainerChange(context: self.cuttlefishContext)
 
@@ -224,8 +222,8 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
         self.lockStateTracker.recheck()
 
         self.mockAuthKit.machineIDFetchErrors.append(CKPrettyError(domain: CKErrorDomain,
-                code: CKError.networkUnavailable.rawValue,
-                userInfo: [CKErrorRetryAfterKey: 2]))
+                                                                   code: CKError.networkUnavailable.rawValue,
+                                                                   userInfo: [CKErrorRetryAfterKey: 2]))
 
         self.sendContainerChange(context: self.cuttlefishContext)
 
@@ -401,7 +399,7 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         // Peer 2 arrives (with a voucher), but is not on the trusted device list
         let firstPeerID = clique.cliqueMemberIdentifier
@@ -473,11 +471,16 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
 
         // And on unlock, it should handle the update
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+
         self.aksLockState = false
         self.lockStateTracker.recheck()
 
         self.wait(for: [updateTrustExpectation], timeout: 30)
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
     }
 
     func testCKKSResetRecoverFromCKKSConflict() throws {
@@ -492,10 +495,10 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
         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")
+            let clique = OTClique(contextData: self.otcliqueContext)
+            try clique.establish()
         } catch {
-            XCTFail("Shouldn't have errored making new friends: \(error)")
+            XCTFail("Shouldn't have errored establishing Octagon: \(error)")
         }
 
         // Now, we should be in 'ready', and CKKS should be stuck
@@ -537,6 +540,78 @@ class OctagonErrorHandlingTests: OctagonTestsBase {
             XCTAssertEqual(tlkUUID, (self.keys![zoneID] as? ZoneKeys)?.tlk?.uuid, "TLK should match conflicted version")
         }
     }
+
+    func testHandlePeerMissingOnSetUserControllableViews() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        // Another device updates the world, but we don't get the push
+        let reset = self.makeInitiatorContext(contextID: "reset")
+        self.assertResetAndBecomeTrusted(context: reset)
+
+        // Now, the original peer sets their view status
+        #if os(tvOS)
+        throw XCTSkip("TVs don't set user-controllable views")
+        #else
+
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        do {
+            try clique.setUserControllableViewsSyncStatus(true)
+            XCTFail("Should be an error setting user-visible sync status")
+        } catch {
+        }
+
+        // Octagon should notice that it's been kicked out.
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        #endif // os(tvOS)
+    }
+
+    func testHandlePeerMissingOnTrustUpdate() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        // Another device joins
+        let joiner = self.makeInitiatorContext(contextID: "joiner")
+        self.assertJoinViaEscrowRecovery(joiningContext: joiner, sponsor: self.cuttlefishContext)
+
+        // Now, directly after the default context fetches, another device resets Octagon.
+        // To simulate this, we reset things in the updateTrust listener.
+        let reset = self.makeInitiatorContext(contextID: "reset")
+
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            reset.startOctagonStateMachine()
+
+            do {
+                try reset.setCDPEnabled()
+                self.assertEnters(context: reset, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+                let arguments = OTConfigurationContext()
+                arguments.altDSID = try reset.authKitAdapter.primaryiCloudAccountAltDSID()
+                arguments.context = reset.contextID
+                arguments.otControl = self.otControl
+
+                let clique = try OTClique.newFriends(withContextData: arguments, resetReason: .testGenerated)
+                XCTAssertNotNil(clique, "Clique should not be nil")
+            } catch {
+                XCTFail("Shouldn't have errored making new friends: \(error)")
+            }
+            self.assertEnters(context: reset, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+            updateTrustExpectation.fulfill()
+            return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .updateTrustPeerNotFound)
+        }
+
+        // Notify Octagon of the join
+        self.sendContainerChange(context: self.cuttlefishContext)
+
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+
+        // Octagon should notice that it's been kicked out.
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+    }
 }
 
 #endif
diff --git a/keychain/ot/tests/octagon/OctagonTests+EscrowRecords.swift b/keychain/ot/tests/octagon/OctagonTests+EscrowRecords.swift
new file mode 100644 (file)
index 0000000..5f9a4f5
--- /dev/null
@@ -0,0 +1,788 @@
+#if OCTAGON
+
+@objcMembers
+class OctagonEscrowRecordTests: OctagonTestsBase {
+
+    func testFetchEscrowRecord() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let entropy = try self.loadSecret(label: clique.cliqueMemberIdentifier!)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords: [OTEscrowRecord] = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 1, "should be 1 escrow record")
+            let reduced = escrowRecords.compactMap { $0.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+    }
+
+    func testViableBottleCachingAfterJoin() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let entropy = try self.loadSecret(label: clique.cliqueMemberIdentifier!)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        // Fake that this peer also created some TLKShares for itself
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: bottlerContext)
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        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")
+            joinWithBottleExpectation.fulfill()
+        }
+
+        self.wait(for: [joinWithBottleExpectation], timeout: 100)
+
+        let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
+        self.tphClient.dump(withContainer: OTCKContainerName, context: OTDefaultContext) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+            dumpCallback.fulfill()
+        }
+        self.wait(for: [dumpCallback], timeout: 10)
+
+        self.verifyDatabaseMocks()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+
+        //now call fetchviablebottles, we should get the uncached version
+        let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchUnCachedViableBottlesExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 1)
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+
+        //now call fetchviablebottles, we should get the cached version
+        let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles")
+        fetchViableBottlesExpectation.isInverted = true
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchViableBottlesExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow record")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesExpectation], timeout: 1)
+    }
+
+    func testCachedEscrowRecordFetch() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let entropy = try self.loadSecret(label: clique.cliqueMemberIdentifier!)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        // Fake that this peer also created some TLKShares for itself
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: bottlerContext)
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        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")
+            joinWithBottleExpectation.fulfill()
+        }
+
+        self.wait(for: [joinWithBottleExpectation], timeout: 100)
+
+        let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
+        self.tphClient.dump(withContainer: OTCKContainerName, context: OTDefaultContext) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+            dumpCallback.fulfill()
+        }
+        self.wait(for: [dumpCallback], timeout: 10)
+
+        self.verifyDatabaseMocks()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+
+        //now call fetchviablebottles, we should get the uncached version
+        let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchUnCachedViableBottlesExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 1)
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        //now call fetchviablebottles, we should get the cached version
+        let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles")
+        fetchViableBottlesExpectation.isInverted = true
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchViableBottlesExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesExpectation], timeout: 1)
+
+        let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName, context: initiatorContextID)
+        container.escrowCacheTimeout = 1
+
+        //sleep to invalidate the cache
+        sleep(1)
+
+        //now call fetchviablebottles, we should get the uncached version
+        let uncachedViableBottlesFetchExpectation = self.expectation(description: "fetch Uncached ViableBottles")
+        let fetchBottlesFromCuttlefishFetchExpectation = self.expectation(description: "fetch bottles from cuttlefish expectation")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchBottlesFromCuttlefishFetchExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+            uncachedViableBottlesFetchExpectation.fulfill()
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchBottlesFromCuttlefishFetchExpectation], timeout: 10)
+        self.wait(for: [uncachedViableBottlesFetchExpectation], timeout: 10)
+    }
+
+    func testForcedEscrowRecordFetch() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        bottlerotcliqueContext.overrideEscrowCache = false
+
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let entropy = try self.loadSecret(label: clique.cliqueMemberIdentifier!)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        // Fake that this peer also created some TLKShares for itself
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: bottlerContext)
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        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")
+            joinWithBottleExpectation.fulfill()
+        }
+
+        self.wait(for: [joinWithBottleExpectation], timeout: 100)
+
+        self.verifyDatabaseMocks()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+
+        //now call fetchviablebottles, we should get records from cuttlefish
+        let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchUnCachedViableBottlesExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 1)
+
+        //set the override to force an escrow record fetch
+        bottlerotcliqueContext.overrideEscrowCache = true
+
+        //now call fetchviablebottles, we should get records from cuttlefish
+        let fetchViableBottlesExpectation = self.expectation(description: "fetch forced ViableBottles")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchViableBottlesExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 2, "should be 2 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesExpectation], timeout: 10)
+    }
+
+    func testSignInWithEscrowPrecachingEnabled() throws {
+        self.startCKAccountStatusMock()
+
+        let contextName = OTDefaultContext
+        let containerName = OTCKContainerName
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        // Tell SOS that it is absent, so we don't enable CDP on bringup
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCCircleAbsent)
+
+        //expect fetch escrow record fetch
+        let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles")
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchViableBottlesExpectation.fulfill()
+            return nil
+        }
+
+        // Device is signed out
+        self.mockAuthKit.altDSID = nil
+        self.mockAuthKit.hsa2 = false
+
+        // With no account, Octagon should go directly into 'NoAccount'
+        self.cuttlefishContext.startOctagonStateMachine()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
+
+        let newAltDSID = UUID().uuidString
+        self.mockAuthKit.altDSID = newAltDSID
+        self.mockAuthKit.hsa2 = true
+        XCTAssertNoThrow(try self.cuttlefishContext.accountAvailable(newAltDSID), "Sign-in shouldn't error")
+
+        let signInExpectation = self.expectation(description: "signing in expectation")
+
+        self.manager.sign(in: newAltDSID, container: containerName, context: contextName) { error in
+            XCTAssertNil(error, "error should not be nil")
+            signInExpectation.fulfill()
+        }
+
+        self.wait(for: [signInExpectation], timeout: 10)
+        self.wait(for: [fetchViableBottlesExpectation], timeout: 10)
+    }
+
+    func testLegacyEscrowRecordFetch() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+        OctagonSetPlatformSupportsSOS(true)
+
+        self.startCKAccountStatusMock()
+
+        let initiatorContextID = "joiner"
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = OTDefaultContext
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        self.mockAuthKit.hsa2 = true
+        bottlerotcliqueContext.otControl = self.otControl
+
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        XCTAssertTrue(OctagonPerformSOSUpgrade(), "SOS upgrade should be on")
+
+        // SOS TLK shares will be uploaded after the establish
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.cuttlefishContext.startOctagonStateMachine()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
+        self.verifyDatabaseMocks()
+
+        let joinerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+        self.assertJoinViaEscrowRecovery(joiningContext: joinerContext, sponsor: self.cuttlefishContext)
+
+        let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName, context: OTDefaultContext)
+
+        //now call fetchviablebottles, we should get the uncached version
+        let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
+
+        self.fakeCuttlefishServer.injectLegacyEscrowRecords = true
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            fetchUnCachedViableBottlesExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+
+            XCTAssertEqual(escrowRecords.count, 3, "should be 3 escrow records")
+            let recordsWithBottles = escrowRecords.filter { $0!.escrowInformationMetadata.bottleId != "" }
+            XCTAssertEqual(recordsWithBottles.count, 2, "should be 2 escrow records with a bottleID")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 1)
+
+        //now call fetchviablebottles, we should get the cached version
+        let fetchViableBottlesExpectation = self.expectation(description: "fetch Cached ViableBottles")
+        fetchViableBottlesExpectation.isInverted = true
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            let legacy = container.containerMO.legacyEscrowRecords as! Set<EscrowRecordMO>
+            let partial = container.containerMO.partiallyViableEscrowRecords as! Set<EscrowRecordMO>
+            let full = container.containerMO.fullyViableEscrowRecords as! Set<EscrowRecordMO>
+
+            XCTAssertEqual(legacy.count, 1, "legacy escrowRecords should contain 1 record")
+            XCTAssertEqual(partial.count, 1, "partially viable escrowRecords should contain 1 record")
+            XCTAssertEqual(full.count, 1, "fully viable escrowRecords should contain 1 record")
+
+            fetchViableBottlesExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+
+            XCTAssertEqual(escrowRecords.count, 3, "should be 3 escrow record")
+            let recordsWithBottles = escrowRecords.filter { $0!.escrowInformationMetadata.bottleId != "" }
+            XCTAssertEqual(recordsWithBottles.count, 2, "should be 2 escrow records with a bottleID")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesExpectation], timeout: 1)
+
+        //check cache is empty after escrow fetch timeout expires
+        container.escrowCacheTimeout = 1
+        sleep(1)
+
+        //now call fetchviablebottles, we should get the uncached version, check there's 0 cached records
+        let fetchViableBottlesAfterExpiredTimeoutExpectation = self.expectation(description: "fetch Cached ViableBottles expectaiton after timeout")
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            XCTAssertEqual(container.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO>, [], "legacy escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO>, [], "partially viable escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO>, [], "fully viable escrowRecords should be empty")
+
+            fetchViableBottlesAfterExpiredTimeoutExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 3, "should be 3 escrow record")
+            let recordsWithBottles = escrowRecords.filter { $0!.escrowInformationMetadata.bottleId != "" }
+            XCTAssertEqual(recordsWithBottles.count, 2, "should be 2 escrow records with a bottleID")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesAfterExpiredTimeoutExpectation], timeout: 10)
+    }
+
+    func testEmptyEscrowRecords() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        self.fakeCuttlefishServer.includeEscrowRecords = false
+        self.fakeCuttlefishServer.injectLegacyEscrowRecords = false
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName, context: initiatorContextID)
+
+        let fetchViableBottlesAfterExpiredTimeoutExpectation = self.expectation(description: "fetch Cached ViableBottles expectaiton after timeout")
+
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            container.moc.performAndWait {
+                XCTAssertEqual(container.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO>, [], "legacy escrowRecords should be empty")
+                XCTAssertEqual(container.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO>, [], "partially viable escrowRecords should be empty")
+                XCTAssertEqual(container.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO>, [], "fully viable escrowRecords should be empty")
+            }
+            fetchViableBottlesAfterExpiredTimeoutExpectation.fulfill()
+            return nil
+        }
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            XCTAssertEqual(escrowRecordDatas.count, 0, "should be 0 escrow records")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesAfterExpiredTimeoutExpectation], timeout: 10)
+        container.moc.performAndWait {
+            XCTAssertEqual(container.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO>, [], "legacy escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO>, [], "partially viable escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO>, [], "fully viable escrowRecords should be empty")
+        }
+    }
+
+    func testRemoveEscrowCache() throws {
+        OctagonSetOptimizationEnabled(true)
+        OctagonSetEscrowRecordFetchEnabled(true)
+
+        let initiatorContextID = "initiator-context-id"
+        let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
+
+        bottlerContext.startOctagonStateMachine()
+        let ckacctinfo = CKAccountInfo()
+        ckacctinfo.accountStatus = .available
+        ckacctinfo.hasValidCredentials = true
+        ckacctinfo.accountPartition = .production
+
+        bottlerContext.cloudkitAccountStateChange(nil, to: ckacctinfo)
+        XCTAssertNoThrow(try bottlerContext.setCDPEnabled())
+        self.assertEnters(context: bottlerContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let clique: OTClique
+        let bottlerotcliqueContext = OTConfigurationContext()
+        bottlerotcliqueContext.context = initiatorContextID
+        bottlerotcliqueContext.dsid = "1234"
+        bottlerotcliqueContext.altDSID = self.mockAuthKit.altDSID!
+        bottlerotcliqueContext.otControl = self.otControl
+        do {
+            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 {
+            XCTFail("Shouldn't have errored making new friends: \(error)")
+            throw error
+        }
+
+        self.assertEnters(context: bottlerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: bottlerContext)
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords: [OTEscrowRecord] = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 1, "should be 1 escrow record")
+            let reduced = escrowRecords.compactMap { $0.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+
+        let removeExpectation = self.expectation(description: "remove expectation")
+        self.manager.invalidateEscrowCache(OTCKContainerName, contextID: initiatorContextID) { error in
+            XCTAssertNil(error, "error should not be nil")
+            removeExpectation.fulfill()
+        }
+        self.wait(for: [removeExpectation], timeout: 10)
+
+        let container = try self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName, context: initiatorContextID)
+
+        let fetchViableBottlesAfterCacheRemovalExpectation = self.expectation(description: "fetchViableBottles expectation after cache removal")
+        self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
+            self.fakeCuttlefishServer.fetchViableBottlesListener = nil
+            XCTAssertEqual(container.containerMO.legacyEscrowRecords as? Set<EscrowRecordMO>, [], "legacy escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.partiallyViableEscrowRecords as? Set<EscrowRecordMO>, [], "partially viable escrowRecords should be empty")
+            XCTAssertEqual(container.containerMO.fullyViableEscrowRecords as? Set<EscrowRecordMO>, [], "fully viable escrowRecords should be empty")
+
+            fetchViableBottlesAfterCacheRemovalExpectation.fulfill()
+            return nil
+        }
+
+        do {
+            let escrowRecordDatas = try OTClique.fetchEscrowRecordsInternal(bottlerotcliqueContext)
+            let escrowRecords = escrowRecordDatas.map { OTEscrowRecord(data: $0) }
+            XCTAssertNotNil(escrowRecords, "escrowRecords should not be nil")
+            XCTAssertEqual(escrowRecords.count, 1, "should be 1 escrow records")
+            let reduced = escrowRecords.compactMap { $0!.escrowInformationMetadata.bottleId }
+            XCTAssert(reduced.contains(bottle.bottleID), "The bottle we're about to restore should be viable")
+        } catch {
+            XCTFail("Shouldn't have errored fetching escrow records: \(error)")
+            throw error
+        }
+        self.wait(for: [fetchViableBottlesAfterCacheRemovalExpectation], timeout: 10)
+
+    }
+}
+
+#endif
index d79263f8e3ed491b255b914f5e89ffd72a2091f7..37698b05aecd0c78b63f04c0fc5e67a179c81717 100644 (file)
@@ -51,12 +51,6 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         self.startCKAccountStatusMock()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
-        // Try to enforce that that CKKS doesn't know about the key hierarchy until Octagon asks it
-        self.holdCloudKitFetches()
-
-        // Note: CKKS will want to upload a TLKShare for its self
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
-
         // Before you call joinWithBottle, you need to call fetchViableBottles.
         let fetchViableExpectation = self.expectation(description: "fetchViableBottles callback occurs")
         self.cuttlefishContext.rpcFetchAllViableBottles { viable, _, error in
@@ -72,9 +66,6 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
             joinWithBottleExpectation.fulfill()
         }
 
-        sleep(1)
-        self.releaseCloudKitFetchHold()
-
         self.wait(for: [joinWithBottleExpectation], timeout: 100)
 
         let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
@@ -93,7 +84,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
 
         self.verifyDatabaseMocks()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
     }
 
     func testBottleRestoreEntersOctagonReady() throws {
@@ -254,8 +246,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         let differentRestoreExpectation = self.expectation(description: "different restore returns")
         differentDevice.startOctagonStateMachine()
         differentDevice.join(withBottle: bottle.bottleID,
-                            entropy: entropy!,
-                            bottleSalt: self.otcliqueContext.altDSID!) { error in
+                             entropy: entropy!,
+                             bottleSalt: self.otcliqueContext.altDSID!) { error in
                                 XCTAssertNil(error, "error should be nil")
                                 differentRestoreExpectation.fulfill()
         }
@@ -280,8 +272,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         restoreContext.join(withBottle: bottle.bottleID,
                             entropy: entropy!,
                             bottleSalt: self.otcliqueContext.altDSID!) { error in
-            XCTAssertNil(error, "error should be nil")
-            restoreExpectation.fulfill()
+                                XCTAssertNil(error, "error should be nil")
+                                restoreExpectation.fulfill()
         }
         self.wait(for: [restoreExpectation], timeout: 10)
 
@@ -468,7 +460,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         // We will upload a new TLK for the new peer
         self.assertAllCKKSViewsUpload(tlkShares: 1)
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
 
         self.sendContainerChangeWaitForFetch(context: initiatorContext)
         bottleIDs = try OTClique.findOptimalBottleIDs(withContextData: self.otcliqueContext)
@@ -608,7 +601,6 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
                 fetchEscrowContentsException.fulfill()
             }
             self.wait(for: [fetchEscrowContentsException], timeout: 10)
-
         } catch {
             XCTFail("failed to reset clique: \(error)")
         }
@@ -901,12 +893,12 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
                                                       machineID: "c-machine-id",
                                                       otherDevices: [self.mockAuthKit.currentMachineID, deviceBmockAuthKit.currentMachineID])
         let restoreContext = self.manager.context(forContainerName: OTCKContainerName,
-                                                   contextID: "restoreContext",
-                                                   sosAdapter: OTSOSMissingAdapter(),
-                                                   authKitAdapter: restoremockAuthKit,
-                                                   lockStateTracker: self.lockStateTracker,
-                                                   accountStateTracker: self.accountStateTracker,
-                                                   deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter())
+                                                  contextID: "restoreContext",
+                                                  sosAdapter: OTSOSMissingAdapter(),
+                                                  authKitAdapter: restoremockAuthKit,
+                                                  lockStateTracker: self.lockStateTracker,
+                                                  accountStateTracker: self.accountStateTracker,
+                                                  deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter())
 
         restoreContext.startOctagonStateMachine()
         let newOTCliqueContext = OTConfigurationContext()
@@ -969,6 +961,7 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
     }
 
     func testCachedBottleFetch() throws {
+        OctagonSetOptimizationEnabled(false)
         let initiatorContextID = "initiator-context-id"
         let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
 
@@ -1009,15 +1002,12 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
 
         let bottle = self.fakeCuttlefishServer.state.bottles[0]
 
-        self.cuttlefishContext.startOctagonStateMachine()
-        self.startCKAccountStatusMock()
-        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
-
         // Try to enforce that that CKKS doesn't know about the key hierarchy until Octagon asks it
         self.holdCloudKitFetches()
 
-        // Note: CKKS will want to upload a TLKShare for its self
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
         let joinWithBottleExpectation = self.expectation(description: "joinWithBottle callback occurs")
         self.cuttlefishContext.join(withBottle: bottle.bottleID, entropy: entropy!, bottleSalt: self.otcliqueContext.altDSID!) { error in
@@ -1046,7 +1036,7 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
 
         self.verifyDatabaseMocks()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.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")
@@ -1061,6 +1051,10 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         self.cuttlefishContext.rpcFetchAllViableBottles { viable, _, error in
             XCTAssertNil(error, "should be no error fetching viable bottles")
             XCTAssert(viable?.contains(bottle.bottleID) ?? false, "The bottle we're about to restore should be viable")
+            XCTAssertEqual(viable?.count, 2, "There should be 2 bottles")
+            XCTAssertNotEqual(viable?[0], "", "Bottle should not be empty")
+            XCTAssertNotEqual(viable?[1], "", "Bottle should not be empty")
+
             FetchAllViableBottles.fulfill()
         }
         self.wait(for: [FetchAllViableBottles], timeout: 10)
@@ -1095,6 +1089,7 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
     }
 
     func testViableBottleCachingAfterJoin() throws {
+        OctagonSetOptimizationEnabled(false)
         let initiatorContextID = "initiator-context-id"
         let bottlerContext = self.makeInitiatorContext(contextID: initiatorContextID)
 
@@ -1140,21 +1135,12 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
-        // Try to enforce that that CKKS doesn't know about the key hierarchy until Octagon asks it
-        self.holdCloudKitFetches()
-
-        // Note: CKKS will want to upload a TLKShare for its self
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
-
         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")
             joinWithBottleExpectation.fulfill()
         }
 
-        sleep(1)
-        self.releaseCloudKitFetchHold()
-
         self.wait(for: [joinWithBottleExpectation], timeout: 100)
 
         let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
@@ -1173,7 +1159,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
 
         self.verifyDatabaseMocks()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
 
         //now call fetchviablebottles, we should get the uncached version
         let fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
@@ -1266,21 +1253,12 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         self.startCKAccountStatusMock()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
-        // Try to enforce that that CKKS doesn't know about the key hierarchy until Octagon asks it
-        self.holdCloudKitFetches()
-
-        // Note: CKKS will want to upload a TLKShare for its self
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
-
         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")
             joinWithBottleExpectation.fulfill()
         }
 
-        sleep(1)
-        self.releaseCloudKitFetchHold()
-
         self.wait(for: [joinWithBottleExpectation], timeout: 100)
 
         var egoPeerID: String?
@@ -1302,7 +1280,8 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
 
         self.verifyDatabaseMocks()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
 
         let bottles: [Bottle] = self.fakeCuttlefishServer.state.bottles
         var bottleToExclude: String?
@@ -1333,8 +1312,9 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         self.wait(for: [FetchAllViableBottles], timeout: 10)
         self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 10)
 
-        //now call fetchviablebottles, we should get the uncached version
-        fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch UnCached ViableBottles")
+        //now call fetchviablebottles, we should get the cached version
+        fetchUnCachedViableBottlesExpectation = self.expectation(description: "fetch cached ViableBottles")
+        fetchUnCachedViableBottlesExpectation.isInverted = true
 
         self.fakeCuttlefishServer.fetchViableBottlesListener = { request in
             self.fakeCuttlefishServer.fetchViableBottlesListener = nil
@@ -1352,11 +1332,11 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
             FetchAllViableBottles.fulfill()
         }
         self.wait(for: [FetchAllViableBottles], timeout: 10)
-        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 10)
+        self.wait(for: [fetchUnCachedViableBottlesExpectation], timeout: 1)
     }
 
     func testRecoverTLKSharesSendByPeers() throws {
-        // First, set up the world: two peers, one of which has sent TLKs tto itself and the other
+        // First, set up the world: two peers, one of which has sent TLKs to itself and the other
         let noSelfSharesContext = self.makeInitiatorContext(contextID: "noShares", authKitAdapter: self.mockAuthKit2)
         let allSharesContext = self.makeInitiatorContext(contextID: "allShares", authKitAdapter: self.mockAuthKit3)
 
@@ -1368,7 +1348,7 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         self.assertEnters(context: noSelfSharesContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: noSelfSharesPeerID, opinion: .trusts, target: allSharesPeerID)),
-                       "noShares should trust allShares")
+                      "noShares should trust allShares")
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: noSelfSharesPeerID, opinion: .trusts, target: noSelfSharesPeerID)),
                       "No shares should trust itself")
 
@@ -1376,17 +1356,123 @@ class OctagonEscrowRecoveryTests: OctagonTestsBase {
         try self.putSelfTLKSharesInCloudKit(context: allSharesContext)
         try self.putAllTLKSharesInCloudKit(to: noSelfSharesContext, from: allSharesContext)
 
-        try self.ckksZones.forEach { zone in
-            XCTAssertFalse(try self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: noSelfSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should not have self shares for noSelfShares")
-            XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: allSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should have a share for noSelfShares from allShares")
+        self.ckksZones.forEach { zone in
+            XCTAssertFalse(self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: noSelfSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should not have self shares for noSelfShares")
+            XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: allSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should have a share for noSelfShares from allShares")
         }
 
         // Now, recover from noSelfShares
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
         self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: noSelfSharesContext)
         // And CKKS should enter ready!
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+    }
+
+    func testRecoverTLKSharesSentByPeersAfterCKKSFetchTimeout() throws {
+        // First, set up the world: two peers, one of which has sent TLKs to itself and the other
+        let noSelfSharesContext = self.makeInitiatorContext(contextID: "noShares", authKitAdapter: self.mockAuthKit2)
+        let allSharesContext = self.makeInitiatorContext(contextID: "allShares", authKitAdapter: self.mockAuthKit3)
+
+        self.startCKAccountStatusMock()
+        let noSelfSharesPeerID = self.assertResetAndBecomeTrusted(context: noSelfSharesContext)
+        let allSharesPeerID = self.assertJoinViaEscrowRecovery(joiningContext: allSharesContext, sponsor: noSelfSharesContext)
+
+        self.sendContainerChangeWaitForFetch(context: noSelfSharesContext)
+        self.assertEnters(context: noSelfSharesContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: noSelfSharesPeerID, opinion: .trusts, target: allSharesPeerID)),
+                      "noShares should trust allShares")
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: noSelfSharesPeerID, opinion: .trusts, target: noSelfSharesPeerID)),
+                      "No shares should trust itself")
+
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: allSharesContext)
+        try self.putAllTLKSharesInCloudKit(to: noSelfSharesContext, from: allSharesContext)
+
+        self.ckksZones.forEach { zone in
+            XCTAssertFalse(self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: noSelfSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should not have self shares for noSelfShares")
+            XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: noSelfSharesPeerID, senderPeerID: allSharesPeerID, zoneID: zone as! CKRecordZone.ID), "Should have a share for noSelfShares from allShares")
+        }
+
+        // Simulate CKKS fetches taking forever. In practice, this is caused by many round-trip fetches to CK happening over minutes.
+        self.holdCloudKitFetches()
+
+        self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: noSelfSharesContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateFetch, within: 10 * NSEC_PER_SEC)
+
+        // now, let CKKS fetch and become ready
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.releaseCloudKitFetchHold()
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+    }
+
+    func testJoinWithBottleCreatedBeforeSignin() throws {
+        // A remote device creates the keys before CKKS starts up at all
+        self.putFakeKeyHierarchiesInCloudKit()
+
+        self.startCKAccountStatusMock()
+
+        let remote = self.makeInitiatorContext(contextID: "remote")
+        let remotePeerID = self.assertResetAndBecomeTrusted(context: remote)
+
+        // Note that depending on when CKKS starts up, it may or may not have received this in its initial fetch. But, Octagon should force a fetch during signin anyway!
+        try self.putSelfTLKSharesInCloudKit(context: remote)
+
+        let entropy = try self.loadSecret(label: remotePeerID)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: remote)
+
+        self.verifyDatabaseMocks()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+    }
+
+    func testJoinWithBottleCreatedAfterInitialFetch() throws {
+        // Our local machine signs into CloudKit, and becomes untrusted
+
+        self.startCKAccountStatusMock()
+
+        XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKCreation, within: 10 * NSEC_PER_SEC)
+
+        // Now, another device comes along and performs an establish
+        let remote = self.makeInitiatorContext(contextID: "remote")
+        let remotePeerID = self.assertResetAndBecomeTrusted(context: remote)
+
+        let entropy = try self.loadSecret(label: remotePeerID)
+        XCTAssertNotNil(entropy, "entropy should not be nil")
+
+        // Fake that this peer also created some TLKShares for itself
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: remote)
+
+        let bottle = self.fakeCuttlefishServer.state.bottles[0]
+
+        // And now our local machine is told to restore from the newly-joined peer
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        self.otcliqueContext.sbd = OTMockSecureBackup(bottleID: bottle.bottleID, entropy: entropy)
+
+        let newClique: OTClique
+        do {
+            newClique = try OTClique.performEscrowRecovery(withContextData: self.otcliqueContext, escrowArguments: [:])
+            XCTAssertNotNil(newClique, "newClique should not be nil")
+        } catch {
+            XCTFail("Shouldn't have errored recovering: \(error)")
+            throw error
+        }
+
+        self.verifyDatabaseMocks()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
     }
 }
 
diff --git a/keychain/ot/tests/octagon/OctagonTests+EscrowTestVectors.swift b/keychain/ot/tests/octagon/OctagonTests+EscrowTestVectors.swift
new file mode 100644 (file)
index 0000000..ee1b70a
--- /dev/null
@@ -0,0 +1,1872 @@
+#if OCTAGON
+
+    let accountInfoWithInfoSample = """
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>SecureBackupAccountIsHighSecurity</key>
+    <false/>
+    <key>SecureBackupAlliCDPRecords</key>
+    <array>
+        <dict>
+            <key>SecureBackupEscrowDate</key>
+            <date>2020-01-31T03:07:40Z</date>
+            <key>SecureBackupRemainingAttempts</key>
+            <integer>10</integer>
+            <key>encodedMetadata</key>
+            <string>YnBsaXN0MDDZAQIDBAUGBwgJCgsMDQ4PECYgVnNlcmlhbF8QEkJhY2t1cEtleWJhZ0RpZ2VzdFVidWlsZFhwZWVySW5mb18QIGNvbS5hcHBsZS5zZWN1cmViYWNrdXAudGltZXN0YW1wWGJvdHRsZUlEXkNsaWVudE1ldGFkYXRhXGVzY3Jvd2VkU1BLSV8QHVNlY3VyZUJhY2t1cFVzZXNNdWx0aXBsZWlDU0NzXEMzOVYyMDlBSjlMNU8QFMhRrcsWNmcw7dI/9uhpDUpq4FZ2VjE4QTIxNE8RBLIwggSuMYIEYTAUDA9Db25mbGljdFZlcnNpb24CAQMwKwwPQXBwbGljYXRpb25EYXRlBBgYFjIwMjAwMTMwMjI0MTI2LjI4MDA1N1owVQwQUHVibGljU2lnbmluZ0tleQRBBOW+fXyAnCMa6by/cKGf1iHkcz9VEsa6rocBXgrLGVSb7Dy4XzT7fa1jf+X2co6ZTrXr3Vt56TBJZx8X6YNMY+swWAwPQXBwbGljYXRpb25Vc2lnBEUwQwIgY4hdZ7zcWd+Ue77JKF2OK99No8MUe9f5Fg2AzLviJKcCH04d5DOYNyFk6LTzWVuHD/2uMR7zASajNdfXbpFQ578wcAwNRGV2aWNlR2VzdGFsdDFfMBMMCU1vZGVsTmFtZQwGaVBob25lMBMMCU9TVmVyc2lvbgwGMThBMjE0MBYMDENvbXB1dGVyTmFtZQwGaVBob25lMBsMFk1lc3NhZ2VQcm90b2NvbFZlcnNpb24CAQAwfAwXT2N0YWdvblB1YmxpY1NpZ25pbmdLZXkEYQSguiFhjcalFK/bQBPruMsnWzZ0qv7VtPwmhjbdCQJ4mCMY1v6+60RCEsWMs+wQ200Tv40DvCBpzRABcsM70f8tuk1Q/wMXVDQ2kVfgmIVmobzvqNLwcSBHpU44nOEnNRkwfwwaT2N0YWdvblB1YmxpY0VuY3J5cHRpb25LZXkEYQQNGdKw9D+ZMSXl2YwRidBiFyb2GI/MGdDSCFDNvvRq5ig9sJHGMKgbswKltv7gkYzgvvg51slkltO0d5nQm0Juqj3dnIh9QtbPXfUew7LGjBNJIj3IOI8DJdnPqdGee+cwggH4DBBWMkRpY3Rpb25hcnlEYXRhBIIB4jGCAd4wEAwMRXNjcm93UmVjb3JkBQAwHAwMU2VyaWFsTnVtYmVyDAxDMzlWMjA5QUo5TDUwLQwJQmFja3VwS2V5BCBmWfEWzk0k71iVH/hINYf572sP/4l/uVZaMyhNb36frzBgDAxNYWNoaW5lSURLZXkMUHlXbkk4dmROZzZFV2F5ZVcvRlA0Y0RaUnNlM0xNbjhQeGcveC9zUHpaSklTNWNzM1JLbzQvc3RPVzQ2blE5OGlObHBTSHJuUjBrZnNiUjNYMIIBGQwFVmlld3PRggEODAdBcHBsZVRWDAdIb21lS2l0DAdQQ1MtRkRFDAlQQ1MtTm90ZXMMClBDUy1CYWNrdXAMClBDUy1Fc2Nyb3cMClBDUy1QaG90b3MMC0JhY2t1cEJhZ1YwDAtQQ1MtU2hhcmluZwwMTmFub1JlZ2lzdHJ5DAxQQ1MtQ2xvdWRLaXQMDFBDUy1GZWxkc3BhcgwMUENTLU1haWxkcm9wDAxQQ1MtaU1lc3NhZ2UMDVBDUy1NYXN0ZXJLZXkMDldhdGNoTWlncmF0aW9uDA5pQ2xvdWRJZGVudGl0eQwPUENTLWlDbG91ZERyaXZlDBBBY2Nlc3NvcnlQYWlyaW5nDBBDb250aW51aXR5VW5sb2NrBEcwRQIgRLmiTIo/hgxmoOMgZEygsTzdJiHOMTI68Y8DQGgXpWICIQCHr913nsr4kFaYZd3i/ioYQum8B5KOpxFR90u1CPgPEl8QEzIwMjAtMDEtMzEgMDM6MDc6NDBfECRERDVFM0Y5Ri0zNzAyLTQ3ODktOEFDRi0yRDI4QkM4NkE5NEPcERITFBUWFxgZGhscHQ4eHR8gISIjICMlXxAWZGV2aWNlX2VuY2xvc3VyZV9jb2xvcl8QHVNlY3VyZUJhY2t1cE1ldGFkYXRhVGltZXN0YW1wXxAPZGV2aWNlX3BsYXRmb3JtXGRldmljZV9jb2xvcl8QI1NlY3VyZUJhY2t1cE51bWVyaWNQYXNzcGhyYXNlTGVuZ3RoXxAhU2VjdXJlQmFja3VwVXNlc0NvbXBsZXhQYXNzcGhyYXNlWmRldmljZV9taWRfEBRkZXZpY2VfbW9kZWxfdmVyc2lvbltkZXZpY2VfbmFtZV8QIVNlY3VyZUJhY2t1cFVzZXNOdW1lcmljUGFzc3BocmFzZV8QEmRldmljZV9tb2RlbF9jbGFzc1xkZXZpY2VfbW9kZWxRMRQAAAAAAAAAAAAAAAAAAAABEAYJXxBQeVduSTh2ZE5nNkVXYXllVy9GUDRjRFpSc2UzTE1uOFB4Zy94L3NQelpKSVM1Y3MzUktvNC9zdE9XNDZuUTk4aU5scFNIcm5SMGtmc2JSM1haaVBob25lMTAsNVZpUGhvbmUJXWlQaG9uZSA4IFBsdXNPEHgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATIde8QFJDJYQJa6NrxP5WDLEhPNga9732ZGyoVoKi0RnxT6aIlb/LBrRvnrdZFyGUMlSYGSY3GIgrLz3YJ0A0W4BN6YKMtsgGCDONSD5/KHRzTEAE5e3Yp26nshhMavOcJAAgAGwAiADcAPQBGAGkAcgCBAI4ArgC7ANIA2QWPBaUFzAXlBf4GHgYwBj0GYwaHBpIGqQa1BtkG7gb7Bv0HDgcQBxEHZAdvB3YHdweFCAAAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAAIAQ==</string>
+            <key>label</key>
+            <string>com.apple.icdp.record</string>
+            <key>metadata</key>
+            <dict>
+                <key>BackupKeybagDigest</key>
+                <data>
+                yFGtyxY2ZzDt0j/26GkNSmrgVnY=
+                </data>
+                <key>ClientMetadata</key>
+                <dict>
+                    <key>SecureBackupMetadataTimestamp</key>
+                    <string>2020-01-31 03:07:40</string>
+                    <key>SecureBackupNumericPassphraseLength</key>
+                    <integer>6</integer>
+                    <key>SecureBackupUsesComplexPassphrase</key>
+                    <true/>
+                    <key>SecureBackupUsesNumericPassphrase</key>
+                    <true/>
+                    <key>device_color</key>
+                    <string>1</string>
+                    <key>device_enclosure_color</key>
+                    <string>1</string>
+                    <key>device_mid</key>
+                    <string>yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X</string>
+                    <key>device_model</key>
+                    <string>iPhone 8 Plus</string>
+                    <key>device_model_class</key>
+                    <string>iPhone</string>
+                    <key>device_model_version</key>
+                    <string>iPhone10,5</string>
+                    <key>device_name</key>
+                    <string>iPhone</string>
+                    <key>device_platform</key>
+                    <integer>1</integer>
+                </dict>
+                <key>SecureBackupUsesMultipleiCSCs</key>
+                <true/>
+                <key>bottleID</key>
+                <string>DD5E3F9F-3702-4789-8ACF-2D28BC86A94C</string>
+                <key>build</key>
+                <string>18A214</string>
+                <key>com.apple.securebackup.timestamp</key>
+                <string>2020-01-31 03:07:40</string>
+                <key>escrowedSPKI</key>
+                <data>
+                MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyHXvEBSQyWEC
+                Wuja8T+VgyxITzYGve99mRsqFaCotEZ8U+miJW/ywa0b
+                563WRchlDJUmBkmNxiIKy892CdANFuATemCjLbIBggzj
+                Ug+fyh0c0xABOXt2Kdup7IYTGrzn
+                </data>
+                <key>peerInfo</key>
+                <data>
+                MIIErjGCBGEwFAwPQ29uZmxpY3RWZXJzaW9uAgEDMCsM
+                D0FwcGxpY2F0aW9uRGF0ZQQYGBYyMDIwMDEzMDIyNDEy
+                Ni4yODAwNTdaMFUMEFB1YmxpY1NpZ25pbmdLZXkEQQTl
+                vn18gJwjGum8v3Chn9Yh5HM/VRLGuq6HAV4KyxlUm+w8
+                uF80+32tY3/l9nKOmU61691beekwSWcfF+mDTGPrMFgM
+                D0FwcGxpY2F0aW9uVXNpZwRFMEMCIGOIXWe83FnflHu+
+                yShdjivfTaPDFHvX+RYNgMy74iSnAh9OHeQzmDchZOi0
+                81lbhw/9rjEe8wEmozXX126RUOe/MHAMDURldmljZUdl
+                c3RhbHQxXzATDAlNb2RlbE5hbWUMBmlQaG9uZTATDAlP
+                U1ZlcnNpb24MBjE4QTIxNDAWDAxDb21wdXRlck5hbWUM
+                BmlQaG9uZTAbDBZNZXNzYWdlUHJvdG9jb2xWZXJzaW9u
+                AgEAMHwMF09jdGFnb25QdWJsaWNTaWduaW5nS2V5BGEE
+                oLohYY3GpRSv20AT67jLJ1s2dKr+1bT8JoY23QkCeJgj
+                GNb+vutEQhLFjLPsENtNE7+NA7wgac0QAXLDO9H/LbpN
+                UP8DF1Q0NpFX4JiFZqG876jS8HEgR6VOOJzhJzUZMH8M
+                Gk9jdGFnb25QdWJsaWNFbmNyeXB0aW9uS2V5BGEEDRnS
+                sPQ/mTEl5dmMEYnQYhcm9hiPzBnQ0ghQzb70auYoPbCR
+                xjCoG7MCpbb+4JGM4L74OdbJZJbTtHeZ0JtCbqo93ZyI
+                fULWz131HsOyxowTSSI9yDiPAyXZz6nRnnvnMIIB+AwQ
+                VjJEaWN0aW9uYXJ5RGF0YQSCAeIxggHeMBAMDEVzY3Jv
+                d1JlY29yZAUAMBwMDFNlcmlhbE51bWJlcgwMQzM5VjIw
+                OUFKOUw1MC0MCUJhY2t1cEtleQQgZlnxFs5NJO9YlR/4
+                SDWH+e9rD/+Jf7lWWjMoTW9+n68wYAwMTWFjaGluZUlE
+                S2V5DFB5V25JOHZkTmc2RVdheWVXL0ZQNGNEWlJzZTNM
+                TW44UHhnL3gvc1B6WkpJUzVjczNSS280L3N0T1c0Nm5R
+                OThpTmxwU0hyblIwa2ZzYlIzWDCCARkMBVZpZXdz0YIB
+                DgwHQXBwbGVUVgwHSG9tZUtpdAwHUENTLUZERQwJUENT
+                LU5vdGVzDApQQ1MtQmFja3VwDApQQ1MtRXNjcm93DApQ
+                Q1MtUGhvdG9zDAtCYWNrdXBCYWdWMAwLUENTLVNoYXJp
+                bmcMDE5hbm9SZWdpc3RyeQwMUENTLUNsb3VkS2l0DAxQ
+                Q1MtRmVsZHNwYXIMDFBDUy1NYWlsZHJvcAwMUENTLWlN
+                ZXNzYWdlDA1QQ1MtTWFzdGVyS2V5DA5XYXRjaE1pZ3Jh
+                dGlvbgwOaUNsb3VkSWRlbnRpdHkMD1BDUy1pQ2xvdWRE
+                cml2ZQwQQWNjZXNzb3J5UGFpcmluZwwQQ29udGludWl0
+                eVVubG9jawRHMEUCIES5okyKP4YMZqDjIGRMoLE83SYh
+                zjEyOvGPA0BoF6ViAiEAh6/dd57K+JBWmGXd4v4qGELp
+                vAeSjqcRUfdLtQj4DxI=
+                </data>
+                <key>serial</key>
+                <string>C39V209AJ9L5</string>
+            </dict>
+            <key>osVersion</key>
+            <string>18A214</string>
+            <key>peerInfoSerialNumber</key>
+            <string>C39V209AJ9L5</string>
+            <key>recordID</key>
+            <string>sNs6voV0N35D/T91SuGmJnGO29</string>
+            <key>recordStatus</key>
+            <string>valid</string>
+            <key>silentAttemptAllowed</key>
+            <true/>
+        </dict>
+    </array>
+    <key>SecureBackupContainsiCloudIdentity</key>
+    <true/>
+    <key>SecureBackupEnabled</key>
+    <true/>
+    <key>SecureBackupEscrowTrustStatus</key>
+    <integer>0</integer>
+    <key>SecureBackupRecoveryRequiresVerificationToken</key>
+    <false/>
+    <key>SecureBackupStingrayMetadata</key>
+    <dict>
+        <key>BackupKeybagDigest</key>
+        <data>
+        LTrJHVHFZ5vQO59wUih1MEgg1qI=
+        </data>
+        <key>ClientMetadata</key>
+        <dict>
+            <key>SecureBackupClientVersion</key>
+            <string>iPhone OS;18A214</string>
+            <key>SecureBackupKeyRegistry</key>
+            <dict>
+                <key>AccessibilityVOPronunciation2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH5MIH2AgE0AgEBBCDeXT460rcv
+                        jIDp8aJE+uDw1JKyosrd5OaCN/Ke
+                        QJy+kqBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZTBjBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRIMEYCIQDOAegi
+                        450wm5Yk2Qtu7sSf4/jGWzCWU0a4
+                        FPRQSCgCUwIhANpyPSOc/yiCIIfd
+                        YULrKwcZ0dm710etKYFNitrv8VRx
+                        </data>
+                    </array>
+                </dict>
+                <key>AccessibilityVOPronunciation3</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGSMIGPAgE1AgEBBCAmObm/AMsh
+                        CPishw7Zj5VqF7pxEz7WPYFQoTdN
+                        WC6PkqFlMGMEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEgwRgIhAKUc
+                        sWDKPbwQt2TLHm2bzDWTVg2rOYrb
+                        o+4sGs0sT5alAiEAv3x1jY/E/xXN
+                        Jbex7oy7x0dLq4FGmNJFHWLQrDQd
+                        GRw=
+                        </data>
+                    </array>
+                </dict>
+                <key>AccountData</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEmAgEBBCApjqgrPqZL
+                        BVUo4ShL7VlQX14zLBzgjiiVP6ke
+                        WE57G6FkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgaaOc
+                        o1aiL8bKLKXv4WmWg6kRwTFQjdZM
+                        S+GRIJmxe1oCIQDAdSxG+N8iojUF
+                        dRAMlGqgzMZMVxKZDiviyf7O0YOR
+                        9Q==
+                        </data>
+                    </array>
+                </dict>
+                <key>Activities</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEOAgEBBCDXTpaU32V/
+                        ljxo71s2tcojaFlrzWTu93dunzeY
+                        6K5TK6FkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhAMxT
+                        7l56PjtGjLM/rK1TLAeJmg5QkgIt
+                        Mo77FSHyMHH/AiBjR6GOatFE+CtQ
+                        uaz7uL+JNEoF0R0+1MykoHRSHqPI
+                        pQ==
+                        </data>
+                    </array>
+                </dict>
+                <key>BTAnnouncement</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgETAgEBBCD0zBfXeZOJ
+                        FS8oXM/hL8rH9HaMyKBeHoOKMdfw
+                        MtAo9qFjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgb/2S
+                        ceDq75L07mzvNa3IgnlUh8hvlAAs
+                        TJPyGtgFJNwCIGNWkSlYNNQEGUQZ
+                        R9GHVgIWMD8ccRKjz17kMtdoJSkI
+                        </data>
+                    </array>
+                </dict>
+                <key>BTPairing</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgESAgEBBCBsRs9WTIBy
+                        92mIMVd6URteSUxiAwRpHEKiT1ky
+                        0MZPOqFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgQDg5
+                        9S8sDoDS4OkFJKCCOIo/0gkLy7ol
+                        bA0ebbRqbOcCIQCONcU18leu/dVG
+                        clWNgN4FPWIHMX3Xs6QD4h+hpJFs
+                        9g==
+                        </data>
+                    </array>
+                </dict>
+                <key>Backup</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEIAgEBBCBezDIWdM56
+                        G/KBXahejdDg+W06PIZORqx808HB
+                        k+J2dqFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhAPF5
+                        A/HcSV4gftgp/JNJt3YncN6UaO7W
+                        fN2uLJpFVbtMAiBdbyb1R/79q4An
+                        Mv+DFCsR274j/nc4TBJl52libm+i
+                        9g==
+                        </data>
+                    </array>
+                </dict>
+                <key>BluetoothCloudPairing2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH5MIH2AgEyAgEBBCClfvDzGvfD
+                        bRAjpecc9+7M+if4wO/tdWQ8vOb1
+                        1L1+pKBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZTBjBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRIMEYCIQD+DnMw
+                        WzcKXCpNN7vODSoCFnuMeHrQV3Hd
+                        E7W6PtJ7WwIhAPNmAa/o0hGaVoZQ
+                        QMDMDy6x4aILZSev+q+H1SzxFU9P
+                        </data>
+                    </array>
+                </dict>
+                <key>BulkMail</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgERAgEBBCCI3XoOP4Ko
+                        su3w8M+ECPTMCnjbM3nLmjK/6WlJ
+                        OUoIgaFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhAIgz
+                        I2bYHyqRHAQpYq3liI6jtn8ZT1ve
+                        /Pz6euQP4NAuAiBB2dIbtiuwSxgV
+                        IkqI699bhauRROHjO9r48FrjrTJl
+                        cA==
+                        </data>
+                    </array>
+                </dict>
+                <key>CloudKit</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGSMIGPAgEEAgEBBCDX4Lqi2liR
+                        QKhXA2QYm0l7edIQPhVLwuk/TWLl
+                        yAT9PaFlMGMEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEgwRgIhAL2u
+                        oy74rk2RNImZA2BlpEt1lbYXDjQD
+                        LVWFl48ZiGflAiEArkFMxuEWlWOH
+                        BtNjjZ44fmxKxWsZi8+NGAHfBCd+
+                        IAU=
+                        </data>
+                    </array>
+                </dict>
+                <key>CloudKitApple</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEXAgEBBCAjsVTQ0pZm
+                        rzPCJAdrUjU8RDTgE57XNKIyvXPY
+                        0HkVhqFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgfrBi
+                        TRmWf4KPF+HN26p3jCAjdIeTIySY
+                        CHoXSYnuDxMCIQDPm8w+aF9D5f8n
+                        ZdPGAJgZGf7IfYYej7uksgAfWpiv
+                        6Q==
+                        </data>
+                    </array>
+                </dict>
+                <key>Continuity</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEVAgEBBCAACkc0AMRb
+                        cY8hsM3mTlgYJovohPSj6QIjo2tB
+                        hGJGoaFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgHKPo
+                        mEfyG4Y5oqrUXC3ILH97fFYNLXT/
+                        vxnypm4m3NACIQDO3uZEcTXfDXT7
+                        7iJlctPPnWtskWaGZdxaKSEdQ1Ga
+                        BQ==
+                        </data>
+                    </array>
+                </dict>
+                <key>CoreSuggestionsPseudoEvents2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgEzAgEBBCCvNPJB1xx7
+                        x/4UOr+5IH/0UzVKX+QpvmqX7ODO
+                        leMkrKBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCIGfKKUNL
+                        wZhpIi9OIrEtkrsB7rzpdPRx/nc+
+                        pd53aepmAiArIUBx0EAPslG1TrYH
+                        SLNo0XCtF4C0ihTQfaJPBAiyqA==
+                        </data>
+                    </array>
+                </dict>
+                <key>Gaming</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEPAgEBBCDJbjy/eQN5
+                        71Uz8wPWukKE0SZY/QvIlA4GfkVy
+                        102fBqFjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgSrBW
+                        Rcxox1/CdtChoDYXmabj8Y4vZYBS
+                        LOgHMdIwKQoCIEkq6KImjlvmlWBk
+                        ewyK0jUwqSyhtuJuJtXux0TUKIpa
+                        </data>
+                    </array>
+                </dict>
+                <key>KeyboardServices</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGSMIGPAgENAgEBBCAZ2Mqr74uD
+                        cAkMedabKkMBE1YVv3r9BY+ZQxiz
+                        tbxuOaFlMGMEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEgwRgIhAJSI
+                        7dsRXpoxNc7bFCtPFSDwUrWlwNbN
+                        oa+j9VpBg/nqAiEAuj1iKHKO5ixZ
+                        92iBCwS6tta9CNYL8DZMMoJYhrkg
+                        LSA=
+                        </data>
+                    </array>
+                </dict>
+                <key>Maildrop</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEHAgEBBCChFkKqgrWz
+                        OfMgBCCorBsVT8hy+zmWs15UbouB
+                        PzHsGKFjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgJUhO
+                        SBsTLydtk7Xu0V2PP7A+Q3VoDsDr
+                        JTGWbd8z01wCIE03dzox48zVifu5
+                        Uo5LPTqD5n1HxwNX21flE1bs+W8Y
+                        </data>
+                    </array>
+                </dict>
+                <key>MapsSync</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEoAgEBBCADagtpAora
+                        2dL8YgDGudGGs9SNDfTdlEkAmFcE
+                        DYVR76FjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgYIZn
+                        OdcURVO0mg3mLmB3McpFItiTlpsv
+                        0fhSNluJZHYCIEX2PE8he+N4PSLE
+                        q4HDjL2NVwGPX7mfXhQR/mrdrD+l
+                        </data>
+                    </array>
+                </dict>
+                <key>MasterKey</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYHDMIHAAgEBAgEBBCDBd3m4WFN5
+                        LsrHxCmPrmepRrZHDyx66Xo8SFTT
+                        8u9bpqAwMC4wLAIBAQQnMCWgEAwO
+                        TWFjIE9TIFg7MTdENDehERgPMjAx
+                        ODA5MjgxOTQ1MjVaoWQwYgQUAaKG
+                        m18QogpAmwTW7wAhpcqfemgCAQEE
+                        RzBFAiB9fOTaJMlRDK+FkotvzkJu
+                        jB1quh9OBx3CqmLNpiry1wIhAOJ4
+                        wV3ckIwdzk/YNkGZLoSP9GhxsoY3
+                        0yQKPqkZzQEQ
+                        </data>
+                    </array>
+                </dict>
+                <key>Messages2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgEpAgEBBCC/q5CztxOc
+                        zrhN7w5PxTq2sWqTTdIRGht/2++h
+                        NuGp36BlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCIECcCDJY
+                        COrM8qBndA7BeEQh8i70wcFIk34v
+                        0hyC1VEcAiAdpGuOYOq8iCydXCrZ
+                        kUOOCLK97fcO89AxaaDQ49r2KA==
+                        </data>
+                    </array>
+                </dict>
+                <key>News</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGSMIGPAgELAgEBBCA3ZmHh5Ky4
+                        vX3DShRnlUuRPEIL1k/g4tvJJbkF
+                        5IfVWaFlMGMEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEgwRgIhAMeT
+                        2qHhhVTbb/0mF5IMLllOCL4wljRT
+                        TVKzc2tDhdVKAiEAgJVLdcM90d+3
+                        j16ZxlF195knpfHs/9dor1wEIixd
+                        EjY=
+                        </data>
+                    </array>
+                </dict>
+                <key>Notes</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEJAgEBBCCKIp/yJqTm
+                        4Iuf/SWj8j1YQa6azRmpCY/bKq/g
+                        iO6aZqFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhAOF5
+                        JxJkSDXw6hNSF9eJkwt5cKRsMMV3
+                        JuDJK/fBGW1lAiABjZZ1U+XzytGp
+                        5i1A6YgE7VVpR9btI6/QQi2iZbFA
+                        Ag==
+                        </data>
+                    </array>
+                </dict>
+                <key>Photos</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEDAgEBBCCcav3S7T1z
+                        VLM9B88tyXLT6Y5GjRD2jCzDdlKs
+                        YdfhsaFjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgPwDW
+                        JNcSN2+zAN47Hg0UcbnzPRbHJBR3
+                        JrDpBOEn7pYCICtNOoLuVEwfqX7j
+                        A2fX7soQVUfT4j/y34C5CPrIbKxL
+                        </data>
+                    </array>
+                </dict>
+                <key>Rawhide</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH4MIH1AgE2AgEBBCAO/9RLJMcH
+                        o3qhFeFb3qanoK8t49rSDrm9ilPv
+                        AeiKJ6BlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZDBiBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRHMEUCIEqa4Rq2
+                        iCw3ULDe3577bLpHuUyRvUDtEKE0
+                        rS7H4IIGAiEA4yG/enWyQuz+TacB
+                        Vbe3U0cZ8mNarFnCWvjagNZ/BU4=
+                        </data>
+                    </array>
+                </dict>
+                <key>Rawhide3</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH4MIH1AgE4AgEBBCDfi1Ny5x/R
+                        aYdLHWW+xFbNw90R5XCc5isHN6ud
+                        qaGyKqBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZDBiBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRHMEUCIQClF2jC
+                        dx76r4x23i8sBLm6syiQYYhvPmC2
+                        bEvnxPkxagIgUg/wLELGQMoReD12
+                        SiiQglIgKNtzSuCgRfdUjAYB7fY=
+                        </data>
+                    </array>
+                </dict>
+                <key>Safari</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEWAgEBBCBqKP7jb+TP
+                        nhhTpvziH9LG4aDa6i1IDLJmtFBl
+                        7u7AXKFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgYT1t
+                        a5nB5G1GRccSzXyo84mvxb3xTeqS
+                        V0HNw3zP9uUCIQDnoAU+3LtXDkVK
+                        4n51tfLXr3XZIVEwPGImBB/p2qGx
+                        QQ==
+                        </data>
+                    </array>
+                </dict>
+                <key>Sharing</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEMAgEBBCCeimmOmppn
+                        EufS9uArUm8PTZ8AQfV1cAszCMD8
+                        uJoN9qFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgIyyv
+                        XdIJY2RRQcBHo7Uf8qzZwq3GYHqK
+                        yCbh3voiR2gCIQD/cgaeToE5Z7be
+                        wD6evPVSPSXwBc7OH0FJFy+1iqCc
+                        Og==
+                        </data>
+                    </array>
+                </dict>
+                <key>TTYCallHistory</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgEUAgEBBCCNrMVagA0+
+                        ttQkY4NGtYqj49b4PHHV7YFaAHyV
+                        d9vodqFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIgAUD9
+                        nE+lBkcEnXyL0pcE/LE4diyBd/Ub
+                        osjHyB5j22wCIQCUcJfgxHVChg8A
+                        e6FjMuYjf7cVoyNf0YmuUEWkmwvo
+                        Ig==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.health.sync2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgEsAgEBBCBC9NWuZFgs
+                        rkDeXFDLnakWgoI4L/cXyz+m43lC
+                        2JWUJKBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCIGo37UsM
+                        Xb7GaLeBwYfg302TWGv0xbM6XDuo
+                        xi/RX09VAiBOSD4os5NX+GTYqLdR
+                        erCTQ5dEVScIWaR6n45SATDuRg==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.icloud-appleid.privacy</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgE/AgEBBCDyKeoxY5kg
+                        0jXZokvw9XIZk/dXsLybRdeGyOhC
+                        RXTz/6FkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhANGl
+                        TEY7KpACQHm7qcSuuS/j63P5/AHu
+                        M/CFNtpxHPs2AiBB4iFuMmexGzcA
+                        dxjD8AweXzf3BuT2eAMPveTum/As
+                        YQ==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.knowledgestore2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgEvAgEBBCBbIpT6tptz
+                        5puJ0XdYbcQiOBT9JDtH4o1W9en3
+                        P4hJPqBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCIBEFJhmK
+                        SW5huLbY39W2AuOZ7sMzOwTka/Bl
+                        aOYDw/qNAiBNsupg44L53rbTy0+J
+                        ItQBOKQPFMyS4ggM+38xEh1o/w==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.news.private.secure2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgExAgEBBCBjOqSZoGDw
+                        ScKt5ncrZEkl/5e43V/wCItiOI3f
+                        fCu3XaBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCIBbcBuay
+                        kWaCE1IFXL/4nmckm8tSDLnSLUje
+                        T2YtgVB6AiA7S+NREY9sOh3WrB5p
+                        VpmZfhd3Blv6JbeHkBsMjWDCUg==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.routined2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH4MIH1AgErAgEBBCCO6YXL9f4P
+                        kkoFCTOYTejP548/+n2QYLyev/v9
+                        60tVSKBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZDBiBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRHMEUCIG1WEsAe
+                        upMhR1v7+1RxWB5AosnbhgnLueM0
+                        FT4xIYFgAiEAokT0B7qa+pQMJgVi
+                        Jy48mJOwTbFTVcN9Csz1cbxD6+w=
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.siri.knowledge2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH5MIH2AgEuAgEBBCCM34oVJt4n
+                        8zzP2NzHDaKADwE6BqMEvWbXPXnG
+                        LiJfzaBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZTBjBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRIMEYCIQD+HNJz
+                        cwUhn+8nGbYmaXsYgjUN5IGBuhwG
+                        kkws3W66pAIhAIHSbuQ7n6p/Rkjs
+                        KOeVOq25ZcL+3hibiJJZIvNEqtSU
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.siri.profile2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH3MIH0AgEtAgEBBCCOKC4GWP07
+                        MXtnJuAXpyVkRwrXBhFMf1fEv1EN
+                        L2HFGKBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhYzBhBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRGMEQCID6kHeWN
+                        nKA2CRiHtOssTg7KKMONOf5K8wnO
+                        spBk+d9vAiBKRpXkBbHzObbc9Sz6
+                        3WEfAi+2Z6iOZ+vVDVirAbFr/A==
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.textinput.KeyboardServices.Secure2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH4MIH1AgEqAgEBBCDtVL0VIeP3
+                        V7gD9jkiaWu4xwxe215t3PammS0L
+                        No2WIaBlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZDBiBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRHMEUCIQCLfuV/
+                        Hulb54Wrc8pNt1ibM8IFuN6XvkDj
+                        ijiryyxGVgIgHfaVTZE/F2b02h4X
+                        aAPBi1YIDvMAoycxd9ylXQI1cr0=
+                        </data>
+                    </array>
+                </dict>
+                <key>com.apple.wallet.paymentservices2</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYH4MIH1AgEwAgEBBCDMr1rH/wSx
+                        KnXhhMuq2kmQAsbuu8aQ7CUjAaP7
+                        ltmt56BlMGMwCgIBAwQFMAMCAQAw
+                        JwIBBgQiBCAownsDFvISVYfCbbD/
+                        50T51ZSZzt04daIl5fdJpmI89jAs
+                        AgEBBCcwJaAQDA5NYWMgT1MgWDsx
+                        N0Q0N6ERGA8yMDE4MDkyODE5NDUz
+                        MFqhZDBiBBQBooabXxCiCkCbBNbv
+                        ACGlyp96aAIBAQRHMEUCIQC2O2y2
+                        BdX70rfntL/TRaSfQ2hi2HDlJRcD
+                        Y4Ac7dTNDAIgMCCNLTjH3w3yanom
+                        cdUpUYpUXk0xg7rmWv776V2/ph0=
+                        </data>
+                    </array>
+                </dict>
+                <key>iAD</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEQAgEBBCDcezl6FqtG
+                        yHkX174CEG8VSAOi4P3lIlFNO4qJ
+                        fVX0saFjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgQvuS
+                        zR9rw1O2ySTcaQADxxJd1GuffZ2c
+                        xK1kGvS45cUCICC++3nOux4yl6TG
+                        ku4P9QDla3NQp/7hH+lKmOIpvcOk
+                        </data>
+                    </array>
+                </dict>
+                <key>iCloudDrive</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGRMIGOAgECAgEBBCAXOlNsMQNV
+                        JQUY+dqcGt39XUTbDVT2ksgEBMVv
+                        yOjkPaFkMGIEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEcwRQIhAIL+
+                        1l8MsRW3rN9wMeM7tSinakp/c2/D
+                        p2kO8Z8OZBxSAiAL15IC/CrJgkQL
+                        yS4rarGeTmMFKGz34i/jQ1AQHzQy
+                        0Q==
+                        </data>
+                    </array>
+                </dict>
+                <key>iMessage</key>
+                <dict>
+                    <key>PublicIdentities</key>
+                    <array>
+                        <data>
+                        YYGQMIGNAgEKAgEBBCDK+TvjMZ0j
+                        zhAklsGuo1nbUpfAsRutInhCa0uX
+                        k/HLA6FjMGEEFAGihptfEKIKQJsE
+                        1u8AIaXKn3poAgEBBEYwRAIgaDaM
+                        i4SMzCnvHsQyB4k94BaG6y34FbB3
+                        LDlMT2pa7EYCIHJGgdwlbbRfFyYz
+                        j08ohfXpCRbck5akTbDkOxRYIdyB
+                        </data>
+                    </array>
+                </dict>
+            </dict>
+            <key>SecureBackupStableMetadata</key>
+            <dict>
+                <key>EscrowKey</key>
+                <string>wVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3k=</string>
+                <key>LooseLeaves</key>
+                <dict>
+                    <key>AccessibilityVOPronunciation3</key>
+                    <array>
+                        <data>
+                        ZIIBnTCCAZkEUwEA7coGYUYS65YH
+                        nBubKFI66JIshlD/zcZadtS7UPht
+                        /gQw4Na60gEDpn3LLWAPmNzSU5aF
+                        q2i5FdGApmZz2ZjxJhKs34OzsSz2
+                        kh2Dpg1xkYYABIH6KTIPWejPTEmB
+                        IMu/M8MHedxNSBN92aCUaaFKlFpI
+                        Efr4ERxhq2+7aqBDUod+agFjj6Bz
+                        Ei4NBHu/j4LZsb4fcOMwq2G594K7
+                        cevsVg5hsWb800lTOnIWzgnPfk//
+                        T7CYB3S5UnPQnLtORz7gQZzWlqlo
+                        HJSGltcXdt9nF5hOsawKZttCDaL6
+                        0j00MtfeD0WO+aLl2BmD8syaCwNF
+                        RCG8zplq3ot9Anh6xzoeTGzljjuY
+                        mPQPAKVFkUNyBI81ZK04m9wxPUh1
+                        64CPXdv2hsm+zGqNrTX1sny7hlcA
+                        VbMXspR54l7EpBlHw0hO9D+2wtrf
+                        I4cwtfSpKFG9oAQgJjm5vwDLIQj4
+                        rIcO2Y+Vahe6cRM+1j2BUKE3TVgu
+                        j5ICAQIEIMFSm9doDsBBLY2n03Nk
+                        YLw/jjbTcxbWf7/ZhJH9Q3d5
+                        </data>
+                    </array>
+                    <key>AccountData</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAIkREyheGTEpx
+                        90YhB0zt3gW7v4Jjgs2YF9K8fDOd
+                        GFYwGDCkB4bB6j9FZr1ZEg57UMjq
+                        djwsUAthex7ePflo01Wn4PzatH1r
+                        LOwjHLfTO+12BIH5P5Bm3AyaWPJq
+                        W138OzxseZfkxmZayjGK2tHsbrRi
+                        gth3AkOUvysatYcgmAzVFfBUITc2
+                        F2eUOMlX05Lq98JWGJUN1wx6LKYK
+                        CAmISy7GfaDDSWd35YlSRXrYHl2m
+                        kDjGpUkUT4RB2REVsBH6OuOXM1NG
+                        3sFrV3Mx7LZt7qWt8j8fbpwT9S36
+                        l77TyJIMPu/xkywGxLSUP5UDjiby
+                        e/Z8T1SEpqyikOx+r7/YY3iZczIi
+                        KcDVJCkzxQbEGEka4a9r8h35SgM5
+                        uy8bzjO/heXIh9OhxcKv2bYqQbln
+                        bMjtL0vLqp2ihT9blHf7JZRrW/86
+                        Yo0hO1V3e310BCApjqgrPqZLBVUo
+                        4ShL7VlQX14zLBzgjiiVP6keWE57
+                        GwIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Activities</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAit6fWo+OJu+u
+                        0AmgeLcyLkhTi2UnNSi+KCrMPwq7
+                        cLkwDDfCp19sx91iRV66MjOXnyac
+                        2K3Z4Ne0Yu1pTA80NvfKboJngDgI
+                        sGXGdipH0RiWBIH5IVxHisC8FLLk
+                        JrToYv9zZNkscu5xh1v9/RC43IEQ
+                        +1VIYwvzCkUGCfRNg/rf7mHIT4o0
+                        nQppvEb75QbPXoHzB2TembqJYBID
+                        ltYQBrVSwII0rwDipCH+LrPNJkRc
+                        QoyRuVsH2baT2e6Jz3L630zc4vzm
+                        Dxt2tPEWfluCjjQPkgX96A2mF0lF
+                        F8lHIQyVTQOxs7KwgrreCk92/XVP
+                        qS/31SlphaMV87/ZCnKtMpVb0F3u
+                        GFM21274mvl+83giEOUgMqzDhMqO
+                        SJ6MXIgW2/lYpBz+UKpLZVHNnYzA
+                        FIO9soDHThSGR/wCjOFVo2PhYruS
+                        9zwtMg+iJuy+BCDXTpaU32V/ljxo
+                        71s2tcojaFlrzWTu93dunzeY6K5T
+                        KwIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>BTAnnouncement</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEAt971wW2seGN1
+                        VyUtU9Uo26f45e+nwJSlPDuZnJ7k
+                        8YwwrOft/abFvpL9EQi55rdaFcWZ
+                        MA9Nm1kqyDno1lScw7YDhPXFOFmu
+                        RLiUcfJcVu+lBIH40fYFa6SwWaS1
+                        A4fpAmULHHJpuG2kya+ESnHHZFw6
+                        G6ok39oj0ji/GRTW5WsWhjMxn7YM
+                        ziN7ZUuImxTbNFQyvTEymOVBaxxR
+                        6MD7Bg+yie/glTHQdFUFlxnOimIz
+                        C6AsPCbWm8Z7BDTEr6i7t4f1tjDu
+                        eAT7Jj7Uxe9W2eQzx/+J9JbjBPSB
+                        4OxHRfqpRc7DeMMGTZy/fAQKND6V
+                        AMYPdhnUARGxAkzkUf8gAmJD3nc/
+                        v9NGnU6TLtxRjEytKSQhUy9A6zyX
+                        YMxK7nyv56dTPMGnxg8uIOdNIixA
+                        DIhy5WeV/vUsn3sabMHP7tyXcnMt
+                        BxyawjgsL14EIPTMF9d5k4kVLyhc
+                        z+Evysf0dozIoF4eg4ox1/Ay0Cj2
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>BTPairing</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAQ3obteunNorD
+                        2SpZOpGB+88OlqQgI4mYVzIeqYzr
+                        MqcwjpgS+EMayACEgCy30mwZkXV+
+                        y1mxtVo8Jz5sAHprj3wiiyHrur2q
+                        uQnLjJJ4s88dBIH58t/+KhpQs7BR
+                        mUgocoztX8bNopGuc08Uq5hHiBeZ
+                        L5Q72jHu8wRIC/SSuz2o+THUyF8J
+                        duh8fnOanFdTTVvm4sZVONCKCHF1
+                        O2XAy5kOeYRY43/omrS0rFyELiSY
+                        1ABalykBCBQYH/5WCzGAQnh3h6s7
+                        lVuYvTpsFlz+wzWxXnhAH0HVST9A
+                        f8COEpidxATAZ7OTpBAYD9SXvBmT
+                        axSsB6sPdhQ83WLGFz4D+W4raymg
+                        uSRIQXUUjw0PSP2LPIaWagww/4hE
+                        ZGp74PILQOeiOzBjeeNbzTdr5r2n
+                        IFCcQr1jmYh2Eb2fhB+HjU2Wn9EX
+                        5yd6VOzXfqAOBCBsRs9WTIBy92mI
+                        MVd6URteSUxiAwRpHEKiT1ky0MZP
+                        OgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Backup</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEA3A/n4WhznwF/
+                        LvLzAhTFBE7oIxKivBNqU7OSE6FT
+                        GWUw5pLbLd3Uq72xUPHw4nDGp7mY
+                        m/aNK4J9BKbsgmKDLNVwls7anxkS
+                        JkA706XCsbdgBIH5It/fR9OHWKzu
+                        8iHEaf7YYhQSabWoNfJRpZS1EkNV
+                        e9DojJDJfg8ExcQQsPu6JSLFhQ+a
+                        cvPEWsoKzW0PIsVb5oiiqU4WWeAG
+                        US5LbxAENGeAEOJqbna0D7iWXHkm
+                        EGtRKl+raWSZAsXAGpSKGy9efsst
+                        DbNGOcN4ievp8DnSkFwSoQ+EvkUA
+                        Mb1MoiCCCB0NCfn+MK8LIg0g+MhB
+                        Hp3lf8HC8Aie+gcj5hzVesMeG6lj
+                        OOeBVE8BS6fUet5IWoSNhhRyDoyE
+                        0V5kja4Mr8hY5XnB3G0770VoDwYY
+                        mPQj0jgrG+jS4AQsSDW4PknNxLgK
+                        Hk/7StJ7vJx6BCBezDIWdM56G/KB
+                        XahejdDg+W06PIZORqx808HBk+J2
+                        dgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>BulkMail</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEA8MWcOAuFRzvg
+                        Ybrd2u3dBi/D1UFZ9oqNL2EdTjM7
+                        314wOTSbbAqyhIYWd5wkNwbwh4QQ
+                        ZN5ZKEcv+VpIOLTc5gg9dF9GAtq7
+                        iWQnctLlI/RZBIH54/fs/QwzrSJh
+                        en5U1iskhIsWbBzdK+QtdekgVFYI
+                        P34Q28Qang7eN0hZo+ndyiBcqHJ3
+                        kL5mfk6ZIpvcUHFpXgC0wwxTgDDm
+                        T0yHAEOevwgf2Qng2jobFp5PwpHi
+                        wmqCI4RltMVMwnnv4vh8yM8WZihe
+                        sZEXMBiqS3gmWRk43dBTCKAzHhKP
+                        lR82vZHOTiJDbj3Ewpnu2MjfjMFL
+                        C9wi+Dcuk8K2a6YRq4N5voLQ5Aiv
+                        KO/rW/Te7P4wrObgCEtTWZZETQmE
+                        QjMa7uGqA8rD3yoWXX+TcVIj1Bhg
+                        psCJUT6kyYEvv8Y5q9oCYMMLy+6o
+                        2trU56gfq1xMBCCI3XoOP4Kosu3w
+                        8M+ECPTMCnjbM3nLmjK/6WlJOUoI
+                        gQIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>CloudKit</key>
+                    <array>
+                        <data>
+                        ZIIBnTCCAZkEUwEA7mcfkI9joA5Y
+                        RiHMKVPYdCl0EZbdHHSkd+XbtD7M
+                        z1swmsOp0wrFLe6Vs8Fl/eLiARGA
+                        oFbEyqKuOqGBvVJcANDyON1SpccP
+                        YyE+m9Fv1N84BIH68b9LFxZu11g2
+                        wdpwAoLfHGAIpixj/l/ExdN1SejD
+                        h42zj68oMRJipC5Pzuy7Rsfo8hBq
+                        DgSCZQ0ASzcyZvd/r1eUVlkPdtfW
+                        3e1G8CiLvEJjalHXMK/q+ZkT5ix5
+                        RrImOK4L8KpwVcLyYf6RxPhvLtQI
+                        FuyDWZ/zcGeOQfXbEU0N3DEcM86j
+                        T5VpOVvbejiFABDV2auJtxAzcbPo
+                        imkyfQH6B0hb7J4MoUBqojYp3/Wb
+                        Xgd+xsZueOYaioaD5F47gGJJt68v
+                        V79KNCrerlvSaoAAFZMT3aj1EfjW
+                        zc2Q+XU2ugjdA7yNrxDXAtzteqcT
+                        bqVa7k48t+smmgQg1+C6otpYkUCo
+                        VwNkGJtJe3nSED4VS8LpP01i5cgE
+                        /T0CAQIEIMFSm9doDsBBLY2n03Nk
+                        YLw/jjbTcxbWf7/ZhJH9Q3d5
+                        </data>
+                    </array>
+                    <key>CloudKitApple</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEA2gOwrczljkPA
+                        WHgRADJ6o8gdgLyxKKfRWNqWUnri
+                        s14w5TsyO/m09rQMYaqozK92iNdi
+                        KgZVS4ewntjnRL0MINfQuxE83RV7
+                        rGrDO3oEuJ6cBIH5V8A65gqIk5kQ
+                        7ZgU+4YDOpi8zZcfMSPbssw5fPy2
+                        RcH112RboQAPpDRWqfRA+v6ozvIU
+                        BLFt3yHfhZLpd13PbxxjaSKjxd/x
+                        LhdMWk39WAcIlIQFTyurBS3C0Nsf
+                        pH2oVVjoOaLI/iv1cIITjgHgjUcQ
+                        oX161WZTUcp4C7GD6eExWGNfc9lh
+                        7jEXNoutRL7W2eBMIJbca0cNaoen
+                        zh8Ee4t/CNeBuWe2Ex2ka+KZBRGP
+                        Ruw4o5T2W/iCOu3dY+izFhzp1BLZ
+                        0AbBDpmEII7+8evOrXHqYX7rEt9F
+                        te5bDvZoO1hmO6sIuuONuiK9ad43
+                        zWXdZMqNOZk6BCAjsVTQ0pZmrzPC
+                        JAdrUjU8RDTgE57XNKIyvXPY0HkV
+                        hgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Continuity</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAEJ5swAeKdGml
+                        KBxozSTpsTC97zVft9/MWvYmFdVB
+                        askw0WgUkVHiegWuHKE5xphAVwc9
+                        8fEHr8WdxDfrbg0k8X/oUBAhjK09
+                        QFBdKAAT6sAuBIH5MiYviQHOuAnJ
+                        mFIVlH6qMoiv+JHzgkXl4futwcwV
+                        oI/t8Y8VE81qeXgP6N6y9iF/VpRV
+                        GhVqaD7jNqXjVFycgWrwOXHYF5V6
+                        HgxGIGe7/lIIytjAy0Ubrn4IZGn1
+                        hKGmFM39r4hoFFn4UYL11wXTl3xC
+                        BxG+Nt66tnD2tZSMvlVOkBi1Z/uW
+                        xFsm7veDYzCveRI38yOKmdmG4zkn
+                        fw+AQF8tYcWOKYe39TKhwgNEYe5/
+                        WI9/3CxWUqxd9H0g9wb6OOlUjnJE
+                        Jf/3uoYFLUpAlYLyDP8JlDqDad1T
+                        xL9wdUmt+DeiHHTC72wHCt0Q1Tnv
+                        HJhBBhiUR6x7BCAACkc0AMRbcY8h
+                        sM3mTlgYJovohPSj6QIjo2tBhGJG
+                        oQIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Escrow</key>
+                    <array>
+                        <data>
+                        ZIIBnTCCAZkEUwEAq92z+A2mGWee
+                        OAh6/oSmx+1nNN8OVrv0OZFF9ACP
+                        0L0w3Tq7x0BsXOKji8FqrajsM0b/
+                        9vvFNDPKpeD0iM6qgjnOjXhTEVU3
+                        5BNEd9eXuNpWBIH6NWYRYQLnDg/R
+                        X2JWnmomZjRrOIr058bkXVsn7nbE
+                        CP5XP8UiniHnk1DchxDMlkkmckV9
+                        612PnxNyegWg29s0i1hf9s+NLrhk
+                        3KQEQ585xa6Ghc14F2oN8M6T1xMp
+                        K86u3bO7NeSVJXbst2LqeGFYf6no
+                        p176vubd+jrNAvMVemeCADoYLyDY
+                        LgNmAPrVfQC/THUMQVMC954K12m6
+                        0I4xoenEvFOR6Vlg4wyuR9eJCcUh
+                        b4+iqBQO62xtbxakcQETMx4GBL/y
+                        y69NTEfA+hGKD0uTqiU1PTGmOtUr
+                        KTfH6X9y0aju9o0B5jAUMJ6rkOHu
+                        nLQr6jYvW+L59gQgwVKb12gOwEEt
+                        jafTc2RgvD+ONtNzFtZ/v9mEkf1D
+                        d3kCAQIEIMFSm9doDsBBLY2n03Nk
+                        YLw/jjbTcxbWf7/ZhJH9Q3d5
+                        </data>
+                    </array>
+                    <key>FDE</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAMAsrg/pUgwcX
+                        RauUPBcyWRKaaIrhSthNfvQSO2pB
+                        HKkw8daKeW6oP3npBiMnXgGZAohM
+                        k5VD2zlLd/jHgN5vL4WwoR0ohT2c
+                        ZjYHzUG81P1oBIH5TR0h3tRdlap8
+                        wORCCEhoRaZOXozPoQLc6UQb06yb
+                        KSG54WqWIeiYDDYBNSJ3Pqn7pTIx
+                        bhyxg569iDwnBWlHZcOmlbTQPePx
+                        2r+Qysu/a8Pf+S9IYBkz6BCBoS8i
+                        K7d7ZonfO6P6ObuXHQXIUeDqeCqF
+                        CwYIVslDBViyywv8v30zmKB+Gs5C
+                        IlwrkDUeXGjimKsynu5FghhOKNc1
+                        hrmfn+XLV8Ht+eS8SkcjmuZ4NAiy
+                        4YZpyKGVX8VEC7WtwnVQv7Dj7+AB
+                        Q+dZYZZDIMkRYLff8sP4vizqDK8/
+                        wXOKv06sBpSG1avueWr0O5jXxLdH
+                        tqQjjFU/fXPPBCAkfz8NsHhEsMkD
+                        wr+lLP6dfwEGvs83Be0DwG+OwI3G
+                        UgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Gaming</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEAL9qPoxGTOloQ
+                        mg+k5v9L9DK1FVDLI94ISo0SIl2g
+                        IWswe/PThv4UwYAvYy151JYnVXRG
+                        pIglXCh3wMmRn/HeBt0pwoeVc8Qp
+                        tw60Ds997cnEBIH4Pi3mibPRMb11
+                        8nGz+D4A5bzm/9+SZyW8lXsr9vb9
+                        CppQEXP3xp+2IosFV3J8YgZhFkNk
+                        foB9fcjjSuk4NE++NnoGXG3FqT88
+                        UrvDvpykFttHs7odv+n1yMn1HYlO
+                        KD0lCrp0LAzsRrDfm8rQHt8XxACR
+                        mBmUGuR/hreDWw+kLaeWfi7YJ+UO
+                        lCmOJWo02jUyusVoasNyYh09oCJP
+                        8P+jnJKaLbI7uJsty5kLMpVFHqP9
+                        RMYB5GQT0n18q0fUEO6XREgBSn0S
+                        Og412K7XjJaZeqE0DqkF87Hi3JLg
+                        1zRjAGS2B9nAes/fntuQco/eyCPx
+                        LHAsqDaHsecEIMluPL95A3nvVTPz
+                        A9a6QoTRJlj9C8iUDgZ+RXLXTZ8G
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>KeyboardServices</key>
+                    <array>
+                        <data>
+                        ZIIBnTCCAZkEUwEA/tGjVinL3pjD
+                        EQPaRVbA1KOHUUWoLy2O4ImMlSZP
+                        Qxowjy3uVmizCnwAr4HCq8tQezOX
+                        6Rmr7UYEf4CXVQ30BCuKrTC4iIwt
+                        mvqWuk68Fh2MBIH63FQzTbLYTz8H
+                        meAieQeF7vk39HOcW1gJIu4nFk8n
+                        x1sc+sA56IWcFZYDHzJsauykjz4s
+                        ezTE/45Crpl3qiCgnAgdQ29fQnDZ
+                        sQVOGChZI+H83dN0lobteC4Nsxkx
+                        EOWS+csPvEYREAcZWAz8C2cl2MEA
+                        crhKqAQ+0QxiorH5Coif+M9+nnTR
+                        AAPsmw1MOqA7JNecRfwV69W8SjAD
+                        8fJcx46hH9aehHd0eVgxUZz9qoXq
+                        VbjOEFL2Zx1aYvqc2wGyWEUIDmdC
+                        Sof3DYZ/U8ePGQteXjTduaetIfTD
+                        N8+4gE9/APPDiVNzwKaZQYOGshk+
+                        DZw7wedOQwn0wgQgGdjKq++Lg3AJ
+                        DHnWmypDARNWFb96/QWPmUMYs7W8
+                        bjkCAQIEIMFSm9doDsBBLY2n03Nk
+                        YLw/jjbTcxbWf7/ZhJH9Q3d5
+                        </data>
+                    </array>
+                    <key>Maildrop</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEAq3Qy6v5D1m+q
+                        f++g6YHn64jfWkV8Relexixw2tY8
+                        GdgwJ6cmMqCgtvNO8S+o9/s2Q7x1
+                        iY7Z+D2l2YS6bo5QMtr2XxZtL648
+                        vKlQXw9m+TeDBIH41LFxD1yx7/x4
+                        qYqVSUgiWJJQVHgj5ld63Fxrf7SH
+                        8JMqluC/D232rw3aGNrIbJ9De7ZZ
+                        B90/2BQEvt31H574yy6AA69fr6EI
+                        gZQDw8aYXye7H0ZEnUIvb0vJqhxJ
+                        okO8+qLryVYZp2b9VGmAtRCtSJJm
+                        o9SQqBzYVDyeS5Fwe/7qTnYT/6f7
+                        0frJBen0IMB2F6B9Ymh2EfB5mgIt
+                        YvQsi/iedZ0SoShEhELv/dkMFQfE
+                        sBL4fWGgZdXWSIvaQDw/r/t1p5Qx
+                        CgFazEZ3P2Nma3CONYe4DdmdzvrC
+                        9pU/sngdKk8W+yKB8XivorNvSA2v
+                        ItMNxcrBPQ4EIKEWQqqCtbM58yAE
+                        IKisGxVPyHL7OZazXlRui4E/MewY
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>MapsSync</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEApFg3dOexxalj
+                        8nUrzt4S8lvykjPlpatoQaZV5jXH
+                        utow2+O3Yevp/vk2zN3BZA8Z57Rr
+                        irw/eSC66GQAIdaXTkQrQT/4pB6O
+                        iKxPo0t6Zy0tBIH4khoiH57Ia4E8
+                        v4OSvsWDJhdW+VG62anIBrNq/VjN
+                        YQGe0tNceaXA1xDmmCtATLQzjiZT
+                        cHCGXn5whPdXaNBnpWJZr5S2v6zF
+                        Hbja5DQKAoJN9tX6SiHsnkjFKblN
+                        4FzcCXZwtcatnvzn7quAhczRe9MH
+                        aS6Fjx3sll9v/fhoVv59f8+NBoQx
+                        ZKsEJVbJ3JiR2K5Gd5ddwMhckZjL
+                        2ukh2zheY7nH71M/0h+5tlvQD2JG
+                        AfGjjsIco0wMFkZRcB7TcnklYVrk
+                        +pn/Qvz8GAWmrThOJpwoNmYSgaSm
+                        +R2M4cL0KLSvuqyHjDHk0dDjXgoV
+                        U6FcHhuItnoEIANqC2kCitrZ0vxi
+                        AMa50Yaz1I0N9N2USQCYVwQNhVHv
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>MasterKey</key>
+                    <array>
+                        <data>
+                        ZIIB0DCCAcwEUwEAl0pbM+TN/wyy
+                        dy8KAtqB2Ra739lKTulOuUSwbnNh
+                        360w+LwPDymGHkz8b9qb8G8CQysT
+                        yrmi+cXbp9WY8PpWpxSfrzK78mGE
+                        j5aLPVEHXU0sBIIBLK9R/FnK18rb
+                        q6AgmjGZid6JlPzBvvGN6C73embB
+                        eMYoALRyxQ/DZOk44jzcP31LYfSO
+                        Co+Q3MEKiITdA2wp8csupYRh/U1b
+                        iFgsin+KeGi7WchB3GXvsE2Xiyvq
+                        p78e4V20nVihsGjHfAGgJ3qe7JjJ
+                        Bxfs8+SojxfWRGlCrjjnFa+yY0Vz
+                        XgqELEKP+Y2YvpPoSxq5NYWTbIkF
+                        29mlPT8sbI0jW2odY1cNzuPKCQEp
+                        nK9o8adqOSIe6Rq+wtUVRaAuN04N
+                        CQZD8oVfjxTdPGq2EXlbUx+5po4K
+                        /yCJzA4wBONR6nxzc8AsF0rycSop
+                        1ZaYMONrMjQjtR1/JvVZnNnZWBSD
+                        vBz/74gdRPui0jG2ddKrubI1pZ7T
+                        oELHtdw5WdGRb+LVkDncchopcAQg
+                        wXd5uFhTeS7Kx8Qpj65nqUa2Rw8s
+                        eul6PEhU0/LvW6YCAQIEIMFSm9do
+                        DsBBLY2n03NkYLw/jjbTcxbWf7/Z
+                        hJH9Q3d5
+                        </data>
+                    </array>
+                    <key>News</key>
+                    <array>
+                        <data>
+                        ZIIBnTCCAZkEUwEAbLiwWK0ZW+qd
+                        E7VQF/Vgc6Ca06iAa0KjlCHxqzfa
+                        QWAwTUxr9mwi+sFXnZtJZS1lxjmf
+                        7Dkz/lfogz+o2A0eUMtT2veBw676
+                        0wjRg1OUVEATBIH6uUM8GHhyqc1v
+                        eSwAwr1M2jpDpw2T1KGfjKYIlD3l
+                        AKC0SEt21m8KWdZbK9wIpK5XKblp
+                        mqZ74iezeRWyUm4wYE0DaZQd0uNp
+                        De63OU636GybAXMvJ3NbNbBhoXsS
+                        7Vrjp4luJq3/Hc1Z1v8Bs5/VU0ca
+                        KAlH/MxLNJnAFu3wKzOSqpqvM0Al
+                        XsrZd9HaBOKTz6cVpb46eM7GkXNy
+                        YfoFripk2XfYIgB4ZTRMJstAbw9i
+                        AxcSfN6UE0VaVYk+kcfcC41km/kt
+                        5yQXPEteuDhTZF36Ls09fmwRjry2
+                        7O3gzYtC/N2bcXKEvqMQJHw6972O
+                        NBjNkxyvkdyIKgQgN2Zh4eSsuL19
+                        w0oUZ5VLkTxCC9ZP4OLbySW5BeSH
+                        1VkCAQIEIMFSm9doDsBBLY2n03Nk
+                        YLw/jjbTcxbWf7/ZhJH9Q3d5
+                        </data>
+                    </array>
+                    <key>Notes</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEA5QBs7cwCbsgx
+                        b6+/WPrQqmz8PyGvRm1M9by43vPo
+                        XpEwIvaozyKcDGBuIUOKXPoZHm8q
+                        MLwCqjz3la7fD2E8zysNgHx8R94d
+                        Zs6RTFm00Kd8BIH5+z6ZZmeFMqKu
+                        14NIZXFS4lpZ5wVa0dBMzkU34qNb
+                        dfzIGnOrtJdvTdBjlt7RBpwjdnxU
+                        Om9+v/7OqzfPvu7Jfs7knMiDYNdd
+                        4VV1RYSvXngW413oMoWQrgt7Di6D
+                        4yEXwB6iCTjo4eRzhwRKqGVXL+MB
+                        bzxKbQlQ5T5GmQO26dHeOW2bomPa
+                        RP7an00X2C82dZIO4ri0HO++9yhA
+                        Optmyos5C36lj4TASVuyHJddwmoj
+                        RySv1ma4DezRxcCZzY3MF3ZjUIIK
+                        pIX5NzNCkFbCFYLz/YJ8vSmNm2TZ
+                        C4FhwSEPI3M9BwqSdVXzVTO7I0CN
+                        U12UPyTaW6exBCCKIp/yJqTm4Iuf
+                        /SWj8j1YQa6azRmpCY/bKq/giO6a
+                        ZgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Photos</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEA5N7lj1BTLUER
+                        P51xbaN4uvwmaMYtYNZfXtNEqvOX
+                        SL0wsbOiat59vkct3mt211TBke09
+                        P8RBWD5Sqzrdfhutqg88shqDVvNP
+                        iYFzHfAv6syDBIH4o/HHz51zYY9J
+                        hNwCHW8G//opH42HzklRulXLOFy2
+                        3QwDRUfiJIae2P6Y8sTYbHU8NbuK
+                        BSEos5i0siIdqDD7lXi2/Y68uu6S
+                        k2jNnRZS2sfO9qOFGOwZv6JGDh2i
+                        3YBAptDnESr7hlvAZ8HZyrl8SYi1
+                        IN6R0DHalhTF0kx+K+i78u7yqipB
+                        H6oUeYc6GuAFYkkYt1E2os6b2M1+
+                        H9h47Skl21hvah+UAnMXpRHuDhFR
+                        dNXy6LtQPmKlKOStp6AwS3JQfTEv
+                        1kEdUv27R2MpQib7pQwXEn2L0MFQ
+                        R4QFj1TPG7hPkHPI25hotdFod0dV
+                        0v0LK6S2Af0EIJxq/dLtPXNUsz0H
+                        zy3JctPpjkaNEPaMLMN2Uqxh1+Gx
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>Safari</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAbbqSrvyPe8zp
+                        5T3WiZy6a2oIop8rT9+jxu7K8kt/
+                        UTcwK6jGuKAWyE3vKuzyYFZsD6W1
+                        7aCq0ZGfCAxU7LOg+Ss+T5AP7LsX
+                        RsLuG4qs8c2QBIH5DVOG01pG8RvW
+                        FZxMYkq4xHTH+XPP6Mki0ppRbiqv
+                        vXk/R3i3CWr7sdRcgHLrWEuu20b7
+                        MOujrqRatx3x9LeCydhiLgmr9G9x
+                        Rm8AmRlcYipgD49Dsvd4BF4NkNWS
+                        jtc4A645IyZBdH+GJ2JWQOtubT8p
+                        GWEES2waAuuUm47FftMgdH33HfjG
+                        ypG7d6f4rnoU5NgrauIrz8uA9ezT
+                        TJeJYj4dI4AJ72LA8FnlZNPJ+p2w
+                        c5CWTuLKHKjcA+DSJirdYJGFusTj
+                        JiBmPBzEfHWTU+dEcehSCMxJnsK0
+                        sKYUy8Gx86NMB5T7qK8dzgvbep7B
+                        4iivY5KjPirOBCBqKP7jb+TPnhhT
+                        pvziH9LG4aDa6i1IDLJmtFBl7u7A
+                        XAIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>Sharing</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAH/kF2CGnaMF7
+                        EeY5ls9Fd5WSvugys6kQdLxXU9+u
+                        0xgw9ZoHh1n6tl/l8TjVn68IfqcK
+                        UtbkGEgcwgPj7oykBnDlUJxEBdW/
+                        LtWleF8Xp2Y1BIH5zaaktjtHOx4k
+                        bXWPLNKOdF/zLfiGnI35fpzSZzLD
+                        7F1eanbVaIAxWcNNO/83Q7qirjcO
+                        Oy8mU3dNQmE6+x7owH1Bpxk97IJX
+                        cqL62Qm8tbeQG+K2w5iq+X7CZYzx
+                        wKlo3pw5dgzuBSPv7llYcsjlzlie
+                        3zYDHFHDpXhtJM/pgCGcZ0xxJDi0
+                        wO/eSc8eW+6ea7S9F83aTiK4lDiN
+                        l9DnDcowEpXR9mBzvWRyaf8yXO/R
+                        2wwZbF9X47eYfeB7r2AZmyhnoQdt
+                        doet0A27Cp6jpuvBFvLiLqR2dDhR
+                        OnY/2LsluiY6qTcsmtcoOliHNjXk
+                        VXQWRizDA2ZOBCCeimmOmppnEufS
+                        9uArUm8PTZ8AQfV1cAszCMD8uJoN
+                        9gIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>TTYCallHistory</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAxUH7GAzWiPzn
+                        ziecAwy1WBgXS+jYd3WPN2bYMol7
+                        ZGgwOPm2ifOo7M9szW9cjl/dI3JM
+                        419ce2yWog/TbFJ2cAWKpfB3WsDE
+                        0cyPrUBYHIJ6BIH5ImIZ9NBEdMrP
+                        e1zKlrFLEnwOxncJCen7RrQd3/bt
+                        WSG42saJI10Zk8lQSW09YGJ7xh8Y
+                        NQp2IOWKBytmxdvR9jAudn/8z4w7
+                        NXWqhfqYpjrzVmG5nz9XTxt75DBz
+                        bozqsYvKVQWfmq/C7FXRPP9we27S
+                        KXjNNnMgk2u6ircum+tWn9OftEEA
+                        s0EXGcI30YqoTKcgLsfyGGlTsG5C
+                        9P9CffzpOtrzY+nprBxZSmIScK4i
+                        FTx6N8w+j9S3lQeqTLthvBH6DTc6
+                        0pCCF4OnxgWpP9POm9IltCgo9WJv
+                        llIGI5T1WT7C7SgMpxscLu84aCrD
+                        EUdxjL8SpNBMBCCNrMVagA0+ttQk
+                        Y4NGtYqj49b4PHHV7YFaAHyVd9vo
+                        dgIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>com.apple.icloud-appleid.privacy</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEApcI++fPiMp2F
+                        7719sTxSJqaM6ee9DlujcuWuzM6t
+                        JVow1MYYRnnH8QbtORp2/ddi/I/o
+                        OoPNQ7y8LVOGFVyJoARvHXAuJbiy
+                        oT/PNy3FzHjbBIH5rEU6m8vdSuPs
+                        0ygcTuIPvXnGDYdkGzx4c39oflgm
+                        aFgUsuW++rH1HOa6cCgJ/lstbJUX
+                        RWhgoOMro9kMmgI89wzcd5DSBiG9
+                        UhQt9ZDVvWz262k5O01os9poHy5Q
+                        WHECo4HqcfykUXLt/pQUo0QcQ9b4
+                        xGRis/X7vzpprRcK8M983alsaJH6
+                        Zeh87J6DDPajPfxHN/HPzB3D+Gkl
+                        TSbzm+WRA0d3Iea3wh5edoJl9HSq
+                        Xgxx4UFnpQyz+Y9Yl467o7Yn42/C
+                        +2IvNFRQM98STxWssxamHdoHl5p1
+                        rUIUxseaHYCmdhvMUAslosNalc/p
+                        wDmXbrlFVqktBCDyKeoxY5kg0jXZ
+                        okvw9XIZk/dXsLybRdeGyOhCRXTz
+                        /wIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>iAD</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEAT1yMt7X/tEb5
+                        DGCA2BPD9zgwPca1ZgTNiFadCztP
+                        NZEwQzlt/Wmok9wBFnZtBF1eSoDw
+                        W+hkyWSHqMLWbw7nhDCGFsK5mhxX
+                        SD2syn2d4JYBBIH43drE0fkWOe+h
+                        /k/tlsA0K+MVK4mjDGX+Rob97aDe
+                        +AK5hR4Td8TOTPdilMfO4o5DpToD
+                        Q7wzVF+tYqesLviZcTLlbtK+8+OI
+                        bxx7OprVdxp8L1UQcRRDe5MrzEpn
+                        yUGad/VmIvqBWJXVH+IaqLXTLhsV
+                        T1XwYvaM3Q2gk3h3EYA6zjTLUKl/
+                        GagiADSmJUnL/sz6dI81fXhstcWw
+                        ELvvxM1VqpBIZPQJ3E9XPNTX96bg
+                        6tdsH1xyzezqijanhcOqIYcR8fbu
+                        PocuN220LJOZ89k0gQTYWswU9V77
+                        qw8TCiBu6KBL82omINf51oA3cXoS
+                        MjQCQBnUl+QEINx7OXoWq0bIeRfX
+                        vgIQbxVIA6Lg/eUiUU07iol9VfSx
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                    <key>iCloudDrive</key>
+                    <array>
+                        <data>
+                        ZIIBnDCCAZgEUwEAhTriZPlk5ba8
+                        weQP8abhLwtXIMRdFUPlVDwmgqCY
+                        2U8w/ZpeoOaJ5wp+7NNBOQgGi88J
+                        CQfor7ChKRLSy0rdlAZDLKEHZifl
+                        NJMpqaRLDNMFBIH5Zo4hPORCAtqi
+                        KM6BZmXDM4ZnyqLNREjAw8SAyQKq
+                        viDGU5f55CavjkHluBLUzvddxRPu
+                        e+IFc6+Yes+Rs6R0Xj9xZpprfAFk
+                        1vusLNajPhT+a4+ChnEtrp5c8keB
+                        z7xte8YgPINm9HyTERH4X/QrwHXE
+                        0un5d2iU5tE1Q9a+V9FctlUHl4De
+                        EKk1cO6+UdckPo5l/1ozpxscvNpt
+                        wgfla36ivuZQ8Nawz7Bc9s9EiFRv
+                        Pa3EaHN1pJOMzJ3eWCqkFy+XheEa
+                        F6riryW/Ybl/prjzre3i0EKTzzXO
+                        bnZ6OceTfOzMmPHKmCj56rjqharV
+                        hoo2e8zhwV0lBCAXOlNsMQNVJQUY
+                        +dqcGt39XUTbDVT2ksgEBMVvyOjk
+                        PQIBAgQgwVKb12gOwEEtjafTc2Rg
+                        vD+ONtNzFtZ/v9mEkf1Dd3k=
+                        </data>
+                    </array>
+                    <key>iMessage</key>
+                    <array>
+                        <data>
+                        ZIIBmzCCAZcEUwEAEZKDmq9tWraG
+                        4Q3otQnxhDK/rs9+l6EeptQ0JF/j
+                        PCgw4ua1T1g9j/IC4OOk9PEUUQix
+                        4R5VYCTstE9HtdVC7AhhOIbFUp+K
+                        8ms36ITjerXQBIH4egZIG+JkLXf2
+                        n9WCQHv2Ue/cw6SbxEmKtrNtYfqs
+                        85x9rhhZLaEag55ko7hq/5nvRyAN
+                        0MMH1DxU7TipecTWz4we5FRHWn00
+                        2PM4TqMDci7/0+Z6+UAQwXzF8SyA
+                        X12W2UZns78mKKCLCWMBfsj2Dvu1
+                        sab7LIn4eZHiMq25bk+w5s2kI/X7
+                        2ee6eeNGqhPS2Qx5a7uHSkuQ/+OY
+                        TUG8v/3Azsb0Gzn0gplS7peFXNAm
+                        /FyzYhMeWQWbPlWc8HdDshzppCbq
+                        XkBbXq5Szlbh/68pTMHAXYLWqWsU
+                        LEkgtNgu/zAm405LDqU/pXb1MzIk
+                        bJAbsvGpie8EIMr5O+MxnSPOECSW
+                        wa6jWdtSl8CxG60ieEJrS5eT8csD
+                        AgECBCDBUpvXaA7AQS2Np9NzZGC8
+                        P44203MW1n+/2YSR/UN3eQ==
+                        </data>
+                    </array>
+                </dict>
+            </dict>
+            <key>SecureBackupiCloudDataProtection</key>
+            <dict>
+                <key>kPCSMetadataEscrowedKeys</key>
+                <data>
+                ZIIayjCCGsYEUwEAPy4812ENrmwVk6t0W6sfIrlO6AiE
+                gmqgnxn3sL0HIeEwRUGvxCIWt3mQR09OyX60jN44aMzY
+                PANLmNbWzcM1aHDJm6yLdO6haQEjAvmG8/8NBIIaRp3E
+                xXChfOzkEz30rxfRi4Dzk+uU3c2qN/qmO9jcdYHB18ja
+                gteFAASSTK5JofeMqNMqbnd81l2wXbhC2gdok/dawR85
+                kVCYOO8Bf0y8pTaZUrjX2b4UYR9fDf79kNP0oyvncn43
+                u9kYdnh0q9PDKf1E0VYFt74P2ZTRQxDgd5pSglYe82md
+                FZhv0vgmjF+kykzlfFbftYughM6Wg8pvzMP+5luRj31e
+                vzrc0cTSzUWSCQMLmipkWg6RL7+ee0cuRSdSzQxYBvzd
+                61uc5GYfw6Z20B7qlVAdcSDgyl49hrSIb7JZcpOHSVIV
+                dcQiOD8+00avphT2gH1IEm1ckMtTqObftwgrXiysQs4z
+                y42OtdWBclOATpn2h41lBiKUPRfLhiZRHDi2ewly6d9v
+                2oHA4nzo2ydxK7IrmkQpG0HGuJwQL0aBK0eyu9tapo0G
+                BG2gprNitthlMleO3NlGOcID+2Zc2TFiLe0R3Qtj3Wk/
+                Pvg1G1wchPi0uIgDBs+3GY1+EY7OBSTlRiQQXG7doQ68
+                YyFfI9XDEJq2T5dfeSvQ/Ii+ERWDRge1uZ0p60oox6Bu
+                e8tZzo+yOOQD0uSqPtlcjjsbkGHykR3J0gBQLxxnuKF1
+                7odIY9oeScrJfsnVmnsE//XtllmcLgLhZj1jThqqcEJ/
+                jg6Zk+q3vtk5L4t9c0HzNrDZYC8KnUPZ3xQVF5wYgBqy
+                UL7fIOtLfCzKmdWM1EZaKbpv2frwgs/updXRMFCT1do1
+                7FgznRruGobBbfW5Hzg9MAhnmOlqnHKgrDTLlsLyOUOY
+                PK2w1DkIWz6eG7lKN8JGwFgGjK60w9/3wMsmZzsX2aOe
+                sMtnjpxtJgx00ab7rEWp+HH8dpPq00butcsriePkpTQ7
+                M65m6r1du+05vxscAxCazxCKigWK3B8+VBcJOuQSQ5w8
+                uTbBoD5SexSvzun7MeCbLuI5p5B4WITXOhekn23sMwMs
+                St5+6iSANjtnNOY4DUikYTjkJ+Cc6kWR3h9MIlmh+Ros
+                DSRf+QyArypm/EAY5Xw9sHrGsQ+4lrbuEjvxKH5b5kI8
+                QsrI5ktdxDSZn1WicbiMK+U1H46KJSaAeY9RwcudGoVn
+                pD2XvoD329/TgdgoQ6zrQ0cuXl/M5sCLzcmFBLJbJD0g
+                5O+vMhhc4pF3Udy5Xxuuji8/xpa5Gkae2rwQL28P/ZCP
+                RZyazSOx0aK9TCDfBBkgwYzYYmcSXWk0bYYrs2Zracut
+                3NnUN8efIJb8SnjRd6kCLWvMgSyRdU7vbTMfjpa66Mii
+                TF1avDiNJ6WRmHw6HgzOXE7MiKk5d2WEPC6h33Z/jGVp
+                iuFqMSajXetwUbc97nffiTxraaHnxAi8U+EL0X6uxyRd
+                xKu//fAfbpwy4W9MZzOEd9fkqomSQb1A6fDftsVhHP+m
+                7rk+WIGYn6DKHSLqQMGnXdKG1VQxqbQZkXra2Z6Z47ok
+                XxavfUA8Vy7qiT3HDWDVAq5IKFnAO7pltkpYQ8KBRCrF
+                0JWDPuXua23jyqNW9zUjGwGw3+hZ2dpGSuYIRGcnp8he
+                uJe85jkJ3YGeYXQSRPNHHZqiflA7PcVtHTaG0Oy6QDDK
+                57sp7n6UOsON4S2xBmNkMJ3kXBlR227y21HrE/fnWtBA
+                B9Tsmrd4ydXisIW4qxKZzMkNoBQlE+68Y8zwZXaqRHQ3
+                zIap916Zmdn5nAlWWDZWwA7VA6W02IAvjxQO7Q5V8wZ3
+                lQ77cZJRA9udptfV/oWu8sI6U/w9Ju+DVAHmbn+Y0834
+                TpGalDwKcWgrwdgL0UCd/VHRoLK+5fcPKz9Q1KXbpFWk
+                glZ9priGzXfc3M6rlM95tpgoabmjruGVnPIHYnAKl80S
+                v/1/gVOQf7cHsK5oKg2c9euXKSeouJMbDPd0DvtZrmGU
+                tiWZiXjvmuKajIhLO9AAtubYWMBjQkimw1/oo7xH9qys
+                Pr4nvv3S8gA3mbwstnePqO4h3iiZJLnkYrudRKNWq3w8
+                qNPY63Vd6IVCR9bjySSOhwcXmvwEGe4Vtz/linzjEsgr
+                75hMYT3xJDXiXk01azsXbHWAyz5aF+oQaz6G6PySQGUZ
+                GeN26qCNL4VWeFt7sGa36MnH5tJSczLO9yXMX3kbiqJh
+                j5ipDCgd0duhsfqnURiU7SmB4fYRuvfw5wDnHLfbuU6x
+                qwaW0IKYsBBtgvn+i1AvxhE5bwaMqyn2RdAgxMiRB8Af
+                X6LRBk0aOBcGahwmbLLxtLeGMD5jvbT4kkfA6u24Af3q
+                PXCKO07aP4YUyXMtrti89wnkzqaMACiul8PVfXeWuvGK
+                hBVJPf3zcD14fdDk/oeTZRlHyf5PD0D5cMbU1lVv+1Ld
+                vm7f+zoMXMv18If2pWpK8Nc6pqG5OuDa8mcdvR3iY6z0
+                HpTQdVMUnH31Y6pncR6JYOc6DPXF7mvaizUvK5Jgl3Jx
+                BoZauBw5f1ZS4gC6TD1omkJETgmb2qKy8O14qDSpFBlm
+                gyCkXLacP8mK4xbM2KU4Tz9dm+jcuGH9GYWLERzkGir2
+                ksbeDLR8zjOUwFAvJuHYC835rL7TeNI6Ieb5xqz2Z0OJ
+                40hiaarxpXolNon00JvOLjo3GPvTE0d/pA+SRiXm1Ez0
+                AtaBkbYywgbQYWbFZvQr88EATOnzaUrBHIYfjCAxT5RV
+                OHVzlhH35D2hhXD3fpbRpXGegXVG91de7bb5EZg5aHAG
+                2qTfcOA/rYez4O8U/xh4RLIFL9ew9fulhfm1sUhKgPRt
+                e/BurazU6fAzlzNPZ3soA/sN6C0xwhR6InxUHr8WtrJx
+                8ak+s+ISmQav7gwo9Nc4JF345HSUGgKZefJcKko5pOrs
+                cym8NDDEFhJDISItu5r8SV71heSho9lTXC15r980BxC+
+                TNTlXSKp6ua8cZj3Mvn5/Zi32+I+eLqeAkbHiROZm0mX
+                vkgSeplFBp7K2WfeSY2N72AWcV2b9TdZ3KQ2MYTv3qJz
+                u57WMkwvMGfGRukfsGJwBxeFpJnVCJnDQ5wyPSXxkbIN
+                eAOhCKLnkqpZjKuivVz6TSNJ8TOhgjK38KhKQW4pRY9H
+                NwGR6VSNe2vxJQoOdslgVekl91Al+RlU5AVykyKLEycu
+                60g+rjesTmDPP/Tr/b2tIqRmAJbcxM05baUFdkNAXi0j
+                9uzjZtis2QQfqjLOIdSQUXWAQ3mafw3r3vNjofgOyVyS
+                cuSv10SKSxqqsZreix4ae6KX9kGsI0al/lyPA6qQuQpe
+                WG7HkjAmQc+AGemGMqruJd/xbRyp28guxkiVsI52ljHM
+                K9iu0jUKGQnH72Hr/InEAVxjk1s3/wrOjOsYha4mhOSt
+                Lvu3qH5NCqRDBOd69hzpKRu9QVU8MdbvYqbsz/WJI6yG
+                8mTh5VFEhjkVb/QhXTWSrhoXsaqv8oQBk4Xde9v2lWzQ
+                j9QvwXKeulngVsf8dEqV8xJD6SLH+NoSLxAebk1qEItc
+                feZTzvEt57wWMOX+8zalFSDLkqEuTWd8ViQ9ZlSo5WV3
+                AFbcKDcWvoyCF347IVA7y+FzWmTLbfSjSmtKIu/bX1d1
+                WnlDZqL5oAPRcMh+Njp9Zh4uvnOBPnwoxnVvOpDrbhrx
+                fmF6tXzSjz2/y66mpNT2upQZBRATIKy9rn8fdC0WUSTS
+                yi2Br0JYKrw4ajm7QkoGIniQeZ+bbtqQyfu2lgMKUyeU
+                mHhj7vH441xYcj6bn6Umy5iY+oHb+JkrcWQmNKHA5dTg
+                OB35cC0/i9hB+jkOWAMGx4MJZ5Si9jCe9myhWZzuk+km
+                FsAueeg/HjYjNBEfYuMUMrpRIJpzgPQ7AolfUE9EieeV
+                1CPzRZbl1EteDdD1RYd7wWo2qWwhbYMopGGTZtgpBZwl
+                dIxkSnRFwuaeqSq5h6FFriDbtvZAsl+smRVPgWQl3O6M
+                UQQfRS2Mqe4lfi1wi7znhGEGZnQr2zeoKfudbU4xrq7C
+                6KcfCineZ66pRSqTF1ERpo5olierMsn7Q6sGvezb3umO
+                aGi5KmysL4CStBM/rMfk4UAJP8/JHOe8hj5BzJ0Vj2p0
+                QH/icLnwxQXPlt3An6EoLVyfea2n+Xz5zBsPsFem3aE+
+                MOyNuBT+Wi99iISUGjYCeoK0IPMxDowQlgO8bdL5frG8
+                v3rGEidUYEkSX3kv/3dqg/m2+L/rHzaKZo09HQSLGaCF
+                BngxviUGzC7IRNdSwNGWiz5dvvALrkMDheqNb5Zs9KHV
+                nmzs4xyKNHh2rwziYD+qP0gtcvja7Q7rp/30JLUoh7lE
+                HSlox8LZvrhcKsX5Fj2tJ5y1gEAWOThhRsw7eVVS034G
+                Uue76HsHzNA+Sszh3v5tawcqVuXXkVCJPabPRjoEVTxz
+                3Ngzp13qm1uQcdshmCBhSWZ0spKSjIVmSgJbKj+GRKBu
+                XV4+e2zFGMEfnnyJXWt91gErH/+22LQmROrWReucNmf2
+                HWS0RGaL9OUehhrriV1Tt1Y5YD8A23DtErU+9NWCHcyF
+                1KnL3CoYyNWKTPnptrqD8N7RaS28JOtDT9bi7hn/nTgz
+                alO6SUzBIa9TKSugQd9F/AHQfiMTSyEbz+RrWNWHlfQj
+                S5Kjuo0GG2kypc7jRDSVeHnZ6xAWvl/gpl+PU3RyALDo
+                oPJ97ETYH5hMpOJa7/AnlduBwQyd+Ix7Dg4+Z+rKQscN
+                Sxc/Gfb29OBIi1LUU+g3WqiMK34T1zF0QqzynMMVt/rz
+                eeB/R1ea9yO3FIQCvyNVTBOMbOwt32kSKraiRa1JZ183
+                0PYAOKoLy7eEC9h9n7JLXV2V/F/1O7/lU6RzB46SZUiR
+                9Ye8wKfTlA3EZcc5LdWgZFG34kLEMr5Z6P5gOPcYuwae
+                QiMcBVYAb3Cce1uDsgLhSPJXHJfhQG5mEaKFfomNe++X
+                +fK8uYplGPjB0hxmJPIh4lFAqNhJhI6tozTyd/+KmJHH
+                sSniBG+LEcuR621TQVUf56mx6cCE5Pzxaee4faEPsC9X
+                YK6NonfXuOpEFkbH9mPsIUprwOE/s2MOBCg6yTgiQ6Ok
+                u+FNltMGm1mWkFqsgvkAUYTCvB2zYfV1qVxjf+VgyJ11
+                oUHrbMJ+jZwKISKSnvTLAiq013mA5BJ4vDsDU4S5O9Uv
+                GRHmejmbYbfmGVIw50TwTnFJHIpyrwpkjZOqsJ1p/k/e
+                rUwwZ2OGxZ85qPTRTDEwCnJGSxKI7BbEfi7wbNT4OBKW
+                zlTmtr+uCWpRw6joQ76vyYWHtj0BrmMK2TYKsl6zZZFP
+                ARBCFGrO8hjpAkQ3k9oZ5p8KU7dWXspPwAgOESWllmOE
+                4kUtuTWFuUtt77vo6Jy1Him/d8jQiNdVBcw+7gnTGBXz
+                zrljq65uBO2pzUBkdG5nkBXwK/161E5MXQb6bkXxPyJq
+                heGzvkVtIfTS/zAeswBO+WNXyGqONOfa7qaGl+IPnVaJ
+                PalQXuuka+IxsEMIwkw/In03x+Jb6Hud7p9qAaCxd9IH
+                rrNq73BkTw2GQAm7VTwm5nzE61WWwuh0XaKhquse0znP
+                xyBijVUAkyBvht7NaXA04wj8HX1sTDnSwH1RFDyQIMei
+                V2uVrqKFtyVfQLxNbn6YfXjbA8iwethkLGJGS5rXq/ay
+                pk8fs2rvYYywL48s+gcMgxDbfWu8rux8F9ymO/DM5sNJ
+                buCCcc+kYL4VMNAtM22CAZM0/OrAL8ItUXUsn0MvVAs1
+                skDQuyZBPlPTmJ5Ta7DPXoHJikeMclNki6TjmROFuCM6
+                5rMa3pOTrb+UKh0ozqK8lrmYQVRJ8ZBfr48DkdgHDd8d
+                Kyb1ymSmGWd9dnS2eV62J+nd2nKIfZ0j1JiMY7cgESMe
+                v1kD3SXRdCLlen80L0sdLRjcFbzg7M2Pq6IV5W54tgt4
+                LKgYettPhlMNoPeEvUProp+AkbWDfeptakwxgmYrRrhw
+                9nhlbX9paKSZ9JQ/2skUknBPc2zc04qCL4ghXwcG8X4/
+                a0DzaUBLiW35rp6WwqnmlndkwUeJ6VSiH113JjK3oyRg
+                dDQgHhdecffQysaWn0+03ccx8eVe3FMAknX8KYI6Q/iM
+                Uum+KsGcUH/Cza4qbSEZKERvc59jeN6rY1/J7U/JCown
+                jyKelYJ4ai0i2lMenpmzM9xkXw8amhubeCiAEDpklntX
+                0nWuVYjSy2hzqo6N3KC4Py+0sY0tAqp23EYnatxCwYTr
+                aQUZ5CHW3SzsP4PjOLEhoixBuX3b/HjG8C59KN18cIcR
+                HdQU4IYMmkZV3DfxpEWxAwM3M+1sAA+ZHzYQB8I/OppV
+                2YiZaHcDxDUO5aj98w3Qr1BbE3l89Z+tMWBIe/QigCA8
+                JIOf032BQ+RM5Q5rzprOzyKCfCJIcwsSMv3cQpuiWPG8
+                79TmWzkd4Ayv9lKWbHY2eoTqieRc5B49fdtMAo94OFlV
+                zC6EY+823s6pkI0LiOuc5PRxRnhexSixsCrbsU7e/0DX
+                BX9vK4E2ShGs3EJFEbvshbuDQSFitds4HsotmIBvZH7T
+                UFqbKfVUyuQfdKd53mzZ9RwIVVOleMtjwfdSFGut15pU
+                J/RqcSAtYaObnc44EbeelmA5HzMfuji6GO+sN90UVD9J
+                +Wk6BPIefRf+JOof89byJuYS2IQ7cFckPa2Yjd8roWgb
+                uqNP5h8mVZf+SzMNwcHWIAHBxMZ7ymqLq4RcjriNzGUY
+                wv4hJsnsMGFJz7HPg3jxiNKe5RLsaF3volW1ROVyAs8f
+                OoAdAJasXh5SGbhW5jppCkNhrjJrfWsHI2tX8vbMVO3H
+                hr00mrx1Gaz7jcE88H2kQruDuqv0VdFIfeCIEzI9FoAh
+                0xtj7IKBYhazOtIGXNr/3SDH1esUPgFbMz9KOBzdsamH
+                F32hva6NFI4FZHNnXmckB1eNiKD8fiGNN8NTg+K7rEJT
+                FXAWLDwbKQKjffZkQELfHGMubGct9jRkb4PcLkeY6G6a
+                ICxbIdWD/1oNeMUrO7ma42ii1k2gOeIocthJf6S7QRxU
+                3sL7YCDSeL+qYRynyMRgYNbjGCKehdQsYvHLwFqgCPf5
+                9+dCKkK7Qu3u4hoUahircTW1jbe98jkjuo/qOgmUBT3S
+                j5dWR3wjV4EguKW1A936NxkGWMooVdxk2iV1jJkn8p1a
+                zsQAn4KhBH18sfzTR10zDxPC8pHEE9HyhOyVYsgiSh4V
+                5X3aFICEYjb1LlxkycNuYv1Sd+PnUEMDTaFLgZyrj7pR
+                5AKY4Kbb7cQTbCpxUbHSs4nie/Q2Inl22XQ6Mz7NTtQG
+                kNE7uUvOzc1J3OBl/vpyy3arKf6NfXIIKPD3I60pHzoB
+                0OIPexhasJPHyBoQ/0P4k99JCBux6wt6scmRC6fUxvzV
+                FAf15Oo81W1Z51hLL30fFospXFPcknxo2FVxIs3yPvKJ
+                zBpOWBtLbznDHCf3IDPGoVQ1HuhguvFUylc0G7Z3rM5T
+                z3ORkHExX8V8Vb1ROFAOuo3X0jB8wzv+ir5bKykZXQmL
+                V01FQpF8Q+SvERgwNr1Gn8Gv5WVeoQ7XhA1pEmR+iOwK
+                VmH8LepXPQP9Ggm1fH/CSrjhMju+0YsrnIIuiiAWa/zw
+                ++guaPx02owWBd6FQVg7KrjyrWLdXmRwt1m8Hset7e7C
+                a3D1DttfOWFqrd87CE+2GSTR6WBptLGtWgsWkBsUx3kq
+                xtnW9t3eEDOIn3TmgRyQ4tekktczPS21FZwFLnx/s2dm
+                yEWAU1/2rswSSv83Hb+bKECbyFSLl4mKB89qjQ6vPYVu
+                hVwFer7xCyt6o5kh+/6MJ0Ts3lU0xqHgddsOxn3Vmtac
+                LwTBemQfIMo5CTOE222qeIuxXn9pxSN6/FpIBxHPUANH
+                fRzOS8G2/gSHX4cgP6JWPt1UYXWwY6aoeUj0jBWu4iwl
+                8tNrI9W/8ELjji4IhIJB2zraowhL4ri81RogsCIyquaP
+                U5lvqD+y2glp7nD+eb8OhfaqsQAVIqZUm0oPgbqij2D8
+                M2S2NSAmD1Fn4WzR8PtDN+6K7TJBP8qz/cNXIRcx8AZH
+                LYyhJ+oY4+mlxWVpyhM/K6VMJZ2757JMPNnuO8MwaGbj
+                xyoCfc0YPLHcdH9JI8x2QQtUwXb+kH8PtrEUcfm4BeXK
+                0qjwCa7igKxA0QyzqG6WybelTNZYhSC0of1F1pN3eOqN
+                wtNvj4jN0R3iBG3wklEQ/ySh7RGdzaLqIRFpAudvZWVk
+                SnNYnmbEQyJFEv7o39kjvAPTL/Lw2oa0LHBdmgzueHZ7
+                cb8avYCyuyiY4wf0cA+ZN7OBLmrzVuAffWNqf34yvTk1
+                BcagiFN4idpmsjZWNu58L49LOPPO/HeVl9DBUqu1ISzi
+                TAPoEalrXmm/IDw65RAo7QuuEaUlxLFlrAvIUnbv6Ofp
+                nfkH4TgEwVDKwnlclvhV09NmhqUx2Zn7sSvbofNcvRPP
+                SNQrkLPRN8nScpYtr2dfoPQHCVI1mwxPfqd/pt9D0j64
+                dfDM7gLYsxk7r7QeBF1f0d27vpQlYw3NNWFzV8rHhUwF
+                jwu+mc0REFuecKvuVk1ETajKX5uPnJ/wDK3dEHNQWYfx
+                O1lrlvqzyHhh4TJpjKn1FGIwCl7DsnBknkq/Ftg2MpE3
+                7bDsXbQTPVthfGoVwis46X7rf07zzFDQtLrDauZFKqVF
+                Xvq2JnMzIBuQKYoPZVJpI263kIznFrNex2dOiF1XfoRP
+                BN5KiwjgfQgQGbcDrRzaGScflHMAwhC/maZ/XH/RO7do
+                weNT0usHXBKdL5yuyeKJWN2WiNJUi4jYGH4gh9WOW88Z
+                YUQeOnQu7PiYhD9dGwJQF1L5Q8sgJXttoQVmc7hnQu2n
+                UdyO9zE+htxDuvmjS4up6rC0e1mmpbNcKZXzQf03iQIc
+                wmIT+9607OEw4p9c6efsFhwP8UE5hVplF1iVJ60MC8L1
+                rhO90R47+S/xhvAr+BlY3bsOJdgAnacA4TAIPiwZ1HjU
+                9Q533lQVU0ZaJhNZefomfmA4fi5OkC/rv73AMxIc0wtm
+                fZCAW06HrgTX/UJu6GmoPUF8XudtJcZIj9J20yepihji
+                75pvJuzp0ELRB9uW8k+EqFZFtQyW4+WD8QQAAgEDBCDB
+                UpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eQ==
+                </data>
+                <key>kPCSMetadataiCDP</key>
+                <true/>
+                <key>kPCSMetadataiCDPArmed</key>
+                <true/>
+            </dict>
+            <key>SecureBackupiCloudIdentityPublicData</key>
+            <data>
+            YYGRMIGOAgECAgEBBCAXOlNsMQNVJQUY+dqcGt39XUTbDVT2ksgE
+            BMVvyOjkPaFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcw
+            RQIhAIL+1l8MsRW3rN9wMeM7tSinakp/c2/Dp2kO8Z8OZBxSAiAL
+            15IC/CrJgkQLyS4rarGeTmMFKGz34i/jQ1AQHzQy0Q==
+            </data>
+        </dict>
+        <key>com.apple.securebackup.timestamp</key>
+        <string>2018-09-28 19:45:25</string>
+    </dict>
+    <key>SecureBackupStingrayMetadataHash</key>
+    <dict>
+        <key>BackupKeybagDigest</key>
+        <data>
+        LTrJHVHFZ5vQO59wUih1MEgg1qI=
+        </data>
+        <key>com.apple.securebackup.timestamp</key>
+        <string>2018-09-28 19:45:25</string>
+        <key>encodedMetadata</key>
+        <string>YnBsaXN0MDDTAAEAAwAFAAIABAAGXxAgY29tLmFwcGxlLnNlY3VyZWJhY2t1cC50aW1lc3RhbXBfEBMyMDE4LTA5LTI4IDE5OjQ1OjI1XxASQmFja3VwS2V5YmFnRGlnZXN0TxAULTrJHVHFZ5vQO59wUih1MEgg1qJeQ2xpZW50TWV0YWRhdGHVAAcADgDTANUBLAAIAA8A1ADWAS1fECBTZWN1cmVCYWNrdXBpQ2xvdWREYXRhUHJvdGVjdGlvbtMACQALAAwACgAKAA1fEBVrUENTTWV0YWRhdGFpQ0RQQXJtZWQJXxAQa1BDU01ldGFkYXRhaUNEUF8QGGtQQ1NNZXRhZGF0YUVzY3Jvd2VkS2V5c08RGs5kghrKMIIaxgRTAQA/LjzXYQ2ubBWTq3Rbqx8iuU7oCISCaqCfGfewvQch4TBFQa/EIha3eZBHT07JfrSM3jhozNg8A0uY1tbNwzVocMmbrIt07qFpASMC+Ybz/w0EghpGncTFcKF87OQTPfSvF9GLgPOT65Tdzao3+qY72Nx1gcHXyNqC14UABJJMrkmh94yo0ypud3zWXbBduELaB2iT91rBHzmRUJg47wF/TLylNplSuNfZvhRhH18N/v2Q0/SjK+dyfje72Rh2eHSr08Mp/UTRVgW3vg/ZlNFDEOB3mlKCVh7zaZ0VmG/S+CaMX6TKTOV8Vt+1i6CEzpaDym/Mw/7mW5GPfV6/OtzRxNLNRZIJAwuaKmRaDpEvv557Ry5FJ1LNDFgG/N3rW5zkZh/DpnbQHuqVUB1xIODKXj2GtIhvsllyk4dJUhV1xCI4Pz7TRq+mFPaAfUgSbVyQy1Oo5t+3CCteLKxCzjPLjY611YFyU4BOmfaHjWUGIpQ9F8uGJlEcOLZ7CXLp32/agcDifOjbJ3ErsiuaRCkbQca4nBAvRoErR7K721qmjQYEbaCms2K22GUyV47c2UY5wgP7ZlzZMWIt7RHdC2PdaT8++DUbXByE+LS4iAMGz7cZjX4Rjs4FJOVGJBBcbt2hDrxjIV8j1cMQmrZPl195K9D8iL4RFYNGB7W5nSnrSijHoG57y1nOj7I45APS5Ko+2VyOOxuQYfKRHcnSAFAvHGe4oXXuh0hj2h5Jysl+ydWaewT/9e2WWZwuAuFmPWNOGqpwQn+ODpmT6re+2Tkvi31zQfM2sNlgLwqdQ9nfFBUXnBiAGrJQvt8g60t8LMqZ1YzURlopum/Z+vCCz+6l1dEwUJPV2jXsWDOdGu4ahsFt9bkfOD0wCGeY6WqccqCsNMuWwvI5Q5g8rbDUOQhbPp4buUo3wkbAWAaMrrTD3/fAyyZnOxfZo56wy2eOnG0mDHTRpvusRan4cfx2k+rTRu61yyuJ4+SlNDszrmbqvV277Tm/GxwDEJrPEIqKBYrcHz5UFwk65BJDnDy5NsGgPlJ7FK/O6fsx4Jsu4jmnkHhYhNc6F6SfbewzAyxK3n7qJIA2O2c05jgNSKRhOOQn4JzqRZHeH0wiWaH5GiwNJF/5DICvKmb8QBjlfD2wesaxD7iWtu4SO/EoflvmQjxCysjmS13ENJmfVaJxuIwr5TUfjoolJoB5j1HBy50ahWekPZe+gPfb39OB2ChDrOtDRy5eX8zmwIvNyYUEslskPSDk768yGFzikXdR3LlfG66OLz/GlrkaRp7avBAvbw/9kI9FnJrNI7HRor1MIN8EGSDBjNhiZxJdaTRthiuzZmtpy63c2dQ3x58glvxKeNF3qQIta8yBLJF1Tu9tMx+OlrroyKJMXVq8OI0npZGYfDoeDM5cTsyIqTl3ZYQ8LqHfdn+MZWmK4WoxJqNd63BRtz3ud9+JPGtpoefECLxT4QvRfq7HJF3Eq7/98B9unDLhb0xnM4R31+SqiZJBvUDp8N+2xWEc/6buuT5YgZifoModIupAwadd0obVVDGptBmRetrZnpnjuiRfFq99QDxXLuqJPccNYNUCrkgoWcA7umW2SlhDwoFEKsXQlYM+5e5rbePKo1b3NSMbAbDf6FnZ2kZK5ghEZyenyF64l7zmOQndgZ5hdBJE80cdmqJ+UDs9xW0dNobQ7LpAMMrnuynufpQ6w43hLbEGY2QwneRcGVHbbvLbUesT9+da0EAH1Oyat3jJ1eKwhbirEpnMyQ2gFCUT7rxjzPBldqpEdDfMhqn3XpmZ2fmcCVZYNlbADtUDpbTYgC+PFA7tDlXzBneVDvtxklED252m19X+ha7ywjpT/D0m74NUAeZuf5jTzfhOkZqUPApxaCvB2AvRQJ39UdGgsr7l9w8rP1DUpdukVaSCVn2muIbNd9zczquUz3m2mChpuaOu4ZWc8gdicAqXzRK//X+BU5B/twewrmgqDZz165cpJ6i4kxsM93QO+1muYZS2JZmJeO+a4pqMiEs70AC25thYwGNCSKbDX+ijvEf2rKw+vie+/dLyADeZvCy2d4+o7iHeKJkkueRiu51Eo1arfDyo09jrdV3ohUJH1uPJJI6HBxea/AQZ7hW3P+WKfOMSyCvvmExhPfEkNeJeTTVrOxdsdYDLPloX6hBrPobo/JJAZRkZ43bqoI0vhVZ4W3uwZrfoycfm0lJzMs73JcxfeRuKomGPmKkMKB3R26Gx+qdRGJTtKYHh9hG69/DnAOcct9u5TrGrBpbQgpiwEG2C+f6LUC/GETlvBoyrKfZF0CDEyJEHwB9fotEGTRo4FwZqHCZssvG0t4YwPmO9tPiSR8Dq7bgB/eo9cIo7Tto/hhTJcy2u2Lz3CeTOpowAKK6Xw9V9d5a68YqEFUk9/fNwPXh90OT+h5NlGUfJ/k8PQPlwxtTWVW/7Ut2+bt/7Ogxcy/Xwh/alakrw1zqmobk64NryZx29HeJjrPQelNB1UxScffVjqmdxHolg5zoM9cXua9qLNS8rkmCXcnEGhlq4HDl/VlLiALpMPWiaQkROCZvaorLw7XioNKkUGWaDIKRctpw/yYrjFszYpThPP12b6Ny4Yf0ZhYsRHOQaKvaSxt4MtHzOM5TAUC8m4dgLzfmsvtN40joh5vnGrPZnQ4njSGJpqvGleiU2ifTQm84uOjcY+9MTR3+kD5JGJebUTPQC1oGRtjLCBtBhZsVm9CvzwQBM6fNpSsEchh+MIDFPlFU4dXOWEffkPaGFcPd+ltGlcZ6BdUb3V17ttvkRmDlocAbapN9w4D+th7Pg7xT/GHhEsgUv17D1+6WF+bWxSEqA9G178G6trNTp8DOXM09neygD+w3oLTHCFHoifFQevxa2snHxqT6z4hKZBq/uDCj01zgkXfjkdJQaApl58lwqSjmk6uxzKbw0MMQWEkMhIi27mvxJXvWF5KGj2VNcLXmv3zQHEL5M1OVdIqnq5rxxmPcy+fn9mLfb4j54up4CRseJE5mbSZe+SBJ6mUUGnsrZZ95JjY3vYBZxXZv1N1ncpDYxhO/eonO7ntYyTC8wZ8ZG6R+wYnAHF4WkmdUImcNDnDI9JfGRsg14A6EIoueSqlmMq6K9XPpNI0nxM6GCMrfwqEpBbilFj0c3AZHpVI17a/ElCg52yWBV6SX3UCX5GVTkBXKTIosTJy7rSD6uN6xOYM8/9Ov9va0ipGYAltzEzTltpQV2Q0BeLSP27ONm2KzZBB+qMs4h1JBRdYBDeZp/Deve82Oh+A7JXJJy5K/XRIpLGqqxmt6LHhp7opf2QawjRqX+XI8DqpC5Cl5YbseSMCZBz4AZ6YYyqu4l3/FtHKnbyC7GSJWwjnaWMcwr2K7SNQoZCcfvYev8icQBXGOTWzf/Cs6M6xiFriaE5K0u+7eofk0KpEME53r2HOkpG71BVTwx1u9ipuzP9YkjrIbyZOHlUUSGORVv9CFdNZKuGhexqq/yhAGThd172/aVbNCP1C/Bcp66WeBWx/x0SpXzEkPpIsf42hIvEB5uTWoQi1x95lPO8S3nvBYw5f7zNqUVIMuSoS5NZ3xWJD1mVKjlZXcAVtwoNxa+jIIXfjshUDvL4XNaZMtt9KNKa0oi79tfV3VaeUNmovmgA9FwyH42On1mHi6+c4E+fCjGdW86kOtuGvF+YXq1fNKPPb/Lrqak1Pa6lBkFEBMgrL2ufx90LRZRJNLKLYGvQlgqvDhqObtCSgYieJB5n5tu2pDJ+7aWAwpTJ5SYeGPu8fjjXFhyPpufpSbLmJj6gdv4mStxZCY0ocDl1OA4HflwLT+L2EH6OQ5YAwbHgwlnlKL2MJ72bKFZnO6T6SYWwC556D8eNiM0ER9i4xQyulEgmnOA9DsCiV9QT0SJ55XUI/NFluXUS14N0PVFh3vBajapbCFtgyikYZNm2CkFnCV0jGRKdEXC5p6pKrmHoUWuINu29kCyX6yZFU+BZCXc7oxRBB9FLYyp7iV+LXCLvOeEYQZmdCvbN6gp+51tTjGursLopx8KKd5nrqlFKpMXURGmjmiWJ6syyftDqwa97Nve6Y5oaLkqbKwvgJK0Ez+sx+ThQAk/z8kc57yGPkHMnRWPanRAf+JwufDFBc+W3cCfoSgtXJ95raf5fPnMGw+wV6bdoT4w7I24FP5aL32IhJQaNgJ6grQg8zEOjBCWA7xt0vl+sby/esYSJ1RgSRJfeS//d2qD+bb4v+sfNopmjT0dBIsZoIUGeDG+JQbMLshE11LA0ZaLPl2+8AuuQwOF6o1vlmz0odWebOzjHIo0eHavDOJgP6o/SC1y+NrtDuun/fQktSiHuUQdKWjHwtm+uFwqxfkWPa0nnLWAQBY5OGFGzDt5VVLTfgZS57voewfM0D5KzOHe/m1rBypW5deRUIk9ps9GOgRVPHPc2DOnXeqbW5Bx2yGYIGFJZnSykpKMhWZKAlsqP4ZEoG5dXj57bMUYwR+efIlda33WASsf/7bYtCZE6tZF65w2Z/YdZLREZov05R6GGuuJXVO3VjlgPwDbcO0StT701YIdzIXUqcvcKhjI1YpM+em2uoPw3tFpLbwk60NP1uLuGf+dODNqU7pJTMEhr1MpK6BB30X8AdB+IxNLIRvP5GtY1YeV9CNLkqO6jQYbaTKlzuNENJV4ednrEBa+X+CmX49TdHIAsOig8n3sRNgfmEyk4lrv8CeV24HBDJ34jHsODj5n6spCxw1LFz8Z9vb04EiLUtRT6DdaqIwrfhPXMXRCrPKcwxW3+vN54H9HV5r3I7cUhAK/I1VME4xs7C3faRIqtqJFrUlnXzfQ9gA4qgvLt4QL2H2fsktdXZX8X/U7v+VTpHMHjpJlSJH1h7zAp9OUDcRlxzkt1aBkUbfiQsQyvlno/mA49xi7Bp5CIxwFVgBvcJx7W4OyAuFI8lccl+FAbmYRooV+iY1775f58ry5imUY+MHSHGYk8iHiUUCo2EmEjq2jNPJ3/4qYkcexKeIEb4sRy5HrbVNBVR/nqbHpwITk/PFp57h9oQ+wL1dgro2id9e46kQWRsf2Y+whSmvA4T+zYw4EKDrJOCJDo6S74U2W0wabWZaQWqyC+QBRhMK8HbNh9XWpXGN/5WDInXWhQetswn6NnAohIpKe9MsCKrTXeYDkEni8OwNThLk71S8ZEeZ6OZtht+YZUjDnRPBOcUkcinKvCmSNk6qwnWn+T96tTDBnY4bFnzmo9NFMMTAKckZLEojsFsR+LvBs1Pg4EpbOVOa2v64JalHDqOhDvq/JhYe2PQGuYwrZNgqyXrNlkU8BEEIUas7yGOkCRDeT2hnmnwpTt1Zeyk/ACA4RJaWWY4TiRS25NYW5S23vu+jonLUeKb93yNCI11UFzD7uCdMYFfPOuWOrrm4E7anNQGR0bmeQFfAr/XrUTkxdBvpuRfE/ImqF4bO+RW0h9NL/MB6zAE75Y1fIao4059rupoaX4g+dVok9qVBe66Rr4jGwQwjCTD8ifTfH4lvoe53un2oBoLF30geus2rvcGRPDYZACbtVPCbmfMTrVZbC6HRdoqGq6x7TOc/HIGKNVQCTIG+G3s1pcDTjCPwdfWxMOdLAfVEUPJAgx6JXa5WuooW3JV9AvE1ufph9eNsDyLB62GQsYkZLmter9rKmTx+zau9hjLAvjyz6BwyDENt9a7yu7HwX3KY78Mzmw0lu4IJxz6RgvhUw0C0zbYIBkzT86sAvwi1RdSyfQy9UCzWyQNC7JkE+U9OYnlNrsM9egcmKR4xyU2SLpOOZE4W4Izrmsxrek5Otv5QqHSjOoryWuZhBVEnxkF+vjwOR2AcN3x0rJvXKZKYZZ312dLZ5XrYn6d3acoh9nSPUmIxjtyARIx6/WQPdJdF0IuV6fzQvSx0tGNwVvODszY+rohXlbni2C3gsqBh620+GUw2g94S9Q+uin4CRtYN96m1qTDGCZitGuHD2eGVtf2lopJn0lD/ayRSScE9zbNzTioIviCFfBwbxfj9rQPNpQEuJbfmunpbCqeaWd2TBR4npVKIfXXcmMrejJGB0NCAeF15x99DKxpafT7TdxzHx5V7cUwCSdfwpgjpD+IxS6b4qwZxQf8LNriptIRkoRG9zn2N43qtjX8ntT8kKjCePIp6VgnhqLSLaUx6embMz3GRfDxqaG5t4KIAQOmSWe1fSda5ViNLLaHOqjo3coLg/L7SxjS0CqnbcRidq3ELBhOtpBRnkIdbdLOw/g+M4sSGiLEG5fdv8eMbwLn0o3XxwhxEd1BTghgyaRlXcN/GkRbEDAzcz7WwAD5kfNhAHwj86mlXZiJlodwPENQ7lqP3zDdCvUFsTeXz1n60xYEh79CKAIDwkg5/TfYFD5EzlDmvOms7PIoJ8IkhzCxIy/dxCm6JY8bzv1OZbOR3gDK/2UpZsdjZ6hOqJ5FzkHj1920wCj3g4WVXMLoRj7zbezqmQjQuI65zk9HFGeF7FKLGwKtuxTt7/QNcFf28rgTZKEazcQkURu+yFu4NBIWK12zgeyi2YgG9kftNQWpsp9VTK5B90p3nebNn1HAhVU6V4y2PB91IUa63XmlQn9GpxIC1ho5udzjgRt56WYDkfMx+6OLoY76w33RRUP0n5aToE8h59F/4k6h/z1vIm5hLYhDtwVyQ9rZiN3yuhaBu6o0/mHyZVl/5LMw3BwdYgAcHExnvKaourhFyOuI3MZRjC/iEmyewwYUnPsc+DePGI0p7lEuxoXe+iVbVE5XICzx86gB0AlqxeHlIZuFbmOmkKQ2GuMmt9awcja1fy9sxU7ceGvTSavHUZrPuNwTzwfaRCu4O6q/RV0Uh94IgTMj0WgCHTG2PsgoFiFrM60gZc2v/dIMfV6xQ+AVszP0o4HN2xqYcXfaG9ro0UjgVkc2deZyQHV42IoPx+IY03w1OD4rusQlMVcBYsPBspAqN99mRAQt8cYy5sZy32NGRvg9wuR5jobpogLFsh1YP/Wg14xSs7uZrjaKLWTaA54ihy2El/pLtBHFTewvtgINJ4v6phHKfIxGBg1uMYIp6F1Cxi8cvAWqAI9/n350IqQrtC7e7iGhRqGKtxNbWNt73yOSO6j+o6CZQFPdKPl1ZHfCNXgSC4pbUD3fo3GQZYyihV3GTaJXWMmSfynVrOxACfgqEEfXyx/NNHXTMPE8LykcQT0fKE7JViyCJKHhXlfdoUgIRiNvUuXGTJw25i/VJ34+dQQwNNoUuBnKuPulHkApjgptvtxBNsKnFRsdKzieJ79DYieXbZdDozPs1O1AaQ0Tu5S87NzUnc4GX++nLLdqsp/o19cggo8PcjrSkfOgHQ4g97GFqwk8fIGhD/Q/iT30kIG7HrC3qxyZELp9TG/NUUB/Xk6jzVbVnnWEsvfR8WiylcU9ySfGjYVXEizfI+8onMGk5YG0tvOcMcJ/cgM8ahVDUe6GC68VTKVzQbtneszlPPc5GQcTFfxXxVvVE4UA66jdfSMHzDO/6KvlsrKRldCYtXTUVCkXxD5K8RGDA2vUafwa/lZV6hDteEDWkSZH6I7ApWYfwt6lc9A/0aCbV8f8JKuOEyO77Riyucgi6KIBZr/PD76C5o/HTajBYF3oVBWDsquPKtYt1eZHC3Wbwex63t7sJrcPUO2185YWqt3zsIT7YZJNHpYGm0sa1aCxaQGxTHeSrG2db23d4QM4ifdOaBHJDi16SS1zM9LbUVnAUufH+zZ2bIRYBTX/auzBJK/zcdv5soQJvIVIuXiYoHz2qNDq89hW6FXAV6vvELK3qjmSH7/ownROzeVTTGoeB12w7GfdWa1pwvBMF6ZB8gyjkJM4Tbbap4i7Fef2nFI3r8WkgHEc9QA0d9HM5Lwbb+BIdfhyA/olY+3VRhdbBjpqh5SPSMFa7iLCXy02sj1b/wQuOOLgiEgkHbOtqjCEviuLzVGiCwIjKq5o9TmW+oP7LaCWnucP55vw6F9qqxABUiplSbSg+BuqKPYPwzZLY1ICYPUWfhbNHw+0M37ortMkE/yrP9w1chFzHwBkctjKEn6hjj6aXFZWnKEz8rpUwlnbvnskw82e47wzBoZuPHKgJ9zRg8sdx0f0kjzHZBC1TBdv6Qfw+2sRRx+bgF5crSqPAJruKArEDRDLOobpbJt6VM1liFILSh/UXWk3d46o3C02+PiM3RHeIEbfCSURD/JKHtEZ3NouohEWkC529lZWRKc1ieZsRDIkUS/ujf2SO8A9Mv8vDahrQscF2aDO54dntxvxq9gLK7KJjjB/RwD5k3s4EuavNW4B99Y2p/fjK9OTUFxqCIU3iJ2mayNlY27nwvj0s48878d5WX0MFSq7UhLOJMA+gRqWteab8gPDrlECjtC64RpSXEsWWsC8hSdu/o5+md+QfhOATBUMrCeVyW+FXT02aGpTHZmfuxK9uh81y9E89I1CuQs9E3ydJyli2vZ1+g9AcJUjWbDE9+p3+m30PSPrh18MzuAtizGTuvtB4EXV/R3bu+lCVjDc01YXNXyseFTAWPC76ZzREQW55wq+5WTURNqMpfm4+cn/AMrd0Qc1BZh/E7WWuW+rPIeGHhMmmMqfUUYjAKXsOycGSeSr8W2DYykTftsOxdtBM9W2F8ahXCKzjpfut/TvPMUNC0usNq5kUqpUVe+rYmczMgG5Apig9lUmkjbreQjOcWs17HZ06IXVd+hE8E3kqLCOB9CBAZtwOtHNoZJx+UcwDCEL+Zpn9cf9E7t2jB41PS6wdcEp0vnK7J4olY3ZaI0lSLiNgYfiCH1Y5bzxlhRB46dC7s+JiEP10bAlAXUvlDyyAle22hBWZzuGdC7adR3I73MT6G3EO6+aNLi6nqsLR7Waals1wplfNB/TeJAhzCYhP73rTs4TDin1zp5+wWHA/xQTmFWmUXWJUnrQwLwvWuE73RHjv5L/GG8Cv4GVjduw4l2ACdpwDhMAg+LBnUeNT1DnfeVBVTRlomE1l5+iZ+YDh+Lk6QL+u/vcAzEhzTC2Z9kIBbToeuBNf9Qm7oaag9QXxe520lxkiP0nbTJ6mKGOLvmm8m7OnQQtEH25byT4SoVkW1DJbj5YPxBAACAQMEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5XxAXU2VjdXJlQmFja3VwS2V5UmVnaXN0cnnfECcAEAAVABoAHwAkACkALgAzADgAPQBCAEcATABRAFYAWwBgAGUAagBvAHQAeQB+AIMAiACNAJIAlwCcAKEApgCrALAAtQC6AL8AxADJAM4AEQAWABsAIAAlACoALwA0ADkAPgBDAEgATQBSAFcAXABhAGYAawBwAHUAegB/AIQAiQCOAJMAmACdAKIApwCsALEAtgC7AMAAxQDKAM9YQ2xvdWRLaXTRABIAE18QEFB1YmxpY0lkZW50aXRpZXOhABRPEQCVYYGSMIGPAgEEAgEBBCDX4Lqi2liRQKhXA2QYm0l7edIQPhVLwuk/TWLlyAT9PaFlMGMEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEgwRgIhAL2uoy74rk2RNImZA2BlpEt1lbYXDjQDLVWFl48ZiGflAiEArkFMxuEWlWOHBtNjjZ44fmxKxWsZi8+NGAHfBCd+IAVfECxjb20uYXBwbGUudGV4dGlucHV0LktleWJvYXJkU2VydmljZXMuU2VjdXJlMtEAFwAYXxAQUHVibGljSWRlbnRpdGllc6EAGU8RAPthgfgwgfUCASoCAQEEIO1UvRUh4/dXuAP2OSJpa7jHDF7bXm3c9qaZLQs2jZYhoGUwYzAKAgEDBAUwAwIBADAnAgEGBCIEICjCewMW8hJVh8JtsP/nRPnVlJnO3Th1oiXl90mmYjz2MCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTMwWqFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIhAIt+5X8e6Vvnhatzyk23WJszwgW43pe+QOOKOKvLLEZWAiAd9pVNkT8XZvTaHhdoA8GLVggO8wCjJzF33KVdAjVyvV8QEEtleWJvYXJkU2VydmljZXPRABwAHV8QEFB1YmxpY0lkZW50aXRpZXOhAB5PEQCVYYGSMIGPAgENAgEBBCAZ2Mqr74uDcAkMedabKkMBE1YVv3r9BY+ZQxiztbxuOaFlMGMEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEgwRgIhAJSI7dsRXpoxNc7bFCtPFSDwUrWlwNbNoa+j9VpBg/nqAiEAuj1iKHKO5ixZ92iBCwS6tta9CNYL8DZMMoJYhrkgLSBYTWFpbGRyb3DRACEAIl8QEFB1YmxpY0lkZW50aXRpZXOhACNPEQCTYYGQMIGNAgEHAgEBBCChFkKqgrWzOfMgBCCorBsVT8hy+zmWs15UbouBPzHsGKFjMGEEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEYwRAIgJUhOSBsTLydtk7Xu0V2PP7A+Q3VoDsDrJTGWbd8z01wCIE03dzox48zVifu5Uo5LPTqD5n1HxwNX21flE1bs+W8YXxAWY29tLmFwcGxlLmhlYWx0aC5zeW5jMtEAJgAnXxAQUHVibGljSWRlbnRpdGllc6EAKE8RAPphgfcwgfQCASwCAQEEIEL01a5kWCyuQN5cUMudqRaCgjgv9xfLP6bjeULYlZQkoGUwYzAKAgEDBAUwAwIBADAnAgEGBCIEICjCewMW8hJVh8JtsP/nRPnVlJnO3Th1oiXl90mmYjz2MCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTMwWqFjMGEEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEYwRAIgajftSwxdvsZot4HBh+DfTZNYa/TFszpcO6jGL9FfT1UCIE5IPiizk1f4ZNiot1F6sJNDl0RVJwhZpHqfjlIBMO5GV1Jhd2hpZGXRACsALF8QEFB1YmxpY0lkZW50aXRpZXOhAC1PEQD7YYH4MIH1AgE2AgEBBCAO/9RLJMcHo3qhFeFb3qanoK8t49rSDrm9ilPvAeiKJ6BlMGMwCgIBAwQFMAMCAQAwJwIBBgQiBCAownsDFvISVYfCbbD/50T51ZSZzt04daIl5fdJpmI89jAsAgEBBCcwJaAQDA5NYWMgT1MgWDsxN0Q0N6ERGA8yMDE4MDkyODE5NDUzMFqhZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCIEqa4Rq2iCw3ULDe3577bLpHuUyRvUDtEKE0rS7H4IIGAiEA4yG/enWyQuz+TacBVbe3U0cZ8mNarFnCWvjagNZ/BU5fEBxDb3JlU3VnZ2VzdGlvbnNQc2V1ZG9FdmVudHMy0QAwADFfEBBQdWJsaWNJZGVudGl0aWVzoQAyTxEA+mGB9zCB9AIBMwIBAQQgrzTyQdcce8f+FDq/uSB/9FM1Sl/kKb5ql+zgzpXjJKygZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiBnyilDS8GYaSIvTiKxLZK7Ae686XT0cf53PqXed2nqZgIgKyFAcdBAD7JRtU62B0izaNFwrReAtIoU0H2iTwQIsqhZTWVzc2FnZXMy0QA1ADZfEBBQdWJsaWNJZGVudGl0aWVzoQA3TxEA+mGB9zCB9AIBKQIBAQQgv6uQs7cTnM64Te8OT8U6trFqk03SERobf9vvoTbhqd+gZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiBAnAgyWAjqzPKgZ3QOwXhEIfIu9MHBSJN+L9IcgtVRHAIgHaRrjmDqvIgsnVwq2ZFDjgiyve33DvPQMWmg0OPa9ihaQWN0aXZpdGllc9EAOgA7XxAQUHVibGljSWRlbnRpdGllc6EAPE8RAJRhgZEwgY4CAQ4CAQEEINdOlpTfZX+WPGjvWza1yiNoWWvNZO73d26fN5jorlMroWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiEAzFPuXno+O0aMsz+srVMsB4maDlCSAi0yjvsVIfIwcf8CIGNHoY5q0UT4K1C5rPu4v4k0SgXRHT7UzKSgdFIeo8ilXxAgY29tLmFwcGxlLmljbG91ZC1hcHBsZWlkLnByaXZhY3nRAD8AQF8QEFB1YmxpY0lkZW50aXRpZXOhAEFPEQCUYYGRMIGOAgE/AgEBBCDyKeoxY5kg0jXZokvw9XIZk/dXsLybRdeGyOhCRXTz/6FkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIhANGlTEY7KpACQHm7qcSuuS/j63P5/AHuM/CFNtpxHPs2AiBB4iFuMmexGzcAdxjD8AweXzf3BuT2eAMPveTum/AsYVpDb250aW51aXR50QBEAEVfEBBQdWJsaWNJZGVudGl0aWVzoQBGTxEAlGGBkTCBjgIBFQIBAQQgAApHNADEW3GPIbDN5k5YGCaL6IT0o+kCI6NrQYRiRqGhZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCIByj6JhH8huGOaKq1FwtyCx/e3xWDS10/78Z8qZuJtzQAiEAzt7mRHE13w10++4iZXLTz51rbJFmhmXcWikhHUNRmgVfEBZCbHVldG9vdGhDbG91ZFBhaXJpbmcy0QBJAEpfEBBQdWJsaWNJZGVudGl0aWVzoQBLTxEA/GGB+TCB9gIBMgIBAQQgpX7w8xr3w20QI6XnHPfuzPon+MDv7XVkPLzm9dS9fqSgZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWUwYwQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEESDBGAiEA/g5zMFs3ClwqTTe7zg0qAhZ7jHh60Fdx3RO1uj7Se1sCIQDzZgGv6NIRmlaGUEDAzA8useGiC2Unr/qvh9Us8RVPT1hCdWxrTWFpbNEATgBPXxAQUHVibGljSWRlbnRpdGllc6EAUE8RAJRhgZEwgY4CARECAQEEIIjdeg4/gqiy7fDwz4QI9MwKeNszecuaMr/paUk5SgiBoWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiEAiDMjZtgfKpEcBClireWIjqO2fxlPW978/Pp65A/g0C4CIEHZ0hu2K7BLGBUiSojr31uFq5FE4eM72vjwWuOtMmVwVkJhY2t1cNEAUwBUXxAQUHVibGljSWRlbnRpdGllc6EAVU8RAJRhgZEwgY4CAQgCAQEEIF7MMhZ0znob8oFdqF6N0OD5bTo8hk5GrHzTwcGT4nZ2oWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiEA8XkD8dxJXiB+2Cn8k0m3didw3pRo7tZ83a4smkVVu0wCIF1vJvVH/v2rgCcy/4MUKxHbviP+dzhMEmXnaWJub6L2WUJUUGFpcmluZ9EAWABZXxAQUHVibGljSWRlbnRpdGllc6EAWk8RAJRhgZEwgY4CARICAQEEIGxGz1ZMgHL3aYgxV3pRG15JTGIDBGkcQqJPWTLQxk86oWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiBAODn1LywOgNLg6QUkoII4ij/SCQvLuiVsDR5ttGps5wIhAI41xTXyV6791UZyVY2A3gU9YgcxfdezpAPiH6GkkWz2W0FjY291bnREYXRh0QBdAF5fEBBQdWJsaWNJZGVudGl0aWVzoQBfTxEAlGGBkTCBjgIBJgIBAQQgKY6oKz6mSwVVKOEoS+1ZUF9eMywc4I4olT+pHlhOexuhZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCIGmjnKNWoi/Gyiyl7+FploOpEcExUI3WTEvhkSCZsXtaAiEAwHUsRvjfIqI1BXUQDJRqoMzGTFcSmQ4r4sn+ztGDkfVfEBNjb20uYXBwbGUucm91dGluZWQy0QBiAGNfEBBQdWJsaWNJZGVudGl0aWVzoQBkTxEA+2GB+DCB9QIBKwIBAQQgjumFy/X+D5JKBQkzmE3oz+ePP/p9kGC8nr/7/etLVUigZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiBtVhLAHrqTIUdb+/tUcVgeQKLJ24YJy7njNBU+MSGBYAIhAKJE9Ae6mvqUDCYFYicuPJiTsE2xU1XDfQrM9XG8Q+vsXUNsb3VkS2l0QXBwbGXRAGcAaF8QEFB1YmxpY0lkZW50aXRpZXOhAGlPEQCUYYGRMIGOAgEXAgEBBCAjsVTQ0pZmrzPCJAdrUjU8RDTgE57XNKIyvXPY0HkVhqFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIgfrBiTRmWf4KPF+HN26p3jCAjdIeTIySYCHoXSYnuDxMCIQDPm8w+aF9D5f8nZdPGAJgZGf7IfYYej7uksgAfWpiv6V8QF2NvbS5hcHBsZS5zaXJpLnByb2ZpbGUy0QBsAG1fEBBQdWJsaWNJZGVudGl0aWVzoQBuTxEA+mGB9zCB9AIBLQIBAQQgjiguBlj9OzF7ZybgF6clZEcK1wYRTH9XxL9RDS9hxRigZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiA+pB3ljZygNgkYh7TrLE4OyijDjTn+SvMJzrKQZPnfbwIgSkaV5AWx8zm23PUs+t1hHwIvtmeojmfr1Q1YqwGxa/xWR2FtaW5n0QBxAHJfEBBQdWJsaWNJZGVudGl0aWVzoQBzTxEAk2GBkDCBjQIBDwIBAQQgyW48v3kDee9VM/MD1rpChNEmWP0LyJQOBn5FctdNnwahYzBhBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRGMEQCIEqwVkXMaMdfwnbQoaA2F5mm4/GOL2WAUizoBzHSMCkKAiBJKuiiJo5b5pVgZHsMitI1MKksobbibibV7sdE1CiKWltpQ2xvdWREcml2ZdEAdgB3XxAQUHVibGljSWRlbnRpdGllc6EAeE8RAJRhgZEwgY4CAQICAQEEIBc6U2wxA1UlBRj52pwa3f1dRNsNVPaSyAQExW/I6OQ9oWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiEAgv7WXwyxFbes33Ax4zu1KKdqSn9zb8OnaQ7xnw5kHFICIAvXkgL8KsmCRAvJLitqsZ5OYwUobPfiL+NDUBAfNDLRVlNhZmFyadEAewB8XxAQUHVibGljSWRlbnRpdGllc6EAfU8RAJRhgZEwgY4CARYCAQEEIGoo/uNv5M+eGFOm/OIf0sbhoNrqLUgMsma0UGXu7sBcoWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiBhPW1rmcHkbUZFxxLNfKjzia/FvfFN6pJXQc3DfM/25QIhAOegBT7cu1cORUrifnW18tevddkhUTA8YiYEH+naobFBVU5vdGVz0QCAAIFfEBBQdWJsaWNJZGVudGl0aWVzoQCCTxEAlGGBkTCBjgIBCQIBAQQgiiKf8iak5uCLn/0lo/I9WEGums0ZqQmP2yqv4IjummahZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCIQDheScSZEg18OoTUhfXiZMLeXCkbDDFdybgySv3wRltZQIgAY2WdVPl88rRqeYtQOmIBO1VaUfW7SOv0EItomWxQAJfECFjb20uYXBwbGUud2FsbGV0LnBheW1lbnRzZXJ2aWNlczLRAIUAhl8QEFB1YmxpY0lkZW50aXRpZXOhAIdPEQD7YYH4MIH1AgEwAgEBBCDMr1rH/wSxKnXhhMuq2kmQAsbuu8aQ7CUjAaP7ltmt56BlMGMwCgIBAwQFMAMCAQAwJwIBBgQiBCAownsDFvISVYfCbbD/50T51ZSZzt04daIl5fdJpmI89jAsAgEBBCcwJaAQDA5NYWMgT1MgWDsxN0Q0N6ERGA8yMDE4MDkyODE5NDUzMFqhZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCIQC2O2y2BdX70rfntL/TRaSfQ2hi2HDlJRcDY4Ac7dTNDAIgMCCNLTjH3w3yanomcdUpUYpUXk0xg7rmWv776V2/ph1fEB1BY2Nlc3NpYmlsaXR5Vk9Qcm9udW5jaWF0aW9uMtEAigCLXxAQUHVibGljSWRlbnRpdGllc6EAjE8RAPxhgfkwgfYCATQCAQEEIN5dPjrSty+MgOnxokT64PDUkrKiyt3k5oI38p5AnL6SoGUwYzAKAgEDBAUwAwIBADAnAgEGBCIEICjCewMW8hJVh8JtsP/nRPnVlJnO3Th1oiXl90mmYjz2MCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTMwWqFlMGMEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEgwRgIhAM4B6CLjnTCbliTZC27uxJ/j+MZbMJZTRrgU9FBIKAJTAiEA2nI9I5z/KIIgh91hQusrBxnR2bvXR60pgU2K2u/xVHFfEB1BY2Nlc3NpYmlsaXR5Vk9Qcm9udW5jaWF0aW9uM9EAjwCQXxAQUHVibGljSWRlbnRpdGllc6EAkU8RAJVhgZIwgY8CATUCAQEEICY5ub8AyyEI+KyHDtmPlWoXunETPtY9gVChN01YLo+SoWUwYwQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEESDBGAiEApRyxYMo9vBC3ZMsebZvMNZNWDas5ituj7iwazSxPlqUCIQC/fHWNj8T/Fc0lt7HujLvHR0urgUaY0kUdYtCsNB0ZHFhSYXdoaWRlM9EAlACVXxAQUHVibGljSWRlbnRpdGllc6EAlk8RAPthgfgwgfUCATgCAQEEIN+LU3LnH9Fph0sdZb7EVs3D3RHlcJzmKwc3q52pobIqoGUwYzAKAgEDBAUwAwIBADAnAgEGBCIEICjCewMW8hJVh8JtsP/nRPnVlJnO3Th1oiXl90mmYjz2MCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTMwWqFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIhAKUXaMJ3HvqvjHbeLywEubqzKJBhiG8+YLZsS+fE+TFqAiBSD/AsQsZAyhF4PXZKKJCCUiAo23NK4KBF91SMBgHt9ldTaGFyaW5n0QCZAJpfEBBQdWJsaWNJZGVudGl0aWVzoQCbTxEAlGGBkTCBjgIBDAIBAQQgnoppjpqaZxLn0vbgK1JvD02fAEH1dXALMwjA/LiaDfahZDBiBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRHMEUCICMsr13SCWNkUUHAR6O1H/Ks2cKtxmB6isgm4d76IkdoAiEA/3IGnk6BOWe23sA+nrz1Uj0l8AXOzh9BSRcvtYqgnDpfEBljb20uYXBwbGUua25vd2xlZGdlc3RvcmUy0QCeAJ9fEBBQdWJsaWNJZGVudGl0aWVzoQCgTxEA+mGB9zCB9AIBLwIBAQQgWyKU+rabc+abidF3WG3EIjgU/SQ7R+KNVvXp9z+IST6gZTBjMAoCAQMEBTADAgEAMCcCAQYEIgQgKMJ7AxbyElWHwm2w/+dE+dWUmc7dOHWiJeX3SaZiPPYwLAIBAQQnMCWgEAwOTWFjIE9TIFg7MTdENDehERgPMjAxODA5MjgxOTQ1MzBaoWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiARBSYZikluYbi22N/VtgLjme7DMzsE5GvwZWjmA8P6jQIgTbLqYOOC+d6208tPiSLUATikDxTMkuIIDPt/MRIdaP9WUGhvdG9z0QCjAKRfEBBQdWJsaWNJZGVudGl0aWVzoQClTxEAk2GBkDCBjQIBAwIBAQQgnGr90u09c1SzPQfPLcly0+mORo0Q9owsw3ZSrGHX4bGhYzBhBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRGMEQCID8A1iTXEjdvswDeOx4NFHG58z0WxyQUdyaw6QThJ+6WAiArTTqC7lRMH6l+4wNn1+7KEFVH0+I/8t+AuQj6yGysS1NpQUTRAKgAqV8QEFB1YmxpY0lkZW50aXRpZXOhAKpPEQCTYYGQMIGNAgEQAgEBBCDcezl6FqtGyHkX174CEG8VSAOi4P3lIlFNO4qJfVX0saFjMGEEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEYwRAIgQvuSzR9rw1O2ySTcaQADxxJd1GuffZ2cxK1kGvS45cUCICC++3nOux4yl6TGku4P9QDla3NQp/7hH+lKmOIpvcOkWE1hcHNTeW5j0QCtAK5fEBBQdWJsaWNJZGVudGl0aWVzoQCvTxEAk2GBkDCBjQIBKAIBAQQgA2oLaQKK2tnS/GIAxrnRhrPUjQ303ZRJAJhXBA2FUe+hYzBhBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRGMEQCIGCGZznXFEVTtJoN5i5gdzHKRSLYk5abL9H4UjZbiWR2AiBF9jxPIXvjeD0ixKuBw4y9jVcBj1+5n14UEf5q3aw/pVROZXdz0QCyALNfEBBQdWJsaWNJZGVudGl0aWVzoQC0TxEAlWGBkjCBjwIBCwIBAQQgN2Zh4eSsuL19w0oUZ5VLkTxCC9ZP4OLbySW5BeSH1VmhZTBjBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRIMEYCIQDHk9qh4YVU22/9JheSDC5ZTgi+MJY0U01Ss3NrQ4XVSgIhAICVS3XDPdHft49emcZRdfeZJ6Xx7P/XaK9cBCIsXRI2XxAZY29tLmFwcGxlLnNpcmkua25vd2xlZGdlMtEAtwC4XxAQUHVibGljSWRlbnRpdGllc6EAuU8RAPxhgfkwgfYCAS4CAQEEIIzfihUm3ifzPM/Y3McNooAPAToGowS9Ztc9ecYuIl/NoGUwYzAKAgEDBAUwAwIBADAnAgEGBCIEICjCewMW8hJVh8JtsP/nRPnVlJnO3Th1oiXl90mmYjz2MCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTMwWqFlMGMEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEgwRgIhAP4c0nNzBSGf7ycZtiZpexiCNQ3kgYG6HAaSTCzdbrqkAiEAgdJu5Dufqn9GSOwo55U6rbllwv7eGJuIklki80Sq1JRfEB5jb20uYXBwbGUubmV3cy5wcml2YXRlLnNlY3VyZTLRALwAvV8QEFB1YmxpY0lkZW50aXRpZXOhAL5PEQD6YYH3MIH0AgExAgEBBCBjOqSZoGDwScKt5ncrZEkl/5e43V/wCItiOI3ffCu3XaBlMGMwCgIBAwQFMAMCAQAwJwIBBgQiBCAownsDFvISVYfCbbD/50T51ZSZzt04daIl5fdJpmI89jAsAgEBBCcwJaAQDA5NYWMgT1MgWDsxN0Q0N6ERGA8yMDE4MDkyODE5NDUzMFqhYzBhBBQBooabXxCiCkCbBNbvACGlyp96aAIBAQRGMEQCIBbcBuaykWaCE1IFXL/4nmckm8tSDLnSLUjeT2YtgVB6AiA7S+NREY9sOh3WrB5pVpmZfhd3Blv6JbeHkBsMjWDCUl5CVEFubm91bmNlbWVudNEAwQDCXxAQUHVibGljSWRlbnRpdGllc6EAw08RAJNhgZAwgY0CARMCAQEEIPTMF9d5k4kVLyhcz+Evysf0dozIoF4eg4ox1/Ay0Cj2oWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiBv/ZJx4OrvkvTubO81rciCeVSHyG+UACxMk/Ia2AUk3AIgY1aRKVg01AQZRBlH0YdWAhYwPxxxEqPPXuQy12glKQhZTWFzdGVyS2V50QDGAMdfEBBQdWJsaWNJZGVudGl0aWVzoQDITxEAxmGBwzCBwAIBAQIBAQQgwXd5uFhTeS7Kx8Qpj65nqUa2Rw8seul6PEhU0/LvW6agMDAuMCwCAQEEJzAloBAMDk1hYyBPUyBYOzE3RDQ3oREYDzIwMTgwOTI4MTk0NTI1WqFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIgfXzk2iTJUQyvhZKLb85CbowdarofTgcdwqpizaYq8tcCIQDieMFd3JCMHc5P2DZBmS6Ej/RocbKGN9MkCj6pGc0BEFhpTWVzc2FnZdEAywDMXxAQUHVibGljSWRlbnRpdGllc6EAzU8RAJNhgZAwgY0CAQoCAQEEIMr5O+MxnSPOECSWwa6jWdtSl8CxG60ieEJrS5eT8csDoWMwYQQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERjBEAiBoNoyLhIzMKe8exDIHiT3gFobrLfgVsHcsOUxPalrsRgIgckaB3CVttF8XJjOPTyiF9ekJFtyTlqRNsOQ7FFgh3IFeVFRZQ2FsbEhpc3RvcnnRANAA0V8QEFB1YmxpY0lkZW50aXRpZXOhANJPEQCUYYGRMIGOAgEUAgEBBCCNrMVagA0+ttQkY4NGtYqj49b4PHHV7YFaAHyVd9vodqFkMGIEFAGihptfEKIKQJsE1u8AIaXKn3poAgEBBEcwRQIgAUD9nE+lBkcEnXyL0pcE/LE4diyBd/UbosjHyB5j22wCIQCUcJfgxHVChg8Ae6FjMuYjf7cVoyNf0YmuUEWkmwvoIl8QGVNlY3VyZUJhY2t1cENsaWVudFZlcnNpb25fEBBpUGhvbmUgT1M7MThBMjE0XxAaU2VjdXJlQmFja3VwU3RhYmxlTWV0YWRhdGHSANcA2QDYANpZRXNjcm93S2V5XxAsd1ZLYjEyZ093RUV0amFmVGMyUmd2RCtPTnROekZ0Wi92OW1Fa2YxRGQzaz1bTG9vc2VMZWF2ZXPfEBsA2wDeAOEA5ADnAOoA7QDwAPMA9gD5APwA/wECAQUBCAELAQ4BEQEUARcBGgEdASABIwEmASkA3ADfAOIA5QDoAOsA7gDxAPQA9wD6AP0BAAEDAQYBCQEMAQ8BEgEVARgBGwEeASEBJAEnASpYQ2xvdWRLaXShAN1PEQGhZIIBnTCCAZkEUwEA7mcfkI9joA5YRiHMKVPYdCl0EZbdHHSkd+XbtD7Mz1swmsOp0wrFLe6Vs8Fl/eLiARGAoFbEyqKuOqGBvVJcANDyON1SpccPYyE+m9Fv1N84BIH68b9LFxZu11g2wdpwAoLfHGAIpixj/l/ExdN1SejDh42zj68oMRJipC5Pzuy7Rsfo8hBqDgSCZQ0ASzcyZvd/r1eUVlkPdtfW3e1G8CiLvEJjalHXMK/q+ZkT5ix5RrImOK4L8KpwVcLyYf6RxPhvLtQIFuyDWZ/zcGeOQfXbEU0N3DEcM86jT5VpOVvbejiFABDV2auJtxAzcbPoimkyfQH6B0hb7J4MoUBqojYp3/WbXgd+xsZueOYaioaD5F47gGJJt68vV79KNCrerlvSaoAAFZMT3aj1EfjWzc2Q+XU2ugjdA7yNrxDXAtzteqcTbqVa7k48t+smmgQg1+C6otpYkUCoVwNkGJtJe3nSED4VS8LpP01i5cgE/T0CAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5XxAdQWNjZXNzaWJpbGl0eVZPUHJvbnVuY2lhdGlvbjOhAOBPEQGhZIIBnTCCAZkEUwEA7coGYUYS65YHnBubKFI66JIshlD/zcZadtS7UPht/gQw4Na60gEDpn3LLWAPmNzSU5aFq2i5FdGApmZz2ZjxJhKs34OzsSz2kh2Dpg1xkYYABIH6KTIPWejPTEmBIMu/M8MHedxNSBN92aCUaaFKlFpIEfr4ERxhq2+7aqBDUod+agFjj6BzEi4NBHu/j4LZsb4fcOMwq2G594K7cevsVg5hsWb800lTOnIWzgnPfk//T7CYB3S5UnPQnLtORz7gQZzWlqloHJSGltcXdt9nF5hOsawKZttCDaL60j00MtfeD0WO+aLl2BmD8syaCwNFRCG8zplq3ot9Anh6xzoeTGzljjuYmPQPAKVFkUNyBI81ZK04m9wxPUh164CPXdv2hsm+zGqNrTX1sny7hlcAVbMXspR54l7EpBlHw0hO9D+2wtrfI4cwtfSpKFG9oAQgJjm5vwDLIQj4rIcO2Y+Vahe6cRM+1j2BUKE3TVguj5ICAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5XxAQS2V5Ym9hcmRTZXJ2aWNlc6EA408RAaFkggGdMIIBmQRTAQD+0aNWKcvemMMRA9pFVsDUo4dRRagvLY7giYyVJk9DGjCPLe5WaLMKfACvgcKry1B7M5fpGavtRgR/gJdVDfQEK4qtMLiIjC2a+pa6TrwWHYwEgfrcVDNNsthPPweZ4CJ5B4Xu+Tf0c5xbWAki7icWTyfHWxz6wDnohZwVlgMfMmxq7KSPPix7NMT/jkKumXeqIKCcCB1Db19CcNmxBU4YKFkj4fzd03SWhu14Lg2zGTEQ5ZL5yw+8RhEQBxlYDPwLZyXYwQByuEqoBD7RDGKisfkKiJ/4z36edNEAA+ybDUw6oDsk15xF/BXr1bxKMAPx8lzHjqEf1p6Ed3R5WDFRnP2qhepVuM4QUvZnHVpi+pzbAbJYRQgOZ0JKh/cNhn9Tx48ZC15eNN25p60h9MM3z7iAT38A88OJU3PApplBg4ayGT4NnDvB505DCfTCBCAZ2Mqr74uDcAkMedabKkMBE1YVv3r9BY+ZQxiztbxuOQIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lTRkRFoQDmTxEBoGSCAZwwggGYBFMBADALK4P6VIMHF0WrlDwXMlkSmmiK4UrYTX70EjtqQRypMPHWinluqD956QYjJ14BmQKITJOVQ9s5S3f4x4Deby+FsKEdKIU9nGY2B81BvNT9aASB+U0dId7UXZWqfMDkQghIaEWmTl6Mz6EC3OlEG9OsmykhueFqliHomAw2ATUidz6p+6UyMW4csYOevYg8JwVpR2XDppW00D3j8dq/kMrLv2vD3/kvSGAZM+gQgaEvIiu3e2aJ3zuj+jm7lx0FyFHg6ngqhQsGCFbJQwVYsssL/L99M5igfhrOQiJcK5A1Hlxo4pirMp7uRYIYTijXNYa5n5/ly1fB7fnkvEpHI5rmeDQIsuGGacihlV/FRAu1rcJ1UL+w4+/gAUPnWWGWQyDJEWC33/LD+L4s6gyvP8Fzir9OrAaUhtWr7nlq9DuY18S3R7akI4xVP31zzwQgJH8/DbB4RLDJA8K/pSz+nX8BBr7PNwXtA8BvjsCNxlICAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5WEJ1bGtNYWlsoQDpTxEBoGSCAZwwggGYBFMBAPDFnDgLhUc74GG63drt3QYvw9VBWfaKjS9hHU4zO99eMDk0m2wKsoSGFnecJDcG8IeEEGTeWShHL/laSDi03OYIPXRfRgLau4lkJ3LS5SP0WQSB+eP37P0MM60iYXp+VNYrJISLFmwc3SvkLXXpIFRWCD9+ENvEGp4O3jdIWaPp3cogXKhyd5C+Zn5OmSKb3FBxaV4AtMMMU4Aw5k9MhwBDnr8IH9kJ4No6GxaeT8KR4sJqgiOEZbTFTMJ57+L4fMjPFmYoXrGRFzAYqkt4JlkZON3QUwigMx4Sj5UfNr2Rzk4iQ249xMKZ7tjI34zBSwvcIvg3LpPCtmumEauDeb6C0OQIryjv61v03uz+MKzm4AhLU1mWRE0JhEIzGu7hqgPKw98qFl1/k3FSI9QYYKbAiVE+pMmBL7/GOavaAmDDC8vuqNra1OeoH6tcTAQgiN16Dj+CqLLt8PDPhAj0zAp42zN5y5oyv+lpSTlKCIECAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5U2lBRKEA7E8RAZ9kggGbMIIBlwRTAQBPXIy3tf+0RvkMYIDYE8P3ODA9xrVmBM2IVp0LO081kTBDOW39aaiT3AEWdm0EXV5KgPBb6GTJZIeowtZvDueEMIYWwrmaHFdIPazKfZ3glgEEgfjd2sTR+RY576H+T+2WwDQr4xUriaMMZf5Ghv3toN74ArmFHhN3xM5M92KUx87ijkOlOgNDvDNUX61ip6wu+JlxMuVu0r7z44hvHHs6mtV3GnwvVRBxFEN7kyvMSmfJQZp39WYi+oFYldUf4hqotdMuGxVPVfBi9ozdDaCTeHcRgDrONMtQqX8ZqCIANKYlScv+zPp0jzV9eGy1xbAQu+/EzVWqkEhk9AncT1c81Nf3puDq12wfXHLN7OqKNqeFw6ohhxHx9u4+hy43bbQsk5nz2TSBBNhazBT1XvurDxMKIG7ooEvzaiYg1/nWgDdxehIyNAJAGdSX5AQg3Hs5eharRsh5F9e+AhBvFUgDouD95SJRTTuKiX1V9LECAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5WGlNZXNzYWdloQDvTxEBn2SCAZswggGXBFMBABGSg5qvbVq2huEN6LUJ8YQyv67PfpehHqbUNCRf4zwoMOLmtU9YPY/yAuDjpPTxFFEIseEeVWAk7LRPR7XVQuwIYTiGxVKfivJrN+iE43q10ASB+HoGSBviZC139p/VgkB79lHv3MOkm8RJirazbWH6rPOcfa4YWS2hGoOeZKO4av+Z70cgDdDDB9Q8VO04qXnE1s+MHuRUR1p9NNjzOE6jA3Iu/9PmevlAEMF8xfEsgF9dltlGZ7O/JiigiwljAX7I9g77tbGm+yyJ+HmR4jKtuW5PsObNpCP1+9nnunnjRqoT0tkMeWu7h0pLkP/jmE1BvL/9wM7G9Bs59IKZUu6XhVzQJvxcs2ITHlkFmz5VnPB3Q7Ic6aQm6l5AW16uUs5W4f+vKUzBwF2C1qlrFCxJILTYLv8wJuNOSw6lP6V29TMyJGyQG7LxqYnvBCDK+TvjMZ0jzhAklsGuo1nbUpfAsRutInhCa0uXk/HLAwIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lWR2FtaW5noQDyTxEBn2SCAZswggGXBFMBAC/aj6MRkzpaEJoPpOb/S/QytRVQyyPeCEqNEiJdoCFrMHvz04b+FMGAL2MtedSWJ1V0RqSIJVwod8DJkZ/x3gbdKcKHlXPEKbcOtA7Pfe3JxASB+D4t5omz0TG9dfJxs/g+AOW85v/fkmclvJV7K/b2/QqaUBFz98aftiKLBVdyfGIGYRZDZH6AfX3I40rpODRPvjZ6Blxtxak/PFK7w76cpBbbR7O6Hb/p9cjJ9R2JTig9JQq6dCwM7Eaw35vK0B7fF8QAkZgZlBrkf4a3g1sPpC2nln4u2CflDpQpjiVqNNo1MrrFaGrDcmIdPaAiT/D/o5ySmi2yO7ibLcuZCzKVRR6j/UTGAeRkE9J9fKtH1BDul0RIAUp9EjoONdiu14yWmXqhNA6pBfOx4tyS4Nc0YwBktgfZwHrP357bkHKP3sgj8SxwLKg2h7HnBCDJbjy/eQN571Uz8wPWukKE0SZY/QvIlA4GfkVy102fBgIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3laQ29udGludWl0eaEA9U8RAaBkggGcMIIBmARTAQAQnmzAB4p0aaUoHGjNJOmxML3vNV+338xa9iYV1UFqyTDRaBSRUeJ6Ba4coTnGmEBXBz3x8QevxZ3EN+tuDSTxf+hQECGMrT1AUF0oABPqwC4EgfkyJi+JAc64CcmYUhWUfqoyiK/4kfOCReXh+63BzBWgj+3xjxUTzWp5eA/o3rL2IX9WlFUaFWpoPuM2peNUXJyBavA5cdgXlXoeDEYgZ7v+UgjK2MDLRRuufghkafWEoaYUzf2viGgUWfhRgvXXBdOXfEIHEb423rq2cPa1lIy+VU6QGLVn+5bEWybu94NjMK95EjfzI4qZ2YbjOSd/D4BAXy1hxY4ph7f1MqHCA0Rh7n9Yj3/cLFZSrF30fSD3Bvo46VSOckQl//e6hgUtSkCVgvIM/wmUOoNp3VPEv3B1Sa34N6IcdMLvbAcK3RDVOe8cmEEGGJRHrHsEIAAKRzQAxFtxjyGwzeZOWBgmi+iE9KPpAiOja0GEYkahAgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eVpBY3Rpdml0aWVzoQD4TxEBoGSCAZwwggGYBFMBAIren1qPjibvrtAJoHi3Mi5IU4tlJzUovigqzD8Ku3C5MAw3wqdfbMfdYkVeujIzl58mnNit2eDXtGLtaUwPNDb3ym6CZ4A4CLBlxnYqR9EYlgSB+SFcR4rAvBSy5Ca06GL/c2TZLHLucYdb/f0QuNyBEPtVSGML8wpFBgn0TYP63+5hyE+KNJ0KabxG++UGz16B8wdk3pm6iWASA5bWEAa1UsCCNK8A4qQh/i6zzSZEXEKMkblbB9m2k9nuic9y+t9M3OL85g8bdrTxFn5bgo40D5IF/egNphdJRRfJRyEMlU0DsbOysIK63gpPdv11T6kv99UpaYWjFfO/2QpyrTKVW9Bd7hhTNtdu+Jr5fvN4IhDlIDKsw4TKjkiejFyIFtv5WKQc/lCqS2VRzZ2MwBSDvbKAx04Uhkf8AozhVaNj4WK7kvc8LTIPoibsvgQg106WlN9lf5Y8aO9bNrXKI2hZa81k7vd3bp83mOiuUysCAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5WUJUUGFpcmluZ6EA+08RAaBkggGcMIIBmARTAQBDehu166c2isPZKlk6kYH7zw6WpCAjiZhXMh6pjOsypzCOmBL4QxrIAISALLfSbBmRdX7LWbG1WjwnPmwAemuPfCKLIeu6vaq5CcuMknizzx0Egfny3/4qGlCzsFGZSChyjO1fxs2ika5zTxSrmEeIF5kvlDvaMe7zBEgL9JK7Paj5MdTIXwl26Hx+c5qcV1NNW+bixlU40IoIcXU7ZcDLmQ55hFjjf+iatLSsXIQuJJjUAFqXKQEIFBgf/lYLMYBCeHeHqzuVW5i9OmwWXP7DNbFeeEAfQdVJP0B/wI4SmJ3EBMBns5OkEBgP1Je8GZNrFKwHqw92FDzdYsYXPgP5bitrKaC5JEhBdRSPDQ9I/Ys8hpZqDDD/iERkanvg8gtA56I7MGN541vNN2vmvacgUJxCvWOZiHYRvZ+EH4eNTZaf0RfnJ3pU7Nd+oA4EIGxGz1ZMgHL3aYgxV3pRG15JTGIDBGkcQqJPWTLQxk86AgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eVtBY2NvdW50RGF0YaEA/k8RAaBkggGcMIIBmARTAQAiRETKF4ZMSnH3RiEHTO3eBbu/gmOCzZgX0rx8M50YVjAYMKQHhsHqP0VmvVkSDntQyOp2PCxQC2F7Ht49+WjTVafg/Nq0fWss7CMct9M77XYEgfk/kGbcDJpY8mpbXfw7PGx5l+TGZlrKMYra0exutGKC2HcCQ5S/Kxq1hyCYDNUV8FQhNzYXZ5Q4yVfTkur3wlYYlQ3XDHospgoICYhLLsZ9oMNJZ3fliVJFetgeXaaQOMalSRRPhEHZERWwEfo645czU0bewWtXczHstm3upa3yPx9unBP1LfqXvtPIkgw+7/GTLAbEtJQ/lQOOJvJ79nxPVISmrKKQ7H6vv9hjeJlzMiIpwNUkKTPFBsQYSRrhr2vyHflKAzm7LxvOM7+F5ciH06HFwq/ZtipBuWdsyO0vS8uqnaKFP1uUd/sllGtb/zpijSE7VXd7fXQEICmOqCs+pksFVSjhKEvtWVBfXjMsHOCOKJU/qR5YTnsbAgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eV1DbG91ZEtpdEFwcGxloQEBTxEBoGSCAZwwggGYBFMBANoDsK3M5Y5DwFh4EQAyeqPIHYC8sSin0VjallJ64rNeMOU7Mjv5tPa0DGGqqMyvdojXYioGVUuHsJ7Y50S9DCDX0LsRPN0Ve6xqwzt6BLienASB+VfAOuYKiJOZEO2YFPuGAzqYvM2XHzEj27LMOXz8tkXB9ddkW6EAD6Q0Vqn0QPr+qM7yFASxbd8h34WS6Xddz28cY2kio8Xf8S4XTFpN/VgHCJSEBU8rqwUtwtDbH6R9qFVY6DmiyP4r9XCCE44B4I1HEKF9etVmU1HKeAuxg+nhMVhjX3PZYe4xFzaLrUS+1tngTCCW3GtHDWqHp84fBHuLfwjXgblnthMdpGvimQURj0bsOKOU9lv4gjrt3WPosxYc6dQS2dAGwQ6ZhCCO/vHrzq1x6mF+6xLfRbXuWw72aDtYZjurCLrjjboivWneN81l3WTKjTmZOgQgI7FU0NKWZq8zwiQHa1I1PEQ04BOe1zSiMr1z2NB5FYYCAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5XxAgY29tLmFwcGxlLmljbG91ZC1hcHBsZWlkLnByaXZhY3mhAQRPEQGgZIIBnDCCAZgEUwEApcI++fPiMp2F7719sTxSJqaM6ee9DlujcuWuzM6tJVow1MYYRnnH8QbtORp2/ddi/I/oOoPNQ7y8LVOGFVyJoARvHXAuJbiyoT/PNy3FzHjbBIH5rEU6m8vdSuPs0ygcTuIPvXnGDYdkGzx4c39oflgmaFgUsuW++rH1HOa6cCgJ/lstbJUXRWhgoOMro9kMmgI89wzcd5DSBiG9UhQt9ZDVvWz262k5O01os9poHy5QWHECo4HqcfykUXLt/pQUo0QcQ9b4xGRis/X7vzpprRcK8M983alsaJH6Zeh87J6DDPajPfxHN/HPzB3D+GklTSbzm+WRA0d3Iea3wh5edoJl9HSqXgxx4UFnpQyz+Y9Yl467o7Yn42/C+2IvNFRQM98STxWssxamHdoHl5p1rUIUxseaHYCmdhvMUAslosNalc/pwDmXbrlFVqktBCDyKeoxY5kg0jXZokvw9XIZk/dXsLybRdeGyOhCRXTz/wIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lbaUNsb3VkRHJpdmWhAQdPEQGgZIIBnDCCAZgEUwEAhTriZPlk5ba8weQP8abhLwtXIMRdFUPlVDwmgqCY2U8w/ZpeoOaJ5wp+7NNBOQgGi88JCQfor7ChKRLSy0rdlAZDLKEHZiflNJMpqaRLDNMFBIH5Zo4hPORCAtqiKM6BZmXDM4ZnyqLNREjAw8SAyQKqviDGU5f55CavjkHluBLUzvddxRPue+IFc6+Yes+Rs6R0Xj9xZpprfAFk1vusLNajPhT+a4+ChnEtrp5c8keBz7xte8YgPINm9HyTERH4X/QrwHXE0un5d2iU5tE1Q9a+V9FctlUHl4DeEKk1cO6+UdckPo5l/1ozpxscvNptwgfla36ivuZQ8Nawz7Bc9s9EiFRvPa3EaHN1pJOMzJ3eWCqkFy+XheEaF6riryW/Ybl/prjzre3i0EKTzzXObnZ6OceTfOzMmPHKmCj56rjqharVhoo2e8zhwV0lBCAXOlNsMQNVJQUY+dqcGt39XUTbDVT2ksgEBMVvyOjkPQIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lWU2FmYXJpoQEKTxEBoGSCAZwwggGYBFMBAG26kq78j3vM6eU91omcumtqCKKfK0/fo8buyvJLf1E3MCuoxrigFshN7yrs8mBWbA+lte2gqtGRnwgMVOyzoPkrPk+QD+y7F0bC7huKrPHNkASB+Q1ThtNaRvEb1hWcTGJKuMR0x/lzz+jJItKaUW4qr715P0d4twlq+7HUXIBy61hLrttG+zDro66kWrcd8fS3gsnYYi4Jq/RvcUZvAJkZXGIqYA+PQ7L3eAReDZDVko7XOAOuOSMmQXR/hidiVkDrbm0/KRlhBEtsGgLrlJuOxX7TIHR99x34xsqRu3en+K56FOTYK2riK8/LgPXs00yXiWI+HSOACe9iwPBZ5WTTyfqdsHOQlk7iyhyo3APg0iYq3WCRhbrE4yYgZjwcxHx1k1PnRHHoUgjMSZ7CtLCmFMvBsfOjTAeU+6ivHc4L23qeweIor2OSoz4qzgQgaij+42/kz54YU6b84h/SxuGg2uotSAyyZrRQZe7uwFwCAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5VlBob3Rvc6EBDU8RAZ9kggGbMIIBlwRTAQDk3uWPUFMtQRE/nXFto3i6/CZoxi1g1l9e00Sq85dIvTCxs6Jq3n2+Ry3ea3bXVMGR7T0/xEFYPlKrOt1+G62qDzyyGoNW80+JgXMd8C/qzIMEgfij8cfPnXNhj0mE3AIdbwb/+ikfjYfOSVG6Vcs4XLbdDANFR+Ikhp7Y/pjyxNhsdTw1u4oFISizmLSyIh2oMPuVeLb9jry67pKTaM2dFlLax872o4UY7Bm/okYOHaLdgECm0OcRKvuGW8BnwdnKuXxJiLUg3pHQMdqWFMXSTH4r6Lvy7vKqKkEfqhR5hzoa4AViSRi3UTaizpvYzX4f2HjtKSXbWG9qH5QCcxelEe4OEVF01fLou1A+YqUo5K2noDBLclB9MS/WQR1S/btHYylCJvulDBcSfYvQwVBHhAWPVM8buE+Qc8jbmGi10Wh3R1XS/QsrpLYB/QQgnGr90u09c1SzPQfPLcly0+mORo0Q9owsw3ZSrGHX4bECAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5VkJhY2t1cKEBEE8RAaBkggGcMIIBmARTAQDcD+fhaHOfAX8u8vMCFMUETugjEqK8E2pTs5IToVMZZTDmktst3dSrvbFQ8fDicManuZib9o0rgn0EpuyCYoMs1XCWztqfGRImQDvTpcKxt2AEgfki399H04dYrO7yIcRp/thiFBJptag18lGllLUSQ1V70OiMkMl+DwTFxBCw+7olIsWFD5py88RaygrNbQ8ixVvmiKKpThZZ4AZRLktvEAQ0Z4AQ4mpudrQPuJZceSYQa1EqX6tpZJkCxcAalIobL15+yy0Ns0Y5w3iJ6+nwOdKQXBKhD4S+RQAxvUyiIIIIHQ0J+f4wrwsiDSD4yEEeneV/wcLwCJ76ByPmHNV6wx4bqWM454FUTwFLp9R63khahI2GFHIOjITRXmSNrgyvyFjlecHcbTvvRWgPBhiY9CPSOCsb6NLgBCxINbg+Sc3EuAoeT/tK0nu8nHoEIF7MMhZ0znob8oFdqF6N0OD5bTo8hk5GrHzTwcGT4nZ2AgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eVZFc2Nyb3ehARNPEQGhZIIBnTCCAZkEUwEAq92z+A2mGWeeOAh6/oSmx+1nNN8OVrv0OZFF9ACP0L0w3Tq7x0BsXOKji8FqrajsM0b/9vvFNDPKpeD0iM6qgjnOjXhTEVU35BNEd9eXuNpWBIH6NWYRYQLnDg/RX2JWnmomZjRrOIr058bkXVsn7nbECP5XP8UiniHnk1DchxDMlkkmckV9612PnxNyegWg29s0i1hf9s+NLrhk3KQEQ585xa6Ghc14F2oN8M6T1xMpK86u3bO7NeSVJXbst2LqeGFYf6nop176vubd+jrNAvMVemeCADoYLyDYLgNmAPrVfQC/THUMQVMC954K12m60I4xoenEvFOR6Vlg4wyuR9eJCcUhb4+iqBQO62xtbxakcQETMx4GBL/yy69NTEfA+hGKD0uTqiU1PTGmOtUrKTfH6X9y0aju9o0B5jAUMJ6rkOHunLQr6jYvW+L59gQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3kCAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5WE1haWxkcm9woQEWTxEBn2SCAZswggGXBFMBAKt0Mur+Q9Zvqn/voOmB5+uI31pFfEXpXsYscNrWPBnYMCenJjKgoLbzTvEvqPf7NkO8dYmO2fg9pdmEum6OUDLa9l8WbS+uPLypUF8PZvk3gwSB+NSxcQ9cse/8eKmKlUlIIliSUFR4I+ZXetxca3+0h/CTKpbgvw9t9q8N2hjayGyfQ3u2WQfdP9gUBL7d9R+e+MsugAOvX6+hCIGUA8PGmF8nux9GRJ1CL29LyaocSaJDvPqi68lWGadm/VRpgLUQrUiSZqPUkKgc2FQ8nkuRcHv+6k52E/+n+9H6yQXp9CDAdhegfWJodhHweZoCLWL0LIv4nnWdEqEoRIRC7/3ZDBUHxLAS+H1hoGXV1kiL2kA8P6/7daeUMQoBWsxGdz9jZmtwjjWHuA3Znc76wvaVP7J4HSpPFvsigfF4r6Kzb0gNryLTDcXKwT0OBCChFkKqgrWzOfMgBCCorBsVT8hy+zmWs15UbouBPzHsGAIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lVTm90ZXOhARlPEQGgZIIBnDCCAZgEUwEA5QBs7cwCbsgxb6+/WPrQqmz8PyGvRm1M9by43vPoXpEwIvaozyKcDGBuIUOKXPoZHm8qMLwCqjz3la7fD2E8zysNgHx8R94dZs6RTFm00Kd8BIH5+z6ZZmeFMqKu14NIZXFS4lpZ5wVa0dBMzkU34qNbdfzIGnOrtJdvTdBjlt7RBpwjdnxUOm9+v/7OqzfPvu7Jfs7knMiDYNdd4VV1RYSvXngW413oMoWQrgt7Di6D4yEXwB6iCTjo4eRzhwRKqGVXL+MBbzxKbQlQ5T5GmQO26dHeOW2bomPaRP7an00X2C82dZIO4ri0HO++9yhAOptmyos5C36lj4TASVuyHJddwmojRySv1ma4DezRxcCZzY3MF3ZjUIIKpIX5NzNCkFbCFYLz/YJ8vSmNm2TZC4FhwSEPI3M9BwqSdVXzVTO7I0CNU12UPyTaW6exBCCKIp/yJqTm4Iuf/SWj8j1YQa6azRmpCY/bKq/giO6aZgIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lYTWFwc1N5bmOhARxPEQGfZIIBmzCCAZcEUwEApFg3dOexxalj8nUrzt4S8lvykjPlpatoQaZV5jXHutow2+O3Yevp/vk2zN3BZA8Z57Rrirw/eSC66GQAIdaXTkQrQT/4pB6OiKxPo0t6Zy0tBIH4khoiH57Ia4E8v4OSvsWDJhdW+VG62anIBrNq/VjNYQGe0tNceaXA1xDmmCtATLQzjiZTcHCGXn5whPdXaNBnpWJZr5S2v6zFHbja5DQKAoJN9tX6SiHsnkjFKblN4FzcCXZwtcatnvzn7quAhczRe9MHaS6Fjx3sll9v/fhoVv59f8+NBoQxZKsEJVbJ3JiR2K5Gd5ddwMhckZjL2ukh2zheY7nH71M/0h+5tlvQD2JGAfGjjsIco0wMFkZRcB7TcnklYVrk+pn/Qvz8GAWmrThOJpwoNmYSgaSm+R2M4cL0KLSvuqyHjDHk0dDjXgoVU6FcHhuItnoEIANqC2kCitrZ0vxiAMa50Yaz1I0N9N2USQCYVwQNhVHvAgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eVROZXdzoQEfTxEBoWSCAZ0wggGZBFMBAGy4sFitGVvqnRO1UBf1YHOgmtOogGtCo5Qh8as32kFgME1Ma/ZsIvrBV52bSWUtZcY5n+w5M/5X6IM/qNgNHlDLU9r3gcOu+tMI0YNTlFRAEwSB+rlDPBh4cqnNb3ksAMK9TNo6Q6cNk9Shn4ymCJQ95QCgtEhLdtZvClnWWyvcCKSuVym5aZqme+Ins3kVslJuMGBNA2mUHdLjaQ3utzlOt+hsmwFzLydzWzWwYaF7Eu1a46eJbiat/x3NWdb/AbOf1VNHGigJR/zMSzSZwBbt8CszkqqarzNAJV7K2XfR2gTik8+nFaW+OnjOxpFzcmH6Ba4qZNl32CIAeGU0TCbLQG8PYgMXEnzelBNFWlWJPpHH3AuNZJv5LeckFzxLXrg4U2Rd+i7NPX5sEY68tuzt4M2LQvzdm3FyhL6jECR8Ove9jjQYzZMcr5HciCoEIDdmYeHkrLi9fcNKFGeVS5E8QgvWT+Di28kluQXkh9VZAgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eV5CVEFubm91bmNlbWVudKEBIk8RAZ9kggGbMIIBlwRTAQC33vXBbax4Y3VXJS1T1Sjbp/jl76fAlKU8O5mcnuTxjDCs5+39psW+kv0RCLnmt1oVxZkwD02bWSrIOejWVJzDtgOE9cU4Wa5EuJRx8lxW76UEgfjR9gVrpLBZpLUDh+kCZQsccmm4baTJr4RKccdkXDobqiTf2iPSOL8ZFNblaxaGMzGftgzOI3tlS4ibFNs0VDK9MTKY5UFrHFHowPsGD7KJ7+CVMdB0VQWXGc6KYjMLoCw8JtabxnsENMSvqLu3h/W2MO54BPsmPtTF71bZ5DPH/4n0luME9IHg7EdF+qlFzsN4wwZNnL98BAo0PpUAxg92GdQBEbECTORR/yACYkPedz+/00adTpMu3FGMTK0pJCFTL0DrPJdgzErufK/np1M8wafGDy4g500iLEAMiHLlZ5X+9Syfexpswc/u3Jdycy0HHJrCOCwvXgQg9MwX13mTiRUvKFzP4S/Kx/R2jMigXh6DijHX8DLQKPYCAQIEIMFSm9doDsBBLY2n03NkYLw/jjbTcxbWf7/ZhJH9Q3d5WU1hc3RlcktleaEBJU8RAdRkggHQMIIBzARTAQCXSlsz5M3/DLJ3LwoC2oHZFrvf2UpO6U65RLBuc2HfrTD4vA8PKYYeTPxv2pvwbwJDKxPKuaL5xdun1Zjw+lanFJ+vMrvyYYSPlos9UQddTSwEggEsr1H8WcrXyturoCCaMZmJ3omU/MG+8Y3oLvd6ZsF4xigAtHLFD8Nk6TjiPNw/fUth9I4Kj5DcwQqIhN0DbCnxyy6lhGH9TVuIWCyKf4p4aLtZyEHcZe+wTZeLK+qnvx7hXbSdWKGwaMd8AaAnep7smMkHF+zz5KiPF9ZEaUKuOOcVr7JjRXNeCoQsQo/5jZi+k+hLGrk1hZNsiQXb2aU9PyxsjSNbah1jVw3O48oJASmcr2jxp2o5Ih7pGr7C1RVFoC43Tg0JBkPyhV+PFN08arYReVtTH7mmjgr/IInMDjAE41HqfHNzwCwXSvJxKinVlpgw42syNCO1HX8m9Vmc2dlYFIO8HP/viB1E+6LSMbZ10qu5sjWlntOgQse13DlZ0ZFv4tWQOdxyGilwBCDBd3m4WFN5LsrHxCmPrmepRrZHDyx66Xo8SFTT8u9bpgIBAgQgwVKb12gOwEEtjafTc2RgvD+ONtNzFtZ/v9mEkf1Dd3lXU2hhcmluZ6EBKE8RAaBkggGcMIIBmARTAQAf+QXYIadowXsR5jmWz0V3lZK+6DKzqRB0vFdT367TGDD1mgeHWfq2X+XxONWfrwh+pwpS1uQYSBzCA+PujKQGcOVQnEQF1b8u1aV4XxenZjUEgfnNpqS2O0c7HiRtdY8s0o50X/Mt+Iacjfl+nNJnMsPsXV5qdtVogDFZw007/zdDuqKuNw47LyZTd01CYTr7HujAfUGnGT3sgldyovrZCby1t5Ab4rbDmKr5fsJljPHAqWjenDl2DO4FI+/uWVhyyOXOWJ7fNgMcUcOleG0kz+mAIZxnTHEkOLTA795Jzx5b7p5rtL0XzdpOIriUOI2X0OcNyjASldH2YHO9ZHJp/zJc79HbDBlsX1fjt5h94HuvYBmbKGehB212h63QDbsKnqOm68EW8uIupHZ0OFE6dj/YuyW6JjqpNyya1yg6WIc2NeRVdBZGLMMDZk4EIJ6KaY6ammcS59L24CtSbw9NnwBB9XVwCzMIwPy4mg32AgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eV5UVFlDYWxsSGlzdG9yeaEBK08RAaBkggGcMIIBmARTAQDFQfsYDNaI/OfOJ5wDDLVYGBdL6Nh3dY83ZtgyiXtkaDA4+baJ86jsz2zNb1yOX90jckzjX1x7bJaiD9NsUnZwBYql8HdawMTRzI+tQFgcgnoEgfkiYhn00ER0ys97XMqWsUsSfA7GdwkJ6ftGtB3f9u1ZIbjaxokjXRmTyVBJbT1gYnvGHxg1CnYg5YoHK2bF29H2MC52f/zPjDs1daqF+pimOvNWYbmfP1dPG3vkMHNujOqxi8pVBZ+ar8LsVdE8/3B7btIpeM02cyCTa7qKty6b61af05+0QQCzQRcZwjfRiqhMpyAux/IYaVOwbkL0/0J9/Ok62vNj6emsHFlKYhJwriIVPHo3zD6P1LeVB6pMu2G8EfoNNzrSkIIXg6fGBak/086b0iW0KCj1Ym+WUgYjlPVZPsLtKAynGxwu7zhoKsMRR3GMvxKk0EwEII2sxVqADT621CRjg0a1iqPj1vg8cdXtgVoAfJV32+h2AgECBCDBUpvXaA7AQS2Np9NzZGC8P44203MW1n+/2YSR/UN3eV8QJFNlY3VyZUJhY2t1cGlDbG91ZElkZW50aXR5UHVibGljRGF0YU8RAJRhgZEwgY4CAQICAQEEIBc6U2wxA1UlBRj52pwa3f1dRNsNVPaSyAQExW/I6OQ9oWQwYgQUAaKGm18QogpAmwTW7wAhpcqfemgCAQEERzBFAiEAgv7WXwyxFbes33Ax4zu1KKdqSn9zb8OnaQ7xnw5kHFICIAvXkgL8KsmCRAvJLitqsZ5OYwUobPfiL+NDUBAfNDLRAAgAFQA4AE4AYwB6AIkAngDBAM4A5gDnAPoBFRvnHAEcoBypHK4cwRzEHV0djB2RHaQdpx6mHrkevh7RHtQfbR92H3sfjh+RICggQSBGIFkgXCFaIWIhZyF6IX0ifCKbIqAisyK2I7QjviPDI9Yj2STXJOIk5yT6JP0llSW4Jb0l0CXTJmsmdiZ7Jo4mkScpJ0InRydaJ10oXShmKGsofiiBKRkpICklKTgpOynTKd0p4in1KfgqkCqcKqEqtCq3K08rZStqK30rgCx/LI0skiylLKgtQC1aLV8tci11LnMuei5/LpIulS8sLzgvPS9QL1Mv6y/yL/cwCjANMKUwqzCwMMMwxjFeMYIxhzGaMZ0ynDK8MsEy1DLXM9cz9zP8NA80EjSrNLQ0uTTMNM81zjXWNds17jXxNok2pTaqNr02wDe+N8U3yjfdN+A4dzh7OIA4kziWOS05Njk7OU45UTnoOe058joFOgg6oTq9OsI61TrYO9g7+Tv+PBE8FD0SPSE9Jj05PTw90z3dPeI99T34PsI+yz7QPuM+5j99P4w/kT+kP6dAP0BbQG5Ai0CUQJ5AzUDZQUhBUUFUQvlDGUMcRMFE1ETXRnxGgEaDSCdIMEgzSddJ20neS4FLikuNTTBNN006Tt1O6E7rUI9QmlCdUkFSS1JOU/JT/lQBVaVVs1W2V1pXfVeAWSRZMFkzWtda3lrhXIVcjFyPXjJeOV48X+Bf51/qYY9hmGGbYz5jRGNHZOtk9GT3Zppmn2aiaEdoVmhZafxqBmoJa+Fr6WvsbZBtn22ib0ZvbQAAAAAAAAICAAAAAAAAAS4AAAAAAAAAAAAAAAAAAHAF</string>
+    </dict>
+    <key>SecureBackupStableMetadata</key>
+    <false/>
+    <key>SecureBackupUsesRecoveryKey</key>
+    <false/>
+    <key>SecureBackupiCDPRecords</key>
+    <array>
+        <dict>
+            <key>SecureBackupEscrowDate</key>
+            <date>2020-01-31T03:07:40Z</date>
+            <key>SecureBackupRemainingAttempts</key>
+            <integer>10</integer>
+            <key>encodedMetadata</key>
+            <string>YnBsaXN0MDDZAQIDBAUGBwgJCgsMDQ4PECYgVnNlcmlhbF8QEkJhY2t1cEtleWJhZ0RpZ2VzdFVidWlsZFhwZWVySW5mb18QIGNvbS5hcHBsZS5zZWN1cmViYWNrdXAudGltZXN0YW1wWGJvdHRsZUlEXkNsaWVudE1ldGFkYXRhXGVzY3Jvd2VkU1BLSV8QHVNlY3VyZUJhY2t1cFVzZXNNdWx0aXBsZWlDU0NzXEMzOVYyMDlBSjlMNU8QFMhRrcsWNmcw7dI/9uhpDUpq4FZ2VjE4QTIxNE8RBLIwggSuMYIEYTAUDA9Db25mbGljdFZlcnNpb24CAQMwKwwPQXBwbGljYXRpb25EYXRlBBgYFjIwMjAwMTMwMjI0MTI2LjI4MDA1N1owVQwQUHVibGljU2lnbmluZ0tleQRBBOW+fXyAnCMa6by/cKGf1iHkcz9VEsa6rocBXgrLGVSb7Dy4XzT7fa1jf+X2co6ZTrXr3Vt56TBJZx8X6YNMY+swWAwPQXBwbGljYXRpb25Vc2lnBEUwQwIgY4hdZ7zcWd+Ue77JKF2OK99No8MUe9f5Fg2AzLviJKcCH04d5DOYNyFk6LTzWVuHD/2uMR7zASajNdfXbpFQ578wcAwNRGV2aWNlR2VzdGFsdDFfMBMMCU1vZGVsTmFtZQwGaVBob25lMBMMCU9TVmVyc2lvbgwGMThBMjE0MBYMDENvbXB1dGVyTmFtZQwGaVBob25lMBsMFk1lc3NhZ2VQcm90b2NvbFZlcnNpb24CAQAwfAwXT2N0YWdvblB1YmxpY1NpZ25pbmdLZXkEYQSguiFhjcalFK/bQBPruMsnWzZ0qv7VtPwmhjbdCQJ4mCMY1v6+60RCEsWMs+wQ200Tv40DvCBpzRABcsM70f8tuk1Q/wMXVDQ2kVfgmIVmobzvqNLwcSBHpU44nOEnNRkwfwwaT2N0YWdvblB1YmxpY0VuY3J5cHRpb25LZXkEYQQNGdKw9D+ZMSXl2YwRidBiFyb2GI/MGdDSCFDNvvRq5ig9sJHGMKgbswKltv7gkYzgvvg51slkltO0d5nQm0Juqj3dnIh9QtbPXfUew7LGjBNJIj3IOI8DJdnPqdGee+cwggH4DBBWMkRpY3Rpb25hcnlEYXRhBIIB4jGCAd4wEAwMRXNjcm93UmVjb3JkBQAwHAwMU2VyaWFsTnVtYmVyDAxDMzlWMjA5QUo5TDUwLQwJQmFja3VwS2V5BCBmWfEWzk0k71iVH/hINYf572sP/4l/uVZaMyhNb36frzBgDAxNYWNoaW5lSURLZXkMUHlXbkk4dmROZzZFV2F5ZVcvRlA0Y0RaUnNlM0xNbjhQeGcveC9zUHpaSklTNWNzM1JLbzQvc3RPVzQ2blE5OGlObHBTSHJuUjBrZnNiUjNYMIIBGQwFVmlld3PRggEODAdBcHBsZVRWDAdIb21lS2l0DAdQQ1MtRkRFDAlQQ1MtTm90ZXMMClBDUy1CYWNrdXAMClBDUy1Fc2Nyb3cMClBDUy1QaG90b3MMC0JhY2t1cEJhZ1YwDAtQQ1MtU2hhcmluZwwMTmFub1JlZ2lzdHJ5DAxQQ1MtQ2xvdWRLaXQMDFBDUy1GZWxkc3BhcgwMUENTLU1haWxkcm9wDAxQQ1MtaU1lc3NhZ2UMDVBDUy1NYXN0ZXJLZXkMDldhdGNoTWlncmF0aW9uDA5pQ2xvdWRJZGVudGl0eQwPUENTLWlDbG91ZERyaXZlDBBBY2Nlc3NvcnlQYWlyaW5nDBBDb250aW51aXR5VW5sb2NrBEcwRQIgRLmiTIo/hgxmoOMgZEygsTzdJiHOMTI68Y8DQGgXpWICIQCHr913nsr4kFaYZd3i/ioYQum8B5KOpxFR90u1CPgPEl8QEzIwMjAtMDEtMzEgMDM6MDc6NDBfECRERDVFM0Y5Ri0zNzAyLTQ3ODktOEFDRi0yRDI4QkM4NkE5NEPcERITFBUWFxgZGhscHQ4eHR8gISIjICMlXxAWZGV2aWNlX2VuY2xvc3VyZV9jb2xvcl8QHVNlY3VyZUJhY2t1cE1ldGFkYXRhVGltZXN0YW1wXxAPZGV2aWNlX3BsYXRmb3JtXGRldmljZV9jb2xvcl8QI1NlY3VyZUJhY2t1cE51bWVyaWNQYXNzcGhyYXNlTGVuZ3RoXxAhU2VjdXJlQmFja3VwVXNlc0NvbXBsZXhQYXNzcGhyYXNlWmRldmljZV9taWRfEBRkZXZpY2VfbW9kZWxfdmVyc2lvbltkZXZpY2VfbmFtZV8QIVNlY3VyZUJhY2t1cFVzZXNOdW1lcmljUGFzc3BocmFzZV8QEmRldmljZV9tb2RlbF9jbGFzc1xkZXZpY2VfbW9kZWxRMRQAAAAAAAAAAAAAAAAAAAABEAYJXxBQeVduSTh2ZE5nNkVXYXllVy9GUDRjRFpSc2UzTE1uOFB4Zy94L3NQelpKSVM1Y3MzUktvNC9zdE9XNDZuUTk4aU5scFNIcm5SMGtmc2JSM1haaVBob25lMTAsNVZpUGhvbmUJXWlQaG9uZSA4IFBsdXNPEHgwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATIde8QFJDJYQJa6NrxP5WDLEhPNga9732ZGyoVoKi0RnxT6aIlb/LBrRvnrdZFyGUMlSYGSY3GIgrLz3YJ0A0W4BN6YKMtsgGCDONSD5/KHRzTEAE5e3Yp26nshhMavOcJAAgAGwAiADcAPQBGAGkAcgCBAI4ArgC7ANIA2QWPBaUFzAXlBf4GHgYwBj0GYwaHBpIGqQa1BtkG7gb7Bv0HDgcQBxEHZAdvB3YHdweFCAAAAAAAAAACAQAAAAAAAAAoAAAAAAAAAAAAAAAAAAAIAQ==</string>
+            <key>label</key>
+            <string>com.apple.icdp.record</string>
+            <key>metadata</key>
+            <dict>
+                <key>BackupKeybagDigest</key>
+                <data>
+                yFGtyxY2ZzDt0j/26GkNSmrgVnY=
+                </data>
+                <key>ClientMetadata</key>
+                <dict>
+                    <key>SecureBackupMetadataTimestamp</key>
+                    <string>2020-01-31 03:07:40</string>
+                    <key>SecureBackupNumericPassphraseLength</key>
+                    <integer>6</integer>
+                    <key>SecureBackupUsesComplexPassphrase</key>
+                    <true/>
+                    <key>SecureBackupUsesNumericPassphrase</key>
+                    <true/>
+                    <key>device_color</key>
+                    <string>1</string>
+                    <key>device_enclosure_color</key>
+                    <string>1</string>
+                    <key>device_mid</key>
+                    <string>yWnI8vdNg6EWayeW/FP4cDZRse3LMn8Pxg/x/sPzZJIS5cs3RKo4/stOW46nQ98iNlpSHrnR0kfsbR3X</string>
+                    <key>device_model</key>
+                    <string>iPhone 8 Plus</string>
+                    <key>device_model_class</key>
+                    <string>iPhone</string>
+                    <key>device_model_version</key>
+                    <string>iPhone10,5</string>
+                    <key>device_name</key>
+                    <string>iPhone</string>
+                    <key>device_platform</key>
+                    <integer>1</integer>
+                </dict>
+                <key>SecureBackupUsesMultipleiCSCs</key>
+                <true/>
+                <key>bottleID</key>
+                <string>DD5E3F9F-3702-4789-8ACF-2D28BC86A94C</string>
+                <key>bottleValid</key>
+                <string>valid</string>
+                <key>build</key>
+                <string>18A214</string>
+                <key>com.apple.securebackup.timestamp</key>
+                <string>2020-01-31 03:07:40</string>
+                <key>escrowedSPKI</key>
+                <data>
+                MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEyHXvEBSQyWEC
+                Wuja8T+VgyxITzYGve99mRsqFaCotEZ8U+miJW/ywa0b
+                563WRchlDJUmBkmNxiIKy892CdANFuATemCjLbIBggzj
+                Ug+fyh0c0xABOXt2Kdup7IYTGrzn
+                </data>
+                <key>peerInfo</key>
+                <data>
+                MIIErjGCBGEwFAwPQ29uZmxpY3RWZXJzaW9uAgEDMCsM
+                D0FwcGxpY2F0aW9uRGF0ZQQYGBYyMDIwMDEzMDIyNDEy
+                Ni4yODAwNTdaMFUMEFB1YmxpY1NpZ25pbmdLZXkEQQTl
+                vn18gJwjGum8v3Chn9Yh5HM/VRLGuq6HAV4KyxlUm+w8
+                uF80+32tY3/l9nKOmU61691beekwSWcfF+mDTGPrMFgM
+                D0FwcGxpY2F0aW9uVXNpZwRFMEMCIGOIXWe83FnflHu+
+                yShdjivfTaPDFHvX+RYNgMy74iSnAh9OHeQzmDchZOi0
+                81lbhw/9rjEe8wEmozXX126RUOe/MHAMDURldmljZUdl
+                c3RhbHQxXzATDAlNb2RlbE5hbWUMBmlQaG9uZTATDAlP
+                U1ZlcnNpb24MBjE4QTIxNDAWDAxDb21wdXRlck5hbWUM
+                BmlQaG9uZTAbDBZNZXNzYWdlUHJvdG9jb2xWZXJzaW9u
+                AgEAMHwMF09jdGFnb25QdWJsaWNTaWduaW5nS2V5BGEE
+                oLohYY3GpRSv20AT67jLJ1s2dKr+1bT8JoY23QkCeJgj
+                GNb+vutEQhLFjLPsENtNE7+NA7wgac0QAXLDO9H/LbpN
+                UP8DF1Q0NpFX4JiFZqG876jS8HEgR6VOOJzhJzUZMH8M
+                Gk9jdGFnb25QdWJsaWNFbmNyeXB0aW9uS2V5BGEEDRnS
+                sPQ/mTEl5dmMEYnQYhcm9hiPzBnQ0ghQzb70auYoPbCR
+                xjCoG7MCpbb+4JGM4L74OdbJZJbTtHeZ0JtCbqo93ZyI
+                fULWz131HsOyxowTSSI9yDiPAyXZz6nRnnvnMIIB+AwQ
+                VjJEaWN0aW9uYXJ5RGF0YQSCAeIxggHeMBAMDEVzY3Jv
+                d1JlY29yZAUAMBwMDFNlcmlhbE51bWJlcgwMQzM5VjIw
+                OUFKOUw1MC0MCUJhY2t1cEtleQQgZlnxFs5NJO9YlR/4
+                SDWH+e9rD/+Jf7lWWjMoTW9+n68wYAwMTWFjaGluZUlE
+                S2V5DFB5V25JOHZkTmc2RVdheWVXL0ZQNGNEWlJzZTNM
+                TW44UHhnL3gvc1B6WkpJUzVjczNSS280L3N0T1c0Nm5R
+                OThpTmxwU0hyblIwa2ZzYlIzWDCCARkMBVZpZXdz0YIB
+                DgwHQXBwbGVUVgwHSG9tZUtpdAwHUENTLUZERQwJUENT
+                LU5vdGVzDApQQ1MtQmFja3VwDApQQ1MtRXNjcm93DApQ
+                Q1MtUGhvdG9zDAtCYWNrdXBCYWdWMAwLUENTLVNoYXJp
+                bmcMDE5hbm9SZWdpc3RyeQwMUENTLUNsb3VkS2l0DAxQ
+                Q1MtRmVsZHNwYXIMDFBDUy1NYWlsZHJvcAwMUENTLWlN
+                ZXNzYWdlDA1QQ1MtTWFzdGVyS2V5DA5XYXRjaE1pZ3Jh
+                dGlvbgwOaUNsb3VkSWRlbnRpdHkMD1BDUy1pQ2xvdWRE
+                cml2ZQwQQWNjZXNzb3J5UGFpcmluZwwQQ29udGludWl0
+                eVVubG9jawRHMEUCIES5okyKP4YMZqDjIGRMoLE83SYh
+                zjEyOvGPA0BoF6ViAiEAh6/dd57K+JBWmGXd4v4qGELp
+                vAeSjqcRUfdLtQj4DxI=
+                </data>
+                <key>serial</key>
+                <string>C39V209AJ9L5</string>
+            </dict>
+            <key>osVersion</key>
+            <string>18A214</string>
+            <key>peerInfoSerialNumber</key>
+            <string>C39V209AJ9L5</string>
+            <key>recordID</key>
+            <string>sNs6voV0N35D/T91SuGmJnGO29</string>
+            <key>recordStatus</key>
+            <string>valid</string>
+            <key>silentAttemptAllowed</key>
+            <true/>
+        </dict>
+    </array>
+    <key>SecureBackupiCloudDataProtectionEnabled</key>
+    <false/>
+</dict>
+</plist>
+
+"""
+#endif
index 67c3928f2c1726d59d1821b961c5fb5be19f1329..c8f7501bba72dc638675a2caca8f38b5fe132d0f 100644 (file)
@@ -8,7 +8,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         let peer1ID = self.assertResetAndBecomeTrustedInDefaultContext()
 
         // Now, we'll approve a new peer with a new policy! First, make that new policy.
-        let currentPolicyOptional = builtInPolicyDocuments().filter { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }.first
+        let currentPolicyOptional = builtInPolicyDocuments().first { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }
         XCTAssertNotNil(currentPolicyOptional, "Should have one current policy")
         let currentPolicy = currentPolicyOptional!
 
@@ -46,8 +46,9 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
                                osVersion: "something",
                                policyVersion: newPolicy.version,
                                policySecrets: nil,
+                               syncUserControllableViews: .UNKNOWN,
                                signingPrivKeyPersistentRef: nil,
-                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error in
                                 XCTAssertNil(error, "Should be no error preparing the second peer")
                                 XCTAssertNotNil(peerID, "Should have a peerID")
                                 peer2ID = peerID!
@@ -91,7 +92,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
                                                                             voucherSig: voucherSig!,
                                                                             ckksKeys: [],
                                                                             tlkShares: [],
-                                                                            preapprovedKeys: []) { peerID, _, _, _, error in
+                                                                            preapprovedKeys: []) { peerID, _, _, error in
                                                                                 XCTAssertNil(error, "Should be no error joining")
                                                                                 XCTAssertNotNil(peerID, "Should have a peerID")
                                                                                 joinExpectation.fulfill()
@@ -118,9 +119,13 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
             return nil
         }
 
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
         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)
+        self.verifyDatabaseMocks()
     }
 
     func testRejectVouchingForPeerWithUnknownNewPolicy() throws {
@@ -128,7 +133,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         _ = self.assertResetAndBecomeTrustedInDefaultContext()
 
         // Now, a new peer joins with a policy we can't fetch
-        let currentPolicyOptional = builtInPolicyDocuments().filter { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }.first
+        let currentPolicyOptional = builtInPolicyDocuments().first { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }
         XCTAssertNotNil(currentPolicyOptional, "Should have one current policy")
         let currentPolicy = currentPolicyOptional!
 
@@ -166,8 +171,9 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
                                osVersion: "something",
                                policyVersion: newPolicy.version,
                                policySecrets: nil,
+                               syncUserControllableViews: .UNKNOWN,
                                signingPrivKeyPersistentRef: nil,
-                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error in
                                 XCTAssertNil(error, "Should be no error preparing the second peer")
                                 XCTAssertNotNil(peerID, "Should have a peerID")
 
@@ -204,7 +210,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         let peer1ID = self.assertResetAndBecomeTrustedInDefaultContext()
 
         // Now, a new peer joins with a policy we can't fetch
-        let currentPolicyOptional = builtInPolicyDocuments().filter { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }.first
+        let currentPolicyOptional = builtInPolicyDocuments().first { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }
         XCTAssertNotNil(currentPolicyOptional, "Should have one current policy")
         let currentPolicy = currentPolicyOptional!
 
@@ -268,12 +274,13 @@ class OctagonForwardCompatibilityTests: 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)
     }
 
     func createOctagonAndCKKSUsingFuturePolicy() throws -> (TPPolicyDocument, CKRecordZone.ID) {
         // We want to set up a world with a peer, in Octagon, with TLKs for zones that don't even exist in our current policy.
         // First, make a new policy.
-        let currentPolicyOptional = builtInPolicyDocuments().filter { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }.first
+        let currentPolicyOptional = builtInPolicyDocuments().first { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }
         XCTAssertNotNil(currentPolicyOptional, "Should have one current policy")
         let currentPolicyDocument = currentPolicyOptional!
 
@@ -289,18 +296,43 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         XCTAssertFalse(currentPolicyDocument.categoriesByView.keys.contains(futureViewName), "Current policy should not include future view")
 
         let newPolicyDocument = try TPPolicyDocument(internalVersion: currentPolicyDocument.version.versionNumber + 1,
-            modelToCategory: currentPolicyDocument.modelToCategory,
-            categoriesByView: currentPolicyDocument.categoriesByView.merging([futureViewName: Set(["watch", "full", "tv"])]) { _, new in new },
-            introducersByCategory: currentPolicyDocument.introducersByCategory,
-            redactions: [:],
-            keyViewMapping: [futureViewMapping] + currentPolicyDocument.keyViewMapping,
-            hashAlgo: .SHA256)
+                                                     modelToCategory: currentPolicyDocument.modelToCategory,
+                                                     categoriesByView: currentPolicyDocument.categoriesByView.merging([futureViewName: Set(["watch", "full", "tv"])]) { _, new in new },
+                                                     introducersByCategory: currentPolicyDocument.introducersByCategory,
+                                                     redactions: [:],
+                                                     keyViewMapping: [futureViewMapping] + currentPolicyDocument.keyViewMapping,
+                                                     userControllableViewList: currentPolicyDocument.userControllableViewList,
+                                                     piggybackViews: currentPolicyDocument.piggybackViews,
+                                                     hashAlgo: .SHA256)
 
         self.fakeCuttlefishServer.policyOverlay.append(newPolicyDocument)
 
         return (newPolicyDocument, futureViewZoneID)
     }
 
+    func createFuturePolicyMovingAllItemsToLimitedPeers() throws -> (TPPolicyDocument) {
+        let currentPolicyOptional = builtInPolicyDocuments().first { $0.version.versionNumber == prevailingPolicyVersion.versionNumber }
+        XCTAssertNotNil(currentPolicyOptional, "Should have one current policy")
+        let currentPolicyDocument = currentPolicyOptional!
+
+        let limitedPeersViewMapping = TPPBPolicyKeyViewMapping(view: "LimitedPeersAllowed",
+                                                               matchingRule: TPDictionaryMatchingRule.trueMatch())
+
+        let newPolicyDocument = try TPPolicyDocument(internalVersion: currentPolicyDocument.version.versionNumber + 1,
+                                                     modelToCategory: currentPolicyDocument.modelToCategory,
+                                                     categoriesByView: currentPolicyDocument.categoriesByView,
+                                                     introducersByCategory: currentPolicyDocument.introducersByCategory,
+                                                     redactions: [:],
+                                                     keyViewMapping: [limitedPeersViewMapping] + currentPolicyDocument.keyViewMapping,
+                                                     userControllableViewList: currentPolicyDocument.userControllableViewList,
+                                                     piggybackViews: currentPolicyDocument.piggybackViews,
+                                                     hashAlgo: .SHA256)
+
+        self.fakeCuttlefishServer.policyOverlay.append(newPolicyDocument)
+
+        return newPolicyDocument
+    }
+
     func testRestoreBottledPeerUsingFuturePolicy() throws {
         let (newPolicyDocument, futureViewZoneID) = try self.createOctagonAndCKKSUsingFuturePolicy()
 
@@ -312,11 +344,9 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
 
         self.putFakeKeyHierarchiesInCloudKit()
         try self.putSelfTLKSharesInCloudKit(context: futurePeerContext)
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
 
         // Now, our peer (with no inbuilt knowledge of newPolicyDocument) joins via escrow recovery.
-        // It should be able to recover the FutureView TLK
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
 
         let serverJoinExpectation = self.expectation(description: "peer1 joins successfully")
         self.fakeCuttlefishServer.joinListener = { joinRequest in
@@ -333,12 +363,13 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         let peerID = self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: futurePeerContext)
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         XCTAssertEqual(self.injectedManager!.policy?.version, newPolicyDocument.version, "CKKS should be configured with new policy")
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
         self.verifyDatabaseMocks()
 
         self.wait(for: [serverJoinExpectation], timeout: 10)
 
         // And the joined peer should have recovered the TLK, and uploaded itself a share
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: peerID, senderPeerID: peerID, zoneID: futureViewZoneID))
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: peerID, senderPeerID: peerID, zoneID: futureViewZoneID))
     }
 
     func testPairingJoinUsingFuturePolicy() throws {
@@ -352,7 +383,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
 
         self.putFakeKeyHierarchiesInCloudKit()
         try self.putSelfTLKSharesInCloudKit(context: futurePeerContext)
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
 
         // Now, our peer (with no inbuilt knowledge of newPolicyDocument) joins via pairing
         // It should be able to recover the FutureView TLK
@@ -374,7 +405,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
 
         // And then fake like the other peer uploaded TLKShares after the join succeeded (it would normally happen during, but that's okay)
         try self.putAllTLKSharesInCloudKit(to: self.cuttlefishContext, from: futurePeerContext)
-        self.sendAllCKKSViewsZoneChanged()
+        self.injectedManager!.zoneChangeFetcher.notifyZoneChange(nil)
 
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         XCTAssertEqual(self.injectedManager!.policy?.version, newPolicyDocument.version, "CKKS should be configured with new policy")
@@ -383,7 +414,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         self.wait(for: [serverJoinExpectation], timeout: 10)
 
         // And the joined peer should have recovered the TLK, and uploaded itself a share
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: peerID, senderPeerID: peerID, zoneID: futureViewZoneID))
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: peerID, senderPeerID: peerID, zoneID: futureViewZoneID))
     }
 
     func testRecoveryKeyJoinUsingFuturePolicy() throws {
@@ -397,7 +428,7 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
 
         self.putFakeKeyHierarchiesInCloudKit()
         try self.putSelfTLKSharesInCloudKit(context: futurePeerContext)
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: futurePeerID, senderPeerID: futurePeerID, zoneID: futureViewZoneID))
 
         // Create the recovery key
         let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String
@@ -428,9 +459,6 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
             return nil
         }
 
-        // It should recover and upload the FutureView TLK
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
-
         self.cuttlefishContext.startOctagonStateMachine()
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
@@ -439,10 +467,15 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
 
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         XCTAssertEqual(self.injectedManager!.policy?.version, newPolicyDocument.version, "CKKS should be configured with new policy")
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+
+        // And double-check that the future view is covered
+        let accountMetadata = try self.cuttlefishContext.accountMetadataStore.loadOrCreateAccountMetadata()
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: accountMetadata.peerID, senderPeerID: accountMetadata.peerID, zoneID: futureViewZoneID))
         self.verifyDatabaseMocks()
 
         self.wait(for: [serverJoinExpectation], timeout: 10)
@@ -513,28 +546,49 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
         self.assertResetAndBecomeTrustedInDefaultContext()
 
         // Now, another peer comes along and joins via BP recovery, using a new policy
-        let (newPolicyDocument, _) = try self.createOctagonAndCKKSUsingFuturePolicy()
+        let (newPolicyDocument, futureZoneID) = try self.createOctagonAndCKKSUsingFuturePolicy()
 
         let futurePeerContext = self.makeInitiatorContext(contextID: "futurePeer")
         futurePeerContext.policyOverride = newPolicyDocument.version
 
         let serverJoinExpectation = self.expectation(description: "futurePeer joins successfully")
-         self.fakeCuttlefishServer.joinListener = { joinRequest in
-             XCTAssertTrue(joinRequest.peer.hasStableInfoAndSig, "Joining peer should have a stable info")
-             let newStableInfo = joinRequest.peer.stableInfoAndSig.stableInfo()
+        self.fakeCuttlefishServer.joinListener = { joinRequest in
+            XCTAssertTrue(joinRequest.peer.hasStableInfoAndSig, "Joining peer should have a stable info")
+            let newStableInfo = joinRequest.peer.stableInfoAndSig.stableInfo()
 
-             XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Policy version in peer should match frozen policy version")
-             XCTAssertEqual(newStableInfo.flexiblePolicyVersion, newPolicyDocument.version, "Prevailing policy version in peer should match new policy version")
-             serverJoinExpectation.fulfill()
-             return nil
-         }
+            XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Policy version in peer should match frozen policy version")
+            XCTAssertEqual(newStableInfo.flexiblePolicyVersion, newPolicyDocument.version, "Prevailing policy version in peer should match new policy version")
+            serverJoinExpectation.fulfill()
+            return nil
+        }
 
         let peer2ID = self.assertJoinViaEscrowRecovery(joiningContext: futurePeerContext, sponsor: self.cuttlefishContext)
         self.wait(for: [serverJoinExpectation], timeout: 10)
 
+        // And the other peer creates the new View, and shares it with us
+        self.putFakeKeyHierarchiesInCloudKit { zoneID in
+            return zoneID.zoneName == futureZoneID.zoneName
+        }
+
+        // The remote peer uploads tlkshares for itself, because it received them during its escrow recovery
+        try self.putSelfTLKSharesInCloudKit(context: futurePeerContext) //, filter)
+        try self.putTLKShareInCloudKit(to: self.cuttlefishContext, from: futurePeerContext, zoneID: futureZoneID)
+
+        // First, tell all existing CKKS views to fetch, and wait for it to do so. This will ensure that it receives the tlkshares uploaded above, and
+        // won't immediately upload new ones when the peer list changes.
+        self.silentFetchesAllowed = false
+        self.expectCKFetch()
+        try XCTUnwrap(self.injectedManager).zoneChangeFetcher.notifyZoneChange(nil)
+        self.verifyDatabaseMocks()
+        self.silentFetchesAllowed = true
+
         // Now, tell our first peer about the new changes. It should trust the new peer, and update its policy
+        // It should also upload itself a TLKShare for the future view
+        self.assertAllCKKSViewsUpload(tlkShares: 1, filter: { $0.zoneName == futureZoneID.zoneName })
+
         let updateTrustExpectation = self.expectation(description: "updateTrustExpectation successfully")
-        self.fakeCuttlefishServer.updateListener = { request in
+        self.fakeCuttlefishServer.updateListener = {
+            request in
             let newStableInfo = request.stableInfoAndSig.stableInfo()
 
             XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Policy version in peer should match frozen policy version")
@@ -549,6 +603,201 @@ class OctagonForwardCompatibilityTests: OctagonTestsBase {
 
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
         self.wait(for: [updateTrustExpectation], timeout: 10)
+
+        // Once we've uploaded the TLKShare for the future view, then we're fairly sure the view object has been created locally.
+        self.verifyDatabaseMocks()
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+    }
+
+    func testRecoverFromPeerUsingOldPolicy() throws {
+        self.startCKAccountStatusMock()
+
+        let pastPeerContext = self.makeInitiatorContext(contextID: "pastPeer")
+
+        let policyV6Document = builtInPolicyDocuments().filter { $0.version.versionNumber == 6 }.first!
+        pastPeerContext.policyOverride = policyV6Document.version
+
+        let serverEstablishExpectation = self.expectation(description: "futurePeer establishes successfully")
+        self.fakeCuttlefishServer.establishListener = { establishRequest in
+            XCTAssertTrue(establishRequest.peer.hasStableInfoAndSig, "Establishing peer should have a stable info")
+            let newStableInfo = establishRequest.peer.stableInfoAndSig.stableInfo()
+
+            XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Frozen policy version in peer should be frozen version")
+            XCTAssertEqual(newStableInfo.flexiblePolicyVersion, policyV6Document.version, "Prevailing policy version in peer should be v6")
+            serverEstablishExpectation.fulfill()
+            return nil
+        }
+
+        self.assertResetAndBecomeTrusted(context: pastPeerContext)
+        self.wait(for: [serverEstablishExpectation], timeout: 10)
+
+        self.putFakeKeyHierarchiesInCloudKit(filter: { zoneID in policyV6Document.keyViewMapping.contains { $0.view == zoneID.zoneName } })
+        try self.putSelfTLKSharesInCloudKit(context: pastPeerContext, filter: { zoneID in policyV6Document.keyViewMapping.contains { $0.view == zoneID.zoneName } })
+
+        // Ensure that CKKS will bring up the Backstop view
+        self.injectedManager!.setSyncingViewsAllowList(Set(["Backstop"] + self.intendedCKKSZones!.map { $0.zoneName }))
+
+        // Now, Octagon comes along and recovers the bottle.
+
+        // Right now, Octagon will join and then immediately updateTrust to upload the new set of TLKs
+        // This probably can be reworked for performance.
+        let serverJoinExpectation = self.expectation(description: "joins successfully")
+        self.fakeCuttlefishServer.joinListener = { joinRequest in
+            XCTAssertEqual(joinRequest.viewKeys.count, 0, "Should have zero sets of new viewkeys during join")
+            serverJoinExpectation.fulfill()
+            return nil
+        }
+
+        // TVs do not participate in the backstop view, and so won't upload anything
+        #if !os(tvOS)
+        let serverUpdateTrustExpectation = self.expectation(description: "updateTrust successfully")
+        self.fakeCuttlefishServer.updateListener = { updateRequest in
+            XCTAssertEqual(updateRequest.viewKeys.count, 1, "Should have one new set of viewkeys during update")
+            serverUpdateTrustExpectation.fulfill()
+            return nil
+        }
+        #endif
+
+        self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: pastPeerContext)
+        self.wait(for: [serverJoinExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+        #if !os(tvOS)
+        self.wait(for: [serverUpdateTrustExpectation], timeout: 10)
+        #endif
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+    }
+
+    func testRecoverFromPeerUsingExtremelyOldPolicy() throws {
+        self.startCKAccountStatusMock()
+
+        let pastPeerContext = self.makeInitiatorContext(contextID: "pastPeer")
+
+        let policyV1Document = builtInPolicyDocuments().filter { $0.version.versionNumber == 1 }.first!
+        pastPeerContext.policyOverride = policyV1Document.version
+
+        let serverEstablishExpectation = self.expectation(description: "futurePeer establishes successfully")
+        self.fakeCuttlefishServer.establishListener = { establishRequest in
+            XCTAssertTrue(establishRequest.peer.hasStableInfoAndSig, "Establishing peer should have a stable info")
+            let newStableInfo = establishRequest.peer.stableInfoAndSig.stableInfo()
+
+            XCTAssertNil(newStableInfo.flexiblePolicyVersion, "Peer should be from before prevailing policy version were set")
+            XCTAssertEqual(newStableInfo.frozenPolicyVersion, policyV1Document.version, "Frozen policy version in peer should be v1 - a very old peer")
+            serverEstablishExpectation.fulfill()
+            return nil
+        }
+
+        self.assertResetAndBecomeTrusted(context: pastPeerContext)
+        self.wait(for: [serverEstablishExpectation], timeout: 10)
+
+        // This filtering should only add Manatee
+        self.putFakeKeyHierarchiesInCloudKit(filter: { zoneID in policyV1Document.keyViewMapping.contains { $0.view == zoneID.zoneName } })
+        try self.putSelfTLKSharesInCloudKit(context: pastPeerContext, filter: { zoneID in policyV1Document.keyViewMapping.contains { $0.view == zoneID.zoneName } })
+
+        // Ensure that CKKS will bring up the Backstop view, and allow it to bring up PCSEscrow if that's what it wants (it shouldn't)
+        self.injectedManager!.setSyncingViewsAllowList(Set(["Backstop", "PCSEscrow"] + self.intendedCKKSZones!.map { $0.zoneName }))
+
+        // Now, Octagon comes along and recovers the bottle.
+
+        // Right now, Octagon will join and then immediately updateTrust to upload the new set of TLKs
+        // This probably can be reworked for performance.
+        let serverJoinExpectation = self.expectation(description: "joins successfully")
+        self.fakeCuttlefishServer.joinListener = { joinRequest in
+            // Since Octagon ignores the other peer's policy, it will create the TLKs at establish time
+            let zones = Set(joinRequest.viewKeys.map { $0.view })
+
+            #if !os(tvOS)
+            XCTAssertEqual(zones.count, 3, "Should have three sets of new viewkeys during join")
+            XCTAssertTrue(zones.contains("Manatee"), "Should have a TLK for the manatee view")
+            #else
+            XCTAssertEqual(zones.count, 1, "Should have one set of new viewkeys during join")
+            #endif
+            XCTAssertTrue(zones.contains("LimitedPeersAllowed"), "Should have a TLK for the LimitedPeersAllowed view")
+
+            XCTAssertFalse(zones.contains("PCSEscrow"), "Should not have a TLK for the PCSEscrow view")
+
+            let joiningPeer = joinRequest.peer.stableInfoAndSig.stableInfo()
+            XCTAssertEqual(joiningPeer.flexiblePolicyVersion, prevailingPolicyVersion, "Our current policy should be the prevailing policy - the sponsor peer should be ignored")
+            XCTAssertEqual(joiningPeer.frozenPolicyVersion, frozenPolicyVersion, "Frozen policy version in peer should be the real policy")
+
+            serverJoinExpectation.fulfill()
+            return nil
+        }
+
+        self.assertJoinViaEscrowRecovery(joiningContext: self.cuttlefishContext, sponsor: pastPeerContext)
+        self.wait(for: [serverJoinExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContext, sender: self.cuttlefishContext)
+    }
+
+    func testCKKSRequestPolicyCheck() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        let newPolicyDocument = try self.createFuturePolicyMovingAllItemsToLimitedPeers()
+
+        let futurePeerContext = self.makeInitiatorContext(contextID: "futurePeer")
+        futurePeerContext.policyOverride = newPolicyDocument.version
+
+        let serverJoinExpectation = self.expectation(description: "futurePeer joins successfully")
+        self.fakeCuttlefishServer.joinListener = { joinRequest in
+            XCTAssertTrue(joinRequest.peer.hasStableInfoAndSig, "Joining peer should have a stable info")
+            let newStableInfo = joinRequest.peer.stableInfoAndSig.stableInfo()
+
+            XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Policy version in peer should match frozen policy version")
+            XCTAssertEqual(newStableInfo.flexiblePolicyVersion, newPolicyDocument.version, "Prevailing policy version in peer should match new policy version")
+            serverJoinExpectation.fulfill()
+            return nil
+        }
+
+        self.assertJoinViaEscrowRecovery(joiningContext: futurePeerContext, sponsor: self.cuttlefishContext)
+        self.wait(for: [serverJoinExpectation], timeout: 10)
+
+        // And the peer adds a new item to the LimitedPeersAllowed view, but one that didn't used to go there
+        var item = self.fakeRecordDictionary("account0", zoneID: self.limitedPeersAllowedZoneID)
+        item["vwht"] = "asdf"
+
+        self.addItem(toCloudKitZone: item, recordName: "7B598D31-F9C5-481E-98AC-5A507ACB2D85", zoneID: self.limitedPeersAllowedZoneID)
+
+        let limitedPeersView = self.injectedManager?.findView("LimitedPeersAllowed")
+        XCTAssertNotNil(limitedPeersView, "Should have a LimitedPeersAllowed view")
+
+        // This CKKS notification should cause Octagon to update trust, and then fill CKKS in (which should then accept the item)
+
+        let updateExpectation = self.expectation(description: "peer updates successfully")
+        self.fakeCuttlefishServer.updateListener = { request in
+            let newStableInfo = request.stableInfoAndSig.stableInfo()
+
+            XCTAssertEqual(newStableInfo.frozenPolicyVersion, frozenPolicyVersion, "Policy version in peer should match frozen policy version")
+            XCTAssertEqual(newStableInfo.flexiblePolicyVersion, newPolicyDocument.version, "Prevailing policy version in peer should match new policy version")
+
+            updateExpectation.fulfill()
+            return nil
+        }
+
+        // CKKS will also upload TLKShares for the new peer
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+
+        try XCTUnwrap(self.injectedManager).zoneChangeFetcher.notifyZoneChange(nil)
+        limitedPeersView!.waitForFetchAndIncomingQueueProcessing()
+
+        // And wait for the updateTrust to occur, then for Octagon to return to ready, then for any incoming queue processing in ckks
+        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)
+        limitedPeersView!.waitForOperations(of: CKKSIncomingQueueOperation.self)
+        self.verifyDatabaseMocks()
+
+        // The item should be found
+        self.findGenericPassword("account0", expecting: errSecSuccess)
     }
 }
 
index 6591eb61e3c18076d7b3eff847d308fccade6fa3..1da7c30a351ec8c379f6be4ad2c3de34b4c48de2 100644 (file)
@@ -1,7 +1,6 @@
 #if OCTAGON
 
 class OctagonHealthCheckTests: OctagonTestsBase {
-
     func testHealthCheckAllTrusted() throws {
         let containerName = OTCKContainerName
         let contextName = OTDefaultContext
@@ -70,9 +69,9 @@ class OctagonHealthCheckTests: OctagonTestsBase {
         self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
 
         #if os(tvOS)
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), false, "Should not have posted a CFU on aTV")
+        XCTAssertFalse(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should not have posted a CFU on aTV")
         #else
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), true, "Should have posted a CFU (due to being untrusted)")
+        XCTAssertTrue(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should have posted a CFU (due to being untrusted)")
         #endif
 
         self.verifyDatabaseMocks()
@@ -92,9 +91,9 @@ class OctagonHealthCheckTests: OctagonTestsBase {
         self.wait(for: [healthCheckCallback2], timeout: 10)
 
         #if os(tvOS)
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), false, "Should not have posted a CFU on aTV")
+        XCTAssertFalse(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should not have posted a CFU on aTV")
         #else
-        XCTAssertEqual(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), true, "Should have posted a CFU")
+        XCTAssertTrue(self.cuttlefishContext.followupHandler.hasPosted(.stateRepair), "Should have posted a CFU")
         #endif
     }
 
@@ -589,7 +588,6 @@ class OctagonHealthCheckTests: OctagonTestsBase {
     }
 
     func testHealthCheckWhenLocked() throws {
-
         let containerName = OTCKContainerName
         let contextName = OTDefaultContext
 
@@ -642,6 +640,37 @@ class OctagonHealthCheckTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
     }
 
+    func testHealthCheckBeforeClassCUnlock() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        // Now, the device restarts, and isn't unlocked immediately.
+        self.aksLockState = true
+        SecMockAKS.lockClassA_C()
+        self.lockStateTracker.recheck()
+
+        do {
+            _ = try OTAccountMetadataClassC.loadFromKeychain(forContainer: self.cuttlefishContext.containerName, contextID: self.cuttlefishContext.contextID)
+            XCTFail("shouldn't have been able to load the class c metadata")
+        } catch {
+            // We expected this error; fall through
+        }
+
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForClassCUnlock, within: 10 * NSEC_PER_SEC)
+
+        // A health check should fail, and leave us waiting for the initial unlock
+
+        let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs")
+        self.manager.healthCheck(self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID, skipRateLimitingCheck: false) { error in
+            XCTAssertNotNil(error, "error should be present")
+            healthCheckCallback.fulfill()
+        }
+        self.wait(for: [healthCheckCallback], timeout: 20)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForClassCUnlock, within: 10 * NSEC_PER_SEC)
+    }
+
     func testLastHealthCheckPersistedTime() throws {
         let containerName = OTCKContainerName
         let contextName = OTDefaultContext
@@ -909,6 +938,244 @@ class OctagonHealthCheckTests: OctagonTestsBase {
 
         self.assertEnters(context: cuttlefishContext, state: OctagonStateWaitForHSA2, within: 10 * NSEC_PER_SEC)
     }
+
+    func testRPCTrustStatusReturnsIsLocked() throws {
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+
+        XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
+        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)
+
+        self.aksLockState = true
+        self.lockStateTracker.recheck()
+
+        let configuration = OTOperationConfiguration()
+
+        let statusexpectation = self.expectation(description: "status callback occurs")
+        self.cuttlefishContext.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, isLocked, error   in
+            XCTAssertEqual(egoStatus, .in, "Self peer for OTDefaultContext should be trusted")
+            XCTAssertNotNil(egoPeerID, "Should have a peerID")
+            XCTAssertEqual(isLocked, true, "should be true")
+            XCTAssertNil(error, "error should be nil")
+            statusexpectation.fulfill()
+        }
+        self.wait(for: [statusexpectation], timeout: 10)
+
+        let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs")
+        self.manager.healthCheck(OTCKContainerName, context: OTDefaultContext, skipRateLimitingCheck: false) { error in
+            XCTAssertNil(error, "error should be nil")
+            healthCheckCallback.fulfill()
+        }
+        self.wait(for: [healthCheckCallback], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
+    }
+
+    func testBecomeUntrustedResultsInWaitForUnlock() 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: <rdar://problem/49080104> 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
+        let updateTrustExpectation = self.expectation(description: "fetchChanges")
+
+        // Ths push will only be delivered when the device is unlocked, so simulate the device locking during the fetch
+        self.fakeCuttlefishServer.fetchChangesListener = { request in
+            self.fakeCuttlefishServer.fetchChangesListener = nil
+
+            self.aksLockState = true
+            self.lockStateTracker.recheck()
+
+            updateTrustExpectation.fulfill()
+            return nil
+        }
+        peer3.notifyContainerChange(nil)
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+
+        self.assertEnters(context: peer3, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
+
+        self.aksLockState = false
+        self.lockStateTracker.recheck()
+
+        self.assertEnters(context: peer3, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfUntrusted(context: peer3)
+    }
+
+    func testEvaluateTPHOctagonTrust() throws {
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+
+        XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
+        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)
+
+        let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs")
+        self.manager.healthCheck(OTCKContainerName, context: OTDefaultContext, skipRateLimitingCheck: false) { error in
+            XCTAssertNil(error, "error should be nil")
+            healthCheckCallback.fulfill()
+        }
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateTPHTrustCheck, within: 10 * NSEC_PER_SEC)
+
+        self.aksLockState = true
+        self.lockStateTracker.recheck()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
+
+        self.wait(for: [healthCheckCallback], timeout: 10)
+
+        self.aksLockState = false
+        self.lockStateTracker.recheck()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+    }
+
+    func testEvaluateSecdOctagonTrust() throws {
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.startCKAccountStatusMock()
+
+        XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
+        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)
+
+        let leaveExpectation = self.expectation(description: "rpcLeaveClique returns")
+        self.cuttlefishContext.rpcLeaveClique { leaveError in
+            XCTAssertNil(leaveError, "Should be no error leaving")
+            leaveExpectation.fulfill()
+        }
+        self.wait(for: [leaveExpectation], timeout: 10)
+
+        let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs")
+        self.manager.healthCheck(OTCKContainerName, context: OTDefaultContext, skipRateLimitingCheck: false) { error in
+            XCTAssertNotNil(error, "error should not be nil")
+            healthCheckCallback.fulfill()
+        }
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStatePostRepairCFU, within: 10 * NSEC_PER_SEC)
+
+        self.aksLockState = true
+        self.lockStateTracker.recheck()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
+
+        self.wait(for: [healthCheckCallback], timeout: 10)
+
+        self.aksLockState = false
+        self.lockStateTracker.recheck()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+    }
 }
 
 #endif
index 70ed71e6b32f45195a7f79dff496220562b622da..7b7cb3fa2e77b77b87168e68b0391b32a2e9dcb9 100644 (file)
@@ -30,4 +30,75 @@ extension EstablishRequest {
     }
 }
 
+extension OctagonTestsBase {
+    func simulateRestart(context: OTCuttlefishContext) -> OTCuttlefishContext {
+        self.manager.removeContext(forContainerName: context.containerName, contextID: context.contextID)
+
+        if context.contextID == OTDefaultContext {
+            self.restartCKKSViews()
+        }
+
+        let newContext = self.manager.context(forContainerName: context.containerName, contextID: context.contextID)
+
+        if context.contextID == OTDefaultContext {
+            XCTAssertNil(self.injectedManager?.policy, "CKKS should not have a policy after 'restart'")
+        }
+
+        newContext.startOctagonStateMachine()
+
+        return newContext
+    }
+
+    func cliqueFor(context: OTCuttlefishContext) -> OTClique {
+        let otcliqueContext = OTConfigurationContext()
+        otcliqueContext.context = context.contextID
+        otcliqueContext.altDSID = try! context.authKitAdapter.primaryiCloudAccountAltDSID()
+        otcliqueContext.otControl = self.otControl
+
+        return OTClique(contextData: otcliqueContext)
+    }
+
+    func assertFetchUserControllableViewsSyncStatus(clique: OTClique, status: Bool) {
+        do {
+            let result = try clique.fetchUserControllableViewsSyncingEnabled()
+            XCTAssertEqual(result, status, "API should report that sync status matches expectation")
+        } catch {
+            XCTFail("Should be no error fetching status: \(error)")
+        }
+    }
+
+    func assertModifyUserViews(clique: OTClique, intendedSyncStatus: Bool) {
+        let updateTrustExpectation = self.expectation(description: "updateTrust")
+        self.fakeCuttlefishServer.updateListener = { request in
+            let newStableInfo = request.stableInfoAndSig.stableInfo()
+            if intendedSyncStatus {
+                XCTAssertEqual(newStableInfo.syncUserControllableViews, .ENABLED, "User views should now be enabled")
+            } else {
+                XCTAssertEqual(newStableInfo.syncUserControllableViews, .DISABLED, "User views should now be disabled")
+            }
+            updateTrustExpectation.fulfill()
+
+            return nil
+        }
+
+        XCTAssertNoThrow(try clique.setUserControllableViewsSyncStatus(intendedSyncStatus), "Should be no error setting user-visible sync status")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: intendedSyncStatus)
+
+        self.wait(for: [updateTrustExpectation], timeout: 10)
+        self.fakeCuttlefishServer.updateListener = nil
+    }
+
+    func assertModifyUserViewsWithNoPeerUpdate(clique: OTClique, intendedSyncStatus: Bool, finalSyncStatus: Bool? = nil) {
+        self.fakeCuttlefishServer.updateListener = { request in
+            XCTFail("Expected no updates during user view status modification")
+            return nil
+        }
+
+        XCTAssertNoThrow(try clique.setUserControllableViewsSyncStatus(intendedSyncStatus), "Should be no error setting user-visible sync status")
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: finalSyncStatus ?? intendedSyncStatus)
+
+        self.fakeCuttlefishServer.updateListener = nil
+    }
+}
+
 #endif
index 10172e3514cd8b8282f02fe43b70079f3d603cbd..9bada6c8d98051f7f4d281075add43961bc9361e 100644 (file)
@@ -14,12 +14,23 @@ extension Container {
 @objcMembers
 class OctagonRecoveryKeyTests: OctagonTestsBase {
     override func setUp() {
+        // Please don't make the SOS API calls, no matter what
+        OctagonSetSOSFeatureEnabled(false)
+
         super.setUp()
+
+        // Set this to what it normally is. Each test can muck with it, if they like
+        #if os(macOS) || os(iOS)
+        OctagonSetPlatformSupportsSOS(true)
+        self.manager.setSOSEnabledForPlatformFlag(true)
+        #else
+        self.manager.setSOSEnabledForPlatformFlag(false)
+        OctagonSetPlatformSupportsSOS(false)
+        #endif
     }
 
     func testSetRecoveryKey() throws {
         self.startCKAccountStatusMock()
-        self.manager.setSOSEnabledForPlatformFlag(false)
 
         self.cuttlefishContext.startOctagonStateMachine()
         XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
@@ -73,6 +84,7 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
 
         let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String
@@ -91,8 +103,13 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
         self.verifyDatabaseMocks()
 
+        self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
         let bottle = self.fakeCuttlefishServer.state.bottles[0]
 
         let initiatorContextID = "new guy"
@@ -111,8 +128,11 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         self.sendContainerChangeWaitForFetch(context: initiatorContext)
+
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
 
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
 
         let stableInfoCheckDumpCallback = self.expectation(description: "stableInfoCheckDumpCallback callback occurs")
@@ -178,6 +198,7 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
 
         let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String
@@ -196,6 +217,8 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
 
         let bottle = self.fakeCuttlefishServer.state.bottles[0]
 
@@ -303,10 +326,15 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             thirdPeerStableInfoCheckDumpCallback.fulfill()
         }
         self.wait(for: [thirdPeerStableInfoCheckDumpCallback], timeout: 10)
+
+        // And ensure that the original peer uploads shares for the third as well
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
     }
 
     func createEstablishContext(contextID: String) -> OTCuttlefishContext {
-
         return self.manager.context(forContainerName: OTCKContainerName,
                                     contextID: contextID,
                                     sosAdapter: self.mockSOSAdapter,
@@ -346,10 +374,11 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.assertEnters(context: establishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: establishContext)
 
+        let establishedPeerID = self.fetchEgoPeerID(context: establishContext)
+
         // Fake that this peer also created some TLKShares for itself
         self.putFakeKeyHierarchiesInCloudKit()
         try self.putSelfTLKSharesInCloudKit(context: establishContext)
-
         self.assertSelfTLKSharesInCloudKit(context: establishContext)
 
         let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String
@@ -364,8 +393,10 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         }
         self.wait(for: [createRecoveryExpectation], timeout: 10)
 
+        try self.putRecoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID))
         self.sendContainerChangeWaitForFetch(context: establishContext)
 
+        // Now, join from a new device
         let recoveryContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
 
         recoveryContext.startOctagonStateMachine()
@@ -378,8 +409,11 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        let joinedPeerID = self.fetchEgoPeerID(context: recoveryContext)
 
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.sendContainerChangeWaitForFetch(context: recoveryContext)
 
         let stableInfoCheckDumpCallback = self.expectation(description: "stableInfoCheckDumpCallback callback occurs")
@@ -427,7 +461,19 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             stableInfoAcceptorCheckDumpCallback.fulfill()
         }
         self.wait(for: [stableInfoAcceptorCheckDumpCallback], timeout: 10)
-        try self.putSelfTLKSharesInCloudKit(context: recoveryContext)
+
+        // And check the current state of the world
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: joinedPeerID, opinion: .trusts, target: joinedPeerID)),
+                       "joined peer should trust itself")
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: joinedPeerID, opinion: .trusts, target: establishedPeerID)),
+                      "joined peer should trust establish peer")
+
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: establishedPeerID, opinion: .trusts, target: establishedPeerID)),
+                       "establish peer should trust itself")
+        XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: establishedPeerID, opinion: .trusts, target: joinedPeerID)),
+                      "establish peer should trust joined peer")
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.assertSelfTLKSharesInCloudKit(context: recoveryContext)
     }
 
@@ -493,7 +539,7 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
 
         self.assertConsidersSelfTrusted(context: recoveryContext)
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC)
@@ -605,6 +651,7 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         XCTAssertNotNil(entropy, "entropy should not be nil")
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
         let bottle = self.fakeCuttlefishServer.state.bottles[0]
@@ -654,9 +701,9 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         }
         self.wait(for: [setRecoveryKeyExpectation], timeout: 10)
 
-        let recoveryKey2 = SecRKCreateRecoveryKeyString(nil)
+        let recoveryKey2 = try XCTUnwrap(SecRKCreateRecoveryKeyString(nil))
         let setRecoveryKeyExpectationAgain = self.expectation(description: "setRecoveryKeyExpectationAgain callback occurs")
-        TestsObjectiveC.setNewRecoveryKeyWithData(initiatorConfigurationContext, recoveryKey: recoveryKey2!) { rk, error in
+        TestsObjectiveC.setNewRecoveryKeyWithData(initiatorConfigurationContext, recoveryKey: recoveryKey2) { rk, error in
             XCTAssertNil(error, "error should be nil")
             XCTAssertNotNil(rk, "rk should not be nil")
             setRecoveryKeyExpectationAgain.fulfill()
@@ -664,7 +711,16 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.wait(for: [setRecoveryKeyExpectationAgain], timeout: 10)
 
         self.sendContainerChangeWaitForFetch(context: initiatorContext)
+
+        // When the original peer responds to the new peer, it should upload tlkshares for the new peer and the new RK
+        // (since the remote peer didn't upload shares for the new RK)
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey2, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey2, salt: try XCTUnwrap(self.mockAuthKit.altDSID), sender: self.cuttlefishContext))
 
         var initiatorRecoverySigningKey: Data?
         var initiatorRecoveryEncryptionKey: Data?
@@ -760,20 +816,21 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         // Fake that this peer also created some TLKShares for itself
         self.putFakeKeyHierarchiesInCloudKit()
         try self.putSelfTLKSharesInCloudKit(context: establishContext)
-
         self.assertSelfTLKSharesInCloudKit(context: establishContext)
 
-        let recoveryKey = SecRKCreateRecoveryKeyString(nil)
+        let recoveryKey = try XCTUnwrap(SecRKCreateRecoveryKeyString(nil))
         XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
         self.manager.setSOSEnabledForPlatformFlag(true)
 
         let setRecoveryKeyExpectation = self.expectation(description: "setRecoveryKeyExpectation callback occurs")
-        TestsObjectiveC.setNewRecoveryKeyWithData(recoverykeyotcliqueContext, recoveryKey: recoveryKey!) { _, error in
+        TestsObjectiveC.setNewRecoveryKeyWithData(recoverykeyotcliqueContext, recoveryKey: recoveryKey) { _, error in
             XCTAssertNil(error, "error should be nil")
             setRecoveryKeyExpectation.fulfill()
         }
         self.wait(for: [setRecoveryKeyExpectation], timeout: 10)
 
+        try self.putRecoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID))
+
         self.sendContainerChangeWaitForFetch(context: establishContext)
 
         let newCliqueContext = OTConfigurationContext()
@@ -786,17 +843,22 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         newGuyContext.startOctagonStateMachine()
 
         self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext)
+        self.verifyDatabaseMocks()
 
         self.manager.setSOSEnabledForPlatformFlag(true)
         let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
-        OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in
+        OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
 
         self.sendContainerChangeWaitForFetch(context: newGuyContext)
 
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
+
         let stableInfoAcceptorCheckDumpCallback = self.expectation(description: "stableInfoAcceptorCheckDumpCallback callback occurs")
         self.tphClient.dump(withContainer: OTCKContainerName, context: OTDefaultContext) { dump, _ in
             XCTAssertNotNil(dump, "dump should not be nil")
@@ -848,33 +910,46 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.wait(for: [stableInfoCheckDumpCallback], timeout: 10)
     }
 
-    func testOTCliqueJoinUsingANotEnrolledRecoveryKey() throws {
+    func testJoinWithUnknownRecoveryKey() throws {
         OctagonRecoveryKeySetIsEnabled(true)
-        self.manager.setSOSEnabledForPlatformFlag(false)
+
         self.startCKAccountStatusMock()
 
-        let recoveryKey = SecRKCreateRecoveryKeyString(nil)
-        XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
+        let remote = self.makeInitiatorContext(contextID: "remote")
+        self.assertResetAndBecomeTrusted(context: remote)
 
-        let newCliqueContext = OTConfigurationContext()
-        newCliqueContext.context = OTDefaultContext
-        newCliqueContext.dsid = self.otcliqueContext.dsid
-        newCliqueContext.altDSID = self.mockAuthKit.altDSID!
-        newCliqueContext.otControl = self.otControl
+        let recoveryKey = try XCTUnwrap(SecRKCreateRecoveryKeyString(nil), "recoveryKey should not be nil")
 
-        let recoveryGuyContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
-        self.manager.setSOSEnabledForPlatformFlag(true)
+        #if !os(macOS) && !os(iOS)
+        let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
+        TestsObjectiveC.recoverOctagon(usingData: self.otcliqueContext, recoveryKey: recoveryKey) { error in
+            XCTAssertNotNil(error, "error should exist")
+            joinWithRecoveryKeyExpectation.fulfill()
+        }
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        // double-check that the status is not in
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
+
+        #else
 
         let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
-        TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in
+        TestsObjectiveC.recoverOctagon(usingData: self.otcliqueContext, recoveryKey: recoveryKey) { error in
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
 
-        self.sendContainerChange(context: recoveryGuyContext)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
 
-        let newGuyCheckDumpCallback = self.expectation(description: "newGuyCheckDumpCallback callback occurs")
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
+        self.verifyDatabaseMocks()
+
+        let rejoinedDumpCallback = self.expectation(description: "dump callback occurs")
         self.tphClient.dump(withContainer: OTCKContainerName, context: OTDefaultContext) { dump, _ in
             XCTAssertNotNil(dump, "dump should not be nil")
             let egoSelf = dump!["self"] as? [String: AnyObject]
@@ -892,12 +967,10 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             XCTAssertEqual(included!.count, 1, "should be 1 peer ids")
             let vouchers = dump!["vouchers"]
             XCTAssertNotNil(vouchers, "vouchers should not be nil")
-            newGuyCheckDumpCallback.fulfill()
+            rejoinedDumpCallback.fulfill()
         }
-        self.wait(for: [newGuyCheckDumpCallback], timeout: 10)
-        self.assertEnters(context: recoveryGuyContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-
-        self.assertSelfTLKSharesInCloudKit(context: recoveryGuyContext)
+        self.wait(for: [rejoinedDumpCallback], timeout: 10)
+        #endif
     }
 
     func testSetRecoveryKeyAsLimitedPeer() throws {
@@ -974,12 +1047,11 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.assertSelfTLKSharesInCloudKit(context: establishContext)
 
-        let recoveryKey = SecRKCreateRecoveryKeyString(nil)
-        XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
+        let recoveryKey = try XCTUnwrap(SecRKCreateRecoveryKeyString(nil), "should be able to create a recovery key")
         self.manager.setSOSEnabledForPlatformFlag(true)
 
         let setRecoveryKeyExpectation = self.expectation(description: "setRecoveryKeyExpectation callback occurs")
-        TestsObjectiveC.setNewRecoveryKeyWithData(recoverykeyotcliqueContext, recoveryKey: recoveryKey!) { _, error in
+        TestsObjectiveC.setNewRecoveryKeyWithData(recoverykeyotcliqueContext, recoveryKey: recoveryKey) { _, error in
             XCTAssertNil(error, "error should be nil")
             setRecoveryKeyExpectation.fulfill()
         }
@@ -1005,13 +1077,19 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.sendContainerChangeWaitForUntrustedFetch(context: newGuyContext)
 
+        // We'll perform a reset here. Allow for CKKS to do the same.
+        self.silentZoneDeletesAllowed = true
+
         self.manager.setSOSEnabledForPlatformFlag(true)
         let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
-        OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in
+        OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
     }
 
     func testVouchWithWrongRecoveryKey() throws {
@@ -1081,11 +1159,16 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         recoveryKey = SecRKCreateRecoveryKeyString(nil)
         XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
 
+        // We'll reset Octagon here, so allow for CKKS to reset as well
+        self.silentZoneDeletesAllowed = true
+
         OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
     }
 
     func testRecoveryWithDistrustedPeers() throws {
@@ -1137,6 +1220,8 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.sendContainerChangeWaitForFetch(context: establishContext)
 
+        try self.putRecoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey!, salt: self.mockAuthKit.altDSID!)
+
         //now this peer will leave octagon
         XCTAssertNoThrow(try clique.leave(), "Should be no error departing clique")
 
@@ -1158,11 +1243,17 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.manager.setSOSEnabledForPlatformFlag(true)
         let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
 
+        // We expect an Octagon reset here, because the RK is for a distrusted peer
+        // This also performs a CKKS reset
+        self.silentZoneDeletesAllowed = true
+
         OTClique.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey!) { error in
             XCTAssertNil(error, "error should be nil")
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
     }
 
     func testMalformedRecoveryKey() throws {
@@ -1233,27 +1324,26 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             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)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
     }
 
     @discardableResult
-    func createAndSetRecoveryKey(context: OTCuttlefishContext) -> String {
+    func createAndSetRecoveryKey(context: OTCuttlefishContext) throws -> String {
         let cliqueConfiguration = OTConfigurationContext()
         cliqueConfiguration.context = context.contextID
         cliqueConfiguration.altDSID = try! context.authKitAdapter.primaryiCloudAccountAltDSID()
         cliqueConfiguration.otControl = self.otControl
 
-        let recoveryKey = SecRKCreateRecoveryKeyString(nil)
-        XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
+        let recoveryKey = try XCTUnwrap(SecRKCreateRecoveryKeyString(nil), "should be able to create a recovery key")
 
         let setRecoveryKeyExpectation = self.expectation(description: "setRecoveryKeyExpectation callback occurs")
-        TestsObjectiveC.setNewRecoveryKeyWithData(cliqueConfiguration, recoveryKey: recoveryKey!) { _, error in
+        TestsObjectiveC.setNewRecoveryKeyWithData(cliqueConfiguration, recoveryKey: recoveryKey) { _, error in
             XCTAssertNil(error, "error should be nil")
             setRecoveryKeyExpectation.fulfill()
         }
         self.wait(for: [setRecoveryKeyExpectation], timeout: 10)
 
-        return recoveryKey!
+        return recoveryKey
     }
 
     func testConcurWithTrustedPeer() throws {
@@ -1271,8 +1361,8 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         // peer1 sets a recovery key
-        var rkSigningPubKey : Data? = nil
-        var rkEncryptionPubKey : Data? = nil
+        var rkSigningPubKey: Data?
+        var rkEncryptionPubKey: Data?
 
         let setRKExpectation = self.expectation(description: "setRecoveryKey")
         self.fakeCuttlefishServer.setRecoveryKeyListener = { request in
@@ -1286,7 +1376,7 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
             return nil
         }
 
-        self.createAndSetRecoveryKey(context: self.cuttlefishContext)
+        try self.createAndSetRecoveryKey(context: self.cuttlefishContext)
         self.wait(for: [setRKExpectation], timeout: 10)
 
         // And peer2 concurs with it upon receiving a push
@@ -1317,9 +1407,9 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.startCKAccountStatusMock()
         self.manager.setSOSEnabledForPlatformFlag(true)
 
-        let _ = self.assertResetAndBecomeTrustedInDefaultContext()
+        _ = self.assertResetAndBecomeTrustedInDefaultContext()
         // peer1 sets a recovery key
-        self.createAndSetRecoveryKey(context: self.cuttlefishContext)
+        try self.createAndSetRecoveryKey(context: self.cuttlefishContext)
 
         // Restart TPH
         self.tphClient.containerMap.removeAllContainers()
@@ -1331,9 +1421,9 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
         self.startCKAccountStatusMock()
         self.manager.setSOSEnabledForPlatformFlag(true)
 
-        let _ = self.assertResetAndBecomeTrustedInDefaultContext()
+        _ = self.assertResetAndBecomeTrustedInDefaultContext()
         // peer1 sets a recovery key
-        self.createAndSetRecoveryKey(context: self.cuttlefishContext)
+        try self.createAndSetRecoveryKey(context: self.cuttlefishContext)
 
         // Before restarting TPH, emulate a world in which the RK variables were not set on the container
 
@@ -1346,5 +1436,131 @@ class OctagonRecoveryKeyTests: OctagonTestsBase {
 
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
     }
+
+    func testCKKSSendsTLKSharesToRecoveryKey() throws {
+        #if os(tvOS) || os(watchOS)
+        self.startCKAccountStatusMock()
+        throw XCTSkip("Apple TVs and watches will not set recovery key")
+        #else
+
+        self.startCKAccountStatusMock()
+
+        // To get into a state where we don't upload the TLKShares to each RK on RK creation, put Octagon into a waitfortlk state
+        // Right after CKKS fetches for the first time, insert a new key hierarchy into CloudKit
+        self.silentFetchesAllowed = false
+        self.expectCKFetchAndRun {
+            self.putFakeKeyHierarchiesInCloudKit()
+            self.putFakeDeviceStatusesInCloudKit()
+            self.silentFetchesAllowed = true
+        }
+
+        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'
+        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 waitfortlk, as they don't have the TLKs uploaded by the other peer
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
+        // And a recovery key is set
+        let recoveryKey = try self.createAndSetRecoveryKey(context: self.cuttlefishContext)
+
+        // and now, all TLKs arrive! CKKS should upload two shares: one for itself, and one for the recovery key
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
+        self.saveTLKMaterialToKeychain()
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID)))
+
+        #endif // tvOS || watchOS
+    }
+
+    func testRKRecoveryRecoversCKKSCreatedShares() throws {
+        self.startCKAccountStatusMock()
+
+        let remote = self.createEstablishContext(contextID: "remote")
+        self.assertResetAndBecomeTrusted(context: remote)
+
+        #if os(tvOS) || os(watchOS)
+        self.manager.setSOSEnabledForPlatformFlag(true)
+        let recoveryKey = try self.createAndSetRecoveryKey(context: remote)
+        self.manager.setSOSEnabledForPlatformFlag(false)
+        #else
+        let recoveryKey = try self.createAndSetRecoveryKey(context: remote)
+        #endif
+
+        // And TLKShares for the RK are sent from the Octagon peer
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putRecoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID), sender: remote)
+        XCTAssertTrue(try self.recoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID), sender: remote))
+
+        // Now, join! This should recover the TLKs.
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+
+        let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs")
+        self.cuttlefishContext.join(withRecoveryKey: recoveryKey) { error in
+            XCTAssertNil(error, "error should be nil")
+            joinWithRecoveryKeyExpectation.fulfill()
+        }
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+    }
+
+    func testRecoverTLKSharesSentToRKAfterCKKSTimeout() throws {
+        OctagonRecoveryKeySetIsEnabled(true)
+        self.manager.setSOSEnabledForPlatformFlag(false)
+        self.startCKAccountStatusMock()
+
+        let remote = self.createEstablishContext(contextID: "remote")
+        self.assertResetAndBecomeTrusted(context: remote)
+
+        // Fake that this peer also created some TLKShares for itself
+        self.putFakeKeyHierarchiesInCloudKit()
+        try self.putSelfTLKSharesInCloudKit(context: remote)
+        self.assertSelfTLKSharesInCloudKit(context: remote)
+
+        self.manager.setSOSEnabledForPlatformFlag(true)
+        let recoveryKey = try self.createAndSetRecoveryKey(context: remote)
+
+        try self.putRecoveryKeyTLKSharesInCloudKit(recoveryKey: recoveryKey, salt: try XCTUnwrap(self.mockAuthKit.altDSID))
+
+        // Now, join from a new device
+        // Simulate CKKS fetches taking forever. In practice, this is caused by many round-trip fetches to CK happening over minutes.
+        self.holdCloudKitFetches()
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKey callback occurs")
+        self.cuttlefishContext.join(withRecoveryKey: recoveryKey) { error in
+            XCTAssertNil(error, "error should be nil")
+            joinWithRecoveryKeyExpectation.fulfill()
+        }
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateFetch, within: 10 * NSEC_PER_SEC)
+
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.releaseCloudKitFetchHold()
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+        self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
+    }
 }
 #endif
index db3fb52f508579ea791bfeab3ba445b3d18aea17..8daace771d16cf5e4ba932561af47ed79cc597da 100644 (file)
@@ -117,8 +117,8 @@ class OctagonResetTests: OctagonTestsBase {
         self.verifyDatabaseMocks()
 
         // CKKS should pass through "waitfortrust" during a reset
-        let waitfortrusts = self.ckksViews.compactMap { view in
-            (view as! CKKSKeychainView).keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] as? CKKSCondition
+        let waitfortrusts = self.injectedManager!.views.allValues.map { view in
+            (view as! CKKSKeychainView).keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust]!
         }
         XCTAssert(!waitfortrusts.isEmpty, "Should have at least one waitfortrust condition")
 
@@ -148,6 +148,7 @@ class OctagonResetTests: OctagonTestsBase {
 
     func testOctagonResetAlsoResetsCKKSViewsMissingTLKs() {
         self.putFakeKeyHierarchiesInCloudKit()
+        self.putFakeDeviceStatusesInCloudKit()
 
         let zoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
         XCTAssertNotNil(zoneKeys, "Should have some zone keys")
@@ -157,7 +158,7 @@ class OctagonResetTests: OctagonTestsBase {
         self.cuttlefishContext.startOctagonStateMachine()
         XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
 
         self.silentZoneDeletesAllowed = true
 
@@ -167,7 +168,7 @@ class OctagonResetTests: OctagonTestsBase {
             XCTFail("failed to make new friends: \(error)")
         }
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         let laterZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
         XCTAssertNotNil(laterZoneKeys, "Should have some zone keys")
@@ -239,7 +240,8 @@ class OctagonResetTests: OctagonTestsBase {
     }
 
     func testOctagonResetWithRemoteDevicesWithKeysDoesNotResetCKKS() {
-        // CKKS has no keys, and there's another device claiming to have them already, so CKKS won't immediately reset it
+        // CKKS has no keys, and there's another device claiming to have them already, so CKKS won't immediately reset it.
+        // But, Octagon will!
         self.putFakeKeyHierarchiesInCloudKit()
         self.putFakeDeviceStatusesInCloudKit()
 
@@ -266,13 +268,13 @@ class OctagonResetTests: OctagonTestsBase {
             XCTFail("failed to make new friends: \(error)")
         }
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         #if !os(tvOS)
         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")
+        XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should not have the same keys - a reset should have occurred")
         #else
         let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
         XCTAssertNil(laterZoneKeys, "Should have no Manatee zone keys for aTV")
@@ -281,7 +283,7 @@ class OctagonResetTests: OctagonTestsBase {
         let lpLaterZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
         XCTAssertNotNil(lpLaterZoneKeys, "Should have some zone keys for LimitedPeersAllowed")
         XCTAssertNotNil(lpLaterZoneKeys?.tlk, "Should have a tlk in the newly created keyset for LimitedPeersAllowed")
-        XCTAssertEqual(lpZoneKeys?.tlk?.uuid, lpLaterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys for LimitedPeersAllowed")
+        XCTAssertNotEqual(lpZoneKeys?.tlk?.uuid, lpLaterZoneKeys?.tlk?.uuid, "CKKS zone should not have the same keys for LimitedPeersAllowed - a reset should have occurred")
     }
 
     func testOctagonResetWithTLKsDoesNotResetCKKS() {
@@ -357,6 +359,19 @@ class OctagonResetTests: OctagonTestsBase {
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
+
+        // And after this reset, can we put together an escrow record?
+        let escrowContentsExpectation = self.expectation(description: "fetchEscrowContents")
+        self.cuttlefishContext.fetchEscrowContents { entropy, bottleID, signingPubKey, error in
+            XCTAssertNil(error, "Should be no error fetching escrow contents")
+
+            XCTAssertNotNil(entropy, "Should have some entropy")
+            XCTAssertNotNil(bottleID, "Should have some bottleID")
+            XCTAssertNotNil(signingPubKey, "Should have some signing public key")
+
+            escrowContentsExpectation.fulfill()
+        }
+        self.wait(for: [escrowContentsExpectation], timeout: 10)
     }
 
     func testResetReasonUnknown() throws {
@@ -439,15 +454,6 @@ class OctagonResetTests: OctagonTestsBase {
 
         _ = 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")
 
@@ -457,15 +463,42 @@ class OctagonResetTests: OctagonTestsBase {
         newCliqueContext.altDSID = self.mockAuthKit.altDSID!
         newCliqueContext.otControl = self.otControl
 
+        // Calling with an unknown RK only resets if the local device is SOS capable, so pretend it is
+        OctagonSetSOSFeatureEnabled(false)
+        #if os(macOS) || os(iOS)
+        OctagonSetPlatformSupportsSOS(true)
+        self.manager.setSOSEnabledForPlatformFlag(true)
+
+        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
+        }
+        #else
+        self.manager.setSOSEnabledForPlatformFlag(false)
+        OctagonSetPlatformSupportsSOS(false)
+        #endif
+
         let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
         TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in
+            #if os(macOS) || os(iOS)
             XCTAssertNil(error, "error should be nil")
+            #else
+            XCTAssertNotNil(error, "error should not be nil")
+            #endif
             joinWithRecoveryKeyExpectation.fulfill()
         }
-        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
-        self.wait(for: [resetExpectation], timeout: 10)
+        self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 20)
 
+        #if os(macOS) || os(iOS)
+        self.wait(for: [resetExpectation], timeout: 10)
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        #else
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        #endif
         self.verifyDatabaseMocks()
     }
 
@@ -509,11 +542,9 @@ class OctagonResetTests: OctagonTestsBase {
             throw error
         }
         self.wait(for: [resetExpectation], timeout: 10)
-
     }
 
     func testResetReasonHealthCheck() throws {
-
         let containerName = OTCKContainerName
         let contextName = OTDefaultContext
 
@@ -564,7 +595,8 @@ class OctagonResetTests: OctagonTestsBase {
         }
         self.wait(for: [healthCheckCallback, resetExpectation], timeout: 10)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
 
         let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
@@ -575,9 +607,6 @@ class OctagonResetTests: OctagonTestsBase {
             dumpCallback.fulfill()
         }
         self.wait(for: [dumpCallback], timeout: 10)
-
-        self.verifyDatabaseMocks()
-        self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
     }
 
     func testLegacyJoinCircleDoesNotReset() throws {
@@ -767,7 +796,7 @@ class OctagonResetTests: OctagonTestsBase {
         self.wait(for: [joinWithBottleExpectation], timeout: 10)
 
         self.assertEnters(context: joinerContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        self.assertConsidersSelfTrusted(context:joinerContext)
+        self.assertConsidersSelfTrusted(context: joinerContext)
 
         self.silentZoneDeletesAllowed = true
 
@@ -783,17 +812,32 @@ class OctagonResetTests: OctagonTestsBase {
 
         self.sendContainerChangeWaitForFetchForStates(context: joinerContext, states: [OctagonStateUntrusted])
         self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext, states: [OctagonStateReady])
-        self.assertConsidersSelfTrusted(context:self.cuttlefishContext)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
         let statusExpectation = self.expectation(description: "status callback occurs")
         let configuration = OTOperationConfiguration()
 
-        joinerContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in
+        joinerContext.rpcTrustStatus(configuration) { egoStatus, _, _, _, _, _ in
             XCTAssertEqual(.notIn, egoStatus, "cliqueStatus should be 'Not In'")
             statusExpectation.fulfill()
         }
         self.wait(for: [statusExpectation], timeout: 10)
+    }
+
+    func testAcceptResetRemovesSelfPeer() throws {
+        self.startCKAccountStatusMock()
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        let otherPeer = self.makeInitiatorContext(contextID: "peer2")
+        self.assertResetAndBecomeTrusted(context: otherPeer)
+
+        // And we get told about the reset
+        self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext,
+                                                      states: [OctagonStateReadyUpdated,
+                                                               OctagonStateUntrusted, ])
 
+        XCTAssertEqual(self.cuttlefishContext.stateMachine.paused.wait(5 * NSEC_PER_SEC), 0, "State machine should have paused")
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 1 * NSEC_PER_SEC)
     }
 }
 
index 11961ed33c1ae90a75f38cc7c8a169b2a85920aa..b1640e564cccdc965007cc0258c8adfd1f4b850d 100644 (file)
@@ -1,7 +1,6 @@
 #if OCTAGON
 
 class OctagonSOSTests: OctagonTestsBase {
-
     func testSOSOctagonKeyConsistency() throws {
         self.putFakeKeyHierarchiesInCloudKit()
         self.putSelfTLKSharesInCloudKit()
@@ -67,11 +66,13 @@ class OctagonSOSTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         self.verifyDatabaseMocks()
         self.waitForCKModifications()
 
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
         self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
 
         let peerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID()
@@ -85,8 +86,6 @@ class OctagonSOSTests: OctagonTestsBase {
         self.aksLockState = true
         self.lockStateTracker.recheck()
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
-
         // Now restart the context
         self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
         self.restartCKKSViews()
@@ -124,17 +123,18 @@ class OctagonSOSTests: OctagonTestsBase {
         self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
 
         XCTAssertTrue(OctagonPerformSOSUpgrade(), "SOS upgrade should be on")
+
         self.cuttlefishContext.startOctagonStateMachine()
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
-
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
         self.waitForCKModifications()
 
         self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
+        self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
 
         let peerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID()
         XCTAssertNotNil(peerID, "Should have a peer ID")
@@ -144,11 +144,6 @@ class OctagonSOSTests: OctagonTestsBase {
 
         self.mockSOSAdapter.trustedPeers.add(newSOSPeer)
 
-        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
-        self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
-
         // Now restart the context
         self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
         self.restartCKKSViews()
@@ -160,7 +155,7 @@ class OctagonSOSTests: OctagonTestsBase {
         self.lockStateTracker.recheck()
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
 
         self.assertAllCKKSViewsUpload(tlkShares: 2)
         self.aksLockState = false
@@ -176,7 +171,7 @@ class OctagonSOSTests: OctagonTestsBase {
 
         self.verifyDatabaseMocks()
         self.waitForCKModifications()
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
     }
 
     func testSOSPerformOctagonKeyConsistencyOnCircleChange() throws {
@@ -241,11 +236,16 @@ class OctagonSOSTests: OctagonTestsBase {
             XCTAssertNotNil(error, "error should not be nil")
         }
 
+        /*
+         * I don't see any way in swift to call a deprecated API.
+         * But, since we're not actually testing behavior here, it's
+         * okay to ignore.
         do {
             try clique.safariPasswordSyncingEnabled()
         } catch {
             XCTAssertNotNil(error, "error should not be nil")
         }
+         */
 
         do {
             try clique.waitForInitialSync()
@@ -253,7 +253,12 @@ class OctagonSOSTests: OctagonTestsBase {
             XCTAssertNotNil(error, "error should not be nil")
         }
 
+        /*
+         * I don't see any way in swift to call a deprecated API.
+         * But, since we're not actually testing behavior here, it's
+         * okay to ignore.
         clique.viewSet(Set(), disabledViews: Set())
+         */
 
         do {
             try clique.setUserCredentialsAndDSID("", password: Data())
index 86e5caf39f3b916dda8660eb7b0f9ae42b5055a8..671bed8360897d229cbf94a5c72e9e27101bf279 100644 (file)
@@ -38,6 +38,15 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         // Also, CKKS should be configured with the prevailing policy version
         XCTAssertNotNil(self.injectedManager?.policy, "Should have given CKKS a TPPolicy during SOS upgrade")
         XCTAssertEqual(self.injectedManager?.policy?.version, prevailingPolicyVersion, "Policy given to CKKS should be prevailing policy")
+
+        // And we should have followed the SOS Safari view state
+        XCTAssertTrue(self.mockSOSAdapter.safariViewEnabled, "SOS adapter should say that the safari view is enabled")
+
+        // And we should have told SOS that CKKS4All is on
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
+
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
     }
 
     // Verify that an SOS upgrade only does one establish (and no update trust).
@@ -208,6 +217,8 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         self.wait(for: [establishExpectation], timeout: 10)
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
+        XCTAssertFalse(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should not have been told that CKKS4All is enabled")
+
         // It should be paused
         XCTAssertEqual(self.cuttlefishContext.stateMachine.possiblePendingFlags(), [], "Should have zero pending flags after 'not reachable'")
     }
@@ -286,6 +297,90 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC)
     }
 
+    func testDontSOSUpgradeIfWouldRemovePreapprover() throws {
+        // If a remote peer resets Octagon, they might preapprove the local device's SOS identity.
+        // But, if the local device responds to the reset and rejoins, it might not have received the
+        // SOS circle containing the remote peer.
+        //
+        // In that case, it should accept its kicked-out fate and not rejoin (and kick out the reset device).
+
+        self.putFakeKeyHierarchiesInCloudKit()
+        self.putSelfTLKSharesInCloudKit()
+        self.saveTLKMaterialToKeychain()
+
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.startCKAccountStatusMock()
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.verifyDatabaseMocks()
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
+        // Now, peer2 comes along, and resets the world
+
+        let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID")
+        // but note: this peer is not yet added to the mockSOSAdapter
+        let peer2mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer2SOSMockPeer,
+                                                     trustedPeers: self.mockSOSAdapter.allPeers(),
+                                                     essential: false)
+        let peer2 = self.makeInitiatorContext(contextID: "peer2",
+                                              authKitAdapter: self.mockAuthKit2,
+                                              sosAdapter: peer2mockSOS)
+
+        self.assertResetAndBecomeTrusted(context: peer2)
+
+        // Peer1 should accept the reset, and not rejoin.
+        self.fakeCuttlefishServer.joinListener = { _ in
+            XCTFail("Should not have attemped to re-join")
+            return nil
+        }
+
+        self.sendContainerChangeWaitForFetchForStates(context: self.cuttlefishContext,
+                                                      states: [OctagonStateReadyUpdated,
+                                                               OctagonStateBecomeUntrusted,
+                                                               OctagonStateAttemptSOSUpgrade,
+                                                               OctagonStateUntrusted, ])
+
+        XCTAssertEqual(self.cuttlefishContext.stateMachine.paused.wait(5 * NSEC_PER_SEC), 0, "State machine should have paused")
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 1 * NSEC_PER_SEC)
+
+        // But when SOS does catch up, we join just fine.
+        self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer)
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
+
+        self.fakeCuttlefishServer.joinListener = { joinRequest in
+            let newDynamicInfo = joinRequest.peer.dynamicInfoAndSig.dynamicInfo()
+            XCTAssertEqual(newDynamicInfo.includedPeerIDs.count, 2, "Peer should trust two identities")
+            return nil
+        }
+
+        self.mockSOSAdapter.sendTrustedPeerSetChangedUpdate()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
+
+        self.verifyDatabaseMocks()
+    }
+
+    func testDontSOSUpgradeIfErrorFetchingPeers() throws {
+        self.putFakeKeyHierarchiesInCloudKit()
+        self.putSelfTLKSharesInCloudKit()
+        self.saveTLKMaterialToKeychain()
+
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.mockSOSAdapter.trustedPeersError = NSError(domain: NSOSStatusErrorDomain,
+                                                        code: 1)
+        self.startCKAccountStatusMock()
+        self.cuttlefishContext.startOctagonStateMachine()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateAttemptSOSUpgrade, within: 10 * NSEC_PER_SEC)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+    }
+
     func testSOSJoin() throws {
         if !OctagonPerformSOSUpgrade() {
             return
@@ -314,6 +409,10 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
 
+        XCTAssertTrue(self.mockSOSAdapter.safariViewEnabled, "SOS adapter should say that the safari view is enabled")
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+
         // Peer1 should have sent a request for silent escrow update
         self.wait(for: [peer1EscrowRequestNotification], timeout: 5)
 
@@ -340,6 +439,9 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         self.assertEnters(context: peer2, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: peer2)
 
+        XCTAssertTrue(peer2mockSOS.safariViewEnabled, "SOS adapter should say that the safari view is enabled")
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2), status: true)
+
         // Peer2 should have sent a request for silent escrow update
         self.wait(for: [peer2EscrowRequestNotification], timeout: 5)
 
@@ -354,12 +456,108 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
                        "peer 1 should not trust peer 2 (as it hasn't responded to peer2's upgradeJoin yet)")
 
         // Now, tell peer1 about the change
+        self.assertAllCKKSViewsUpload(tlkShares: 1)
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
 
         // Peer1 should trust peer2 now, since it upgraded it from implicitly explicitly trusted
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
                       "peer 1 should trust peer 2 after update")
         XCTAssertEqual(self.fakeCuttlefishServer.state.bottles.count, 2, "should be 2 bottles")
+
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+    }
+
+    func testSOSJoinWithDisabledSafariView() throws {
+        self.startCKAccountStatusMock()
+
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.mockSOSAdapter.safariViewEnabled = false
+
+        let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID")
+        self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer)
+
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
+        self.cuttlefishContext.startOctagonStateMachine()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        XCTAssertFalse(self.mockSOSAdapter.safariViewEnabled, "SOS adapter should say that the safari view is disabled")
+
+        #if os(tvOS)
+        // TVs won't ever turn this off
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        #else
+        // Watches don't have SOS, but in this test, we fake that they do. They should follow "SOS"'s state, just like phones and macs
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+        #endif
+
+        let peer2mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer2SOSMockPeer,
+                                                     trustedPeers: self.mockSOSAdapter.allPeers(),
+                                                     essential: false)
+        peer2mockSOS.safariViewEnabled = 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)
+
+        #if os(tvOS)
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2), status: true)
+        #else
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2), status: false)
+        #endif
+    }
+
+    func testSOSJoinWithEnabledSafariViewButDisabledByPeer() throws {
+        self.startCKAccountStatusMock()
+
+        // This peer joins with disabled user views
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.mockSOSAdapter.safariViewEnabled = false
+
+        let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID")
+        self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer)
+
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
+        self.cuttlefishContext.startOctagonStateMachine()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
+        XCTAssertFalse(self.mockSOSAdapter.safariViewEnabled, "SOS adapter should say that the safari view is disabled")
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
+        let clique = self.cliqueFor(context: self.cuttlefishContext)
+
+        #if os(tvOS)
+        //  TVs won't ever turn this off
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: true)
+        #else
+        // Watches don't have SOS, but in this test, we fake that they do. They should follow "SOS"'s state, just like phones and macs
+        self.assertFetchUserControllableViewsSyncStatus(clique: clique, status: false)
+        #endif
+
+        let peer2mockSOS = CKKSMockSOSPresentAdapter(selfPeer: peer2SOSMockPeer,
+                                                     trustedPeers: self.mockSOSAdapter.allPeers(),
+                                                     essential: false)
+        // peer2 joins via SOS preapproval, but with the safari view enabled. It should enable user view syncing, even though the other peer has it off
+        peer2mockSOS.safariViewEnabled = true
+
+        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)
+
+        self.assertFetchUserControllableViewsSyncStatus(clique: self.cliqueFor(context: peer2), status: true)
     }
 
     func testSOSJoinUponNotificationOfPreapproval() throws {
@@ -382,6 +580,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         XCTAssertNotNil(peerID, "Should have a peer ID after making new friends")
 
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
 
         // Peer 2 attempts to join via preapproval
         let peer2SOSMockPeer = self.createSOSPeer(peerID: "peer2ID")
@@ -499,7 +698,6 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
 
                 updateTrustExpectation2.fulfill()
                 return nil
-
             }
             updateTrustExpectation1.fulfill()
 
@@ -691,10 +889,11 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         // Now, the circle status changes
 
         self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.mockSOSAdapter.trustedPeers.add(originalPeerSOSMockPeer)
         self.cuttlefishContext.startOctagonStateMachine()
 
         // Peer1 should upload TLKShares for SOS Peer2 via CK CRUD. We should probably fix that someday?
-        self.assertAllCKKSViewsUpload(tlkShares: 1)
+        self.assertAllCKKSViewsUpload(tlkShares: 2)
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 40 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
@@ -768,6 +967,90 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
 
         self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
+    }
+
+    func testNotInSOSCircleAndWaitForUpgrade() throws {
+        self.putFakeKeyHierarchiesInCloudKit()
+        self.putSelfTLKSharesInCloudKit()
+        self.saveTLKMaterialToKeychain()
+
+        self.startCKAccountStatusMock()
+
+        self.mockSOSAdapter.sosEnabled = true
+        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)
+
+        let upgradeExpectation = self.expectation(description: "waitForOctagonUpgrade")
+        self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: self.otcliqueContext.context) { error in
+            XCTAssertNotNil(error, "error should not be nil")
+            XCTAssertEqual((error! as NSError).domain, "com.apple.security.sos.error", "domain should be com.apple.security.sos.error")
+            XCTAssertEqual((error! as NSError).code, 1037, "code should be 1037")
+            upgradeExpectation.fulfill()
+        }
+        self.wait(for: [upgradeExpectation], timeout: 2)
+    }
+
+    func testSosUpgradeFromDisabledCDPStatus() throws {
+        self.putFakeKeyHierarchiesInCloudKit()
+        self.putSelfTLKSharesInCloudKit()
+        self.saveTLKMaterialToKeychain()
+
+        self.startCKAccountStatusMock()
+
+        self.mockSOSAdapter.sosEnabled = true
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCCircleAbsent)
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForCDP, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.fetchCDPStatus(context: self.cuttlefishContext), .disabled, "CDP status should be 'disabled'")
+
+        // SOS arrives!
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+
+        // Attempting the upgrade succeeds, now that SOS is present
+        let upgradeExpectation = self.expectation(description: "waitForOctagonUpgrade")
+        self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: self.otcliqueContext.context) { error in
+            XCTAssertNil(error, "operation should not fail")
+            upgradeExpectation.fulfill()
+        }
+        self.wait(for: [upgradeExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 40 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        XCTAssertEqual(self.fetchCDPStatus(context: self.cuttlefishContext), .enabled, "CDP status should be 'enabled'")
+
+        self.verifyDatabaseMocks()
+
+        self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+    }
+
+    func testSosUpgradeAPIWhenCDPStateOff() {
+        // this test checks that calling waitForOctagonUpgrade (when SOS is still absent) doesn't unconditionally set the CDP bit.
+        self.startCKAccountStatusMock()
+
+        self.mockSOSAdapter.sosEnabled = true
+        self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCCircleAbsent)
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForCDP, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.fetchCDPStatus(context: self.cuttlefishContext), .disabled, "CDP status should be 'disabled'")
+
+        let upgradeExpectation = self.expectation(description: "waitForOctagonUpgrade")
+        self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: self.otcliqueContext.context) { error in
+            XCTAssertNotNil(error, "operation should have failed - SOS is absent and Octagon cannot upgrade from it")
+            XCTAssertEqual((error! as NSError).domain, "com.apple.security.sos.error", "domain should be com.apple.security.sos.error")
+            XCTAssertEqual((error! as NSError).code, kSOSErrorNoCircle, "code should be kSOSErrorNoCircle")
+            upgradeExpectation.fulfill()
+        }
+        self.wait(for: [upgradeExpectation], timeout: 10)
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateWaitForCDP, within: 10 * NSEC_PER_SEC)
+        XCTAssertEqual(self.fetchCDPStatus(context: self.cuttlefishContext), .disabled, "CDP status should be 'disabled'")
     }
 
     func testDoNotAttemptUpgradeOnRestart() throws {
@@ -784,12 +1067,11 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         }
 
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
         self.verifyDatabaseMocks()
         self.waitForCKModifications()
         self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         let peerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID()
         XCTAssertNotNil(peerID, "Should have a peer ID after making new friends")
@@ -798,15 +1080,11 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         self.assertAllCKKSViewsUpload(tlkShares: 1)
 
         self.mockSOSAdapter.circleStatus = SOSCCStatus(kSOSCCInCircle)
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
 
-        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)
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
-
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
 
         let restartedPeerID = try self.cuttlefishContext.accountMetadataStore.getEgoPeerID()
         XCTAssertNotNil(restartedPeerID, "Should have a peer ID after restarting")
@@ -1015,7 +1293,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         self.verifyDatabaseMocks()
         self.waitForCKModifications()
@@ -1053,13 +1331,12 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         self.mockSOSAdapter.trustedPeers.add(peer2SOSMockPeer)
 
         // But, SOS doesn't send this update. Let's test that the upload occurs on the next securityd restart
-        self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
-        self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
-        self.cuttlefishContext.startOctagonStateMachine()
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
 
         self.verifyDatabaseMocks()
         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)
 
         // BUT, a second restart shouldn't hit the server
 
@@ -1067,10 +1344,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
             XCTFail("shouldn't have updateTrusted")
             return nil
         }
-        self.manager.removeContext(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
-        self.cuttlefishContext = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
-        self.cuttlefishContext.startOctagonStateMachine()
-
+        self.cuttlefishContext = self.simulateRestart(context: self.cuttlefishContext)
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
     }
 
@@ -1236,6 +1510,21 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
 
         self.cuttlefishContext.startOctagonStateMachine()
 
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateAttemptSOSUpgrade, within: 10 * NSEC_PER_SEC)
+
+        let updateChangesExpectation = self.expectation(description: "fetchChanges")
+        self.fakeCuttlefishServer.fetchChangesListener = { request in
+            self.fakeCuttlefishServer.fetchChangesReturnEmptyResponse = true
+            updateChangesExpectation.fulfill()
+            self.fakeCuttlefishServer.fetchChangesListener = nil
+            self.mockAuthKit.machineIDFetchErrors.append(NSError(domain: AKAppleIDAuthenticationErrorDomain,
+                                                                 code: AKAppleIDAuthenticationError.authenticationErrorCannotFindServer.rawValue,
+                                                                 userInfo: nil))
+
+            return nil
+        }
+        self.wait(for: [updateChangesExpectation], timeout: 10)
+
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
     }
@@ -1366,7 +1655,7 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
 
         // 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
+        peer3.waitForOctagonUpgrade { error in
             XCTAssertNotNil(error, "should be an error performing an SOS upgrade (the second time)")
             upgradeExpectation.fulfill()
         }
@@ -1384,6 +1673,80 @@ class OctagonSOSUpgradeTests: OctagonTestsBase {
         }
         self.wait(for: [upgradeWaitExpectation], timeout: 5)
     }
+
+    func testSOSJoinByPreapprovalAfterUnknownState() 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: <rdar://problem/49080104> 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")
+
+        let container = try! self.tphClient.getContainer(withContainer: self.cuttlefishContext.containerName, context: "peer3")
+        container.moc.performAndWait {
+            container.model.deletePeer(withID: peer3ID)
+        }
+
+        // And we notify peer3 about this, and it should become sad
+        self.sendContainerChangeWaitForFetchForStates(context: peer3, states: [OctagonStateReadyUpdated, OctagonStateReady])
+        self.assertConsidersSelfTrusted(context: peer3)
+    }
 }
 
 #endif // OCTAGON
index 64bca2d79edfe29885692672f940a78b0bf17679..0202448f2847cbc268c6b77394ad7917111d5eea 100644 (file)
@@ -6,6 +6,7 @@
 #import <CloudKit/CloudKit_Private.h>
 
 #import <AuthKit/AuthKit.h>
+#import <AuthKit/AKError.h>
 
 #import <KeychainCircle/KeychainCircle.h>
 #import "KeychainCircle/KCJoiningSession.h"
@@ -37,6 +38,7 @@
 
 #import "keychain/ot/OT.h"
 #import "keychain/ot/OTClique.h"
+#import "keychain/ot/OTClique+Private.h"
 #import "keychain/ot/OTControl.h"
 #import "keychain/ot/OTControlProtocol.h"
 #import "keychain/ot/OTManager.h"
@@ -82,6 +84,7 @@
 #import "keychain/SecureObjectSync/SOSControlServer.h"
 #import "KeychainCircle/Tests/FakeSOSControl.h"
 #import "keychain/escrowrequest/Framework/SecEscrowRequest.h"
+#import "OSX/sec/ipc/server_security_helpers.h"
 
 //CDP
 #import <CoreCDP/CDPFollowUpController.h>
 
 #include <dispatch/dispatch.h>
 #import "keychain/ot/OctagonCKKSPeerAdapter.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecord.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecordMetadata.h"
+#import "keychain/ot/proto/generated_source/OTEscrowRecordMetadataClientMetadata.h"
index 5e17bae512d9c7b13dca050c78ec377017a671ba..b8294ab774de71ebfa3a4e3b85563c8b980fba98 100644 (file)
@@ -42,7 +42,7 @@ class OTMockDeviceInfoAdapter: OTDeviceInformationAdapter {
         return self.mockOsVersion
     }
 
-    func serialNumber() -> String {
+    func serialNumber() -> String? {
         return self.mockSerialNumber
     }
 
@@ -189,8 +189,8 @@ class OTMockLogger: NSObject, SFAnalyticsProtocol {
 }
 
 let OTMockEscrowRequestNotification = Notification.Name("silent-escrow-request-triggered")
-class OTMockSecEscrowRequest: NSObject, SecEscrowRequestable {
 
+class OTMockSecEscrowRequest: NSObject, SecEscrowRequestable {
     static var populateStatuses = false
     var statuses: [String: String] = [:]
 
@@ -220,7 +220,6 @@ class OTMockSecEscrowRequest: NSObject, SecEscrowRequestable {
 }
 
 class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
-
     var tmpPath: String!
     var tmpURL: URL!
 
@@ -232,6 +231,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     var intendedCKKSZones: Set<CKRecordZone.ID>!
     var manateeZoneID: CKRecordZone.ID!
     var limitedPeersAllowedZoneID: CKRecordZone.ID!
+    var passwordsZoneID: CKRecordZone.ID!
 
     var fakeCuttlefishServer: FakeCuttlefishServer!
     var fakeCuttlefishCreator: FakeCuttlefishInvocableCreator!
@@ -286,6 +286,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
         self.manateeZoneID = CKRecordZone.ID(zoneName: "Manatee")
         self.limitedPeersAllowedZoneID = CKRecordZone.ID(zoneName: "LimitedPeersAllowed")
+        self.passwordsZoneID = CKRecordZone.ID(zoneName: "Passwords")
 
         // We'll use this set to limit the views that CKKS brings up in the tests (mostly for performance reasons)
         if self.intendedCKKSZones == nil {
@@ -333,21 +334,12 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
         self.injectedManager!.setSyncingViewsAllowList(Set(self.intendedCKKSZones!.map { $0.zoneName }))
 
-        // Ensure we've made the CKKSKeychainView objects we're interested in
-        self.ckksZones.forEach { obj in
-            let zoneID = obj as! CKRecordZone.ID
-            self.ckksViews.add(self.injectedManager!.findOrCreateView(zoneID.zoneName))
-        }
+        // Octagon is responsible for creating CKKS views; so we don't create any in the test setup
 
         // Double-check that the world of zones and views looks like what we expect
         XCTAssertEqual(self.ckksZones as? Set<CKRecordZone.ID>, self.intendedCKKSZones, "should still operate on our expected zones only")
-        XCTAssertEqual(self.ckksZones.count, self.ckksViews.count, "Should have the same number of views as expected zones")
         XCTAssertEqual(self.ckksZones.count, self.zones!.count, "Should have the same number of fake zones as expected zones")
 
-        XCTAssertEqual(Set(self.ckksViews.map { ($0 as! CKKSKeychainView).zoneName }),
-                       Set(self.ckksZones.map { ($0 as! CKRecordZone.ID).zoneName }),
-                       "ckksViews should match ckksZones")
-
         // Octagon must initialize the views
         self.automaticallyBeginCKKSViewCloudKitOperation = false
 
@@ -412,6 +404,11 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
         XCTAssertTrue(self.manager.allContextsPause(10 * NSEC_PER_SEC), "All cuttlefish contexts should pause")
 
+        do {
+            try self.tphClient.containerMap.deleteAllPersistentStores()
+        } catch {
+            XCTFail("Failed to clean up CoreData databases: \(error)")
+        }
         self.tphClient.containerMap.removeAllContainers()
 
         super.tearDown()
@@ -448,7 +445,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     override func managedViewList() -> Set<String> {
-        if(self.overrideUseCKKSViewsFromPolicy) {
+        if self.overrideUseCKKSViewsFromPolicy {
             let viewNames = self.ckksZones.map { ($0 as! CKRecordZone.ID).zoneName }
             return Set(viewNames)
         } else {
@@ -463,9 +460,13 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     func fetchEgoPeerID() -> String {
+        return self.fetchEgoPeerID(context: self.cuttlefishContext)
+    }
+
+    func fetchEgoPeerID(context: OTCuttlefishContext) -> String {
         var ret: String!
         let fetchPeerIDExpectation = self.expectation(description: "fetchPeerID callback occurs")
-        self.cuttlefishContext.rpcFetchEgoPeerID { peerID, fetchError in
+        context.rpcFetchEgoPeerID { peerID, fetchError in
             XCTAssertNil(fetchError, "should not error fetching ego peer ID")
             XCTAssertNotNil(peerID, "Should have a peer ID")
             ret = peerID
@@ -481,8 +482,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         self.tphClient.setAllowedMachineIDsWithContainer(container,
                                                          context: context,
                                                          allowedMachineIDs: self.mockAuthKit.currentDeviceList(), honorIDMSListChanges: honorIDMSListChanges) { _, error in
-            XCTAssertNil(error, "Should be no error setting allow list")
-            allowListExpectation.fulfill()
+                                                            XCTAssertNil(error, "Should be no error setting allow list")
+                                                            allowListExpectation.fulfill()
         }
         self.wait(for: [allowListExpectation], timeout: 10)
     }
@@ -520,7 +521,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         let statusexpectation = self.expectation(description: "trust status returns")
         let configuration = OTOperationConfiguration()
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
-        context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, isLocked, _  in
+        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)")
@@ -537,7 +538,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         configuration.useCachedAccountStatus = true
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
 
-        context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ 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()
@@ -556,7 +557,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
         configuration.useCachedAccountStatus = false
         let statusexpectation = self.expectation(description: "(cached) trust status returns")
-        context.rpcTrustStatus(configuration) { egoStatus, egoPeerID, _, _, _ 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()
@@ -569,7 +570,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         let statusexpectation = self.expectation(description: "trust status returns")
         let configuration = OTOperationConfiguration()
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
-        context.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in
+        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()
@@ -582,7 +583,7 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         let statusexpectation = self.expectation(description: "trust status returns")
         let configuration = OTOperationConfiguration()
         configuration.timeoutWaitForCKAccount = 500 * NSEC_PER_MSEC
-        context.rpcTrustStatus(configuration) { egoStatus, _, _, _, _ in
+        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()
@@ -626,36 +627,29 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     func restartCKKSViews() {
-        let viewNames = self.ckksViews.map { ($0 as! CKKSKeychainView).zoneName }
-        self.ckksViews.removeAllObjects()
+        let viewNames = self.intendedCKKSZones.map { $0.zoneName }
 
         self.injectedManager!.resetSyncingPolicy()
 
         for view in viewNames {
-            self.ckksViews.add(self.injectedManager!.restartZone(view))
+            self.injectedManager!.restartZone(view)
         }
     }
 
     func sendAllCKKSTrustedPeersChanged() {
-        self.ckksViews.forEach { view in
+        self.injectedManager!.views.forEach { _, view in
             (view as! CKKSKeychainView).trustedPeerSetChanged(nil)
         }
     }
 
-    func sendAllCKKSViewsZoneChanged() {
-        for expectedView in self.ckksZones {
-            let view = self.injectedManager?.findView((expectedView as! CKRecordZone.ID).zoneName)
-            XCTAssertNotNil(view, "Should have a view '\(expectedView)'")
-            view!.notifyZoneChange(nil)
-        }
-    }
-
     func assert(ckks: CKKSKeychainView, enters: String, within: UInt64) {
-        XCTAssertEqual(0, (ckks.keyHierarchyConditions[enters] as! CKKSCondition).wait(within), "CKKS state machine should enter '\(enters)' (currently '\(ckks.keyHierarchyState)')")
+        XCTAssertEqual(0, (ckks.stateMachine.stateConditions[enters] as! CKKSCondition).wait(within), "CKKS state machine should enter '\(enters)' (currently '\(ckks.stateMachine.currentState)')")
     }
 
-    func assertAllCKKSViews(enter: String, within: UInt64) {
-        for expectedView in self.ckksZones {
+    func assertAllCKKSViews(enter: String, within: UInt64, filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { expectedView in
             let view = self.injectedManager?.findView((expectedView as! CKRecordZone.ID).zoneName)
             XCTAssertNotNil(view, "Should have a view '\(expectedView)'")
             self.assert(ckks: view!, enters: enter, within: within)
@@ -670,32 +664,42 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         }
     }
 
-    func assertAllCKKSViewsUpload(tlkShares: UInt) {
-        for expectedView in self.ckksZones {
+    func assertAllCKKSViewsUpload(tlkShares: UInt, filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { expectedView in
             self.expectCKModifyKeyRecords(0, currentKeyPointerRecords: 0, tlkShareRecords: tlkShares, zoneID: expectedView as! CKRecordZone.ID)
         }
     }
 
-    func putFakeKeyHierarchiesInCloudKit() {
-        self.ckksZones.forEach { zone in
+    func putFakeKeyHierarchiesInCloudKit(filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { zone in
             self.putFakeKeyHierarchy(inCloudKit: zone as! CKRecordZone.ID)
         }
     }
 
-    func putSelfTLKSharesInCloudKit() {
-        self.ckksZones.forEach { zone in
+    func putSelfTLKSharesInCloudKit(filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { zone in
             self.putSelfTLKShares(inCloudKit: zone as! CKRecordZone.ID)
         }
     }
 
-    func putFakeDeviceStatusesInCloudKit() {
-        self.ckksZones.forEach { zone in
+    func putFakeDeviceStatusesInCloudKit(filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { zone in
             self.putFakeDeviceStatus(inCloudKit: zone as! CKRecordZone.ID)
         }
     }
 
-    func saveTLKMaterialToKeychain() {
-        self.ckksZones.forEach { zone in
+    func saveTLKMaterialToKeychain(filter: ((CKRecordZone.ID) -> Bool)? = nil) {
+        let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { zone in
             self.saveTLKMaterial(toKeychain: zone as! CKRecordZone.ID)
         }
     }
@@ -710,8 +714,10 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         self.wait(for: [resetExpectation], timeout: 30)
     }
 
-    func putSelfTLKSharesInCloudKit(context: OTCuttlefishContext) throws {
-        try self.ckksZones.forEach { zone in
+    func putSelfTLKSharesInCloudKit(context: OTCuttlefishContext, filter: ((CKRecordZone.ID) -> Bool)? = nil) throws {
+    let f: ((CKRecordZone.ID) -> Bool) = filter ?? { (zone: CKRecordZone.ID) in return true }
+
+        try self.ckksZones.filter { f($0 as! CKRecordZone.ID) }.forEach { zone in
             try self.putTLKShareInCloudKit(to: context, from: context, zoneID: zone as! CKRecordZone.ID)
         }
     }
@@ -734,16 +740,41 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     func putRecoveryKeyTLKSharesInCloudKit(recoveryKey: String, salt: String) throws {
-        try self.ckksZones.forEach { zone in
-            try self.putRecoveryKeyTLKShareInCloudKit(recoveryKey: recoveryKey, salt: salt, zoneID: zone as! CKRecordZone.ID)
+        let recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
+
+        self.ckksZones.forEach { zone in
+            let zoneID = zone as! CKRecordZone.ID
+            let zoneKeys = self.keys![zoneID] as! ZoneKeys
+            self.putTLKShare(inCloudKit: zoneKeys.tlk!, from: recoveryKeys.peerKeys, to: recoveryKeys.peerKeys, zoneID: zoneID)
         }
     }
 
-    func putRecoveryKeyTLKShareInCloudKit(recoveryKey: String, salt: String, zoneID: CKRecordZone.ID) throws {
+    func putRecoveryKeyTLKSharesInCloudKit(recoveryKey: String, salt: String, sender: OTCuttlefishContext) throws {
         let recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
 
-        let zoneKeys = self.keys![zoneID] as! ZoneKeys
-        self.putTLKShare(inCloudKit: zoneKeys.tlk!, from: recoveryKeys.peerKeys, to: recoveryKeys.peerKeys, zoneID: zoneID)
+        let senderAccountMetadata = try sender.accountMetadataStore.loadOrCreateAccountMetadata()
+        let senderPeerKeys: OctagonSelfPeerKeys = try loadEgoKeysSync(peerID: senderAccountMetadata.peerID)
+
+        self.ckksZones.forEach { zone in
+            let zoneID = zone as! CKRecordZone.ID
+            let zoneKeys = self.keys![zoneID] as! ZoneKeys
+            self.putTLKShare(inCloudKit: zoneKeys.tlk!, from: senderPeerKeys, to: recoveryKeys.peerKeys, zoneID: zoneID)
+        }
+    }
+
+    func recoveryKeyTLKSharesInCloudKit(recoveryKey: String, salt: String) throws -> Bool {
+        let recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
+
+        return self.tlkSharesInCloudKit(receiverPeerID: recoveryKeys.peerKeys.peerID,
+                                        senderPeerID: recoveryKeys.peerKeys.peerID)
+    }
+
+    func recoveryKeyTLKSharesInCloudKit(recoveryKey: String, salt: String, sender: OTCuttlefishContext) throws -> Bool {
+        let recoveryKeys = try RecoveryKey(recoveryKeyString: recoveryKey, recoverySalt: salt)
+        let senderAccountMetadata = try sender.accountMetadataStore.loadOrCreateAccountMetadata()
+
+        return self.tlkSharesInCloudKit(receiverPeerID: recoveryKeys.peerKeys.peerID,
+                                        senderPeerID: senderAccountMetadata.peerID)
     }
 
     func assertSelfTLKSharesInCloudKit(context: OTCuttlefishContext) {
@@ -764,12 +795,20 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     func assertTLKSharesInCloudKit(receiverPeerID: String, senderPeerID: String) {
-        for case let view as CKKSKeychainView in self.ckksViews {
-            XCTAssertNoThrow(try self.assertTLKShareInCloudKit(receiverPeerID: receiverPeerID, senderPeerID: senderPeerID, zoneID: view.zoneID), "view \(view) should have a self TLK uploaded")
+        XCTAssertTrue(self.tlkSharesInCloudKit(receiverPeerID: receiverPeerID, senderPeerID: senderPeerID), "All views should have a self TLK uploaded")
+    }
+
+    func tlkSharesInCloudKit(receiverPeerID: String, senderPeerID: String) -> Bool {
+        let tlkContains: [Bool] = self.ckksViews.map {
+            let view: CKKSKeychainView = $0 as! CKKSKeychainView
+            return self.tlkShareInCloudKit(receiverPeerID: receiverPeerID, senderPeerID: senderPeerID, zoneID: view.zoneID)
         }
+
+        // return true if all entries in tlkContains is true
+        return tlkContains.allSatisfy { $0 == true }
     }
 
-    func tlkShareInCloudKit(receiverPeerID: String, senderPeerID: String, zoneID: CKRecordZone.ID) throws -> Bool {
+    func tlkShareInCloudKit(receiverPeerID: String, senderPeerID: String, zoneID: CKRecordZone.ID) -> Bool {
         guard let zone = self.zones![zoneID] as? FakeCKZone else {
             return false
         }
@@ -785,8 +824,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         return false
     }
 
-    func assertTLKShareInCloudKit(receiverPeerID: String, senderPeerID: String, zoneID: CKRecordZone.ID) throws {
-        XCTAssertTrue(try self.tlkShareInCloudKit(receiverPeerID: receiverPeerID, senderPeerID: senderPeerID, zoneID: zoneID),
+    func assertTLKShareInCloudKit(receiverPeerID: String, senderPeerID: String, zoneID: CKRecordZone.ID) {
+        XCTAssertTrue(self.tlkShareInCloudKit(receiverPeerID: receiverPeerID, senderPeerID: senderPeerID, zoneID: zoneID),
                       "Should have found a TLKShare for peerID \(String(describing: receiverPeerID)) sent by \(String(describing: senderPeerID)) for \(zoneID)")
     }
 
@@ -895,9 +934,11 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
     // 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)
+
+        // If we wait for each condition in order here, we might lose thread races and cause issues.
+        // Fetch every state we'll examine (note that this doesn't handle repeated checks for the same state)
+
+        let stateConditions = states.map { ($0, context.stateMachine.stateConditions[$0] as! CKKSCondition) }
 
         let updateTrustExpectation = self.expectation(description: "fetchChanges")
 
@@ -909,10 +950,11 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
         context.notifyContainerChange(nil)
         self.wait(for: [updateTrustExpectation], timeout: 10)
 
-        // 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)
+        for (state, stateCondition) in stateConditions {
+            XCTAssertEqual(0, stateCondition.wait(10 * NSEC_PER_SEC), "State machine should enter '\(String(describing: state))'")
+            if state == OctagonStateReady || state == OctagonStateUntrusted {
+                XCTAssertEqual(0, context.stateMachine.paused.wait(10 * NSEC_PER_SEC), "State machine should pause soon")
+            }
         }
     }
 
@@ -1049,7 +1091,6 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
     }
 
     func assertSelfOSVersion(_ osVersion: String) {
-
         let statusExpectation = self.expectation(description: "status callback occurs")
         self.tphClient.dumpEgoPeer(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID) { _, _, stableInfo, _, error in
             XCTAssertNil(error, "should be no error dumping ego peer")
@@ -1063,6 +1104,8 @@ class OctagonTestsBase: CloudKitKeychainSyncingMockXCTest {
 
 class OctagonTests: OctagonTestsBase {
     func testTPHPrepare() {
+        self.startCKAccountStatusMock()
+
         let contextName = "asdf"
         let containerName = "test_container"
 
@@ -1079,22 +1122,34 @@ class OctagonTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           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")
+                          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")
 
-                            tphPrepareExpectation.fulfill()
+            let adapter = OctagonCKKSPeerAdapter(peerID: peerID!, containerName: containerName, contextID: contextName, cuttlefishXPC: CuttlefishXPCWrapper(cuttlefishXPCConnection: self.tphXPCProxy.connection()))
+
+            do {
+                let selves = try adapter.fetchSelfPeers()
+                try TestsObjectiveC.testSecKey(selves)
+            } catch {
+                XCTFail("Test failed: \(error)")
+            }
+
+            tphPrepareExpectation.fulfill()
         }
 
         self.wait(for: [tphPrepareExpectation], timeout: 10)
     }
 
     func testTPHMultiPrepare() throws {
+        self.startCKAccountStatusMock()
+
         let contextName = OTDefaultContext
         let containerName = OTCKContainerName
 
@@ -1113,8 +1168,9 @@ class OctagonTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -1141,8 +1197,9 @@ class OctagonTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -1200,8 +1257,9 @@ class OctagonTests: OctagonTestsBase {
                           osVersion: "asdf",
                           policyVersion: nil,
                           policySecrets: nil,
+                          syncUserControllableViews: .UNKNOWN,
                           signingPrivKeyPersistentRef: nil,
-                          encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                          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")
@@ -1543,29 +1601,23 @@ class OctagonTests: OctagonTestsBase {
         // these should be failures
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLKUpload, within: 10 * NSEC_PER_SEC)
         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 {
+    func testNewFriendsForEmptyAccountWithExistingTLKs() throws {
         self.putFakeKeyHierarchiesInCloudKit()
         self.saveTLKMaterialToKeychain()
 
         self.startCKAccountStatusMock()
 
-        // CKKS should go into 'logged out', as Octagon hasn't told it to go yet
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateLoggedOut, within: 10 * NSEC_PER_SEC)
-
         self.cuttlefishContext.startOctagonStateMachine()
         XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
 
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
-
-        // CKKS should reset the zones after Octagon has entered
-        self.silentZoneDeletesAllowed = true
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
 
         do {
             let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
@@ -1578,13 +1630,11 @@ class OctagonTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
-        // and all subCKKSes should enter ready upload...
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
     }
 
     func testLoadToReadyOnRestart() throws {
-
         let startDate = Date()
 
         self.startCKAccountStatusMock()
@@ -1849,6 +1899,9 @@ class OctagonTests: OctagonTestsBase {
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
         self.verifyDatabaseMocks()
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatusIsSet, "SOS adapter should have been told that CKKS4All is not enabled")
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is enabled")
+        self.mockSOSAdapter.ckks4AllStatusIsSet = false
 
         // 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")
@@ -1858,6 +1911,9 @@ class OctagonTests: OctagonTestsBase {
         self.assertConsidersSelfUntrusted(context: self.cuttlefishContext)
         assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
 
+        XCTAssertTrue(self.mockSOSAdapter.ckks4AllStatusIsSet, "SOS adapter should have been told that CKKS4All is not enabled")
+        XCTAssertFalse(self.mockSOSAdapter.ckks4AllStatus, "SOS adapter should have been told that CKKS4All is not enabled")
+
         // TODO: an item added here shouldn't sync
     }
 
@@ -1881,7 +1937,7 @@ class OctagonTests: OctagonTestsBase {
         self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
         self.verifyDatabaseMocks()
-        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
         let peer1ID = fetchEgoPeerID()
 
@@ -1926,8 +1982,9 @@ class OctagonTests: OctagonTestsBase {
                                osVersion: peer2DeviceAdapter.osVersion(),
                                policyVersion: nil,
                                policySecrets: nil,
+                               syncUserControllableViews: .UNKNOWN,
                                signingPrivKeyPersistentRef: nil,
-                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                               encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error in
                                 XCTAssertNil(error, "Should be no error preparing identity")
                                 XCTAssertNotNil(permanentInfo, "Should have a permanent identity")
                                 XCTAssertNotNil(permanentInfoSig, "Should have a permanent identity signature")
@@ -1950,7 +2007,7 @@ class OctagonTests: OctagonTestsBase {
                                                                             voucherSig: voucherSig!,
                                                                             ckksKeys: [],
                                                                             tlkShares: [],
-                                                                            preapprovedKeys: []) { peerID, _, _, _, error in
+                                                                            preapprovedKeys: []) { peerID, _, _, error in
                                                                                 XCTAssertNil(error, "Should be no error joining")
                                                                                 XCTAssertNotNil(peerID, "Should have a peerID")
                                                                                 peer2ID = peerID
@@ -1973,6 +2030,7 @@ class OctagonTests: OctagonTestsBase {
         self.assertConsidersSelfTrusted(context: peer2)
 
         // Now that we've lied enough...
+        self.assertAllCKKSViewsUpload(tlkShares: 1, filter: { $0.zoneName == "LimitedPeersAllowed" })
         self.sendContainerChangeWaitForFetch(context: self.cuttlefishContext)
 
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer1ID, opinion: .trusts, target: peer2ID)),
@@ -1980,6 +2038,10 @@ class OctagonTests: OctagonTestsBase {
         XCTAssertTrue(self.fakeCuttlefishServer.assertCuttlefishState(FakeCuttlefishAssertion(peer: peer2ID, opinion: .trusts, target: peer1ID)),
                       "peer 2 should trust peer 1")
 
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+        self.verifyDatabaseMocks()
+
         // But does peer1 claim to know peer2?
         do {
             let peersByID = try clique.peerDeviceNamesByPeerID()
@@ -2028,7 +2090,6 @@ class OctagonTests: OctagonTestsBase {
 
             let status = clique.fetchStatus(nil)
             XCTAssertEqual(status, CliqueStatus.in, "clique should return In")
-
         } catch {
             XCTFail("Shouldn't have errored making new friends: \(error)")
             throw error
@@ -2058,7 +2119,6 @@ class OctagonTests: OctagonTestsBase {
             OctagonSetPlatformSupportsSOS(true)
             let status = newClique.fetchStatus(nil)
             XCTAssertEqual(status, CliqueStatus.in, "clique should return In")
-
         } catch {
             XCTFail("Shouldn't have errored making new friends: \(error)")
             throw error
@@ -2151,10 +2211,10 @@ class OctagonTests: OctagonTestsBase {
         let path = OctagonStateTransitionPath(from: [
             OctagonStateResetAndEstablish: [
                 OctagonStateBottleJoinVouchWithBottle: [
-                        OctagonStateResetAndEstablish: OctagonStateTransitionPathStep.success(),
-                    ],
+                    OctagonStateResetAndEstablish: OctagonStateTransitionPathStep.success(),
                 ],
-            ])
+            ],
+        ])
         let watcher = OctagonStateTransitionWatcher(named: "should-fail",
                                                     serialQueue: self.cuttlefishContext.queue,
                                                     path: path!,
@@ -2210,7 +2270,7 @@ class OctagonTests: OctagonTestsBase {
 
         let cfuExpectation = self.expectation(description: "cfu callback occurs")
         self.cuttlefishContext.followupHandler.clearAllPostedFlags()
-        self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary { _, posted, _, error in
+        self.cuttlefishContext.checkTrustStatusAndPostRepairCFUIfNecessary { _, posted, _, _, error in
             #if !os(tvOS)
             XCTAssertTrue(posted, "posted should be true")
             #else
@@ -2228,9 +2288,6 @@ class OctagonTests: OctagonTestsBase {
 
         self.startCKAccountStatusMock()
 
-        self.aksLockState = true
-        self.lockStateTracker.recheck()
-
         let initiatorContext = self.manager.context(forContainerName: OTCKContainerName,
                                                     contextID: OTDefaultContext,
                                                     sosAdapter: self.mockSOSAdapter,
@@ -2239,14 +2296,19 @@ class OctagonTests: OctagonTestsBase {
                                                     accountStateTracker: self.accountStateTracker,
                                                     deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)"))
 
-        let accountMetadataStoreActual = initiatorContext.accountMetadataStore //grab the previously instantiated account state holder
+        // Pre-create some Account metadata, so that Octagon will experience a keychain locked error when loading
+        try initiatorContext.accountMetadataStore.persistAccountChanges { metadata in
+            return metadata
+        }
 
-        initiatorContext.setAccountStateHolder(self.accountMetaDataStore) // set the mocked account state holder
+        // Lock all AKS classes
+        self.aksLockState = true
+        SecMockAKS.lockClassA_C()
+        self.lockStateTracker.recheck()
 
         initiatorContext.startOctagonStateMachine()
-        self.assertEnters(context: initiatorContext, state: OctagonStateWaitForUnlock, within: 10 * NSEC_PER_SEC)
+        self.assertEnters(context: initiatorContext, state: OctagonStateWaitForClassCUnlock, within: 10 * NSEC_PER_SEC)
 
-        initiatorContext.setAccountStateHolder(accountMetadataStoreActual) //re-set the actual store
         self.aksLockState = false
         self.lockStateTracker.recheck()
 
@@ -2304,21 +2366,23 @@ class OctagonTests: OctagonTestsBase {
         self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
 
         #if !os(tvOS)
-        let expectedViews = Set(["ProtectedCloudStorage",
-                                 "AutoUnlock",
-                                 "LimitedPeersAllowed",
-                                 "SecureObjectSync",
-                                 "DevicePairing",
-                                 "Engram",
-                                 "Home",
-                                 "Applications",
-                                 "WiFi",
-                                 "Health",
-                                 "Manatee",
-                                 // <rdar://problem/57810109> Cuttlefish: remove Safari prefix from view names
-                                 "SafariCreditCards",
-                                 "SafariPasswords",
-                                 "ApplePay", ])
+        let expectedViews = Set([
+            "ApplePay",
+            "Applications",
+            "AutoUnlock",
+            "Backstop",
+            "CreditCards",
+            "DevicePairing",
+            "Engram",
+            "Health",
+            "Home",
+            "LimitedPeersAllowed",
+            "Manatee",
+            "Passwords",
+            "ProtectedCloudStorage",
+            "SecureObjectSync",
+            "WiFi",
+        ])
         #else
         let expectedViews = Set(["LimitedPeersAllowed",
                                  "Home",
@@ -2326,9 +2390,9 @@ class OctagonTests: OctagonTestsBase {
         #endif
 
         let getViewsExpectation = self.expectation(description: "getViews callback happens")
-        self.tphClient.fetchCurrentPolicy(withContainer: OTCKContainerName, context: OTDefaultContext) { outViews, _, error in
+        self.tphClient.fetchCurrentPolicy(withContainer: OTCKContainerName, context: OTDefaultContext, modelIDOverride: nil) { outPolicy, _, error in
             XCTAssertNil(error, "should not have failed")
-            XCTAssertEqual(expectedViews, Set(outViews!))
+            XCTAssertEqual(expectedViews, outPolicy!.viewList)
             getViewsExpectation.fulfill()
         }
         self.wait(for: [getViewsExpectation], timeout: 10)
@@ -2337,7 +2401,6 @@ class OctagonTests: OctagonTestsBase {
     let octagonNotificationName = "com.apple.security.octagon.trust-status-change"
 
     func testNotifications() throws {
-
         let contextName = OTDefaultContext
         let containerName = OTCKContainerName
 
@@ -2505,7 +2568,6 @@ class OctagonTests: OctagonTestsBase {
     }
 
     func testAPSRateLimiter() throws {
-
         let untrustedNotification = XCTDarwinNotificationExpectation(notificationName: octagonNotificationName)
 
         self.startCKAccountStatusMock()
@@ -2631,7 +2693,7 @@ class OctagonTests: OctagonTestsBase {
 
         //this call uses the default value and should timeout in 10 seconds
         let upgradeCallback = self.expectation(description: "attempting sos upgrade callback")
-        self.manager.attemptSosUpgrade(OTCKContainerName, context: OTDefaultContext) { error in
+        self.manager.wait(forOctagonUpgrade: OTCKContainerName, context: OTDefaultContext) { error in
             XCTAssertNotNil(error, "error should not be nil")
             upgradeCallback.fulfill()
         }
@@ -2639,7 +2701,6 @@ class OctagonTests: OctagonTestsBase {
     }
 
     func testTTRTrusted() {
-
         self.startCKAccountStatusMock()
 
         self.cuttlefishContext.startOctagonStateMachine()
@@ -2681,13 +2742,13 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
         let limitedTLKs: Bool
     }
 
-    func assertTLKs(expectation: TestCase, receiverPeerID: String, senderPeerID: String) throws {
-        let haveManateeTLK = try self.tlkShareInCloudKit(receiverPeerID: receiverPeerID,
-                                                         senderPeerID: senderPeerID,
-                                                         zoneID: self.manateeZoneID)
-        let haveLimitedPeersAllowedTLK = try self.tlkShareInCloudKit(receiverPeerID: receiverPeerID,
-                                                                     senderPeerID: senderPeerID,
-                                                                     zoneID: self.limitedPeersAllowedZoneID)
+    func assertTLKs(expectation: TestCase, receiverPeerID: String, senderPeerID: String) {
+        let haveManateeTLK = self.tlkShareInCloudKit(receiverPeerID: receiverPeerID,
+                                                     senderPeerID: senderPeerID,
+                                                     zoneID: self.manateeZoneID)
+        let haveLimitedPeersAllowedTLK = self.tlkShareInCloudKit(receiverPeerID: receiverPeerID,
+                                                                 senderPeerID: senderPeerID,
+                                                                 zoneID: self.limitedPeersAllowedZoneID)
 
         XCTAssertEqual(haveManateeTLK, expectation.manateeTLKs, "manatee should be what's expected: \(expectation)")
         XCTAssertEqual(haveLimitedPeersAllowedTLK, expectation.limitedTLKs, "limited should be what's expected: \(expectation)")
@@ -2714,9 +2775,8 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
 
         self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
 
-        let ckksKeys: [CKKSKeychainBackedKeySet] = self.ckksViews.compactMap { view in
-            let viewName = (view as! CKKSKeychainView).zoneName
-            let currentKeySet = CKKSCurrentKeySet.load(forZone: CKRecordZone.ID(zoneName: viewName))
+        let ckksKeys: [CKKSKeychainBackedKeySet] = self.intendedCKKSZones.compactMap { zoneID in
+            let currentKeySet = CKKSCurrentKeySet.load(forZone: zoneID)
             return try! currentKeySet.asKeychainBackedSet()
         }
 
@@ -2751,8 +2811,9 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                    osVersion: "something",
                                    policyVersion: nil,
                                    policySecrets: nil,
+                                   syncUserControllableViews: .UNKNOWN,
                                    signingPrivKeyPersistentRef: nil,
-                                   encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                                   encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error in
                                     XCTAssertNil(error, "Should be no error preparing identity")
                                     XCTAssertNotNil(permanentInfo, "Should have a permanent identity")
                                     XCTAssertNotNil(permanentInfoSig, "Should have a permanent identity signature")
@@ -2771,9 +2832,9 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                                                 XCTAssertNotNil(voucher, "Should have a voucher")
                                                                 XCTAssertNotNil(voucherSig, "Should have a voucher signature")
 
-                                                                try! self.assertTLKs(expectation: testCase,
-                                                                                     receiverPeerID: peerID!,
-                                                                                     senderPeerID: senderPeerID)
+                                                                self.assertTLKs(expectation: testCase,
+                                                                                receiverPeerID: peerID!,
+                                                                                senderPeerID: senderPeerID)
 
                                                                 self.tphClient.join(withContainer: OTCKContainerName,
                                                                                     context: peer2ContextID,
@@ -2781,7 +2842,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                                                                     voucherSig: voucherSig!,
                                                                                     ckksKeys: [],
                                                                                     tlkShares: [],
-                                                                                    preapprovedKeys: []) { peerID, _, _, _, error in
+                                                                                    preapprovedKeys: []) { peerID, _, _, error in
                                                                                         XCTAssertNil(error, "Should be no error joining")
                                                                                         XCTAssertNotNil(peerID, "Should have a peerID")
                                                                                         joinExpectation.fulfill()
@@ -2800,14 +2861,13 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                                                 XCTAssertNil(voucherSig, "voucherSig should be nil")
                                                                 XCTAssertNotNil(error, "error should be non nil")
 
-                                                                try! self.assertTLKs(expectation: testCase,
-                                                                                     receiverPeerID: peerID!,
-                                                                                     senderPeerID: senderPeerID)
+                                                                self.assertTLKs(expectation: testCase,
+                                                                                receiverPeerID: peerID!,
+                                                                                senderPeerID: senderPeerID)
 
                                                                 joinExpectation.fulfill()
                                         }
                                     }
-
             }
             self.wait(for: [joinExpectation], timeout: 10)
         }
@@ -2859,8 +2919,9 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                    osVersion: "something",
                                    policyVersion: nil,
                                    policySecrets: nil,
+                                   syncUserControllableViews: .UNKNOWN,
                                    signingPrivKeyPersistentRef: nil,
-                                   encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, _, error in
+                                   encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, _, error in
                                     XCTAssertNil(error, "Should be no error preparing identity")
                                     XCTAssertNotNil(permanentInfo, "Should have a permanent identity")
                                     XCTAssertNotNil(permanentInfoSig, "Should have a permanent identity signature")
@@ -2883,7 +2944,7 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                                         voucherSig: voucher!.sig,
                                                         ckksKeys: [],
                                                         tlkShares: [],
-                                                        preapprovedKeys: []) { peerID, _, _, _, error in
+                                                        preapprovedKeys: []) { peerID, _, _, error in
                                                             if expectedSuccess {
                                                                 XCTAssertNil(error, "expected success")
                                                                 XCTAssertNotNil(peerID, "peerID should be set")
@@ -2893,7 +2954,6 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                                                             }
                                                             joinExpectation.fulfill()
                                     }
-
             }
             self.wait(for: [joinExpectation], timeout: 10)
 
@@ -2928,9 +2988,9 @@ class OctagonTestsOverrideModelBase: OctagonTestsBase {
                 self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
             }
 
-            try self.assertTLKs(expectation: testCase,
-                                receiverPeerID: peer2ID,
-                                senderPeerID: peer1ID)
+            self.assertTLKs(expectation: testCase,
+                            receiverPeerID: peer2ID,
+                            senderPeerID: peer1ID)
         }
     }
 }
index a972b584e5a5f58310d58e584d89eec13afb48ea..bfb7d304f4131365d53798a0e5e8e1a7be13f929 100644 (file)
@@ -17,14 +17,14 @@ class ProxyXPCConnection: NSObject, NSXPCListenerDelegate {
         self.listener.resume()
     }
 
-    public func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
+    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
         newConnection.exportedInterface = self.serverInterface
         newConnection.exportedObject = self.obj
         newConnection.resume()
         return true
     }
 
-    public func connection() -> NSXPCConnection {
+    func connection() -> NSXPCConnection {
         let connection = NSXPCConnection(listenerEndpoint: self.listener.endpoint)
         connection.remoteObjectInterface = self.serverInterface
         connection.resume()
index 2c76a5ecaf11e963735ab61ca54974ce61e96600..9c45c9691840a21231665977e41a14fc82f5124a 100644 (file)
@@ -77,7 +77,6 @@ let version0_txt: [UInt8] = [
 let version0_txt_len = 395
 
 extension OctagonPairingTests {
-
     func testPiggybacking() {
         self.startCKAccountStatusMock()
 
@@ -214,6 +213,7 @@ extension OctagonPairingTests {
         XCTAssertNotNil(requestSession, "requestSession should not be nil")
         XCTAssertNotNil(requestDelegate, "requestDelegate should not be nil")
         XCTAssertNotNil(acceptDelegate, "acceptDelegate should not be nil")
+        OctagonSetPlatformSupportsSOS(false)
 
         do {
             initialMessageContainingOctagonVersion = try requestSession!.initialMessage()
@@ -269,7 +269,6 @@ extension OctagonPairingTests {
         do {
             identityMessage = try requestCircleSession.initialMessage()
             XCTAssertNotNil(identityMessage, "No identity message")
-
         } catch {
             XCTAssertNil(error, "error retrieving identityMessage message")
         }
@@ -284,7 +283,6 @@ extension OctagonPairingTests {
             XCTAssertNotNil(voucherMessage, "No voucherMessage message")
         } catch {
             XCTAssertNil(error, "error retrieving voucherMessage message")
-
         }
 
         var nothing: Data?
@@ -293,7 +291,6 @@ extension OctagonPairingTests {
             XCTAssertNotNil(nothing, "No nothing message")
         } catch {
             XCTAssertNil(error, "error retrieving nothing message")
-
         }
 
         XCTAssertTrue(requestSession!.isDone(), "requestor should be done")
@@ -545,6 +542,43 @@ extension OctagonPairingTests {
         self.wait(for: [firstMessageWithNewJoiningConfigCallback], timeout: 10)
     }
 
+    func testPairingResetWithNoAccount() {
+        // no account
+        self.mockAuthKit.altDSID = nil
+        self.mockAuthKit.hsa2 = false
+
+        // no cloudkit account
+        self.accountStatus = .noAccount
+        self.startCKAccountStatusMock()
+
+        self.cuttlefishContext.startOctagonStateMachine()
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
+
+        let joining = OTJoiningConfiguration(protocolType: "OctagonPiggybacking",
+                                             uniqueDeviceID: "requester",
+                                             uniqueClientID: "client",
+                                             pairingUUID: "3B99AE99-5FEB-4AF5-9992-DF042118B5FE",
+                                             containerName: self.cuttlefishContext.containerName,
+                                             contextID: self.cuttlefishContext.contextID,
+                                             epoch: 1,
+                                             isInitiator: true)
+
+        self.cuttlefishContext.handlePairingRestart(joining)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
+
+        let joining2 = OTJoiningConfiguration(protocolType: "OctagonPiggybacking",
+                                              uniqueDeviceID: "requester",
+                                              uniqueClientID: "client",
+                                              pairingUUID: "3B99AE99-5FEB-4AF5-0000-DF042118B5FE",
+                                              containerName: self.cuttlefishContext.containerName,
+                                              contextID: self.cuttlefishContext.contextID,
+                                              epoch: 1,
+                                              isInitiator: true)
+
+        self.cuttlefishContext.handlePairingRestart(joining2)
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateNoAccount, within: 10 * NSEC_PER_SEC)
+    }
+
     func testVersion2ofPiggybackingWithSOS() throws {
         KCSetJoiningOctagonPiggybackingEnabled(true)
         OctagonSetPlatformSupportsSOS(true)
@@ -636,7 +670,177 @@ extension OctagonPairingTests {
             XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
             XCTAssertNotNil(parsedMessage.secondData, "No sos message")
             XCTAssertNotNil(identityMessage, "No identity message")
+        } catch {
+            XCTAssertNil(error, "error retrieving identityMessage message")
+        }
+
+        // Double-check that there's an Octagon message in the packet
+        let initiatorIdentityMessage = try self.unpackPiggybackingInitialMessage(identityMessage: identityMessage!, session: acceptSession!.accessSession())
+        XCTAssertTrue(initiatorIdentityMessage.hasPrepare, "Pairing message should contain prepared information")
+
+        var voucherMessage: Data?
+        do {
+            voucherMessage = try acceptSession!.processMessage(identityMessage!)
+            let parsedMessage = try KCJoiningMessage(der: identityMessage!)
+            XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
+            XCTAssertNotNil(parsedMessage.secondData, "No sos message")
+            XCTAssertNotNil(voucherMessage, "No voucherMessage message")
+        } catch {
+            XCTAssertNil(error, "error retrieving voucherMessage message")
+        }
 
+        var nothing: Data?
+        do {
+            nothing = try requestCircleSession.processMessage(voucherMessage!)
+            XCTAssertNotNil(nothing, "No nothing message")
+        } catch {
+            XCTAssertNil(error, "error retrieving nothing message")
+        }
+
+        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
+        XCTAssertTrue(requestSession!.isDone(), "requestor should be done")
+        XCTAssertTrue(acceptSession!.isDone(), "acceptor should be done")
+
+        clientStateMachine = self.manager.clientStateMachine(forContainerName: OTCKContainerName, contextID: self.contextForAcceptor, clientName: self.initiatorName)
+
+        clientStateMachine.notifyContainerChange()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertEnters(context: self.cuttlefishContextForAcceptor, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContextForAcceptor)
+        self.verifyDatabaseMocks()
+
+        self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContextForAcceptor, sender: self.cuttlefishContext)
+
+        let initiatorDumpCallback = self.expectation(description: "initiatorDumpCallback callback occurs")
+        self.tphClient.dump(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+
+            initiatorDumpCallback.fulfill()
+        }
+        self.wait(for: [initiatorDumpCallback], timeout: 10)
+
+        let acceptorDumpCallback = self.expectation(description: "acceptorDumpCallback callback occurs")
+        self.tphClient.dump(withContainer: self.cuttlefishContext.containerName, context: self.contextForAcceptor) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+            acceptorDumpCallback.fulfill()
+        }
+        self.wait(for: [acceptorDumpCallback], timeout: 10)
+        XCTAssertEqual(self.fakeCuttlefishServer.state.bottles.count, 2, "should be 2 bottles")
+    }
+
+    func testVersion2ofPiggybackingWithAcceptorOctagonOnly() throws {
+        KCSetJoiningOctagonPiggybackingEnabled(true)
+        OctagonSetPlatformSupportsSOS(true)
+        self.startCKAccountStatusMock()
+
+        self.getAcceptorInCircle()
+
+        let initiator1Context = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
+
+        var clientStateMachine = self.manager.clientStateMachine(forContainerName: OTCKContainerName, contextID: self.contextForAcceptor, clientName: self.initiatorName)
+        initiator1Context.startOctagonStateMachine()
+
+        self.assertEnters(context: initiator1Context, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        // Note that in this strange situation, the join should create the CKKS TLKs
+        let (requestDelegate, acceptDelegate, acceptSession, requestSession) = self.setupKCJoiningSessionObjects()
+        var initialMessageContainingOctagonVersion: Data?
+        var challengeContainingEpoch: Data?
+        var response: Data?
+        var verification: Data?
+        var doneMessage: Data?
+
+        XCTAssertNotNil(acceptSession, "acceptSession should not be nil")
+        XCTAssertNotNil(requestSession, "requestSession should not be nil")
+        XCTAssertNotNil(requestDelegate, "requestDelegate should not be nil")
+        XCTAssertNotNil(acceptDelegate, "acceptDelegate should not be nil")
+
+        do {
+            initialMessageContainingOctagonVersion = try requestSession!.initialMessage()
+        } catch {
+            XCTAssertNil(error, "error retrieving initialMessageContainingOctagonVersion message")
+        }
+
+        XCTAssertNotNil(initialMessageContainingOctagonVersion, "initial message should not be nil")
+
+        do {
+            OctagonSetPlatformSupportsSOS(false)
+            challengeContainingEpoch = try acceptSession!.processMessage(initialMessageContainingOctagonVersion!)
+            XCTAssertNotNil(challengeContainingEpoch, "challengeContainingEpoch should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving challengeContainingEpoch message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(true)
+            response = try requestSession!.processMessage(challengeContainingEpoch!)
+            XCTAssertNotNil(response, "response message should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(false)
+            verification = try acceptSession!.processMessage(response!)
+            XCTAssertNotNil(verification, "verification should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving verification message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(true)
+            doneMessage = try requestSession!.processMessage(verification!)
+            XCTAssertNotNil(doneMessage, "doneMessage should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        let signInCallback = self.expectation(description: "trigger sign in")
+        self.otControl.sign(in: "348576349857", container: OTCKContainerName, context: OTDefaultContext) { error in
+            XCTAssertNil(error, "error should be nil")
+            signInCallback.fulfill()
+        }
+        self.wait(for: [signInCallback], timeout: 10)
+
+        XCTAssertTrue(requestSession!.isDone(), "SecretSession done")
+        XCTAssertFalse(acceptSession!.isDone(), "Unexpected accept session done")
+
+        let aesSession = requestSession!.session
+
+        let requestCircleSession = KCJoiningRequestCircleSession(circleDelegate: requestDelegate!,
+                                                                 session: aesSession!,
+                                                                 otcontrol: self.otControl,
+                                                                 error: nil)
+        XCTAssertNotNil(requestCircleSession, "No request secret session")
+
+        requestCircleSession.setContextIDOnJoiningConfiguration(self.initiatorPiggybackingConfig.contextID)
+        requestCircleSession.setControlObject(self.otControl)
+
+        var identityMessage: Data?
+        do {
+            identityMessage = try requestCircleSession.initialMessage()
+            let parsedMessage = try KCJoiningMessage(der: identityMessage!)
+            XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
+            XCTAssertNotNil(parsedMessage.secondData, "No sos message")
+            XCTAssertNotNil(identityMessage, "No identity message")
         } catch {
             XCTAssertNil(error, "error retrieving identityMessage message")
         }
@@ -647,6 +851,7 @@ extension OctagonPairingTests {
 
         var voucherMessage: Data?
         do {
+            OctagonSetPlatformSupportsSOS(false)
             voucherMessage = try acceptSession!.processMessage(identityMessage!)
             let parsedMessage = try KCJoiningMessage(der: identityMessage!)
             XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
@@ -658,6 +863,181 @@ extension OctagonPairingTests {
 
         var nothing: Data?
         do {
+            OctagonSetPlatformSupportsSOS(true)
+            nothing = try requestCircleSession.processMessage(voucherMessage!)
+            XCTAssertNotNil(nothing, "No nothing message")
+        } catch {
+            XCTAssertNil(error, "error retrieving nothing message")
+        }
+
+        assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
+
+        XCTAssertTrue(requestSession!.isDone(), "requestor should be done")
+        XCTAssertTrue(acceptSession!.isDone(), "acceptor should be done")
+
+        clientStateMachine = self.manager.clientStateMachine(forContainerName: OTCKContainerName, contextID: self.contextForAcceptor, clientName: self.initiatorName)
+
+        clientStateMachine.notifyContainerChange()
+
+        self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertEnters(context: self.cuttlefishContextForAcceptor, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
+        self.assertConsidersSelfTrusted(context: self.cuttlefishContextForAcceptor)
+        self.verifyDatabaseMocks()
+
+        self.assertSelfTLKSharesInCloudKit(context: self.cuttlefishContext)
+        self.assertTLKSharesInCloudKit(receiver: self.cuttlefishContextForAcceptor, sender: self.cuttlefishContext)
+
+        let initiatorDumpCallback = self.expectation(description: "initiatorDumpCallback callback occurs")
+        self.tphClient.dump(withContainer: self.cuttlefishContext.containerName, context: self.cuttlefishContext.contextID) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+
+            initiatorDumpCallback.fulfill()
+        }
+        self.wait(for: [initiatorDumpCallback], timeout: 10)
+
+        let acceptorDumpCallback = self.expectation(description: "acceptorDumpCallback callback occurs")
+        self.tphClient.dump(withContainer: self.cuttlefishContext.containerName, context: self.contextForAcceptor) { dump, _ in
+            XCTAssertNotNil(dump, "dump should not be nil")
+            let egoSelf = dump!["self"] as? [String: AnyObject]
+            XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
+            let dynamicInfo = egoSelf!["dynamicInfo"] as? [String: AnyObject]
+            XCTAssertNotNil(dynamicInfo, "dynamicInfo should not be nil")
+            let included = dynamicInfo!["included"] as? [String]
+            XCTAssertNotNil(included, "included should not be nil")
+            XCTAssertEqual(included!.count, 2, "should be 2 peer ids")
+            acceptorDumpCallback.fulfill()
+        }
+        self.wait(for: [acceptorDumpCallback], timeout: 10)
+        XCTAssertEqual(self.fakeCuttlefishServer.state.bottles.count, 2, "should be 2 bottles")
+    }
+
+    func testVersion2ofPiggybackingWithRequesterOctagonOnly() throws {
+        KCSetJoiningOctagonPiggybackingEnabled(true)
+        OctagonSetPlatformSupportsSOS(true)
+        self.startCKAccountStatusMock()
+
+        self.getAcceptorInCircle()
+
+        let initiator1Context = self.manager.context(forContainerName: OTCKContainerName, contextID: OTDefaultContext)
+
+        var clientStateMachine = self.manager.clientStateMachine(forContainerName: OTCKContainerName, contextID: self.contextForAcceptor, clientName: self.initiatorName)
+        initiator1Context.startOctagonStateMachine()
+
+        self.assertEnters(context: initiator1Context, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
+
+        // Note that in this strange situation, the join should create the CKKS TLKs
+        let (requestDelegate, acceptDelegate, acceptSession, requestSession) = self.setupKCJoiningSessionObjects()
+        var initialMessageContainingOctagonVersion: Data?
+        var challengeContainingEpoch: Data?
+        var response: Data?
+        var verification: Data?
+        var doneMessage: Data?
+
+        XCTAssertNotNil(acceptSession, "acceptSession should not be nil")
+        XCTAssertNotNil(requestSession, "requestSession should not be nil")
+        XCTAssertNotNil(requestDelegate, "requestDelegate should not be nil")
+        XCTAssertNotNil(acceptDelegate, "acceptDelegate should not be nil")
+
+        do {
+            initialMessageContainingOctagonVersion = try requestSession!.initialMessage()
+        } catch {
+            XCTAssertNil(error, "error retrieving initialMessageContainingOctagonVersion message")
+        }
+
+        XCTAssertNotNil(initialMessageContainingOctagonVersion, "initial message should not be nil")
+
+        do {
+            OctagonSetPlatformSupportsSOS(true)
+            challengeContainingEpoch = try acceptSession!.processMessage(initialMessageContainingOctagonVersion!)
+            XCTAssertNotNil(challengeContainingEpoch, "challengeContainingEpoch should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving challengeContainingEpoch message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(false)
+            response = try requestSession!.processMessage(challengeContainingEpoch!)
+            XCTAssertNotNil(response, "response message should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(true)
+            verification = try acceptSession!.processMessage(response!)
+            XCTAssertNotNil(verification, "verification should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving verification message")
+        }
+
+        do {
+            OctagonSetPlatformSupportsSOS(false)
+            doneMessage = try requestSession!.processMessage(verification!)
+            XCTAssertNotNil(doneMessage, "doneMessage should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        let signInCallback = self.expectation(description: "trigger sign in")
+        self.otControl.sign(in: "348576349857", container: OTCKContainerName, context: OTDefaultContext) { error in
+            XCTAssertNil(error, "error should be nil")
+            signInCallback.fulfill()
+        }
+        self.wait(for: [signInCallback], timeout: 10)
+
+        XCTAssertTrue(requestSession!.isDone(), "SecretSession done")
+        XCTAssertFalse(acceptSession!.isDone(), "Unexpected accept session done")
+
+        let aesSession = requestSession!.session
+
+        let requestCircleSession = KCJoiningRequestCircleSession(circleDelegate: requestDelegate!,
+                                                                 session: aesSession!,
+                                                                 otcontrol: self.otControl,
+                                                                 error: nil)
+        XCTAssertNotNil(requestCircleSession, "No request secret session")
+
+        requestCircleSession.setContextIDOnJoiningConfiguration(self.initiatorPiggybackingConfig.contextID)
+        requestCircleSession.setControlObject(self.otControl)
+
+        var identityMessage: Data?
+        do {
+            OctagonSetPlatformSupportsSOS(false)
+            identityMessage = try requestCircleSession.initialMessage()
+            let parsedMessage = try KCJoiningMessage(der: identityMessage!)
+            XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
+            XCTAssertNil(parsedMessage.secondData, "sos message is populated")
+            XCTAssertNotNil(identityMessage, "No identity message")
+        } catch {
+            XCTAssertNil(error, "error retrieving identityMessage message")
+        }
+
+        // Double-check that there's an Octagon message in the packet
+        let initiatorIdentityMessage = try self.unpackPiggybackingInitialMessage(identityMessage: identityMessage!, session: acceptSession!.accessSession())
+        XCTAssertTrue(initiatorIdentityMessage.hasPrepare, "Pairing message should contain prepared information")
+
+        var voucherMessage: Data?
+        do {
+            OctagonSetPlatformSupportsSOS(true)
+            voucherMessage = try acceptSession!.processMessage(identityMessage!)
+            let parsedMessage = try KCJoiningMessage(der: identityMessage!)
+            XCTAssertNotNil(parsedMessage.firstData, "No octagon message")
+            XCTAssertNil(parsedMessage.secondData, "sos message is populated")
+            XCTAssertNotNil(voucherMessage, "No voucherMessage message")
+        } catch {
+            XCTAssertNil(error, "error retrieving voucherMessage message")
+        }
+
+        var nothing: Data?
+        do {
+            OctagonSetPlatformSupportsSOS(false)
             nothing = try requestCircleSession.processMessage(voucherMessage!)
             XCTAssertNotNil(nothing, "No nothing message")
         } catch {
@@ -799,7 +1179,6 @@ extension OctagonPairingTests {
         do {
             identityMessage = try requestCircleSession.initialMessage()
             XCTAssertNotNil(identityMessage, "No identity message")
-
         } catch {
             XCTAssertNil(error, "error retrieving identityMessage message")
         }
@@ -810,7 +1189,6 @@ extension OctagonPairingTests {
             XCTAssertNotNil(voucherMessage, "No voucherMessage message")
         } catch {
             XCTAssertNil(error, "error retrieving voucherMessage message")
-
         }
 
         var nothing: Data?
@@ -819,13 +1197,125 @@ extension OctagonPairingTests {
             XCTAssertNotNil(nothing, "No nothing message")
         } catch {
             XCTAssertNil(error, "error retrieving nothing message")
-
         }
 
         XCTAssertTrue(requestSession!.isDone(), "requestor should be done")
         XCTAssertTrue(acceptSession!.isDone(), "acceptor should be done")
     }
 
+    func testPiggybackingForTLKRequest() throws {
+        KCSetJoiningOctagonPiggybackingEnabled(true)
+        OctagonSetIsEnabled(true)
+        self.startCKAccountStatusMock()
+
+        self.assertResetAndBecomeTrustedInDefaultContext()
+
+        let (requestDelegate, acceptDelegate, acceptSession, requestSession) = self.setupKCJoiningSessionObjects()
+        var initialMessageContainingOctagonVersion: Data?
+        var challengeContainingEpoch: Data?
+        var response: Data?
+        var verification: Data?
+        var doneMessage: Data?
+
+        XCTAssertNotNil(acceptSession, "acceptSession should not be nil")
+        XCTAssertNotNil(requestSession, "requestSession should not be nil")
+        XCTAssertNotNil(requestDelegate, "requestDelegate should not be nil")
+        XCTAssertNotNil(acceptDelegate, "acceptDelegate should not be nil")
+
+        do {
+            initialMessageContainingOctagonVersion = try requestSession!.initialMessage()
+        } catch {
+            XCTAssertNil(error, "error retrieving initialMessageContainingOctagonVersion message")
+        }
+
+        XCTAssertNotNil(initialMessageContainingOctagonVersion, "initial message should not be nil")
+
+        do {
+            challengeContainingEpoch = try acceptSession!.processMessage(initialMessageContainingOctagonVersion!)
+            XCTAssertNotNil(challengeContainingEpoch, "challengeContainingEpoch should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving challengeContainingEpoch message")
+        }
+
+        do {
+            response = try requestSession!.processMessage(challengeContainingEpoch!)
+            XCTAssertNotNil(response, "response message should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        do {
+            verification = try acceptSession!.processMessage(response!)
+            XCTAssertNotNil(verification, "verification should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving verification message")
+        }
+
+        do {
+            doneMessage = try requestSession!.processMessage(verification!)
+            XCTAssertNotNil(doneMessage, "doneMessage should not be nil")
+        } catch {
+            XCTAssertNil(error, "error retrieving response message")
+        }
+
+        XCTAssertTrue(requestSession!.isDone(), "SecretSession should be done")
+        XCTAssertFalse(acceptSession!.isDone(), "Accept session should not be done")
+
+        let aesSession = requestSession!.session
+
+        let requestCircleSession = KCJoiningRequestCircleSession(circleDelegate: requestDelegate!,
+                                                                 session: aesSession!,
+                                                                 otcontrol: self.otControl,
+                                                                 error: nil)
+        XCTAssertNotNil(requestCircleSession, "Should have a request secret session")
+
+        var tlkResponseMessage: Data?
+        do {
+            let tlkRequestMessage = try KCJoiningMessage(type: kTLKRequest, data: Data())
+            tlkResponseMessage = try acceptSession!.processMessage(tlkRequestMessage.der)
+            XCTAssertNotNil(tlkResponseMessage, "Should have a TLK response")
+        } catch {
+            XCTAssertNil(error, "error retrieving voucherMessage message")
+        }
+
+        XCTAssertTrue(acceptSession!.isDone(), "Accept session should be done after responding to a TLK request")
+        // Note that we no longer care about the joiningSession, because this software stack doesn't receive tlkrequest messages.
+
+        let tlkResponseMessageCiphertext = try KCJoiningMessage(der: tlkResponseMessage!)
+        let tlkResponseMessageDER = try requestCircleSession.accessSession().decryptAndVerify(tlkResponseMessageCiphertext.firstData)
+
+        let piggybackedPlist = TestsObjectiveC.copyPiggybackingInitialSyncData(tlkResponseMessageDER)
+        XCTAssertNotNil(piggybackedPlist, "Should have something piggybacked across the channel")
+
+        let tlks = piggybackedPlist?["tlks"] as? [Any]
+        XCTAssertNotNil(tlks, "Should have some tlk contents")
+        #if !os(tvOS)
+        // TVs don't have the Passwords view, and so won't send it via piggybacking
+        XCTAssertEqual(tlks?.count, 1, "Should have one tlk transferred")
+
+        if let tlk = tlks?.first as? [AnyHashable: Any] {
+            let view = tlk["srvr"] as? String
+            XCTAssertEqual(view, "Passwords", "Should have the TLK for the passwords view")
+
+            let uuid = tlk["acct"] as? String
+            if let keyset = self.keys?[self.passwordsZoneID!] as? ZoneKeys {
+                XCTAssertEqual(uuid, keyset.currentTLKPointer?.currentKeyUUID, "Piggybacked TLK should match zone's TLK")
+            } else {
+                XCTFail("CKKS should have made keys for the passwords view")
+            }
+            print(tlk)
+        } else {
+            XCTFail("Unable to extract TLK as plist")
+        }
+        #else
+        XCTAssertEqual(tlks?.count, 0, "Should have zero tlks transferred (from a TV)")
+        #endif
+
+        // The plist might also have some idents. Check that there aren't any
+        let idents = piggybackedPlist?["idents"] as? [Any]
+        XCTAssertNotNil(idents, "Should have some idents array")
+        XCTAssertEqual(idents?.count, 0, "Should have no idents contents")
+    }
 }
 
 #endif
index 142b3410018c85d54a31e527cf4184fa753ef6bc..53a656af281faa21100f77863331e49c4b10c7fd 100644 (file)
@@ -1,9 +1,7 @@
 #if OCTAGON
 
 extension OctagonPairingTests {
-
     func test2ClientsBothOctagonAndSOS() {
-
         OctagonSetPlatformSupportsSOS(true)
         self.startCKAccountStatusMock()
 
@@ -578,7 +576,6 @@ extension OctagonPairingTests {
     }
 
     func test2ClientsSOSOnly() {
-
         OctagonSetPlatformSupportsSOS(true)
         OctagonSetIsEnabled(false)
         self.startCKAccountStatusMock()
index 47786d254236188189324ab9c37ad67ccec88550..b2910fa8e376b51d6f982be4399993ffc35cfd8f 100644 (file)
@@ -1,7 +1,6 @@
 #if OCTAGON
 
 extension OctagonPairingTests {
-
     func assertSOSSuccess() {
         XCTAssertNotNil(self.fcInitiator?.accountPrivateKey, "no accountPrivateKey in fcInitiator")
         XCTAssertNotNil(self.fcAcceptor?.accountPrivateKey, "no accountPrivateKey in fcAcceptor")
@@ -1398,7 +1397,6 @@ extension OctagonPairingTests {
          self.assertConsidersSelfTrusted(context: initiatorContext)
          */
     }
-
 }
 
 #endif
index 5eda3686a79587a1813978fc076de3f908be68a7..0345fac29b49e77f265c6808e67888da2356a82d 100644 (file)
@@ -1,7 +1,6 @@
 #if OCTAGON
 
 func GenerateFullECKey(keySize: Int) -> (SecKey) {
-
     let keyPair = _SFECKeyPair.init(randomKeyPairWith: _SFECKeySpecifier.init(curve: SFEllipticCurve.nistp384))!
 
     var keyAttributes: [String: String] = [:]
@@ -38,7 +37,7 @@ class KCJoiningRequestTestDelegate: NSObject, KCJoiningRequestSecretDelegate, KC
         var gestalt: [String: String] = [:]
         gestalt[kPIUserDefinedDeviceNameKey as String] = "Fakey"
 
-        let newPeerInfo = SOSPeerInfoCreate(nil, gestalt as CFDictionary, nil, signingKey, octagonSigningKey, octagonEncryptionKey, nil)
+        let newPeerInfo = SOSPeerInfoCreate(nil, gestalt as CFDictionary, nil, signingKey, octagonSigningKey, octagonEncryptionKey, true, nil)
 
         self.peerInfo = newPeerInfo
         self.sharedSecret = secret
@@ -78,7 +77,6 @@ class KCJoiningRequestTestDelegate: NSObject, KCJoiningRequestSecretDelegate, KC
 }
 
 class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJoiningAcceptCircleDelegate {
-
     var secrets: [String] = []
     var currentSecret: Int = 0
     var retriesLeft: Int = 0
@@ -102,7 +100,6 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo
     }
 
     init(withSecrets secrets: [String], retries: Int, code: String) {
-
         self.secrets = secrets
         self.currentSecret = 0
         self.retriesPerSecret = retries
@@ -159,7 +156,10 @@ class KCJoiningAcceptTestDelegate: NSObject, KCJoiningAcceptSecretDelegate, KCJo
     }
 
     func circleGetInitialSyncViews(_ flags: SOSInitialSyncFlags, error: NSErrorPointer) -> Data {
-        return Data()
+
+        // Skip the XPC and just call the server method
+        let possibleData = try? TestsObjectiveC.copyInitialSyncData(flags)
+        return possibleData ?? Data()
     }
 }
 
@@ -253,7 +253,7 @@ extension OctagonTestsBase {
         let acceptSession = try KCJoiningAcceptSession(secretDelegate: acceptDelegate as KCJoiningAcceptSecretDelegate,
                                                        circleDelegate: acceptDelegate as KCJoiningAcceptCircleDelegate,
                                                        dsid: dsid,
-                                                       rng: ccDRBGGetRngState())
+                                                       rng: ccrng(nil))
         requestSession.setControlObject(self.otControl)
         acceptSession.setControlObject(self.otControl)
 
@@ -360,7 +360,6 @@ extension OctagonTestsBase {
 
 @objcMembers
 class OctagonPairingTests: OctagonTestsBase {
-
     var sosAdapterForAcceptor: CKKSMockSOSPresentAdapter!
     var cuttlefishContextForAcceptor: OTCuttlefishContext!
     var contextForAcceptor = "defaultContextForAcceptor"
@@ -377,6 +376,27 @@ class OctagonPairingTests: OctagonTestsBase {
     var fcAcceptor: FCPairingFakeSOSControl!
 
     override func setUp() {
+        // We want the Passwords view to exist, so that we can check the piggybacking TLK channel
+        if self.mockDeviceInfo == nil {
+            let actualDeviceAdapter = OTDeviceInformationActualAdapter()
+            self.mockDeviceInfo = OTMockDeviceInfoAdapter(modelID: actualDeviceAdapter.modelID(),
+                                                          deviceName: actualDeviceAdapter.deviceName(),
+                                                          serialNumber: NSUUID().uuidString,
+                                                          osVersion: actualDeviceAdapter.osVersion())
+        }
+
+        if self.mockDeviceInfo.mockModelID.contains("AppleTV") {
+            self.intendedCKKSZones = Set([
+                CKRecordZone.ID(zoneName: "LimitedPeersAllowed"),
+            ])
+        } else {
+            self.intendedCKKSZones = Set([
+                CKRecordZone.ID(zoneName: "LimitedPeersAllowed"),
+                CKRecordZone.ID(zoneName: "Manatee"),
+                CKRecordZone.ID(zoneName: "Passwords"),
+            ])
+        }
+
         super.setUp()
 
         // The acceptor should have its own SOS state
@@ -386,12 +406,12 @@ class OctagonPairingTests: OctagonTestsBase {
         self.sosAdapterForAcceptor.circleStatus = SOSCCStatus(kSOSCCInCircle)
 
         self.cuttlefishContextForAcceptor = self.manager.context(forContainerName: OTCKContainerName,
-                                                contextID: self.contextForAcceptor,
-                                                sosAdapter: self.sosAdapterForAcceptor,
-                                                authKitAdapter: self.mockAuthKit3,
-                                                lockStateTracker: self.lockStateTracker,
-                                                accountStateTracker: self.accountStateTracker,
-                                                deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)"))
+                                                                 contextID: self.contextForAcceptor,
+                                                                 sosAdapter: self.sosAdapterForAcceptor,
+                                                                 authKitAdapter: self.mockAuthKit3,
+                                                                 lockStateTracker: self.lockStateTracker,
+                                                                 accountStateTracker: self.accountStateTracker,
+                                                                 deviceInformationAdapter: OTMockDeviceInfoAdapter(modelID: "iPhone9,1", deviceName: "test-SOS-iphone", serialNumber: "456", osVersion: "iOS (fake version)"))
 
         self.acceptorPiggybackingConfig = OTJoiningConfiguration(protocolType: OTProtocolPiggybacking,
                                                                  uniqueDeviceID: "acceptor",
@@ -444,7 +464,6 @@ class OctagonPairingTests: OctagonTestsBase {
     }
 
     func setupPairingEndpoints(withPairNumber pairNumber: String, initiatorContextID: String, acceptorContextID: String, initiatorUniqueID: String, acceptorUniqueID: String) -> (KCPairingChannel, KCPairingChannel) {
-
         let (acceptorClique, initiatorClique) = self.setupOTCliquePair(withNumber: pairNumber)
         XCTAssertNotNil(acceptorClique, "acceptorClique should not be nil")
         XCTAssertNotNil(initiatorClique, "initiatorClique should not be nil")
@@ -505,16 +524,11 @@ class OctagonPairingTests: OctagonTestsBase {
     }
 
     func setupOTCliquePair(withNumber count: String) -> (OTClique?, OTClique?) {
-
         let secondAcceptorData = OTConfigurationContext()
         secondAcceptorData.context = "secondAcceptor"
         secondAcceptorData.dsid = "a-"+count
         secondAcceptorData.altDSID = "alt-a-"+count
 
-        let acceptorAnalytics = SFSignInAnalytics(signInUUID: "uuid", category: "com.apple.cdp", eventName: "signed in")
-        XCTAssertNotNil(acceptorAnalytics, "acceptorAnalytics should not be nil")
-        secondAcceptorData.analytics = acceptorAnalytics
-
         let acceptor = OTClique(contextData: secondAcceptorData)
         XCTAssertNotNil(acceptor, "Clique should not be nil")
         acceptor.setPairingDefault(true)
@@ -524,9 +538,6 @@ class OctagonPairingTests: OctagonTestsBase {
         secondInitiatorData.dsid = "i-"+count
         secondInitiatorData.altDSID = "alt-i-"+count
 
-        let initiatorAnalytics = SFSignInAnalytics(signInUUID: "uuid", category: "com.apple.cdp", eventName: "signed in")
-        XCTAssertNotNil(initiatorAnalytics, "initiatorAnalytics should not be nil")
-        secondInitiatorData.analytics = initiatorAnalytics
         let initiator = OTClique(contextData: secondInitiatorData)
         XCTAssertNotNil(initiator, "Clique should not be nil")
         initiator.setPairingDefault(true)
index 413ad8e3a480e4ac1b86b7ee0c97f655eab306e8..9a2901c943bc9c99273cc03392f3c6a85cd370e8 100644 (file)
@@ -5,6 +5,8 @@
 #import <Foundation/Foundation.h>
 #import <Security/OTClique.h>
 #import <TrustedPeers/TrustedPeers.h>
+#include <Security/SecureObjectSync/SOSCloudCircle.h>
+#include "keychain/ckks/CKKSPeer.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -23,6 +25,12 @@ NS_ASSUME_NONNULL_BEGIN
 + (BOOL)saveCoruptDataToKeychainForContainer:(NSString*)containerName
                                    contextID:(NSString*)contextID
                                        error:(NSError**)error;
+
++ (NSData* _Nullable)copyInitialSyncData:(SOSInitialSyncFlags)flags error:(NSError**)error;
+
++ (NSDictionary* _Nullable)copyPiggybackingInitialSyncData:(NSData*)data;
+
++ (BOOL)testSecKey:(CKKSSelves*)octagonSelf error:(NSError**)error;
 @end
 
 NS_ASSUME_NONNULL_END
index 510211940569f41ec59caf286c645df7cae6a4db..d89c674120463ab3d24884ded4c31e753a978597 100644 (file)
@@ -2,10 +2,12 @@
 #import <Security/OTClique.h>
 #import <OCMock/OCMock.h>
 
-#import <SoftLinking/SoftLinking.h>
 #import "keychain/ot/OTCuttlefishContext.h"
 #import <Security/SecItemPriv.h>
+#import <SecurityFoundation/SecurityFoundation.h>
 #import "keychain/categories/NSError+UsefulConstructors.h"
+#import "keychain/securityd/SOSCloudCircleServer.h"
+#import "keychain/SecureObjectSync/SOSAccountPriv.h"
 
 static const uint8_t signingKey_384[] = {
     0x04, 0xe4, 0x1b, 0x3e, 0x88, 0x81, 0x9f, 0x3b, 0x80, 0xd0, 0x28, 0x1c,
@@ -106,4 +108,115 @@ static const uint8_t signingKey_384[] = {
     }
 }
 
++ (NSData* _Nullable)copyInitialSyncData:(SOSInitialSyncFlags)flags error:(NSError**)error
+{
+    CFErrorRef cferror = NULL;
+    NSData* result = CFBridgingRelease(SOSCCCopyInitialSyncData_Server(flags, &cferror));
+
+    if(cferror && error) {
+        *error = CFBridgingRelease(cferror);
+    }
+
+    return result;
+}
+
++ (NSDictionary* _Nullable)copyPiggybackingInitialSyncData:(NSData*)data
+{
+    const uint8_t* der = [data bytes];
+    const uint8_t *der_end = der + [data length];
+
+    NSDictionary* results = SOSPiggyCopyInitialSyncData(&der, der_end);
+    return results;
+}
+
++ (BOOL)testSecKey:(CKKSSelves*)octagonSelf error:(NSError**)error
+{
+    id<CKKSSelfPeer> currentSelfPeer = octagonSelf.currentSelf;
+
+    NSData* signingFullKey = currentSelfPeer.signingKey.keyData;
+
+    SecKeyRef octagonSigningPubSecKey = CFRetainSafe(currentSelfPeer.publicSigningKey.secKey);
+    SecKeyRef octagonEncryptionPubSecKey = CFRetainSafe(currentSelfPeer.publicEncryptionKey.secKey);
+
+    NSError* localerror = nil;
+
+    bool savedSigningKey = SOSCCSaveOctagonKeysToKeychain(@"Octagon Peer Signing ID for Test-ak",
+                                                          signingFullKey,
+                                                          384,
+                                                          octagonSigningPubSecKey,
+                                                          &localerror);
+    if(!savedSigningKey) {
+        if(error) {
+            *error = localerror;
+        }
+        CFReleaseNull(octagonSigningPubSecKey);
+        CFReleaseNull(octagonEncryptionPubSecKey);
+        return NO;
+    }
+
+    // Okay, can we load this key pair?
+
+    // Try the SPI route first
+    CFErrorRef cferror = NULL;
+    SecKeyRef signingPrivateKey = SecKeyCopyMatchingPrivateKey(octagonSigningPubSecKey, &cferror);
+    if(!signingPrivateKey) {
+        if(error) {
+            *error = CFBridgingRelease(cferror);
+        } else {
+            CFReleaseNull(cferror);
+        }
+        CFReleaseNull(octagonSigningPubSecKey);
+        CFReleaseNull(octagonEncryptionPubSecKey);
+        return NO;
+    }
+
+    // and can you get the persistent ref from that private key?
+    CFDataRef pref = NULL;
+    OSStatus status = SecKeyCopyPersistentRef(signingPrivateKey, &pref);
+    if(status != errSecSuccess) {
+        if(error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                         code:status
+                                  description:@"Failed to copy persistent ref"];
+        }
+        CFReleaseNull(pref);
+        CFReleaseNull(octagonSigningPubSecKey);
+        CFReleaseNull(octagonEncryptionPubSecKey);
+        return NO;
+    }
+
+
+    SFECKeyPair *signingFullKeyPair = [[SFECKeyPair alloc] initWithData:signingFullKey
+                                                              specifier:[[SFECKeySpecifier alloc] initWithCurve:SFEllipticCurveNistp384]
+                                                                  error:&localerror];
+    if(!signingFullKey) {
+        if(error) {
+            *error = localerror;
+        }
+        CFReleaseNull(octagonSigningPubSecKey);
+        CFReleaseNull(octagonEncryptionPubSecKey);
+        return NO;
+    }
+
+    CFDataRef prefFromSF = NULL;
+    OSStatus statusFromSF = SecKeyCopyPersistentRef(signingFullKeyPair.secKey, &prefFromSF);
+    if(statusFromSF != errSecSuccess) {
+        if(error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain
+                                         code:statusFromSF
+                                  description:@"Failed to copy persistent ref"];
+        }
+        CFReleaseNull(pref);
+        CFReleaseNull(octagonSigningPubSecKey);
+        CFReleaseNull(octagonEncryptionPubSecKey);
+        return NO;
+    }
+
+    CFReleaseNull(pref);
+    CFReleaseNull(octagonSigningPubSecKey);
+    CFReleaseNull(octagonEncryptionPubSecKey);
+
+    return YES;
+}
+
 @end
index 382933355e65a5770bf3dfc67bdb7cf1a818d386..9e7cf6a8964a7d993bda2bca3a9c831419d7a981 100644 (file)
@@ -11,37 +11,55 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (instancetype)initWithOTControl:(OTControl*)control;
 
-- (long)startOctagonStateMachine:(NSString*)container context:(NSString*)contextID;
+- (long)startOctagonStateMachine:(NSString *)container context:(NSString *)contextID;
 
-- (long)signIn:(NSString*)altDSID container:(NSString* _Nullable)container context:(NSString*)contextID;
+- (long)signIn:(NSString *)altDSID container:(NSString * _Nullable)container context:(NSString *)contextID;
 
-- (long)signOut:(NSString* _Nullable)container context:(NSString*)contextID;
+- (long)signOut:(NSString * _Nullable)container context:(NSString *)contextID;
 
-- (long)depart:(NSString* _Nullable)container context:(NSString*)contextID;
+- (long)depart:(NSString * _Nullable)container context:(NSString *)contextID;
 
-- (long)resetOctagon:(NSString*)container context:(NSString*)contextID altDSID:(NSString*)altDSID;
+- (long)resetOctagon:(NSString *)container context:(NSString *)contextID altDSID:(NSString *)altDSID;
 
-- (long)resetProtectedData:(NSString*)container context:(NSString*)contextID altDSID:(NSString*)altDSID appleID:(NSString*)appleID dsid:(NSString*)dsid;
+- (long)resetProtectedData:(NSString *)container context:(NSString *)contextID altDSID:(NSString *)altDSID appleID:(NSString *)appleID dsid:(NSString *)dsid;
 
-- (long)status:(NSString* _Nullable)container context:(NSString*)contextID json:(bool)json;
+- (long)status:(NSString * _Nullable)container context:(NSString *)contextID json:(bool)json;
 
-- (long)recoverUsingBottleID:(NSString*)bottleID
-                     entropy:(NSData*)entropy
-                     altDSID:(NSString*)altDSID
-               containerName:(NSString*)containerName
-                     context:(NSString*)context
-                     control:(OTControl*)control;
+- (long)recoverUsingBottleID:(NSString *)bottleID
+                     entropy:(NSData *)entropy
+                     altDSID:(NSString *)altDSID
+               containerName:(NSString *)containerName
+                     context:(NSString *)context
+                     control:(OTControl *)control;
 
-- (long)fetchAllBottles:(NSString*)altDSID
-          containerName:(NSString*)containerName
-                context:(NSString*)context
-                control:(OTControl*)control;
+- (long)fetchAllBottles:(NSString *)altDSID
+          containerName:(NSString *)containerName
+                context:(NSString *)context
+                control:(OTControl *)control;
 
-- (long)healthCheck:(NSString* _Nullable)container context:(NSString*)contextID skipRateLimitingCheck:(BOOL)skipRateLimitingCheck;
-- (long)refetchCKKSPolicy:(NSString*)container context:(NSString*)contextID;
+- (long)fetchEscrowRecords:(NSString * _Nullable)container context:(NSString *)contextID;
+- (long)fetchAllEscrowRecords:(NSString* _Nullable)container context:(NSString*)contextID;
+
+- (long)healthCheck:(NSString * _Nullable)container context:(NSString *)contextID skipRateLimitingCheck:(BOOL)skipRateLimitingCheck;
+- (long)refetchCKKSPolicy:(NSString *)container context:(NSString *)contextID;
 
 - (long)tapToRadar:(NSString *)action description:(NSString *)description radar:(NSString *)radar;
 
+- (long)performEscrowRecovery:(NSString * _Nullable)container
+                      context:(NSString *)contextID
+                     recordID:(NSString *)recordID
+                      appleID:(NSString *)appleID
+                       secret:(NSString *)secret;
+
+- (long)performSilentEscrowRecovery:(NSString * _Nullable)container context:(NSString *)contextID appleID:(NSString *)appleID secret:(NSString *)secret;
+
+- (long)setUserControllableViewsSyncStatus:(NSString * _Nullable)containerName
+                                 contextID:(NSString *)contextID
+                                   enabled:(BOOL)enabled;
+
+- (long)fetchUserControllableViewsSyncStatus:(NSString * _Nullable)containerName
+                                   contextID:(NSString *)contextID;
+
 @end
 
 NS_ASSUME_NONNULL_END
index 5637dec991ad9725437afd0bcabc7b3f7e1aa3f3..a9f56ff250de144b11b2e8c2b17abca2f2b13b41 100644 (file)
 #import "keychain/ot/OT.h"
 #import "keychain/ot/OTConstants.h"
 #import "keychain/ot/OTControl.h"
+
 #import "keychain/otctl/OTControlCLI.h"
 
+#import "keychain/OctagonTrust/OctagonTrust.h"
 
 #import <AuthKit/AKAppleIDAuthenticationController.h>
 #import <AuthKit/AKAppleIDAuthenticationContext.h>
 #import <AuthKit/AKAppleIDAuthenticationContext_Private.h>
 
-static NSString* fetch_pet(NSString* appleID, NSString* dsid)
+static NSString * fetch_pet(NSString * appleID, NSString * dsid)
 {
     if(!appleID && !dsid) {
         NSLog(@"Must provide either an AppleID or a DSID to fetch a PET");
@@ -34,7 +36,7 @@ static NSString* fetch_pet(NSString* appleID, NSString* dsid)
     authContext.authenticationType = AKAppleIDAuthenticationTypeSilent;
     authContext.isUsernameEditable = NO;
 
-    __block NSString* pet = nil;
+    __block NSString * pet = nil;
 
     dispatch_semaphore_t s = dispatch_semaphore_create(0);
 
@@ -130,7 +132,7 @@ static void print_json(NSDictionary* dict)
     return self;
 }
 
-- (long)startOctagonStateMachine:(NSString*)container context:(NSString*)contextID {
+- (long)startOctagonStateMachine:(NSString *)container context:(NSString *)contextID {
 #if OCTAGON
     __block long ret = -1;
 
@@ -152,7 +154,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)signIn:(NSString*)altDSID container:(NSString* _Nullable)container context:(NSString*)contextID {
+- (long)signIn:(NSString *)altDSID container:(NSString * _Nullable)container context:(NSString *)contextID {
 #if OCTAGON
     __block long ret = -1;
 
@@ -175,7 +177,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)signOut:(NSString* _Nullable)container context:(NSString*)contextID {
+- (long)signOut:(NSString * _Nullable)container context:(NSString *)contextID {
 #if OCTAGON
     __block long ret = -1;
     [self.control signOut:container
@@ -195,7 +197,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)depart:(NSString* _Nullable)container context:(NSString*)contextID {
+- (long)depart:(NSString * _Nullable)container context:(NSString *)contextID {
 #if OCTAGON
     __block long ret = -1;
 
@@ -216,7 +218,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)resetOctagon:(NSString*)container context:(NSString*)contextID altDSID:(NSString*)altDSID {
+- (long)resetOctagon:(NSString *)container context:(NSString *)contextID altDSID:(NSString *)altDSID {
 #if OCTAGON
     __block long ret = -1;
 
@@ -241,7 +243,7 @@ static void print_json(NSDictionary* dict)
 }
 
 
-- (long)resetProtectedData:(NSString*)container context:(NSString*)contextID altDSID:(NSString*)altDSID appleID:(NSString*)appleID dsid:(NSString*)dsid
+- (long)resetProtectedData:(NSString *)container context:(NSString *)contextID altDSID:(NSString *)altDSID appleID:(NSString *)appleID dsid:(NSString *)dsid
 {
 #if OCTAGON
     __block long ret = -1;
@@ -252,6 +254,7 @@ static void print_json(NSDictionary* dict)
     data.authenticationAppleID = appleID;
     data.altDSID = altDSID;
     data.context = contextID;
+    data.containerName = container;
 
     OTClique* clique = [OTClique resetProtectedData:data error:&error];
     if(clique != nil && error == nil) {
@@ -264,13 +267,13 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (void)printPeer:(NSDictionary*)peerInformation prefix:(NSString* _Nullable)prefix {
-    NSString* peerID = peerInformation[@"peerID"];
-    NSString* model = peerInformation[@"permanentInfo"][@"model_id"];
+- (void)printPeer:(NSDictionary*)peerInformation prefix:(NSString * _Nullable)prefix {
+    NSString * peerID = peerInformation[@"peerID"];
+    NSString * model = peerInformation[@"permanentInfo"][@"model_id"];
     NSNumber* epoch = peerInformation[@"permanentInfo"][@"epoch"];
-    NSString* deviceName = peerInformation[@"stableInfo"][@"device_name"];
-    NSString* serialNumber = peerInformation[@"stableInfo"][@"serial_number"];
-    NSString* os = peerInformation[@"stableInfo"][@"os_version"];
+    NSString * deviceName = peerInformation[@"stableInfo"][@"device_name"];
+    NSString * serialNumber = peerInformation[@"stableInfo"][@"serial_number"];
+    NSString * os = peerInformation[@"stableInfo"][@"os_version"];
 
     printf("%s%s hw:'%s' name:'%s' serial: '%s' os:'%s' epoch:%d\n",
            (prefix ? [prefix UTF8String] : ""),
@@ -282,10 +285,10 @@ static void print_json(NSDictionary* dict)
            [epoch intValue]);
 }
 
-- (void)printPeers:(NSArray<NSString*>*)peerIDs
-             egoPeerID:(NSString* _Nullable)egoPeerID
-    informationOnPeers:(NSDictionary<NSString*, NSDictionary*>*)informationOnPeers {
-    for(NSString* peerID in peerIDs) {
+- (void)printPeers:(NSArray<NSString *>*)peerIDs
+             egoPeerID:(NSString * _Nullable)egoPeerID
+    informationOnPeers:(NSDictionary<NSString *, NSDictionary*>*)informationOnPeers {
+    for(NSString * peerID in peerIDs) {
         NSDictionary* peerInformation = informationOnPeers[peerID];
 
         if(!peerInformation) {
@@ -301,7 +304,156 @@ static void print_json(NSDictionary* dict)
     }
 }
 
-- (long)status:(NSString* _Nullable)container context:(NSString*)contextID json:(bool)json {
+- (long)fetchEscrowRecords:(NSString * _Nullable)container context:(NSString *)contextID {
+#if OCTAGON
+    __block long ret = -1;
+
+    NSError* error = nil;
+    OTConfigurationContext *data = [[OTConfigurationContext alloc] init];
+    data.context = contextID;
+    data.containerName = container;
+
+    NSArray<OTEscrowRecord*>* records = [OTClique fetchEscrowRecords:data error:&error];
+    if(records != nil && error == nil) {
+        printf("Successfully fetched %lu records.\n", (unsigned long)records.count);
+        ret = 0;
+        for(OTEscrowRecord* record in records){
+            CFErrorRef* localError = NULL;
+            SOSPeerInfoRef peer = SOSPeerInfoCreateFromData(kCFAllocatorDefault, localError, (__bridge CFDataRef)record.escrowInformationMetadata.peerInfo);
+            CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
+            printf("fetched record id: %s\n", [(__bridge NSString *)peerID UTF8String]);
+        }
+    }
+    return ret;
+#else
+    printf("Unimplemented.\n");
+    return -1;
+#endif
+}
+
+- (long)fetchAllEscrowRecords:(NSString* _Nullable)container context:(NSString*)contextID {
+#if OCTAGON
+    __block long ret = -1;
+
+    NSError* error = nil;
+    OTConfigurationContext *data = [[OTConfigurationContext alloc] init];
+    data.context = contextID;
+    data.containerName = container;
+
+    NSArray<OTEscrowRecord*>* records = [OTClique fetchAllEscrowRecords:data error:&error];
+    if(records != nil && error == nil) {
+        printf("Successfully fetched %lu records.\n", (unsigned long)records.count);
+        ret = 0;
+        for(OTEscrowRecord* record in records){
+            CFErrorRef* localError = NULL;
+            SOSPeerInfoRef peer = SOSPeerInfoCreateFromData(kCFAllocatorDefault, localError, (__bridge CFDataRef)record.escrowInformationMetadata.peerInfo);
+            CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
+            printf("fetched record id: %s\n", [(__bridge NSString*)peerID UTF8String]);
+        }
+    }
+    return ret;
+#else
+    printf("Unimplemented.\n");
+    return -1;
+#endif
+}
+
+- (long)performEscrowRecovery:(NSString * _Nullable)container context:(NSString *)contextID recordID:(NSString *)recordID appleID:(NSString *)appleID secret:(NSString *)secret
+{
+#if OCTAGON
+    __block long ret = -1;
+
+    NSError* error = nil;
+    OTConfigurationContext *data = [[OTConfigurationContext alloc] init];
+    data.context = contextID;
+
+    OTICDPRecordContext* cdpContext = [[OTICDPRecordContext alloc] init];
+    cdpContext.cdpInfo = [[OTCDPRecoveryInformation alloc] init];
+    cdpContext.cdpInfo.recoverySecret = secret;
+    cdpContext.cdpInfo.containsIcdpData = true;
+    cdpContext.cdpInfo.usesMultipleIcsc = true;
+    cdpContext.authInfo = [[OTEscrowAuthenticationInformation alloc] init];
+    cdpContext.authInfo.authenticationAppleid = appleID;
+    cdpContext.authInfo.authenticationPassword = fetch_pet(appleID, nil);
+    
+    NSArray<OTEscrowRecord*>* escrowRecords = [OTClique fetchEscrowRecords:data error:&error];
+    if (escrowRecords == nil || error != nil) {
+        printf("Failed to fetch escrow records.\n");
+        ret = -1;
+    }
+    OTEscrowRecord* record = nil;
+    
+    for (OTEscrowRecord* r in escrowRecords) {
+        CFErrorRef* localError = NULL;
+        SOSPeerInfoRef peer = SOSPeerInfoCreateFromData(kCFAllocatorDefault, localError, (__bridge CFDataRef)r.escrowInformationMetadata.peerInfo);
+        CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
+        
+        if ([(__bridge NSString *)peerID isEqualToString:recordID]) {
+            record = r;
+            break;
+        }
+    }
+    if (record == nil){
+        printf("Failed to find escrow record to restore. \n");
+        return -1;
+    }
+    
+    OTClique* clique = [OTClique performEscrowRecovery:data cdpContext:cdpContext escrowRecord:record error:&error];
+    if (clique != nil && error == nil) {
+        printf("Successfully performed escrow recovery.\n");
+        ret = 0;
+    } else {
+        fprintf(stderr, "Escrow recovery failed: %s\n", error.description.UTF8String);
+    }
+    return ret;
+#else
+    printf("Unimplemented.\n");
+    return -1;
+#endif
+}
+
+- (long)performSilentEscrowRecovery:(NSString * _Nullable)container context:(NSString *)contextID appleID:(NSString *)appleID secret:(NSString *)secret {
+#if OCTAGON
+    __block long ret = -1;
+    
+    NSError* error = nil;
+    OTConfigurationContext *data = [[OTConfigurationContext alloc] init];
+    data.context = contextID;
+    
+    OTICDPRecordContext* cdpContext = [[OTICDPRecordContext alloc] init];
+    cdpContext.cdpInfo = [[OTCDPRecoveryInformation alloc] init];
+
+    cdpContext.cdpInfo.recoverySecret = secret;
+    cdpContext.cdpInfo.containsIcdpData = true;
+    cdpContext.cdpInfo.silentRecoveryAttempt = true;
+    cdpContext.cdpInfo.usesMultipleIcsc = true;
+
+    cdpContext.authInfo = [[OTEscrowAuthenticationInformation alloc] init];
+    cdpContext.authInfo.authenticationAppleid = appleID;
+    cdpContext.authInfo.authenticationPassword = fetch_pet(appleID, nil);
+
+
+    NSArray<OTEscrowRecord*>* records = [OTClique fetchEscrowRecords:data error:&error];
+    if (records == nil || error != nil) {
+        printf("Failed to fetch escrow records.\n");
+        ret = -1;
+    }
+    OTClique* clique = [OTClique performSilentEscrowRecovery:data cdpContext:cdpContext allRecords:records error:&error];
+    if (clique != nil && error == nil) {
+        printf("Successfully performed escrow recovery.\n");
+        ret = 0;
+    } else {
+        fprintf(stderr, "Escrow recovery failed: %s\n", error.description.UTF8String);
+    }
+    return ret;
+#else
+    printf("Unimplemented.\n");
+    return -1;
+#endif
+}
+
+
+- (long)status:(NSString * _Nullable)container context:(NSString *)contextID json:(bool)json {
 #if OCTAGON
     __block long ret = 0;
 
@@ -330,10 +482,10 @@ static void print_json(NSDictionary* dict)
                                NSDictionary* contextDump = result[@"contextDump"];
 
                                // Make it easy to find peer information
-                               NSMutableDictionary<NSString*, NSDictionary*>* peers = [NSMutableDictionary dictionary];
-                               NSMutableArray<NSString*>* allPeerIDs = [NSMutableArray array];
+                               NSMutableDictionary<NSString *, NSDictionary*>* peers = [NSMutableDictionary dictionary];
+                               NSMutableArray<NSString *>* allPeerIDs = [NSMutableArray array];
                                for(NSDictionary* peerInformation in contextDump[@"peers"]) {
-                                   NSString* peerID = peerInformation[@"peerID"];
+                                   NSString * peerID = peerInformation[@"peerID"];
                                    if(peerID) {
                                        peers[peerID] = peerInformation;
                                        [allPeerIDs addObject:peerID];
@@ -341,7 +493,7 @@ static void print_json(NSDictionary* dict)
                                }
 
                                NSDictionary* egoInformation = contextDump[@"self"];
-                               NSString* egoPeerID = egoInformation[@"peerID"];
+                               NSString * egoPeerID = egoInformation[@"peerID"];
                                NSDictionary* egoDynamicInfo = egoInformation[@"dynamicInfo"];
 
                                if(egoPeerID) {
@@ -352,7 +504,7 @@ static void print_json(NSDictionary* dict)
                                    // The self peer is technically a peer, so, shove it on in there
                                    peers[egoPeerID] = egoInformation;
 
-                                   NSArray<NSString*>* includedPeers = egoDynamicInfo[@"included"];
+                                   NSArray<NSString *>* includedPeers = egoDynamicInfo[@"included"];
                                    printf("Trusted peers (by me):\n");
                                    if(includedPeers && includedPeers.count > 0) {
                                        [self printPeers:includedPeers egoPeerID:egoPeerID informationOnPeers:peers];
@@ -362,7 +514,7 @@ static void print_json(NSDictionary* dict)
                                    }
                                    printf("\n");
 
-                                   NSArray<NSString*>* excludedPeers = egoDynamicInfo[@"excluded"];
+                                   NSArray<NSString *>* excludedPeers = egoDynamicInfo[@"excluded"];
                                    printf("Excluded peers (by me):\n");
                                    if(excludedPeers && excludedPeers.count > 0) {
                                        [self printPeers:excludedPeers egoPeerID:egoPeerID informationOnPeers:peers];
@@ -403,11 +555,11 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)recoverUsingBottleID:(NSString*)bottleID
+- (long)recoverUsingBottleID:(NSString *)bottleID
                      entropy:(NSData*)entropy
-                     altDSID:(NSString*)altDSID
-               containerName:(NSString*)containerName
-                     context:(NSString*)context
+                     altDSID:(NSString *)altDSID
+               containerName:(NSString *)containerName
+                     context:(NSString *)context
                      control:(OTControl*)control {
     __block long ret = 0;
 
@@ -441,24 +593,24 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)fetchAllBottles:(NSString*)altDSID
-          containerName:(NSString*)containerName
-                context:(NSString*)context
+- (long)fetchAllBottles:(NSString *)altDSID
+          containerName:(NSString *)containerName
+                context:(NSString *)context
                 control:(OTControl*)control {
     __block long ret = 0;
 
 #if OCTAGON
     __block NSError* localError = nil;
 
-    __block NSArray<NSString*>* localViableBottleIDs = nil;
-    __block NSArray<NSString*>* localPartiallyViableBottleIDs = nil;
+    __block NSArray<NSString *>* localViableBottleIDs = nil;
+    __block NSArray<NSString *>* localPartiallyViableBottleIDs = nil;
 
     dispatch_semaphore_t sema = dispatch_semaphore_create(0);
 
     [control fetchAllViableBottles:containerName
                            context:context
-                             reply:^(NSArray<NSString*>* _Nullable sortedBottleIDs,
-                                     NSArray<NSString*>* _Nullable sortedPartialBottleIDs,
+                             reply:^(NSArray<NSString *>* _Nullable sortedBottleIDs,
+                                     NSArray<NSString *>* _Nullable sortedPartialBottleIDs,
                                      NSError* _Nullable controlError) {
                                  if(controlError) {
                                      secnotice("clique", "findOptimalBottleIDsWithContextData errored: %@\n", controlError);
@@ -476,11 +628,11 @@ static void print_json(NSDictionary* dict)
         return -1;
     }
 
-    [localViableBottleIDs enumerateObjectsUsingBlock:^(NSString* obj, NSUInteger idx, BOOL* stop) {
+    [localViableBottleIDs enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL* stop) {
         printf("preferred bottleID: %s\n", [obj UTF8String]);
     }];
 
-    [localPartiallyViableBottleIDs enumerateObjectsUsingBlock:^(NSString* obj, NSUInteger idx, BOOL* stop) {
+    [localPartiallyViableBottleIDs enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL* stop) {
         printf("partial recovery bottleID: %s\n", [obj UTF8String]);
     }];
 
@@ -491,7 +643,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)healthCheck:(NSString* _Nullable)container context:(NSString*)contextID skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
+- (long)healthCheck:(NSString * _Nullable)container context:(NSString *)contextID skipRateLimitingCheck:(BOOL)skipRateLimitingCheck
 {
 #if OCTAGON
     __block long ret = -1;
@@ -514,7 +666,7 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
-- (long)refetchCKKSPolicy:(NSString*)container context:(NSString*)contextID
+- (long)refetchCKKSPolicy:(NSString *)container context:(NSString *)contextID
 {
     #if OCTAGON
         __block long ret = 1;
@@ -559,4 +711,53 @@ static void print_json(NSDictionary* dict)
 #endif
 }
 
+- (long)setUserControllableViewsSyncStatus:(NSString * _Nullable)containerName
+                                 contextID:(NSString *)contextID
+                                   enabled:(BOOL)enabled
+{
+    #if OCTAGON
+        __block long ret = 1;
+
+        [self.control setUserControllableViewsSyncStatus:containerName
+                                               contextID:contextID
+                                                 enabled:enabled
+                                                   reply:^(BOOL nowSyncing, NSError * _Nullable error) {
+            if(error) {
+                printf("Error setting user controllable views: %s\n", [[error description] UTF8String]);
+            } else {
+                printf("User controllable views are now %s.", [(nowSyncing ? @"enabled" : @"paused") UTF8String]);
+                ret = 0;
+            }
+        }];
+        return ret;
+    #else
+        printf("Unimplemented.\n");
+        return 1;
+    #endif
+}
+
+- (long)fetchUserControllableViewsSyncStatus:(NSString * _Nullable)containerName
+                                   contextID:(NSString *)contextID
+{
+    #if OCTAGON
+        __block long ret = 1;
+
+        [self.control fetchUserControllableViewsSyncStatus:containerName
+                                                 contextID:contextID
+                                                     reply:^(BOOL nowSyncing, NSError * _Nullable error) {
+            if(error) {
+                printf("Error setting user controllable views: %s\n", [[error description] UTF8String]);
+            } else {
+                printf("User controllable views are currently %s.", [(nowSyncing ? @"enabled" : @"paused") UTF8String]);
+                ret = 0;
+            }
+        }];
+        return ret;
+    #else
+        printf("Unimplemented.\n");
+        return 1;
+    #endif
+}
+
+
 @end
index dd0cb2cb9bfab04957429028acd8a17bffaefff6..3086aa6633d0bb8d3f6d4fa4e4697b8857773a33 100644 (file)
@@ -7,6 +7,7 @@
 #import <Security/SecInternalReleasePriv.h>
 #import <Security/Security.h>
 #import <err.h>
+#import <OctagonTrust/OctagonTrust.h>
 
 #import "keychain/otctl/OTControlCLI.h"
 #import "keychain/otctl/EscrowRequestCLI.h"
@@ -23,6 +24,7 @@ static int signIn = false;
 static int signOut = false;
 static int resetoctagon = false;
 static int resetProtectedData = false;
+static int userControllableViewsSyncStatus = false;
 
 static int fetchAllBottles = false;
 static int recover = false;
@@ -38,6 +40,12 @@ static int ckks_policy_flag = false;
 
 static int ttr_flag = false;
 
+static int fetch_escrow_records = false;
+static int fetch_all_escrow_records = false;
+
+static int recoverRecord = false;
+static int recoverSilentRecord = false;
+
 static int health = false;
 
 #if TARGET_OS_WATCH
@@ -48,6 +56,11 @@ static char* bottleIDArg = NULL;
 static char* contextNameArg = NULL;
 static char* secretArg = NULL;
 static char* skipRateLimitingCheckArg = NULL;
+static char* recordID = NULL;
+
+static int argEnable = false;
+static int argPause = false;
+
 static int json = false;
 
 static char* altDSIDArg = NULL;
@@ -71,6 +84,10 @@ int main(int argc, char** argv)
         {.shortname = 'e', .longname = "bottleID", .argument = &bottleIDArg, .description = "bottle record id"},
         {.shortname = 'r', .longname = "skipRateLimiting", .argument = &skipRateLimitingCheckArg, .description = " enter values YES or NO, option defaults to NO, This gives you the opportunity to skip the rate limiting check when performing the cuttlefish health check"},
         {.shortname = 'j', .longname = "json", .flag = &json, .flagval = true, .description = "Output in JSON"},
+        {.shortname = 'i', .longname = "recordID", .argument = &recordID, .flagval = true, .description = "recordID"},
+
+        {.shortname = 'E', .longname = "enable", .flag = &argEnable, .flagval = true, .description = "Enable something (pair with a modification command)"},
+        {.shortname = 'P', .longname = "pause", .flag = &argPause, .flagval = true, .description = "Pause something (pair with a modification command)"},
 
         {.longname = "altDSID", .argument = &altDSIDArg, .description = "altDSID (for sign-in/out)"},
         {.longname = "entropy", .argument = &secretArg, .description = "escrowed entropy in JSON"},
@@ -89,6 +106,8 @@ int main(int argc, char** argv)
         {.command = "resetoctagon", .flag = &resetoctagon, .flagval = true, .description = "Reset and establish new Octagon trust"},
         {.command = "resetProtectedData", .flag = &resetProtectedData, .flagval = true, .description = "Reset ProtectedData"},
 
+        {.command = "user-controllable-views", .flag = &userControllableViewsSyncStatus, .flagval = true, .description = "Modify or view user-controllable views status (If one of --enable or --pause is passed, will modify status)"},
+
         {.command = "allBottles", .flag = &fetchAllBottles, .flagval = true, .description = "Fetch all viable bottles"},
         {.command = "recover", .flag = &recover, .flagval = true, .description = "Recover using this bottle"},
         {.command = "depart", .flag = &depart, .flagval = true, .description = "Depart from Octagon Trust"},
@@ -103,6 +122,13 @@ int main(int argc, char** argv)
 
         {.command = "taptoradar", .flag = &ttr_flag, .flagval = true, .description = "Trigger a TapToRadar"},
 
+        {.command = "fetchEscrowRecords", .flag = &fetch_escrow_records, .flagval = true, .description = "Fetch Escrow Records"},
+        {.command = "fetchAllEscrowRecords", .flag = &fetch_all_escrow_records, .flagval = true, .description = "Fetch All Escrow Records"},
+
+        {.command = "recover-record", .flag = &recoverRecord, .flagval = true, .description = "Recover record"},
+        {.command = "recover-record-silent", .flag = &recoverSilentRecord, .flagval = true, .description = "Silent record recovery"},
+
+
 
 #if TARGET_OS_WATCH
         {.command = "pairme", .flag = &pairme, .flagval = true, .description = "Perform pairing (watchOS only)"},
@@ -154,6 +180,22 @@ int main(int argc, char** argv)
             long ret = [ctl resetProtectedData:container context:context altDSID:altDSID appleID:appleID dsid:dsid];
             return (int)ret;
         }
+        if(userControllableViewsSyncStatus) {
+            internalOnly();
+
+            if(argEnable && argPause) {
+                print_usage(&args);
+                return -1;
+            }
+
+            if(argEnable == false && argPause == false) {
+                return (int)[ctl fetchUserControllableViewsSyncStatus:container contextID:context];
+            }
+
+            // At this point, we're sure that either argEnabled or argPause is set; so the value of argEnabled captures the user's intention
+            return (int)[ctl setUserControllableViewsSyncStatus:container contextID:context enabled:argEnable];
+        }
+
         if(fetchAllBottles) {
             return (int)[ctl fetchAllBottles:altDSID containerName:container context:context control:rpc];
         }
@@ -198,7 +240,33 @@ int main(int argc, char** argv)
         if(status) {
             return (int)[ctl status:container context:context json:json];
         }
+        if(fetch_escrow_records) {
+            return (int)[ctl fetchEscrowRecords:container context:context];
+        }
+        if(fetch_all_escrow_records) {
+            return (int)[ctl fetchAllEscrowRecords:container context:context];
+        }
+        if(recoverRecord) {
+            NSString* recordIDString = recordID ? [NSString stringWithCString:recordID encoding:NSUTF8StringEncoding] : nil;
+            NSString* secret = secretArg ? [NSString stringWithCString:secretArg encoding:NSUTF8StringEncoding] : nil;
+
+            if(!recordIDString || !secret || !appleID) {
+                print_usage(&args);
+                return -1;
+            }
+
+            return (int)[ctl performEscrowRecovery:container context:context recordID:recordIDString appleID:appleID secret:secret];
+        }
+        if(recoverSilentRecord){
+            NSString* secret = secretArg ? [NSString stringWithCString:secretArg encoding:NSUTF8StringEncoding] : nil;
+
+            if(!secret || !appleID) {
+                print_usage(&args);
+                return -1;
+            }
 
+            return (int)[ctl performSilentEscrowRecovery:container context:context appleID:appleID secret:secret];
+        }
         if(health) {
             BOOL skip = NO;
             if([skipRateLimitingCheck isEqualToString:@"YES"]) {
index 309ee32a0cbe2d0c63c28d10a466b37419edae28..71f20133dc5474b4ea51ad1b654db3aa04553995 100644 (file)
@@ -3,10 +3,9 @@
 #define OTPairingIDSServiceName     @"com.apple.private.alloy.octagon"
 
 #define OTPairingIDSKeyMessageType  @"m"
-#define OTPairingIDSKeyError        @"e"
 #define OTPairingIDSKeySession      @"session"
 #define OTPairingIDSKeyPacket       @"packet"
-#define OTPairingIDSKeyErrorDeprecated  @"error"
+#define OTPairingIDSKeyErrorDescription @"error"
 
 enum OTPairingIDSMessageType {
     OTPairingIDSMessageTypePacket = 1,
index 7fbbef9ab5545b00402f534e643f648d53046754..e8854f26fd8c803cf780899fafaa044b59285616 100644 (file)
@@ -1,7 +1,6 @@
 #import <TargetConditionals.h>
 #import <Foundation/Foundation.h>
 #import <IDS/IDS.h>
-#import <Security/SecXPCHelper.h>
 
 #import "keychain/categories/NSError+UsefulConstructors.h"
 
@@ -23,8 +22,7 @@
 
 - (instancetype)initWithMessage:(NSDictionary *)message fromID:(NSString *)fromID context:(IDSMessageContext *)context
 {
-    self = [super init];
-    if (self != nil) {
+    if ((self = [super init])) {
         self.message = message;
         self.fromID = fromID;
         self.context = context;
     }
 
     if (!self->_error) {
-        NSData *errorData = self.message[OTPairingIDSKeyError];
-        if (errorData != NULL) {
-            self->_error = [SecXPCHelper errorFromEncodedData:errorData];
-        } else {
-            // Key from older iOS builds; remove soon
-            // When this is removed, it will still be useful to have a fallback in case errorData is missing or errorFromEncodedData fails
-            NSString *errorString = self.message[OTPairingIDSKeyErrorDeprecated];
-            self->_error = [NSError errorWithDomain:OTPairingErrorDomain code:OTPairingErrorTypeRemote description:errorString];
-        }
+        NSString *errorString = self.message[OTPairingIDSKeyErrorDescription];
+        self->_error = [NSError errorWithDomain:OTPairingErrorDomain code:OTPairingErrorTypeRemote description:errorString];
     }
 
     return self->_error;
index c1b70852b72c875b5249b67f14fd415c67b888e7..826230c08a2ed0af6f53f0c62b1d5d00728b1b0d 100644 (file)
@@ -3,7 +3,6 @@
 #import <IDS/IDS.h>
 #import <KeychainCircle/KeychainCircle.h>
 #import <os/assumes.h>
-#import <Security/SecXPCHelper.h>
 #import <xpc/private.h>
 
 #if TARGET_OS_WATCH
@@ -49,8 +48,7 @@
 
 - (instancetype)init
 {
-    self = [super init];
-    if (self != nil) {
+    if ((self = [super init])) {
         self.queue = dispatch_queue_create("com.apple.security.otpaird", DISPATCH_QUEUE_SERIAL);
         self.service = [[IDSService alloc] initWithService:OTPairingIDSServiceName];
         [self.service addDelegate:self queue:self.queue];
     NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
     message[OTPairingIDSKeyMessageType] = @(OTPairingIDSMessageTypeError);
     message[OTPairingIDSKeySession] = self.session.identifier;
-    message[OTPairingIDSKeyError] = [SecXPCHelper encodedDataFromError:unlockError];
-    message[OTPairingIDSKeyErrorDeprecated] = unlockError.localizedDescription; // For older watchOS builds; remove soon
+    message[OTPairingIDSKeyErrorDescription] = unlockError.description;
     NSString *toID = packet.fromID;
     NSString *responseIdentifier = packet.outgoingResponseIdentifier;
     [self _sendMessage:message to:toID identifier:responseIdentifier];
 
             if (channelError != nil) {
 #if TARGET_OS_IOS
-                NSError *cleansedError = [SecXPCHelper cleanseErrorForXPC:channelError];
                 NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
                 message[OTPairingIDSKeyMessageType] = @(OTPairingIDSMessageTypeError);
                 message[OTPairingIDSKeySession] = self.session.identifier;
-                message[OTPairingIDSKeyError] = cleansedError ? [SecXPCHelper encodedDataFromError:cleansedError] : nil;
-                message[OTPairingIDSKeyErrorDeprecated] = channelError.description;
+                message[OTPairingIDSKeyErrorDescription] = channelError.description;
                 os_assert(packet != nil); // the acceptor always responds to a request packet, it's never initiating
                 toID = packet.fromID;
                 responseIdentifier = packet.outgoingResponseIdentifier;
                                 identifier:&identifier
                                      error:&error];
     if (sendResult) {
-        self.session.sentMessageIdentifier = identifier;
+        /* sentMessageIdentifier is used to validate the next reply; do not set if no reply is expected. */
+        if (expectReply) {
+            self.session.sentMessageIdentifier = identifier;
+        }
     } else {
         os_log(OS_LOG_DEFAULT, "send message failed (%@): %@", identifier, error);
         // On iOS, do nothing; watch will time out waiting for response.
index 9444f1ca481d9e6e4186ce99c24e80ac5b8ebfc6..3d4cf5792bcc27645a05f277d4f6607ee952722e 100644 (file)
@@ -22,8 +22,7 @@
 {
     KCPairingChannelContext *channelContext = nil;
 
-    self = [super init];
-    if (self != nil) {
+    if ((self = [super init])) {
         self.identifier = identifier;
 
         channelContext = [KCPairingChannelContext new];
index 687c9a259c4897c5d84dd8cb1754a98a2447bea6..55994f0347dab1db4ddbf4484da93925ba69ae4b 100644 (file)
        </array>
        <key>com.apple.private.octagon</key>
        <true/>
-       <key>com.apple.security.exception.files.absolute-path.read-only</key>
-       <array>
-               <string>/usr/libexec</string>
-       </array>
-       <key>com.apple.security.exception.iokit-user-client-class</key>
-       <array>
-               <string>AppleKeyStoreUserClient</string>
-       </array>
-       <key>com.apple.security.exception.mach-lookup.global-name</key>
-       <array>
-               <string>com.apple.security.octagon</string>
-               <string>com.apple.securityd.sos</string>
-       </array>
-       <key>com.apple.security.ts.identity-services-client</key>
-       <true/>
        <key>keychain-cloud-circle</key>
        <true/>
        <key>platform-application</key>
        <true/>
        <key>seatbelt-profiles</key>
        <array>
-               <string>temporary-sandbox</string>
+               <string>otpaird</string>
        </array>
 </dict>
 </plist>
index 32082d1c1c0765e4ce1133f98dfa393fd7aedd10..4749b51b2fe00a04642d5edcbaf2e1592f54df68 100644 (file)
        </array>
        <key>com.apple.private.octagon</key>
        <true/>
-       <key>com.apple.security.exception.files.absolute-path.read-only</key>
-       <array>
-               <string>/usr/libexec</string>
-       </array>
-       <key>com.apple.security.exception.iokit-user-client-class</key>
-       <array>
-               <string>AppleKeyStoreUserClient</string>
-       </array>
-       <key>com.apple.security.exception.mach-lookup.global-name</key>
-       <array>
-               <string>com.apple.security.octagon</string>
-       </array>
-       <key>com.apple.security.ts.identity-services-client</key>
-       <true/>
        <key>platform-application</key>
        <true/>
        <key>seatbelt-profiles</key>
        <array>
-               <string>temporary-sandbox</string>
+               <string>otpaird</string>
        </array>
 </dict>
 </plist>
index c5b42c661a6dec7518931a64d4caf6c61e4e1fe9..69aecb432ad628c7346147dbadf3208d209a7d59 100644 (file)
@@ -172,6 +172,13 @@ static void oneReport(void) {
         NSLog(@"policy is nil");
         return;
     }
+    TPSyncingPolicy* syncingPolicy = [policy syncingPolicyForModel:@"iPhone"
+                                         syncUserControllableViews:TPPBPeerStableInfo_UserControllableViewStatus_UNKNOWN
+                                                             error:&error];
+    if(syncingPolicy == nil || error != nil) {
+        NSLog(@"syncing policy is nil: %@", error);
+        return;
+    }
 
     unsigned real_mismatches = 0;
     unsigned expected_mismatches = 0;
@@ -219,7 +226,7 @@ static void oneReport(void) {
             NSMutableDictionary* mutA = [a mutableCopy];
             mutA[(id)kSecClass] = (id)itemClass;
 
-            NSString* newView = [policy mapKeyToView:mutA];
+            NSString* newView = [syncingPolicy mapDictionaryToView:mutA];
             if (newView != nil) {
                 NSLog(@"new: %@", newView);
             }
index d3f6fd16ed955a302853a82395ca1c75dae012c6..413b75cb37cdc4af2de446b13f760cfd080bbfc7 100644 (file)
@@ -62,7 +62,7 @@ static inline bool SOSAccountJoinCirclesAfterRestore_wTxn(SOSAccount* acct, CFEr
 {
     __block bool result = false;
     [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
-        result = SOSAccountJoinCirclesAfterRestore(txn, nil, error);
+        result = SOSAccountJoinCirclesAfterRestore(txn, error);
     }];
     return result;
 }
@@ -71,7 +71,7 @@ static inline bool SOSAccountJoinCircles_wTxn(SOSAccount* acct, CFErrorRef* erro
 {
     __block bool result = false;
     [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
-        result = SOSAccountJoinCircles(txn, nil, error);
+        result = SOSAccountJoinCircles(txn, error);
     }];
     return result;
 }
index e354c55f5837a5135e5bef322a6535e09edce50e..24b0050f44335d3f413b424e37a136f8c9da9152 100644 (file)
@@ -29,8 +29,7 @@ CFMutableArrayRef message_transports = NULL;
 
 -(id) initWithAccount:(SOSAccount*) acct andName:(CFStringRef) n andCircleName:(CFStringRef) cN
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.name = CFRetainSafe(n);
         self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
         self.account = acct;
@@ -142,8 +141,7 @@ void SOSTransportCircleTestClearChanges(SOSCircleStorageTransportTest* transport
 
 -(id) initWithAccount:(SOSAccount *)acct andWithAccountName:(CFStringRef)acctName andCircleName:(CFStringRef)cName
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.account = acct;
         self.accountName = (__bridge NSString *)(acctName);
         self.circleName = (__bridge NSString*)cName;
@@ -313,8 +311,7 @@ SOSAccount* SOSTransportCircleTestGetAccount(SOSCircleStorageTransportTest* tran
 
 -(id) initWithAccount:(SOSAccount*)acct andName:(CFStringRef)n andCircleName:(CFStringRef) cN
 {
-    self = [super init];
-    if(self){
+    if ((self = [super init])) {
         self.engine = SOSDataSourceFactoryGetEngineForDataSourceName(acct.factory, cN, NULL);
         self.account = acct;
         self.changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
@@ -513,12 +510,12 @@ void SOSAccountUpdateTestTransports(SOSAccount* account, CFDictionaryRef gestalt
     SOSTransportMessageKVSTestSetName((SOSMessageKVSTest*)account.kvs_message_transport, new_name);
 }
 
-static CF_RETURNS_RETAINED SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a, CFStringRef name, CFStringRef accountName)
+static CF_RETURNS_RETAINED SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* account, CFStringRef name, CFStringRef accountName)
 {
     CFErrorRef localError = NULL;
-    SOSAccountTrustClassic *trust = a.trust;
+    SOSAccountTrustClassic *trust = account.trust;
 
-    SOSCircleRef circle = CFRetainSafe([a.trust getCircle:&localError]);
+    SOSCircleRef circle = CFRetainSafe([account.trust getCircle:&localError]);
     if(!circle || isSOSErrorCoded(localError, kSOSErrorIncompatibleCircle)){
         secnotice("circle", "Error retrieving the circle: %@", localError);
         CFReleaseNull(localError);
@@ -534,7 +531,7 @@ static CF_RETURNS_RETAINED SOSCircleRef SOSAccountEnsureCircleTest(SOSAccount* a
         CFReleaseNull(localError);
     }
 
-    if(![trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(a.gestalt) deviceID:(__bridge CFStringRef)(a.deviceID) backupKey:(__bridge CFDataRef)(a.backup_key) err:&localError])
+    if(![trust ensureFullPeerAvailable:account err:&localError])
     {
         secnotice("circle", "had an error building full peer: %@", localError);
         CFReleaseNull(localError);
index b570064992997d414d22b9582887fd509c89789b..b239deb7fe4fb39739b89a84331e5116858b064a 100644 (file)
@@ -42,6 +42,7 @@ void secd_test_setup_temp_keychain(const char* test_prefix, dispatch_block_t do_
 {
     CFStringRef tmp_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/tmp/%s.%X/"), test_prefix, arc4random());
     CFStringRef keychain_dir = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@Library/Keychains"), tmp_dir);
+    secnotice("secdtest", "Keychain path: %@", keychain_dir);
     
     CFStringPerformWithCString(keychain_dir, ^(const char *keychain_dir_string) {
         errno_t err = mkpath_np(keychain_dir_string, 0755);
index b23910980af23afe71b2be431f8d34203242a1d3..fb62c13a1786a2b88f10a2ae97b5be36095cd073 100644 (file)
@@ -51,6 +51,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -150,14 +151,16 @@ static void tests(void)
 
     SOSTestCleanup();
 }
+#endif
 
 int secd_100_initialsync(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(33);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 8fe1cb2c06cf002aa4facb0529c0afd87c97f736..b2ba0f57224d77d05558016a998182691bf0ad9d 100644 (file)
@@ -20,6 +20,7 @@
 #include "SOSAccountTesting.h"
 
 #include "keychain/SecureObjectSync/SOSAccount.h"
+#if SOS_ENABLED
 
 #define kAccountPasswordString ((uint8_t*) "FooFooFoo")
 #define kAccountPasswordStringLen 10
@@ -165,14 +166,17 @@ static void tests(void) {
 
     SOSTestCleanup();
 }
+#endif
 
 int secd_130_other_peer_views(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(72);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     secd_test_clear_testviews();
     tests();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index e75660d47a8e196cee9c4f63b5ed34e36de0d0da..78010ff5d4bfbc37056d3e373844ee24ee05a8d3 100644 (file)
@@ -28,6 +28,9 @@
 #include "SOSTestDataSource.h"
 
 #include "SOSRegressionUtilities.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 static int kTestTestCount = 10;
 static int MAX_PENALTY_TIME = 32;
@@ -268,12 +271,15 @@ static void tests(void)
     ok(successful_writes == 12, "successfull writes should have only reached 10");
     ok(monitor->penalty_box == 0, "penalty box should reset back to 0");
 }
+#endif
 
 int secd_154_engine_backoff(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 446afdcec4ae68f5436dc0c10f0837ee797d3492..69419ef49a9c6c5378f27fc6a604fe7156a13371 100644 (file)
@@ -38,6 +38,7 @@
 #include "SOSTestDevice.h"
 #include "SOSTestDataSource.h"
 #include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
+#if SOS_ENABLED
 
 
 static void tests(void)
@@ -158,14 +159,16 @@ static void tests(void)
 
    // ids_test_sync(alice_account, bob_account);
 }
+#endif
 
 int secd_155_otr_negotiation_monitor(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(44);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 55d926f93e537ac0cbdfd2e9e9f0c35d8fdec416..9bd5ceff9605489bb0354060de7e658cbbc3cbd2 100644 (file)
@@ -56,6 +56,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 #define HOW_MANY_MINIONS 4
 
@@ -223,14 +224,16 @@ static void tests(void)
     SOSTestCleanup();
     
 }
+#endif
 
 int secd_200_logstate(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(((HOW_MANY_MINIONS+1)*10 + 1));
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index d851ca17ac889efd0e8188973cc9d7506d539d48..d4f26ce6f339ade421853cc4d73c52b5616437cf 100644 (file)
@@ -58,6 +58,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -164,14 +165,16 @@ static void tests(void)
 
     CFReleaseNull(changes);
 }
+#endif
 
 int secd_201_coders(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(38);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index e00d57af24f6a506f47c82a291964a5bf5cd872e..0d60804ad8cbe646a84c5d6287a32b9fc1895717 100644 (file)
@@ -22,6 +22,9 @@
 #import <utilities/SecCFWrappers.h>
 
 #import "SecdTestKeychainUtilities.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 
 const int kTestRecoveryKeyCount = 3;
@@ -52,16 +55,17 @@ static void testRecoveryKeyBasic(void)
     }
 }
 
+#endif
 
 int secd_202_recoverykey(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestRecoveryKeyCount + kTestRecoveryKeyBasicCount);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     testRecoveryKeyBasic();
-
     testRecoveryKey();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 82e7c890600674dbe591549fd9ede35baa83fab8..13d14f80c3e9b14ab2d788cc63d9ce19b8caf82c 100644 (file)
 #import "CKDSimulatedStore.h"
 #import "CKDSimulatedAccount.h"
 #import "CKDAKSLockMonitor.h"
-
 #include "SOSCloudKeychainConstants.h"
+#include "SOSAccountTesting.h"
+
+
+#if SOS_ENABLED
 
 @interface CKDSimulatedLockMonitor : NSObject<CKDLockMonitor>
 
@@ -47,8 +50,7 @@
 }
 
 - (instancetype) init {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         _locked = true;
         _unlockedSinceBoot = false;
     }
@@ -189,12 +191,15 @@ static void tests(void) {
 
 }
 
+#endif
 
 int secd_210_keyinterest(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(12);
-
     tests();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 4aa765e04494dac3a54abb3007f82e5e5a49ca64..3a2573fde82e56af6a35b0edc29ba6a60969154c 100644 (file)
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFError.h>
 #include <utilities/SecCFRelease.h>
+#include <utilities/der_plist.h>
 #include <Security/SecBase64.h>
 
+#include <os/feature_private.h>
+
 #include <libaks_acl_cf_keys.h>
 
 #include <ctkclient/ctkclient_test.h>
@@ -216,7 +219,7 @@ static void test_item_query() {
                                                                (id)kSecReturnPersistentRef : @YES }, &result));
     is(phase, 0);
     NSData *persistentRef = (__bridge NSData *)result;
-    is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo);
+    is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
     CFReleaseSafe(result);
 
     phase = 0;
@@ -226,7 +229,7 @@ static void test_item_query() {
                                                                (id)kSecReturnPersistentRef : @YES }, &result));
     is(phase, 2);
     persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
-    is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo);
+    is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
     CFReleaseSafe(result);
 
     phase = 0;
@@ -236,7 +239,7 @@ static void test_item_query() {
                                                                (id)kSecReturnPersistentRef : @YES }, &result));
     is(phase, 0);
     persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
-    is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo);
+    is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
     CFReleaseSafe(result);
 
     phase = 0;
@@ -247,7 +250,7 @@ static void test_item_query() {
                                                                (id)kSecReturnPersistentRef : @YES }, &result));
     is(phase, 2);
     persistentRef = ((__bridge NSDictionary *)result)[(id)kSecValuePersistentRef];
-    is(CFDataCompare((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), kCFCompareEqualTo);
+    is(CFEqual((__bridge CFDataRef)persistentRefId, (__bridge CFDataRef)[persistentRef subdataWithRange:NSMakeRange(0, 4)]), TRUE);
     CFReleaseSafe(result);
 
     CFRelease(query);
@@ -775,37 +778,44 @@ static CFMutableDictionaryRef copy_certificate_attributes(const char *base64Cert
     return result;
 }
 
-static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFStringRef oid, CFStringRef tokenID)
+static CFDictionaryRef copy_certificate_query(const char *base64cert, CFStringRef label, CFDataRef oid, CFStringRef tokenID)
 {
     CFMutableDictionaryRef certAttributes = copy_certificate_attributes(base64cert);
 
     CFDictionarySetValue(certAttributes, kSecAttrLabel, label);
     CFDictionarySetValue(certAttributes, kSecAttrAccessible, kSecAttrAccessibleAlwaysPrivate);
-    CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid);
+    if (oid != NULL) {
+        CFDictionarySetValue(certAttributes, kSecAttrTokenOID, oid);
+    }
     CFDictionaryRemoveValue(certAttributes, kSecValueData);
 
-    SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
-    ok(acl);
-    CFTypeRef key[] = { kSecAttrTokenID };
-    CFTypeRef value[] = { tokenID };
-    CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    ok(SecAccessControlSetProtection(acl, protection, NULL));
-    CFRelease(protection);
-    ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
-    CFDataRef aclData = SecAccessControlCopyData(acl);
-    ok(aclData);
-    if (aclData) {
-        CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData);
-        CFRelease(aclData);
-    }
+    if (tokenID != NULL) {
+        SecAccessControlRef acl = SecAccessControlCreate(kCFAllocatorDefault, NULL);
+        ok(acl);
+        CFTypeRef key[] = { kSecAttrTokenID };
+        CFTypeRef value[] = { tokenID };
+        CFDictionaryRef protection = CFDictionaryCreate(kCFAllocatorDefault, key, value, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+        ok(SecAccessControlSetProtection(acl, protection, NULL));
+        CFRelease(protection);
+        ok(SecAccessControlAddConstraintForOperation(acl, kAKSKeyOpDefaultAcl, kCFBooleanTrue, NULL));
+        CFDataRef aclData = SecAccessControlCopyData(acl);
+        ok(aclData);
+        if (aclData) {
+            CFDictionarySetValue(certAttributes, kSecAttrAccessControl, aclData);
+            CFRelease(aclData);
+        }
 
-    if (acl)
-        CFRelease(acl);
+        if (acl)
+            CFRelease(acl);
+    } else {
+        NSData *certData = CFBridgingRelease(copy_certificate_data(base64cert));
+        CFDictionarySetValue(certAttributes, kSecValueData, (__bridge CFDataRef)certData);
+    }
 
     return certAttributes;
 }
 
-static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFStringRef oid, CFStringRef tokenID)
+static CFDictionaryRef copy_key_query(CFDictionaryRef certAttributes, CFStringRef label, CFDataRef oid, CFStringRef tokenID)
 {
     CFMutableDictionaryRef keyAttributes = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) ;
 
@@ -859,20 +869,25 @@ static void check_array_for_type_id(CFArrayRef array, CFTypeID typeID)
 
 static void test_propagate_token_items()
 {
-    CFStringRef cert1OID = CFSTR("oid1");
-    CFStringRef cert2OID = CFSTR("oid2");
-    CFStringRef key1OID = CFSTR("oid3");
-    CFStringRef key2OID = CFSTR("oid4");
+    if (!os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        // This test does not work if tokens cannot be used by keychain.
+        return;
+    }
+
+    NSData *cert1OID = [@"oid1" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData *cert2OID = [@"oid2" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData *key1OID = [@"oid3" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData *key2OID = [@"oid4" dataUsingEncoding:NSUTF8StringEncoding];
 
     TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
         blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
-            if (CFEqual(oid, cert1OID)) {
+            if (CFEqual(oid, (__bridge CFDataRef)cert1OID)) {
                 return copy_certificate_data(cert1);
             }
-            else if (CFEqual(oid, cert2OID)) {
+            else if (CFEqual(oid, (__bridge CFDataRef)cert2OID)) {
                 return copy_certificate_data(cert2);
             }
-            else if (CFEqual(oid, key1OID) || CFEqual(oid, key2OID)) {
+            else if (CFEqual(oid, (__bridge CFDataRef)key1OID) || CFEqual(oid, (__bridge CFDataRef)key2OID)) {
                 return kCFNull;
             }
             else {
@@ -885,9 +900,9 @@ static void test_propagate_token_items()
 
     CFMutableArrayRef items = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 
-    CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), cert1OID, tokenID);
+    CFDictionaryRef certQuery = copy_certificate_query(cert1, CFSTR("test_cert1"), (__bridge CFDataRef)cert1OID, tokenID);
     ok(certQuery);
-    CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), key1OID, tokenID);
+    CFDictionaryRef keyQuery = copy_key_query(certQuery, CFSTR("test_key1"), (__bridge CFDataRef)key1OID, tokenID);
     ok(keyQuery);
 
     CFArrayAppendValue(items, certQuery);
@@ -895,9 +910,9 @@ static void test_propagate_token_items()
     CFReleaseSafe(certQuery);
     CFReleaseSafe(keyQuery);
 
-    certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), cert2OID, tokenID);
+    certQuery = copy_certificate_query(cert2, CFSTR("test_cert2"), (__bridge CFDataRef)cert2OID, tokenID);
     ok(certQuery);
-    keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), key2OID, tokenID);
+    keyQuery = copy_key_query(certQuery, CFSTR("test_key2"), (__bridge CFDataRef)key2OID, tokenID);
     ok(keyQuery);
 
     CFArrayAppendValue(items, certQuery);
@@ -906,9 +921,9 @@ static void test_propagate_token_items()
     CFReleaseSafe(keyQuery);
 
     OSStatus result;
-    ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items.");
+    ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL), "Failed to delete items.");
 
-    ok_status(result = SecItemUpdateTokenItems(tokenID, items), "Failed to propagate items.");
+    ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], items), "Failed to propagate items.");
     CFRelease(items);
 
     CFMutableDictionaryRef query = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
@@ -957,7 +972,7 @@ static void test_propagate_token_items()
     ok(queryResult && CFGetTypeID(queryResult) == CFArrayGetTypeID() && CFArrayGetCount(queryResult) == 0, "Expect empty array");
     CFReleaseNull(queryResult);
 
-    ok_status(result = SecItemUpdateTokenItems(tokenID, NULL), "Failed to delete items.");
+    ok_status(result = SecItemUpdateTokenItemsForAccessGroups(tokenID, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL), "Failed to delete items.");
 
     CFDictionarySetValue(query, kSecReturnRef, kCFBooleanTrue);
     CFDictionarySetValue(query, kSecReturnData, kCFBooleanFalse);
@@ -967,17 +982,10 @@ static void test_propagate_token_items()
 }
 
 static void test_identity_on_two_tokens() {
-    CFStringRef cert3OID = CFSTR("oid1");
-    TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
-
-        blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
-            if (CFEqual(oid, cert3OID))
-                return copy_certificate_data(cert3);
-            else
-                return kCFNull;
-        };
-
-    });
+    if (!os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        // This test does not work if tokens cannot be used by keychains.
+        return;
+    }
 
     @autoreleasepool {
         NSString *tokenID1 = @"com.apple.secdtest:identity_test_token1";
@@ -989,6 +997,25 @@ static void test_identity_on_two_tokens() {
         id publicKey = CFBridgingRelease(SecKeyCopyPublicKey((__bridge SecKeyRef)privKey));
         NSData *pubKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash((__bridge SecKeyRef)publicKey));
 
+        NSData *cert3OID = [@"oid1" dataUsingEncoding:NSUTF8StringEncoding];
+        TKTokenTestSetHook(^(CFDictionaryRef attributes, TKTokenTestBlocks *blocks) {
+
+            blocks->copyObjectData = ^CFTypeRef(CFDataRef oid, CFErrorRef *error) {
+                if (CFEqual(oid, (__bridge CFDataRef)cert3OID))
+                    return copy_certificate_data(cert3);
+                else
+                    return kCFNull;
+            };
+
+            blocks->copyPublicKeyData = ^CFDataRef(CFDataRef oid, CFErrorRef *error) {
+                if ([privKeyData isEqualToData:(__bridge NSData *)oid]) {
+                    return SecKeyCopyExternalRepresentation((SecKeyRef)publicKey, error);
+                }
+                return NULL;
+            };
+
+        });
+
         id ac = CFBridgingRelease(SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlocked, 0, NULL));
         id acData = CFBridgingRelease(SecAccessControlCopyData((__bridge SecAccessControlRef)ac));
         NSDictionary *keyQuery = @{ (id)kSecClass: (id)kSecClassKey,
@@ -1002,15 +1029,15 @@ static void test_identity_on_two_tokens() {
                                     (id)kSecAttrApplicationLabel : pubKeyHash,
                                    };
         OSStatus result;
-        ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[keyQuery]), "Failed to propagate key item.");
+        ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)@[keyQuery]), "Failed to propagate key item.");
 
         id privateKey;
         ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)@{(id)kSecClass: (id)kSecClassKey, (id)kSecAttrTokenID: tokenID1, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, (id)kSecReturnRef: @YES}, (void *)&privateKey));
 
-        NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), cert3OID, (__bridge CFStringRef)tokenID2));
+        NSDictionary *certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("test_cert3"), (__bridge CFDataRef)cert3OID, (__bridge CFStringRef)tokenID2));
         ok(certQuery);
 
-        ok_status(result = SecItemUpdateTokenItems((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[certQuery]), "Failed to propagate cert item.");
+        ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)@[certQuery]), "Failed to propagate cert item.");
 
         CFTypeRef resultRef;
         NSDictionary *query = @{ (id)kSecClass : (id)kSecClassKey, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES,  (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken };
@@ -1024,6 +1051,97 @@ static void test_identity_on_two_tokens() {
         query = @{ (id)kSecClass : (id)kSecClassIdentity, (id)kSecAttrApplicationLabel : pubKeyHash, (id)kSecReturnRef : @YES, (id)kSecReturnAttributes : @YES, (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken };
         ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef*)&resultRef));
         CFReleaseNull(resultRef);
+
+        NSData *persRef, *persRef2;
+        id newRef;
+
+        // Query persistent reference for key and verify that we can get key back using it.
+        query = @{ (id)kSecValueRef: privateKey, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
+        query = @{ (id)kSecClass: (id)kSecClassKey, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
+        eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
+        query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef));
+        eq_cf((__bridge CFTypeRef)privateKey, (__bridge CFTypeRef)newRef);
+
+        // Query persistent reference for certificate and verify that we can get certificate back using it.
+        id certRef;
+        query = @{ (id)kSecClass: (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash: pubKeyHash, (id)kSecReturnRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&certRef));
+
+        persRef = nil;
+        persRef2 = nil;
+        newRef = nil;
+        query = @{ (id)kSecValueRef: certRef, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
+        query = @{ (id)kSecClass: (id)kSecClassCertificate, (id)kSecAttrPublicKeyHash: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
+        eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
+        query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef));
+        eq_cf((__bridge CFTypeRef)certRef, (__bridge CFTypeRef)newRef);
+
+        // Query persistent reference for identity and verify that we can get identity back using it.
+        id identityRef;
+        NSDictionary *attrs;
+        query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
+        identityRef = attrs[(id)kSecValueRef];
+        eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
+
+        persRef = nil;
+        persRef2 = nil;
+        attrs = nil;
+        query = @{ (id)kSecValueRef: identityRef, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
+        query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
+        eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
+        query = @{ (id)kSecValuePersistentRef: persRef2, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
+        eq_cf((__bridge CFTypeRef)identityRef, (__bridge CFTypeRef)attrs[(id)kSecValueRef]);
+        eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
+
+        // Remove certificate from token and add it as regular keychain item (non-token) one. Following tests
+        // repeat identity test for key-on-token, certificate-non-token hybrid identities.
+        ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID2, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL));
+        certQuery = CFBridgingRelease(copy_certificate_query(cert3, CFSTR("reg_cert3"), NULL, NULL));
+        ok_status(result = SecItemAdd((__bridge CFDictionaryRef)certQuery, NULL));
+
+        query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&identityRef));
+        isnt(identityRef, NULL);
+
+        persRef = nil;
+        persRef2 = nil;
+        attrs = nil;
+        query = @{ (id)kSecValueRef: identityRef, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef));
+        query = @{ (id)kSecClass: (id)kSecClassIdentity, (id)kSecAttrApplicationLabel: pubKeyHash, (id)kSecReturnPersistentRef: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&persRef2));
+        eq_cf((__bridge CFTypeRef)persRef, (__bridge CFTypeRef)persRef2);
+        query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES, (id)kSecReturnAttributes: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&attrs));
+        eq_cf((__bridge CFTypeRef)identityRef,  (__bridge CFTypeRef)attrs[(id)kSecValueRef]);
+        eq_cf((__bridge CFTypeRef)attrs[(id)kSecAttrTokenID], (__bridge CFTypeRef)tokenID1);
+
+        // After removing token with key, getting identity from persistent reference must fail gracefully.
+        ok_status(result = SecItemUpdateTokenItemsForAccessGroups((__bridge CFStringRef)tokenID1, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL));
+        query = @{ (id)kSecValuePersistentRef: persRef, (id)kSecReturnRef: @YES };
+        is_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newRef), errSecItemNotFound);
+
+        // Getting persistent reference to non-token item with token-like (but malformed) data must not crash.
+        NSData *data = CFBridgingRelease(CFPropertyListCreateDERData(kCFAllocatorDefault, (__bridge CFPropertyListRef)@[], NULL));
+        query = @{ (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrLabel: @"probe", (id)kSecValueData: data};
+        ok_status(result = SecItemAdd((__bridge CFDictionaryRef)query, NULL));
+        NSDictionary *dict;
+        query = @{ (id)kSecClass: (id)kSecClassGenericPassword, (id)kSecAttrLabel: @"probe", (id)kSecReturnPersistentRef: @YES, (id)kSecReturnData: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&dict));
+        NSData *newData;
+        query = @{ (id)kSecValuePersistentRef: dict[(id)kSecValuePersistentRef], (id)kSecReturnData: @YES };
+        ok_status(result = SecItemCopyMatching((__bridge CFDictionaryRef)query, (void *)&newData));
+        eq_cf((__bridge CFTypeRef)data, (__bridge CFTypeRef)newData);
     }
 }
 
@@ -1093,7 +1211,7 @@ static void test_ies(SecKeyRef privateKey, SecKeyAlgorithm algorithm) {
     NSDictionary *params = @{ (id)kSecAttrKeyType : privateParams[(id)kSecAttrKeyType],
                               (id)kSecAttrKeySizeInBits : privateParams[(id)kSecAttrKeySizeInBits],
                               (id)kSecAttrTokenID : @"tid-ies",
-                              (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @YES }
+                              (id)kSecPrivateKeyAttrs : @{ (id)kSecAttrIsPermanent : @NO }
                               };
     NSError *error;
     SecKeyRef tokenKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)params, (void *)&error);
@@ -1165,7 +1283,12 @@ static void tests(void) {
 }
 
 int secd_33_keychain_ctk(int argc, char *const *argv) {
-    plan_tests(491);
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        plan_tests(539);
+    } else {
+        plan_tests(403);
+    }
+
     tests();
 
     return 0;
index ff85cb8f188d434458eb4b9dff3f29082311d249..a6ef85bec7ae0f4284af93084d42c79574825d0b 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "secd_regressions.h"
 
+#import <Foundation/Foundation.h>
 #include <Security/Security.h>
 
 #include <utilities/SecCFWrappers.h>
@@ -66,7 +67,8 @@ int secd_36_ks_encrypt(int argc, char *const *argv)
     ok(ac = SecAccessControlCreate(NULL, &error), "SecAccessControlCreate: %@", error);
     ok(SecAccessControlSetProtection(ac, kSecAttrAccessibleWhenUnlocked, &error), "SecAccessControlSetProtection: %@", error);
 
-    ret = ks_encrypt_data(keybag, ac, NULL, data, (__bridge CFDictionaryRef)@{@"persistref" : @"aaa-bbb-ccc"}, NULL, &enc, true, &error);
+    CFDictionaryRef empty = (__bridge CFDictionaryRef)@{};
+    ret = ks_encrypt_data(keybag, ac, NULL, data, (__bridge CFDictionaryRef)@{@"persistref" : @"aaa-bbb-ccc"}, empty, &enc, true, &error);
     is(true, ret);
 
     CFReleaseNull(ac);
@@ -75,7 +77,11 @@ int secd_36_ks_encrypt(int argc, char *const *argv)
         CFMutableDictionaryRef attributes = NULL;
         uint32_t version = 0;
 
-        ret = ks_decrypt_data(keybag, kAKSKeyOpDecrypt, &ac, NULL, enc, NULL, NULL, &attributes, &version, true, NULL, &error);
+        NSData* dummyACM = [NSData dataWithBytes:"dummy" length:5];
+        const SecDbClass* class = kc_class_with_name(kSecClassGenericPassword);
+        NSArray* dummyArray = [NSArray array];
+
+        ret = ks_decrypt_data(keybag, kAKSKeyOpDecrypt, &ac, (__bridge CFDataRef _Nonnull)dummyACM, enc, class, (__bridge CFArrayRef)dummyArray, &attributes, &version, true, NULL, &error);
         is(true, ret, "ks_decrypt_data: %@", error);
 
         CFTypeRef aclProtection = ac ? SecAccessControlGetProtection(ac) : NULL;
index 70ff2f44a8df86978a980c0402fe7f91fcf377ca..fb815ea8ee38d9299be10c05b9ccb86537233741 100644 (file)
@@ -45,6 +45,8 @@
 #include "SecdTestKeychainUtilities.h"
 #include "SOSAccountTesting.h"
 
+#if SOS_ENABLED
+
 static int kTestTestCount = 9 + kSecdTestSetupTestCount;
 static void tests(void)
 {
@@ -96,6 +98,15 @@ static void tests(void)
     is([account getCircleStatus:&cfError], kSOSCCInCircle, "Still in Circle  (%@)", error);
     CFReleaseNull(cfError);
     
+    SecKeyRef userKey = SOSAccountCopyStashedUserPrivateKey(account, &cfError);
+    ok(userKey, "retrieved userKey");
+    CFReleaseNull(userKey);
+    
+    SecKeyRef deviceKey = SOSAccountCopyDevicePrivateKey(account, &cfError);
+    ok(deviceKey, "retrieved deviceKey");
+    CFReleaseNull(deviceKey);
+    
+    
     CFReleaseNull(new_gestalt);
 
     SOSDataSourceFactoryRelease(test_factory);
@@ -107,13 +118,16 @@ static void tests(void)
     SOSTestCleanup();
 }
 
+#endif
+
 int secd_50_account(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 67f198c151d8a4efee9ec815b95fccb2dd40d513..826b302dd58f611967f0b3a2dfdc188949a22ed3 100644 (file)
@@ -31,6 +31,9 @@
 #include <utilities/der_plist.h>
 #include "keychain/SecureObjectSync/SOSDigestVector.h"
 #include "keychain/securityd/SecDbItem.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 static void testNullMessage(uint64_t msgid)
 {
@@ -241,12 +244,15 @@ static void tests(void)
     testFlaggedMessage(test_directive, test_reason, ++msgid, 0x865);
     testFlaggedMessage(test_directive, test_reason, ++msgid, 0xdeadbeef);
 }
+#endif
 
 int secd_50_message(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(26);
-
     tests();
-
+#else
+    plan_tests(0);
+#endif
        return 0;
 }
index 08ee55e802a38ad506dee9e6d7e0e260346c889f..272c93f0fd72dfb31997fb31a9eee8ce8b4929b3 100644 (file)
 #include "SOSAccountTesting.h"
 #include "SOSTransportTestTransports.h"
 
-#if 0
-const uint8_t v6_der[] = {
-    0x30, 0x82, 0x06, 0xee, 0x02, 0x01, 0x06, 0x31, 0x4e, 0x30, 0x11, 0x0c,
-    0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04,
-    0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73,
-    0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56,
-    0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c,
-    0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d,
-    0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27, 0x73, 0x20, 0x69,
-    0x50, 0x61, 0x64, 0x30, 0x82, 0x05, 0xe0, 0x30, 0x82, 0x05, 0xdc, 0x04,
-    0x82, 0x04, 0x1c, 0x30, 0x82, 0x04, 0x18, 0x02, 0x01, 0x01, 0x0c, 0x02,
-    0x61, 0x6b, 0x02, 0x08, 0x0d, 0x4f, 0xc4, 0x65, 0x00, 0x00, 0x00, 0x03,
-    0x30, 0x82, 0x03, 0x2c, 0x30, 0x82, 0x01, 0xa2, 0x31, 0x82, 0x01, 0x56,
-    0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74,
-    0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x2b,
-    0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
-    0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16, 0x32, 0x30, 0x31,
-    0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30, 0x35, 0x39, 0x2e,
-    0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55, 0x0c, 0x10, 0x50,
-    0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67,
-    0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e, 0x16, 0x03, 0x13,
-    0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4, 0xf0, 0x47, 0x52,
-    0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06, 0x73, 0x23, 0x72,
-    0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61, 0xc9, 0x08, 0x43,
-    0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49, 0xe3, 0x0c, 0x8e,
-    0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11, 0xe1, 0x30, 0x59,
-    0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f,
-    0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20, 0x66,
-    0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f, 0x75, 0xee, 0x65,
-    0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c, 0xdb, 0x46, 0xe5,
-    0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20, 0x0a, 0x37, 0xf0,
-    0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4, 0x4a, 0x45, 0x02,
-    0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf, 0x6b, 0x0b, 0x6b,
-    0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d, 0x44, 0x65, 0x76,
-    0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c, 0x74, 0x31, 0x4e,
-    0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d,
-    0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b, 0x0c, 0x16, 0x4d,
-    0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63,
-    0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00,
-    0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x72,
-    0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74, 0x63, 0x68, 0x27,
-    0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30, 0x44, 0x02, 0x20,
-    0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf, 0xd2, 0xfb, 0x1e,
-    0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47, 0x4b, 0xfe, 0xd0,
-    0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02, 0x20, 0x6b, 0xcf,
-    0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b, 0xad, 0xf5, 0xb9,
-    0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e, 0x80, 0xef, 0xb5,
-    0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x30, 0x82, 0x01, 0x82, 0x31, 0x82,
-    0x01, 0x35, 0x30, 0x12, 0x0c, 0x0d, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x49,
-    0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x01, 0x01, 0x01, 0x30, 0x14,
-    0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x56, 0x65,
-    0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01, 0x00, 0x30, 0x29, 0x0c, 0x0d,
-    0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c,
-    0x74, 0x31, 0x18, 0x30, 0x16, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75,
-    0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x06, 0x69, 0x43, 0x6c,
-    0x6f, 0x75, 0x64, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69,
-    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18,
-    0x18, 0x16, 0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37,
-    0x30, 0x30, 0x35, 0x39, 0x2e, 0x39, 0x36, 0x30, 0x38, 0x33, 0x35, 0x5a,
-    0x30, 0x55, 0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69,
-    0x67, 0x6e, 0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0x53,
-    0x1d, 0x77, 0x7c, 0x1b, 0x8a, 0x53, 0xad, 0x88, 0xdf, 0x56, 0xf9, 0x11,
-    0xfd, 0x40, 0x69, 0x7c, 0x0b, 0xbb, 0x2a, 0xf7, 0x48, 0x7e, 0x69, 0x3d,
-    0x0c, 0xfb, 0xc8, 0x90, 0x27, 0xb5, 0x18, 0x88, 0x09, 0x3f, 0x06, 0x37,
-    0xca, 0x5d, 0x9c, 0x64, 0x34, 0x13, 0x89, 0x09, 0xe9, 0x0e, 0x99, 0xa3,
-    0xc8, 0xc1, 0x86, 0xb3, 0x6e, 0x30, 0xf1, 0x20, 0x38, 0x78, 0x56, 0x40,
-    0xf4, 0xd7, 0x36, 0x30, 0x5a, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69,
-    0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x47,
-    0x30, 0x45, 0x02, 0x20, 0x45, 0x47, 0xbf, 0x5b, 0x4d, 0x57, 0x77, 0x90,
-    0x7b, 0x74, 0x90, 0x2f, 0x5d, 0x7b, 0x02, 0x3c, 0x21, 0xe8, 0x5c, 0x24,
-    0x0c, 0x77, 0xd8, 0x19, 0xff, 0xce, 0x28, 0x45, 0x76, 0x50, 0xb1, 0xee,
-    0x02, 0x21, 0x00, 0xe3, 0xea, 0x0f, 0xcb, 0x72, 0xd7, 0x88, 0x15, 0xa4,
-    0x71, 0xbe, 0x9e, 0xa6, 0xf2, 0x9c, 0xa8, 0x9b, 0x93, 0xec, 0x31, 0x7a,
-    0xe3, 0x92, 0x8a, 0xf2, 0x2f, 0xfd, 0x98, 0xc9, 0xe1, 0xc4, 0x7c, 0x04,
-    0x47, 0x30, 0x45, 0x02, 0x21, 0x00, 0xce, 0x5f, 0x67, 0x9d, 0x78, 0x9f,
-    0xc6, 0x3b, 0xb3, 0x51, 0xde, 0x6d, 0x9e, 0xff, 0xf5, 0xab, 0xda, 0xf4,
-    0x7e, 0xb2, 0xe9, 0x1a, 0xf2, 0xd9, 0x0d, 0x48, 0x30, 0x07, 0xbc, 0x06,
-    0xf5, 0x42, 0x02, 0x20, 0x64, 0x1d, 0x7d, 0x43, 0xc1, 0x3b, 0x50, 0xd6,
-    0x7b, 0x3b, 0xce, 0x6f, 0xec, 0x23, 0x21, 0x8a, 0x9b, 0x06, 0x3f, 0x64,
-    0xfe, 0xd6, 0x29, 0xaf, 0x5b, 0x0c, 0x69, 0x8f, 0x48, 0x88, 0x08, 0x1e,
-    0x30, 0x00, 0x30, 0x00, 0x31, 0x81, 0xd0, 0x30, 0x66, 0x0c, 0x1a, 0x30,
-    0x56, 0x4f, 0x73, 0x47, 0x76, 0x56, 0x72, 0x51, 0x46, 0x4e, 0x46, 0x6b,
-    0x52, 0x35, 0x37, 0x71, 0x59, 0x73, 0x4c, 0x47, 0x6f, 0x33, 0x49, 0x50,
-    0x51, 0x04, 0x48, 0x30, 0x46, 0x02, 0x21, 0x00, 0xf9, 0xc9, 0x69, 0xda,
-    0x69, 0xe7, 0x32, 0xeb, 0x14, 0xc1, 0xbd, 0x56, 0xb7, 0x3e, 0xab, 0x08,
-    0x6d, 0xe2, 0x16, 0xd9, 0x0a, 0xa8, 0x67, 0x7a, 0x56, 0xdc, 0x64, 0xf2,
-    0x2f, 0x2e, 0xe8, 0xb9, 0x02, 0x21, 0x00, 0xac, 0x5c, 0x29, 0x80, 0x60,
-    0x57, 0xd7, 0x51, 0x23, 0x1f, 0x00, 0x09, 0x70, 0xf3, 0xd5, 0x1a, 0x49,
-    0xad, 0xaf, 0x35, 0x77, 0x07, 0xf4, 0x85, 0x1f, 0x63, 0xe0, 0xea, 0x67,
-    0x36, 0xb5, 0x3b, 0x30, 0x66, 0x0c, 0x1a, 0x6e, 0x6b, 0x62, 0x77, 0x33,
-    0x2f, 0x57, 0x72, 0x39, 0x4f, 0x33, 0x6a, 0x45, 0x68, 0x4f, 0x48, 0x46,
-    0x67, 0x32, 0x34, 0x67, 0x62, 0x4d, 0x61, 0x6a, 0x76, 0x04, 0x48, 0x30,
-    0x46, 0x02, 0x21, 0x00, 0x9f, 0x4f, 0x60, 0x2f, 0x54, 0x5e, 0x9f, 0x6a,
-    0x7d, 0x37, 0xd9, 0x9f, 0x62, 0x69, 0xd7, 0x8c, 0xfc, 0xf5, 0x78, 0x54,
-    0x7d, 0xb6, 0x91, 0x4b, 0x48, 0x88, 0x3d, 0x59, 0x05, 0x70, 0x09, 0xbf,
-    0x02, 0x21, 0x00, 0xe2, 0xaf, 0xc9, 0x27, 0x12, 0xfa, 0x64, 0x51, 0x19,
-    0x13, 0x1d, 0x57, 0x56, 0x6b, 0x93, 0xa3, 0xc6, 0x31, 0xf8, 0x70, 0x97,
-    0x9e, 0x79, 0xf5, 0xc0, 0x2d, 0xf3, 0x3c, 0x8b, 0x86, 0x92, 0x28, 0x04,
-    0x82, 0x01, 0xb8, 0x30, 0x82, 0x01, 0xb4, 0x30, 0x82, 0x01, 0xa2, 0x31,
-    0x82, 0x01, 0x56, 0x30, 0x14, 0x0c, 0x0f, 0x43, 0x6f, 0x6e, 0x66, 0x6c,
-    0x69, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x02, 0x01,
-    0x00, 0x30, 0x2b, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
-    0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x04, 0x18, 0x18, 0x16,
-    0x32, 0x30, 0x31, 0x35, 0x30, 0x32, 0x32, 0x36, 0x31, 0x37, 0x30, 0x30,
-    0x35, 0x39, 0x2e, 0x39, 0x31, 0x35, 0x33, 0x35, 0x38, 0x5a, 0x30, 0x55,
-    0x0c, 0x10, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x53, 0x69, 0x67, 0x6e,
-    0x69, 0x6e, 0x67, 0x4b, 0x65, 0x79, 0x04, 0x41, 0x04, 0xd9, 0x02, 0x0e,
-    0x16, 0x03, 0x13, 0xfb, 0xf8, 0x29, 0xbf, 0x83, 0xbd, 0x6b, 0x5a, 0xc4,
-    0xf0, 0x47, 0x52, 0xc7, 0x87, 0x81, 0xe9, 0xda, 0xe0, 0xb4, 0x8b, 0x06,
-    0x73, 0x23, 0x72, 0xba, 0xba, 0xc4, 0x1a, 0x35, 0xa2, 0xc6, 0x46, 0x61,
-    0xc9, 0x08, 0x43, 0x4f, 0x89, 0x08, 0x9d, 0xe1, 0xd5, 0x3d, 0x83, 0x49,
-    0xe3, 0x0c, 0x8e, 0xfb, 0x33, 0x37, 0xd7, 0x6d, 0x03, 0xe0, 0x39, 0x11,
-    0xe1, 0x30, 0x59, 0x0c, 0x0f, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61,
-    0x74, 0x69, 0x6f, 0x6e, 0x55, 0x73, 0x69, 0x67, 0x04, 0x46, 0x30, 0x44,
-    0x02, 0x20, 0x66, 0x9e, 0xd0, 0x80, 0x11, 0xa4, 0x17, 0x94, 0x66, 0x5f,
-    0x75, 0xee, 0x65, 0xbf, 0xd0, 0x49, 0x8f, 0xe6, 0x22, 0xf6, 0x3c, 0x2c,
-    0xdb, 0x46, 0xe5, 0x3f, 0x4f, 0x85, 0xb9, 0x8a, 0x6c, 0x8a, 0x02, 0x20,
-    0x0a, 0x37, 0xf0, 0xf1, 0x9f, 0x13, 0xfd, 0xae, 0x5f, 0xb7, 0xd0, 0xb4,
-    0x4a, 0x45, 0x02, 0x8a, 0x2f, 0xdc, 0x8b, 0xd3, 0xfb, 0x09, 0xeb, 0xcf,
-    0x6b, 0x0b, 0x6b, 0x18, 0x9c, 0xcf, 0x6c, 0x55, 0x30, 0x5f, 0x0c, 0x0d,
-    0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x47, 0x65, 0x73, 0x74, 0x61, 0x6c,
-    0x74, 0x31, 0x4e, 0x30, 0x11, 0x0c, 0x09, 0x4d, 0x6f, 0x64, 0x65, 0x6c,
-    0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x04, 0x69, 0x50, 0x61, 0x64, 0x30, 0x1b,
-    0x0c, 0x16, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x50, 0x72, 0x6f,
-    0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-    0x02, 0x01, 0x00, 0x30, 0x1c, 0x0c, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x75,
-    0x74, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x0c, 0x0c, 0x4d, 0x69, 0x74,
-    0x63, 0x68, 0x27, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x04, 0x46, 0x30,
-    0x44, 0x02, 0x20, 0x72, 0x06, 0xdb, 0xf8, 0x06, 0xff, 0x7f, 0xac, 0xcf,
-    0xd2, 0xfb, 0x1e, 0x86, 0x0d, 0x87, 0x4e, 0xb9, 0x1b, 0x26, 0x1e, 0x47,
-    0x4b, 0xfe, 0xd0, 0x54, 0x0c, 0xdf, 0x88, 0x5a, 0x27, 0x92, 0x1d, 0x02,
-    0x20, 0x6b, 0xcf, 0x7f, 0xb5, 0xfe, 0x19, 0x16, 0xd2, 0x7f, 0xb1, 0x7b,
-    0xad, 0xf5, 0xb9, 0xea, 0x23, 0x69, 0x37, 0x19, 0x5e, 0xd3, 0x8c, 0x9e,
-    0x80, 0xef, 0xb5, 0x65, 0x9a, 0xd5, 0x42, 0x51, 0x13, 0x04, 0x0c, 0x6b,
-    0x65, 0x79, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02,
-    0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41,
-    0x94, 0x6d, 0x46, 0x38, 0xde, 0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86,
-    0xbe, 0xd5, 0x78, 0x08, 0x2f, 0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f,
-    0x1e, 0xca, 0x05, 0x21, 0x51, 0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46,
-    0x53, 0x7e, 0x49, 0x97, 0xb8, 0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92,
-    0xdd, 0x30, 0xe2, 0x4d, 0xd4, 0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c,
-    0x04, 0x41, 0x04, 0x78, 0xea, 0x03, 0x41, 0x94, 0x6d, 0x46, 0x38, 0xde,
-    0x37, 0xe0, 0xb6, 0xc8, 0xfa, 0x94, 0x86, 0xbe, 0xd5, 0x78, 0x08, 0x2f,
-    0x1f, 0x5e, 0xa4, 0x0c, 0x93, 0xc2, 0x5f, 0x1e, 0xca, 0x05, 0x21, 0x51,
-    0xc2, 0xce, 0x7c, 0xcf, 0x58, 0x2f, 0x46, 0x53, 0x7e, 0x49, 0x97, 0xb8,
-    0x06, 0x98, 0x9b, 0xe2, 0x12, 0xa9, 0x92, 0xdd, 0x30, 0xe2, 0x4d, 0xd4,
-    0x32, 0x09, 0x62, 0x5f, 0xea, 0x0c, 0x0c, 0x04, 0x27, 0x30, 0x25, 0x04,
-    0x10, 0x48, 0xd4, 0x7b, 0x6a, 0x50, 0xfb, 0x84, 0xf8, 0xb5, 0x8d, 0x13,
-    0x62, 0xcc, 0x42, 0xa5, 0x42, 0x02, 0x03, 0x00, 0xc3, 0x50, 0x02, 0x02,
-    0x01, 0x00, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x07,
-    0x31, 0x00 };
-#endif
+#if SOS_ENABLED
 
 #define kCompatibilityTestCount 0
 #if 0
@@ -252,16 +101,18 @@ static void tests(void)
     SOSDataSourceRelease(test_source, NULL);
 }
 
+#endif
+
 int secd_51_account_inflate(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount + kCompatibilityTestCount);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     secd_test_clear_testviews();
     tests();
-
-    /* we can't re-inflate the v6 DER since we don't have a viable private key for it. */
-    // test_v6();
+#else
+    plan_tests(0);
+#endif
 
     return 0;
 }
index 37b1cf8ba518b9a6713c6f49f1854ada5da18c5d..418d208b88b9b03326735b8fdf0bfcde8713988b 100644 (file)
@@ -46,6 +46,7 @@
 #include "SecdTestKeychainUtilities.h"
 #include "SOSAccountTesting.h"
 
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -201,15 +202,16 @@ static void tests(void)
     SOSTestCleanup();
 
 }
-
+#endif
 
 int secd_52_account_changed(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(113);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index bb2f6a74082c581e9abc9d3e3bfc95dd1c71373c..a33f138ce4a84958a0526fe71402c2f030ca283e 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -128,7 +129,7 @@ static void tests(void)
 
     SOSCircleSetGeneration(carolTrust.trustedCircle, gencount);
     
-    SecKeyRef user_privkey = SOSUserKeygen(cfpassword, (__bridge CFDataRef)(carol_account.accountKeyDerivationParamters), &error);
+    SecKeyRef user_privkey = SOSUserKeygen(cfpassword, (__bridge CFDataRef)(carol_account.accountKeyDerivationParameters), &error);
     CFNumberRef genCountTest = SOSCircleGetGeneration(carolTrust.trustedCircle);
     CFIndex testPtr;
     CFNumberGetValue(genCountTest, kCFNumberCFIndexType, &testPtr);
@@ -158,7 +159,11 @@ static void tests(void)
     is([alice_account getCircleStatus:&error],kSOSCCNotInCircle,"alice is not in the account (%@)", error);
     is([bob_account getCircleStatus:&error], kSOSCCNotInCircle,"bob is not in the account (%@)", error);
     is([carol_account getCircleStatus:&error], kSOSCCInCircle,"carol is in the account (%@)", error);
-
+    secLogEnable();
+    [carol_account iCloudIdentityStatus:^(NSData *json, NSError *error) {
+        diag("icloud identity JSON\n%s\n", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]);
+    }];
+    secLogDisable();
     CFReleaseNull(gencount);
     CFReleaseNull(cfpassword);
     CFReleaseNull(user_privkey);
@@ -168,14 +173,16 @@ static void tests(void)
 
     SOSTestCleanup();
 }
+#endif
 
 int secd_52_offering_gencount_reset(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(63);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index b11e1d31713b9cc5a8c9774b6001fd3dcb41c318..aed491b3aa8c2ad9f90324f38bd679cc30a2e03e 100644 (file)
@@ -53,6 +53,8 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
+
 static int kTestTestCount = 257;
 
 static void tests(void)
@@ -325,7 +327,7 @@ static void tests(void)
                                                          carol_account.peerInfo,
                                                          NULL);
 
-    ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, nil, NULL));
+    ok(SOSAccountRemovePeersFromCircle(bob_account, peers_to_remove_array, NULL));
 
     is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, carol_account, NULL), 4, "Remove peers");
 
@@ -343,14 +345,16 @@ static void tests(void)
     
     SOSTestCleanup();
 }
+#endif
 
 int secd_55_account_circle(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index da6aabcab25a848de2d06e01ba9633a78d09f2f4..1d32bfe9fa73c85a0e9b066f225aafec6a67390d 100644 (file)
@@ -53,6 +53,8 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
+
 static int kTestTestCount = 10;
 
 static void tests(void)
@@ -101,14 +103,16 @@ static void tests(void)
     carol_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_55_account_incompatibility(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 50748a0819f3f6215776692e72a9539f2a4a557b..28a6caa963e2083f3d17b9cabe46cfd1cd269c74 100644 (file)
@@ -51,6 +51,8 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
+
 #define kAccountPasswordString ((uint8_t*) "FooFooFoo")
 #define kAccountPasswordStringLen 10
 
@@ -209,14 +211,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_56_account_apply(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(181);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index d455b32776bc19ef4370bb4ea98b5731b3e9955f..f41933719cb920d505cf7e4cae8eb75f73e403c3 100644 (file)
@@ -55,7 +55,9 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#include "SOSAccountTesting.h"
 
+#if SOS_ENABLED
 
 static bool acceptApplicants(SOSAccount* account, CFIndex count) {
     bool retval = false;
@@ -148,14 +150,16 @@ static void tests(void)
     alice_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_57_1_account_last_standing(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(45);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 6e1710d18345375023787969eef5f9c2781472a1..f21450ed691aefe7a3c6f17611f4dabd73b3a754 100644 (file)
@@ -52,6 +52,8 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
+
 
 /*
  static void trim_retirements_from_circle(SOSAccount* account) {
@@ -250,14 +252,17 @@ static void tests(void)
     SOSTestCleanup();
 }
 
+#endif
+
 int secd_57_account_leave(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(191);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     secd_test_clear_testviews();
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index db6ff25c84880e93738310ff512b549c6813822a..a915156a8d30277c3d7790d97f7a4c81e82cf9dc 100644 (file)
@@ -50,6 +50,7 @@
 #include "SOSAccountTesting.h"
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
 
 static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef password) {
     CFErrorRef error = NULL;
@@ -59,15 +60,6 @@ static bool AssertCreds(SOSAccount* account,CFStringRef acct_name, CFDataRef pas
     return retval;
 }
 
-static inline bool SOSAccountEvaluateKeysAndCircle_wTxn(SOSAccount* acct, CFErrorRef* error)
-{
-    __block bool result = false;
-    [acct performTransaction:^(SOSAccountTransaction * _Nonnull txn) {
-        result = SOSAccountEvaluateKeysAndCircle(txn, NULL);
-    }];
-    return result;
-}
-
 static bool ResetToOffering(SOSAccount* account) {
     CFErrorRef error = NULL;
     bool retval;
@@ -245,14 +237,16 @@ static void tests(void)
     david_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_58_password_change(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(211);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index dcdb0699c0def8f46a4915b618755143533575b0..29192cf2f1d607bc4b9ff5896c6ba48f7f99de3e 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
 
 static void tests(void)
 {
@@ -146,14 +147,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_59_account_cleanup(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(91);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 3fbb31d2a645a7485e4a26040fcfa65c3106b033..d39069c62c5a106119a66d7a528e68c56f557acb 100644 (file)
@@ -51,6 +51,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 
 static bool purgeICloudIdentity(SOSAccount* account) {
@@ -283,14 +284,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_60_account_cloud_identity(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(159);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index ac6b75c10a766548ba3cb27531c2d5a69b3ce741..75f33af08f60fd863e438d746f3350ca94850a55 100644 (file)
@@ -51,6 +51,8 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
+
 /*
  static void trim_retirements_from_circle(SOSAccount* account) {
  SOSAccountForEachCircle(account, ^(SOSCircleRef circle) {
@@ -178,13 +180,16 @@ static void tests(void)
     SOSTestCleanup();
 }
 
+#endif
+
 int secd_61_account_leave_not_in_kansas_anymore(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(82);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 41934fda203dafd88a0fbc7c1e70688cf98b01ec..9f685164b7feb7d2eb007ee821837d44d841ab2a 100644 (file)
 
 #include "keychain/securityd/SOSCloudCircleServer.h"
 
-#if !TARGET_OS_SIMULATOR
+
 #include "SOSAccountTesting.h"
-#endif
 #include "SecdTestKeychainUtilities.h"
-
-#if !TARGET_OS_SIMULATOR
+#if SOS_ENABLED
 
 static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error)
 {
@@ -68,12 +66,9 @@ static CFDataRef CopyBackupKeyForString(CFStringRef string, CFErrorRef *error)
     });
     return result;
 }
-#endif
 
 static void tests(void)
 {
-#if !TARGET_OS_SIMULATOR
-        
     __block CFErrorRef error = NULL;
     CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
     CFStringRef cfaccount = CFSTR("test@test.org");
@@ -156,7 +151,7 @@ static void tests(void)
     ok([bob_account.trust checkForRings:&error], "Alice_account is good");
     CFReleaseNull(error);
 
-    is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 5, "updates");
+    is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 4, "updates");
 
 
     ok([alice_account.trust checkForRings:&error], "Alice_account is good");
@@ -248,22 +243,18 @@ static void tests(void)
     alice_account = nil;
     bob_account = nil;
     SOSTestCleanup();
-#endif
-
 }
+#endif
 
 int secd_62_account_backup(int argc, char *const *argv)
 {
-#if !TARGET_OS_SIMULATOR
+#if SOS_ENABLED
     plan_tests(98);
-#else
-    plan_tests(1);
-#endif
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     secd_test_setup_testviews(); // for running this test solo
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 5e0ef6d016edb40824e50db2452c3c76591d5089..5aa3b963ea39af2e450c56b87b5dfdf547d56d05 100644 (file)
@@ -51,6 +51,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 
 typedef void (^stir_block)(int expected_iterations);
@@ -198,14 +199,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_63_account_resurrection(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(73);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 6c905c29837762f70cd3616ea249a0466626321b..ecee45c0443555ef83f375aaf19a7439761ad74b 100644 (file)
@@ -35,6 +35,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 static int64_t getCurrentGenCount(SOSAccount* account) {
     SOSAccountTrustClassic* trust = account.trust;
@@ -131,14 +132,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_64_circlereset(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(35);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 5db81a50677b06b01d9eb68416acd13904073dbd..6a2f4a4ccf81bf9751f3344c687a3996a92273e6 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "SecdTestKeychainUtilities.h"
 
+#if SOS_ENABLED
 
 typedef void (^stir_block)(int expected_iterations);
 typedef int (^execute_block)(void);
@@ -171,14 +172,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_65_account_retirement_reset(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(28);
-
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 57ffd281c6c24ff43c4844365ffa7149f4f5cd8a..2d7a5ad5b76e4db23a9779ca15b4ac707e3de710 100644 (file)
 #include "keychain/securityd/SOSCloudCircleServer.h"
 #include "SecdTestKeychainUtilities.h"
 
-#if TARGET_OS_SIMULATOR
-
-int secd_66_account_recovery(int argc, char *const *argv) {
-    plan_tests(1);
-    secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    return 0;
-}
-
-#else
+#if SOS_ENABLED
 
 #include "SOSAccountTesting.h"
 
@@ -346,16 +338,16 @@ static void tests(bool recKeyFirst)
 
     SOSTestCleanup();
 }
+#endif
 
 int secd_66_account_recovery(int argc, char *const *argv) {
+#if SOS_ENABLED
     plan_tests(281);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests(true);
     tests(false);
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
-
-#endif
diff --git a/keychain/securityd/Regressions/secd-668-ghosts.m b/keychain/securityd/Regressions/secd-668-ghosts.m
deleted file mode 100644 (file)
index 957c30a..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 2012-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@
- */
-
-//
-//  secd-668-ghosts.c
-//  sec
-//
-
-#include <CoreFoundation/CFDictionary.h>
-#include <utilities/SecCFWrappers.h>
-
-#include "keychain/SecureObjectSync/SOSAccount.h"
-#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
-
-#include "secd_regressions.h"
-#include "SOSAccountTesting.h"
-#include "SecdTestKeychainUtilities.h"
-
-/*
- Make a circle with two peers - alice and bob(bob is iOS and serial#"abababababab")
- have alice leave the circle
- release bob, make a new bob - iOS and same serial number
- try to join the circle - it should resetToOffering with ghost fix
- For phase 1 we expect the ghostfix to work with iOS devices, but not with MacOSX devices.
- */
-
-#if 0
-static void hauntedCircle(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted)
-{
-    CFErrorRef error = NULL;
-    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
-    CFStringRef cfaccount = CFSTR("test@test.org");
-    CFStringRef ghostSerialID = CFSTR("abababababab");
-    CFStringRef ghostIdsID = CFSTR("targetIDS");
-    
-    CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
-    SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), devClass, ghostSerialID, ghostIdsID);
-    
-    // Start Circle
-    ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle");
-    is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates");
-    ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins");
-    
-    // Alice Leaves
-    ok( [alice_account.trust leaveCircle:alice_account err:&error], "Alice Leaves (%@)", error);
-    CFReleaseNull(error);
-    is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 2, "updates");
-    accounts_agree("Alice bails", bob_account, alice_account);
-    is(countPeers(bob_account), 1, "There should only be 1 valid peer");
-    // We're dropping all peers that are in the circle - leaving a circle with only one peer - and that's a ghost
-
-    // Make new bob - same as the old bob except peerID
-
-    SOSAccount* bobFinal = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID);
-    is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 1, "updates");
-
-    ok(SOSTestJoinWith(cfpassword, cfaccount, changes, bobFinal), "Application Made");
-    CFReleaseNull(cfpassword);
-
-    // Did ghostbuster work?
-    is(ProcessChangesUntilNoChange(changes, bobFinal, NULL), 2, "updates");
-    if(expectGhostBusted) { // ghostbusting is currently disabled for MacOSX Peers
-        ok([bobFinal isInCircle:NULL], "Bob is in");
-    } else {
-        ok(![bobFinal isInCircle:NULL], "Bob is not in");
-    }
-
-    is(countPeers(bobFinal), 1, "There should only be 1 valid peer");
-
-    CFReleaseNull(changes);
-    
-    bob_account = nil;
-    alice_account = nil;
-    bobFinal = nil;
-    SOSTestCleanup();
-}
-
-static void multiBob(SOSPeerInfoDeviceClass devClass, bool expectGhostBusted, bool delayedPrivKey, bool pairJoin) {
-    CFErrorRef error = NULL;
-    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
-    CFStringRef cfaccount = CFSTR("test@test.org");
-    CFStringRef ghostSerialID = CFSTR("abababababab");
-    CFStringRef ghostIdsID = CFSTR("targetIDS");
-    
-    CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
-    
-    // Start Circle
-    ok(SOSAccountAssertUserCredentialsAndUpdate(alice_account, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
-    is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates");
-    
-    ok(SOSAccountResetToOffering_wTxn(alice_account, &error), "Reset to offering (%@)", error);
-    CFReleaseNull(error);
-    
-    is(ProcessChangesUntilNoChange(changes, alice_account, NULL), 1, "updates");
-    
-    SOSTestMakeGhostInCircle(CFSTR("Bob1"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 2);
-    SOSTestMakeGhostInCircle(CFSTR("Bob2"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 3);
-    SOSTestMakeGhostInCircle(CFSTR("Bob3"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 4);
-    SOSTestMakeGhostInCircle(CFSTR("Bob4"), devClass, ghostSerialID, ghostIdsID, cfpassword, cfaccount, changes, alice_account, 5);
-    
-    SOSAccount* bobFinal_account = SOSTestCreateAccountAsSerialClone(CFSTR("BobFinal"), devClass, ghostSerialID, ghostIdsID);
-    
-    if(pairJoin) {
-        SOSTestJoinThroughPiggyBack(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 6, true);
-        is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle");
-    } else if(delayedPrivKey) {
-        SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, DROP_USERKEY, 6, true);
-        is(countPeers(bobFinal_account), 6, "Expect ghosts still in circle");
-    } else {
-        SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bobFinal_account, KEEP_USERKEY, 2, true);
-    }
-    
-    if(pairJoin || delayedPrivKey) { // this allows the ghostbusting to be done in a delayed fashion for the instances where that is proper
-        SOSAccountTryUserCredentials(bobFinal_account, cfaccount, cfpassword, &error);
-        ok(SOSTestChangeAccountDeviceName(bobFinal_account, CFSTR("ThereCanBeOnlyOneBob")), "force an unrelated circle change");
-        is(ProcessChangesUntilNoChange(changes, alice_account, bobFinal_account, NULL), 3, "updates");
-    }
-
-    CFReleaseNull(cfpassword);
-
-    
-    ok([bobFinal_account isInCircle:NULL], "bobFinal_account is in");
-
-    is(countPeers(bobFinal_account), 2, "Expect ghostBobs to be gone");
-    is(countPeers(alice_account), 2, "Expect ghostBobs to be gone");
-    accounts_agree_internal("Alice and ThereCanBeOnlyOneBob are the only circle peers and they agree", alice_account, bobFinal_account, false);
-
-    CFReleaseNull(changes);
-
-    alice_account = nil;
-    bobFinal_account = nil;
-    
-    SOSTestCleanup();
-}
-
-static void iosICloudIdentity() {
-    CFErrorRef error = NULL;
-    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
-    CFStringRef cfaccount = CFSTR("test@test.org");
-    CFStringRef ghostIdsID = CFSTR("targetIDS");
-    
-    CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    SOSAccount* alice_account = CreateAccountForLocalChanges(CFSTR("Alice"), CFSTR("TestSource"));
-    
-    // Start Circle
-    ok(SOSTestStartCircleWithAccount(alice_account, changes, cfaccount, cfpassword), "Have Alice start a circle");
-    
-    SOSCircleRef circle = [alice_account.trust getCircle:NULL];
-    __block CFStringRef serial = NULL;
-    SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
-        if(SOSPeerInfoIsCloudIdentity(peer)) {
-            serial = SOSPeerInfoCopySerialNumber(peer);
-        }
-    });
-    
-    SOSAccount* bob_account = SOSTestCreateAccountAsSerialClone(CFSTR("Bob"), SOSPeerInfo_iOS, serial, ghostIdsID);
-
-    is(ProcessChangesUntilNoChange(changes, alice_account, bob_account, NULL), 1, "updates");
-    ok(SOSTestJoinWithApproval(cfpassword, cfaccount, changes, alice_account, bob_account, KEEP_USERKEY, 2, false), "Bob Joins");
-    CFReleaseNull(cfpassword);
-
-    circle = [alice_account.trust getCircle:&error];
-    __block bool hasiCloudIdentity = false;
-    SOSCircleForEachActivePeer(circle, ^(SOSPeerInfoRef peer) {
-        if(SOSPeerInfoIsCloudIdentity(peer)) {
-            hasiCloudIdentity = true;
-        }
-    });
-
-    ok(hasiCloudIdentity, "GhostBusting didn't mess with the iCloud Identity");
-    
-    CFReleaseNull(changes);
-    alice_account = nil;
-    SOSTestCleanup();
-}
-#endif // 0
-
-int secd_68_ghosts(int argc, char *const *argv)
-{
-    plan_tests(1);
-    
-    secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
-#if 0
-    // changing ghostbusting.  handleUpdateCircle version is going away.
-    hauntedCircle(SOSPeerInfo_iOS, true);
-    hauntedCircle(SOSPeerInfo_macOS, false);
-    multiBob(SOSPeerInfo_iOS, true, false, false);
-    multiBob(SOSPeerInfo_iOS, false, true, false);
-    multiBob(SOSPeerInfo_iOS, false, false, true); // piggyback join case
-
-    iosICloudIdentity();
-#endif
-    return 0;
-}
index 93809dfddb37f5ba086739f561728609962236bb..b4de05d8ca0c780a92267cd86b4dc846bf9b5199 100644 (file)
@@ -61,6 +61,8 @@
 
 
 #include "SOSAccountTesting.h"
+#if SOS_ENABLED
+
 static void tests() {
     CFErrorRef error = NULL;
     int keySizeInBits = 256;
@@ -119,11 +121,15 @@ static void tests() {
 
 
 }
+#endif
 
 int secd_67_prefixedKeyIDs(int argc, char *const *argv) {
+#if SOS_ENABLED
     plan_tests(12);
-
     tests();
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
 
diff --git a/keychain/securityd/Regressions/secd-68-fullPeerInfoIntegrity.m b/keychain/securityd/Regressions/secd-68-fullPeerInfoIntegrity.m
new file mode 100644 (file)
index 0000000..542307c
--- /dev/null
@@ -0,0 +1,121 @@
+//
+//  secd-68-fullPeerInfoIntegrity.m
+//  secdRegressions
+//
+//  Created by Richard Murphy on 4/30/20.
+//
+
+#import <Foundation/Foundation.h>
+
+#include <Security/SecBase.h>
+#include <Security/SecItem.h>
+
+#include <CoreFoundation/CFDictionary.h>
+
+#include "keychain/SecureObjectSync/SOSAccount.h"
+#include <Security/SecureObjectSync/SOSCloudCircle.h>
+#include "keychain/SecureObjectSync/SOSInternal.h"
+#include "keychain/SecureObjectSync/SOSUserKeygen.h"
+#include "keychain/SecureObjectSync/SOSTransport.h"
+#include "keychain/SecureObjectSync/SOSAccountTrustClassic+Circle.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "secd_regressions.h"
+#include "SOSTestDataSource.h"
+
+#include "SOSRegressionUtilities.h"
+#include <utilities/SecCFWrappers.h>
+#include <Security/SecKeyPriv.h>
+
+#include "keychain/securityd/SOSCloudCircleServer.h"
+
+#include "SOSAccountTesting.h"
+
+#include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
+
+static NSString *makeCircle(SOSAccount* testaccount, CFMutableDictionaryRef changes) {
+    CFErrorRef error = NULL;
+
+    // Every time we resetToOffering should result in a new fpi
+    NSString *lastPeerID = testaccount.peerID;
+    ok(SOSAccountResetToOffering_wTxn(testaccount, &error), "Reset to offering (%@)", error);
+    CFReleaseNull(error);
+    is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
+    NSString *currentPeerID = testaccount.peerID;
+    ok(![lastPeerID isEqualToString:currentPeerID], "peerID changed on circle reset");
+    return currentPeerID;
+}
+
+static void tests(void) {
+    CFErrorRef error = NULL;
+    CFDataRef cfpassword = CFDataCreate(NULL, (uint8_t *) "FooFooFoo", 10);
+    CFStringRef cfaccount = CFSTR("test@test.org");
+
+    CFMutableDictionaryRef changes = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
+    SOSAccount* testaccount = CreateAccountForLocalChanges(CFSTR("TestDev"), CFSTR("TestSource"));
+
+    // Just making an account object to mess with
+    ok(SOSAccountAssertUserCredentialsAndUpdate(testaccount, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
+    is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
+    CFReleaseNull(error);
+
+    // make a circle then make sure fpi isn't reset just for a normal ensureFullPeerAvailable
+    NSString *lastPeerID = makeCircle(testaccount, changes);
+    ok([testaccount.trust ensureFullPeerAvailable:testaccount err:&error], "fullPeer is available");
+    NSString *currentPeerID = testaccount.peerID;
+    ok([lastPeerID isEqualToString: currentPeerID], "peerID did not alter in trip through ensureFullPeerAvailable");
+
+
+    // leaving a circle should reset the fpi
+    lastPeerID = makeCircle(testaccount, changes);
+    ok([testaccount.trust leaveCircle:testaccount err:&error], "leave the circle %@", error);
+    CFReleaseNull(error);
+    is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
+    currentPeerID = testaccount.peerID;
+    ok(![lastPeerID isEqualToString:currentPeerID], "peerID changed on leaving circle");
+
+    // break the fullpeerinfo by purging the private key - then fix in ensureFullPeerAvailable
+    lastPeerID = makeCircle(testaccount, changes);
+    ok(SOSFullPeerInfoPurgePersistentKey(testaccount.fullPeerInfo, &error), "purging persistent key %@", error);
+    currentPeerID = testaccount.peerID;
+    ok([lastPeerID isEqualToString:currentPeerID], "pre-ensuring peerID remains the same");
+    lastPeerID = currentPeerID;
+    ok([testaccount.trust ensureFullPeerAvailable:testaccount err:&error], "fullPeer is available");
+    currentPeerID = testaccount.peerID;
+    ok(![lastPeerID isEqualToString: currentPeerID], "peerID changed because fullPeerInfo fixed in ensureFullPeerAvailable");
+    lastPeerID = currentPeerID;
+
+    // If that last thing worked this peer won't be in the circle any more - changing fpi changes "me"
+    ok(SOSAccountAssertUserCredentialsAndUpdate(testaccount, cfaccount, cfpassword, &error), "Credential setting (%@)", error);
+    is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
+    CFReleaseNull(error);
+    ok(![testaccount isInCircle: &error], "No longer in circle");
+
+    // This join should work because the peer we left in the circle will be a ghost and there are no other peers
+    ok(SOSAccountJoinCircles_wTxn(testaccount, &error), "Apply to circle (%@)", error);
+    CFReleaseNull(error);
+    is(ProcessChangesUntilNoChange(changes, testaccount, NULL), 1, "updates");
+    ok([testaccount isInCircle: &error], "Is in circle");
+    currentPeerID = testaccount.peerID;
+    ok(![lastPeerID isEqualToString: currentPeerID], "peerID changed because fullPeerInfo changed during join");
+
+    CFReleaseNull(cfpassword);
+    testaccount = nil;
+    SOSTestCleanup();
+}
+#endif
+
+int secd_68_fullPeerInfoIntegrity(int argc, char *const *argv)
+{
+#if SOS_ENABLED
+    plan_tests(29);
+    secd_test_setup_temp_keychain(__FUNCTION__, NULL);
+    tests();
+#else
+    plan_tests(0);
+#endif
+    return 0;
+}
index a229bcaad2ab958554aed6e3e311c092587fd439..6a84024c9fc39440846cee265a8d73e669ac8023 100644 (file)
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecIOFormat.h>
 #include <utilities/SecFileLocations.h>
+#include "SOSAccountTesting.h"
 
 #include <AssertMacros.h>
 #include <stdint.h>
+#if SOS_ENABLED
 
 static int kTestTestCount = 121;
 
@@ -242,23 +244,23 @@ TODO: {
     }, CFSTR("Alice"), CFSTR("Bob"), NULL);
 }
 }
+#endif
 
 int secd_70_engine_corrupt(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     __security_simulatecrash_enable(false);
-
     /* custom keychain dir */
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     nosha1();
     drop_item();
     drop_manifest();
     add_sha1();
     change_sha1();
-
     __security_simulatecrash_enable(true);
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 62be20d5f6b68ea5ea70a6bbd347b4d0ac13197b..f7287f1cffb86c07e658d8e39ad7119aa41c9ee4 100644 (file)
@@ -25,6 +25,9 @@
 #include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h"
 #include "secd_regressions.h"
 #include "SecdTestKeychainUtilities.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 static int kTestTestCount = 581;
 
@@ -48,15 +51,17 @@ static void smash(void) {
         return false;
     }, CFSTR("alice"), CFSTR("bob"), NULL);
 }
+#endif
 
 int secd_70_engine_smash(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     /* custom keychain dir */
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     smash();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 87ac71fd86f2f5313f75bcef3592ef8e45579c71..e3c9d658fa37cbceac8a73d8d8d16c56b18a01ab 100644 (file)
 
 #include <AssertMacros.h>
 #include <stdint.h>
+#include "SOSAccountTesting.h"
 
-__unused static bool SOSCircleHandleCircleWithLock(SOSEngineRef engine, CFStringRef myID, CFDataRef message, CFErrorRef *error) {
-
-    CFMutableArrayRef trustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-    CFMutableArrayRef untrustedPeers = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-    CFStringRef peerID = NULL;
-    const uint8_t expected[20] =  { 0xea, 0x6c, 0x01, 0x4d,
-        0xc7, 0x2d, 0x6f, 0x8c,
-        0xcd, 0x1e, 0xd9, 0x2a,
-        0xce, 0x1d, 0x41, 0xf0,
-        0xd8, 0xde, 0x89, 0x57 };
-
-    const char resultSize = sizeof(expected);
-
-    CFDataRef coder = CFDataCreate(kCFAllocatorDefault, expected, resultSize);
-    CFArrayForEachC(SOSEngineGetPeerIDs(engine), peerID){
-        CFArrayAppendValue(trustedPeers, peerID);
-    };
-    CFReleaseNull(coder);
-
-    CFShow(trustedPeers);
-    // all trusted
-    SOSEngineCircleChanged(engine, myID,trustedPeers, untrustedPeers);
-
-    // make first peer untrusted
-    peerID = (CFStringRef)CFArrayGetValueAtIndex(trustedPeers, 0);
-    CFArrayAppendValue(untrustedPeers, peerID);
-    CFArrayRemoveAllValue(trustedPeers, peerID);
-    //we should see peerState cleared out except for the coder!
-    SOSEngineCircleChanged(engine, myID, trustedPeers, untrustedPeers);
-
-    CFArrayAppendValue(trustedPeers, peerID);
-    CFArrayRemoveAllValue(untrustedPeers, peerID);
-
-
-    return true;
-}
+#if SOS_ENABLED
 
 static void testsync3(const char *name,  const char *test_directive, const char *test_reason) {
     __block int iteration=0;
@@ -163,8 +129,6 @@ static void testsync(const char *name,  const char *test_directive, const char *
                               }
                               }
                               CFReleaseSafe(messageDigestStr);
-                              //SOSCircleHandleCircleWithLock(source->ds->engine, SOSEngineGetMyID(source->ds->engine), CFDataCreate(kCFAllocatorDefault, 0, 0), NULL);
-
                           }
                           return false;
                       }, CFSTR("alice"), CFSTR("bob"), NULL);
@@ -503,15 +467,17 @@ SKIP:
     testsyncmany("v2syncmany", test_directive, test_reason, 9, 10, 2, syncmany_add);
     testsync2p();
 }
+#endif
 
 int secd_70_engine(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(1172);
-
     /* custom keychain dir */
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     synctests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 88735ab4208836c0b009b3dc057f1e7e49fccb33..d391742c6f80ccf7ff8c801202ff477f094b2a13 100644 (file)
@@ -48,6 +48,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 
 static void RegressionsLogError(CFErrorRef error) {
@@ -180,14 +181,16 @@ static void tests(void)
     CFReleaseNull(bobSideSession);
     CFReleaseNull(testError);
 }
+#endif
 
 int secd_70_otr_remote(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 1f9eabf165e80124d38627c873c7aae3932d3674..5c7f8efa76d5c5f71378f51274cabcdece512361 100644 (file)
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecIOFormat.h>
 #include <utilities/SecFileLocations.h>
+#include "SOSAccountTesting.h"
 
 #include <AssertMacros.h>
 #include <stdint.h>
+#if SOS_ENABLED
 
 static int kTestTestCount = 8;
 
@@ -180,12 +182,15 @@ static void testSaveRestore(void) {
     CFReleaseSafe(testDevices);
     CFReleaseSafe(error);
 }
-                                                                                        
+#endif
+
 int secd_71_engine_save(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     testSaveRestore();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index d814afdff269a07e7eacd27cd8ce0a129ad725b6..8ed3a5a68fb96ed186d391606465d65e51878a90 100644 (file)
@@ -25,6 +25,9 @@
 #include "keychain/SecureObjectSync/Regressions/SOSTestDevice.h"
 #include "secd_regressions.h"
 #include "SecdTestKeychainUtilities.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 static int kTestTestCount = 646;
 
@@ -79,15 +82,17 @@ static void beer_servers(void) {
     CFRelease(objectNames);
     CFRelease(itemData);
 }
+#endif
 
 int secd_74_engine_beer_servers(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-
     /* custom keychain dir */
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-
     beer_servers();
-
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 6e65d3c33b9e5f7f36a2ac155fe5d1f6ae2051fb..10c50ff1cdb48588f69c747fbb6d0392562b3456 100644 (file)
@@ -27,6 +27,9 @@
 #include "SecdTestKeychainUtilities.h"
 #include <utilities/SecCFWrappers.h>
 #include "keychain/SecureObjectSync/SOSPeer.h"
+#include "SOSAccountTesting.h"
+
+#if SOS_ENABLED
 
 static int kTestTestCount = 53;
 
@@ -115,15 +118,16 @@ static void test_engine_views(void) {
     CFReleaseNull(objectNames);
     CFReleaseNull(itemData);
 }
+#endif
 
 int secd_75_engine_views(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
-    /* custom keychain dir */
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     test_engine_views();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 57bc8d44ef5ccccdd7714c95a862cba6e25194a0..0f73e0ffcfcdcdf3b69a39d722849e2fec2420ac 100644 (file)
@@ -37,6 +37,7 @@
 #include "secd_regressions.h"
 #include "SOSAccountTesting.h"
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) {
     CFErrorRef error = NULL;
@@ -94,12 +95,17 @@ static void alwaysOnTest()
     
     SOSTestCleanup();
 }
+#endif
 
 int secd_80_views_alwayson(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(35);
     secd_test_clear_testviews();
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     alwaysOnTest();
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index db10961baf0ff63654dbd59fd90632707271953d..a1e38ca1ce67c98deb11c724628af3aebaabd183 100644 (file)
@@ -54,6 +54,7 @@
 #include "keychain/securityd/SOSCloudCircleServer.h"
 #include "SecdTestKeychainUtilities.h"
 #include "SOSAccountTesting.h"
+#if SOS_ENABLED
 
 
 static void testView(SOSAccount* account, SOSViewResultCode expected, CFStringRef view, SOSViewActionCode action, char *label) {
@@ -143,10 +144,10 @@ static void tests(void)
     testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected view capability for kSOSViewKeychainV0");
     testView(account, kSOSCCViewMember, kSOSViewAppleTV, kSOSCCViewQuery, "Expected view capability for kSOSViewAppleTV");
 
-    ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0");
+    ok([account.trust updateViewSets:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet], "Expect not accepting kSOSKeychainV0");
     testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0");
 
-    ok([account.trust updateViewSetsWithAnalytics:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet parentEvent: NULL], "Expect not accepting kSOSKeychainV0");
+    ok([account.trust updateViewSets:account enabled:SOSViewsGetV0ViewSet() disabled:nullSet], "Expect not accepting kSOSKeychainV0");
     testView(account, kSOSCCViewNotMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected no addition of kSOSKeychainV0");
 
     SOSPeerInfoRef pi = account.peerInfo;
@@ -155,10 +156,10 @@ static void tests(void)
     
     ok(vr == kSOSCCViewMember, "Set Virtual View manually");
     
-    ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0");
+    ok(![account.trust updateViewSets:account enabled:nullSet disabled:SOSViewsGetV0ViewSet()], "Expect not removing kSOSKeychainV0");
     testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there");
     
-    ok(![account.trust updateViewSetsWithAnalytics:account enabled:nullSet disabled:SOSViewsGetV0ViewSet() parentEvent: NULL], "Expect not removing kSOSKeychainV0");
+    ok(![account.trust updateViewSets:account enabled:nullSet disabled:SOSViewsGetV0ViewSet()], "Expect not removing kSOSKeychainV0");
     testView(account, kSOSCCViewMember, kSOSViewKeychainV0, kSOSCCViewQuery, "Expected kSOSKeychainV0 is still there");
    
     SOSDataSourceRelease(test_source, NULL);
@@ -166,15 +167,18 @@ static void tests(void)
 
     SOSTestCleanup();
 }
+#endif
 
 int secd_80_views_basic(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(kTestTestCount);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
     secd_test_clear_testviews();
     testViewLists();
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 30eddba5fcb0771b2366af8186734567f8874c66..4a8aa0b9b5f7d1eb897c6d6bfb2b1f4d90f12a17 100644 (file)
@@ -465,6 +465,25 @@ static void item_with_skip_auth_ui(uint32_t *item_num)
     CFRelease(item);
 }
 
+#if LA_CONTEXT_IMPLEMENTED
+static void item_forbidden_delete(uint32_t *item_num) {
+    CFMutableDictionaryRef item = CFDictionaryCreateMutableForCFTypesWith(kCFAllocatorDefault, kSecClass, kSecClassInternetPassword, NULL);
+    fillItem(item, (*item_num)++);
+
+    SecAccessControlRef aclRef = SecAccessControlCreate(kCFAllocatorDefault, NULL);
+    ok(aclRef, "Create SecAccessControlRef");
+    ok(SecAccessControlSetProtection(aclRef, kSecAttrAccessibleAlwaysPrivate, NULL));
+    ok(SecAccessControlAddConstraintForOperation(aclRef, kAKSKeyOpEncrypt, kCFBooleanTrue, NULL));
+
+    CFDictionarySetValue(item, kSecAttrAccessControl, aclRef);
+    ok_status(SecItemAdd(item, NULL), "add undeletable");
+    is_status(SecItemDelete(item), errSecAuthFailed, "delete local - authentication failed");
+
+    CFReleaseNull(aclRef);
+    CFRelease(item);
+}
+#endif
+
 int secd_81_item_acl(int argc, char *const *argv)
 {
     uint32_t item_num = 1;
@@ -479,15 +498,16 @@ int secd_81_item_acl(int argc, char *const *argv)
         SecItemServerSetKeychainKeybag(test_keybag);
     });
 #if TARGET_OS_IPHONE
-    plan_tests(70);
+    plan_tests(75);
 #else
-    plan_tests(29);
+    plan_tests(34);
 #endif
     item_with_skip_auth_ui(&item_num);
     item_with_invalid_acl(&item_num);
     item_with_application_password(&item_num);
     item_with_acl_caused_maxauth(&item_num);
     item_with_akpu(&item_num);
+    item_forbidden_delete(&item_num);
 #else
     plan_tests(3);
     item_with_skip_auth_ui(&item_num);
index a9979d44c8183274ba4739029930e67570cd5627..bb4fe0a57ff31a9e4a759a9cc644ebd64423343a 100644 (file)
@@ -46,7 +46,7 @@
 #include <unistd.h>
 
 #include "secd_regressions.h"
-#include "SOSTestDataSource.h"
+#include "keychain/SecureObjectSync/Regressions/SOSTestDataSource.h"
 
 #include "SOSRegressionUtilities.h"
 #include <utilities/SecCFWrappers.h>
@@ -57,6 +57,7 @@
 #include "SOSAccountTesting.h"
 
 #include "SecdTestKeychainUtilities.h"
+#if SOS_ENABLED
 
 static bool SOSAccountResetCircleToNastyOffering(SOSAccount* account, SecKeyRef userPriv, SOSPeerInfoRef pi, CFErrorRef *error) {
     bool result = false;
@@ -66,7 +67,7 @@ static bool SOSAccountResetCircleToNastyOffering(SOSAccount* account, SecKeyRef
         CFReleaseNull(userPub);
         return result;
     }
-    if(![account.trust ensureFullPeerAvailable:(__bridge CFDictionaryRef)(account.gestalt) deviceID:(__bridge CFStringRef)(account.deviceID) backupKey:(__bridge CFDataRef)(account.backup_key) err:error]){
+    if(![account.trust ensureFullPeerAvailable:account err:error]){
         CFReleaseNull(userPub);
         return result;
     }
@@ -219,14 +220,16 @@ static void tests(void)
     bob_account = nil;
     SOSTestCleanup();
 }
+#endif
 
 int secd_60_account_cloud_exposure(int argc, char *const *argv)
 {
+#if SOS_ENABLED
     plan_tests(41);
-    
     secd_test_setup_temp_keychain(__FUNCTION__, NULL);
-    
     tests();
-    
+#else
+    plan_tests(0);
+#endif
     return 0;
 }
index 422b0cdeb118471e9dfd4821067589b991737d5d..2ad4d9343f3259cb0eaa2f841879333ed498cc91 100644 (file)
@@ -63,11 +63,11 @@ ONE_TEST(secd_64_circlereset)
 ONE_TEST(secd_65_account_retirement_reset)
 ONE_TEST(secd_66_account_recovery)
 ONE_TEST(secd_67_prefixedKeyIDs)
+ONE_TEST(secd_68_fullPeerInfoIntegrity)
 ONE_TEST(secd_70_engine)
 ONE_TEST(secd_70_engine_corrupt)
 ONE_TEST(secd_70_engine_smash)
 ONE_TEST(secd_71_engine_save)
-ONE_TEST(secd_68_ghosts)
 ONE_TEST(secd_155_otr_negotiation_monitor)
 
 DISABLED_ONE_TEST(secd_70_otr_remote)
index 89e1ae5c17efb4b33b65ebd2ce0bf9fd7f208607..ee4768c269c1cf369efc93c03a5dba6580bad386 100644 (file)
@@ -28,6 +28,7 @@
 #import <Security/SecItem.h>
 #import <Security/SecItemPriv.h>
 #import <Foundation/NSXPCConnection_Private.h>
+#import <Security/SecXPCHelper.h>
 
 NSString* kSecEntitlementKeychainControl = @"com.apple.private.keychain.keychaincontrol";
 
@@ -75,9 +76,11 @@ XPC_RETURNS_RETAINED xpc_endpoint_t SecServerCreateKeychainControlEndpoint(void)
         return NO;
     }
 
+    NSSet<Class>* errorClasses = [SecXPCHelper safeErrorClasses];
+
     NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainControl)];
-    [interface setClass:[NSError class] forSelector:@selector(rpcFindCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES];
-    [interface setClass:[NSError class] forSelector:@selector(rpcDeleteCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcFindCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcDeleteCorruptedItemsWithReply:) argumentIndex:1 ofReply:YES];
     newConnection.exportedInterface = interface;
     newConnection.exportedObject = self;
     [newConnection resume];
index fb9c07b2cbd01e4c822bd92c5954be6efe3bfa36..c37085a15a1db927c5177b38374b8f71c93e8717 100644 (file)
@@ -37,6 +37,7 @@
 #import "SecTask.h"
 #import "keychain/categories/NSError+UsefulConstructors.h"
 #import "SecEntitlements.h"
+#import <Security/SecXPCHelper.h>
 #import <SecurityFoundation/SFKeychain.h>
 #import <SecurityFoundation/SFCredential_Private.h>
 #import <SecurityFoundation/SFCredentialStore_Private.h>
@@ -104,6 +105,16 @@ static NSString* const SFCredentialSecretPassword = @"password";
 
     // wait a bit for shared function from SecurityFoundation to get to SDK, then addopt that
     NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainServerProtocol)];
+
+    NSSet<Class> *errorClasses = [SecXPCHelper safeErrorClasses];
+
+    [interface setClasses:errorClasses forSelector:@selector(rpcAddCredential:withAccessPolicy:reply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcFetchPasswordCredentialForPersistentIdentifier:reply:) argumentIndex:2 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcRemoveCredentialWithPersistentIdentifier:reply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcReplaceOldCredential:withNewCredential:reply:) argumentIndex:1 ofReply:YES];
+    [interface setClasses:errorClasses forSelector:@selector(rpcReplaceCredential:withNewCredential:reply:) argumentIndex:1 ofReply:YES];
+
     [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFServiceIdentifier class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:NO];
     [interface setClasses:[NSSet setWithObjects:[NSArray class], [SFPasswordCredential class], nil] forSelector:@selector(rpcLookupCredentialsForServiceIdentifiers:reply:) argumentIndex:0 ofReply:YES];
     newConnection.exportedInterface = interface;
index 0bb84b8be754b8f7c7ddb3f2d57e7380b3b0bf49..1c249e86bfdf584c69231a615b352ff89344f254 100644 (file)
@@ -35,24 +35,24 @@ __BEGIN_DECLS
 //
 // MARK: Server versions of our SPI
 //
+
 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error);
 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error);
 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error);
-bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error);
 
 bool SOSCCCanAuthenticate_Server(CFErrorRef *error);
 bool SOSCCPurgeUserCredentials_Server(CFErrorRef *error);
 
 SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error);
 bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error);
-bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error);
 bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error);
-bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error);
 
 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error);
-bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error);
 bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error);
-bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error);
+
+// This will async off the notification, so it does not return a value.
+void SOSCCNotifyLoggedIntoAccount_Server(void);
+
 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error);
 bool SOSCCBailFromCircle_Server(uint64_t limit_in_seconds, CFErrorRef* error);
 
@@ -75,12 +75,10 @@ CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error);
 bool SOSCCAccountSetToNew_Server(CFErrorRef *error);
 bool SOSCCResetToOffering_Server(CFErrorRef* error);
 bool SOSCCResetToEmpty_Server(CFErrorRef* error);
-bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error);
 
 CFBooleanRef SOSCCPeersHaveViewsEnabled_Server(CFArrayRef viewNames, CFErrorRef *error);
 
 SOSViewResultCode SOSCCView_Server(CFStringRef view, SOSViewActionCode action, CFErrorRef *error);
-bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent);
 bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews);
 
 enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error);
@@ -95,7 +93,6 @@ SOSPeerInfoRef SOSCCSetNewPublicBackupKey_Server(CFDataRef newPublicBackup, CFEr
 bool SOSCCRegisterSingleRecoverySecret_Server(CFDataRef backupSlice, bool setupV0Only, CFErrorRef *error);
 
 bool SOSCCWaitForInitialSync_Server(CFErrorRef*);
-bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error);
 
 //
 // MARK: Internal kicks.
@@ -172,10 +169,21 @@ void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataR
                                         CFDataRef signingPublicKey, CFDataRef encryptionPublicKey,
                                         SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef,
                                         void (^action)(CFErrorRef error));
+void SOSCCPerformPreloadOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey,
+                                         SecKeyRef octagonSigningFullKeyRef, SecKeyRef octagonEncryptionFullKeyRef,
+                                         SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef,
+                                         void (^action)(CFErrorRef error));
+
+bool SOSCCSetCKKS4AllStatus(bool status, CFErrorRef* error);
 
 void SOSCCResetOTRNegotiation_Server(CFStringRef peerid);
 void SOSCCPeerRateLimiterSendNextMessage_Server(CFStringRef peerid, CFStringRef accessGroup);
 
+#if __OBJC2__
+bool SOSCCSaveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, __unused int keySize, SecKeyRef octagonPublicKey, NSError** error);
+void SOSCCEnsureAccessGroupOfKey(SecKeyRef publicKey, NSString* oldAgrp, NSString* newAgrp);
+#endif
+
 __END_DECLS
 
 #endif
index ae3a447d29043fb64a46874f18c3a297384524d7..1a336f805d4aacfca9f43157f9fffe2b037c46cd 100644 (file)
@@ -55,7 +55,7 @@
 #import "keychain/SigninMetrics/OctagonSignPosts.h"
 #import "NSError+UsefulConstructors.h"
 
-#include <utilities/SecADWrapper.h>
+#import "utilities/SecCoreAnalytics.h"
 #include <utilities/SecCFWrappers.h>
 #include <utilities/SecCFRelease.h>
 
@@ -71,7 +71,6 @@
 #include <corecrypto/ccec.h>
 #include <corecrypto/ccdigest.h>
 #include <corecrypto/ccsha2.h>
-#include <CommonCrypto/CommonRandomSPI.h>
 #include <Security/SecKeyPriv.h>
 #include <Security/SecFramework.h>
 
@@ -224,7 +223,7 @@ exit:
 
 static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_gestalt)
 {
-    secdebug("account", "Created account");
+    secdebug("account", "Create account for UID %d  EUID %d", getuid(), geteuid());
 
     CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
     SOSAccount* account = NULL;
@@ -244,7 +243,7 @@ static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_ges
         if (account){
             [account.trust updateGestalt:account newGestalt:our_gestalt];
         } else {
-            secerror("Got error inflating account: %@", inflationError);
+            secnotice("account", "Got error inflating account: %@", inflationError);
         }
 
     }
@@ -254,10 +253,10 @@ static SOSAccount* SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_ges
         account = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
 
         if (!account)
-            secerror("Got NULL creating account");
+            secnotice("account", "Got NULL creating account");
     }
 
-    //[account startStateMachine];
+    [account startStateMachine];
 
 done:
     CFReleaseNull(savedAccount);
@@ -466,7 +465,7 @@ static SOSAccount* GetSharedAccount(bool onlyIfItExists) {
     dispatch_once(&onceToken, ^{
         secdebug("account", "Account Creation start");
 
-        CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+        CFDictionaryRef gestalt = CreateDeviceGestaltDictionaryAndRegisterForUpdate(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), NULL);
 
         if (!gestalt) {
 #if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR
@@ -496,7 +495,7 @@ static SOSAccount* GetSharedAccount(bool onlyIfItExists) {
             // TODO: Figure out why peer_additions isn't right in some cases (like when joining a v2 circle with a v0 peer.
             if (CFSetGetCount(peer_additions) != 0) {
                 secnotice("updates", "Requesting Ensure Peer Registration.");
-                SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+                SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), NULL);
             } else {
                 secinfo("updates", "Not requesting Ensure Peer Registration, since it's not needed");
             }
@@ -565,7 +564,7 @@ static SOSAccount* GetSharedAccount(bool onlyIfItExists) {
             }
         };
         // TODO: We should not be doing extra work whenever securityd is launched, let's see if we can eliminate this call
-        SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+        SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(SOS_ACCOUNT_PRIORITY, 0), NULL);
  
         // provide state handler to sysdiagnose and logging
         os_state_add_handler(dispatch_get_global_queue(0, 0), accountStateBlock);
@@ -686,6 +685,7 @@ static bool do_with_account_while_unlocked(CFErrorRef *error, bool (^action)(SOS
             // Get ramp settings from the Cloud
             if(ghostbustnow) {
                 gbOptions = [SOSAccount  ghostBustGetRampSettings];
+                gbOptions += SOSGhostBustiCloudIdentities;
             }
         }
 #endif
@@ -818,22 +818,16 @@ SOSViewResultCode SOSCCView_Server(CFStringRef viewname, SOSViewActionCode actio
     return status;
 }
 
-bool SOSCCViewSetWithAnalytics_Server(CFSetRef enabledViews, CFSetRef disabledViews, CFDataRef parentEvent) {
-    __block bool status = false;
+bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
     OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCViewSet);
+    __block bool status = false;
 
     do_with_account_if_after_first_unlock(NULL, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        status = [txn.account.trust updateViewSetsWithAnalytics:txn.account enabled:enabledViews disabled:disabledViews parentEvent:(__bridge NSData*)parentEvent];
+        status = [txn.account.trust updateViewSets:txn.account enabled:enabledViews disabled:disabledViews];
         return true;
     });
     OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCViewSet, OctagonSignpostNumber1(SOSSignpostNameSOSCCViewSet), (int)status);
-    return status;
-}
-
-
-bool SOSCCViewSet_Server(CFSetRef enabledViews, CFSetRef disabledViews) {
-    return SOSCCViewSetWithAnalytics_Server(enabledViews, disabledViews, NULL);
-}
+    return status;}
 
 
 void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchronization){
@@ -844,7 +838,7 @@ void sync_the_last_data_to_kvs(CFTypeRef account, bool waitForeverForSynchroniza
 
     secnoticeq("force-push", "calling SOSCloudKeychainSynchronizeAndWait");
 
-    SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
+    SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
         if (sync_error) {
             secerrorq("SOSCloudKeychainSynchronizeAndWait: %@", sync_error);
             localError = sync_error;
@@ -877,7 +871,7 @@ static bool SyncKVSAndWait(CFErrorRef *error) {
     secnoticeq("fresh", "EFP calling SOSCloudKeychainSynchronizeAndWait");
 
     os_activity_initiate("CloudCircle EFRESH", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
-        SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
+        SOSCloudKeychainSynchronizeAndWait(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(__unused CFDictionaryRef returnedValues, CFErrorRef sync_error) {
             secnotice("fresh", "EFP returned, callback error: %@", sync_error);
 
             success = (sync_error == NULL);
@@ -904,7 +898,7 @@ static bool Flush(CFErrorRef *error) {
     dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
     secnotice("flush", "Starting");
 
-    SOSCloudKeychainFlush(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
+    SOSCloudKeychainFlush(dispatch_get_global_queue(SOS_TRANSPORT_PRIORITY, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
         success = (sync_error == NULL);
         if (error) {
             CFRetainAssign(*error, sync_error);
@@ -923,134 +917,102 @@ static bool Flush(CFErrorRef *error) {
 }
 
 bool SOSCCTryUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
+    __block bool result = false;
     secnotice("updates", "Trying credentials and dsid (%@) for %@", dsid, user_label);
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCTryUserCredentials);
+    
+    dispatch_sync(SOSCCCredentialQueue(), ^{
+        OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCTryUserCredentials);
+
+        // Try the password with no EFRESH - attempting to get through this faster for rdar://problem/57242044
+        result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
+            bool retval = false;
+            if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
+                SOSAccountAssertDSID(txn.account, dsid);
+            }
+            if(txn.account.accountKeyDerivationParameters) {
+                retval = SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
+            }
+            return retval;
+        });
 
-    bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
-            SOSAccountAssertDSID(txn.account, dsid);
+        // If that fails - either lacking parameters to begin with or failed to construct the correct key try with EFRESH
+        if(result == false) {
+            if(SyncKVSAndWait(error) && Flush(error)) {
+                result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
+                    return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
+                });
+            }
         }
-        return true;
-    });
 
-    require_quiet(result, done);
-
-    require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
-    require_quiet(Flush(error), done);          // And processed it already...before asserting
-
-    result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
-        return SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
+        // if either key constructions passed do a flush to bring through anything we weren't "interested" in before.
+        if(result) {
+            Flush(error);
+        }
+        OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCTryUserCredentials, OctagonSignpostNumber1(SOSSignpostNameSOSCCTryUserCredentials), (int)result);
     });
-
-    require_quiet(result, done);
-    require_quiet(Flush(error), done);
-
-done:
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCTryUserCredentials, OctagonSignpostNumber1(SOSSignpostNameSOSCCTryUserCredentials), (int)result);
-
     return result;
 }
 
-static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, NSData* parentEvent, CFErrorRef *error) {
+static bool SOSCCAssertUserCredentialsAndOptionalDSID(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error) {
+    __block bool result = false;
     secnotice("updates", "Setting credentials and dsid (%@) for %@", dsid, user_label);
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID);
-
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = nil;
-
-    if(parentEvent) {
-        parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:parentEvent error:&localError];
-    }
-
-    SFSignInAnalytics *syncAndWaitEvent = nil;
-    SFSignInAnalytics *flushEvent = nil;
-    SFSignInAnalytics *secondFlushEvent = nil;
-    SFSignInAnalytics *generationSignatureUpdateEvent = nil;
-
-    bool result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
-            SOSAccountAssertDSID(txn.account, dsid);
+    
+    dispatch_sync(SOSCCCredentialQueue(), ^{
+        OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameAssertUserCredentialsAndOptionalDSID);
+        
+        // Shortcut if we're talking to the same account and can construct the same trusted key
+        result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
+            bool retval = false;
+            CFStringRef accountDSID = SOSAccountGetValue(txn.account, kSOSDSIDKey, NULL);
+            if(CFEqualSafe(accountDSID, dsid) && txn.account.accountKeyDerivationParameters && txn.account.accountKeyIsTrusted) {
+                retval = SOSAccountTryUserCredentials(txn.account, user_label, user_password, block_error);
+            }
+            return retval;
+        });
+        if(result) {
+            return; // shortcut to not do the following work if we're duping a setcreds operation.
         }
-        return true;
-    });
-
-    require_quiet(result, done);
 
-    if(parent) {
-        syncAndWaitEvent = [parent newSubTaskForEvent:@"syncAndWaitEvent"];
-    }
-    require_quiet(SyncKVSAndWait(error), done); // Make sure we've seen what the server has
-    if(syncAndWaitEvent) {
-        [syncAndWaitEvent stopWithAttributes:nil];
-    }
+        result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
+            if (dsid != NULL && CFStringCompare(dsid, CFSTR(""), 0) != 0) {
+                SOSAccountAssertDSID(txn.account, dsid);
+            }
+            return true;
+        });
 
-    if(parent) {
-        flushEvent = [parent newSubTaskForEvent:@"flushEvent"];
-    }
-    require_quiet(Flush(error), done);          // And processed it already...before asserting
-    if(flushEvent) {
-        [flushEvent stopWithAttributes:nil];
-    }
+        if(result && SyncKVSAndWait(error) && Flush(error)) {
+            result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
+                return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
+            });
+        }
 
-    result = do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *block_error) {
-        return SOSAccountAssertUserCredentials(txn.account, user_label, user_password, block_error);
-    });
+        // if either key constructions passed do a flush to bring through anything we weren't "interested" in before.
+        if(result) {
+            Flush(error);
+        }
 
-    require_quiet(result, done);
-    if(parent) {
-        secondFlushEvent = [parent newSubTaskForEvent:@"secondFlushEvent"];
-    }
-    require_quiet(Flush(error), done); // Process any incoming information..circles et.al. before fixing our signature
-    if(secondFlushEvent) {
-        [secondFlushEvent stopWithAttributes:nil];
-    }
+        result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
+            return SOSAccountGenerationSignatureUpdate(txn.account, error);
+        });
+        
+        secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@",
+                  dsid, user_label, result, error ? *error : NULL);
 
-    if(parent) {
-        generationSignatureUpdateEvent = [parent newSubTaskForEvent:@"generationSignatureUpdateEvent"];
-    }
-    result = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        return SOSAccountGenerationSignatureUpdate(txn.account, error);
+        OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result);
     });
 
-    if(generationSignatureUpdateEvent) {
-        [generationSignatureUpdateEvent stopWithAttributes:nil];
-    }
-
-done:
-    if(syncAndWaitEvent){
-        [syncAndWaitEvent stopWithAttributes:nil];
-    }
-    if(flushEvent){
-        [flushEvent stopWithAttributes:nil];
-    }
-    if(secondFlushEvent){
-        [secondFlushEvent stopWithAttributes:nil];
-    }
-    if(generationSignatureUpdateEvent){
-        [generationSignatureUpdateEvent stopWithAttributes:nil];
-    }
-    secnotice("updates", "Complete credentials and dsid (%@) for %@: %d %@",
-              dsid, user_label, result, error ? *error : NULL);
-
-    OctagonSignpostEnd(signPost, SOSSignpostNameAssertUserCredentialsAndOptionalDSID, OctagonSignpostNumber1(SOSSignpostNameAssertUserCredentialsAndOptionalDSID), (int)result);
-
     return result;
 }
 
 bool SOSCCSetUserCredentialsAndDSID_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFErrorRef *error)
 {
     // TODO: Return error if DSID is NULL to insist our callers provide one?
-    return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, nil, error);
-}
-
-bool SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server(CFStringRef user_label, CFDataRef user_password, CFStringRef dsid, CFDataRef parentEvent, CFErrorRef *error)
-{
-    return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, (__bridge NSData*)parentEvent, error);
+    return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, dsid, error);
 }
 
 bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
 {
-    return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, nil, error);
+    return SOSCCAssertUserCredentialsAndOptionalDSID(user_label, user_password, NULL, error);
 }
 
 bool SOSCCCanAuthenticate_Server(CFErrorRef *error)
@@ -1095,24 +1057,19 @@ SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
     }) ? status : kSOSCCError;
 }
 
-bool SOSCCRequestToJoinCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
+bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
 {
     __block bool result = true;
     OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircle);
 
     bool requested = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        result = SOSAccountJoinCircles(txn, (__bridge NSData*)parentEvent, block_error);
+        result = SOSAccountJoinCircles(txn, block_error);
         return result;
     });
     OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircle), (int)requested);
     return requested;
 }
 
-bool SOSCCRequestToJoinCircle_Server(CFErrorRef* error)
-{
-    return SOSCCRequestToJoinCircleWithAnalytics_Server(nil, error);
-}
-
 bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error)
 {
     __block bool result = true;
@@ -1129,45 +1086,24 @@ bool SOSCCAccountHasPublicKey_Server(CFErrorRef *error)
     return hasPublicKey;
 }
 
-bool SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
+bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
 {
     __block bool result = true;
     bool returned = false;
     OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore);
     returned = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        NSError* localError = nil;
-        SFSignInAnalytics* parent = nil;
-        SFSignInAnalytics *ensurePeerRegistrationEvent = nil;
-        
-        if(parentEvent) {
-            parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
-            ensurePeerRegistrationEvent = [parent newSubTaskForEvent:@"ensurePeerRegistrationEvent"];
-        }
-
         SOSAccountEnsurePeerRegistration(txn.account, block_error);
         if(block_error && *block_error){
             NSError* blockError = (__bridge NSError*)*block_error;
-            if(blockError){
-                if(ensurePeerRegistrationEvent) {
-                    [ensurePeerRegistrationEvent logRecoverableError:blockError];
-                }
+            if (blockError) {
                 secerror("ensure peer registration error: %@", blockError);
             }
         }
-        if(ensurePeerRegistrationEvent) {
-            [ensurePeerRegistrationEvent stopWithAttributes:nil];
-        }
-        result = SOSAccountJoinCirclesAfterRestore(txn, (__bridge NSData*)parentEvent, block_error);
+        result = SOSAccountJoinCirclesAfterRestore(txn, block_error);
         return result;
     });
     OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestToJoinCircleAfterRestore), (int)result);
     return returned;
-
-}
-
-bool SOSCCRequestToJoinCircleAfterRestore_Server(CFErrorRef* error)
-{
-    return SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server(nil, error);
 }
 
 bool SOSCCAccountSetToNew_Server(CFErrorRef *error)
@@ -1213,36 +1149,6 @@ bool SOSCCResetToEmpty_Server(CFErrorRef* error)
     return resetResult;
 }
 
-bool SOSCCResetToEmptyWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
-{
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCResetToEmpty);
-
-    bool resetResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        bool result = false;
-
-        if (!SOSAccountHasPublicKey(txn.account, error)) {
-            return result;
-        }
-        result =  [txn.account.trust resetAccountToEmptyWithAnalytics:txn.account transport:txn.account.circle_transport parentEvent:(__bridge NSData*)parentEvent err:block_error];
-        return result;
-    });
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCResetToEmpty, OctagonSignpostNumber1(SOSSignpostNameSOSCCResetToEmpty), (int)resetResult);
-    return resetResult;
-}
-
-bool SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error)
-{
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
-
-    bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        bool result = [txn.account.trust leaveCircleWithAccount:txn.account withAnalytics:(__bridge NSData*)parentEvent err:error];
-        return result;
-    });
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemoveThisDeviceFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle), (int)removeResult);
-
-    return removeResult;
-}
-
 bool SOSCCRemoveThisDeviceFromCircle_Server(CFErrorRef* error)
 {
     OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemoveThisDeviceFromCircle);
@@ -1260,23 +1166,29 @@ bool SOSCCRemovePeersFromCircle_Server(CFArrayRef peers, CFErrorRef* error)
     OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
 
     bool removeResult =  do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, nil, block_error);
+        bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, block_error);
         return result;
     });
     OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
     return removeResult;
 }
 
-bool SOSCCRemovePeersFromCircleWithAnalytics_Server(CFArrayRef peers, CFDataRef parentEvent, CFErrorRef* error)
-{
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCRemovePeersFromCircle);
+void SOSCCNotifyLoggedIntoAccount_Server() {
+    // This call is mixed in with SOSCCSetUserCredentialsAndDSID calls from our accountsd plugin
+    dispatch_async(SOSCCCredentialQueue(), ^{
+        CFErrorRef error = NULL;
+        bool loggedInResult = do_with_account_while_unlocked(&error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
+            secinfo("circleOps", "Signed into account!");
+            txn.account.accountIsChanging = false; // we've changed
+            return true;
+        });
 
-    bool removeResult = do_with_account_while_unlocked(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        bool result = SOSAccountRemovePeersFromCircle(txn.account, peers, (__bridge NSData*)parentEvent, block_error);
-        return result;
+        if(!loggedInResult || error != NULL) {
+            secerror("circleOps: error delivering account-sign-in notification: %@", error);
+        }
+
+        CFReleaseNull(error);
     });
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRemovePeersFromCircle, OctagonSignpostNumber1(SOSSignpostNameSOSCCRemovePeersFromCircle), (int)removeResult);
-    return removeResult;
 }
 
 bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
@@ -1296,7 +1208,7 @@ bool SOSCCLoggedOutOfAccount_Server(CFErrorRef *error)
         sync_the_last_data_to_kvs((__bridge CFTypeRef)(txn.account), waitForeverForSynchronization);
 
         SOSAccountSetToNew(txn.account);
-
+        txn.account.accountIsChanging = true;
 
         return result;
     });
@@ -1459,99 +1371,6 @@ static uint64_t initialSyncTimeoutFromDefaultsWrite(void)
     return timeout;
 }
 
-bool SOSCCWaitForInitialSyncWithAnalytics_Server(CFDataRef parentEvent, CFErrorRef* error) {
-    __block dispatch_semaphore_t inSyncSema = NULL;
-    __block bool result = false;
-    __block bool synced = false;
-    bool timed_out = false;
-    __block CFStringRef inSyncCallID = NULL;
-    __block time_t start;
-    __block CFBooleanRef shouldUseInitialSyncV0 = false;
-    SFSignInAnalytics* syncingEvent = nil;
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCWaitForInitialSync);
-
-    NSError* localError = nil;
-    SFSignInAnalytics* parent = [NSKeyedUnarchiver unarchivedObjectOfClass:[SFSignInAnalytics class] fromData:(__bridge NSData*)parentEvent error:&localError];
-
-    secnotice("initial sync", "Wait for initial sync start!");
-
-    result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountTransaction* txn, CFErrorRef* block_error) {
-        shouldUseInitialSyncV0 = (CFBooleanRef)SOSAccountGetValue(txn.account, kSOSInitialSyncTimeoutV0, error);
-        bool alreadyInSync = (SOSAccountHasCompletedInitialSync(txn.account));
-
-        if (!alreadyInSync) {
-            start = time(NULL);
-            inSyncSema = dispatch_semaphore_create(0);
-
-            SFSignInAnalytics* callWhenInSyncEvent = [parent newSubTaskForEvent:@"callWhenInSync"];
-            inSyncCallID = SOSAccountCallWhenInSync(txn.account, ^bool(SOSAccount* mightBeSynced) {
-                synced = true;
-
-                if(inSyncSema){
-                    dispatch_semaphore_signal(inSyncSema);
-                    NSDictionary* attributes = @{@"finishedSyncing" : @YES};
-                    [syncingEvent stopWithAttributes:attributes];
-                }
-                return true;
-            });
-            NSDictionary* attributes = @{};
-            [callWhenInSyncEvent stopWithAttributes:attributes];
-        }
-        else{
-            synced = true;
-        }
-        return true;
-    });
-
-    require_quiet(result, fail);
-
-
-    if(inSyncSema){
-        syncingEvent = [parent newSubTaskForEvent:@"initialSyncEvent"];
-        if(shouldUseInitialSyncV0){
-            secnotice("piggy","setting initial sync timeout to 5 minutes");
-            timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, 300ull * NSEC_PER_SEC));
-        }
-        else{
-            uint64_t timeoutFromDefaultsWrite = initialSyncTimeoutFromDefaultsWrite();
-            secnotice("piggy","setting initial sync timeout to %llu seconds", timeoutFromDefaultsWrite);
-            timed_out = dispatch_semaphore_wait(inSyncSema, dispatch_time(DISPATCH_TIME_NOW, timeoutFromDefaultsWrite * NSEC_PER_SEC));
-        }
-    }
-    if (timed_out && shouldUseInitialSyncV0) {
-        do_with_account(^(SOSAccountTransaction* txn) {
-            if (SOSAccountUnregisterCallWhenInSync(txn.account, inSyncCallID)) {
-                if(inSyncSema){
-                    inSyncSema = NULL; // We've canceled the timeout so we must be the last.
-                }
-            }
-        });
-        NSError* error = [NSError errorWithDomain:@"securityd" code:errSecTimedOut userInfo:@{NSLocalizedDescriptionKey: @"timed out waiting for initial sync"}];
-        [syncingEvent logUnrecoverableError:error];
-        NSDictionary* attributes = @{@"finishedSyncing" : @NO, @"legacyPiggybacking" : @YES};
-        [syncingEvent stopWithAttributes:attributes];
-    }
-
-    require_quiet(result, fail);
-
-    if(result)
-    {
-        SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
-    }
-    else if(!result)
-    {
-        SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
-    }
-
-    secnotice("initial sync", "Finished!: %d", result);
-
-fail:
-    CFReleaseNull(inSyncCallID);
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCWaitForInitialSync, OctagonSignpostNumber1(SOSSignpostNameSOSCCWaitForInitialSync), (int)result);
-
-    return result;
-}
-
 bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
     
     __block dispatch_semaphore_t inSyncSema = NULL;
@@ -1611,18 +1430,14 @@ bool SOSCCWaitForInitialSync_Server(CFErrorRef* error) {
             }
         });
     }
-    
-    require_quiet(result, fail);
 
-    if(result)
-    {
-        SecADClientPushValueForDistributionKey(SOSAggdSyncCompletionKey, getTimeDifference(start));
-    }
-    else if(!result)
-    {
-        SecADAddValueForScalarKey(SOSAggdSyncTimeoutKey, 1);
+    if(result) {
+        [SecCoreAnalytics sendEvent:(__bridge id)SOSAggdSyncCompletionKey
+                              event:@{SecCoreAnalyticsValue: [NSNumber numberWithLong:getTimeDifference(start)]}];
+    } else {
+        [SecCoreAnalytics sendEvent:(__bridge id)SOSAggdSyncTimeoutKey
+                              event:@{SecCoreAnalyticsValue: @1}];
     }
-
     secnotice("initial sync", "Finished!: %d", result);
 
 fail:
@@ -1766,20 +1581,87 @@ bool SOSCCProcessEnsurePeerRegistration_Server(CFErrorRef* error)
     return processResult;
 }
 
+static bool internalSyncWithPeers(CFSetRef peers, CFSetRef backupPeers, CFMutableSetRef handled, CFErrorRef *error) {
+    return do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
+        CFSetRef addedResult = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error);
+        CFSetUnion(handled, addedResult);
+        bool retval = (addedResult != NULL);
+        CFReleaseNull(addedResult);
+        return retval;
+    });
+}
+
+#define MAXPEERS 7
+
+static bool SOSCFSubsetOfN(CFSetRef peers, size_t n, CFErrorRef* error, bool (^action)(CFSetRef subset, CFErrorRef* error)) {
+    __block bool retval = true;
+    __block size_t ready = 0;
+    __block CFMutableSetRef subset = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+
+    CFSetForEach(peers, ^(const void *value) {
+        CFSetAddValue(subset, value);
+        ready++;
+        if(ready >= n) {
+            retval &= action(subset, error);
+            ready = 0;
+            CFSetRemoveAllValues(subset);
+        }
+    });
+    if(CFSetGetCount(subset)) {
+        retval &= action(subset, error);
+    }
+    CFReleaseNull(subset);
+    return retval;
+}
+
 CF_RETURNS_RETAINED CFSetRef SOSCCProcessSyncWithPeers_Server(CFSetRef peers, CFSetRef backupPeers, CFErrorRef *error) {
-    __block CFSetRef result = NULL;
-    OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithPeers);
+    static dispatch_queue_t swpQueue = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        swpQueue = dispatch_queue_create("syncWithPeers", DISPATCH_QUEUE_SERIAL);
+    });
+    
+    __block CFMutableSetRef handled = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
+    __block CFSetRef noPeers = CFSetCreateMutable(kCFAllocatorDefault, 0, &kCFTypeSetCallBacks);
 
-    if (!do_with_account_while_unlocked(error, ^bool(SOSAccountTransaction* txn, CFErrorRef *error) {
-        result = SOSAccountProcessSyncWithPeers(txn, peers, backupPeers, error);
-        return result != NULL;
-    })) {
-        // Be sure we don't return a result if we got an error
-        CFReleaseNull(result);
+    if(!peers) {
+        peers = noPeers;
     }
-    OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithPeers), (int)(result != NULL));
 
-    return result;
+    if(!backupPeers) {
+        backupPeers = noPeers;
+    }
+
+    dispatch_sync(swpQueue, ^{
+        OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCProcessSyncWithPeers);
+
+        if((CFSetGetCount(peers) + CFSetGetCount(backupPeers)) < MAXPEERS) {
+            internalSyncWithPeers(peers, backupPeers, handled, error);
+        } else {
+            // sync any backupPeers
+            if(backupPeers && CFSetGetCount(backupPeers)) {
+                SOSCFSubsetOfN(backupPeers, MAXPEERS, error, ^bool(CFSetRef subset, CFErrorRef *error) {
+                    return internalSyncWithPeers(noPeers, subset, handled, error);
+                });
+            }
+
+            // sync any device peers
+            if(peers && CFSetGetCount(peers)) {
+                SOSCFSubsetOfN(peers, MAXPEERS, error, ^bool(CFSetRef subset, CFErrorRef *error) {
+                    return internalSyncWithPeers(subset, noPeers, handled, error);
+                });
+            }
+        }
+
+        OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCProcessSyncWithPeers, OctagonSignpostNumber1(SOSSignpostNameSOSCCProcessSyncWithPeers), (int)(CFSetGetCount(handled) != 0));
+
+        if(CFSetGetCount(handled) == 0) {
+            CFReleaseNull(handled);
+        }
+        CFReleaseNull(noPeers);
+    });
+
+    return handled;
 }
 
 SyncWithAllPeersReason SOSCCProcessSyncWithAllPeers_Server(CFErrorRef* error)
@@ -1856,7 +1738,7 @@ void SOSCCRequestSyncWithPeersList(CFArrayRef /*CFStringRef*/ peerIDs) {
         });
 
         SOSCloudKeychainRequestSyncWithPeers(peerIDs, empty,
-                                             dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+                                             dispatch_get_global_queue(SOS_ENGINE_PRIORITY, 0), NULL);
         CFReleaseNull(empty);
         OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithPeersList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithPeersList), (int)true);
     });
@@ -1873,7 +1755,7 @@ void SOSCCRequestSyncWithBackupPeerList(CFArrayRef /* CFStringRef */ backupPeerI
         });
 
         SOSCloudKeychainRequestSyncWithPeers(empty, backupPeerIDs,
-                                             dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+                                             dispatch_get_global_queue(SOS_ENGINE_PRIORITY, 0), NULL);
 
         CFReleaseNull(empty);
         OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCRequestSyncWithBackupPeerList, OctagonSignpostNumber1(SOSSignpostNameSOSCCRequestSyncWithBackupPeerList), (int)true);
@@ -1889,7 +1771,7 @@ void SOSCCEnsurePeerRegistration(void)
 {
     os_activity_initiate("CloudCircle EnsurePeerRegistration", OS_ACTIVITY_FLAG_DEFAULT, ^(void) {
         OctagonSignpost signPost = OctagonSignpostBegin(SOSSignpostNameSOSCCEnsurePeerRegistration);
-        SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
+        SOSCloudKeychainRequestEnsurePeerRegistration(dispatch_get_global_queue(SOS_ENGINE_PRIORITY, 0), NULL);
         OctagonSignpostEnd(signPost, SOSSignpostNameSOSCCEnsurePeerRegistration, OctagonSignpostNumber1(SOSSignpostNameSOSCCEnsurePeerRegistration), (int)true);
 
     });
@@ -2148,28 +2030,23 @@ void SOSCCPerformWithAllOctagonKeys(void (^action)(SecKeyRef octagonEncryptionKe
     CFReleaseNull(localError);
 }
 
-static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, int keySize, SecKeyRef octagonPublicKey, NSError** error) {
+bool SOSCCSaveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave, __unused int keySize, SecKeyRef octagonPublicKey, NSError** error) {
     NSError* localerror = nil;
 
-    CFDataRef publicKeyHash = SecKeyCopyPublicKeyHash(octagonPublicKey);
 
-    NSMutableDictionary* query = [@{
-                                    (id)kSecClass                   : (id)kSecClassKey,
-                                    (id)kSecAttrKeyType             : (id)kSecAttrKeyTypeEC,
-                                    (id)kSecAttrKeyClass            : (id)kSecAttrKeyClassPrivate,
-                                    (id)kSecAttrAccessGroup         : (id)kSOSInternalAccessGroup,
-                                    (id)kSecAttrLabel               : keyLabel,
-                                    (id)kSecAttrApplicationLabel    : (__bridge NSData*)(publicKeyHash),
-                                    (id)kSecAttrSynchronizable      : (id)kCFBooleanFalse,
-                                    (id)kSecUseDataProtectionKeychain : @YES,
-                                    (id)kSecValueData               : keyDataToSave,
-                                    } mutableCopy];
+    NSMutableDictionary* query = [((NSDictionary*)CFBridgingRelease(SecKeyGeneratePrivateAttributeDictionary(octagonPublicKey,
+                                                                                                             kSecAttrKeyTypeEC,
+                                                                                                             (__bridge CFDataRef)keyDataToSave))) mutableCopy];
+
+    query[(id)kSecAttrLabel] = keyLabel;
+    query[(id)kSecUseDataProtectionKeychain] = @YES;
+    query[(id)kSecAttrSynchronizable] = (id)kCFBooleanFalse;
+    query[(id)kSecAttrAccessGroup] = (id)kSOSInternalAccessGroup;
 
     CFTypeRef result = NULL;
     OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, &result);
 
     if(status == errSecSuccess) {
-        CFReleaseNull(publicKeyHash);
         return true;
     }
     if(status == errSecDuplicateItem) {
@@ -2204,11 +2081,28 @@ static bool saveOctagonKeysToKeychain(NSString* keyLabel, NSData* keyDataToSave,
         *error = localerror;
     }
 
-    CFReleaseNull(publicKeyHash);
-
     return (status == errSecSuccess);
 }
 
+void SOSCCEnsureAccessGroupOfKey(SecKeyRef publicKey, NSString* oldAgrp, NSString* newAgrp)
+{
+    NSData* publicKeyHash = CFBridgingRelease(SecKeyCopyPublicKeyHash(publicKey));
+
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassKey,
+        (id)kSecAttrSynchronizable: (id)kSecAttrSynchronizableAny,
+        (id)kSecAttrApplicationLabel: publicKeyHash,
+        (id)kSecAttrAccessGroup: oldAgrp,
+    };
+
+    OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)query,
+                                    (__bridge CFDictionaryRef)@{
+                                        (id)kSecAttrAccessGroup: newAgrp,
+                                                              });
+
+    secnotice("octagon", "Ensuring key agrp ('%@' from '%@') status: %d", newAgrp, oldAgrp, (int)status);
+};
+
 static NSString* createKeyLabel(NSDictionary *gestalt, NSString* circleName, NSString* prefix)
 {
     NSString *keyName = [NSString stringWithFormat:@"ID for %@-%@",SOSPeerGestaltGetName((__bridge CFDictionaryRef)(gestalt)), circleName];
@@ -2223,18 +2117,19 @@ static NSError* saveKeysToKeychain(SOSAccount* account, NSData* octagonSigningFu
     NSError* saveToKeychainError = nil;
 
     NSString* circleName = (__bridge NSString*)(SOSCircleGetName(account.trust.trustedCircle));
+
     NSString* signingPrefix = @"Octagon Peer Signing ";
     NSString* encryptionPrefix = @"Octagon Peer Encryption ";
     NSString* octagonSigningKeyName = createKeyLabel(account.gestalt, circleName, signingPrefix);
     NSString* octagonEncryptionKeyName = createKeyLabel(account.gestalt, circleName, encryptionPrefix);
 
     /* behavior mimics GeneratePermanentFullECKey_internal */
-    saveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError);
+    SOSCCSaveOctagonKeysToKeychain(octagonSigningKeyName, octagonSigningFullKey, 384, octagonSigningPublicKeyRef, &saveToKeychainError);
     if(saveToKeychainError) {
         secerror("octagon: could not save signing key: %@", saveToKeychainError);
         return saveToKeychainError;
     }
-    saveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError);
+    SOSCCSaveOctagonKeysToKeychain(octagonEncryptionKeyName, octagonEncryptionFullKey, 384, octagonEncryptionPublicKeyRef, &saveToKeychainError);
     if(saveToKeychainError) {
         secerror("octagon: could not save encryption key: %@", saveToKeychainError);
         return saveToKeychainError;
@@ -2290,6 +2185,57 @@ void SOSCCPerformUpdateOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataR
     CFReleaseNull(localError);
 }
 
+void SOSCCPerformPreloadOfAllOctagonKeys(CFDataRef octagonSigningFullKey, CFDataRef octagonEncryptionFullKey,
+                                         SecKeyRef octagonSigningFullKeyRef, SecKeyRef octagonEncryptionFullKeyRef,
+                                         SecKeyRef octagonSigningPublicKeyRef, SecKeyRef octagonEncryptionPublicKeyRef,
+                                         void (^action)(CFErrorRef error))
+{
+    CFErrorRef localError = NULL;
+    do_with_account_if_after_first_unlock(&localError, ^bool(SOSAccountTransaction *txn, CFErrorRef *err) {
+
+        //save octagon key set to the keychain
+        NSError* saveError = nil;
+        saveError = saveKeysToKeychain(txn.account, (__bridge NSData*)octagonSigningFullKey, (__bridge NSData*)octagonEncryptionFullKey,
+                                       octagonSigningPublicKeyRef, octagonEncryptionPublicKeyRef);
+
+        if(saveError) {
+            secerror("octagon-preload-keys: failed to save Octagon keys to the keychain: %@", saveError);
+            action((__bridge CFErrorRef)saveError);
+            return false;
+        }
+
+        //now update the sos account to contain octagon keys
+        if(txn.account){
+            txn.account.octagonSigningFullKeyRef = CFRetainSafe(octagonSigningFullKeyRef);
+            txn.account.octagonEncryptionFullKeyRef = CFRetainSafe(octagonEncryptionFullKeyRef);
+        } else {
+            secnotice("octagon-preload-keys", "No SOSAccount to update?");
+            NSError *noAccountError = [NSError errorWithDomain:(__bridge NSString*)kSOSErrorDomain code:kSOSErrorNoAccount userInfo:@{NSLocalizedDescriptionKey : @"Device has no SOSAccount"}];
+            action((__bridge CFErrorRef)noAccountError);
+            return false;
+        }
+
+        secnotice("octagon-preload-keys", "Success! Octagon Keys Preloaded!");
+
+        action(nil);
+        return true;
+    });
+    CFReleaseNull(localError);
+}
+
+bool SOSCCSetCKKS4AllStatus(bool supports, CFErrorRef* error)
+{
+    CFErrorRef cfAccountError = NULL;
+    bool ret = do_with_account_if_after_first_unlock(&cfAccountError, ^bool(SOSAccountTransaction *txn, CFErrorRef *cferror) {
+        SOSAccountUpdatePeerInfo(txn.account, CFSTR("CKKS4All update"), cferror, ^bool(SOSFullPeerInfoRef fpi, CFErrorRef *blockError) {
+            return SOSFullPeerInfoSetCKKS4AllSupport(fpi, supports, blockError);
+        });
+        return true;
+    });
+    CFErrorPropagate(cfAccountError, error);
+    return ret;
+}
+
 void SOSCCPerformWithTrustedPeers(void (^action)(CFSetRef sosPeerInfoRefs, CFErrorRef error))
 {
     CFErrorRef cfAccountError = NULL;
index 2459ad75874d5199288af57a0f97b60bb7c31a6a..3e6c29a30dff152f86a17eacd2334d4ec0dabc50 100644 (file)
  */
 
 // For now at least, we'll support backups only on iOS and macOS
-#define SECDB_BACKUPS_ENABLED ((TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_IOSMAC) && !TARGET_OS_SIMULATOR && !TARGET_DARWINOS)
+#define SECDB_BACKUPS_ENABLED ((TARGET_OS_OSX || TARGET_OS_IOS || TARGET_OS_MACCATALYST) && !TARGET_OS_SIMULATOR && !TARGET_DARWINOS)
 
 #if __OBJC2__
 #import <Foundation/Foundation.h>
-#if !TARGET_OS_BRIDGE   // Specifically needed until rdar://problem/40583882 lands
 #import <SecurityFoundation/SFKey.h>
-#endif
 #import "SecAKSObjCWrappers.h"
 #import "CheckV12DevEnabled.h"
 
@@ -69,22 +67,20 @@ typedef NS_ENUM(NSInteger, SecDbBackupErrorCode) {
     SecDbBackupTestCodeFailure = 255,     // support code for testing is falling over somehow
 };
 
-@interface SecDbBackupWrappedItemKey : NSObject <NSSecureCoding>
+@interface SecDbBackupWrappedKey : NSObject <NSSecureCoding>
 @property (nonatomic) NSData* wrappedKey;
 @property (nonatomic) NSData* baguuid;
 @end
 
 @interface SecDbBackupManager : NSObject
 
-+ (instancetype)manager;
+// Nullable to make analyzer not complain in the case where the stub returns nil
++ (instancetype _Nullable)manager;
 - (instancetype)init NS_UNAVAILABLE;
 
-#if !TARGET_OS_BRIDGE   // Specifically needed until rdar://problem/40583882 lands
-- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error;
-#else
-- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error;
-#endif
-
+- (NSData* _Nullable)currentBackupBagUUID;
+- (SecDbBackupWrappedKey* _Nullable)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error;
+- (SecDbBackupWrappedKey* _Nullable)wrapMetadataKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error;
 - (void)verifyBackupIntegrity:(bool)lightweight
                    completion:(void (^)(NSDictionary<NSString*, NSString*>* results, NSError* _Nullable error))completion;
 
@@ -96,3 +92,4 @@ NS_ASSUME_NONNULL_END
 // Declare C functions here
 
 bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef _Nullable * _Nonnull error);
+void SecDbResetBackupManager(void);     // For testing. Here so SecKeychainDbReset can use it.
index ff4dc45a2423633fc34db099771444a11c1332cf..b2a5c420f7a0d8548ecb9d945b06c04f62c9615e 100644 (file)
  */
 
 #import "SecDbBackupManager.h"
+#import "sec_action.h"
 
 NSString* const KeychainBackupsErrorDomain = @"com.apple.security.keychain.backups";
 
 // oink oink
-@implementation SecDbBackupWrappedItemKey
+@implementation SecDbBackupWrappedKey
 + (BOOL)supportsSecureCoding {
     return YES;
 }
@@ -44,36 +45,7 @@ NSString* const KeychainBackupsErrorDomain = @"com.apple.security.keychain.backu
 }
 @end
 
-#if !SECDB_BACKUPS_ENABLED
-
-@implementation SecDbBackupManager
-
-+ (instancetype)manager
-{
-    return nil;
-}
-
-- (void)verifyBackupIntegrity:(bool)lightweight
-                   completion:(void (^)(NSDictionary<NSString*, NSString*>* results, NSError* _Nullable error))completion
-{
-    completion(nil, [NSError errorWithDomain:KeychainBackupsErrorDomain
-                                        code:SecDbBackupNotSupported
-                                    userInfo:@{NSLocalizedDescriptionKey : @"platform doesn't do backups"}]);
-}
-
-- (SecDbBackupWrappedItemKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error
-{
-    return nil;
-}
-
-@end
-
-bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error)
-{
-    return true;
-}
-
-#else   // SECDB_BACKUPS_ENABLED is true, roll out the code
+#if SECDB_BACKUPS_ENABLED   // The bottom of this file contains stubs in case the feature is disabled
 
 #import "SecDbBackupManager_Internal.h"
 #include <CommonCrypto/CommonRandom.h>
@@ -101,6 +73,11 @@ bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error)
     return ok;
 }
 
+void SecDbResetBackupManager() {
+    secnotice("SecDbBackup", "Resetting backup manager");
+    [SecDbBackupManager resetManager];
+}
+
 // Reading from disk is relatively expensive. Keep wrapped key in memory and just delete the unwrapped copy on lock
 @interface InMemoryKCSK : NSObject
 @property aks_ref_key_t refKey;
@@ -190,7 +167,8 @@ static SecDbBackupManager* staticManager;
 + (void)resetManager
 {
     if (staticManager) {
-        staticManager = [SecDbBackupManager new];
+        secnotice("SecDbBackup", "Resetting backup manager");
+        staticManager = [[SecDbBackupManager alloc] init];
     }
 }
 
@@ -215,7 +193,7 @@ static SecDbBackupManager* staticManager;
     }
     CFTypeRef cftype = NULL;
     CFErrorRef cferr = NULL;
-    const uint8_t* derp = der_decode_plist(kCFAllocatorDefault, NSPropertyListImmutable, &cftype, &cferr, bytes, bytes + len);
+    const uint8_t* derp = der_decode_plist(kCFAllocatorDefault, &cftype, &cferr, bytes, bytes + len);
     free(bytes);
     if (derp == NULL || derp != (bytes + len) || cftype == NULL) {
         [self fillError:error code:SecDbBackupMalformedKCSKDataOnDisk underlying:CFBridgingRelease(cferr) description:@"Unable to parse der data"];
@@ -227,6 +205,11 @@ static SecDbBackupManager* staticManager;
                                        error:error];
 }
 
+- (NSData*)currentBackupBagUUID
+{
+    return [_bagIdentity.baguuid copy];
+}
+
 #pragma mark - Fixup And Verification
 
 - (void)verifyBackupIntegrity:(bool)lightweight
@@ -438,8 +421,6 @@ static SecDbBackupManager* staticManager;
         return bad_keybag_handle;
     }
 
-    // TODO: verify that bag is still signed, rdar://problem/46702467
-
     secnotice("SecDbBackup", "Backup bag loaded and verified.");
 
     // Must load readBag's identity because the hash from AKS is unstable.
@@ -451,6 +432,7 @@ static SecDbBackupManager* staticManager;
 
 - (BOOL)onQueueReloadDefaultBackupBagWithError:(NSError**)error
 {
+    dispatch_assert_queue(_queue);
     if (_handle != bad_keybag_handle) {
         aks_unload_bag(_handle);
     }
@@ -541,6 +523,7 @@ static SecDbBackupManager* staticManager;
 
 - (InMemoryKCSK*)onQueueReadKCSKFromDiskForClass:(keyclass_t)keyclass error:(NSError**)error
 {
+    dispatch_assert_queue(_queue);
     __block bool ok = true;
     __block CFErrorRef cfError = NULL;
     __block NSData* readUUID;
@@ -610,6 +593,7 @@ static SecDbBackupManager* staticManager;
 
 - (SFECKeyPair*)onQueueFetchKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error
 {
+    dispatch_assert_queue(_queue);
     assert(error);
     assert(_bagIdentity);
     assert(_handle != bad_keybag_handle);
@@ -889,9 +873,23 @@ static SecDbBackupManager* staticManager;
 
 #pragma mark - Item Encryption
 
-- (SecDbBackupWrappedItemKey*)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error
+- (SecDbBackupWrappedKey*)wrapItemKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error
 {
     assert(error);
+    // We don't care about rolled keyclasses; we care about semantic classes
+    if (keyclass > key_class_last) {
+        static dispatch_once_t rolledkeyclassnotifytoken;
+        static sec_action_t rolledkeyclassnotifyaction;
+        dispatch_once(&rolledkeyclassnotifytoken, ^{
+            rolledkeyclassnotifyaction = sec_action_create("rolledkeyclassnotifyaction", 300);
+            sec_action_set_handler(rolledkeyclassnotifyaction, ^{
+                secnotice("SecDbBackup", "Rolled keyclass for item wrap, %d -> %d", keyclass, SecAKSSanitizedKeyclass(keyclass));
+            });
+        });
+        sec_action_perform(rolledkeyclassnotifyaction);
+        keyclass = SecAKSSanitizedKeyclass(keyclass);
+    }
+
     if (keyclass == key_class_akpu) {
         secwarning("SecDbBackup: Don't tempt me Frodo!");
         [self fillError:error code:SecDbBackupInvalidArgument underlying:nil description:@"Do not call wrapItemKey with class akpu"];
@@ -905,7 +903,7 @@ static SecDbBackupManager* staticManager;
         return nil;
     }
 
-    __block SecDbBackupWrappedItemKey* backupWrappedKey;
+    __block SecDbBackupWrappedKey* backupWrappedKey;
 
     __block NSMutableData* wrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN];
     __block NSError* localError;
@@ -928,7 +926,7 @@ static SecDbBackupManager* staticManager;
                 return;
             }
         }
-        backupWrappedKey = [SecDbBackupWrappedItemKey new];
+        backupWrappedKey = [SecDbBackupWrappedKey new];
         backupWrappedKey.wrappedKey = [NSKeyedArchiver archivedDataWithRootObject:wrappedAndSigned requiringSecureCoding:YES error:&localError];
         backupWrappedKey.baguuid = self->_bagIdentity.baguuid;
     });
@@ -944,6 +942,7 @@ static SecDbBackupManager* staticManager;
 
 - (SFSignedData*)onQueueSignData:(NSMutableData*)data withKCSKForKeyclass:(keyclass_t)keyclass error:(NSError**)error
 {
+    dispatch_assert_queue(_queue);
     SFECKeyPair* kcsk = [self onQueueFetchKCSKForKeyclass:keyclass error:error];
     if (!kcsk) {
         return nil;
@@ -953,6 +952,19 @@ static SecDbBackupManager* staticManager;
     return [op sign:data withKey:kcsk error:error];
 }
 
+#pragma mark - Metadata Key Encryption
+
+- (SecDbBackupWrappedKey*)wrapMetadataKey:(_SFAESKey *)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error
+{
+    // We don't care about rolled keyclasses; we care about semantic classes
+    if (keyclass > key_class_last) {
+        secnotice("SecDbBackup", "Rolled keyclass for metadata wrap, %d -> %d", keyclass, SecAKSSanitizedKeyclass(keyclass));
+        keyclass = SecAKSSanitizedKeyclass(keyclass);
+    }
+    // For now, this is identical to item encryption. This will likely change when ACLs are implemented
+    return [self wrapItemKey:key forKeyclass:keyclass error:error];
+}
+
 #pragma mark - Testing Helpers
 
 - (keybag_handle_t)createBackupBagWithSecret:(NSData*)secret error:(NSError**)error
@@ -1052,4 +1064,30 @@ static SecDbBackupManager* staticManager;
 
 @end
 
-#endif // SECDB_BACKUPS_ENABLED
+#else // SECDB_BACKUPS_ENABLED is false
+#pragma mark - Stubs for when backups are disabled
+
+@implementation SecDbBackupManager
+
++ (instancetype)manager
+{
+    return nil;
+}
+
+- (NSData* _Nullable)currentBackupBagUUID {return nil;}
+- (SecDbBackupWrappedKey* _Nullable)wrapItemKey:(id)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error {return nil;}
+- (SecDbBackupWrappedKey* _Nullable)wrapMetadataKey:(SFAESKey*)key forKeyclass:(keyclass_t)keyclass error:(NSError**)error {return nil;}
+- (void)verifyBackupIntegrity:(bool)lightweight
+                   completion:(void (^)(NSDictionary<NSString*, NSString*>* results, NSError* _Nullable error))completion
+{
+    completion(nil, [NSError errorWithDomain:KeychainBackupsErrorDomain
+                                        code:SecDbBackupNotSupported
+                                    userInfo:@{NSLocalizedDescriptionKey : @"platform doesn't do backups"}]);
+}
+
+@end
+
+bool SecDbBackupCreateOrLoadBackupInfrastructure(CFErrorRef* error) {return true;}
+void SecDbResetBackupManager() {}
+
+#endif   // SECDB_BACKUPS_ENABLED
index 71a3b3ebebc4f950394e8dea32691bc3bc439e61..24b7499e4f98eb8f09ee7ded5b66ce07361394ef 100644 (file)
@@ -63,7 +63,7 @@
 
 // Pure utilities
 - (NSData*)getSHA256OfData:(NSData*)data;
-- (SFECKeyPair*)ECKeyPairFromDerBytes:(void*)bytes length:(size_t)len error:(NSError**)error;
+- (SFECKeyPair*)getECKeyPairFromDERBytes:(void*)bytes length:(size_t)len error:(NSError**)error;
 
 @end
 
index 5b63b41aa1bd450ae5dff3159bd4654b9da913df..4e28f17c02532df1a648eda81593c730416e4940 100644 (file)
@@ -337,8 +337,20 @@ static CFTypeRef SecDbItemGetCachedValue(SecDbItemRef item, const SecDbAttr *des
 }
 
 CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error) {
+    return SecDbItemCopyPListWithFlagAndSkip(item, mask, 0, error);
+}
+
+CFMutableDictionaryRef SecDbItemCopyPListWithFlagAndSkip(SecDbItemRef item,
+                                                         CFOptionFlags mask,
+                                                         CFOptionFlags flagsToSkip,
+                                                         CFErrorRef *error)
+{
     CFMutableDictionaryRef dict = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
     SecDbForEachAttrWithMask(item->class, desc, mask) {
+        if((desc->flags & flagsToSkip) != 0) {
+            break;
+        }
+
         CFTypeRef value = SecDbItemGetValue(item, desc, error);
         if (value) {
             if (!CFEqual(kCFNull, value)) {
@@ -559,28 +571,62 @@ static bool SecDbItemGetBoolValue(SecDbItemRef item, const SecDbAttr *desc, bool
     return true;
 }
 
+static void SecDbItemAppendAttributeToDescription(SecDbItemRef item, const SecDbAttr *attr, CFMutableStringRef mdesc)
+{
+    // In non-debug builds, the following attributes aren't very useful.
+#ifndef DEBUG
+    if (CFEqual(CFSTR("data"), attr->name)||
+        CFEqual(CFSTR("v_pk"), attr->name)) {
+        return;
+    }
+#endif
+
+    CFTypeRef value = SecDbItemGetValue(item, attr, NULL);
+    if (value && value != kCFNull) {
+        CFStringAppend(mdesc, CFSTR(","));
+        CFStringAppend(mdesc, attr->name);
+        CFStringAppend(mdesc, CFSTR("="));
+        if (CFEqual(CFSTR("data"), attr->name)) {
+            CFStringAppendEncryptedData(mdesc, value);
+        } else if (CFEqual(CFSTR("v_Data"), attr->name)) {
+            CFStringAppend(mdesc, CFSTR("<?>"));
+        } else if (isData(value)) {
+            CFStringAppendHexData(mdesc, value);
+        } else {
+            CFStringAppendFormat(mdesc, 0, CFSTR("%@"), value);
+        }
+    }
+}
+
 static CFStringRef SecDbItemCopyFormatDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
     CFStringRef desc;
     if (isDictionary(formatOptions) && CFDictionaryContainsKey(formatOptions, kSecDebugFormatOption)) {
         SecDbItemRef item = (SecDbItemRef)cf;
         CFMutableStringRef mdesc = CFStringCreateMutable(CFGetAllocator(cf), 0);
         CFStringAppendFormat(mdesc, NULL, CFSTR("<%@"), item->class->name);
+
+        // First, the primary key attributes
+        SecDbForEachAttrWithMask(item->class, attr, kSecDbPrimaryKeyFlag) {
+            SecDbItemAppendAttributeToDescription(item, attr, mdesc);
+        }
+
+        CFStringAppend(mdesc, CFSTR(", |otherAttr"));
+        // tombstone values are very important, and should print next
         SecDbForEachAttr(item->class, attr) {
-                CFTypeRef value = SecDbItemGetValue(item, attr, NULL);
-                if (value) {
-                    CFStringAppend(mdesc, CFSTR(","));
-                    CFStringAppend(mdesc, attr->name);
-                    CFStringAppend(mdesc, CFSTR("="));
-                    if (CFEqual(CFSTR("data"), attr->name)) {
-                        CFStringAppendEncryptedData(mdesc, value);
-                    } else if (CFEqual(CFSTR("v_Data"), attr->name)) {
-                        CFStringAppend(mdesc, CFSTR("<?>"));
-                    } else if (isData(value)) {
-                        CFStringAppendHexData(mdesc, value);
-                    } else {
-                        CFStringAppendFormat(mdesc, 0, CFSTR("%@"), value);
-                    }
-                }
+            if(CFEqualSafe(CFSTR("tomb"), attr->name)) {
+                SecDbItemAppendAttributeToDescription(item, attr, mdesc);
+            }
+        }
+
+        // And finally, everything else
+        SecDbForEachAttr(item->class, attr) {
+            if((attr->flags & kSecDbPrimaryKeyFlag) != 0) {
+                continue;
+            }
+            if(CFEqualSafe(CFSTR("tomb"), attr->name)) {
+                continue;
+            }
+            SecDbItemAppendAttributeToDescription(item, attr, mdesc);
         }
         CFStringAppend(mdesc, CFSTR(">"));
         desc = mdesc;
@@ -886,6 +932,28 @@ bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef va
     return false;
 }
 
+bool SecItemPreserveAttribute(SecDbItemRef target, SecDbItemRef source, const SecDbAttr* attr) {
+    CFErrorRef cferror = nil;
+    CFTypeRef v = SecDbItemGetValue(source, attr, &cferror);
+    if(cferror) {
+        secnotice("secitem", "Merging: unable to get attribute (%@) : %@", attr->name, cferror);
+        CFReleaseNull(cferror);
+        return false;
+    }
+    if(!v || CFEqualSafe(v, kCFNull)) {
+        return true;
+    }
+    secnotice("secitem", "Preserving existing data for %@", attr->name);
+    SecDbItemSetValue(target, attr, v, &cferror);
+    if(cferror) {
+        secnotice("secitem", "Unable to set attribute (%@) : %@", attr->name, cferror);
+        CFReleaseNull(cferror);
+        return false;
+    }
+    return true;
+}
+
+
 bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error) {
     bool ok = true;
     if (item->_edataState == kSecDbItemClean)
@@ -1058,7 +1126,7 @@ static bool SecDbItemMakeYounger(SecDbItemRef new_item, SecDbItemRef old_item, C
     return attr && SecDbItemMakeAttrYounger(new_item, old_item, attr, error);
 }
 
-static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeTombStone, CFErrorRef *error) {
+static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeTombStone, bool tombstone_time_from_item, CFErrorRef *error) {
     SecDbItemRef new_item = SecDbItemCreate(CFGetAllocator(item), item->class, item->keybag);
     SecDbForEachAttr(item->class, attr) {
         if (attr->kind == kSecDbTombAttr) {
@@ -1075,6 +1143,10 @@ static SecDbItemRef SecDbItemCopyTombstone(SecDbItemRef item, CFBooleanRef makeT
                 break;
             }
         } else if (attr->kind == kSecDbModificationDateAttr) {
+            if(tombstone_time_from_item) {
+                SecItemPreserveAttribute(new_item, item, attr);
+            }
+
             if (!SecDbItemMakeAttrYounger(new_item, item, attr, error)) {
                 CFReleaseNull(new_item);
                 break;
@@ -1296,7 +1368,7 @@ static SecDbQueryRef SecDbQueryCreateWithItemPrimaryKey(SecDbItemRef item, CFErr
     if (!dict)
         return NULL;
 
-    SecDbQueryRef query = query_create(item->class, NULL, NULL, error);
+    SecDbQueryRef query = query_create(item->class, NULL, NULL, NULL, error);
     if (query) {
         CFReleaseSafe(query->q_item);
         query->q_item = dict;
@@ -1343,7 +1415,8 @@ static bool SecDbItemIsCorrupt(SecDbItemRef item, bool *is_corrupt, CFErrorRef *
     if (storedSHA1 && computedSHA1 && !CFEqual(storedSHA1, computedSHA1)) {
         CFStringRef storedHex = CFDataCopyHexString(storedSHA1), computedHex = CFDataCopyHexString(computedSHA1);
         secerror("error %@ %@ != %@ item %@ (corrupted)", sha1attr->name, storedHex, computedHex, item);
-        __security_simulatecrash(CFSTR("Corrupted item (sha1 mismatch) found in keychain"), __sec_exception_code_CorruptItem);
+        // Do not simulate crash for this condition.
+        // The keychain hashes floating point numbers which causes many false positives, this is not fixable except by major surgery
         CFReleaseSafe(storedHex);
         CFReleaseSafe(computedHex);
         *is_corrupt = true;
@@ -1472,11 +1545,21 @@ bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFEr
     return ok & SecErrorPropagate(localError, error); // Don't use && here!
 }
 
-bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error) {
+bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, bool always_use_uuid_from_new_item, CFErrorRef *error) {
     return SecDbItemInsertOrReplace(item, dbconn, error, ^(SecDbItemRef old_item, SecDbItemRef *replace) {
         if (SecDbItemIsTombstone(old_item)) {
             CFRetain(item);
             *replace = item;
+
+            // If the caller doesn't care about the UUID, then use old_item's UUID
+            // Note: this will modify item!
+            if(!always_use_uuid_from_new_item) {
+                SecDbForEachAttr(SecDbItemGetClass(item), attr) {
+                    if(CFEqual(attr->name, v10itemuuid.name)) {
+                        SecItemPreserveAttribute(item, old_item, attr);
+                    }
+                }
+            }
         }
     });
 }
@@ -1700,7 +1783,7 @@ bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnecti
     if (ok && !pk_equal && !CFEqualSafe(makeTombstone, kCFBooleanFalse)) {
         /* The primary key of new_item is different than that of old_item, we
            have been asked to make a tombstone so leave one for the old_item. */
-        SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, makeTombstone, error);
+        SecDbItemRef tombstone = SecDbItemCopyTombstone(old_item, makeTombstone, false, error);
         ok = tombstone;
         if (tombstone) {
             ok = (SecDbItemClearRowId(tombstone, error) &&
@@ -1713,10 +1796,10 @@ bool SecDbItemUpdate(SecDbItemRef old_item, SecDbItemRef new_item, SecDbConnecti
 }
 
 // Replace the object with a tombstone
-bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error) {
+bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool tombstone_time_from_item, CFErrorRef *error) {
     bool ok = false;
     if (!CFEqualSafe(makeTombstone, kCFBooleanFalse)) {
-        SecDbItemRef tombstone = SecDbItemCopyTombstone(item, makeTombstone, error);
+        SecDbItemRef tombstone = SecDbItemCopyTombstone(item, makeTombstone, tombstone_time_from_item, error);
         if (tombstone) {
             ok = SecDbItemDoUpdate(item, tombstone, dbconn, error, ^bool(const SecDbAttr *attr) {
                 return attr->kind == kSecDbRowIdAttr;
index 586b8c0028250e081498fc55cc943c2c64b4151f..1d9966cd66b3ff8c8290d90b445683b3234306a3 100644 (file)
@@ -81,6 +81,7 @@ enum {
     kSecDbSyncPrimaryKeyV0  = (1 << 14),
     kSecDbSyncPrimaryKeyV2  = (1 << 15),
     kSecDbSyncFlag          = (1 << 16),
+    kSecDbSyncSOSCannotSyncFlag= (1 << 17),
 };
 
 #define SecVersionDbFlag(v) ((v & 0xFF) << 8)
@@ -176,6 +177,10 @@ bool SecDbItemSetValue(SecDbItemRef item, const SecDbAttr *desc, CFTypeRef value
 bool SecDbItemSetValues(SecDbItemRef item, CFDictionaryRef values, CFErrorRef *error);
 bool SecDbItemSetValueWithName(SecDbItemRef item, CFStringRef name, CFTypeRef value, CFErrorRef *error);
 
+// Copies a given attribute from source to target. If source does not have that atttribute,
+// doesn't modify target.
+bool SecItemPreserveAttribute(SecDbItemRef target, SecDbItemRef source, const SecDbAttr* attr);
+
 sqlite3_int64 SecDbItemGetRowId(SecDbItemRef item, CFErrorRef *error);
 bool SecDbItemSetRowId(SecDbItemRef item, sqlite3_int64 rowid, CFErrorRef *error);
 bool SecDbItemClearRowId(SecDbItemRef item, CFErrorRef *error);
@@ -189,6 +194,14 @@ bool SecDbItemIsTombstone(SecDbItemRef item);
 
 CFMutableDictionaryRef SecDbItemCopyPListWithMask(SecDbItemRef item, CFOptionFlags mask, CFErrorRef *error);
 
+/*
+ * Note that "mask" requires a single option, but flagsToSkip can have any number combined.
+ */
+CFMutableDictionaryRef SecDbItemCopyPListWithFlagAndSkip(SecDbItemRef item,
+                                                         CFOptionFlags mask,
+                                                         CFOptionFlags flagsToSkip,
+                                                         CFErrorRef *error);
+
 CFDataRef SecDbItemGetPrimaryKey(SecDbItemRef item, CFErrorRef *error);
 CFDataRef SecDbItemGetSHA1(SecDbItemRef item, CFErrorRef *error);
 
@@ -214,9 +227,10 @@ bool SecDbItemInsertOrReplace(SecDbItemRef item, SecDbConnectionRef dbconn, CFEr
 // SecDbItemInsertOrReplace returns an error even when it succeeds; use this to determine if it's spurious
 bool SecErrorIsSqliteDuplicateItemError(CFErrorRef error);
 
-bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error);
+// Note: this function might modify item, unless always_use_uuid_from_new_item is true
+bool SecDbItemInsert(SecDbItemRef item, SecDbConnectionRef dbconn, bool always_use_uuid_from_new_item, CFErrorRef *error);
 
-bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, CFErrorRef *error);
+bool SecDbItemDelete(SecDbItemRef item, SecDbConnectionRef dbconn, CFBooleanRef makeTombstone, bool tombstone_time_from_item, CFErrorRef *error);
 
 bool SecDbItemDoDeleteSilently(SecDbItemRef item, SecDbConnectionRef dbconn, CFErrorRef *error);
 
index ce88986831df2d347055aeb41150c84219836516..83aaaa5dd9da2cff199a65a227bfb2093952e91b 100644 (file)
 #include "keychain/securityd/SecDbItem.h"
 #include "keychain/securityd/SecDbQuery.h"
 
+CF_ASSUME_NONNULL_BEGIN
+
 __BEGIN_DECLS
 
-bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
-                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error);
-bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
-                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error);
-bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
-                            CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error); // used for backup
-bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef *paccess_control, CFDataRef acm_context,
+bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef _Nullable access_control, CFDataRef _Nullable acm_context,
+                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef _Nullable *_Nonnull pBlob, bool useDefaultIV, CFErrorRef _Nullable *_Nullable error);
+bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef _Nullable access_control, CFDataRef _Nullable acm_context,
+                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef _Nullable *_Nonnull pBlob, CFDataRef _Nullable *_Nullable bkUUID, bool useDefaultIV, CFErrorRef _Nullable *_Nullable error);
+bool ks_encrypt_data_legacy(keybag_handle_t keybag, SecAccessControlRef _Nullable access_control, CFDataRef _Nullable acm_context,
+                            CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef _Nullable *_Nonnull pBlob, bool useDefaultIV, CFErrorRef _Nullable *_Nullable error); // used for backup
+bool ks_decrypt_data(keybag_handle_t keybag, CFTypeRef cryptoOp, SecAccessControlRef _Nullable *_Nullable paccess_control, CFDataRef acm_context,
                      CFDataRef blob, const SecDbClass *db_class, CFArrayRef caller_access_groups,
-                     CFMutableDictionaryRef *attributes_p, uint32_t *version_p, bool decryptSecretData, keyclass_t* outKeyclass, CFErrorRef *error);
+                     CFMutableDictionaryRef _Nullable *_Nullable attributes_p, uint32_t *_Nullable version_p, bool decryptSecretData, keyclass_t*_Nullable outKeyclass, CFErrorRef _Nullable *_Nullable error);
 bool s3dl_item_from_data(CFDataRef edata, Query *q, CFArrayRef accessGroups,
-                         CFMutableDictionaryRef *item, SecAccessControlRef *access_control, keyclass_t* keyclass, CFErrorRef *error);
-SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error);
-bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef *error);
-bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error);
+                         CFMutableDictionaryRef _Nonnull *_Nonnull item, SecAccessControlRef _Nullable *_Nullable access_control, keyclass_t *_Nullable keyclass, CFErrorRef _Nullable *_Nullable error);
+SecDbItemRef _Nullable SecDbItemCreateWithBackupDictionary(const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef _Nullable *_Nullable error);
+bool SecDbItemExtractRowIdFromBackupDictionary(SecDbItemRef item, CFDictionaryRef dict, CFErrorRef _Nullable *_Nullable error);
+bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef _Nullable *_Nullable error);
 
-CFTypeRef SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error);
-CFTypeRef SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef *error);
-CFTypeRef SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error);
-CFTypeRef SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error);
-CFTypeRef SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef *error);
+CFTypeRef _Nullable SecDbKeychainItemCopyPrimaryKey(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef _Nullable *_Nullable error);
+CFTypeRef _Nullable SecDbKeychainItemCopySHA256PrimaryKey(SecDbItemRef item, CFErrorRef _Nullable *_Nullable error);
+CFTypeRef _Nullable SecDbKeychainItemCopySHA1(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef _Nullable *_Nullable error);
+CFTypeRef _Nullable SecDbKeychainItemCopyCurrentDate(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef _Nullable *_Nullable error);
+CFTypeRef _Nullable SecDbKeychainItemCopyEncryptedData(SecDbItemRef item, const SecDbAttr *attr, CFErrorRef _Nullable *_Nullable error);
 
-SecAccessControlRef SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef *error);
-bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef *error);
+SecAccessControlRef _Nullable SecDbItemCopyAccessControl(SecDbItemRef item, CFErrorRef _Nullable *_Nullable error);
+bool SecDbItemSetAccessControl(SecDbItemRef item, SecAccessControlRef access_control, CFErrorRef _Nullable *_Nullable error);
 
 void SecDbResetMetadataKeys(void);
 
 __END_DECLS
 
+CF_ASSUME_NONNULL_END
+
 #endif /* _SECURITYD_SECKEYCHAINITEM_H_ */
index 4ad9c89248f34a45ec1e24fb775502ef9542c263..cd7032e03ed68d4db63f0b01498d8bc0872a0b00 100644 (file)
@@ -78,25 +78,25 @@ static CFDataRef kc_create_auth_data(SecAccessControlRef access_control, CFDicti
 static CFDataRef kc_copy_access_groups_data(CFArrayRef access_groups, CFErrorRef *error);
 #endif
 
-static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFOptionFlags mutability, CFPropertyListRef* cf, CFErrorRef *error,
+static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef pl, CFPropertyListRef* cf, CFErrorRef *error,
                                                    const uint8_t* der, const uint8_t *der_end,
-                                                   const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
+                                                   const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error,
                                                                                  const uint8_t* der, const uint8_t *der_end));
-static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFDictionaryRef* dictionary, CFErrorRef *error,
+static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFDictionaryRef* dictionary, CFErrorRef *error,
                                                         const uint8_t* der, const uint8_t *der_end,
-                                                        const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
+                                                        const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error,
                                                                                       const uint8_t* der, const uint8_t *der_end));
-static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
+static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
                                                        const uint8_t* der, const uint8_t *der_end,
-                                                       const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
+                                                       const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error,
                                                                                      const uint8_t* der, const uint8_t *der_end));
-static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFArrayRef* array, CFErrorRef *error,
+static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFArrayRef* array, CFErrorRef *error,
                                                    const uint8_t* der, const uint8_t *der_end,
-                                                   const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
+                                                   const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error,
                                                                                  const uint8_t* der, const uint8_t *der_end));
-static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability, CFSetRef* set, CFErrorRef *error,
+static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFSetRef* set, CFErrorRef *error,
                                                  const uint8_t* der, const uint8_t *der_end,
-                                                 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error,
+                                                 const uint8_t* (^repairBlock)(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error,
                                                                                const uint8_t* der, const uint8_t *der_end));
 
 const uint32_t kUseDefaultIVMask =  1<<31;
@@ -305,13 +305,13 @@ ks_warn_non_device_keybag(void)
     sec_action_perform(action);
 }
 
-bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
-                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, bool useDefaultIV, CFErrorRef *error) {
+bool ks_encrypt_data(keybag_handle_t keybag, SecAccessControlRef _Nullable access_control, CFDataRef _Nullable acm_context,
+                     CFDictionaryRef _Nonnull secretData, CFDictionaryRef _Nonnull attributes, CFDictionaryRef _Nonnull authenticated_attributes, CFDataRef _Nonnull *pBlob, bool useDefaultIV, CFErrorRef *error) {
     return ks_encrypt_data_with_backupuuid(keybag, access_control, acm_context, secretData, attributes, authenticated_attributes, pBlob, NULL, useDefaultIV, error);
 }
 
-bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef access_control, CFDataRef acm_context,
-                     CFDictionaryRef secretData, CFDictionaryRef attributes, CFDictionaryRef authenticated_attributes, CFDataRef *pBlob, CFDataRef *bkUUID, bool useDefaultIV, CFErrorRef *error) {
+bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef _Nullable access_control, CFDataRef _Nullable acm_context,
+                     CFDictionaryRef _Nonnull secretData, CFDictionaryRef _Nonnull attributes, CFDictionaryRef _Nonnull authenticated_attributes, CFDataRef _Nonnull *pBlob, CFDataRef _Nullable *bkUUID, bool useDefaultIV, CFErrorRef *error) {
     if (keybag != KEYBAG_DEVICE) {
         ks_warn_non_device_keybag();
 
@@ -331,8 +331,8 @@ bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef
 
     if (SecAccessControlGetConstraints(access_control)) {
         NSMutableDictionary* allAttributes = [(__bridge NSDictionary*)attributes mutableCopy];
-        [allAttributes addEntriesFromDictionary:(__bridge NSDictionary*)secretData];
-        return ks_encrypt_data_legacy(keybag, access_control, acm_context, (__bridge CFDictionaryRef)allAttributes, authenticated_attributes, pBlob, useDefaultIV, error);
+        [allAttributes addEntriesFromDictionary:(__bridge NSDictionary*_Nonnull)secretData];
+        return ks_encrypt_data_legacy(keybag, access_control, acm_context, (__bridge CFDictionaryRef _Nonnull)allAttributes, authenticated_attributes, pBlob, useDefaultIV, error);
     }
 
     bool success = false;
@@ -342,7 +342,7 @@ bool ks_encrypt_data_with_backupuuid(keybag_handle_t keybag, SecAccessControlRef
         metadataAttributes[@"SecAccessControl"] = (__bridge_transfer NSData*)SecAccessControlCopyData(access_control);
 
         NSString* tamperCheck = [[NSUUID UUID] UUIDString]; // can use the item persistent reference when that starts getting filled in
-        SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:(__bridge NSDictionary*)secretData metadataAttributes:metadataAttributes tamperCheck:tamperCheck keyclass:key_class];
+        SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:(__bridge NSDictionary*_Nonnull)secretData metadataAttributes:metadataAttributes tamperCheck:tamperCheck keyclass:key_class];
 
         NSError* localError = nil;
         NSData* encryptedBlob = [item encryptedBlobWithKeybag:keybag accessControl:access_control acmContext:(__bridge NSData*)acm_context error:&localError];
@@ -789,7 +789,7 @@ static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, cons
     CFDataRef ed = NULL;
     bool ok = false;
 
-    der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len);
+    der_decode_plist(NULL, (CFPropertyListRef*)&blob_dict, NULL, blob_data, blob_data + blob_data_len);
     require_action_quiet(blob_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'blob data'")));
 
     if (!ks_separate_data_and_key(blob_dict, &ed, &key_data)) {
@@ -804,7 +804,7 @@ static bool kc_attribs_key_encrypted_data_from_blob(keybag_handle_t keybag, cons
     require_quiet(external_data = ks_ref_key_get_external_data(keybag, key_data, &tmp_ref_key, &external_data_len, error), out);
 
     CFPropertyListRef external_data_dict = NULL;
-    der_decode_plist(NULL, kCFPropertyListImmutable, &external_data_dict, NULL, external_data, external_data + external_data_len);
+    der_decode_plist(NULL, &external_data_dict, NULL, external_data, external_data + external_data_len);
     require_action_quiet(external_data_dict, out, SecError(errSecDecode, error, CFSTR("kc_attribs_key_encrypted_data_from_blob: failed to decode 'encrypted data dictionary'")));
     acl = CFDictionaryCreateMutableCopy(NULL, 0, external_data_dict);
     SecDbForEachAttrWithMask(class, attr_desc, kSecDbInAuthenticatedDataFlag) {
@@ -902,7 +902,7 @@ static CFDataRef kc_copy_protection_data(SecAccessControlRef access_control)
 static CFTypeRef kc_copy_protection_from(const uint8_t *der, const uint8_t *der_end)
 {
     CFTypeRef result = NULL;
-    der_decode_plist(NULL, kCFPropertyListImmutable, &result, NULL, der, der_end);
+    der_decode_plist(NULL, &result, NULL, der, der_end);
     return result;
 }
 
@@ -925,8 +925,8 @@ CFMutableDictionaryRef s3dl_item_v2_decode(CFDataRef plain, CFErrorRef *error) {
     return dictionaryFromPlist(item, error);
 }
 
-static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) =
-    ^const uint8_t*(CFAllocatorRef allocator, CFOptionFlags mutability, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) {
+static const uint8_t* (^s3dl_item_v3_decode_repair_date)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*, const uint8_t*, const uint8_t*) =
+    ^const uint8_t*(CFAllocatorRef allocator, CFPropertyListRef* pl, CFErrorRef *error, const uint8_t* der, const uint8_t *der_end) {
         if (error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
             CFAbsoluteTime date = 0;
             CFCalendarRef calendar = CFCalendarCreateWithIdentifier(allocator, kCFGregorianCalendar);
@@ -950,10 +950,10 @@ CFMutableDictionaryRef s3dl_item_v3_decode(CFDataRef plain, CFErrorRef *error) {
     CFPropertyListRef item = NULL;
     const uint8_t *der_beg = CFDataGetBytePtr(plain);
     const uint8_t *der_end = der_beg + CFDataGetLength(plain);
-    const uint8_t *der = der_decode_plist(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end);
+    const uint8_t *der = der_decode_plist(0, &item, error, der_beg, der_end);
     if (!der && error && CFEqualSafe(CFErrorGetDomain(*error), sSecDERErrorDomain) && CFErrorGetCode(*error) == kSecDERErrorUnknownEncoding) {
         CFReleaseNull(*error);
-        der = der_decode_plist_with_repair(0, kCFPropertyListMutableContainers, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date);
+        der = der_decode_plist_with_repair(0, &item, error, der_beg, der_end, s3dl_item_v3_decode_repair_date);
     }
     if (der && der != der_end) {
         SecCFCreateError(errSecDecode, kSecErrorDomain, CFSTR("trailing garbage at end of decrypted item"), NULL, error);
@@ -1145,7 +1145,7 @@ bool SecDbItemInferSyncable(SecDbItemRef item, CFErrorRef *error)
  src_keybag is normally the backup keybag.
  dst_keybag is normally the device keybag.
  */
-SecDbItemRef SecDbItemCreateWithBackupDictionary(CFAllocatorRef allocator, const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
+SecDbItemRef SecDbItemCreateWithBackupDictionary(const SecDbClass *dbclass, CFDictionaryRef dict, keybag_handle_t src_keybag, keybag_handle_t dst_keybag, CFErrorRef *error)
 {
     CFDataRef edata = CFDictionaryGetValue(dict, CFSTR("v_Data"));
     SecDbItemRef item = NULL;
@@ -1322,10 +1322,10 @@ out:
     return result;
 }
 
-static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator,
                                                    CFPropertyListRef* pl, CFErrorRef *error,
                                                    const uint8_t* der, const uint8_t *der_end,
-                                                   const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
+                                                   const uint8_t* (^repairBlock)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*,
                                                                                  const uint8_t*, const uint8_t*))
 {
     if (NULL == der) {
@@ -1341,38 +1341,38 @@ static const uint8_t* der_decode_plist_with_repair(CFAllocatorRef allocator, CFO
 
     switch (tag) {
         case CCDER_NULL:
-            return der_decode_null(allocator, mutability, (CFNullRef*)pl, error, der, der_end);
+            return der_decode_null(allocator, (CFNullRef*)pl, error, der, der_end);
         case CCDER_BOOLEAN:
-            return der_decode_boolean(allocator, mutability, (CFBooleanRef*)pl, error, der, der_end);
+            return der_decode_boolean(allocator, (CFBooleanRef*)pl, error, der, der_end);
         case CCDER_OCTET_STRING:
-            return der_decode_data(allocator, mutability, (CFDataRef*)pl, error, der, der_end);
+            return der_decode_data(allocator, (CFDataRef*)pl, error, der, der_end);
         case CCDER_GENERALIZED_TIME: {
-                const uint8_t* der_result = der_decode_date(allocator, mutability, (CFDateRef*)pl, error, der, der_end);
+                const uint8_t* der_result = der_decode_date(allocator, (CFDateRef*)pl, error, der, der_end);
                 if (!der_result) {
-                    der_result = repairBlock(allocator, mutability, pl, error, der, der_end);
+                    der_result = repairBlock(allocator, pl, error, der, der_end);
                 }
                 return der_result;
             }
         case CCDER_CONSTRUCTED_SEQUENCE:
-            return der_decode_array_with_repair(allocator, mutability, (CFArrayRef*)pl, error, der, der_end, repairBlock);
+            return der_decode_array_with_repair(allocator, (CFArrayRef*)pl, error, der, der_end, repairBlock);
         case CCDER_UTF8_STRING:
-            return der_decode_string(allocator, mutability, (CFStringRef*)pl, error, der, der_end);
+            return der_decode_string(allocator, (CFStringRef*)pl, error, der, der_end);
         case CCDER_INTEGER:
-            return der_decode_number(allocator, mutability, (CFNumberRef*)pl, error, der, der_end);
+            return der_decode_number(allocator, (CFNumberRef*)pl, error, der, der_end);
         case CCDER_CONSTRUCTED_SET:
-            return der_decode_dictionary_with_repair(allocator, mutability, (CFDictionaryRef*)pl, error, der, der_end, repairBlock);
+            return der_decode_dictionary_with_repair(allocator, (CFDictionaryRef*)pl, error, der, der_end, repairBlock);
         case CCDER_CONSTRUCTED_CFSET:
-            return der_decode_set_with_repair(allocator, mutability, (CFSetRef*)pl, error, der, der_end, repairBlock);
+            return der_decode_set_with_repair(allocator, (CFSetRef*)pl, error, der, der_end, repairBlock);
         default:
             SecCFDERCreateError(kSecDERErrorUnsupportedDERType, CFSTR("Unsupported DER Type"), NULL, error);
             return NULL;
     }
 }
 
-static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator,
                                                         CFDictionaryRef* dictionary, CFErrorRef *error,
                                                         const uint8_t* der, const uint8_t *der_end,
-                                                        const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
+                                                        const uint8_t* (^repairBlock)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*,
                                                                                       const uint8_t*, const uint8_t*))
 {
     if (NULL == der) {
@@ -1401,7 +1401,7 @@ static const uint8_t* der_decode_dictionary_with_repair(CFAllocatorRef allocator
         CFTypeRef key = NULL;
         CFTypeRef value = NULL;
 
-        payload = der_decode_key_value_with_repair(allocator, mutability, &key, &value, error, payload, payload_end, repairBlock);
+        payload = der_decode_key_value_with_repair(allocator, &key, &value, error, payload, payload_end, repairBlock);
 
         if (payload) {
             CFDictionaryAddValue(dict, key, value);
@@ -1423,10 +1423,10 @@ exit:
     return payload;
 }
 
-static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator,
                                                        CFPropertyListRef* key, CFPropertyListRef* value, CFErrorRef *error,
                                                        const uint8_t* der, const uint8_t *der_end,
-                                                       const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
+                                                       const uint8_t* (^repairBlock)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*,
                                                                                      const uint8_t*, const uint8_t*))
 {
     const uint8_t *payload_end = 0;
@@ -1441,8 +1441,8 @@ static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator,
     CFTypeRef valueObject = NULL;
 
 
-    payload = der_decode_plist_with_repair(allocator, mutability, &keyObject, error, payload, payload_end, repairBlock);
-    payload = der_decode_plist_with_repair(allocator, mutability, &valueObject, error, payload, payload_end, repairBlock);
+    payload = der_decode_plist_with_repair(allocator, &keyObject, error, payload, payload_end, repairBlock);
+    payload = der_decode_plist_with_repair(allocator, &valueObject, error, payload, payload_end, repairBlock);
 
     if (payload != NULL) {
         *key = keyObject;
@@ -1454,10 +1454,10 @@ static const uint8_t* der_decode_key_value_with_repair(CFAllocatorRef allocator,
     return payload;
 }
 
-static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator,
                                                    CFArrayRef* array, CFErrorRef *error,
                                                    const uint8_t* der, const uint8_t *der_end,
-                                                   const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
+                                                   const uint8_t* (^repairBlock)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*,
                                                                                  const uint8_t*, const uint8_t*))
 {
     if (NULL == der) {
@@ -1472,7 +1472,7 @@ static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFO
 
     while (current_element != NULL && current_element < elements_end) {
         CFPropertyListRef element = NULL;
-        current_element = der_decode_plist_with_repair(allocator, mutability, &element, error, current_element, elements_end, repairBlock);
+        current_element = der_decode_plist_with_repair(allocator, &element, error, current_element, elements_end, repairBlock);
         if (current_element) {
             CFArrayAppendValue(result, element);
             CFReleaseNull(element);
@@ -1488,10 +1488,10 @@ static const uint8_t* der_decode_array_with_repair(CFAllocatorRef allocator, CFO
     return current_element;
 }
 
-static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOptionFlags mutability,
+static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator,
                                                  CFSetRef* set, CFErrorRef *error,
                                                  const uint8_t* der, const uint8_t *der_end,
-                                                 const uint8_t* (^repairBlock)(CFAllocatorRef, CFOptionFlags, CFPropertyListRef*, CFErrorRef*,
+                                                 const uint8_t* (^repairBlock)(CFAllocatorRef, CFPropertyListRef*, CFErrorRef*,
                                                                                const uint8_t*, const uint8_t*))
 {
     if (NULL == der) {
@@ -1519,7 +1519,7 @@ static const uint8_t* der_decode_set_with_repair(CFAllocatorRef allocator, CFOpt
     while (payload != NULL && payload < payload_end) {
         CFTypeRef value = NULL;
 
-        payload = der_decode_plist_with_repair(allocator, mutability, &value, error, payload, payload_end, repairBlock);
+        payload = der_decode_plist_with_repair(allocator, &value, error, payload, payload_end, repairBlock);
 
         if (payload) {
             CFSetAddValue(theSet, value);
index 90ccbe00180d2fb6c761387308caf34031c9719a..6f7f449a2755b122532045cb9a0818b89b27b17f 100644 (file)
@@ -109,7 +109,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
 @property (readonly) NSData* serializedRepresentation;
 
 - (instancetype)initWithData:(NSData*)data;
-- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey error:(NSError**)error;
+- (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey tamperCheck:(NSString*)tamperCheck backupWrappedKey:(SecDbBackupWrappedKey*)backupWrappedKey error:(NSError**)error;
 
 @end
 
@@ -249,7 +249,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
 - (instancetype)initWithCiphertext:(SFAuthenticatedCiphertext*)ciphertext
                         wrappedKey:(SecDbKeychainAKSWrappedKey*)wrappedKey
                        tamperCheck:(NSString*)tamperCheck
-                  backupWrappedKey:(SecDbBackupWrappedItemKey*)backupWrappedKey
+                  backupWrappedKey:(SecDbBackupWrappedKey*)backupWrappedKey
                              error:(NSError**)error
 {
     if (self = [super init]) {
@@ -412,8 +412,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
 {
     if (!_metadataAttributes) {
         SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:_keybag
-                                                   createKeyIfMissing:false
-                                                  overwriteCorruptKey:false
+                                                          allowWrites:false
                                                                 error:error];
         if (metadataClassKey) {
             NSError* localError = nil;
@@ -569,8 +568,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
     SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:metadata withKey:key error:error];
 
     SFAESKey* metadataClassKey = [self metadataClassKeyWithKeybag:keybag
-                                               createKeyIfMissing:true
-                                              overwriteCorruptKey:true
+                                                      allowWrites:true
                                                             error:error];
     if (metadataClassKey) {
         SFAuthenticatedCiphertext* wrappedKey = [encryptionOperation encrypt:key.keyData withKey:metadataClassKey error:error];
@@ -607,7 +605,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
     SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:secretData withKey:key error:error];
     SecDbKeychainAKSWrappedKey* wrappedKey = [self wrapToAKS:key withKeybag:keybag accessControl:accessControl acmContext:acmContext error:error];
 
-    SecDbBackupWrappedItemKey* backupWrappedKey;
+    SecDbBackupWrappedKey* backupWrappedKey;
     if (checkV12DevEnabled()) {
         backupWrappedKey = [[SecDbBackupManager manager] wrapItemKey:key forKeyclass:_keyclass error:error];
         if (backupWrappedKey) {
@@ -629,15 +627,13 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
 }
 
 - (SFAESKey*)metadataClassKeyWithKeybag:(keybag_handle_t)keybag
-                     createKeyIfMissing:(bool)createIfMissing
-                    overwriteCorruptKey:(bool)force
+                            allowWrites:(bool)allowWrites
                                   error:(NSError**)error
 {
     return [[SecDbKeychainMetadataKeyStore sharedStore] keyForKeyclass:_keyclass
                                                                 keybag:keybag
                                                           keySpecifier:[self.class keySpecifier]
-                                                    createKeyIfMissing:(bool)createIfMissing
-                                                   overwriteCorruptKey:force
+                                                           allowWrites:allowWrites
                                                                  error:error];
 }
 
@@ -703,12 +699,12 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
         return [[SecDbKeychainAKSWrappedKey alloc] initRefKeyWrappedKeyWithData:wrappedKey refKeyBlob:refKeyBlob];
     }
     else {
-        NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
+        NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN];
         bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error];
         return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
     }
 #else
-    NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:(size_t)keyData.length + 40];
+    NSMutableData* wrappedKey = [[NSMutableData alloc] initWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN];
     bool success = [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:_keyclass plaintext:keyData outKeyclass:&_keyclass ciphertext:wrappedKey error:error];
     return success ? [[SecDbKeychainAKSWrappedKey alloc] initRegularWrappedKeyWithData:wrappedKey] : nil;
 #endif
@@ -719,8 +715,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
     NSData* wrappedKeyData = wrappedKey.wrappedKey;
 
     if (wrappedKey.type == SecDbKeychainAKSWrappedKeyTypeRegular) {
-        NSMutableData* unwrappedKey = [NSMutableData dataWithCapacity:wrappedKeyData.length + 40];
-        unwrappedKey.length = wrappedKeyData.length + 40;
+        NSMutableData* unwrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_KEY_LEN];
         bool result = [SecAKSObjCWrappers aksDecryptWithKeybag:_keybag keyclass:_keyclass ciphertext:wrappedKeyData outKeyclass:&_keyclass plaintext:unwrappedKey error:error];
         if (result) {
             return [[SFAESKey alloc] initWithData:unwrappedKey specifier:[self.class keySpecifier] error:error];
@@ -742,7 +737,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
             return nil;
         }
         NSDictionary* aclDict = nil;
-        der_decode_plist(NULL, kCFPropertyListImmutable, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength);
+        der_decode_plist(NULL, (CFPropertyListRef*)(void*)&aclDict, &cfError, refKeyExternalDataBytes, refKeyExternalDataBytes + refKeyExternalDataLength);
         if (!aclDict) {
             SecError(errSecDecode, &cfError, CFSTR("SecDbKeychainItemV7: failed to decode acl dict"));
         }
@@ -779,7 +774,7 @@ typedef NS_ENUM(uint32_t, SecDbKeychainAKSWrappedKeyType) {
         }
 
         CFPropertyListRef unwrappedKeyData = NULL;
-        der_decode_plist(NULL, kCFPropertyListImmutable, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength);
+        der_decode_plist(NULL, &unwrappedKeyData, &cfError, unwrappedKeyDERData, unwrappedKeyDERData + unwrappedKeyDERLength);
         SFAESKey* result = nil;
         if ([(__bridge NSData*)unwrappedKeyData isKindOfClass:[NSData class]]) {
             result = [[SFAESKey alloc] initWithData:(__bridge NSData*)unwrappedKeyData specifier:[self.class keySpecifier] error:error];
index 5c35094a743b0ce1ca73f7e6f91c60b988bbe9ba..f49ee4d6f1f0cd832089bdd07b8c2a3f724d9f9e 100644 (file)
@@ -41,12 +41,11 @@ NS_ASSUME_NONNULL_BEGIN
 
 - (void)dropClassAKeys;
 
-- (SFAESKey*)keyForKeyclass:(keyclass_t)keyClass
-                     keybag:(keybag_handle_t)keybag
-               keySpecifier:(SFAESKeySpecifier*)keySpecifier
-         createKeyIfMissing:(bool)createIfMissing
-        overwriteCorruptKey:(bool)overwriteCorruptKey
-                      error:(NSError**)error;
+- (SFAESKey* _Nullable)keyForKeyclass:(keyclass_t)keyClass
+                               keybag:(keybag_handle_t)keybag
+                         keySpecifier:(SFAESKeySpecifier*)keySpecifier
+                          allowWrites:(BOOL)allowWrites                // (re)create keys if missing, corrupt or outdated format
+                                error:(NSError**)error;
 
 @end
 
index 860529cfd731ae6aa00742d479a3d4c2c7846f91..cd7a321a10436aa53e94fb77d92bc4f11bc34da1 100644 (file)
 #import <notify.h>
 #import "SecItemServer.h"
 #import "SecAKSObjCWrappers.h"
+#import "SecDbBackupManager.h"
+#import "SecDbKeychainSerializedMetadataKey.h"
+#include "SecItemDb.h"  // kc_transaction
+#include "CheckV12DevEnabled.h"
 #import "sec_action.h"
 
-static SecDbKeychainMetadataKeyStore* sharedStore = nil;
+NS_ASSUME_NONNULL_BEGIN
+
+static SecDbKeychainMetadataKeyStore*_Nullable sharedStore = nil;
 static dispatch_queue_t sharedMetadataStoreQueue;
 static void initializeSharedMetadataStoreQueue(void) {
     static dispatch_once_t onceToken;
@@ -51,9 +57,7 @@ static void initializeSharedMetadataStoreQueue(void) {
     initializeSharedMetadataStoreQueue();
     dispatch_sync(sharedMetadataStoreQueue, ^{
         if(sharedStore) {
-            dispatch_sync(sharedStore->_queue, ^{
-                [sharedStore _onQueueDropAllKeys];
-            });
+            [sharedStore dropAllKeys];
         }
         sharedStore = nil;
     });
@@ -128,6 +132,13 @@ static void initializeSharedMetadataStoreQueue(void) {
     _keysDict[@(key_class_akpu)] = nil;
 }
 
+- (void)dropAllKeys
+{
+    dispatch_sync(_queue, ^{
+        [self _onQueueDropAllKeys];
+    });
+}
+
 - (void)_onQueueDropAllKeys
 {
     dispatch_assert_queue(_queue);
@@ -136,254 +147,350 @@ static void initializeSharedMetadataStoreQueue(void) {
     [_keysDict removeAllObjects];
 }
 
-- (void)_updateActualKeyclassIfNeeded:(keyclass_t)actualKeyclassToWriteBackToDB keyclass:(keyclass_t)keyclass
+// Return SFAESKey and actual keyclass if NSData decrypts, or nil if it does not and populate error
+- (SFAESKey* _Nullable)validateWrappedKey:(NSData*)wrapped
+                              forKeyClass:(keyclass_t)keyclass
+                           actualKeyClass:(keyclass_t*)outKeyclass
+                                   keybag:(keybag_handle_t)keybag
+                             keySpecifier:(SFAESKeySpecifier*)specifier
+                                    error:(NSError**)error
 {
-    __block CFErrorRef cfError = NULL;
+    keyclass_t classToUse = keyclass;
+    if (*outKeyclass != key_class_none && *outKeyclass != keyclass) {
+        classToUse = *outKeyclass;
+    }
+
+    NSMutableData* unwrapped = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_KEY_LEN];
+    SFAESKey* key = NULL;
+    NSError *localError = nil;
+    if ([SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:classToUse ciphertext:wrapped outKeyclass:NULL plaintext:unwrapped error:&localError]) {
+        key = [[SFAESKey alloc] initWithData:unwrapped specifier:specifier error:&localError];
+        if (!key) {
+            secerror("SecDbKeychainItemV7: AKS decrypted metadata blob for class %d but could not turn it into a key: %@", classToUse, localError);
+        }
+    }
+#if USE_KEYSTORE
+    else if (classToUse < key_class_last && *outKeyclass == key_class_none) {
+        *outKeyclass = classToUse | (key_class_last + 1);
+        if ([SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:*outKeyclass ciphertext:wrapped outKeyclass:NULL plaintext:unwrapped error:&localError]) {
+            key = [[SFAESKey alloc] initWithData:unwrapped specifier:specifier error:&localError];
+        }
+    }
+#endif
+    if (!key) {
+        // Don't be noisy for mundane error
+        if (!([localError.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && localError.code == errSecInteractionNotAllowed)) {
+            secerror("SecDbKeychainItemV7: Unable to create key from retrieved data: %@", localError);
+        }
+        if (error) {
+            *error = localError;
+        }
+    }
 
-    secnotice("SecDbKeychainItemV7", "saving actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass);
+    return key;
+}
 
-    kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) {
-        __block bool actualKeyWriteBackOk = true;
+- (SFAESKey* _Nullable)newKeyForKeyclass:(keyclass_t)keyclass
+                              withKeybag:(keybag_handle_t)keybag
+                            keySpecifier:(SFAESKeySpecifier*)specifier
+                                database:(SecDbConnectionRef)dbt
+                                   error:(NSError**)error
+{
+    NSError *localError = nil;
+    SFAESKey* key = [[SFAESKey alloc] initRandomKeyWithSpecifier:specifier error:&localError];
+    if (!key) {
+        if (error) {
+            *error = localError;
+        }
+        return nil;
+    }
+    return [self writeKey:key ForKeyclass:keyclass withKeybag:keybag keySpecifier:specifier database:dbt error:error];
+}
 
-        // we did not find an actualKeyclass entry in the db, so let's add one in now.
-        NSString *sql = @"UPDATE metadatakeys SET actualKeyclass = ? WHERE keyclass = ? AND actualKeyclass IS NULL";
-        __block CFErrorRef actualKeyWriteBackError = NULL;
-        actualKeyWriteBackOk &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &actualKeyWriteBackError, ^(sqlite3_stmt* stmt) {
-            actualKeyWriteBackOk &= SecDbBindInt(stmt, 1, actualKeyclassToWriteBackToDB, &actualKeyWriteBackError);
-            actualKeyWriteBackOk &= SecDbBindInt(stmt, 2, keyclass, &actualKeyWriteBackError);
-            actualKeyWriteBackOk &= SecDbStep(dbt, stmt, &actualKeyWriteBackError, ^(bool* stop) {
-                // woohoo
-            });
-        });
+- (SFAESKey* _Nullable)writeKey:(SFAESKey*)key
+                    ForKeyclass:(keyclass_t)keyclass
+                     withKeybag:(keybag_handle_t)keybag
+                   keySpecifier:(SFAESKeySpecifier*)specifier
+                       database:(SecDbConnectionRef)dbt
+                          error:(NSError**)error
+{
+    NSError *localError = nil;
+    dispatch_assert_queue(_queue);
 
-        if (actualKeyWriteBackOk) {
-            secnotice("SecDbKeychainItemV7", "successfully saved actualKeyclass %d for metadata keyclass %d", actualKeyclassToWriteBackToDB, keyclass);
+    NSMutableData* wrappedKey = [NSMutableData dataWithLength:APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN];
+    keyclass_t outKeyclass = keyclass;
 
+    if (![SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:keyclass plaintext:key.keyData outKeyclass:&outKeyclass ciphertext:wrappedKey error:&localError]) {
+        secerror("SecDbMetadataKeyStore: Unable to encrypt new metadata key to keybag: %@", localError);
+        if (error) {
+            *error = localError;
         }
-        else {
-            // we can always try this again in the future if it failed
-            secerror("SecDbKeychainItemV7: failed to save actualKeyclass %d for metadata keyclass %d; error: %@", actualKeyclassToWriteBackToDB, keyclass, actualKeyWriteBackError);
+        return nil;
+    }
+
+    NSData* mdkdatablob;
+    if (checkV12DevEnabled()) {
+        SecDbBackupWrappedKey* backupWrappedKey;
+        if (SecAKSSanitizedKeyclass(keyclass) != key_class_akpu) {
+            backupWrappedKey = [[SecDbBackupManager manager] wrapMetadataKey:key forKeyclass:keyclass error:&localError];
+            if (!backupWrappedKey) {
+                secerror("SecDbMetadataKeyStore: Unable to encrypt new metadata key to backup infrastructure: %@", localError);
+                if (error) {
+                    *error = localError;
+                }
+                return nil;
+            }
+        }
+
+        SecDbKeychainSerializedMetadataKey* metadatakeydata = [SecDbKeychainSerializedMetadataKey new];
+        metadatakeydata.keyclass = keyclass;
+        metadatakeydata.actualKeyclass = outKeyclass;
+        metadatakeydata.baguuid = backupWrappedKey.baguuid;
+        metadatakeydata.akswrappedkey = wrappedKey;
+        metadatakeydata.backupwrappedkey = backupWrappedKey.wrappedKey;
+        mdkdatablob = [metadatakeydata data];
+    }
+
+    __block bool ok = true;
+    __block CFErrorRef cfErr = NULL;
+    NSString* sql;
+    if (checkV12DevEnabled()) {
+        sql = @"INSERT OR REPLACE INTO metadatakeys (keyclass, actualKeyclass, data, metadatakeydata) VALUES (?,?,?,?)";
+    } else {
+        sql = @"INSERT OR REPLACE INTO metadatakeys (keyclass, actualKeyclass, data) VALUES (?,?,?)";
+    }
+    ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfErr, ^(sqlite3_stmt *stmt) {
+        ok &= SecDbBindObject(stmt, 1, (__bridge CFNumberRef)@(keyclass), &cfErr);
+        ok &= SecDbBindObject(stmt, 2, (__bridge CFNumberRef)@(outKeyclass), &cfErr);
+        if (!checkV12DevEnabled()) {
+            ok &= SecDbBindBlob(stmt, 3, wrappedKey.bytes, wrappedKey.length, SQLITE_TRANSIENT, &cfErr);
+        } else {
+            // Leave stmt param 3 unbound so SQLite will NULL it out
+            ok &= SecDbBindBlob(stmt, 4, mdkdatablob.bytes, mdkdatablob.length, SQLITE_TRANSIENT, &cfErr);
         }
-        return actualKeyWriteBackOk;
+        ok &= SecDbStep(dbt, stmt, &cfErr, NULL);
     });
+
+    if (!ok) {
+        secerror("Failed to write new metadata key for %d: %@", keyclass, cfErr);
+        BridgeCFErrorToNSErrorOut(error, cfErr);
+        return nil;
+    }
+
+    return key;
 }
 
-- (SFAESKey*)keyForKeyclass:(keyclass_t)keyclass
+- (BOOL)readKeyDataForClass:(keyclass_t)keyclass
+                     fromDb:(SecDbConnectionRef)dbt
+             actualKeyclass:(keyclass_t*)actualKeyclass
+              oldFormatData:(NSData**)oldFmt
+              newFormatData:(NSData**)newFmt
+                      error:(NSError**)error
+{
+    dispatch_assert_queue(_queue);
+
+    NSString* sql;
+    if (checkV12DevEnabled()) {
+        sql = @"SELECT data, actualKeyclass, metadatakeydata FROM metadatakeys WHERE keyclass = ?";
+    } else {
+        sql = @"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = ?";
+    }
+
+    __block NSData* wrappedKey;
+    __block NSData* mdkdatablob;
+    __block bool ok = true;
+    __block bool found = false;
+    __block CFErrorRef cfError = NULL;
+    ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) {
+        ok &= SecDbBindObject(stmt, 1, (__bridge CFNumberRef)@(keyclass), &cfError);
+        ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
+            wrappedKey = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
+            *actualKeyclass = sqlite3_column_int(stmt, 1);
+            mdkdatablob = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 2) length:sqlite3_column_bytes(stmt, 2)];
+            found = true;
+        });
+    });
+
+    // ok && !found means no error is passed back, which is specifically handled in keyForKeyclass
+    if (!ok || !found) {
+        BridgeCFErrorToNSErrorOut(error, cfError);
+        *actualKeyclass = key_class_none;
+        return NO;
+    }
+
+    *oldFmt = wrappedKey;
+    *newFmt = mdkdatablob;
+    return YES;
+}
+
+- (SFAESKey* _Nullable)fetchKeyForClass:(keyclass_t)keyclass
+                       fromDb:(SecDbConnectionRef)dbt
+                       keybag:(keybag_handle_t)keybag
+                    specifier:(SFAESKeySpecifier*)keySpecifier
+                  allowWrites:(BOOL)allowWrites
+                        error:(NSError**)error
+{
+    dispatch_assert_queue(_queue);
+
+    NSData* wrappedKey;
+    NSData* mdkdatablob;
+    keyclass_t actualKeyClass = key_class_none;
+    if (![self readKeyDataForClass:keyclass fromDb:dbt actualKeyclass:&actualKeyClass oldFormatData:&wrappedKey newFormatData:&mdkdatablob error:error]) {
+        return nil;
+    }
+
+    // each entry should be either old format or new format. Otherwise this is a bug.
+    if (!(wrappedKey.length == 0 ^ mdkdatablob.length == 0)) {
+        if (error) {
+            *error = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecInternal userInfo:@{NSLocalizedDescriptionKey: @"Metadata key blob both old-world and new-world"}];
+        }
+        return nil;
+    }
+
+    SFAESKey* key;
+    BOOL rewrite = NO;
+    keyclass_t classFromDisk = key_class_none;
+    if (wrappedKey.length > 0) {           // old format read
+        classFromDisk = actualKeyClass;
+        key = [self validateWrappedKey:wrappedKey forKeyClass:keyclass actualKeyClass:&actualKeyClass keybag:keybag keySpecifier:keySpecifier error:error];
+        if (!key) {
+            return nil;
+        }
+        if (checkV12DevEnabled()) {
+            rewrite = YES;
+        }
+    } else if (mdkdatablob.length > 0) {   // new format read
+        SecDbKeychainSerializedMetadataKey* mdkdata = [[SecDbKeychainSerializedMetadataKey alloc] initWithData:mdkdatablob];
+        if (!mdkdata) {
+            // bad read, key corrupt?
+            if (error) {
+                *error = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"New-format metadata key blob didn't deserialize"}];
+            }
+            return nil;
+        }
+
+        // Ignore the old-read actualKeyClass and use blob
+        actualKeyClass = mdkdata.actualKeyclass;
+        classFromDisk = mdkdata.actualKeyclass;
+        key = [self validateWrappedKey:mdkdata.akswrappedkey forKeyClass:keyclass actualKeyClass:&actualKeyClass keybag:keybag keySpecifier:keySpecifier error:error];
+        if (!key) {
+            return nil;
+        }
+
+        if (!mdkdata.backupwrappedkey || ![mdkdata.baguuid isEqual:[[SecDbBackupManager manager] currentBackupBagUUID]]) {
+            rewrite = YES;
+            secnotice("SecDbMetadataKeyStore", "Metadata key for %d has no or mismatching backup data; will rewrite.", keyclass);
+        }
+
+    } else {                    // Wait, there's a row for this class but not something which might be a key?
+        secnotice("SecDbMetadataKeyStore", "No metadata key found on disk despite existing row. That's odd.");
+        return nil;
+    }
+
+    if (allowWrites && (rewrite || classFromDisk != actualKeyClass)) {
+        NSError* localError;
+        if (![self writeKey:key ForKeyclass:keyclass withKeybag:keybag keySpecifier:keySpecifier database:dbt error:&localError]) {
+            // if this fails we can try again in future
+            secwarning("SecDbMetadataKeyStore: Unable to rewrite metadata key for %d to new format: %@", keyclass, localError);
+            localError = nil;
+        }
+    }
+
+    return key;
+}
+
+- (SFAESKey* _Nullable)keyForKeyclass:(keyclass_t)keyclass
                      keybag:(keybag_handle_t)keybag
                keySpecifier:(SFAESKeySpecifier*)keySpecifier
-         createKeyIfMissing:(bool)createIfMissing
-        overwriteCorruptKey:(bool)overwriteCorruptKey
+                allowWrites:(BOOL)allowWrites
                       error:(NSError**)error
 {
-    __block SFAESKey* key = nil;
-    __block NSError* nsErrorLocal = nil;
-    __block CFErrorRef cfError = NULL;
-    static __thread BOOL reentrant = NO;
+    if (!error) {
+        secerror("keyForKeyclass called without error param, this is a bug");
+        return nil;
+    }
 
+    static __thread BOOL reentrant = NO;
     NSAssert(!reentrant, @"re-entering -[%@ %@] - that shouldn't happen!", NSStringFromClass(self.class), NSStringFromSelector(_cmd));
     reentrant = YES;
 
     keyclass = SecAKSSanitizedKeyclass(keyclass);
 
+    __block SFAESKey* key = nil;
+    __block NSError* nsErrorLocal = nil;
+    __block CFErrorRef cfError = NULL;
+    __block bool ok = true;
     dispatch_sync(_queue, ^{
-        // if we think we're locked, it's possible AKS will still give us access to keys, such as during backup,
-        // but we should force AKS to be the truth and not used cached class A keys while locked
-        bool allowKeyCaching = [SecDbKeychainMetadataKeyStore cachingEnabled];
-
-        // However, we must not cache a newly-created key, just in case someone above us in the stack rolls back our database transaction and the stored key is lost.
-        __block bool keyIsNewlyCreated = false;
-#if 0
-        // <rdar://problem/37523001> Fix keychain lock state check to be both secure and fast for EDU mode
-        if (![SecDbKeychainItemV7 isKeychainUnlocked]) {
-            [self _onQueueDropClassAKeys];
-            allowKeyCaching = !(keyclass == key_class_ak || keyclass == key_class_aku || keyclass == key_class_akpu);
-        }
-#endif
+        // try our cache first and rejoice if that succeeds
+        bool allowCaching = [SecDbKeychainMetadataKeyStore cachingEnabled];
 
-        key = allowKeyCaching ? self->_keysDict[@(keyclass)] : nil;
-        if (!key) {
-            __block bool ok = true;
-            __block bool metadataKeyDoesntAuthenticate = false;
-            ok &= kc_with_dbt_non_item_tables(createIfMissing, &cfError, ^bool(SecDbConnectionRef dbt) {
-                __block NSString* sql = [NSString stringWithFormat:@"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = %d", keyclass];
-                ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt *stmt) {
-                    ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
-                        NSData* wrappedKeyData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
-                        NSMutableData* unwrappedKeyData = [NSMutableData dataWithLength:wrappedKeyData.length];
-
-                        keyclass_t actualKeyclass = sqlite3_column_int(stmt, 1);
-
-                        keyclass_t actualKeyclassToWriteBackToDB = 0;
-                        keyclass_t keyclassForUnwrapping = actualKeyclass == 0 ? keyclass : actualKeyclass;
-                        ok &= [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyclassForUnwrapping ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&nsErrorLocal];
-                        if (ok) {
-                            key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&nsErrorLocal];
-
-                            if(!key) {
-                                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) {
-                                actualKeyclassToWriteBackToDB = keyclassForUnwrapping;
-                            }
-                        }
-#if USE_KEYSTORE
-                        else if (actualKeyclass == 0 && keyclass <= key_class_last) {
-                            // in this case we might have luck decrypting with a key-rolled keyclass
-                            keyclass_t keyrolledKeyclass = keyclass | (key_class_last + 1);
-                            secerror("SecDbKeychainItemV7: failed to decrypt metadata key for class %d, but trying keyrolled keyclass (%d); error: %@", keyclass, keyrolledKeyclass, nsErrorLocal);
-
-                            // we don't want to pollute subsequent error-handling logic with what happens on our retry
-                            // we'll give it a shot, and if it works, great - if it doesn't work, we'll just report that error in the log and move on
-                            NSError* retryError = nil;
-                            ok = [SecAKSObjCWrappers aksDecryptWithKeybag:keybag keyclass:keyrolledKeyclass ciphertext:wrappedKeyData outKeyclass:NULL plaintext:unwrappedKeyData error:&retryError];
-
-                            if (ok) {
-                                secerror("SecDbKeychainItemV7: successfully decrypted metadata key using keyrolled keyclass %d", keyrolledKeyclass);
-                                key = [[SFAESKey alloc] initWithData:unwrappedKeyData specifier:keySpecifier error:&retryError];
-
-                                if(!key) {
-                                    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;
-                                }
-                            }
-                            else {
-                                secerror("SecDbKeychainItemV7: failed to decrypt metadata key with keyrolled keyclass %d; error: %@", keyrolledKeyclass, retryError);
-                            }
-                        }
-#endif
+        key = allowCaching ? self->_keysDict[@(keyclass)] : nil;
+        if (key) {
+            return;     // Cache contains validated key for class, excellent!
+        }
 
-                        if (ok && key) {
-                            if (actualKeyclassToWriteBackToDB > 0) {
-                                // check if we have updated this keyclass or not already
-                                static NSMutableDictionary* updated = NULL;
-                                if (!updated) {
-                                    updated = [NSMutableDictionary dictionary];
-                                }
-                                if (!updated[@(keyclass)]) {
-                                    updated[@(keyclass)] = @YES;
-                                    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
-                                        [self _updateActualKeyclassIfNeeded:actualKeyclassToWriteBackToDB keyclass:keyclass];
-                                    });
-                                }
-                            }
-                        }
-                        else {
-                            if (nsErrorLocal && [nsErrorLocal.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && nsErrorLocal.code == errSecInteractionNotAllowed) {
-                                static dispatch_once_t kclockedtoken;
-                                static sec_action_t kclockedaction;
-                                dispatch_once(&kclockedtoken, ^{
-                                    kclockedaction = sec_action_create("keychainlockedlogmessage", 1);
-                                    sec_action_set_handler(kclockedaction, ^{
-                                        secerror("SecDbKeychainItemV7: failed to decrypt metadata key because the keychain is locked (%d)", (int)errSecInteractionNotAllowed);
-                                    });
-                                });
-                                sec_action_perform(kclockedaction);
-                            } else {
-                                secerror("SecDbKeychainItemV7: failed to decrypt and create metadata key for class %d; error: %@", keyclass, nsErrorLocal);
-
-                                // 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) {
-                                    if (__security_simulatecrash_enabled()) {
-                                        os_log_fault(secLogObjForScope("SecDbKeychainItemV7"), "Metadata class key (%d) failed to decrypt: %@", keyclass, nsErrorLocal);
-                                    }
-                                }
-                            }
-                        }
+        // Key not in cache. Open a transaction to find or optionally (re)create key. Transactions can be nested, so this is fine.
+        ok &= kc_with_dbt_non_item_tables(true, &cfError, ^bool(SecDbConnectionRef dbt) {
+            key = [self fetchKeyForClass:keyclass
+                                  fromDb:dbt
+                                  keybag:keybag
+                               specifier:keySpecifier
+                             allowWrites:allowWrites
+                                   error:&nsErrorLocal];
+
+            // The code for this conditional is a little convoluted because I want the "keychain locked" message to take precedence over the "not allowed to create one" message.
+            if (!key && ([nsErrorLocal.domain isEqualToString:(__bridge NSString*)kSecErrorDomain] && nsErrorLocal.code == errSecInteractionNotAllowed)) {
+                static sec_action_t logKeychainLockedMessageAction;
+                static dispatch_once_t keychainLockedMessageOnceToken;
+                dispatch_once(&keychainLockedMessageOnceToken, ^{
+                    logKeychainLockedMessageAction = sec_action_create("keychainlockedlogmessage", 1);
+                    sec_action_set_handler(logKeychainLockedMessageAction, ^{
+                        secerror("SecDbKeychainItemV7: cannot decrypt metadata key because the keychain is locked (%ld)", (long)nsErrorLocal.code);
                     });
                 });
-
-                bool keyNotYetCreated = ok && !key;
-                bool forceOverwriteBadKey = !key && metadataKeyDoesntAuthenticate && overwriteCorruptKey;
-
-                if (createIfMissing && (keyNotYetCreated || forceOverwriteBadKey)) {
-                    // we completed the database query, but no key exists or it's broken - we should create one
-                    if(forceOverwriteBadKey) {
-                        secerror("SecDbKeychainItemV7: metadata key is irreparably corrupt; throwing away forever");
-                        // TODO: track this in LocalKeychainAnalytics
-                    }
-
-                    ok = true; // Reset 'ok': we have a second chance
-
-                    key = [[SFAESKey alloc] initRandomKeyWithSpecifier:keySpecifier error:&nsErrorLocal];
-                    keyIsNewlyCreated = true;
-
-                    if (key) {
-                        NSMutableData* wrappedKey = [NSMutableData dataWithLength:key.keyData.length + 40];
-                        keyclass_t outKeyclass = keyclass;
-                        ok &= [SecAKSObjCWrappers aksEncryptWithKeybag:keybag keyclass:keyclass plaintext:key.keyData outKeyclass:&outKeyclass ciphertext:wrappedKey error:&nsErrorLocal];
-                        if (ok) {
-                            secinfo("SecDbKeychainItemV7", "attempting to save new metadata key for keyclass %d with actualKeyclass %d", keyclass, outKeyclass);
-                            NSString* insertString = forceOverwriteBadKey ? @"INSERT OR REPLACE" : @"INSERT";
-                            sql = [NSString stringWithFormat:@"%@ into metadatakeys (keyclass, actualKeyclass, data) VALUES (?, ?, ?)", insertString];
-                            ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &cfError, ^(sqlite3_stmt* stmt) {
-                                ok &= SecDbBindInt(stmt, 1, keyclass, &cfError);
-                                ok &= SecDbBindInt(stmt, 2, outKeyclass, &cfError);
-                                ok &= SecDbBindBlob(stmt, 3, wrappedKey.bytes, wrappedKey.length, SQLITE_TRANSIENT, NULL);
-                                ok &= SecDbStep(dbt, stmt, &cfError, ^(bool *stop) {
-                                    // woohoo
-                                });
-                            });
-
-                            if (ok) {
-                                secnotice("SecDbKeychainItemV7", "successfully saved new metadata key for keyclass %d", keyclass);
-                            }
-                            else {
-                                secerror("SecDbKeychainItemV7: failed to save new metadata key for keyclass %d - probably there is already one in the database: %@", keyclass, cfError);
-                            }
-                        } else {
-                            secerror("SecDbKeychainItemV7: unable to encrypt new metadata key(%d) with keybag(%d): %@", keyclass, keybag, nsErrorLocal);
-                        }
-                    }
-                    else {
-                        ok = false;
-                    }
-                } else if(!key) {
-                    // No key, but we're not supposed to make one. Make an error if one doesn't yet exist.
-                    ok = false;
-                    if(!nsErrorLocal) {
-                        nsErrorLocal = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Unable to find or create a suitable metadata key"}];
-                    }
+                sec_action_perform(logKeychainLockedMessageAction);
+            } else if (!key && !allowWrites) {
+                secwarning("SecDbMetadataKeyStore: Unable to load metadatakey for class %d from disk (%@) and not allowed to create new one", keyclass, nsErrorLocal);
+                if (!nsErrorLocal) {
+                    // If this is at creation time we are allowed to create so won't be here
+                    // If this is at fetch time and we have a missing or bad key then the item /is/ dead
+                    nsErrorLocal = [NSError errorWithDomain:(id)kSecErrorDomain code:errSecDecode userInfo:@{NSLocalizedDescriptionKey: @"Unable to find a suitable metadata key and not permitted to create one"}];
                 }
-
-                return ok;
-            });
-
-            if (ok && key) {
-                // We can't cache a newly-created key, just in case this db transaction is rolled back and we lose the persisted key.
-                // Don't worry, we'll cache it as soon as it's used again.
-                if (allowKeyCaching && !keyIsNewlyCreated) {
-                    self->_keysDict[@(keyclass)] = key;
-                    __weak __typeof(self) weakSelf = self;
-                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60 * 5 * NSEC_PER_SEC)), self->_queue, ^{
-                        [weakSelf _onQueueDropClassAKeys];
-                    });
+                return false;
+            // If this error is errSecDecode, then it's failed authentication and likely will forever. Other errors are scary. If !key and !error then no key existed.
+            } else if ((!key && !nsErrorLocal) || (!key && [nsErrorLocal.domain isEqualToString:NSOSStatusErrorDomain] && nsErrorLocal.code == errSecDecode)) {
+                secwarning("SecDbMetadataKeyStore: unable to use key (%ld), will attempt to create new one", (long)nsErrorLocal.code);
+                nsErrorLocal = nil;
+                key = [self newKeyForKeyclass:keyclass withKeybag:keybag keySpecifier:keySpecifier database:dbt error:&nsErrorLocal];
+                if (!key) {
+                    secerror("SecDbMetadataKeyStore: unable to create or save new key: %@", nsErrorLocal);
+                    return false;
                 }
+            } else if (!key) {
+                secerror("SecDbMetadataKeyStore: scary error encountered: %@", nsErrorLocal);
+            } else if (allowCaching) {
+                self->_keysDict[@(keyclass)] = key; // Only cache keys fetched from disk
             }
-            else {
-                key = nil;
-            }
+            return !!key;
+        }); // kc_with_dbt
+    }); // our queue
+
+    if (!ok || !key) {
+        if (nsErrorLocal) {
+            *error = nsErrorLocal;
+            CFReleaseNull(cfError);
+        } else {
+            BridgeCFErrorToNSErrorOut(error, cfError);
         }
-    });
+        assert(*error); // Triggers only in testing, which is by design not to break production
+        key = nil;
+    }
 
     reentrant = NO;
 
-    if (error && nsErrorLocal) {
-        *error = nsErrorLocal;
-        CFReleaseNull(cfError);
-    }
-    else {
-        BridgeCFErrorToNSErrorOut(error, cfError);
-    }
-
     return key;
 }
 
 @end
+
+NS_ASSUME_NONNULL_END
diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadataKey.proto b/keychain/securityd/SecDbKeychainV7-protobufs/SecDbKeychainSerializedMetadataKey.proto
new file mode 100644 (file)
index 0000000..0e4f960
--- /dev/null
@@ -0,0 +1,9 @@
+syntax = "proto2";
+
+message SecDbKeychainSerializedMetadataKey {
+    optional int32 keyclass = 1;
+    optional int32 actualKeyclass = 2;
+    optional bytes baguuid = 3;
+    optional bytes akswrappedkey = 4;
+    optional bytes backupwrappedkey = 5;
+}
diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.h b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.h
new file mode 100644 (file)
index 0000000..9ff7f68
--- /dev/null
@@ -0,0 +1,55 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from SecDbKeychainSerializedMetadataKey.proto
+
+#import <Foundation/Foundation.h>
+#import <ProtocolBuffer/PBCodable.h>
+
+#ifdef __cplusplus
+#define SECDBKEYCHAINSERIALIZEDMETADATAKEY_FUNCTION extern "C"
+#else
+#define SECDBKEYCHAINSERIALIZEDMETADATAKEY_FUNCTION extern
+#endif
+
+@interface SecDbKeychainSerializedMetadataKey : PBCodable <NSCopying>
+{
+    int32_t _actualKeyclass;
+    NSData *_akswrappedkey;
+    NSData *_backupwrappedkey;
+    NSData *_baguuid;
+    int32_t _keyclass;
+    struct {
+        int actualKeyclass:1;
+        int keyclass:1;
+    } _has;
+}
+
+
+@property (nonatomic) BOOL hasKeyclass;
+@property (nonatomic) int32_t keyclass;
+
+@property (nonatomic) BOOL hasActualKeyclass;
+@property (nonatomic) int32_t actualKeyclass;
+
+@property (nonatomic, readonly) BOOL hasBaguuid;
+@property (nonatomic, retain) NSData *baguuid;
+
+@property (nonatomic, readonly) BOOL hasAkswrappedkey;
+@property (nonatomic, retain) NSData *akswrappedkey;
+
+@property (nonatomic, readonly) BOOL hasBackupwrappedkey;
+@property (nonatomic, retain) NSData *backupwrappedkey;
+
+// Performs a shallow copy into other
+- (void)copyTo:(SecDbKeychainSerializedMetadataKey *)other;
+
+// Performs a deep merge from other into self
+// If set in other, singular values in self are replaced in self
+// Singular composite values are recursively merged
+// Repeated values from other are appended to repeated values in self
+- (void)mergeFrom:(SecDbKeychainSerializedMetadataKey *)other;
+
+SECDBKEYCHAINSERIALIZEDMETADATAKEY_FUNCTION BOOL SecDbKeychainSerializedMetadataKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadataKey *self, __unsafe_unretained PBDataReader *reader);
+
+@end
+
diff --git a/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.m b/keychain/securityd/SecDbKeychainV7-protobufs/generated_source/SecDbKeychainSerializedMetadataKey.m
new file mode 100644 (file)
index 0000000..b16f7a5
--- /dev/null
@@ -0,0 +1,294 @@
+// This file was automatically generated by protocompiler
+// DO NOT EDIT!
+// Compiled from SecDbKeychainSerializedMetadataKey.proto
+
+#import "SecDbKeychainSerializedMetadataKey.h"
+#import <ProtocolBuffer/PBConstants.h>
+#import <ProtocolBuffer/PBHashUtil.h>
+#import <ProtocolBuffer/PBDataReader.h>
+
+#if !__has_feature(objc_arc)
+# error This generated file depends on ARC but it is not enabled; turn on ARC, or use 'objc_use_arc' option to generate non-ARC code.
+#endif
+
+@implementation SecDbKeychainSerializedMetadataKey
+
+@synthesize keyclass = _keyclass;
+- (void)setKeyclass:(int32_t)v
+{
+    _has.keyclass = YES;
+    _keyclass = v;
+}
+- (void)setHasKeyclass:(BOOL)f
+{
+    _has.keyclass = f;
+}
+- (BOOL)hasKeyclass
+{
+    return _has.keyclass != 0;
+}
+@synthesize actualKeyclass = _actualKeyclass;
+- (void)setActualKeyclass:(int32_t)v
+{
+    _has.actualKeyclass = YES;
+    _actualKeyclass = v;
+}
+- (void)setHasActualKeyclass:(BOOL)f
+{
+    _has.actualKeyclass = f;
+}
+- (BOOL)hasActualKeyclass
+{
+    return _has.actualKeyclass != 0;
+}
+- (BOOL)hasBaguuid
+{
+    return _baguuid != nil;
+}
+@synthesize baguuid = _baguuid;
+- (BOOL)hasAkswrappedkey
+{
+    return _akswrappedkey != nil;
+}
+@synthesize akswrappedkey = _akswrappedkey;
+- (BOOL)hasBackupwrappedkey
+{
+    return _backupwrappedkey != nil;
+}
+@synthesize backupwrappedkey = _backupwrappedkey;
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"%@ %@", [super description], [self dictionaryRepresentation]];
+}
+
+- (NSDictionary *)dictionaryRepresentation
+{
+    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
+    if (self->_has.keyclass)
+    {
+        [dict setObject:[NSNumber numberWithInt:self->_keyclass] forKey:@"keyclass"];
+    }
+    if (self->_has.actualKeyclass)
+    {
+        [dict setObject:[NSNumber numberWithInt:self->_actualKeyclass] forKey:@"actualKeyclass"];
+    }
+    if (self->_baguuid)
+    {
+        [dict setObject:self->_baguuid forKey:@"baguuid"];
+    }
+    if (self->_akswrappedkey)
+    {
+        [dict setObject:self->_akswrappedkey forKey:@"akswrappedkey"];
+    }
+    if (self->_backupwrappedkey)
+    {
+        [dict setObject:self->_backupwrappedkey forKey:@"backupwrappedkey"];
+    }
+    return dict;
+}
+
+BOOL SecDbKeychainSerializedMetadataKeyReadFrom(__unsafe_unretained SecDbKeychainSerializedMetadataKey *self, __unsafe_unretained PBDataReader *reader) {
+    while (PBReaderHasMoreData(reader)) {
+        uint32_t tag = 0;
+        uint8_t aType = 0;
+
+        PBReaderReadTag32AndType(reader, &tag, &aType);
+
+        if (PBReaderHasError(reader))
+            break;
+
+        if (aType == TYPE_END_GROUP) {
+            break;
+        }
+
+        switch (tag) {
+
+            case 1 /* keyclass */:
+            {
+                self->_has.keyclass = YES;
+                self->_keyclass = PBReaderReadInt32(reader);
+            }
+            break;
+            case 2 /* actualKeyclass */:
+            {
+                self->_has.actualKeyclass = YES;
+                self->_actualKeyclass = PBReaderReadInt32(reader);
+            }
+            break;
+            case 3 /* baguuid */:
+            {
+                NSData *new_baguuid = PBReaderReadData(reader);
+                self->_baguuid = new_baguuid;
+            }
+            break;
+            case 4 /* akswrappedkey */:
+            {
+                NSData *new_akswrappedkey = PBReaderReadData(reader);
+                self->_akswrappedkey = new_akswrappedkey;
+            }
+            break;
+            case 5 /* backupwrappedkey */:
+            {
+                NSData *new_backupwrappedkey = PBReaderReadData(reader);
+                self->_backupwrappedkey = new_backupwrappedkey;
+            }
+            break;
+            default:
+                if (!PBReaderSkipValueWithTag(reader, tag, aType))
+                    return NO;
+                break;
+        }
+    }
+    return !PBReaderHasError(reader);
+}
+
+- (BOOL)readFrom:(PBDataReader *)reader
+{
+    return SecDbKeychainSerializedMetadataKeyReadFrom(self, reader);
+}
+- (void)writeTo:(PBDataWriter *)writer
+{
+    /* keyclass */
+    {
+        if (self->_has.keyclass)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_keyclass, 1);
+        }
+    }
+    /* actualKeyclass */
+    {
+        if (self->_has.actualKeyclass)
+        {
+            PBDataWriterWriteInt32Field(writer, self->_actualKeyclass, 2);
+        }
+    }
+    /* baguuid */
+    {
+        if (self->_baguuid)
+        {
+            PBDataWriterWriteDataField(writer, self->_baguuid, 3);
+        }
+    }
+    /* akswrappedkey */
+    {
+        if (self->_akswrappedkey)
+        {
+            PBDataWriterWriteDataField(writer, self->_akswrappedkey, 4);
+        }
+    }
+    /* backupwrappedkey */
+    {
+        if (self->_backupwrappedkey)
+        {
+            PBDataWriterWriteDataField(writer, self->_backupwrappedkey, 5);
+        }
+    }
+}
+
+- (void)copyTo:(SecDbKeychainSerializedMetadataKey *)other
+{
+    if (self->_has.keyclass)
+    {
+        other->_keyclass = _keyclass;
+        other->_has.keyclass = YES;
+    }
+    if (self->_has.actualKeyclass)
+    {
+        other->_actualKeyclass = _actualKeyclass;
+        other->_has.actualKeyclass = YES;
+    }
+    if (_baguuid)
+    {
+        other.baguuid = _baguuid;
+    }
+    if (_akswrappedkey)
+    {
+        other.akswrappedkey = _akswrappedkey;
+    }
+    if (_backupwrappedkey)
+    {
+        other.backupwrappedkey = _backupwrappedkey;
+    }
+}
+
+- (id)copyWithZone:(NSZone *)zone
+{
+    SecDbKeychainSerializedMetadataKey *copy = [[[self class] allocWithZone:zone] init];
+    if (self->_has.keyclass)
+    {
+        copy->_keyclass = _keyclass;
+        copy->_has.keyclass = YES;
+    }
+    if (self->_has.actualKeyclass)
+    {
+        copy->_actualKeyclass = _actualKeyclass;
+        copy->_has.actualKeyclass = YES;
+    }
+    copy->_baguuid = [_baguuid copyWithZone:zone];
+    copy->_akswrappedkey = [_akswrappedkey copyWithZone:zone];
+    copy->_backupwrappedkey = [_backupwrappedkey copyWithZone:zone];
+    return copy;
+}
+
+- (BOOL)isEqual:(id)object
+{
+    SecDbKeychainSerializedMetadataKey *other = (SecDbKeychainSerializedMetadataKey *)object;
+    return [other isMemberOfClass:[self class]]
+    &&
+    ((self->_has.keyclass && other->_has.keyclass && self->_keyclass == other->_keyclass) || (!self->_has.keyclass && !other->_has.keyclass))
+    &&
+    ((self->_has.actualKeyclass && other->_has.actualKeyclass && self->_actualKeyclass == other->_actualKeyclass) || (!self->_has.actualKeyclass && !other->_has.actualKeyclass))
+    &&
+    ((!self->_baguuid && !other->_baguuid) || [self->_baguuid isEqual:other->_baguuid])
+    &&
+    ((!self->_akswrappedkey && !other->_akswrappedkey) || [self->_akswrappedkey isEqual:other->_akswrappedkey])
+    &&
+    ((!self->_backupwrappedkey && !other->_backupwrappedkey) || [self->_backupwrappedkey isEqual:other->_backupwrappedkey])
+    ;
+}
+
+- (NSUInteger)hash
+{
+    return 0
+    ^
+    (self->_has.keyclass ? PBHashInt((NSUInteger)self->_keyclass) : 0)
+    ^
+    (self->_has.actualKeyclass ? PBHashInt((NSUInteger)self->_actualKeyclass) : 0)
+    ^
+    [self->_baguuid hash]
+    ^
+    [self->_akswrappedkey hash]
+    ^
+    [self->_backupwrappedkey hash]
+    ;
+}
+
+- (void)mergeFrom:(SecDbKeychainSerializedMetadataKey *)other
+{
+    if (other->_has.keyclass)
+    {
+        self->_keyclass = other->_keyclass;
+        self->_has.keyclass = YES;
+    }
+    if (other->_has.actualKeyclass)
+    {
+        self->_actualKeyclass = other->_actualKeyclass;
+        self->_has.actualKeyclass = YES;
+    }
+    if (other->_baguuid)
+    {
+        [self setBaguuid:other->_baguuid];
+    }
+    if (other->_akswrappedkey)
+    {
+        [self setAkswrappedkey:other->_akswrappedkey];
+    }
+    if (other->_backupwrappedkey)
+    {
+        [self setBackupwrappedkey:other->_backupwrappedkey];
+    }
+}
+
+@end
+
index 88d72177e7886dddf547bb884659fc908425017a..f6d32354552f4d64297b420d9ad27127aaab4298 100644 (file)
@@ -412,11 +412,6 @@ void query_add_not_attribute(const void *key, const void *value, Query *q)
     }
 }
 
-
-/* AUDIT[securityd](done):
- key (ok) is a caller provided, string starting with 'm'.
- value (ok) is a caller provided, non NULL CFTypeRef.
- */
 static void query_add_match(const void *key, const void *value, Query *q)
 {
     /* Record the match key, value in q_pairs. */
@@ -874,6 +869,7 @@ bool query_notify_and_destroy(Query *q, bool ok, CFErrorRef *error) {
 Query *query_create(const SecDbClass *qclass,
                     CFDataRef musr,
                     CFDictionaryRef query,
+                    SecurityClient* client,
                     CFErrorRef *error)
 {
     if (!qclass) {
@@ -926,6 +922,16 @@ Query *query_create(const SecDbClass *qclass,
     q->q_match_begin = q->q_match_end = key_count;
     q->q_item = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 
+    if (client) {
+        // If not, don't do anything. Parent apps, schema migration, etc. all need access to all items, clip or no
+        if (client->isAppClip) {
+            secdebug("query", "Client is app clip, adding restriction to query attribute");
+            CFDictionaryAddValue(q->q_item, kSecAttrAppClipItem, kCFBooleanTrue);
+        }
+    } else {
+        secdebug("query", "no client information specified so not tweaking query attributes");
+    }
+
     return q;
 }
 
@@ -949,9 +955,9 @@ bool query_update_parse(Query *q, CFDictionaryRef update,
     return query_parse_with_applier(q, update, query_update_applier, error);
 }
 
-Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error) {
+Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, SecurityClient* client, CFErrorRef *error) {
     Query *q;
-    q = query_create(query_get_class(query, error), musr, query, error);
+    q = query_create(query_get_class(query, error), musr, query, client, error);
     if (q) {
         q->q_limit = limit;
         if (!query_parse(q, query, error)) {
index 820090bfdb34860c23961ab2ae146f298f2b36ce..861c3ca32437d9a2a57ff7b289e4a453b1c68a85 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "keychain/securityd/SecKeybagSupport.h"
 #include "keychain/securityd/SecDbItem.h"
+#include "ipc/securityd_client.h"   // be able to create queries which restrict API
 
 __BEGIN_DECLS
 
@@ -116,9 +117,16 @@ typedef struct Query
     // instead of reporting them to the client as an error.
     bool q_skip_acl_items;
 
+    // Some queries (e.g. backups) explicitly do not want to deal with clip-created items
+    bool q_skip_app_clip_items;
+
     // Set to true if any UUIDs generated by this query should be generated from the SHA2 digest of the item in question
     bool q_uuid_from_primary_key;
 
+    // Set to true if you'd like any Tombstones created by this query to have an mdat that is one second after the non-tombstone's mdat.
+    // This is used if you're deleting an item, but are unsure when the item deletion occurred (e.g., you receive an item delete via CloudKit).
+    bool q_tombstone_use_mdat_from_item;
+
     // Set this to a callback that, on an add query, will get passed along with the CKKS subsystem and called when the item makes it off-device (or doesn't)
     __unsafe_unretained SecBoolCFErrorCallback q_add_sync_callback;
 
@@ -146,10 +154,10 @@ typedef struct Query
     Pair q_pairs[];
 } Query;
 
-Query *query_create(const SecDbClass *qclass, CFDataRef musr, CFDictionaryRef query, CFErrorRef *error);
+Query *query_create(const SecDbClass *qclass, CFDataRef musr, CFDictionaryRef query, SecurityClient* client, CFErrorRef *error);
 bool query_destroy(Query *q, CFErrorRef *error);
 bool query_error(Query *q, CFErrorRef *error);
-Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, CFErrorRef *error);
+Query *query_create_with_limit(CFDictionaryRef query, CFDataRef musr, CFIndex limit, SecurityClient* client, CFErrorRef *error);
 void query_add_attribute(const void *key, const void *value, Query *q);
 void query_add_or_attribute(const void *key, const void *value, Query *q);
 void query_add_not_attribute(const void *key, const void *value, Query *q);
index 78591837f32a8d53a7bb8b321838d5342c7f96e8..605cfd1904d216043e339921da0c079c456a171a 100644 (file)
@@ -78,6 +78,16 @@ CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error) {
     return names;
 }
 
+CFStringRef SecServerItemBackupEnsureCopyView(CFStringRef viewName, CFErrorRef *error) {
+    __block CFStringRef name = NULL;
+    if(!withDataSourceAndEngine(error, ^(SOSDataSourceRef ds, SOSEngineRef engine) {
+        name = SOSEngineEnsureCopyBackupPeerForView(engine, viewName, error);
+    })) {
+        CFReleaseNull(name);
+    }
+    return name;
+}
+
 // TODO Move to datasource and remove dsRestoreObject
 static bool SOSDataSourceWithBackup(SOSDataSourceRef ds, CFDataRef backup, keybag_handle_t bag_handle, CFErrorRef *error, void(^with)(SOSObjectRef item)) {
     __block bool ok = true;
index 04607c6073ea2ea988fc5e32870ec39d1b457feb..87156d2829d35efd041511f456e4dcdefe3ddeed 100644 (file)
@@ -37,6 +37,7 @@ __BEGIN_DECLS
 int SecServerItemBackupHandoffFD(CFStringRef backupName, CFErrorRef *error);
 bool SecServerItemBackupSetConfirmedManifest(CFStringRef backupName, CFDataRef keybagDigest, CFDataRef manifest, CFErrorRef *error);
 CFArrayRef SecServerItemBackupCopyNames(CFErrorRef *error);
+CFStringRef SecServerItemBackupEnsureCopyView(CFStringRef peerID, CFErrorRef *error);
 bool SecServerItemBackupRestore(CFStringRef backupName, CFStringRef peerID, CFDataRef keybag, CFDataRef secret, CFDataRef backup, CFErrorRef *error);
 
 __END_DECLS
index d5a3a283ab01216c5e38b0373d7f334c36d3796e..9f6232e277e20955f42450723b116a65b94840e7 100644 (file)
@@ -158,7 +158,7 @@ static SOSManifestRef SecItemDataSourceCopyManifestWithQueries(SecItemDataSource
 }
 
 static Query *SecItemDataSourceAppendQuery(CFMutableArrayRef queries, const SecDbClass *qclass, bool noTombstones, CFErrorRef *error) {
-    Query *q = query_create(qclass, NULL, NULL, error);
+    Query *q = query_create(qclass, NULL, NULL, NULL, error);
     if (q) {
         q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask;
         q->q_limit = kSecMatchUnlimited;
@@ -304,6 +304,7 @@ static SOSManifestRef SecItemDataSourceCopyManifestWithViewNameSet(SecItemDataSo
 }
 
 // Return the newest object (conflict resolver)
+// Any fields marked as "kSecDbSyncSOSCannotSyncFlag" that are in item2 will be present in the returned item.
 static SecDbItemRef SecItemDataSourceCopyMergedItem(SecDbItemRef item1, SecDbItemRef item2, CFErrorRef *error) {
     CFErrorRef localError = NULL;
     SecDbItemRef result = NULL;
@@ -323,7 +324,7 @@ static SecDbItemRef SecItemDataSourceCopyMergedItem(SecDbItemRef item1, SecDbIte
             // Return the item with the smallest digest.
             CFDataRef digest1 = SecDbItemGetSHA1(item1, &localError);
             CFDataRef digest2 = SecDbItemGetSHA1(item2, &localError);
-            if (digest1 && digest2) switch (CFDataCompare(digest1, digest2)) {
+            if (digest1 && digest2) switch (CFDataCompareDERData(digest1, digest2)) {
                 case kCFCompareGreaterThan:
                 case kCFCompareEqualTo:
                     result = item2;
@@ -350,6 +351,22 @@ static SecDbItemRef SecItemDataSourceCopyMergedItem(SecDbItemRef item1, SecDbIte
         else
             CFRelease(localError);
     }
+
+    // Note, if we chose item2 as result above, there's no need to move attributes from item2 to item2
+    if(result && item2 && result != item2) {
+        // We'd like to preserve our local UUID, no matter what. UUIDs are not sent across SOS channels, and so items
+        // arriving via SOS have randomly generated UUIDs.
+        SecDbForEachAttr(SecDbItemGetClass(result), attr) {
+            if(CFEqualSafe(attr->name, v10itemuuid.name)) {
+                SecItemPreserveAttribute(result, item2, attr);
+            }
+        }
+
+        SecDbForEachAttrWithMask(SecDbItemGetClass(result), attr, kSecDbSyncSOSCannotSyncFlag) {
+            SecItemPreserveAttribute(result, item2, attr);
+        }
+    }
+
     return CFRetainSafe(result);
 }
 
@@ -399,7 +416,7 @@ static bool dsForEachObject(SOSDataSourceRef data_source, SOSTransactionRef txn,
         // Setup
         for (size_t class_ix = 0; class_ix < dsSyncedClassesSize; ++class_ix) {
             result = (result
-                      && (queries[class_ix] = query_create(dsSyncedClasses()[class_ix], NULL, NULL, error))
+                      && (queries[class_ix] = query_create(dsSyncedClasses()[class_ix], NULL, NULL, NULL, error))
                       && (sqls[class_ix] = SecDbItemCopySelectSQL(queries[class_ix], return_attr, use_attr_in_where, NULL))
                       && (stmts[class_ix] = SecDbCopyStmt(dbconn, sqls[class_ix], NULL, error)));
         }
@@ -480,9 +497,9 @@ static CFDateRef copyObjectModDate(SOSObjectRef object, CFErrorRef *error) {
 
 static CFDictionaryRef objectCopyPropertyList(SOSObjectRef object, CFErrorRef *error) {
     SecDbItemRef item = (SecDbItemRef) object;
-    CFMutableDictionaryRef secretDataDict = SecDbItemCopyPListWithMask(item, kSecDbReturnDataFlag, error);
-    CFMutableDictionaryRef cryptoDataDict = SecDbItemCopyPListWithMask(item, kSecDbInCryptoDataFlag, error);
-    CFMutableDictionaryRef authDataDict = SecDbItemCopyPListWithMask(item, kSecDbInAuthenticatedDataFlag, error);
+    CFMutableDictionaryRef secretDataDict = SecDbItemCopyPListWithFlagAndSkip(item, kSecDbReturnDataFlag, kSecDbSyncSOSCannotSyncFlag, error);
+    CFMutableDictionaryRef cryptoDataDict = SecDbItemCopyPListWithFlagAndSkip(item, kSecDbInCryptoDataFlag, kSecDbSyncSOSCannotSyncFlag, error);
+    CFMutableDictionaryRef authDataDict = SecDbItemCopyPListWithFlagAndSkip(item, kSecDbInAuthenticatedDataFlag, kSecDbSyncSOSCannotSyncFlag, error);
     
     if (cryptoDataDict) {
         if (authDataDict) {
@@ -665,7 +682,7 @@ static CFDataRef dsCopyStateWithKey(SOSDataSourceRef data_source, CFStringRef ke
                                                                           NULL);
     CFReleaseSafe(dataSourceID);
     __block CFDataRef data = NULL;
-    SecDbQueryRef query = query_create(genp_class(), NULL, dict, error);
+    SecDbQueryRef query = query_create(genp_class(), NULL, dict, NULL, error);
     if (query) {
         if (query->q_item)  CFReleaseSafe(query->q_item);
         query->q_item = dict;
@@ -710,7 +727,7 @@ static CFDataRef dsCopyItemDataWithKeys(SOSDataSourceRef data_source, CFDictiona
     SecItemDataSourceRef ds = (SecItemDataSourceRef)data_source;
     CFMutableDictionaryRef dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, keys);
     __block CFDataRef data = NULL;
-    SecDbQueryRef query = query_create(genp_class(), NULL, dict, error);
+    SecDbQueryRef query = query_create(genp_class(), NULL, dict, NULL, error);
     if (query) {
         if (query->q_item)  CFReleaseSafe(query->q_item);
         query->q_item = dict;
index c52586255aee3f5672d394135564551789fa0540..739db220353b5659f26d90f2699db9d1f641bd12 100644 (file)
@@ -313,8 +313,11 @@ s3dl_query_add(SecDbConnectionRef dbt, Query *q, CFTypeRef *result, CFErrorRef *
     }
 #endif
 
-    if (ok)
-        ok = SecDbItemInsert(item, dbt, error);
+    if (ok) {
+        // We care about the new item's UUID only when we just made it from the primary key.
+        // Otherwise, we just made a random one, and don't mind if it changes.
+        ok = SecDbItemInsert(item, dbt, q->q_uuid_from_primary_key, error);
+    }
 
     if (ok) {
         if (result && q->q_return_type) {
@@ -535,39 +538,22 @@ decode:
         // errSecDecode means the item is corrupted, stash it for delete.
         if (status == errSecDecode) {
             secwarning("ignoring corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, rowid, q->q_error);
-            {
-                CFStringRef tablename = CFStringCreateCopy(kCFAllocatorDefault, q->q_class->name);
-                // Can't get rid of this item on the read path. Let's come back from elsewhere.
-                dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
-                    __block CFErrorRef localErr = NULL;
-                    __block bool ok = true;
-                    ok &= kc_with_dbt(true, &localErr, ^bool(SecDbConnectionRef dbt) {
-                        CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DELETE FROM %@ WHERE rowid=%lli"), tablename, rowid);
-                        ok &= SecDbPrepare(dbt, sql, &localErr, ^(sqlite3_stmt *stmt) {
-                            ok &= SecDbStep(dbt, stmt, &localErr, NULL);
-                        });
-
-                        if (!ok || localErr) {
-                            secerror("Failed to delete corrupt item, %@ row %lli: %@", tablename, rowid, localErr);
-                        } else {
-                            secnotice("item", "Deleted corrupt rowid %lli from table %@", rowid, tablename);
-                        }
-                        CFReleaseNull(localErr);
-                        CFReleaseNull(sql);
-                        CFReleaseSafe(tablename);
-                        return ok;
-                    });
-                });
 
-                CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL);
-                CFMutableStringRef edatastring =  CFStringCreateMutable(kCFAllocatorDefault, 0);
-                if(edatastring) {
-                    CFStringAppendEncryptedData(edatastring, edata);
-                    secnotice("item", "corrupted edata=%@", edatastring);
-                }
-                CFReleaseSafe(edata);
-                CFReleaseSafe(edatastring);
+            // Can't get rid of this item on the read path. Let's come back from elsewhere.
+            CFStringRef tablename = CFStringCreateCopy(kCFAllocatorDefault, q->q_class->name);
+            deleteCorruptedItemAsync(c->dbt, tablename, rowid);
+            CFReleaseNull(tablename);
+
+            // provide helpful logging statement
+            CFDataRef edata = s3dl_copy_data_from_col(stmt, 1, NULL);
+            CFMutableStringRef edatastring =  CFStringCreateMutable(kCFAllocatorDefault, 0);
+            if(edatastring) {
+                CFStringAppendEncryptedData(edatastring, edata);
+                secnotice("item", "corrupted edata=%@", edatastring);
             }
+            CFReleaseSafe(edata);
+            CFReleaseSafe(edatastring);
+
             CFReleaseNull(q->q_error);  // This item was never here, keep going
         } else if (status == errSecAuthNeeded) {
             secwarning("Authentication is needed for %@,rowid=%" PRId64 " (%" PRIdOSStatus "): %@", q->q_class->name, rowid, status, q->q_error);
@@ -731,6 +717,19 @@ SecDbAppendWhereMusr(CFMutableStringRef sql,
     }
 }
 
+static void
+SecDbAppendWhereAppClip(CFMutableStringRef sql,
+                        const Query* q,
+                        bool* needWhere)
+{
+    if (!q->q_skip_app_clip_items) {
+        return;
+    }
+
+    SecDbAppendWhereOrAnd(sql, needWhere);
+    CFStringAppend(sql, CFSTR("clip = 0"));
+}
+
 static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q,
                                    CFArrayRef accessGroups) {
     bool needWhere = true;
@@ -738,6 +737,7 @@ static void SecDbAppendWhereClause(CFMutableStringRef sql, const Query *q,
     SecDbAppendWhereAttrs(sql, q, &needWhere);
     SecDbAppendWhereMusr(sql, q, &needWhere);
     SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
+    SecDbAppendWhereAppClip(sql, q, &needWhere);
 }
 
 static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) {
@@ -748,14 +748,14 @@ static void SecDbAppendLimit(CFMutableStringRef sql, CFIndex limit) {
 static CFStringRef s3dl_create_select_sql(Query *q, CFArrayRef accessGroups) {
     CFMutableStringRef sql = CFStringCreateMutable(NULL, 0);
        if (q->q_class == identity_class()) {
-        CFStringAppendFormat(sql, NULL, CFSTR("SELECT crowid, %@"
-                                              ", rowid,data FROM "
-                                              "(SELECT cert.rowid AS crowid, cert.labl AS labl,"
-                                              " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid,"
-                                              " keys.*,cert.data AS %@"
-                                              " FROM keys, cert"
-                                              " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"),
-                             kSecAttrIdentityCertificateData, kSecAttrIdentityCertificateData);
+        CFStringAppend(sql, CFSTR("SELECT crowid, certdata"
+                                  ", rowid,data FROM "
+                                  "(SELECT cert.rowid AS crowid, cert.labl AS labl,"
+                                  " cert.issr AS issr, cert.slnr AS slnr, cert.skid AS skid,"
+                                  " cert.tkid AS tkid,"
+                                  " keys.*,cert.data AS certdata"
+                                  " FROM keys, cert"
+                                  " WHERE keys.priv == 1 AND cert.pkhh == keys.klbl"));
         SecDbAppendWhereAccessGroups(sql, CFSTR("cert.agrp"), accessGroups, 0);
         /* The next 3 SecDbAppendWhere calls are in the same order as in
          SecDbAppendWhereClause().  This makes sqlBindWhereClause() work,
@@ -766,8 +766,10 @@ static CFStringRef s3dl_create_select_sql(Query *q, CFArrayRef accessGroups) {
         SecDbAppendWhereAttrs(sql, q, &needWhere);
         SecDbAppendWhereMusr(sql, q, &needWhere);
         SecDbAppendWhereAccessGroups(sql, CFSTR("agrp"), accessGroups, &needWhere);
+        SecDbAppendWhereAppClip(sql, q, &needWhere);
        } else {
-        CFStringAppend(sql, CFSTR("SELECT rowid, data FROM "));
+        // Most of the time we don't need agrp, but if an item fails to decode and we want to know more then this is helpful
+        CFStringAppend(sql, CFSTR("SELECT rowid, data, agrp FROM "));
                CFStringAppend(sql, q->q_class->name);
         SecDbAppendWhereClause(sql, q, accessGroups);
     }
@@ -975,7 +977,7 @@ s3dl_copy_matching(SecDbConnectionRef dbt, Query *q, CFTypeRef *result,
                         CFSTR("attributes to query illegal; both row_id and other attributes can't be searched at the same time"));
     if (q->q_token_object_id && query_attr_count(q) != 1)
         return SecError(errSecItemIllegalQuery, error,
-                        CFSTR("attributes to query illegal; both token persitent ref and other attributes can't be searched at the same time"));
+                        CFSTR("attributes to query illegal; both token persistent ref and other attributes can't be searched at the same time"));
 
     // Only copy things that aren't tombstones unless the client explicitly asks otherwise.
     if (!CFDictionaryContainsKey(q->q_item, kSecAttrTombstone))
@@ -1128,10 +1130,7 @@ static CFBooleanRef s3dl_should_make_tombstone(Query *q, bool item_is_syncable,
     else
         return kCFBooleanFalse;
 }
-/* AUDIT[securityd](done):
- attributesToUpdate (ok) is a caller provided dictionary,
- only its cf types have been checked.
- */
+
 bool
 s3dl_query_update(SecDbConnectionRef dbt, Query *q,
                   CFDictionaryRef attributesToUpdate, CFArrayRef accessGroups, CFErrorRef *error)
@@ -1147,7 +1146,7 @@ s3dl_query_update(SecDbConnectionRef dbt, Query *q,
         return SecError(errSecItemIllegalQuery, error, CFSTR("attributes to update illegal; both token persistent ref and other attributes can't be updated at the same time"));
 
     __block bool result = true;
-    Query *u = query_create(q->q_class, NULL, attributesToUpdate, error);
+    Query *u = query_create(q->q_class, NULL, attributesToUpdate, NULL, error);
     if (u == NULL) return false;
     require_action_quiet(query_update_parse(u, attributesToUpdate, error), errOut, result = false);
     query_pre_update(u);
@@ -1174,7 +1173,7 @@ s3dl_query_update(SecDbConnectionRef dbt, Query *q,
                 // We just ignore this, and treat as if item is not found.
                 secwarning("deleting corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError);
                 CFReleaseNull(localError);
-                if (!SecDbItemDelete(item, dbt, false, &localError)) {
+                if (!SecDbItemDelete(item, dbt, false, false, &localError)) {
                     secerror("failed to delete corrupt %@,rowid=%" PRId64 " %@", q->q_class->name, SecDbItemGetRowId(item, NULL), localError);
                     CFReleaseNull(localError);
                 }
@@ -1254,7 +1253,7 @@ s3dl_query_delete(SecDbConnectionRef dbt, Query *q, CFArrayRef accessGroups, CFE
         bool item_is_sync = SecDbItemIsSyncable(item);
         SecDbItemSetValue(item, sha1attr, storedSHA1, NULL);
         CFReleaseSafe(storedSHA1);
-        ok = SecDbItemDelete(item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), error);
+        ok = SecDbItemDelete(item, dbt, s3dl_should_make_tombstone(q, item_is_sync, item), q->q_tombstone_use_mdat_from_item, error);
         if (ok) {
             q->q_changed = true;
             if (item_is_sync)
@@ -1502,8 +1501,9 @@ fail:
     if (stmt) {
         ok = SecDbFinalize(stmt, error);
     }
-    if (!ok)
+    if (!ok) {
         secwarning("DeleteAllFromTableForMUSRView failed for %@ for musr: %@: %@", sql2, musr, error ? *error : NULL);
+    }
     
     CFReleaseNull(sql2);
 
@@ -1526,6 +1526,34 @@ bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool
 }
 #endif
 
+OSStatus SecServerDeleteForAppClipApplicationIdentifier(CFStringRef identifier) {
+    secnotice("item", "Request to delete app clip keychain items for identifier '%@'", identifier);
+
+    __block CFErrorRef cfError = NULL;
+    __block bool ok = true;
+    ok &= kc_with_dbt(true, &cfError, ^bool(SecDbConnectionRef dbt) {
+        return kc_transaction(dbt, &cfError, ^bool{
+            const SecDbSchema* schema = current_schema();
+            for (const SecDbClass *const * class = schema->classes; *class != NULL; ++class) {
+                if ((*class)->itemclass) {
+                    CFStringRef sqlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DELETE FROM %@ WHERE agrp = ? AND clip = 1"), (*class)->name);
+                    ok &= SecDbPrepare(dbt, sqlStr, &cfError, ^(sqlite3_stmt *stmt) {
+                        ok &= SecDbBindObject(stmt, 1, identifier, &cfError);
+                        ok &= SecDbStep(dbt, stmt, &cfError, NULL);
+                    });
+                    CFReleaseNull(sqlStr);
+                }
+            }
+            return ok;
+        });
+    });
+
+    OSStatus status = ok ? errSecSuccess : errSecInternal;
+    secnotice("item", "Finished request to delete app clip keychain items for identifier '%@' with status %i: %@", identifier, (int)status, cfError);
+    CFReleaseNull(cfError);
+
+    return status;
+}
 
 struct s3dl_export_row_ctx {
     struct s3dl_query_ctx qc;
@@ -1540,9 +1568,6 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
     SecAccessControlRef access_control = NULL;
     CFErrorRef localError = NULL;
 
-    /* Skip akpu items when backing up, those are intentionally lost across restores. The same applies to SEP-based keys */
-    bool skip_akpu_or_token = c->filter == kSecBackupableItemFilter;
-
     sqlite_int64 rowid = sqlite3_column_int64(stmt, 0);
     CFMutableDictionaryRef allAttributes = NULL;
     CFMutableDictionaryRef metadataAttributes = NULL;
@@ -1561,12 +1586,14 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
         }
     }
 
+    /* Skip akpu items when backing up, those are intentionally lost across restores. The same applies to SEP-based keys */
     bool is_akpu = access_control ? CFEqualSafe(SecAccessControlGetProtection(access_control), kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly)
                                   // Mask generation, only look at class per se
                                   : (keyclass & key_class_last) == key_class_akpu;
     bool is_token = (ok && allAttributes != NULL) ? CFDictionaryContainsKey(allAttributes, kSecAttrTokenID) : false;
+    bool skip_akpu_or_token = (is_akpu || is_token) && c->filter == kSecBackupableItemFilter;
 
-    if (ok && allAttributes && !(skip_akpu_or_token && (is_akpu || is_token))) {
+    if (ok && allAttributes && !skip_akpu_or_token) {
         /* Only export sysbound items if do_sys_bound is true, only export non sysbound items otherwise. */
         bool do_sys_bound = c->filter == kSecSysBoundItemFilter;
         if (c->filter == kSecNoItemFilter ||
@@ -1607,7 +1634,7 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
                 CFReleaseSafe(pref);
             }
         }
-    } else {
+    } else if (!ok || !allAttributes) {
         OSStatus status = SecErrorGetOSStatus(localError);
 
         if (status == errSecInteractionNotAllowed && is_akpu) {
@@ -1615,13 +1642,15 @@ 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);
-                CFDictionaryRef payload = NULL;
-                CFTypeRef agrp = CFDictionaryGetValue(allAttributes, CFSTR("agrp"));
-                if (agrp) {
-                    payload = CFDictionaryCreateForCFTypes(NULL, CFSTR("agrp"), agrp, NULL);
+                if (sqlite3_column_count(stmt) > 2) {   // Should have rowid,data,agrp from s3dl_create_select_sql
+                    CFStringRef agrp = CFStringCreateWithCString(kCFAllocatorDefault, (const char*)sqlite3_column_text(stmt, 2), kCFStringEncodingUTF8);
+                    if (agrp) {
+                        CFDictionaryRef payload = CFDictionaryCreateForCFTypes(NULL, CFSTR("agrp"), agrp, NULL);
+                        SecABCTrigger(CFSTR("keychain"), CFSTR("invalid-akpu+sysbound"), NULL, payload);
+                        CFReleaseNull(payload);
+                    }
+                    CFReleaseNull(agrp);
                 }
-                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);
@@ -1637,7 +1666,10 @@ static void s3dl_export_row(sqlite3_stmt *stmt, void *context) {
                 q->q_error = localError;
             }
         }
+    } else {
+        secnotice("item", "export rowid %llu skipped. akpu/token: %i", rowid, skip_akpu_or_token);
     }
+
     CFReleaseNull(access_control);
     CFReleaseNull(allAttributes);
     CFReleaseNull(metadataAttributes);
@@ -1659,7 +1691,6 @@ SecCreateKeybagUUID(keybag_handle_t keybag)
 #endif
 }
 
-
 CFDictionaryRef
 SecServerCopyKeychainPlist(SecDbConnectionRef dbt,
                            SecurityClient *client,
@@ -1689,7 +1720,7 @@ SecServerCopyKeychainPlist(SecDbConnectionRef dbt,
         kSecReturnPersistentRefMask;
     q.q_limit = kSecMatchUnlimited;
     q.q_skip_acl_items = true;
-
+    q.q_skip_app_clip_items = true;
 
 #if TARGET_OS_IPHONE
     if (client && client->inMultiUser) {
@@ -1808,7 +1839,7 @@ SecServerImportItem(const void *value, void *context)
     if (state->s->src_keybag == KEYBAG_NONE) {
         item = SecDbItemCreateWithAttributes(kCFAllocatorDefault, state->class, dict, state->s->dest_keybag,  &state->s->error);
     } else {
-        item = SecDbItemCreateWithBackupDictionary(kCFAllocatorDefault, state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error);
+        item = SecDbItemCreateWithBackupDictionary(state->class, dict, state->s->src_keybag, state->s->dest_keybag, &state->s->error);
     }
 
     /* If item is NULL here, control flow ends up at the end where error is cleared. */
@@ -1906,7 +1937,7 @@ SecServerImportItem(const void *value, void *context)
             SecDbItemExtractRowIdFromBackupDictionary(item, dict, &state->s->error);
         }
         SecDbItemInferSyncable(item, &state->s->error);
-        insertStatus = SecDbItemInsert(item, state->s->dbt, &state->s->error);
+        insertStatus = SecDbItemInsert(item, state->s->dbt, false, &state->s->error);
         if (!insertStatus) {
             /*
              When running in EduMode, multiple users share the same
@@ -1920,7 +1951,7 @@ SecServerImportItem(const void *value, void *context)
              again to insert the record.
              */
             SecDbItemClearRowId(item, NULL);
-            SecDbItemInsert(item, state->s->dbt, &state->s->error);
+            SecDbItemInsert(item, state->s->dbt, false, &state->s->error);
         }
     }
 
@@ -2158,7 +2189,7 @@ bool s3dl_dbt_keys_current(SecDbConnectionRef dbt, uint32_t current_generation,
     };
 
     for (size_t class_ix = 0; class_ix < array_size(classes); ++class_ix) {
-        Query *q = query_create(classes[class_ix], NULL, NULL, &localError);
+        Query *q = query_create(classes[class_ix], NULL, NULL, NULL, &localError);
         if (!q)
             return false;
 
index 3a07bb65181e45ec8b82d759516bf232a56e2ee9..3f8efb9e1e81bb5aa0db793b88fa4ba746483230 100644 (file)
@@ -95,6 +95,7 @@ SecServerBackupGetKeybagUUID(CFDictionaryRef keychain, CFErrorRef *error);
 #if TARGET_OS_IPHONE
 bool SecServerDeleteAllForUser(SecDbConnectionRef dbt, CFDataRef musrView, bool keepU, CFErrorRef *error);
 #endif
+OSStatus SecServerDeleteForAppClipApplicationIdentifier(CFStringRef identifier);
 
 bool kc_transaction(SecDbConnectionRef dbt, CFErrorRef *error, bool(^perform)(void));
 bool kc_transaction_type(SecDbConnectionRef dbt, SecDbTransactionType type, CFErrorRef *error, bool(^perform)(void));
index 9a58ef42e0d40f1a766a2b5f987d40eb59a157cf..b49cb54e57c72b960f55fc07a45a46fab08acc1e 100644 (file)
 #define __FLAGS_V0 kSecDbSyncPrimaryKeyV0
 #define __FLAGS_V2 (kSecDbSyncPrimaryKeyV0 | kSecDbSyncPrimaryKeyV2)
 #define __FLAGS_Y  kSecDbSyncFlag
+#define __FLAGS_X  kSecDbSyncFlag | kSecDbSyncSOSCannotSyncFlag
 
 //                                                                   ,----------------- P : Part of primary key
 //                                                                  / ,---------------- L : Stored in local database
 //                                                                 / / ,--------------- I : Attribute wants an index in the database
 //                                                                / / / ,-------------- S : SHA1 hashed attribute value in database (implies L)
-//                                                               / / / / ,------------- A : Returned to client as attribute in queries
-//                                                              / / / / / ,------------ D : Returned to client as data in queries
+//                                                               / / / / ,------------- A : Returned to client as attribute in queries (implied by C)
+//                                                              / / / / / ,------------ D : Returned to client as data in queries (implied by C)
 //                                                             / / / / / / ,----------- R : Returned to client as ref/persistent ref in queries
 //                                                            / / / / / / / ,---------- C : Part of encrypted blob
-//                                                           / / / / / / / / ,--------- H : Attribute is part of item SHA1 hash (Implied by C)
+//                                                           / / / / / / / / ,--------- H : Attribute is part of item SHA1 hash
 //                                                          / / / / / / / / / ,-------- B : Attribute is part of iTunes/iCloud backup bag
 //                                                         / / / / / / / / / / ,------- Z : Attribute has a default value of 0
 //                                                        / / / / / / / / / / / ,------ E : Attribute has a default value of "" or empty data
 //                                                       / / / / / / / / / / / / ,----- N : Attribute must have a value
 //                                                      / / / / / / / / / / / / / ,---- U : Attribute is stored in authenticated, but not necessarily encrypted data
 //                                                     / / / / / / / / / / / / / / ,--- V0: Sync primary key version
-//                                                    / / / / / / / / / / / / / / /  ,- Y : Attribute should be synced
+//                                                    / / / / / / / / / / / / / / /  ,- Y : Attribute should be synced, or
+//                                                    | | | | | | | | | | | | | | |  |  X : Attribute should be synced in CKKS, and ignored in SOS
 //                                                    | | | | | | | | | | | | | | |  |
 // common to all                                      | | | | | | | | | | | | | | |  |
 SECDB_ATTR(v6rowid, "rowid", RowId,        SecDbFlags( ,L, , , , ,R, , ,B, , , , ,  , ), NULL, NULL);
@@ -82,9 +84,9 @@ SECDB_ATTR(v6cdat, "cdat", CreationDate,   SecDbFlags( ,L, , ,A, , ,C,H, , , , ,
 SECDB_ATTR(v6mdat, "mdat",ModificationDate,SecDbFlags( ,L, , ,A, , ,C,H, , , , , ,  ,Y), SecDbKeychainItemCopyCurrentDate, NULL);
 SECDB_ATTR(v6labl, "labl", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , , ,  ,Y), NULL, NULL);
 SECDB_ATTR(v6data, "data", EncryptedData,  SecDbFlags( ,L, , , , , , , ,B, , , , ,  , ), SecDbKeychainItemCopyEncryptedData, NULL);
-SECDB_ATTR(v6agrp, "agrp", String,         SecDbFlags(P,L,I, ,A, , , ,H, , , ,N,U,V0,Y), NULL, NULL);
+SECDB_ATTR(v6agrp, "agrp", String,         SecDbFlags(P,L, , ,A, , , ,H, , , ,N,U,V0,Y), NULL, NULL);
 SECDB_ATTR(v6pdmn, "pdmn", Access,         SecDbFlags( ,L, , ,A, , ,C,H, , , , , ,  ,Y), NULL, NULL);
-SECDB_ATTR(v6sync, "sync", Sync,           SecDbFlags(P,L,I, ,A, , , ,H, ,Z, ,N,U,V0, ), NULL, NULL);
+SECDB_ATTR(v6sync, "sync", Sync,           SecDbFlags(P,L, , ,A, , , ,H, ,Z, ,N,U,V0, ), NULL, NULL);
 SECDB_ATTR(v6tomb, "tomb", Tomb,           SecDbFlags( ,L, , , , , , ,H, ,Z, ,N,U,  ,Y), NULL, NULL);
 SECDB_ATTR(v6sha1, "sha1", SHA1,           SecDbFlags( ,L,I, ,A, ,R, , , , , , , ,  ,Y), SecDbKeychainItemCopySHA1, NULL);
 SECDB_ATTR(v6accc, "accc", AccessControl,  SecDbFlags( , , , ,A, , , , , , , , , ,  , ), NULL, NULL);
@@ -93,7 +95,8 @@ SECDB_ATTR(v6v_pk, "v_pk", PrimaryKey,     SecDbFlags( , , , , , , , , , , , , ,
 SECDB_ATTR(v7vwht, "vwht", String,         SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL);
 SECDB_ATTR(v7tkid, "tkid", String,         SecDbFlags(P,L,I, ,A, , , ,H, , , , ,U,V2,Y), NULL, NULL);
 SECDB_ATTR(v7utomb, "u_Tomb", UTomb,       SecDbFlags( , , , , , , , , , , , , , ,  , ), NULL, NULL);
-SECDB_ATTR(v8musr, "musr", UUID,           SecDbFlags(P,L,I, , , , , , , , , ,N,U,  ,Y), NULL, NULL);
+SECDB_ATTR(v8musr, "musr", UUID,           SecDbFlags(P,L, , , , , , , , , , ,N,U,  ,Y), NULL, NULL);
+SECDB_ATTR(v11_7appclip, "clip", Number,   SecDbFlags( ,L, , , , , , , , ,Z, ,N, ,  , ), NULL, NULL);
 // genp and inet and keys                             | | | | | | | | | | | | | | |  |
 SECDB_ATTR(v6crtr, "crtr", Number,         SecDbFlags( ,L, , ,A, , ,C,H, , , , , ,  ,Y), NULL, NULL);
 SECDB_ATTR(v6alis, "alis", Blob,           SecDbFlags( ,L, ,S,A, , ,C,H, , , , , ,  ,Y), NULL, NULL);
@@ -245,6 +248,16 @@ SECDB_ATTR(v11_5octagonStatus, "octagonstatus", String,   SecDbFlags( ,L, , , ,
 
 SECDB_ATTR(v11_6moreComing,    "morecoming",    Number,   SecDbFlags( ,L, , , , , , , , , , , , ,  , ), NULL, NULL);
 
+SECDB_ATTR(v11_8_bin_notes,    "binn",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+SECDB_ATTR(v11_8_bin_history,  "bini",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+SECDB_ATTR(v11_8_bin_client0,  "bin0",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+SECDB_ATTR(v11_8_bin_client1,  "bin1",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+SECDB_ATTR(v11_8_bin_client2,  "bin2",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+SECDB_ATTR(v11_8_bin_client3,  "bin3",          Data,     SecDbFlags( , , , , ,D, ,C, , , , , , ,  ,X), NULL, NULL);
+
+SECDB_ATTR(v11_9_lastscan,     "lastscan",      String,   SecDbFlags( ,L, , , , , , , , , , , , ,  , ), NULL, NULL);
+SECDB_ATTR(v11_9_extra,        "extra",         Blob,     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);
@@ -339,6 +352,7 @@ const SecDbClass v12_genp_class = {
         &v10_1pcspublickey,
         &v10_1pcspublicidentity,
         &v10_1itempersistentref,
+        &v11_7appclip,
         &v12_backupUUID,
         0
     },
@@ -388,6 +402,13 @@ const SecDbClass v12_inet_class = {
         &v10_1pcspublickey,
         &v10_1pcspublicidentity,
         &v10_1itempersistentref,
+        &v11_7appclip,
+        &v11_8_bin_notes,
+        &v11_8_bin_history,
+        &v11_8_bin_client0,
+        &v11_8_bin_client1,
+        &v11_8_bin_client2,
+        &v11_8_bin_client3,
         &v12_backupUUID,
         0
     },
@@ -428,6 +449,7 @@ const SecDbClass v12_cert_class = {
         &v10_1pcspublickey,
         &v10_1pcspublicidentity,
         &v10_1itempersistentref,
+        &v11_7appclip,
         &v12_backupUUID,
         0
     },
@@ -486,11 +508,277 @@ const SecDbClass v12_keys_class = {
         &v10_1pcspublickey,
         &v10_1pcspublicidentity,
         &v10_1itempersistentref,
+        &v11_7appclip,
         &v12_backupUUID,
         0
     }
 };
 
+const SecDbClass v11_9_ckstate_class = {
+    .name = CFSTR("ckstate"),
+    .itemclass = false,
+    .attrs = {
+        &v10ckzone,
+        &v10ckzonecreated,
+        &v10ckzonesubscribed,
+        &v10lastfetchtime,
+        &v10changetoken,
+        &v10ratelimiter,
+        &v10_4lastFixup,
+        &v11_6moreComing,
+        &v11_9_lastscan,
+        &v11_9_extra,
+        0
+    }
+};
+
+const SecDbClass v11_8_inet_class = {
+    .name = CFSTR("inet"),
+    .itemclass = true,
+    .attrs = {
+        &v6rowid,
+        &v6cdat,
+        &v6mdat,
+        &v6desc,
+        &v6icmt,
+        &v6crtr,
+        &v6type,
+        &v6scrp,
+        &v6labl,
+        &v6alis,
+        &v6invi,
+        &v6nega,
+        &v6cusi,
+        &v6prot,
+        &v6acct,
+        &v6sdmn,
+        &v6srvr,
+        &v6ptcl,
+        &v6atyp,
+        &v6port,
+        &v6path,
+        &v6data,
+        &v6agrp,
+        &v6pdmn,
+        &v6sync,
+        &v6tomb,
+        &v6sha1,
+        &v7vwht,
+        &v7tkid,
+        &v6v_Data,
+        &v6v_pk,
+        &v6accc,
+        &v7utomb,
+        &v8musr,
+        &v10itemuuid,
+        &v10sysbound,
+        &v10_1pcsservice,
+        &v10_1pcspublickey,
+        &v10_1pcspublicidentity,
+        &v10_1itempersistentref,
+        &v11_7appclip,
+        &v11_8_bin_notes,
+        &v11_8_bin_history,
+        &v11_8_bin_client0,
+        &v11_8_bin_client1,
+        &v11_8_bin_client2,
+        &v11_8_bin_client3,
+        0
+    },
+};
+
+const SecDbClass v11_7_genp_class = {
+    .name = CFSTR("genp"),
+    .itemclass = true,
+    .attrs = {
+        &v6rowid,
+        &v6cdat,
+        &v6mdat,
+        &v6desc,
+        &v6icmt,
+        &v6crtr,
+        &v6type,
+        &v6scrp,
+        &v6labl,
+        &v6alis,
+        &v6invi,
+        &v6nega,
+        &v6cusi,
+        &v6prot,
+        &v6acct,
+        &v6svce,
+        &v6gena,
+        &v6data,
+        &v6agrp,
+        &v6pdmn,
+        &v6sync,
+        &v6tomb,
+        &v6sha1,
+        &v7vwht,
+        &v7tkid,
+        &v6v_Data,
+        &v6v_pk,
+        &v6accc,
+        &v7utomb,
+        &v8musr,
+        &v10itemuuid,
+        &v10sysbound,
+        &v10_1pcsservice,
+        &v10_1pcspublickey,
+        &v10_1pcspublicidentity,
+        &v10_1itempersistentref,
+        &v11_7appclip,
+        0
+    },
+};
+
+const SecDbClass v11_7_inet_class = {
+    .name = CFSTR("inet"),
+    .itemclass = true,
+    .attrs = {
+        &v6rowid,
+        &v6cdat,
+        &v6mdat,
+        &v6desc,
+        &v6icmt,
+        &v6crtr,
+        &v6type,
+        &v6scrp,
+        &v6labl,
+        &v6alis,
+        &v6invi,
+        &v6nega,
+        &v6cusi,
+        &v6prot,
+        &v6acct,
+        &v6sdmn,
+        &v6srvr,
+        &v6ptcl,
+        &v6atyp,
+        &v6port,
+        &v6path,
+        &v6data,
+        &v6agrp,
+        &v6pdmn,
+        &v6sync,
+        &v6tomb,
+        &v6sha1,
+        &v7vwht,
+        &v7tkid,
+        &v6v_Data,
+        &v6v_pk,
+        &v6accc,
+        &v7utomb,
+        &v8musr,
+        &v10itemuuid,
+        &v10sysbound,
+        &v10_1pcsservice,
+        &v10_1pcspublickey,
+        &v10_1pcspublicidentity,
+        &v10_1itempersistentref,
+        &v11_7appclip,
+        0
+    },
+};
+
+const SecDbClass v11_7_cert_class = {
+    .name = CFSTR("cert"),
+    .itemclass = true,
+    .attrs = {
+        &v6rowid,
+        &v6cdat,
+        &v6mdat,
+        &v6ctyp,
+        &v6cenc,
+        &v6labl,
+        &v6certalis,
+        &v6subj,
+        &v6issr,
+        &v6slnr,
+        &v6skid,
+        &v6pkhh,
+        &v6data,
+        &v6agrp,
+        &v6pdmn,
+        &v6sync,
+        &v6tomb,
+        &v6sha1,
+        &v7vwht,
+        &v7tkid,
+        &v6v_Data,
+        &v6v_pk,
+        &v6accc,
+        &v7utomb,
+        &v8musr,
+        &v10itemuuid,
+        &v10sysbound,
+        &v10_1pcsservice,
+        &v10_1pcspublickey,
+        &v10_1pcspublicidentity,
+        &v10_1itempersistentref,
+        &v11_7appclip,
+        0
+    },
+};
+
+const SecDbClass v11_7_keys_class = {
+    .name = CFSTR("keys"),
+    .itemclass = true,
+    .attrs = {
+        &v6rowid,
+        &v6cdat,
+        &v6mdat,
+        &v6kcls,
+        &v6labl,
+        &v6alis,
+        &v6perm,
+        &v6priv,
+        &v6modi,
+        &v6klbl,
+        &v6atag,
+        &v6keycrtr,
+        &v6keytype,
+        &v6bsiz,
+        &v6esiz,
+        &v6sdat,
+        &v6edat,
+        &v6sens,
+        &v6asen,
+        &v6extr,
+        &v6next,
+        &v6encr,
+        &v6decr,
+        &v6drve,
+        &v6sign,
+        &v6vrfy,
+        &v6snrc,
+        &v6vyrc,
+        &v6wrap,
+        &v6unwp,
+        &v6data,
+        &v6agrp,
+        &v6pdmn,
+        &v6sync,
+        &v6tomb,
+        &v6sha1,
+        &v7vwht,
+        &v7tkid,
+        &v6v_Data,
+        &v6v_pk,
+        &v6accc,
+        &v7utomb,
+        &v8musr,
+        &v10itemuuid,
+        &v10sysbound,
+        &v10_1pcsservice,
+        &v10_1pcspublickey,
+        &v10_1pcspublicidentity,
+        &v10_1itempersistentref,
+        &v11_7appclip,
+        0
+    }
+};
+
 const SecDbClass v11_6_ckstate_class = {
     .name = CFSTR("ckstate"),
     .itemclass = false,
@@ -1248,7 +1536,7 @@ const SecDbSchema v12_0_schema = {
         &v10_0_sync_key_class,
         &v10_1_ckmirror_class,
         &v10_0_current_key_class,
-        &v11_6_ckstate_class,
+        &v11_9_ckstate_class,
         &v10_0_item_backup_class,
         &v10_0_backup_keybag_class,
         &v10_2_ckmanifest_class,
@@ -1269,6 +1557,114 @@ const SecDbSchema v12_0_schema = {
     }
 };
 
+/*
+ * Version 11.9
+ * Add extra columns for CKState
+ */
+const SecDbSchema v11_9_schema = {
+    .majorVersion = 11,
+    .minorVersion = 9,
+    .classes = {
+        &v11_7_genp_class,
+        &v11_8_inet_class,
+        &v11_7_cert_class,
+        &v11_7_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_9_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.8
+ * Add extra binary columns to inet
+ */
+const SecDbSchema v11_8_schema = {
+    .majorVersion = 11,
+    .minorVersion = 8,
+    .classes = {
+        &v11_7_genp_class,
+        &v11_8_inet_class,
+        &v11_7_cert_class,
+        &v11_7_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.7
+ * Add 'clip' column to denote item was made by App Clip
+ */
+const SecDbSchema v11_7_schema = {
+    .majorVersion = 11,
+    .minorVersion = 7,
+    .classes = {
+        &v11_7_genp_class,
+        &v11_7_inet_class,
+        &v11_7_cert_class,
+        &v11_7_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.6 (Add 'moreComing' field to zone state)
  */
@@ -2920,6 +3316,9 @@ SecDbSchema const * const * kc_schemas = NULL;
 
 const SecDbSchema *v10_kc_schemas_dev[] = {
     &v12_0_schema,
+    &v11_9_schema,
+    &v11_8_schema,
+    &v11_7_schema,
     &v11_6_schema,
     &v11_5_schema,
     &v11_4_schema,
@@ -2943,6 +3342,9 @@ const SecDbSchema *v10_kc_schemas_dev[] = {
 };
 
 const SecDbSchema *v10_kc_schemas[] = {
+    &v11_9_schema,
+    &v11_8_schema,
+    &v11_7_schema,
     &v11_6_schema,
     &v11_5_schema,
     &v11_4_schema,
diff --git a/keychain/securityd/SecItemServer+SWC.h b/keychain/securityd/SecItemServer+SWC.h
new file mode 100644 (file)
index 0000000..d970c89
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2007-2019 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+
+#if TARGET_OS_IOS && !TARGET_OS_BRIDGE
+#include <CoreFoundation/CoreFoundation.h>
+
+// Compatibility wrappers for SWC Objective-C interface.
+typedef enum SecSWCFlags {
+       kSecSWCFlags_None = 0,
+       kSecSWCFlag_UserApproved = (1 << 0),
+       kSecSWCFlag_UserDenied = (1 << 1),
+       kSecSWCFlag_SiteApproved = (1 << 2),
+       kSecSWCFlag_SiteDenied = (1 << 3),
+} SecSWCFlags;
+
+extern SecSWCFlags _SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error);
+extern void _SecSetAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFBooleanRef approved);
+
+extern CFTypeRef _SecCopyFQDNObjectFromString(CFStringRef entitlementValue);
+extern CFStringRef _SecGetFQDNFromFQDNObject(CFTypeRef fqdnObject, SInt32 *outPort);
+#if !TARGET_OS_SIMULATOR
+extern bool _SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, SInt32 port);
+#endif /* !TARGET_OS_SIMULATOR */
+#endif // TARGET_OS_IOS && !TARGET_OS_BRIDGE
diff --git a/keychain/securityd/SecItemServer+SWC.m b/keychain/securityd/SecItemServer+SWC.m
new file mode 100644 (file)
index 0000000..0c601a3
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2007-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 "SecItemServer+SWC.h"
+
+#if TARGET_OS_IOS && !TARGET_OS_BRIDGE
+#import <SharedWebCredentials/SharedWebCredentials.h>
+
+#import "utilities/debugging.h"
+#import "utilities/SecCFError.h"
+
+// Methods in this category are here temporarily until I can add SPI in
+// _SWCServiceSpecifier for the function below to consume.
+@interface NSObject (Workaround61065225)
+- (NSString *)domainHost;
+@end
+
+SecSWCFlags _SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error)
+{
+       __block SecSWCFlags flags = kSecSWCFlags_None;
+
+       @autoreleasepool {
+               secnotice("swc", "Application %@ is requesting approval for %@", appID, fqdn);
+
+               _SWCServiceSpecifier *specifier = [[_SWCServiceSpecifier alloc] initWithServiceType:_SWCServiceTypeWebCredentials
+                                                                                                                                         applicationIdentifier:(__bridge NSString *)appID
+                                                                                                                                                                        domain:(__bridge NSString *)fqdn];
+               NSError *err = nil;
+               NSArray<_SWCServiceDetails *> *allDetails = [_SWCServiceDetails serviceDetailsWithServiceSpecifier:specifier error:&err];
+               if (allDetails) {
+                       _SWCServiceDetails *details = allDetails.firstObject;
+                       if (details) {
+                               switch (details.userApprovalState) {
+                               case SWCServiceApprovalStateApproved:
+                                       flags |= kSecSWCFlag_UserApproved;
+                                       break;
+
+                               case SWCServiceApprovalStateDenied:
+                                       flags |= kSecSWCFlag_UserDenied;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+                               switch (details.siteApprovalState) {
+                               case SWCServiceApprovalStateApproved:
+                                       flags |= kSecSWCFlag_SiteApproved;
+                                       break;
+
+                               case SWCServiceApprovalStateDenied:
+                                       flags |= kSecSWCFlag_SiteDenied;
+                                       break;
+
+                               default:
+                                       break;
+                               }
+                       }
+
+               } else {
+                       // An error occurred.
+                       secerror("+[_SWCServiceDetails serviceDetailsWithServiceSpecifier:error:] failed with %@", err);
+               }
+       }
+
+       if (error) {
+               if (!(flags & kSecSWCFlag_SiteApproved)) {
+                       SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID);
+               } else if (flags & kSecSWCFlag_UserDenied) {
+                       SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID);
+               }
+       }
+
+       return flags;
+}
+
+void _SecSetAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFBooleanRef approved)
+{
+       _SWCServiceSpecifier *specifier = [[_SWCServiceSpecifier alloc] initWithServiceType:_SWCServiceTypeWebCredentials
+                                                                                                                                 applicationIdentifier:(__bridge NSString *)appID
+                                                                                                                                                                domain:(__bridge NSString *)fqdn];
+       NSError *err = nil;
+       NSArray<_SWCServiceDetails *> *allDetails = [_SWCServiceDetails serviceDetailsWithServiceSpecifier:specifier error:&err];
+       if (allDetails) {
+               _SWCServiceDetails *details = allDetails.firstObject;
+               if (details) {
+                       SWCServiceApprovalState state = SWCServiceApprovalStateUnspecified;
+                       if (approved == kCFBooleanTrue) {
+                               state = SWCServiceApprovalStateApproved;
+                       } else if (approved == kCFBooleanFalse) {
+                               state = SWCServiceApprovalStateDenied;
+                       }
+                       if (![details setUserApprovalState:state error:&err]) {
+                               secerror("-[_SWCServiceDetails setUserApprovalState:error:] failed with %@", err);
+                       }
+               }
+
+       } else {
+               secerror("+[_SWCServiceDetails serviceDetailsWithServiceSpecifier:error:] failed with %@", err);
+       }
+}
+
+CFTypeRef _SecCopyFQDNObjectFromString(CFStringRef entitlementValue)
+{
+       CFTypeRef result = NULL;
+
+       @autoreleasepool {
+               _SWCServiceSpecifier *serviceSpecifier = [_SWCServiceSpecifier serviceSpecifiersWithEntitlementValue:@[ (__bridge NSString *)entitlementValue ] error:NULL].firstObject;
+               if (!serviceSpecifier) {
+                       serviceSpecifier = [[_SWCServiceSpecifier alloc] initWithServiceType:nil applicationIdentifier:nil domain:(__bridge NSString *)entitlementValue];
+               }
+               if (serviceSpecifier) {
+                       // Hiding an ObjC reference in a CFTypeRef since the caller is pure C.
+                       result = CFBridgingRetain(serviceSpecifier);
+               }
+       }
+
+       return result;
+}
+
+CFStringRef _SecGetFQDNFromFQDNObject(CFTypeRef fqdnObject, SInt32 *outPort)
+{
+       CFStringRef result = NULL;
+       SInt32 port = -1;
+
+       // Extracting an ObjC reference from a CFTypeRef since the caller is pure C.
+       _SWCServiceSpecifier *serviceSpecifier = (__bridge _SWCServiceSpecifier *)fqdnObject;
+       result = (__bridge CFStringRef)serviceSpecifier.domainHost;
+       if (outPort) {
+               NSNumber *portNumber = serviceSpecifier.domainPort;
+               if (portNumber) {
+                       port = portNumber.unsignedShortValue;
+               }
+
+               *outPort = port;
+       }
+
+       return result;
+}
+
+#if !TARGET_OS_SIMULATOR
+bool _SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, SInt32 port)
+{
+    bool result = false;
+
+       @autoreleasepool {
+               NSArray<_SWCServiceSpecifier *> *serviceSpecifiers;
+               serviceSpecifiers = [_SWCServiceSpecifier serviceSpecifiersWithEntitlementValue:(__bridge NSArray<NSString *> *)domains
+                                                                                                                                                       serviceType:_SWCServiceTypeWebCredentials
+                                                                                                                                                                 error:NULL];
+               for (_SWCServiceSpecifier *serviceSpecifier in serviceSpecifiers) {
+                       // Check if the hostname matches.
+                       NSString *specifierDomain = [serviceSpecifier domainHost];
+                       if (NSOrderedSame == [specifierDomain caseInsensitiveCompare:(__bridge NSString *)domain]) {
+                               result = true;
+
+                               // Also check the port if specified by the caller.
+                               if (result && port >= 0) {
+                                       NSNumber *specifierPort = serviceSpecifier.domainPort;
+                                       result = [specifierPort isEqualToNumber:@(port)];
+                               }
+
+                               if (result) {
+                                       break;
+                               }
+                       }
+               }
+       }
+
+    return result;
+}
+#endif /* !TARGET_OS_SIMULATOR */
+#endif // TARGET_OS_IOS && !TARGET_OS_BRIDGE
index cd9c7b9707074a970d08cfd8a7531346272a1af8..fcace148012ae5cb72c5fb97d457980276b362b7 100644 (file)
@@ -40,6 +40,8 @@
 #include "keychain/securityd/SecItemDb.h"
 #include "keychain/securityd/SecItemSchema.h"
 #include <utilities/SecDb.h>
+#include <utilities/SecDbInternal.h>
+#import <utilities/SecCoreAnalytics.h>
 #include "keychain/securityd/SecDbKeychainItem.h"
 #include "keychain/securityd/SOSCloudCircleServer.h"
 #include <Security/SecBasePriv.h>
@@ -78,7 +80,6 @@
 #endif
 
 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-#include <utilities/SecADWrapper.h>
 #include <sys/time.h>
 #include <unistd.h>
 #endif
 #include <Security/SecuritydXPC.h>
 #include "swcagent_client.h"
 #include "SecPLWrappers.h"
-
-#if TARGET_OS_IOS && !TARGET_OS_BRIDGE
-#include <SharedWebCredentials/SharedWebCredentials.h>
-#endif
+#include "SecItemServer+SWC.h"
+#include <ipc/server_entitlement_helpers.h>
 
 #include <os/variant_private.h>
 
@@ -175,6 +174,7 @@ bool SecKeychainDbGetVersion(SecDbConnectionRef dbt, int *version, CFErrorRef *e
     }
 out:
     secnotice("upgr", "database version is: 0x%08x : %d : %@", *version, ok, localError);
+    secnotice("upgr", "UID: %d  EUID: %d", getuid(), geteuid());
     CFReleaseSafe(localError);
 
 
@@ -213,11 +213,11 @@ measureUpgradePhase1(struct timeval *start, bool success, int64_t itemsMigrated)
     int64_t duration = measureDuration(start);
 
     if (success) {
-        SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated);
-        SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration);
+        SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase1.migrated-items-success"), itemsMigrated);
+        SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase1.migrated-time-success"), duration);
     } else {
-        SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated);
-        SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration);
+        SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase1.migrated-items-fail"), itemsMigrated);
+        SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase1.migrated-time-fail"), duration);
     }
 }
 
@@ -226,8 +226,8 @@ measureUpgradePhase2(struct timeval *start, int64_t itemsMigrated)
 {
     int64_t duration = measureDuration(start);
 
-    SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated);
-    SecADSetValueForScalarKey(CFSTR("com.apple.keychain.phase2.migrated-time"), duration);
+    SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase2.migrated-items"), itemsMigrated);
+    SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.phase2.migrated-time"), duration);
 }
 #endif /* TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR */
 
@@ -372,7 +372,7 @@ static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSc
             // Prepare query to iterate through all items in cur_class.
             if (query != NULL)
                 query_destroy(query, NULL);
-            require_quiet(query = query_create(renamedOldClass, SecMUSRGetAllViews(), NULL, error), out);
+            require_quiet(query = query_create(renamedOldClass, SecMUSRGetAllViews(), NULL, NULL, error), out);
 
             ok &= SecDbItemSelect(query, dbt, error, ^bool(const SecDbAttr *attr) {
                 // We are interested in all attributes which are physically present in the DB.
@@ -410,7 +410,7 @@ static bool UpgradeSchemaPhase1(SecDbConnectionRef dbt, const SecDbSchema *oldSc
                     secnotice("upgr", "dropping item during schema upgrade due to agrp=com.apple.token: %@", item);
                 } else {
                     // Insert new item into the new table.
-                    if (!SecDbItemInsert(item, dbt, &localError)) {
+                    if (!SecDbItemInsert(item, dbt, false, &localError)) {
                         secerror("item: %@ insert during upgrade: %@", item, localError);
                         ok = false;
                     }
@@ -554,7 +554,7 @@ static bool UpgradeItemPhase2(SecDbConnectionRef inDbt, bool *inProgress, int ol
         if (query != NULL) {
             query_destroy(query, NULL);
         }
-        require_action_quiet(query = query_create(*class, SecMUSRGetAllViews(), NULL, error), out, ok = false);
+        require_action_quiet(query = query_create(*class, SecMUSRGetAllViews(), NULL, NULL, error), out, ok = false);
         ok &= SecDbItemSelect(query, threadDbt, error, NULL, ^bool(const SecDbAttr *attr) {
             // No simple per-attribute filtering.
             return false;
@@ -586,7 +586,7 @@ static bool UpgradeItemPhase2(SecDbConnectionRef inDbt, bool *inProgress, int ol
                 if (CFEqualSafe(SecDbItemGetCachedValueWithName(item, kSecAttrAccessGroup), kSecAttrAccessGroupToken) &&
                     SecDbItemGetCachedValueWithName(item, kSecAttrTokenID) == NULL) {
                     secnotice("upgr", "dropping item during item upgrade due to agrp=com.apple.token: %@", item);
-                    ok = SecDbItemDelete(item, threadDbt, kCFBooleanFalse, &localError);
+                    ok = SecDbItemDelete(item, threadDbt, kCFBooleanFalse, false, &localError);
                 } else {
                     // Replace item with the new value in the table; this will cause the item to be decoded and recoded back,
                     // incl. recalculation of item's hash.
@@ -603,7 +603,7 @@ static bool UpgradeItemPhase2(SecDbConnectionRef inDbt, bool *inProgress, int ol
                         // make sure we use a local error so that this error is not proppaged upward and cause a
                         // migration failure.
                         CFErrorRef deleteError = NULL;
-                        (void)SecDbItemDelete(item, threadDbt, false, &deleteError);
+                        (void)SecDbItemDelete(item, threadDbt, false, false, &deleteError);
                         CFReleaseNull(deleteError);
                         ok = true;
                         break;
@@ -670,6 +670,42 @@ out:
     return ok;
 }
 
+// There's no data-driven approach for this. Let's think about it more if it gets unwieldy
+static void performCustomIndexProcessing(SecDbConnectionRef dbt) {
+    CFErrorRef cfErr = NULL;
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS genpagrp; DROP INDEX IF EXISTS genpsync;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS inetagrp; DROP INDEX IF EXISTS inetsync;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS certagrp; DROP INDEX IF EXISTS certsync;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS keysagrp; DROP INDEX IF EXISTS keyssync;"), &cfErr), errhandler);
+
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS genpsync0;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS inetsync0;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS certsync0;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS keyssync0;"), &cfErr), errhandler);
+
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS genpmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS inetmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS certmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS keysmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS item_backupmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS backup_keybagmusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS backup_keyarchivemusr;"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("DROP INDEX IF EXISTS archived_key_backupmusr;"), &cfErr), errhandler);
+
+    require(SecDbExec(dbt, CFSTR("CREATE INDEX IF NOT EXISTS agrp_musr_tomb_svce ON genp(agrp, musr, tomb, svce);"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("CREATE INDEX IF NOT EXISTS agrp_musr_tomb_srvr ON inet(agrp, musr, tomb, srvr);"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("CREATE INDEX IF NOT EXISTS agrp_musr_tomb_subj ON cert(agrp, musr, tomb, subj);"), &cfErr), errhandler);
+    require(SecDbExec(dbt, CFSTR("CREATE INDEX IF NOT EXISTS agrp_musr_tomb_atag ON keys(agrp, musr, tomb, atag);"), &cfErr), errhandler);
+
+    secnotice("upgr", "processed custom indexes (now or in the past)");
+    CFReleaseNull(cfErr);   // Should be nil but belt and suspenders
+    return;
+
+errhandler:
+    secerror("upgr: failed to process custom indexes: %@", cfErr);
+    CFReleaseNull(cfErr);
+}
+
 static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version, bool *inProgress, CFErrorRef *error) {
     __block bool didPhase2 = false;
     __block bool ok = true;
@@ -707,6 +743,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version,
 
         // If this is empty database, just create table according to schema and be done with it.
         require_action_quiet(version2 != 0, out, ok = SecItemDbCreateSchema(dbt, newSchema, NULL, true, &localError);
+                             performCustomIndexProcessing(dbt);
                              LKAReportKeychainUpgradeOutcomeWithError(version2, newVersion, LKAKeychainUpgradeOutcomeNewDb, localError));
 
         int oldVersion = VERSION_OLD(version2);
@@ -796,7 +833,7 @@ static bool SecKeychainDbUpgradeFromVersion(SecDbConnectionRef dbt, int version,
 
     if (ok && didPhase2) {
 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-        SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-success"), 1);
+        SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.migration-success"), 1);
 #endif
     }
 
@@ -839,7 +876,7 @@ out:
             secerror("upgrade: marking database as corrupt");
             SecDbCorrupt(dbt, localError);
 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
-            SecADSetValueForScalarKey(CFSTR("com.apple.keychain.migration-failure"), 1);
+            SecCoreAnalyticsSendValue(CFSTR("com.apple.keychain.migration-failure"), 1);
 #endif
         }
     } else {
@@ -851,19 +888,13 @@ out:
         //If we're done here, we should opportunistically re-add all indices (just in case)
         if(skipped_upgrade || didPhase2) {
             // Create indices, ignoring all errors
+            performCustomIndexProcessing(dbt);
             for (SecDbClass const* const* newClass = newSchema->classes; *newClass; ++newClass) {
                 SecDbForEachAttrWithMask((*newClass), desc, kSecDbIndexFlag | kSecDbInFlag) {
                     CFStringRef sql = NULL;
                     CFErrorRef classLocalError = NULL;
                     bool localOk = true;
-
-                    if (desc->kind == kSecDbSyncAttr) {
-                        // Replace the complete sync index with a partial index for sync=0. Most items are sync=1, so the complete index isn't helpful for sync=1 queries.
-                        sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("DROP INDEX IF EXISTS %@%@; CREATE INDEX IF NOT EXISTS %@%@0 on %@(%@) WHERE %@=0;"),
-                            (*newClass)->name, desc->name, (*newClass)->name, desc->name, (*newClass)->name, desc->name, desc->name);
-                    } else {
-                        sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("CREATE INDEX IF NOT EXISTS %@%@ ON %@(%@);"), (*newClass)->name, desc->name, (*newClass)->name, desc->name);
-                    }
+                    sql = CFStringCreateWithFormat(NULL, NULL, CFSTR("CREATE INDEX IF NOT EXISTS %@%@ ON %@(%@);"), (*newClass)->name, desc->name, (*newClass)->name, desc->name);
                     localOk &= SecDbExec(dbt, sql, &classLocalError);
                     CFReleaseNull(sql);
 
@@ -1234,7 +1265,7 @@ void SecKeychainDbReset(dispatch_block_t inbetween)
     dispatch_sync(get_kc_dbhandle_dispatch(), ^{
         CFReleaseNull(_kc_dbhandle);
         SecDbResetMetadataKeys();
-
+        SecDbResetBackupManager();
         if (inbetween)
             inbetween();
     });
@@ -1286,12 +1317,12 @@ bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFEr
         // The kc_with_dbt upthread will clean this up when it's done.
         return perform(threadDbt);
     }
-    
-    if (writeAndRead && usesItemTables) {
+
 #if SECUREOBJECTSYNC
+    if (writeAndRead && usesItemTables) {
         SecItemDataSourceFactoryGetDefault();
-#endif
     }
+#endif
 
     bool ok = false;
     if (kc_acquire_dbt(writeAndRead, &threadDbt, error)) {
@@ -1323,7 +1354,7 @@ items_matching_issuer_parent(SecDbConnectionRef dbt, CFArrayRef accessGroups, CF
         return false;
 
     CFErrorRef localError = NULL;
-    q = query_create_with_limit(query, musrView, kSecMatchUnlimited, &localError);
+    q = query_create_with_limit(query, musrView, kSecMatchUnlimited, NULL, &localError);
     CFRelease(query);
     if (q) {
         s3dl_copy_matching(dbt, q, (CFTypeRef*)&results, accessGroups, &localError);
@@ -1544,6 +1575,46 @@ out:
     return ok;
 }
 
+//Mark: -
+
+void deleteCorruptedItemAsync(SecDbConnectionRef dbt, CFStringRef tablename, sqlite_int64 rowid)
+{
+    // should really get db from dbt, but I don't know much much we should poke holes thought the boundaries.
+    SecDbRef db = kc_dbhandle(NULL);
+    if (db == NULL) {
+        return;
+    }
+
+    CFRetain(db);
+    CFRetain(tablename);
+
+    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
+        __block CFErrorRef localErr = NULL;
+        kc_with_custom_db(true, true, db, &localErr, ^bool(SecDbConnectionRef dbt) {
+            CFStringRef sql = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("DELETE FROM %@ WHERE rowid=%lli"), tablename, rowid);
+            __block bool ok = true;
+            ok &= SecDbPrepare(dbt, sql, &localErr, ^(sqlite3_stmt *stmt) {
+                ok &= SecDbStep(dbt, stmt, &localErr, NULL);
+            });
+
+            if (!ok || localErr) {
+                secerror("Failed to delete corrupt item, %@ row %lli: %@", tablename, rowid, localErr);
+            } else {
+                secnotice("item", "Deleted corrupt rowid %lli from table %@", rowid, tablename);
+            }
+            CFReleaseNull(localErr);
+            CFReleaseNull(sql);
+            return true;
+        });
+
+        CFRelease(tablename); // can't be a CFReleaseNull() because of scope
+        CFRelease(db);
+    });
+
+}
+
+
+
 /****************************************************************************
  **************** Beginning of Externally Callable Interface ****************
  ****************************************************************************/
@@ -1552,7 +1623,7 @@ static bool SecEntitlementError(CFErrorRef *error)
 {
 #if TARGET_OS_OSX
 #define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.application-identifier nor com.apple.security.application-groups nor keychain-access-groups")
-#elif TARGET_OS_IOSMAC
+#elif TARGET_OS_MACCATALYST
 #define SEC_ENTITLEMENT_WARNING CFSTR("com.apple.developer.associated-application-identifier nor application-identifier nor com.apple.security.application-groups nor keychain-access-groups")
 #else
 #define SEC_ENTITLEMENT_WARNING CFSTR("application-identifier nor keychain-access-groups")
@@ -1596,13 +1667,43 @@ static CFStringRef CopyAccessGroupForRowID(sqlite_int64 rowID, CFStringRef itemC
     }
 }
 
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
+// Expand this, rdar://problem/59297616
+// Known attributes which are not API/SPI should not be permitted in queries
+static bool nonAPIAttributesInDictionary(CFDictionaryRef attrs) {
+    return CFDictionaryContainsKey(attrs, kSecAttrAppClipItem);
+}
+
+static bool appClipHasSaneAccessGroups(SecurityClient* client) {
+    if (!client || !client->applicationIdentifier || !client->accessGroups) {
+        secerror("item: no app clip client or attributes not set, cannot verify restrictions");
+        return false;
+    }
+
+    CFIndex count = CFArrayGetCount(client->accessGroups);
+    if (count == 1 && CFEqualSafe(client->applicationIdentifier, CFArrayGetValueAtIndex(client->accessGroups, 0))) {
+        return true;
+    }
+
+    // sigh, alright is the _other_ access group the application identifier?
+    if (count == 2) {
+        CFIndex tokenIdx = CFArrayGetFirstIndexOfValue(client->accessGroups, CFRangeMake(0, count), kSecAttrAccessGroupToken);
+        if (tokenIdx != kCFNotFound) {
+            return CFEqualSafe(client->applicationIdentifier, CFArrayGetValueAtIndex(client->accessGroups, tokenIdx == 0 ? 1 : 0));
+        }
+    }
+
+    return false;
+}
+
 static bool
 SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
     SecurityClient *client, CFErrorRef *error)
 {
+    if (nonAPIAttributesInDictionary(query)) {
+        SecError(errSecParam, error, CFSTR("Non-API attributes present in query"));
+        return false;
+    }
+
     CFArrayRef accessGroups = CFRetainSafe(client->accessGroups);
 
     CFIndex ag_count;
@@ -1635,7 +1736,7 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
     }
 
     bool ok = false;
-    Query *q = query_create_with_limit(query, client->musr, 1, error);
+    Query *q = query_create_with_limit(query, client->musr, 1, client, error);
     if (q) {
         CFStringRef agrp = CFDictionaryGetValue(q->q_item, kSecAttrAccessGroup);
         if (agrp) {
@@ -1649,18 +1750,6 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
                 query_destroy(q, NULL);
                 return false;
             }
-        } else {
-#if !TARGET_OS_OSX
-            if (accessGroups != NULL) {
-                // On iOS, drop 'com.apple.token' AG from allowed accessGroups, to avoid inserting token elements into
-                // unsuspecting application's keychain. If the application on iOS wants to access token items, it needs
-                // explicitly specify kSecAttrAccessGroup=kSecAttrAccessGroupToken in its query.
-                CFMutableArrayRef mutableGroups =  CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, accessGroups);
-                CFArrayRemoveAllValue(mutableGroups, kSecAttrAccessGroupToken);
-                CFReleaseNull(accessGroups);
-                accessGroups = mutableGroups;
-            }
-#endif
         }
 
 #if TARGET_OS_IPHONE
@@ -1679,9 +1768,9 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
 #endif
 
         query_set_caller_access_groups(q, accessGroups);
-
-        /* Sanity check the query. */
-        if (q->q_system_keychain && !client->allowSystemKeychain) {
+        if (client->isAppClip && !appClipHasSaneAccessGroups(client)) {
+            ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to use access groups other than application identifier"));
+        } else if (q->q_system_keychain && !client->allowSystemKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain"));
         } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain"));
@@ -1703,8 +1792,9 @@ SecItemServerCopyMatching(CFDictionaryRef query, CFTypeRef *result,
             });
         }
 
-        if (!query_destroy(q, error))
+        if (!query_destroy(q, error)) {
             ok = false;
+        }
     }
     CFReleaseNull(accessGroups);
 
@@ -1751,14 +1841,14 @@ SecurityClientCopyWritableAccessGroups(SecurityClient *client) {
     }
 }
 
-
-/* AUDIT[securityd](done):
-   attributes (ok) is a caller provided dictionary, only its cf type has
-       been checked.
- */
 bool
 _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *result, CFErrorRef *error)
 {
+    if (nonAPIAttributesInDictionary(attributes)) {
+        SecError(errSecParam, error, CFSTR("Non-API attributes present"));
+        return false;
+    }
+
     CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client);
 
     bool ok = true;
@@ -1770,20 +1860,22 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul
 
     SecSignpostStart(SecSignpostSecItemAdd);
 
-    Query *q = query_create_with_limit(attributes, client->musr, 0, error);
+    Query *q = query_create_with_limit(attributes, client->musr, 0, client, error);
     if (q) {
         /* Access group sanity checking. */
         CFStringRef agrp = (CFStringRef)CFDictionaryGetValue(attributes,
             kSecAttrAccessGroup);
 
         /* Having the special accessGroup "*" allows access to all accessGroups. */
-        if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*")))
+        if (CFArrayContainsValue(accessGroups, CFRangeMake(0, ag_count), CFSTR("*"))) {
             CFReleaseNull(accessGroups);
+        }
 
         if (agrp) {
             /* The user specified an explicit access group, validate it. */
-            if (!accessGroupsAllows(accessGroups, agrp, client))
+            if (!accessGroupsAllows(accessGroups, agrp, client)) {
                 ok = SecEntitlementErrorForExplicitAccessGroup(agrp, accessGroups, error);
+            }
         } else {
             agrp = (CFStringRef)CFArrayGetValueAtIndex(client->accessGroups, 0);
 
@@ -1820,8 +1912,11 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul
                 q->q_add_sync_callback = add_sync_callback;
             }
 #endif
-
-            if (q->q_system_keychain && !client->allowSystemKeychain) {
+            if (client->isAppClip && !appClipHasSaneAccessGroups(client)) {
+                ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to use access groups other than application identifier"));
+            } else if (client->isAppClip && CFEqualSafe(CFDictionaryGetValue(attributes, kSecAttrSynchronizable), kCFBooleanTrue)) {
+                ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to add synchronizable items to the keychain"));
+            } else if (q->q_system_keychain && !client->allowSystemKeychain) {
                 ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain"));
             } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) {
                 ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain"));
@@ -1851,14 +1946,15 @@ _SecItemAdd(CFDictionaryRef attributes, SecurityClient *client, CFTypeRef *resul
     return ok;
 }
 
-/* AUDIT[securityd](done):
-   query (ok) and attributesToUpdate (ok) are a caller provided dictionaries,
-       only their cf types have been checked.
- */
 bool
 _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
                SecurityClient *client, CFErrorRef *error)
 {
+    if (nonAPIAttributesInDictionary(query) || nonAPIAttributesInDictionary(attributesToUpdate)) {
+        SecError(errSecParam, error, CFSTR("Non-API attributes present"));
+        return false;
+    }
+
     CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client);
 
     CFIndex ag_count;
@@ -1893,7 +1989,7 @@ _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
     }
 
     bool ok = true;
-    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error);
+    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, client, error);
     if (!q) {
         ok = false;
     }
@@ -1906,10 +2002,14 @@ _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
             q->q_system_keychain = false;
         }
 #endif
-
-        /* Sanity check the query. */
         query_set_caller_access_groups(q, accessGroups);
-        if (q->q_system_keychain && !client->allowSystemKeychain) {
+        if (client->isAppClip && !appClipHasSaneAccessGroups(client)) {
+            ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to use access groups other than application identifier"));
+        } else if (client->isAppClip && (CFEqualSafe(CFDictionaryGetValue(query, kSecAttrSynchronizable), kCFBooleanTrue) ||
+            CFEqualSafe(CFDictionaryGetValue(attributesToUpdate, kSecAttrSynchronizable), kCFBooleanTrue)))
+        {
+            ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to make items synchronizable"));
+        } else if (q->q_system_keychain && !client->allowSystemKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain"));
         } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain"));
@@ -1959,13 +2059,14 @@ _SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate,
     return ok;
 }
 
-
-/* AUDIT[securityd](done):
-   query (ok) is a caller provided dictionary, only its cf type has been checked.
- */
 bool
 _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error)
 {
+    if (nonAPIAttributesInDictionary(query)) {
+        SecError(errSecParam, error, CFSTR("Non-API attributes present"));
+        return false;
+    }
+
     CFArrayRef accessGroups = SecurityClientCopyWritableAccessGroups(client);
 
     CFIndex ag_count;
@@ -1997,7 +2098,7 @@ _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error)
         CFReleaseNull(accessGroups);
     }
 
-    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error);
+    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, client, error);
     bool ok;
     if (q) {
 #if TARGET_OS_IPHONE
@@ -2010,8 +2111,9 @@ _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error)
 #endif
 
         query_set_caller_access_groups(q, accessGroups);
-        /* Sanity check the query. */
-        if (q->q_system_keychain && !client->allowSystemKeychain) {
+        if (client->isAppClip && !appClipHasSaneAccessGroups(client)) {
+            ok = SecError(errSecRestrictedAPI, error, CFSTR("App clips are not permitted to use access groups other than application identifier"));
+        } else if (q->q_system_keychain && !client->allowSystemKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain"));
         } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) {
             ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain"));
@@ -2044,11 +2146,8 @@ _SecItemDelete(CFDictionaryRef query, SecurityClient *client, CFErrorRef *error)
 }
 
 static bool SecItemDeleteTokenItems(SecDbConnectionRef dbt, CFTypeRef classToDelete, CFTypeRef tokenID, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) {
-    CFTypeRef keys[] = { kSecClass, kSecAttrTokenID };
-    CFTypeRef values[] = { classToDelete, tokenID };
-    
-    CFDictionaryRef query = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, error);
+    CFDictionaryRef query = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, kSecClass, classToDelete, kSecAttrTokenID, tokenID, NULL);
+    Query *q = query_create_with_limit(query, client->musr, kSecMatchUnlimited, client, error);
     CFRelease(query);
     bool ok;
     if (q) {
@@ -2062,73 +2161,55 @@ static bool SecItemDeleteTokenItems(SecDbConnectionRef dbt, CFTypeRef classToDel
     return ok;
 }
 
-static bool SecItemAddTokenItem(SecDbConnectionRef dbt, CFDictionaryRef attributes, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) {
-    bool ok = true;
-    Query *q = query_create_with_limit(attributes, client->musr, 0, error);
-    if (q) {
-        CFStringRef agrp = kSecAttrAccessGroupToken;
+static bool SecItemAddTokenItemToAccessGroups(SecDbConnectionRef dbt, CFDictionaryRef attributes, CFArrayRef accessGroups, SecurityClient *client, CFErrorRef *error) {
+    Query *q;
+    bool ok = false;
+    for (CFIndex i = 0; i < CFArrayGetCount(accessGroups); ++i) {
+        require_quiet(q = query_create_with_limit(attributes, client->musr, 0, client, error), out);
+        CFStringRef agrp = CFArrayGetValueAtIndex(accessGroups, i);
         query_add_attribute(kSecAttrAccessGroup, agrp, q);
-
-        if (ok) {
-            query_ensure_access_control(q, agrp);
-            if (q->q_system_keychain && !client->allowSystemKeychain) {
-                ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for system keychain"));
-            } else if (q->q_sync_bubble && !client->allowSyncBubbleKeychain) {
-                ok = SecError(errSecMissingEntitlement, error, CFSTR("client doesn't have entitlement for syncbubble keychain"));
-            } else if (q->q_row_id || q->q_token_object_id) {
-                ok = SecError(errSecValuePersistentRefUnsupported, error, CFSTR("q_row_id"));  // TODO: better error string
-            } else if (!q->q_error) {
-                query_pre_add(q, true);
-                ok = s3dl_query_add(dbt, q, NULL, error);
-            }
+        query_ensure_access_control(q, agrp);
+        bool added = false;
+        if (!q->q_error) {
+            query_pre_add(q, true);
+            added = s3dl_query_add(dbt, q, NULL, error);
         }
-        ok = query_notify_and_destroy(q, ok, error);
-    } else {
-        return false;
+        require_quiet(query_notify_and_destroy(q, added, error), out);
     }
+    ok = true;
+out:
     return ok;
 }
 
-bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error) {
-    bool ok = true;
-    CFArrayRef accessGroups = client->accessGroups;
-    CFIndex ag_count;
-    if (!accessGroups || 0 == (ag_count = CFArrayGetCount(accessGroups))) {
-        return SecEntitlementError(error);
+bool _SecItemUpdateTokenItemsForAccessGroups(CFStringRef tokenID, CFArrayRef accessGroups, CFArrayRef items, SecurityClient *client, CFErrorRef *error) {
+    // This is SPI for CTK only, don't even listen to app clips.
+    if (client->isAppClip) {
+        return SecError(errSecRestrictedAPI, error, CFSTR("App Clips may not call this API"));
     }
 
-    ok = kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
+    return kc_with_dbt(true, error, ^bool (SecDbConnectionRef dbt) {
         return kc_transaction(dbt, error, ^bool {
-            if (items) {
-                const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey };
-                for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) {
-                    SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, NULL);
+            bool ok = false;
+            CFErrorRef localError = NULL;
+            const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey };
+            for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) {
+                if (!SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, &localError)) {
+                    require_action_quiet(CFErrorGetCode(localError) == errSecItemNotFound, out, CFErrorPropagate(localError, error));
+                    CFReleaseNull(localError);
                 }
+            }
 
+            if (items) {
                 for (CFIndex i = 0; i < CFArrayGetCount(items); ++i) {
-                    if (!SecItemAddTokenItem(dbt, CFArrayGetValueAtIndex(items, i), accessGroups, client, error))
-                        return false;
+                    require_quiet(SecItemAddTokenItemToAccessGroups(dbt, CFArrayGetValueAtIndex(items, i), accessGroups, client, error), out);
                 }
-                return true;
-            }
-            else {
-                const CFTypeRef classToDelete[] = { kSecClassGenericPassword, kSecClassInternetPassword, kSecClassCertificate, kSecClassKey };
-                bool deleted = true;
-                for (size_t i = 0; i < sizeof(classToDelete) / sizeof(classToDelete[0]); ++i) {
-                    if (!SecItemDeleteTokenItems(dbt, classToDelete[i], tokenID, accessGroups, client, error) && error && CFErrorGetCode(*error) != errSecItemNotFound) {
-                        deleted = false;
-                        break;
-                    }
-                    else if (error && *error) {
-                        CFReleaseNull(*error);
-                    }
-                }
-                return deleted;
             }
+
+            ok = true;
+        out:
+            return ok;
         });
     });
-
-    return ok;
 }
 
 static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClass const* class, CFErrorRef* error) {
@@ -2136,7 +2217,7 @@ static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClas
     CFDictionaryAddValue(query, kSecMatchLimit, kSecMatchLimitAll);
 
     __block CFErrorRef localError = NULL;
-    SecDbQueryRef q = query_create(class, NULL, query, &localError);
+    SecDbQueryRef q = query_create(class, NULL, query, NULL, &localError);
     if (q == NULL) {    // illegal query or out of memory
         secerror("SecItemServerDeleteAll: aborting because failed to initialize Query: %@", localError);
         abort();
@@ -2148,7 +2229,7 @@ static bool deleteNonSysboundItemsForItemClass(SecDbConnectionRef dbt, SecDbClas
         if (!SecItemIsSystemBound(item->attributes, class, false) &&
             !CFEqual(CFDictionaryGetValue(item->attributes, kSecAttrAccessGroup), CFSTR("com.apple.bluetooth")))
         {
-            SecDbItemDelete(item, dbt, kCFBooleanFalse, &localError);
+            SecDbItemDelete(item, dbt, kCFBooleanFalse, false, &localError);
         }
     });
     query_destroy(q, &localError);
@@ -2260,7 +2341,7 @@ _SecItemServerDeleteAllWithAccessGroups(CFArrayRef accessGroups, SecurityClient
             for (n = 0; n < sizeof(qclasses)/sizeof(qclasses[0]) && ok1; n++) {
                 Query *q;
 
-                q = query_create(qclasses[n], client->musr, NULL, error);
+                q = query_create(qclasses[n], client->musr, NULL, client, error);
                 require(q, fail2);
 
                 (void)s3dl_query_delete(dbt, q, accessGroups, &localError);
@@ -2282,82 +2363,15 @@ fail:
 
 #if SHAREDWEBCREDENTIALS
 
+// OSX now has SWC enabled, but cannot link SharedWebCredentials framework: rdar://59958701
+#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_WATCH && !TARGET_OS_TV
+
 /* constants */
 #define SEC_CONST_DECL(k,v) const CFStringRef k = CFSTR(v);
 
 SEC_CONST_DECL (kSecSafariAccessGroup, "com.apple.cfnetwork");
 SEC_CONST_DECL (kSecSafariDefaultComment, "default");
 SEC_CONST_DECL (kSecSafariPasswordsNotSaved, "Passwords not saved");
-SEC_CONST_DECL (kSecSharedCredentialUrlScheme, "https://");
-SEC_CONST_DECL (kSecSharedWebCredentialsService, "webcredentials");
-
-#if !TARGET_OS_SIMULATOR
-static SWCFlags
-_SecAppDomainApprovalStatus(CFStringRef appID, CFStringRef fqdn, CFErrorRef *error)
-{
-    __block SWCFlags flags = kSWCFlags_None;
-    OSStatus status;
-
-    secnotice("swc", "Application %@ is requesting approval for %@", appID, fqdn);
-
-    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
-    if (semaphore == NULL)
-        return 0;
-
-    status = SWCCheckService(kSecSharedWebCredentialsService, appID, fqdn, ^void (OSStatus inStatus, SWCFlags inFlags, CFDictionaryRef inDetails)
-    {
-        if (inStatus == 0) {
-            flags = inFlags;
-        } else {
-            secerror("SWCCheckService failed with %d", (int)inStatus);
-        }
-        dispatch_semaphore_signal(semaphore);
-    });
-
-    if (status == 0) {
-        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
-    } else {
-        secerror("SWCCheckService: failed to queue");
-    }
-    dispatch_release(semaphore);
-
-    if (error) {
-        if (!(flags & kSWCFlag_SiteApproved)) {
-            SecError(errSecAuthFailed, error, CFSTR("\"%@\" failed to approve \"%@\""), fqdn, appID);
-        } else if (flags & kSWCFlag_UserDenied) {
-            SecError(errSecAuthFailed, error, CFSTR("User denied access to \"%@\" by \"%@\""), fqdn, appID);
-        }
-    }
-    return flags;
-}
-
-static bool
-_SecEntitlementContainsDomainForService(CFArrayRef domains, CFStringRef domain, CFStringRef service)
-{
-    bool result = false;
-    CFIndex idx, count = (domains) ? CFArrayGetCount(domains) : (CFIndex) 0;
-    if (!count || !domain || !service) {
-        return result;
-    }
-    for (idx=0; idx < count; idx++) {
-        CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx);
-        if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) {
-            CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1;
-            CFIndex substr_len = CFStringGetLength(str) - prefix_len;
-            CFRange range = { prefix_len, substr_len };
-            CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range);
-            if (substr && CFEqual(substr, domain)) {
-                result = true;
-            }
-            CFReleaseSafe(substr);
-            if (result) {
-                break;
-            }
-        }
-    }
-    return result;
-}
-#endif /* !TARGET_OS_SIMULATOR */
 
 static bool
 _SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringRef appID, bool forSafari)
@@ -2367,21 +2381,7 @@ _SecAddNegativeWebCredential(SecurityClient *client, CFStringRef fqdn, CFStringR
     if (!fqdn) { return result; }
 
     // update our database
-    CFRetainSafe(appID);
-    CFRetainSafe(fqdn);
-    if (0 == SWCSetServiceFlags(kSecSharedWebCredentialsService, appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserDenied,
-        ^void(OSStatus inStatus, SWCFlags inNewFlags){
-            CFReleaseSafe(appID);
-            CFReleaseSafe(fqdn);
-        }))
-    {
-        result = true;
-    }
-    else // didn't queue the block
-    {
-        CFReleaseSafe(appID);
-        CFReleaseSafe(fqdn);
-    }
+       _SecSetAppDomainApprovalStatus(appID, fqdn, kCFBooleanFalse);
 
     if (!forSafari) { return result; }
 
@@ -2475,20 +2475,13 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes,
 
     // parse fqdn with CFURL here, since it could be specified as domain:port
     if (fqdn) {
-        CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn);
-        if (urlStr) {
-            CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil);
-            if (url) {
-                CFStringRef hostname = CFURLCopyHostName(url);
-                if (hostname) {
-                    CFReleaseSafe(fqdn);
-                    fqdn = hostname;
-                    port = CFURLGetPortNumber(url);
-                }
-                CFReleaseSafe(url);
-            }
-            CFReleaseSafe(urlStr);
-        }
+               CFTypeRef fqdnObject = _SecCopyFQDNObjectFromString(fqdn);
+               if (fqdnObject) {
+                       CFReleaseSafe(fqdn);
+                       fqdn = _SecGetFQDNFromFQDNObject(fqdnObject, &port);
+                       CFRetainSafe(fqdn);
+                       CFReleaseSafe(fqdnObject);
+               }
     }
 
     if (!account) {
@@ -2509,7 +2502,7 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes,
         SecError(status, error, CFSTR("Missing application-identifier entitlement"));
         goto cleanup;
     }
-    if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) {
+    if (_SecEntitlementContainsDomainForService(domains, fqdn, port)) {
         status = errSecSuccess;
     }
     if (errSecSuccess != status) {
@@ -2528,8 +2521,8 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes,
     secerror("Ignoring app/site approval state in the Simulator.");
 #else
     // get approval status for this app/domain pair
-    SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
-    if (!(flags & kSWCFlag_SiteApproved)) {
+    SecSWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
+    if (!(flags & kSecSWCFlag_SiteApproved)) {
         goto cleanup;
     }
 #endif
@@ -2589,7 +2582,7 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes,
             bool samePassword = result && *result && CFEqual(*result, credential);
             CFReleaseSafe(credential);
             CFDictionaryAddValue(attrs, kSecAttrComment, kSecSafariDefaultComment);
-            
+
             ok = samePassword || swca_confirm_operation(swca_update_request_id, clientAuditToken, query, error,
                 ^void (CFStringRef confirm_fqdn) {
                     _SecAddNegativeWebCredential(client, confirm_fqdn, appID, false);
@@ -2609,7 +2602,7 @@ _SecAddSharedWebCredential(CFDictionaryRef attributes,
                 ok = _SecItemDelete(query, &swcclient, error);
             }
         }
-        
+
         if(result) CFReleaseNull(*result);
         if(error) CFReleaseNull(*error);
 
@@ -2679,9 +2672,7 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
     CFMutableArrayRef credentials = NULL;
     CFMutableArrayRef foundItems = NULL;
     CFMutableArrayRef fqdns = NULL;
-    CFStringRef fqdn = NULL;
     CFStringRef account = NULL;
-    SInt32 port = -1;
     bool ok = false;
 
     require_quiet(result, cleanup);
@@ -2701,7 +2692,6 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
     };
 
     // On input, the query dictionary contains optional fqdn and account entries.
-    fqdn = CFDictionaryGetValue(query, kSecAttrServer);
     account = CFDictionaryGetValue(query, kSecAttrAccount);
 
     // Check autofill enabled status
@@ -2711,28 +2701,30 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
     }
 
     // Check fqdn; if NULL, add domains from caller's entitlement.
-    if (fqdn) {
-        CFArrayAppendValue(fqdns, fqdn);
-    }
-    else if (domains) {
-        CFIndex idx, count = CFArrayGetCount(domains);
-        for (idx=0; idx < count; idx++) {
-            CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx);
-            // Parse the entry for our service label prefix
-            if (str && CFStringHasPrefix(str, kSecSharedWebCredentialsService)) {
-                CFIndex prefix_len = CFStringGetLength(kSecSharedWebCredentialsService)+1;
-                CFIndex substr_len = CFStringGetLength(str) - prefix_len;
-                CFRange range = { prefix_len, substr_len };
-                fqdn = CFStringCreateWithSubstring(kCFAllocatorDefault, str, range);
-                if (fqdn) {
-                    CFArrayAppendValue(fqdns, fqdn);
-                    CFRelease(fqdn);
+    {
+        CFStringRef fqdn = CFDictionaryGetValue(query, kSecAttrServer);
+        if (fqdn) {
+            CFTypeRef fqdnObject = _SecCopyFQDNObjectFromString(fqdn);
+            if (fqdnObject) {
+                CFArrayAppendValue(fqdns, fqdnObject);
+                CFReleaseSafe(fqdnObject);
+            }
+        }
+        else if (domains) {
+            CFIndex idx, count = CFArrayGetCount(domains);
+            for (idx=0; idx < count; idx++) {
+                CFStringRef str = (CFStringRef) CFArrayGetValueAtIndex(domains, idx);
+                // Parse the entry for our service label prefix
+                CFTypeRef fqdnObject = _SecCopyFQDNObjectFromString(str);
+                if (fqdnObject) {
+                    CFArrayAppendValue(fqdns, fqdnObject);
+                    CFReleaseSafe(fqdnObject);
                 }
             }
         }
     }
     CFIndex count, idx;
-    
+
     count = CFArrayGetCount(fqdns);
     if (count < 1) {
         SecError(errSecParam, error, CFSTR("No domain provided"));
@@ -2743,27 +2735,10 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
     for (idx = 0; idx < count; idx++) {
         CFMutableArrayRef items = NULL;
         CFMutableDictionaryRef attrs = NULL;
-        fqdn = (CFStringRef) CFArrayGetValueAtIndex(fqdns, idx);
-        CFRetainSafe(fqdn);
-        port = -1;
 
-        // Parse the fqdn for a possible port specifier.
-        if (fqdn) {
-            CFStringRef urlStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@%@"), kSecSharedCredentialUrlScheme, fqdn);
-            if (urlStr) {
-                CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, urlStr, nil);
-                if (url) {
-                    CFStringRef hostname = CFURLCopyHostName(url);
-                    if (hostname) {
-                        CFReleaseSafe(fqdn);
-                        fqdn = hostname;
-                        port = CFURLGetPortNumber(url);
-                    }
-                    CFReleaseSafe(url);
-                }
-                CFReleaseSafe(urlStr);
-            }
-        }
+        CFTypeRef fqdnObject = CFArrayGetValueAtIndex(fqdns, idx);
+        SInt32 port = -1;
+        CFStringRef fqdn = _SecGetFQDNFromFQDNObject(fqdnObject, &port);
 
 #if TARGET_OS_SIMULATOR
         secerror("app/site association entitlements not checked in Simulator");
@@ -2771,11 +2746,10 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
            OSStatus status = errSecMissingEntitlement;
         if (!appID) {
             SecError(status, error, CFSTR("Missing application-identifier entitlement"));
-            CFReleaseSafe(fqdn);
             goto cleanup;
         }
         // validate that fqdn is part of caller's entitlement
-        if (_SecEntitlementContainsDomainForService(domains, fqdn, kSecSharedWebCredentialsService)) {
+        if (_SecEntitlementContainsDomainForService(domains, fqdn, port)) {
             status = errSecSuccess;
         }
         if (errSecSuccess != status) {
@@ -2786,7 +2760,6 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
             }
             SecError(status, error, CFSTR("%@"), msg);
             CFReleaseSafe(msg);
-            CFReleaseSafe(fqdn);
             goto cleanup;
         }
 #endif
@@ -2794,7 +2767,6 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
         attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
         if (!attrs) {
             SecError(errSecAllocate, error, CFSTR("Unable to create query dictionary"));
-            CFReleaseSafe(fqdn);
             goto cleanup;
         }
         CFDictionaryAddValue(attrs, kSecClass, kSecClassInternetPassword);
@@ -2827,12 +2799,12 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
             bool approved = true;
 #else
             // get approval status for this app/domain pair
-            SWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
+            SecSWCFlags flags = _SecAppDomainApprovalStatus(appID, fqdn, error);
             if (count > 1) {
                 // ignore interim error since we have multiple domains to check
                 CFReleaseNull(*error);
             }
-            bool approved = (flags & kSWCFlag_SiteApproved);
+            bool approved = (flags & kSecSWCFlag_SiteApproved);
 #endif
             if (approved) {
                 CFArrayAppendArray(foundItems, items, CFRangeMake(0, CFArrayGetCount(items)));
@@ -2840,7 +2812,6 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
         }
         CFReleaseSafe(items);
         CFReleaseSafe(attrs);
-        CFReleaseSafe(fqdn);
     }
 
 //  If matching credentials are found, the credentials provided to the completionHandler
@@ -2946,29 +2917,13 @@ _SecCopySharedWebCredential(CFDictionaryRef query,
         CFArrayRemoveAllValues(credentials);
         if (selected && ok) {
 #if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR
-            fqdn = CFDictionaryGetValue(selected, kSecAttrServer);
+                       // register confirmation with database
+            CFStringRef fqdn = CFDictionaryGetValue(selected, kSecAttrServer);
+            _SecSetAppDomainApprovalStatus(appID, fqdn, kCFBooleanTrue);
 #endif
             CFArrayAppendValue(credentials, selected);
         }
 
-        if (ok) {
-#if TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR
-            // register confirmation with database
-            CFRetainSafe(appID);
-            CFRetainSafe(fqdn);
-            if (0 != SWCSetServiceFlags(kSecSharedWebCredentialsService,
-                appID, fqdn, kSWCFlag_ExternalMask, kSWCFlag_UserApproved,
-                ^void(OSStatus inStatus, SWCFlags inNewFlags){
-                    CFReleaseSafe(appID);
-                    CFReleaseSafe(fqdn);
-                }))
-            {
-                 // we didn't queue the block
-                CFReleaseSafe(appID);
-                CFReleaseSafe(fqdn);
-            }
-#endif
-        }
         CFReleaseSafe(selected);
     }
     else if (NULL == *error) {
@@ -2989,6 +2944,23 @@ cleanup:
     return ok;
 }
 
+#else /* !(TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_WATCH && !TARGET_OS_TV) */
+
+bool _SecAddSharedWebCredential(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error) {
+    if (error) {
+        SecError(errSecUnimplemented, error, CFSTR("_SecAddSharedWebCredential not supported on this platform"));
+    }
+    return false;
+}
+
+bool _SecCopySharedWebCredential(CFDictionaryRef query, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error) {
+    if (error) {
+        SecError(errSecUnimplemented, error, CFSTR("_SecCopySharedWebCredential not supported on this platform"));
+    }
+    return false;
+}
+
+#endif /* !(TARGET_OS_IOS && !TARGET_OS_BRIDGE && !TARGET_OS_WATCH && !TARGET_OS_TV) */
 #endif /* SHAREDWEBCREDENTIALS */
 
 
@@ -3269,6 +3241,13 @@ _SecServerRestoreSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef pa
 errOut:
     return ok;
 }
+
+#else /* SECUREOBJECTSYNC */
+
+SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void) {
+    return NULL;
+}
+
 #endif /* SECUREOBJECTSYNC */
 
 bool _SecServerRollKeysGlue(bool force, CFErrorRef *error) {
@@ -3308,7 +3287,7 @@ InitialSyncItems(CFMutableArrayRef items, bool limitToCurrent, CFStringRef agrp,
     bool result = false;
     Query *q = NULL;
 
-    q = query_create(qclass, NULL, NULL, error);
+    q = query_create(qclass, NULL, NULL, NULL, error);
     require(q, fail);
 
     q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask;
@@ -3452,7 +3431,7 @@ _SecServerImportInitialSyncCredentials(CFArrayRef array, CFErrorRef *error)
                     continue;
                 }
 
-                if (!SecDbItemInsert(dbi, dbt, &cferror)) {
+                if (!SecDbItemInsert(dbi, dbt, false, &cferror)) {
                     secinfo("ImportInitialSyncItems", "Item store failed with: %@: %@", cferror, dbi);
                     CFReleaseNull(cferror);
                 }
@@ -3506,7 +3485,7 @@ TransmogrifyItemsToSyncBubble(SecurityClient *client, uid_t uid,
 
         secnotice("syncbubble", "cleaning out old items");
 
-        q = query_create(qclass, NULL, NULL, error);
+        q = query_create(qclass, NULL, NULL, client, error);
         require(q, fail);
 
         q->q_limit = kSecMatchUnlimited;
@@ -3538,7 +3517,7 @@ TransmogrifyItemsToSyncBubble(SecurityClient *client, uid_t uid,
 
         secnotice("syncbubble", "migrating sync bubble items");
 
-        q = query_create(qclass, NULL, NULL, error);
+        q = query_create(qclass, NULL, NULL, client, error);
         require(q, fail);
 
         q->q_return_type = kSecReturnDataMask | kSecReturnAttributesMask;
@@ -3578,7 +3557,7 @@ TransmogrifyItemsToSyncBubble(SecurityClient *client, uid_t uid,
                         return;
                     }
 
-                    if (!SecDbItemInsert(new_item, dbt, &error3)) {
+                    if (!SecDbItemInsert(new_item, dbt, false, &error3)) {
                         secnotice("syncbubble", "migration failed with %@ for item %@", error3, new_item);
                     }
                     CFRelease(new_item);
@@ -3820,7 +3799,7 @@ _SecServerTransmogrifyToSystemKeychain(SecurityClient *client, CFErrorRef *error
                     continue;
                 }
 
-                q = query_create(*kcClass, SecMUSRGetSingleUserKeychainUUID(), NULL, error);
+                q = query_create(*kcClass, SecMUSRGetSingleUserKeychainUUID(), NULL, client, error);
                 if (q == NULL)
                     continue;
 
index 0c1637786929acaa26201c90d85d4acfc26b3295..b8f82e3ab760905bc7f805eb79ecb91610e9f7f1 100644 (file)
@@ -56,7 +56,7 @@ CFStringRef _SecServerBackupCopyUUID(CFDataRef backup, CFErrorRef *error);
 bool _SecServerBackupKeybagAdd(SecurityClient *client, CFDataRef passcode, CFDataRef *identifier, CFDataRef *pathinfo, CFErrorRef *error);
 bool _SecServerBackupKeybagDelete(CFDictionaryRef attributes, bool deleteAll, CFErrorRef *error);
 
-bool _SecItemUpdateTokenItems(CFStringRef tokenID, CFArrayRef items, SecurityClient *client, CFErrorRef *error);
+bool _SecItemUpdateTokenItemsForAccessGroups(CFStringRef tokenID, CFArrayRef accessGroups, CFArrayRef items, SecurityClient *client, CFErrorRef *error);
 
 CF_RETURNS_RETAINED CFArrayRef _SecServerKeychainSyncUpdateMessage(CFDictionaryRef updates, CFErrorRef *error);
 CF_RETURNS_RETAINED CFDictionaryRef _SecServerBackupSyncable(CFDictionaryRef backup, CFDataRef keybag, CFDataRef password, CFErrorRef *error);
@@ -71,10 +71,10 @@ bool _SecServerTransmogrifyToSyncBubble(CFArrayRef services, uid_t uid, Security
 bool _SecServerDeleteMUSERViews(SecurityClient *client, uid_t uid, CFErrorRef *error);
 #endif
 
-#if TARGET_OS_IOS && !TARGET_OS_BRIDGE
+#if SHAREDWEBCREDENTIALS
 bool _SecAddSharedWebCredential(CFDictionaryRef attributes, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error);
 bool _SecCopySharedWebCredential(CFDictionaryRef query, SecurityClient *client, const audit_token_t *clientAuditToken, CFStringRef appID, CFArrayRef domains, CFTypeRef *result, CFErrorRef *error);
-#endif /* TARGET_OS_IOS */
+#endif /* SHAREDWEBCREDENTIALS */
 
 // Hack to log objects from inside SOS code
 void SecItemServerAppendItemDescription(CFMutableStringRef desc, CFDictionaryRef object);
@@ -92,7 +92,6 @@ bool kc_with_custom_db(bool writeAndRead, bool usesItemTables, SecDbRef db, CFEr
 void SecKeychainDbForceClose(void);
 void SecKeychainDbReset(dispatch_block_t inbetween);
 
-
 SOSDataSourceFactoryRef SecItemDataSourceFactoryGetDefault(void);
 
 /* FIXME: there is a specific type for keybag handle (keybag_handle_t)
@@ -129,6 +128,8 @@ bool accessGroupsAllows(CFArrayRef accessGroups, CFStringRef accessGroup, Securi
 bool itemInAccessGroup(CFDictionaryRef item, CFArrayRef accessGroups);
 void SecKeychainChanged(void);
 
+void deleteCorruptedItemAsync(SecDbConnectionRef dbt, CFStringRef tablename, sqlite_int64 rowid);
+
 __END_DECLS
 
 #endif /* _SECURITYD_SECITEMSERVER_H_ */
index d526c73f44392ae56f6c09abfb80783738b47174..ee88f5d95b55e26b559581ec5c5f0cc7c17ccf5b 100644 (file)
@@ -337,7 +337,7 @@ bool ks_decrypt_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data, CFMutableDa
                                                   aks_return, "decrypt"));
 
     CFPropertyListRef decoded_data = NULL;
-    der_decode_plist(kCFAllocatorDefault, kCFPropertyListImmutable, &decoded_data, NULL, der, der + der_len);
+    der_decode_plist(kCFAllocatorDefault, &decoded_data, NULL, der, der + der_len);
     require_action_quiet(decoded_data, out, SecError(errSecDecode, error, CFSTR("ks_crypt_acl: %x failed to '%s' item, Item can't be decrypted due to failed decode der, so drop the item."),
                                                            aks_return, "decrypt"));
     if (CFGetTypeID(decoded_data) == CFDataGetTypeID()) {
@@ -370,7 +370,7 @@ bool ks_delete_acl(aks_ref_key_t ref_key, CFDataRef encrypted_data,
     int aks_return = kAKSReturnSuccess;
     bool ok = false;
 
-    nrequire_action_quiet(CFEqual(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true);
+    nrequire_action_quiet(CFEqualSafe(SecAccessControlGetConstraint(access_control, kAKSKeyOpDelete), kCFBooleanTrue), out, ok = true);
 
     /* Verify that we have credential handle, otherwise generate proper error containing ACL and operation requested. */
     if (!acm_context) {
index cef0caf17140f0f412f52feb112f2a248a7ee012..fcc4e5647df216a064e8e382977a3cfea30ba144 100644 (file)
@@ -64,7 +64,7 @@ CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFData
     privateKeyRef = SOSAccountCopyDeviceKey(privateAccount, error);
     require_quiet(privateKeyRef, fail);
 
-    privateIdentity = SecOTRFullIdentityCreateFromSecKeyRef(kCFAllocatorDefault, privateKeyRef, error);
+    privateIdentity = SecOTRFullIdentityCreateFromSecKeyRefSOS(kCFAllocatorDefault, privateKeyRef, error);
     require_quiet(privateIdentity, fail);
     CFReleaseNull(privateKeyRef);
 
index 21f50f456343917ea883273ae7992b451b8d7a1d..48c79e591c2cdc1fd47bb1d4447580f2de72d9a2 100644 (file)
@@ -4,6 +4,9 @@
 
 (import "system.sb")
 
+(allow file-write-data
+    (literal "/dev/random"))
+
 (allow file-read* file-write*
     (subpath "/private/var/db/mds")
     (regex #"^/private/var/folders/[^/]+/[^/]+/T(/|$)")
index 026250126afb4cabcd077af1a727a42bff56bff9..05391bd252a8bc38f66cd2bdcf857f8b134e8cea 100644 (file)
@@ -2,6 +2,8 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
+       <key>com.apple.private.cloudkit.notifyOnAccountWarmup</key>
+       <true/>
        <key>com.apple.private.dark-wake-push</key>
        <true/>
        <key>com.apple.private.accounts.allaccounts</key>
@@ -36,6 +38,8 @@
        <true/>
        <key>com.apple.private.cloudkit.supportservice</key>
        <true/>
+       <key>com.apple.private.cloudkit.spi</key>
+       <true/>
        <key>com.apple.private.appleaccount.app-hidden-from-icloud-settings</key>
        <true/>
        <key>com.apple.private.tcc.allow</key>
@@ -92,5 +96,7 @@
        <true/>
        <key>com.apple.symptom_diagnostics.report</key>
        <true/>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
index 367f2274d741c7c1a7ff4f87df00e9d5a91ad4d8..f6a5745dc13f7575b7c7b4aa571302cf3dc8a32b 100644 (file)
@@ -62,7 +62,7 @@ static struct securityd securityd_spi = {
     .sec_item_copy_parent_certificates      = _SecItemCopyParentCertificates,
     .sec_item_certificate_exists            = _SecItemCertificateExists,
     .sec_roll_keys                          = _SecServerRollKeysGlue,
-    .sec_item_update_token_items            = _SecItemUpdateTokenItems,
+    .sec_item_update_token_items_for_access_groups  = _SecItemUpdateTokenItemsForAccessGroups,
     .sec_delete_items_with_access_groups    = _SecItemServerDeleteAllWithAccessGroups,
 #if SHAREDWEBCREDENTIALS
     .sec_add_shared_web_credential          = _SecAddSharedWebCredential,
@@ -72,6 +72,7 @@ static struct securityd securityd_spi = {
     .sec_keychain_backup_syncable           = _SecServerBackupSyncable,
     .sec_keychain_restore_syncable          = _SecServerRestoreSyncable,
     .sec_item_backup_copy_names             = SecServerItemBackupCopyNames,
+    .sec_item_backup_ensure_copy_view       = SecServerItemBackupEnsureCopyView,
     .sec_item_backup_handoff_fd             = SecServerItemBackupHandoffFD,
     .sec_item_backup_set_confirmed_manifest = SecServerItemBackupSetConfirmedManifest,
     .sec_item_backup_restore                = SecServerItemBackupRestore,
@@ -80,24 +81,18 @@ static struct securityd securityd_spi = {
     .soscc_TryUserCredentials               = SOSCCTryUserCredentials_Server,
     .soscc_SetUserCredentials               = SOSCCSetUserCredentials_Server,
     .soscc_SetUserCredentialsAndDSID        = SOSCCSetUserCredentialsAndDSID_Server,
-    .soscc_SetUserCredentialsAndDSIDWithAnalytics  = SOSCCSetUserCredentialsAndDSIDWithAnalytics_Server,
     .soscc_CanAuthenticate                  = SOSCCCanAuthenticate_Server,
     .soscc_PurgeUserCredentials             = SOSCCPurgeUserCredentials_Server,
     .soscc_ThisDeviceIsInCircle             = SOSCCThisDeviceIsInCircle_Server,
     .soscc_RequestToJoinCircle              = SOSCCRequestToJoinCircle_Server,
     .soscc_RequestToJoinCircleAfterRestore  = SOSCCRequestToJoinCircleAfterRestore_Server,
-    .soscc_RequestToJoinCircleAfterRestoreWithAnalytics  = SOSCCRequestToJoinCircleAfterRestoreWithAnalytics_Server,
     .soscc_SetToNew                         = SOSCCAccountSetToNew_Server,
     .soscc_ResetToOffering                  = SOSCCResetToOffering_Server,
     .soscc_ResetToEmpty                     = SOSCCResetToEmpty_Server,
-    .soscc_ResetToEmptyWithAnalytics        = SOSCCResetToEmptyWithAnalytics_Server,
     .soscc_View                             = SOSCCView_Server,
     .soscc_ViewSet                          = SOSCCViewSet_Server,
-    .soscc_ViewSetWithAnalytics             = SOSCCViewSetWithAnalytics_Server,
     .soscc_RemoveThisDeviceFromCircle       = SOSCCRemoveThisDeviceFromCircle_Server,
-    .soscc_RemoveThisDeviceFromCircleWithAnalytics = SOSCCRemoveThisDeviceFromCircleWithAnalytics_Server,
     .soscc_RemovePeersFromCircle            = SOSCCRemovePeersFromCircle_Server,
-    .soscc_RemovePeersFromCircleWithAnalytics = SOSCCRemovePeersFromCircleWithAnalytics_Server,
     .soscc_LoggedOutOfAccount               = SOSCCLoggedOutOfAccount_Server,
     .soscc_BailFromCircle                   = SOSCCBailFromCircle_Server,
     .soscc_AcceptApplicants                 = SOSCCAcceptApplicants_Server,
@@ -124,7 +119,6 @@ static struct securityd securityd_spi = {
     .soscc_SetNewPublicBackupKey            = SOSCCSetNewPublicBackupKey_Server,
     .soscc_RegisterSingleRecoverySecret     = SOSCCRegisterSingleRecoverySecret_Server,
     .soscc_WaitForInitialSync               = SOSCCWaitForInitialSync_Server,
-    .soscc_WaitForInitialSyncWithAnalytics  = SOSCCWaitForInitialSyncWithAnalytics_Server,
     .soscc_AccountHasPublicKey              = SOSCCAccountHasPublicKey_Server,
     .soscc_SOSCCPeersHaveViewsEnabled       = SOSCCPeersHaveViewsEnabled_Server,
     .soscc_RegisterRecoveryPublicKey        = SOSCCRegisterRecoveryPublicKey_Server,
index 5ba4a914a470cb6a9769e28646df022be2e6e3ae..6f6e88338ead4a087abb8bead92b0211ac17db04 100644 (file)
@@ -1,7 +1,7 @@
 import Foundation
 import os
 
-let tplogDebug = OSLog(subsystem: "com.apple.security.trustedpeers", category: "debug")
+let logger = Logger(subsystem: "com.apple.security.trustedpeers", category: "tpctl")
 
 // This should definitely use the ArgumentParser library from the Utility package.
 // However, right now that's not accessible from this code due to build system issues.
@@ -223,7 +223,7 @@ while let arg = argIterator.next() {
             print("Error: --policy-secret data must be base-64")
             exitUsage(1)
         }
-        if nil == policySecrets {
+        if policySecrets == nil {
             policySecrets = [:]
         }
         policySecrets![name] = data
@@ -270,7 +270,6 @@ while let arg = argIterator.next() {
             }
             voucher = voucherData
             voucherSig = voucherSigData
-
         } else {
             guard let voucherBase64 = argIterator.next() else {
                 print("Error: join needs a voucher")
@@ -360,9 +359,7 @@ while let arg = argIterator.next() {
             permanentInfoSig = permanentInfoSigData
             stableInfo = stableInfoData
             stableInfoSig = stableInfoSigData
-
         } else {
-
             guard let peerIDString = argIterator.next() else {
                 print("Error: vouch needs a peerID")
                 print()
@@ -488,14 +485,16 @@ func cleanDictionaryForJSON(_ d: [AnyHashable: Any]) -> [AnyHashable: Any] {
 
 // Bring up a connection to TrustedPeersHelper
 let connection = NSXPCConnection(serviceName: "com.apple.TrustedPeersHelper")
+
 connection.remoteObjectInterface = TrustedPeersHelperSetupProtocol(NSXPCInterface(with: TrustedPeersHelperProtocol.self))
 connection.resume()
+
 let tpHelper = connection.synchronousRemoteObjectProxyWithErrorHandler { error in print("Unable to connect to TPHelper:", error) } as! TrustedPeersHelperProtocol
 
 for command in commands {
     switch command {
     case .dump:
-        os_log("dumping (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("dumping (\(container), \(context))")
         tpHelper.dump(withContainer: container, context: context) { reply, error in
             guard error == nil else {
                 print("Error dumping:", error!)
@@ -514,7 +513,7 @@ for command in commands {
         }
 
     case .depart:
-        os_log("departing (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("departing (\(container), \(context))")
         tpHelper.departByDistrustingSelf(withContainer: container, context: context) { error in
             guard error == nil else {
                 print("Error departing:", error!)
@@ -525,7 +524,7 @@ for command in commands {
         }
 
     case .distrust(let peerIDs):
-        os_log("distrusting %@ for (%@, %@)", log: tplogDebug, type: .default, peerIDs, container, context)
+        logger.log("distrusting \(peerIDs.description) for (\(container), \(context))")
         tpHelper.distrustPeerIDs(withContainer: container, context: context, peerIDs: peerIDs) { error in
             guard error == nil else {
                 print("Error distrusting:", error!)
@@ -534,15 +533,15 @@ for command in commands {
             print("Distrust successful")
         }
 
-    case .join(let voucher, let voucherSig):
-        os_log("joining (%@, %@)", log: tplogDebug, type: .default, container, context)
+    case let .join(voucher, voucherSig):
+        logger.log("joining (\(container), \(context))")
         tpHelper.join(withContainer: container,
                       context: context,
                       voucherData: voucher,
                       voucherSig: voucherSig,
                       ckksKeys: [],
                       tlkShares: [],
-                      preapprovedKeys: preapprovedKeys ?? []) { peerID, _, _, _, error in
+                      preapprovedKeys: preapprovedKeys ?? []) { peerID, _, _, error in
                         guard error == nil else {
                             print("Error joining:", error!)
                             return
@@ -551,12 +550,12 @@ for command in commands {
         }
 
     case .establish:
-        os_log("establishing (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("establishing (\(container), \(context))")
         tpHelper.establish(withContainer: container,
                            context: context,
                            ckksKeys: [],
                            tlkShares: [],
-                           preapprovedKeys: preapprovedKeys ?? []) { peerID, _, error in
+                           preapprovedKeys: preapprovedKeys ?? []) { peerID, _, _, error in
                             guard error == nil else {
                                 print("Error establishing:", error!)
                                 return
@@ -565,7 +564,7 @@ for command in commands {
         }
 
     case .healthInquiry:
-        os_log("healthInquiry (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("healthInquiry (\(container), \(context))")
         tpHelper.pushHealthInquiry(withContainer: container, context: context) { error in
             guard error == nil else {
                 print("Error healthInquiry: \(String(describing: error))")
@@ -575,19 +574,19 @@ for command in commands {
         }
 
     case .localReset:
-        os_log("local-reset (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("local-reset (\(container), \(context))")
         tpHelper.localReset(withContainer: container, context: context) { error in
             guard error == nil else {
                 print("Error resetting:", error!)
                 return
             }
 
-            os_log("local-reset (%@, %@): successful", log: tplogDebug, type: .default, container, context)
+            logger.log("local-reset (\(container), \(context)): successful")
             print("Local reset successful")
         }
 
     case .supportApp:
-        os_log("supportApp (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("supportApp (\(container), \(context))")
 
         tpHelper.getSupportAppInfo(withContainer: container, context: context) { data, error in
             guard error == nil else {
@@ -608,7 +607,7 @@ for command in commands {
         }
 
     case .prepare:
-        os_log("preparing (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("preparing (\(container), \(context))")
 
         if machineID == nil {
             let anisetteController = AKAnisetteProvisioningController()
@@ -623,6 +622,12 @@ for command in commands {
 
         let deviceInfo = OTDeviceInformationActualAdapter()
 
+        serialNumber = serialNumber ?? deviceInfo.serialNumber()
+        guard let serialNumber = serialNumber else {
+            print("failed to get serial number")
+            abort()
+        }
+
         tpHelper.prepare(withContainer: container,
                          context: context,
                          epoch: epoch,
@@ -631,12 +636,13 @@ for command in commands {
                          bottleID: UUID().uuidString,
                          modelID: modelID ?? deviceInfo.modelID(),
                          deviceName: deviceName ?? deviceInfo.deviceName(),
-                         serialNumber: serialNumber ?? deviceInfo.serialNumber(),
+                         serialNumber: serialNumber,
                          osVersion: osVersion ?? deviceInfo.osVersion(),
                          policyVersion: nil,
                          policySecrets: policySecrets,
+                         syncUserControllableViews: .UNKNOWN,
                          signingPrivKeyPersistentRef: nil,
-                         encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, views, _, error in
+                         encPrivKeyPersistentRef: nil) { peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig, syncingPolicy, error in
                             guard error == nil else {
                                 print("Error preparing:", error!)
                                 return
@@ -649,7 +655,7 @@ for command in commands {
                                 "stableInfo": stableInfo!.base64EncodedString(),
                                 "stableInfoSig": stableInfoSig!.base64EncodedString(),
                                 "machineID": machineID!,
-                                "views": Array(views ?? Set()),
+                                "views": Array(syncingPolicy?.viewList ?? Set()),
                                 ] as [String: Any]
                             do {
                                 print(try TPCTLObjectiveC.jsonSerialize(cleanDictionaryForJSON(result)))
@@ -659,14 +665,15 @@ for command in commands {
         }
 
     case .update:
-        os_log("updating (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("updating (\(container), \(context))")
         tpHelper.update(withContainer: container,
                         context: context,
                         deviceName: deviceName,
                         serialNumber: serialNumber,
                         osVersion: osVersion,
                         policyVersion: nil,
-                        policySecrets: policySecrets) { _, error in
+                        policySecrets: policySecrets,
+                        syncUserControllableViews: nil) { _, _, error in
                             guard error == nil else {
                                 print("Error updating:", error!)
                                 return
@@ -676,7 +683,7 @@ for command in commands {
         }
 
     case .reset:
-        os_log("resetting (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("resetting (\(container), \(context))")
         tpHelper.reset(withContainer: container, context: context, resetReason: .userInitiatedReset) { error in
             guard error == nil else {
                 print("Error during reset:", error!)
@@ -687,7 +694,7 @@ for command in commands {
         }
 
     case .validate:
-        os_log("validate (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("validate (\(container), \(context))")
         tpHelper.validatePeers(withContainer: container, context: context) { reply, error in
             guard error == nil else {
                 print("Error validating:", error!)
@@ -706,7 +713,7 @@ for command in commands {
         }
 
     case .viableBottles:
-        os_log("viableBottles (%@, %@)", log: tplogDebug, type: .default, container, context)
+        logger.log("viableBottles (\(container), \(context))")
         tpHelper.fetchViableBottles(withContainer: container, context: context) { sortedBottleIDs, partialBottleIDs, error in
             guard error == nil else {
                 print("Error fetching viable bottles:", error!)
@@ -722,8 +729,8 @@ for command in commands {
             }
         }
 
-    case .vouch(let peerID, let permanentInfo, let permanentInfoSig, let stableInfo, let stableInfoSig):
-        os_log("vouching (%@, %@)", log: tplogDebug, type: .default, container, context)
+    case let .vouch(peerID, permanentInfo, permanentInfoSig, stableInfo, stableInfoSig):
+        logger.log("vouching (\(container), \(context))")
         tpHelper.vouch(withContainer: container,
                        context: context,
                        peerID: peerID,
@@ -746,8 +753,8 @@ for command in commands {
             }
         }
 
-    case .vouchWithBottle(let bottleID, let entropy, let salt):
-        os_log("vouching with bottle (%@, %@)", log: tplogDebug, type: .default, container, context)
+    case let .vouchWithBottle(bottleID, entropy, salt):
+        logger.log("vouching with bottle (\(container), \(context))")
         tpHelper.vouchWithBottle(withContainer: container,
                                  context: context,
                                  bottleID: bottleID,
@@ -766,8 +773,8 @@ for command in commands {
                                     }
         }
 
-    case .allow(let machineIDs, let performIDMS):
-        os_log("allow-listing (%@, %@)", log: tplogDebug, type: .default, container, context)
+    case let .allow(machineIDs, performIDMS):
+        logger.log("allow-listing (\(container), \(context))")
 
         var idmsDeviceIDs: Set<String> = Set()
         var accountIsDemo: Bool = false
diff --git a/libsecurity_smime/Security b/libsecurity_smime/Security
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index 8ac1228c6f3de4df5c7d5e91c18e86df4473da80..513932d2ca88d38a30ebeb55a25e0264769e4b42 100644 (file)
@@ -223,7 +223,6 @@ OSStatus CMSDecoderUpdateMessage(
         case DS_Init:
             /* First time through; set up */
             ASSERT(cmsDecoder->decoder == NULL);
-            ASSERT(cmsDecoder->arena == NULL);
             ortn = SecCmsDecoderCreate(NULL, NULL, NULL, NULL, NULL, NULL, &cmsDecoder->decoder);
             if(ortn) {
                 ortn = cmsRtnToOSStatus(ortn);
index 8fc6d1d9ec546fb09ab04f3f194da6145214d1c3..1cc87e392eb39757a6a4fad6166aeeb9776cfd5a 100644 (file)
@@ -363,7 +363,7 @@ static OSStatus cmsSetupEncoder(
 {
     OSStatus ortn;
 
-    ASSERT(cmsEncoder->arena == NULL);
+    ASSERT(cmsEncoder->cmsMsg != NULL);
     ASSERT(cmsEncoder->encoder == NULL);
 
     cmsEncoder->encoderOut = CFDataCreateMutable(NULL, 0);
index 25d5d8fd29a071a20da66b92003af023defdbcbb..bb34dd3c7892b8aa64eabf069d5f5aadad9826fa 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <Security/SecAsn1Types.h>
-#include <assert.h>
 
 __BEGIN_DECLS
 
@@ -62,13 +61,14 @@ OSStatus cmsRtnToOSStatusDefault(OSStatus smimeRtn, OSStatus defaultRtn);
 
 #define CFRELEASE(cfr) if(cfr != NULL) { CFRelease(cfr); }
 
+#include <security_utilities/simulatecrash_assert.h>
+#define ASSERT(s) assert(s)
+
 #define CMS_DEBUG 0
 #if    CMS_DEBUG
-#define ASSERT(s)                      assert(s)
 #define CSSM_PERROR(s, r)      cssmPerror(s, r)
 #define dprintf(args...)       printf(args)
 #else
-#define ASSERT(s)
 #define CSSM_PERROR(s, r)
 #define dprintf(args...)
 #endif
index 9968af8068009cda8554a4b3e5c47ee4437f6fcc..b511e686436b827170fd0935f83817ec08d50027 100644 (file)
@@ -34,7 +34,7 @@
 /*
  * CMS digesting.
  */
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 
 #include "cmslocal.h"
 
index c0d70ea9cb9aeafada3df76bd9a888a72d841675..2edf9680900a6bd55136bd80542948948a5ce514 100644 (file)
@@ -469,7 +469,8 @@ SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAs
 
     SECITEM_FreeItem(&signature, PR_FALSE);
 
-    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
+    SECOidTag sigAlgTag = SecCmsUtilMakeSignatureAlgorithm(digestalgtag, pubkAlgTag);
+    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), sigAlgTag,
                               NULL) != SECSuccess)
        goto loser;
 
@@ -1131,21 +1132,18 @@ SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo)
     SecCertificateRef signercert;
     CFStringRef emailAddress = NULL;
 
-    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
-       return NULL;
+    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL) {
+        return NULL;
+    }
 
-#if USE_CDSA_CRYPTO
-    SecCertificateGetEmailAddress(signercert, &emailAddress);
-#else
     CFArrayRef names = SecCertificateCopyRFC822Names(signercert);
     if (names) {
-        if (CFArrayGetCount(names) > 0)
+        if (CFArrayGetCount(names) > 0) {
             emailAddress = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
-        if (emailAddress)
-            CFRetain(emailAddress);
+        }
+        CFRetainSafe(emailAddress);
         CFRelease(names);
     }
-#endif
     return emailAddress;
 }
 
index c816df52ddbb1efb385b837575d36fd49d5650f5..8e9a4b9bd291362a73669b7e8cb5444bdeacb5da 100644 (file)
@@ -46,6 +46,7 @@
 #include <Security/SecIdentity.h>
 #include <Security/SecCertificateInternal.h>
 #include <Security/SecKeyPriv.h>
+#include <utilities/SecCFWrappers.h>
 
 #include <CommonCrypto/CommonDigest.h>
 #include <AssertMacros.h>
@@ -231,35 +232,40 @@ SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef ce
 
     void *mark;
     mark = PORT_ArenaMark(pl);
-    CFDataRef serial_data = NULL;
     CFDataRef issuer_data = SecCertificateCopyIssuerSequence(cert);
-    if (!issuer_data)
+    CFDataRef serial_data = SecCertificateCopySerialNumberData(cert, NULL);
+    if (!issuer_data || !serial_data) {
         goto loser;
-    serial_data = SecCertificateCopySerialNumberData(cert, NULL);
-    if (!serial_data)
-        goto loser;
-    
-    SecAsn1Item serialNumber = { CFDataGetLength(serial_data),
-        (uint8_t *)CFDataGetBytePtr(serial_data) };
-    SecAsn1Item issuer = { CFDataGetLength(issuer_data),
-        (uint8_t *)CFDataGetBytePtr(issuer_data) };
-    
-        /* Allocate the SecCmsIssuerAndSN struct. */
+    }
+
+    SecAsn1Item serialNumber = {
+        .Length = CFDataGetLength(serial_data),
+        .Data = (uint8_t *)CFDataGetBytePtr(serial_data)
+    };
+    SecAsn1Item issuer = {
+        .Length = CFDataGetLength(issuer_data),
+        .Data = (uint8_t *)CFDataGetBytePtr(issuer_data)
+    };
+
+    /* Allocate the SecCmsIssuerAndSN struct. */
     certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
-    if (certIssuerAndSN == NULL)
-       goto loser;
+    if (certIssuerAndSN == NULL) {
+        goto loser;
+    }
 
     /* Copy the issuer. */
     certIssuerAndSN->derIssuer.Data = (uint8_t *) PORT_ArenaAlloc(pl, issuer.Length);
-    if (!certIssuerAndSN->derIssuer.Data)
-       goto loser;
+    if (!certIssuerAndSN->derIssuer.Data) {
+        goto loser;
+    }
     PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer.Data, issuer.Length);
     certIssuerAndSN->derIssuer.Length = issuer.Length;
 
     /* Copy the serialNumber. */
     certIssuerAndSN->serialNumber.Data = (uint8_t *) PORT_ArenaAlloc(pl, serialNumber.Length);
-    if (!certIssuerAndSN->serialNumber.Data)
-       goto loser;
+    if (!certIssuerAndSN->serialNumber.Data) {
+        goto loser;
+    }
     PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber.Data, serialNumber.Length);
     certIssuerAndSN->serialNumber.Length = serialNumber.Length;
 
@@ -267,14 +273,12 @@ SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef ce
     CFRelease(issuer_data);
 
     PORT_ArenaUnmark(pl, mark);
-    
+
     return certIssuerAndSN;
 
 loser:
-    if (serial_data)
-        CFRelease(serial_data);
-    if (issuer_data)
-        CFRelease(issuer_data);
+    CFReleaseNull(serial_data);
+    CFReleaseNull(issuer_data);
     PORT_ArenaRelease(pl, mark);
     PORT_SetError(SEC_INTERNAL_ONLY);
 
diff --git a/libsecurity_smime/security_smime b/libsecurity_smime/security_smime
deleted file mode 120000 (symlink)
index 945c9b4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-.
\ No newline at end of file
index 90762e166b0caf82356b0c57813abffc2a6f3f87..f8fb24e27501a783f88a08bd558dcdd64ec8504f 100644 (file)
@@ -38,7 +38,7 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <strings.h>
 
 /* 
@@ -662,13 +662,15 @@ OSStatus _NtlmGeneratePasswordHashes(
        unsigned char hash[NTLM_DIGEST_LENGTH];
        
        result = ntlmPasswordHash(password, hash);
-    if (result)
+    if (result) {
         return result;
-       
-       *ntlmHash = CFDataCreate(alloc, hash, sizeof(hash));
+    }
+
+    *ntlmHash = CFDataCreate(alloc, hash, sizeof(hash));
     memset(hash, 0, sizeof(hash));
-    if (*ntlmHash == NULL)
+    if (*ntlmHash == NULL) {
         result = errSecAllocate;
+    }
 
     static const UInt8 zero[NTLM_DIGEST_LENGTH] = { 0 };
     *lmHash = CFDataCreate(NULL, zero, sizeof(zero));
index 5866c307e57259dee6f680ea8ba876c9eefcda9e..e6a285925cac37ba9777a53f35682d891cd8d087 100644 (file)
@@ -34,7 +34,7 @@
 #include <sys/param.h>
 #include <stdlib.h>
 #include <stdint.h>
-#include <assert.h>
+#include <utilities/simulatecrash_assert.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <strings.h>
@@ -183,12 +183,14 @@ OSStatus ntlmStringToLE(
        unsigned                *ucodeLen)              // RETURNED
 {
        CFIndex len = CFStringGetLength(pwd);
-    if (len > NTLM_MAX_STRING_LEN)
+    if (len > NTLM_MAX_STRING_LEN) {
         return errSecAllocate;
-       unsigned char *data = (unsigned char *)malloc(len * 2);
-    if (data == NULL)
+    }
+    unsigned char *data = (unsigned char *)malloc(len * 2);
+    if (data == NULL) {
         return errSecAllocate;
-       unsigned char *cp = data;
+    }
+    unsigned char *cp = data;
 
        CFIndex dex;
        for(dex=0; dex<len; dex++) {
@@ -430,11 +432,12 @@ OSStatus ntlmPasswordHash(
 
        /* convert to little-endian unicode */
     res = ntlmStringToLE(pwd, &data, &len);
-    if (res)
+    if (res) {
         return res;
-       /* md4 hash of that */
-       md4Hash(data, len, digest);
-       free(data);
+    }
+    /* md4 hash of that */
+    md4Hash(data, len, digest);
+    free(data);
 
     return 0;
 }
index ad12a40eb06e55843ec03572c0fa45d2c7cd9ef9..0e862282b5bcd5933a6eb4ea0e2cd849a1794d5e 100644 (file)
@@ -41,9 +41,8 @@
 #define SEC_PROTOCOL_OPTIONS_KEY_enable_renegotiation "enable_renegotiation"
 #define SEC_PROTOCOL_OPTIONS_KEY_enable_early_data "enable_early_data"
 #define SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_required "peer_authentication_required"
+#define SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_optional "peer_authentication_optional"
 #define SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled "certificate_compression_enabled"
-#define SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled "tls_SIKE503_exchange_enabled"
-#define SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled "tls_HRSS_exchange_enabled"
 #define SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled "eddsa_enabled"
 #define SEC_PROTOCOL_OPTIONS_KEY_tls_delegated_credentials_enabled "tls_delegated_credentials_enabled"
 #define SEC_PROTOCOL_OPTIONS_KEY_tls_grease_enabled "tls_grease_enabled"
@@ -195,12 +194,12 @@ sec_protocol_options_contents_are_equal(sec_protocol_options_content_t contentA,
     CHECK_FIELD(enable_renegotiation);
     CHECK_FIELD(enable_early_data);
     CHECK_FIELD(peer_authentication_required);
+    CHECK_FIELD(peer_authentication_optional);
     CHECK_FIELD(certificate_compression_enabled);
-    CHECK_FIELD(tls_SIKE503_exchange_enabled);
-    CHECK_FIELD(tls_HRSS_exchange_enabled);
     CHECK_FIELD(eddsa_enabled);
     CHECK_FIELD(tls_delegated_credentials_enabled);
     CHECK_FIELD(tls_grease_enabled);
+    CHECK_FIELD(allow_unknown_alpn_protos);
 
 #undef CHECK_FIELD
 
@@ -222,6 +221,7 @@ sec_protocol_options_contents_are_equal(sec_protocol_options_content_t contentA,
     CHECK_BLOCK_QUEUE(challenge_block, challenge_queue);
     CHECK_BLOCK_QUEUE(verify_block, verify_queue);
     CHECK_BLOCK_QUEUE(tls_secret_update_block, tls_secret_update_queue);
+    CHECK_BLOCK_QUEUE(tls_encryption_level_update_block, tls_encryption_level_update_queue);
 
 #undef CHECK_BLOCK_QUEUE
 
@@ -503,26 +503,88 @@ sec_protocol_options_add_tls_application_protocol(sec_protocol_options_t options
 }
 
 void
-sec_protocol_options_set_tls_server_name(sec_protocol_options_t options, const char *server_name)
+sec_protocol_options_add_transport_specific_application_protocol(sec_protocol_options_t options, const char *application_protocol, sec_protocol_transport_t specific_transport)
 {
     SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
-    SEC_PROTOCOL_OPTIONS_VALIDATE(server_name,);
+    SEC_PROTOCOL_OPTIONS_VALIDATE(application_protocol,);
 
     (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
         sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
         SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
 
-        CFStringRef serverName = CFStringCreateWithCString(NULL, server_name, kCFStringEncodingUTF8);
-       if (serverName == NULL) {
-           return false;
-       }
-        if (!SecFrameworkIsDNSName(serverName)) {
-            CFRelease(serverName);
+        if (content->application_protocols == NULL) {
+            content->application_protocols = xpc_array_create(NULL, 0);
+        }
+               xpc_object_t tuple = xpc_array_create(NULL, 0);
+        if (tuple != NULL) {
+            xpc_array_set_string(tuple, XPC_ARRAY_APPEND, application_protocol);
+            xpc_array_set_uint64(tuple, XPC_ARRAY_APPEND, (uint64_t)specific_transport);
+
+            xpc_array_append_value(content->application_protocols, tuple);
+            xpc_release(tuple);
+        }
+        return true;
+    });
+}
+
+xpc_object_t
+sec_protocol_options_copy_transport_specific_application_protocol(sec_protocol_options_t options, sec_protocol_transport_t specific_transport)
+{
+    SEC_PROTOCOL_OPTIONS_VALIDATE(options, NULL);
+
+    xpc_object_t filtered_application_protocols = xpc_array_create(NULL, 0);
+
+    bool success = sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        xpc_object_t application_protocols = content->application_protocols;
+        if (application_protocols == NULL) {
             return false;
         }
-        CFRelease(serverName);
 
-       free(content->server_name);
+        size_t application_protocol_count = xpc_array_get_count(application_protocols);
+        for (size_t i = 0; i < application_protocol_count; i++) {
+            xpc_object_t application_protocol = xpc_array_get_value(application_protocols, i);
+
+            if (xpc_get_type(application_protocol) == XPC_TYPE_STRING) {
+                xpc_array_set_string(filtered_application_protocols, XPC_ARRAY_APPEND, xpc_string_get_string_ptr(application_protocol));
+                continue;
+            }
+
+            if (xpc_get_type(application_protocol) == XPC_TYPE_ARRAY) {
+                uint64_t application_protocol_transport = xpc_array_get_uint64(application_protocol, 1);
+                if (application_protocol_transport != (uint64_t)specific_transport && specific_transport != sec_protocol_transport_any) {
+                    continue;
+                }
+
+                xpc_array_set_string(filtered_application_protocols, XPC_ARRAY_APPEND, xpc_array_get_string(application_protocol, 0));
+                continue;
+            }
+        }
+
+        return xpc_array_get_count(filtered_application_protocols) != 0;
+    });
+
+    if (!success) {
+        xpc_release(filtered_application_protocols);
+        filtered_application_protocols = NULL;
+    }
+
+    return filtered_application_protocols;
+}
+
+void
+sec_protocol_options_set_tls_server_name(sec_protocol_options_t options, const char *server_name)
+{
+    SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
+    SEC_PROTOCOL_OPTIONS_VALIDATE(server_name,);
+
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        free(content->server_name);
         content->server_name = strdup(server_name);
         return true;
     });
@@ -787,6 +849,20 @@ sec_protocol_options_set_peer_authentication_required(sec_protocol_options_t opt
     });
 }
 
+void
+sec_protocol_options_set_peer_authentication_optional(sec_protocol_options_t options, bool peer_authentication_optional) {
+    SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
+
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        content->peer_authentication_optional = peer_authentication_optional;
+        content->peer_authentication_override = true;
+        return true;
+    });
+}
+
 void
 sec_protocol_options_set_key_update_block(sec_protocol_options_t options, sec_protocol_key_update_t update_block, dispatch_queue_t update_queue)
 {
@@ -909,6 +985,31 @@ sec_protocol_options_set_tls_encryption_secret_update_block(sec_protocol_options
     });
 }
 
+void
+sec_protocol_options_set_tls_encryption_level_update_block(sec_protocol_options_t options, sec_protocol_tls_encryption_level_update_t update_block, dispatch_queue_t update_queue)
+{
+    SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
+    SEC_PROTOCOL_OPTIONS_VALIDATE(update_block,);
+    SEC_PROTOCOL_OPTIONS_VALIDATE(update_queue,);
+
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        if (content->tls_encryption_level_update_block != NULL) {
+            Block_release(content->tls_encryption_level_update_block);
+        }
+        if (content->tls_encryption_level_update_queue != NULL) {
+            dispatch_release(content->tls_encryption_level_update_queue);
+        }
+
+        content->tls_encryption_level_update_block = Block_copy(update_block);
+        content->tls_encryption_level_update_queue = update_queue;
+        dispatch_retain(content->tls_encryption_level_update_queue);
+        return true;
+    });
+}
+
 void
 sec_protocol_options_set_session_state(sec_protocol_options_t options, dispatch_data_t session_state)
 {
@@ -1131,21 +1232,7 @@ sec_protocol_options_tls_handshake_message_callback(sec_protocol_options_t optio
 }
 
 void
-sec_protocol_options_set_tls_SIKE503_exchange_enabled(sec_protocol_options_t options, bool tls_SIKE503_exchange_enabled)
-{
-    SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
-
-    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
-        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
-        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
-
-        content->tls_SIKE503_exchange_enabled = tls_SIKE503_exchange_enabled;
-        return true;
-    });
-}
-
-void
-sec_protocol_options_set_tls_HRSS_exchange_enabled(sec_protocol_options_t options, bool tls_HRSS_exchange_enabled)
+sec_protocol_options_set_eddsa_enabled(sec_protocol_options_t options, bool eddsa_enabled)
 {
     SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
 
@@ -1153,13 +1240,13 @@ sec_protocol_options_set_tls_HRSS_exchange_enabled(sec_protocol_options_t option
         sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
         SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
 
-        content->tls_HRSS_exchange_enabled = tls_HRSS_exchange_enabled;
+        content->eddsa_enabled = eddsa_enabled;
         return true;
     });
 }
 
 void
-sec_protocol_options_set_eddsa_enabled(sec_protocol_options_t options, bool eddsa_enabled)
+sec_protocol_options_set_tls_delegated_credentials_enabled(sec_protocol_options_t options, bool tls_delegated_credentials_enabled)
 {
     SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
 
@@ -1167,13 +1254,13 @@ sec_protocol_options_set_eddsa_enabled(sec_protocol_options_t options, bool edds
         sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
         SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
 
-        content->eddsa_enabled = eddsa_enabled;
+        content->tls_delegated_credentials_enabled = tls_delegated_credentials_enabled;
         return true;
     });
 }
 
 void
-sec_protocol_options_set_tls_delegated_credentials_enabled(sec_protocol_options_t options, bool tls_delegated_credentials_enabled)
+sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool tls_grease_enabled)
 {
     SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
 
@@ -1181,13 +1268,13 @@ sec_protocol_options_set_tls_delegated_credentials_enabled(sec_protocol_options_
         sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
         SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
 
-        content->tls_delegated_credentials_enabled = tls_delegated_credentials_enabled;
+        content->tls_grease_enabled = tls_grease_enabled;
         return true;
     });
 }
 
 void
-sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool tls_grease_enabled)
+sec_protocol_options_set_allow_unknown_alpn_protos(sec_protocol_options_t options, bool allow_unknown_alpn_protos)
 {
     SEC_PROTOCOL_OPTIONS_VALIDATE(options,);
 
@@ -1195,7 +1282,8 @@ sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool
         sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
         SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
 
-        content->tls_grease_enabled = tls_grease_enabled;
+        content->allow_unknown_alpn_protos = allow_unknown_alpn_protos;
+        content->allow_unknown_alpn_protos_override = true;
         return true;
     });
 }
@@ -2122,9 +2210,8 @@ static const char *_options_bool_keys[] = {
     SEC_PROTOCOL_OPTIONS_KEY_enable_renegotiation,
     SEC_PROTOCOL_OPTIONS_KEY_enable_early_data,
     SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_required,
+    SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_optional,
     SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled,
-    SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled,
-    SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled,
     SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled,
     SEC_PROTOCOL_OPTIONS_KEY_tls_delegated_credentials_enabled,
     SEC_PROTOCOL_OPTIONS_KEY_tls_grease_enabled,
@@ -2214,9 +2301,8 @@ _serialize_options(xpc_object_t dictionary, sec_protocol_options_content_t optio
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_renegotiation));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(enable_early_data));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(peer_authentication_required));
+    xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(peer_authentication_optional));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(certificate_compression_enabled));
-    xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_SIKE503_exchange_enabled));
-    xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_HRSS_exchange_enabled));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(eddsa_enabled));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_delegated_credentials_enabled));
     xpc_dictionary_set_bool(dictionary, EXPAND_PARAMETER(tls_grease_enabled));
@@ -2291,16 +2377,12 @@ static struct _options_bool_key_setter {
         .setter_pointer = sec_protocol_options_set_peer_authentication_required,
     },
     {
-        .key = SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled,
-        .setter_pointer = sec_protocol_options_set_tls_certificate_compression_enabled,
-    },
-    {
-        .key = SEC_PROTOCOL_OPTIONS_KEY_tls_SIKE503_exchange_enabled,
-        .setter_pointer = sec_protocol_options_set_tls_SIKE503_exchange_enabled,
+        .key = SEC_PROTOCOL_OPTIONS_KEY_peer_authentication_optional,
+        .setter_pointer = sec_protocol_options_set_peer_authentication_optional,
     },
     {
-        .key = SEC_PROTOCOL_OPTIONS_KEY_tls_HRSS_exchange_enabled,
-        .setter_pointer = sec_protocol_options_set_tls_HRSS_exchange_enabled,
+        .key = SEC_PROTOCOL_OPTIONS_KEY_certificate_compression_enabled,
+        .setter_pointer = sec_protocol_options_set_tls_certificate_compression_enabled,
     },
     {
         .key = SEC_PROTOCOL_OPTIONS_KEY_eddsa_enabled,
@@ -2711,3 +2793,17 @@ sec_protocol_options_apply_config(sec_protocol_options_t options, xpc_object_t c
 
     return _apply_config_options(options, config);
 }
+
+bool
+sec_protocol_options_set_tls_block_length_padding(sec_protocol_options_t options, sec_protocol_block_length_padding_t block_length_padding)
+{
+    SEC_PROTOCOL_METADATA_VALIDATE(options, false);
+
+    return sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        content->tls_block_length_padding = block_length_padding;
+        return true;
+    });
+}
index 6d8694d34b572eb2e6c458deabd6429b169b65c0..c57ebf5c4acf467ebf7710654c3fc9f3bc2f75d1 100644 (file)
@@ -143,11 +143,14 @@ sec_protocol_configuration_tls_required(sec_protocol_configuration_t config);
  * @param host
  *      A NULL-terminated C string containing the host endpoint to examine.
  *
+ * @param is_direct
+ *      A flag which indicates if the given hostname is local (direct).
+ *
  * @return True if connections to the endpoint require TLS, and false otherwise.
  */
 API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 bool
-sec_protocol_configuration_tls_required_for_host(sec_protocol_configuration_t config, const char *host);
+sec_protocol_configuration_tls_required_for_host(sec_protocol_configuration_t config, const char *host, bool is_direct);
 
 /*!
  * @function sec_protocol_configuration_tls_required_for_address
index a88816f1ffed0e35222132d482cd9d0782d40bc9..5f31e234a68fc4286071e7dd532a42a593dc150b 100644 (file)
@@ -11,7 +11,7 @@
 #import <Foundation/Foundation.h>
 
 #define MINIMUM_RSA_KEY_SIZE 2048
-#define MINIMUM_ECDSA_KEY_SIZE 2048
+#define MINIMUM_ECDSA_KEY_SIZE 256
 #define MINIMUM_HASH_ALGORITHM kSecSignatureHashAlgorithmSHA256
 #define MINIMUM_PROTOCOL kTLSProtocol12
 
@@ -187,7 +187,7 @@ sec_protocol_configuration_tls_required(sec_protocol_configuration_t config)
 }
 
 static bool
-sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configuration_t config, const char *host, bool parent_domain)
+sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configuration_t config, const char *host, bool parent_domain, bool is_direct)
 {
     xpc_object_t map = sec_protocol_configuration_get_map(config);
     if (map == nil) {
@@ -195,6 +195,11 @@ sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configura
         return true;
     }
 
+    if (is_direct && xpc_dictionary_get_bool(map, kAllowsLocalNetworking)) {
+        // Local domains do not require TLS if the kAllowsLocalNetworking flag is set.
+        return false;
+    }
+
     xpc_object_t domain_map = xpc_dictionary_get_dictionary(map, kExceptionDomains);
     if (domain_map == nil) {
         // Absent per-domain exceptions, use the default.
@@ -205,7 +210,7 @@ sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configura
     if (entry == nil) {
         const char *parent_host = _find_parent_domain(host);
         if (parent_host != NULL) {
-            return sec_protocol_configuration_tls_required_for_host_internal(config, parent_host, true);
+            return sec_protocol_configuration_tls_required_for_host_internal(config, parent_host, true, is_direct);
         }
         return sec_protocol_configuration_tls_required(config);
     }
@@ -222,9 +227,9 @@ sec_protocol_configuration_tls_required_for_host_internal(sec_protocol_configura
 }
 
 bool
-sec_protocol_configuration_tls_required_for_host(sec_protocol_configuration_t config, const char *host)
+sec_protocol_configuration_tls_required_for_host(sec_protocol_configuration_t config, const char *host, bool is_direct)
 {
-    return sec_protocol_configuration_tls_required_for_host_internal(config, host, false);
+    return sec_protocol_configuration_tls_required_for_host_internal(config, host, false, is_direct);
 }
 
 bool
@@ -332,17 +337,21 @@ sec_protocol_configuration_set_ats_overrides(sec_protocol_configuration_t config
 #define BOOLEAN_FOR_KEY(dictionary, key, value, default) \
     bool value = default; \
     { \
-        NSNumber *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
-        if (nsValue) { \
-            value = [nsValue boolValue]; \
+        if (dictionary[[[NSString alloc] initWithFormat:@"%s", key]]) { \
+            NSNumber *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
+            if (nsValue) { \
+                value = [nsValue boolValue]; \
+            } \
         } \
     }
 #define STRING_FOR_KEY(dictionary, key, value, default) \
     NSString *value = default; \
     { \
-        NSString *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
-        if (nsValue) { \
-            value = nsValue; \
+        if (dictionary[[[NSString alloc] initWithFormat:@"%s", key]]) { \
+            NSString *nsValue = [dictionary valueForKey:[[NSString alloc] initWithFormat:@"%s", key]]; \
+            if (nsValue) { \
+                value = nsValue; \
+            } \
         } \
     }
 
@@ -381,13 +390,12 @@ sec_protocol_configuration_set_ats_overrides(sec_protocol_configuration_t config
             *stop = YES;
         }
 
-        xpc_object_t entry_map = xpc_dictionary_create(NULL, NULL, 0);
-
-        BOOLEAN_FOR_KEY(entry_map, kExceptionAllowsInsecureHTTPLoads, allows_http, false);
-        BOOLEAN_FOR_KEY(entry_map, kIncludesSubdomains, includes_subdomains, false);
-        BOOLEAN_FOR_KEY(entry_map, kExceptionRequiresForwardSecrecy, requires_pfs, false);
-        STRING_FOR_KEY(entry_map, kExceptionMinimumTLSVersion, minimum_tls, @"TLSv1.2");
+        BOOLEAN_FOR_KEY(entry, kExceptionAllowsInsecureHTTPLoads, allows_http, false);
+        BOOLEAN_FOR_KEY(entry, kIncludesSubdomains, includes_subdomains, false);
+        BOOLEAN_FOR_KEY(entry, kExceptionRequiresForwardSecrecy, requires_pfs, false);
+        STRING_FOR_KEY(entry, kExceptionMinimumTLSVersion, minimum_tls, @"TLSv1.2");
 
+        xpc_object_t entry_map = xpc_dictionary_create(NULL, NULL, 0);
         xpc_dictionary_set_bool(entry_map, kIncludesSubdomains, includes_subdomains);
         xpc_dictionary_set_bool(entry_map, kExceptionAllowsInsecureHTTPLoads, allows_http);
         xpc_dictionary_set_bool(entry_map, kExceptionRequiresForwardSecrecy, requires_pfs);
index ef0b8aac534138c8adc9a6512ea941aab3d1f59d..56a593170ed602baef2695a4bff4bfa891815010 100644 (file)
@@ -350,16 +350,23 @@ protocol_string_to_version(const char *protocol)
     return (sec_protocol_options_t)_nw_protocol_create_options(mock_protocol_copy_definition());
 }
 
-- (void)testExampleFile:(NSURL *)path
+static bool
+isLocalTLD(NSString *host)
 {
-    NSDictionary *dictionary = [[NSDictionary alloc] init];
-    sec_protocol_configuration_builder_t builder = sec_protocol_configuration_builder_create((__bridge CFDictionaryRef)dictionary, true);
-    sec_protocol_configuration_t configuration = sec_protocol_configuration_create_with_builder(builder);
-    XCTAssertTrue(configuration != nil, @"failed to build configuration");
-    if (!configuration) {
-        return;
+    if ([host length] == 0) {
+        return false;
+    }
+    if ([host hasSuffix:@".local"] || [host hasSuffix:@".local."]) {
+        return true;
+    }
+    if ([host rangeOfString:@"."].location == NSNotFound) {
+        return true;
     }
+    return false;
+}
 
+- (void)testExampleFile:(NSURL *)path
+{
     NSData *exampleData = [[NSData alloc] initWithContentsOfURL:path];
     NSDictionary *exampleATS = [NSJSONSerialization JSONObjectWithData:exampleData options:kNilOptions error:nil];
     XCTAssertNotNil(exampleATS, @"Loading %@ failed", path);
@@ -367,6 +374,24 @@ protocol_string_to_version(const char *protocol)
         return;
     }
 
+    sec_protocol_configuration_builder_t builder = sec_protocol_configuration_builder_create((__bridge CFDictionaryRef)exampleATS, true);
+    sec_protocol_configuration_t configuration = sec_protocol_configuration_create_with_builder(builder);
+    XCTAssertTrue(configuration != nil, @"failed to build configuration");
+    if (!configuration) {
+        return;
+    }
+
+    __block bool allows_local_networking = false;
+    [exampleATS enumerateKeysAndObjectsUsingBlock:^(id _key, id _obj, BOOL *stop) {
+        NSString *key = (NSString *)_key;
+        if ([key isEqualToString:@"NSAllowsLocalNetworking"]) {
+            NSNumber *value = (NSNumber *)_obj;
+            if (value) {
+                allows_local_networking = [value boolValue];
+            }
+        }
+    }];
+
     [exampleATS enumerateKeysAndObjectsUsingBlock:^(id _key, id _obj, BOOL *stop) {
         NSString *key = (NSString *)_key;
         if ([key isEqualToString:@"NSExceptionDomains"]) {
@@ -415,7 +440,15 @@ protocol_string_to_version(const char *protocol)
                     }
                 });
 
-                XCTAssertTrue(allows_http != sec_protocol_configuration_tls_required_for_host(configuration, [domain cStringUsingEncoding:NSUTF8StringEncoding]));
+                bool is_direct = isLocalTLD(domain);
+                bool tls_required = sec_protocol_configuration_tls_required_for_host(configuration, [domain cStringUsingEncoding:NSUTF8StringEncoding], is_direct);
+                if (is_direct) {
+                    // If the hostname is direct, then we permit it if the NSAllowsLocalNetworking exception is set.
+                    XCTAssertTrue(allows_local_networking != tls_required);
+                } else {
+                    // Otherwise, we require TLS it the NSExceptionAllowsInsecureHTTPLoads flag is set.
+                    XCTAssertTrue(allows_http != tls_required);
+                }
             }];
         }
     }];
index 307ea379cf654c199c68722e53de13fb0b1b4b52..23736e4617d34f48dfa2cf702b8b7dbeb257c58e 100644 (file)
@@ -98,16 +98,6 @@ static const struct tls_ciphersuite_definition tls_ciphersuite_definitions[] = {
 static const size_t tls_ciphersuite_definitions_length = \
     sizeof(tls_ciphersuite_definitions) / sizeof(struct tls_ciphersuite_definition);
 
-// Remove macro definitions
-#undef CiphersuitesTLS13
-#undef CiphersuitesPFS
-#undef CiphersuitesNonPFS
-#undef CiphersuitesTLS10_3DES
-#undef CiphersuitesTLS10
-#undef CiphersuitesDHE
-#undef DefineTLSCiphersuiteGroupList
-#undef DefineTLSCiphersuiteDefinition
-
 const tls_ciphersuite_t *
 sec_protocol_helper_ciphersuite_group_to_ciphersuite_list(tls_ciphersuite_group_t group, size_t *list_count)
 {
index 97fd5c0e198ad0215a709645d34b00ab3adbe0e3..e97cfecbbc94139804c4e5588df16bbc7a074202 100644 (file)
 #define CiphersuitesPFS \
     TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \
     TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, \
+    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, \
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, \
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, \
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, \
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, \
     TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, \
     TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, \
-    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, \
-    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, \
-    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, \
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, \
     TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, \
     TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, \
-    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, \
-    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
 
 #define CiphersuitesNonPFS \
     TLS_RSA_WITH_AES_256_GCM_SHA384, \
@@ -115,18 +115,6 @@ sec_protocol_configuration_populate_secure_defaults(sec_protocol_configuration_t
 void
 sec_protocol_configuration_register_builtin_exceptions(sec_protocol_configuration_t configuration);
 
-bool
-sec_protocol_helper_ciphersuite_group_contains_ciphersuite(tls_ciphersuite_group_t group, tls_ciphersuite_t suite);
-
-tls_protocol_version_t
-sec_protocol_helper_ciphersuite_minimum_TLS_version(tls_ciphersuite_t ciphersuite);
-
-tls_protocol_version_t
-sec_protocol_helper_ciphersuite_maximum_TLS_version(tls_ciphersuite_t ciphersuite);
-
-const char *
-sec_protocol_helper_get_ciphersuite_name(tls_ciphersuite_t ciphersuite);
-
 const tls_key_exchange_group_t *
 sec_protocol_helper_tls_key_exchange_group_set_to_key_exchange_group_list(tls_key_exchange_group_set_t set, size_t *listSize);
 
index 3a67ddb3a80b7e5315b94dee5b5f2d786891afc4..5b7448d0e1a1d740f6004e60b0d7eec00114818f 100644 (file)
@@ -135,7 +135,7 @@ sec_protocol_metadata_get_negotiated_protocol_version(sec_protocol_metadata_t me
  *
  * @return A `tls_ciphersuite_t`.
  */
-API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0))
+API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 tls_ciphersuite_t
 sec_protocol_metadata_get_negotiated_tls_ciphersuite(sec_protocol_metadata_t metadata);
 
@@ -151,8 +151,7 @@ sec_protocol_metadata_get_negotiated_tls_ciphersuite(sec_protocol_metadata_t met
  * @return A SSLCipherSuite.
  */
 API_DEPRECATED_WITH_REPLACEMENT("sec_protocol_metadata_get_negotiated_tls_ciphersuite",
-                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0))
-API_UNAVAILABLE(iosmac)
+                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0), macCatalyst(13.0, 13.0))
 SSLCipherSuite
 sec_protocol_metadata_get_negotiated_ciphersuite(sec_protocol_metadata_t metadata);
 
index 616dac53779c11a3e819d0cd9a557d87e1b3e201..3d3deac8cfb630fa55a89c701cc4723b8cd2d1c5 100644 (file)
@@ -129,8 +129,7 @@ sec_protocol_options_append_tls_ciphersuite(sec_protocol_options_t options, tls_
  * @param ciphersuite
  *      A SSLCipherSuite value.
  */
-API_DEPRECATED("Use sec_protocol_options_append_tls_ciphersuite", macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0))
-API_UNAVAILABLE(iosmac)
+API_DEPRECATED("Use sec_protocol_options_append_tls_ciphersuite", macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0), macCatalyst(13.0, 13.0))
 void
 sec_protocol_options_add_tls_ciphersuite(sec_protocol_options_t options, SSLCipherSuite ciphersuite);
 
@@ -162,8 +161,7 @@ sec_protocol_options_append_tls_ciphersuite_group(sec_protocol_options_t options
  * @param group
  *      A SSLCipherSuiteGroup value.
  */
-API_DEPRECATED("Use sec_protocol_options_append_tls_ciphersuite_group", macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0))
-API_UNAVAILABLE(iosmac)
+API_DEPRECATED("Use sec_protocol_options_append_tls_ciphersuite_group", macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0), macCatalyst(13.0, 13.0))
 void
 sec_protocol_options_add_tls_ciphersuite_group(sec_protocol_options_t options, SSLCiphersuiteGroup group);
 
@@ -180,8 +178,7 @@ sec_protocol_options_add_tls_ciphersuite_group(sec_protocol_options_t options, S
  *      A SSLProtocol enum value.
  */
 API_DEPRECATED_WITH_REPLACEMENT("sec_protocol_options_set_min_tls_protocol_version",
-                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0))
-API_UNAVAILABLE(iosmac)
+                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0), macCatalyst(13.0, 13.0))
 void
 sec_protocol_options_set_tls_min_version(sec_protocol_options_t options, SSLProtocol version);
 
@@ -238,8 +235,7 @@ sec_protocol_options_get_default_min_dtls_protocol_version(void);
  *      A SSLProtocol enum value.
  */
 API_DEPRECATED_WITH_REPLACEMENT("sec_protocol_options_set_max_tls_protocol_version",
-                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0))
-API_UNAVAILABLE(iosmac)
+                                macos(10.14, 10.15), ios(12.0, 13.0), watchos(5.0, 6.0), tvos(12.0, 13.0), macCatalyst(13.0, 13.0))
 void
 sec_protocol_options_set_tls_max_version(sec_protocol_options_t options, SSLProtocol version);
 
@@ -303,14 +299,14 @@ sec_protocol_options_add_tls_application_protocol(sec_protocol_options_t options
  * @function sec_protocol_options_set_tls_server_name
  *
  * @abstract
- *      Set the server (domain) name to be used in the TLS SNI. This will override
+ *      Set the server name to be used when verifying the peer's certificate. This will override
  *      the server name obtained from the endpoint.
  *
  * @param options
  *      A `sec_protocol_options_t` instance.
  *
  * @param server_name
- *      A NULL-terminated string carrying the server (domain) name.
+ *      A NULL-terminated string carrying the server name.
  */
 API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0))
 void
@@ -553,6 +549,26 @@ API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0))
 void
 sec_protocol_options_set_peer_authentication_required(sec_protocol_options_t options, bool peer_authentication_required);
 
+/*!
+ * @function sec_protocol_options_set_peer_authentication_optional
+ *
+ * @abstract
+ *      When this is enabled, the endpoint requests the peer certificate, but if none is provided, the
+ *      endpoint still proceeds with the connection. Default false for servers; always false for clients (this
+ *      function is a no-op for clients). If peer_authentication_required is set to true via
+ *      sec_protocol_options_set_peer_authentication_required(), peer_authentication_optional will be disregarded
+ *      and the peer certificate will be required.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param peer_authentication_optional
+ *      Flag to enable or disable requested peer authentication.
+ */
+SPI_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+void
+sec_protocol_options_set_peer_authentication_optional(sec_protocol_options_t options, bool peer_authentication_optional);
+
 #ifdef __BLOCKS__
 
 /*!
index 25395fecaa4daaa4a7da637facd53bcde2a7b30e..b3f1c28f08707dfd5a0d039f7eda6130e92f2ac7 100644 (file)
@@ -231,6 +231,59 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 void
 sec_protocol_options_set_quic_transport_parameters(sec_protocol_options_t options, dispatch_data_t transport_parameters);
 
+/*!
+ * @enum sec_protocol_transport_t
+ *
+ * @abstract An enumeration of the different transport protocols that can have specific security options.
+ */
+typedef enum {
+    sec_protocol_transport_any = 0,
+    sec_protocol_transport_tcp,
+    sec_protocol_transport_quic,
+} sec_protocol_transport_t;
+
+#define SEC_PROTOCOL_HAS_TRANSPORT_SPECIFIC_ALPN 1
+
+/*!
+ * @function sec_protocol_options_add_transport_specific_application_protocol
+ *
+ * @abstract
+ *      Add an application protocol supported by clients of this protocol instance, specific
+ *      to a transport protocol.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param application_protocol
+ *      A NULL-terminated string defining the application protocol.
+ *
+ * @param specific_transport
+ *      A specific transport to which to bind the application protocol.
+ */
+API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+void
+sec_protocol_options_add_transport_specific_application_protocol(sec_protocol_options_t options, const char *application_protocol, sec_protocol_transport_t specific_transport);
+
+/*!
+ * @function sec_protocol_options_copy_transport_specific_application_protocol
+ *
+ * @abstract
+ *      Return the application protocols configured by clients of this protocol instance, specific
+ *      to a transport protocol if applicable.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param specific_transport
+ *      A specific transport to which to bind the application protocol.
+ *
+ * @return An `xpc_object_t` instance carrying an array of application protocol strings, or nil.
+ */
+#define SEC_PROTOCOL_HAS_TRANSPORT_SPECIFIC_ALPN_GETTER 1 /* rdar://problem/63987477 */
+SPI_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+SEC_RETURNS_RETAINED __nullable xpc_object_t
+sec_protocol_options_copy_transport_specific_application_protocol(sec_protocol_options_t options, sec_protocol_transport_t specific_transport);
+
 /*!
  * @enum sec_protocol_tls_encryption_level_t
  *
@@ -282,6 +335,43 @@ sec_protocol_options_set_tls_encryption_secret_update_block(sec_protocol_options
                                                             sec_protocol_tls_encryption_secret_update_t update_block,
                                                             dispatch_queue_t update_queue);
 
+/*!
+ * @block sec_protocol_tls_encryption_level_update_t
+ *
+ * @abstract
+ *      Block to be invoked when the encryption level is updated.
+ *
+ * @param level
+ *      The new `sec_protocol_tls_encryption_level_t`.
+ *
+ * @param is_write
+ *      True if this is a write level and false if it's a read.
+ *
+ */
+typedef void (^sec_protocol_tls_encryption_level_update_t)(sec_protocol_tls_encryption_level_t level, bool is_write);
+
+/*!
+ * @function sec_protocol_options_set_tls_encryption_level_update_block
+ *
+ * @abstract
+ *      Set the TLS encryption level update block. It is invoked whenever the encryption level is updated.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param update_block
+ *      A `sec_protocol_tls_encryption_level_update_t` instance.
+ *
+ * @params update_queue
+ *      A `dispatch_queue_t` on which the update block should be called.
+ */
+#define SEC_PROTOCOL_HAS_TLS_ENCRYPTION_LEVEL_UPDATE_BLOCK 1 /* rdar://problem/63986462 */
+SPI_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+void
+sec_protocol_options_set_tls_encryption_level_update_block(sec_protocol_options_t options,
+                                                            sec_protocol_tls_encryption_level_update_t update_block,
+                                                            dispatch_queue_t update_queue);
+
 /*!
  * @block sec_protocol_private_key_complete_t
  *
@@ -468,45 +558,6 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 void
 sec_protocol_options_add_tls_key_exchange_group_set(sec_protocol_options_t options, SSLKeyExchangeGroupSet set);
 
-/*!
- * @function sec_protocol_options_set_tls_SIKE503_exchange_enabled
- *
- * @abstract
- *      Enable SIKE using P503 for TLS 1.3 key exchange.
- *
- *      DO NOT DEPEND ON THIS SPI. IT IS FOR EXPERIMENTAL PURPOSES AND SUBJECT TO REMOVAL WITHOUT ADVANCE NOTICE.
- *      BUILD BREAKAGE ISSUES WILL BE SENT TO THE CALLING PROJECT.
- *
- * @param options
- *      A `sec_protocol_options_t` instance.
- *
- * @param tls_SIKE503_exchange_enabled
- *      Flag to enable SIKE with P503.
- */
-#define SEC_PROTOCOL_HAS_PQ_TLS_HANDLES 1
-API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
-void
-sec_protocol_options_set_tls_SIKE503_exchange_enabled(sec_protocol_options_t options, bool tls_SIKE503_exchange_enabled);
-
-/*!
- * @function sec_protocol_options_set_tls_HRSS_exchange_enabled
- *
- * @abstract
- *      Enable HRSS for TLS 1.3 key exchange.
- *
- *      DO NOT DEPEND ON THIS SPI. IT IS FOR EXPERIMENTAL PURPOSES AND SUBJECT TO REMOVAL WITHOUT ADVANCE NOTICE.
- *      BUILD BREAKAGE ISSUES WILL BE SENT TO THE CALLING PROJECT.
- *
- * @param options
- *      A `sec_protocol_options_t` instance.
- *
- * @param tls_HRSS_exchange_enabled
- *      Flag to enable HRSS.
- */
-API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
-void
-sec_protocol_options_set_tls_HRSS_exchange_enabled(sec_protocol_options_t options, bool tls_HRSS_exchange_enabled);
-
 /*!
  * @function sec_protocol_options_set_eddsa_enabled
  *
@@ -581,6 +632,23 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 void
 sec_protocol_options_set_tls_grease_enabled(sec_protocol_options_t options, bool tls_grease_enabled);
 
+/*!
+ * @function sec_protocol_options_set_allow_unknown_alpn_protos
+ *
+ * @abstract
+ *      Configure clients to accept server ALPN values they did not advertise.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param allow_unknown_alpn_protos
+ *      Flag to enable or disable the use of unknown ALPN values.
+ */
+#define SEC_PROTOCOL_HAS_ALLOW_UNKNOWN_ALPN_PROTOS_SETTER 1 /* rdar://problem/64449512 */
+SPI_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+void
+sec_protocol_options_set_allow_unknown_alpn_protos(sec_protocol_options_t options, bool allow_unknown_alpn_protos);
+
 /*!
  * @function sec_protocol_options_set_experiment_identifier
  *
@@ -1171,8 +1239,96 @@ API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
 const tls_ciphersuite_t * __nullable
 sec_protocol_helper_ciphersuite_group_to_ciphersuite_list(tls_ciphersuite_group_t group, size_t *list_count);
 
+typedef CF_ENUM(uint16_t, sec_protocol_block_length_padding_t) {
+    SEC_PROTOCOL_BLOCK_LENGTH_PADDING_NONE = 0,
+    SEC_PROTOCOL_BLOCK_LENGTH_PADDING_DEFAULT = 16,
+};
+
+/*!
+ * @function sec_protocol_options_set_tls_block_length_padding
+ *
+ * @abstract
+ *      Pad TLS messages to a multiple of the specified block length. By default, padding is disabled.
+ *
+ * @param options
+ *      A `sec_protocol_options_t` instance.
+ *
+ * @param block_length_padding
+ *      A sec_protocol_block_length_padding_t variable specifying the block length padding. Setting the block length padding to 0 disables padding.
+ *
+ * @return True if the padding policy has been successfully set, false otherwise.
+ */
+API_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
+bool
+sec_protocol_options_set_tls_block_length_padding(sec_protocol_options_t options, sec_protocol_block_length_padding_t block_length_padding);
+
+/*!
+ * @function sec_protocol_helper_ciphersuite_group_contains_ciphersuite
+ *
+ * @abstract
+ *      This function is exposed for testing purposes only. It MUST NOT be called by clients.
+ *
+ * @param group
+ *      A `tls_ciphersuite_group_t` instance.
+ *
+ * @param suite
+ *      A `tls_ciphersuite_t` instance.
+ *
+ * @return True if the ciphersuite group contains the given ciphersuite, false otherwise.
+*/
+API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+bool
+sec_protocol_helper_ciphersuite_group_contains_ciphersuite(tls_ciphersuite_group_t group, tls_ciphersuite_t suite);
+
+/*!
+ * @function sec_protocol_helper_ciphersuite_minimum_TLS_version
+ *
+ * @abstract
+ *      This function is exposed for testing purposes only. It MUST NOT be called by clients.
+ *
+ * @param ciphersuite
+ *      A `tls_ciphersuite_t` instance.
+ *
+ * @return The `tls_protocol_version_t` pertaining to the minimum TLS version designated for the given ciphersuite.
+*/
+API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+tls_protocol_version_t
+sec_protocol_helper_ciphersuite_minimum_TLS_version(tls_ciphersuite_t ciphersuite);
+
+/*!
+ * @function sec_protocol_helper_ciphersuite_maximum_TLS_version
+ *
+ * @abstract
+ *      This function is exposed for testing purposes only. It MUST NOT be called by clients.
+ *
+ * @param ciphersuite
+ *      A `tls_ciphersuite_t` instance.
+ *
+ * @return The `tls_protocol_version_t` pertaining to the maximum TLS version designated for the given ciphersuite.
+*/
+API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+tls_protocol_version_t
+sec_protocol_helper_ciphersuite_maximum_TLS_version(tls_ciphersuite_t ciphersuite);
+
+/*!
+ * @function sec_protocol_helper_get_ciphersuite_name
+ *
+ * @abstract
+ *      This function is exposed for testing purposes only. It MUST NOT be called by clients.
+ *
+ * @param ciphersuite
+ *      A `tls_ciphersuite_t` instance.
+ *
+ * @return A string representation of the given ciphersuite, or NULL if it does not exist.
+*/
+API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0))
+const char * __nullable
+sec_protocol_helper_get_ciphersuite_name(tls_ciphersuite_t ciphersuite);
+
 #define SEC_PROTOCOL_HAS_MULTI_PSK_SUPPORT 1
 
+#define SEC_PROTOCOL_HAS_PEER_AUTHENTICATION_OPTIONAL 1
+
 struct sec_protocol_options_content {
     SSLProtocol min_version;
     SSLProtocol max_version;
@@ -1195,6 +1351,8 @@ struct sec_protocol_options_content {
     dispatch_data_t quic_transport_parameters;
     sec_protocol_tls_encryption_secret_update_t tls_secret_update_block;
     dispatch_queue_t tls_secret_update_queue;
+    sec_protocol_tls_encryption_level_update_t tls_encryption_level_update_block;
+    dispatch_queue_t tls_encryption_level_update_queue;
     sec_protocol_session_update_t session_update_block;
     dispatch_queue_t session_update_queue;
     dispatch_data_t session_state;
@@ -1246,13 +1404,16 @@ struct sec_protocol_options_content {
     unsigned enable_early_data : 1;
     unsigned enable_early_data_override : 1;
     unsigned peer_authentication_required : 1;
+    unsigned peer_authentication_optional : 1;
     unsigned peer_authentication_override : 1;
     unsigned certificate_compression_enabled : 1;
-    unsigned tls_SIKE503_exchange_enabled : 1;
-    unsigned tls_HRSS_exchange_enabled : 1;
     unsigned eddsa_enabled : 1;
     unsigned tls_delegated_credentials_enabled : 1;
     unsigned tls_grease_enabled : 1;
+    unsigned allow_unknown_alpn_protos : 1;
+    unsigned allow_unknown_alpn_protos_override : 1;
+
+    sec_protocol_block_length_padding_t tls_block_length_padding;
 };
 
 struct sec_protocol_metadata_content {
index 4ae69401e2bf56d4344fcaa131deb838feb8de20..bbfdc9c752adcc918d49674ce90904202c272248 100644 (file)
@@ -682,6 +682,24 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     });
 }
 
+- (void)test_sec_protocol_options_set_tls_encryption_level_update_block {
+    void (^update_block)(sec_protocol_tls_encryption_level_t, bool) = ^(__unused sec_protocol_tls_encryption_level_t level, __unused bool is_write) {
+        // pass
+    };
+
+    dispatch_queue_t update_queue = dispatch_queue_create("test_sec_protocol_options_set_tls_encryption_level_update_block_queue", DISPATCH_QUEUE_SERIAL);
+
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+    sec_protocol_options_set_tls_encryption_level_update_block(options, update_block, update_queue);
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+        XCTAssertTrue(content->tls_encryption_level_update_block == update_block);
+        XCTAssertTrue(content->tls_encryption_level_update_queue != nil);
+        return false;
+    });
+}
+
 - (void)test_sec_protocol_options_set_local_certificates {
     sec_protocol_options_t options = [self create_sec_protocol_options];
 
@@ -730,6 +748,30 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     });
 }
 
+- (void)test_sec_protocol_options_set_peer_authentication_required {
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+
+    sec_protocol_options_set_peer_authentication_required(options, true);
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+        XCTAssertTrue(content->peer_authentication_required);
+        return true;
+    });
+}
+
+- (void)test_sec_protocol_options_set_peer_authentication_optional {
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+
+    sec_protocol_options_set_peer_authentication_optional(options, true);
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+        XCTAssertTrue(content->peer_authentication_optional);
+        return true;
+    });
+}
+
 - (void)test_sec_protocol_options_are_equal {
     sec_protocol_options_t optionsA = [self create_sec_protocol_options];
     sec_protocol_options_t optionsB = [self create_sec_protocol_options];
@@ -860,23 +902,95 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
 
     const char *application_protocolA = "h2";
-    const char *application_protocolB = "h3";
     sec_protocol_options_add_tls_application_protocol(optionsA, application_protocolA);
     XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
-    sec_protocol_options_add_tls_application_protocol(optionsB, application_protocolB);
+    sec_protocol_options_add_tls_application_protocol(optionsB, application_protocolA);
+    XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
+
+    const char *application_protocolB = "h3";
+       sec_protocol_options_add_transport_specific_application_protocol(optionsA, application_protocolB,
+                                                                                                                                        sec_protocol_transport_quic);
     XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
+       sec_protocol_options_add_transport_specific_application_protocol(optionsB, application_protocolB,
+                                                                                                                                        sec_protocol_transport_quic);
+    XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
+
 
     sec_protocol_options_append_tls_ciphersuite(optionsB, 7331);
     XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
 }
 
+- (void)test_sec_protocol_options_copy_transport_specific_application_protocol {
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+
+    const char *application_protocol_dummy = "dummy";
+    const char *application_protocol_h2 = "h2";
+    const char *application_protocol_h3 = "h3";
+
+    sec_protocol_options_add_transport_specific_application_protocol(options, application_protocol_h2, sec_protocol_transport_tcp);
+    xpc_object_t protocols = sec_protocol_options_copy_transport_specific_application_protocol(options, sec_protocol_transport_quic);
+    XCTAssertFalse(protocols != NULL);
+    if (protocols != NULL) {
+        return;
+    }
+
+    sec_protocol_options_add_tls_application_protocol(options, application_protocol_dummy);
+    sec_protocol_options_add_transport_specific_application_protocol(options, application_protocol_h3, sec_protocol_transport_quic);
+
+    for (sec_protocol_transport_t t = sec_protocol_transport_any; t <= sec_protocol_transport_quic; t++) {
+        protocols = sec_protocol_options_copy_transport_specific_application_protocol(options, t);
+        XCTAssertFalse(protocols == NULL);
+        if (protocols == NULL) {
+            return;
+        }
+
+        const char *application_protocols_for_any[]  = { application_protocol_h2, application_protocol_dummy, application_protocol_h3, };
+        // application_protocols_for_tcp includes application_protocol_dummy because "dummy" isn't tied to any transport.
+        const char *application_protocols_for_tcp[]  = { application_protocol_h2, application_protocol_dummy, };
+        const char *application_protocols_for_quic[] = { application_protocol_dummy, application_protocol_h3, };
+
+        size_t count_of_application_protocols_for_transport[] = {
+            [sec_protocol_transport_any]  = sizeof(application_protocols_for_any)/sizeof(application_protocols_for_any[0]),
+            [sec_protocol_transport_tcp]  = sizeof(application_protocols_for_tcp)/sizeof(application_protocols_for_tcp[0]),
+            [sec_protocol_transport_quic] = sizeof(application_protocols_for_quic)/sizeof(application_protocols_for_quic[0]),
+        };
+
+        XCTAssertFalse(xpc_get_type(protocols) != XPC_TYPE_ARRAY);
+        if (xpc_get_type(protocols) != XPC_TYPE_ARRAY) {
+            return;
+        }
+
+        size_t protocols_count = xpc_array_get_count(protocols);
+        XCTAssertFalse(protocols_count != count_of_application_protocols_for_transport[t]);
+        if (protocols_count != count_of_application_protocols_for_transport[t]) {
+            return;
+        }
+
+        const char **application_protocols_for_transport[] = {
+            [sec_protocol_transport_any]  = application_protocols_for_any,
+            [sec_protocol_transport_tcp]  = application_protocols_for_tcp,
+            [sec_protocol_transport_quic] = application_protocols_for_quic,
+        };
+
+        for (size_t i = 0; i < protocols_count; i++) {
+            const char *protocol_name = xpc_array_get_string(protocols, i);
+            const char *expected_protocol_name = application_protocols_for_transport[t][i];
+            bool protocol_match = (strcmp(protocol_name, expected_protocol_name) == 0);
+
+            XCTAssertFalse(protocol_match == false);
+            if (protocol_match == false) {
+                return;
+            }
+        }
+    }
+}
+
 - (void)test_sec_protocol_options_set_tls_server_name {
     sec_protocol_options_t optionsA = [self create_sec_protocol_options];
     sec_protocol_options_t optionsB = [self create_sec_protocol_options];
 
     const char *server_nameA = "apple.com";
-    const char *server_nameB = "127.0.0.1";
-    const char *server_nameC = "example.com";
+    const char *server_nameB = "example.com";
 
     /*
      * Empty options should be equal.
@@ -897,19 +1011,11 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     sec_protocol_options_set_tls_server_name(optionsB, server_nameA);
     XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
 
-    /*
-     * Try to set the name to nameB in optionsB.
-     * It should fail since nameB is invalid.
-     * Options A, B should still be equal.
-     */
-    sec_protocol_options_set_tls_server_name(optionsB, server_nameB);
-    XCTAssertTrue(sec_protocol_options_are_equal(optionsA, optionsB));
-
     /*
      * Change the current name in B.
      * Comparison should fail.
      */
-    sec_protocol_options_set_tls_server_name(optionsB, server_nameC);
+    sec_protocol_options_set_tls_server_name(optionsB, server_nameB);
     XCTAssertFalse(sec_protocol_options_are_equal(optionsA, optionsB));
 }
 
@@ -1082,6 +1188,24 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     XCTAssertTrue(accessed, @"Expected sec_protocol_metadata_access_pre_shared_keys to traverse PSK list");
 }
 
+- (void)test_sec_protocol_options_set_tls_block_length_padding {
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+
+    sec_protocol_block_length_padding_t expected_block_length_padding = SEC_PROTOCOL_BLOCK_LENGTH_PADDING_DEFAULT;
+    sec_protocol_options_set_tls_block_length_padding(options, expected_block_length_padding);
+
+    __block sec_protocol_block_length_padding_t current_block_length_padding = SEC_PROTOCOL_BLOCK_LENGTH_PADDING_NONE;
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+
+        current_block_length_padding = content->tls_block_length_padding;
+        return true;
+    });
+
+    XCTAssertTrue(current_block_length_padding == expected_block_length_padding);
+}
+
 - (void)test_sec_protocol_experiment_identifier {
     sec_protocol_options_t options = [self create_sec_protocol_options];
 
@@ -1152,4 +1276,24 @@ _sec_protocol_test_metadata_session_exporter(void *handle)
     XCTAssertTrue(memcmp(uuid, copied_metadata, sizeof(copied_metadata)) == 0);
 }
 
+- (void)test_sec_protocol_options_set_allow_unknown_alpn_protos {
+    sec_protocol_options_t options = [self create_sec_protocol_options];
+
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+        XCTAssertFalse(content->allow_unknown_alpn_protos_override);
+        return true;
+    });
+
+    sec_protocol_options_set_allow_unknown_alpn_protos(options, true);
+    (void)sec_protocol_options_access_handle(options, ^bool(void *handle) {
+        sec_protocol_options_content_t content = (sec_protocol_options_content_t)handle;
+        SEC_PROTOCOL_OPTIONS_VALIDATE(content, false);
+        XCTAssertTrue(content->allow_unknown_alpn_protos);
+        XCTAssertTrue(content->allow_unknown_alpn_protos_override);
+        return true;
+    });
+}
+
 @end
index b5258fffc6e79448a03223e0000fc46410111d6b..558bb46a20ed7eb88ec6c65d667c784669cc2bf2 100644 (file)
@@ -84,11 +84,11 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_array,
 
 - (instancetype)init
 {
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->xpc_array = xpc_array_create(NULL, 0);
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-    self->xpc_array = xpc_array_create(NULL, 0);
     return self;
 }
 
@@ -166,11 +166,11 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_identity,
         return SEC_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-    self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
     return self;
 }
 
@@ -180,12 +180,12 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_identity,
         return SEC_NIL_BAD_INPUT;
     }
     
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
+        self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates));
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-    self->identity = __DECONST(SecIdentityRef, CFRetainSafe(_identity));
-    self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates));
     
     return self;
 }
@@ -202,16 +202,14 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_identity,
         return SEC_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates));
+        self->sign_block = sign;
+        self->decrypt_block = decrypt;
+        self->operation_queue = queue;
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-
-    self->certs = __DECONST(CFArrayRef, CFRetainSafe(certificates));
-    self->sign_block = sign;
-    self->decrypt_block = decrypt;
-    self->operation_queue = queue;
-
     return self;
 }
 
@@ -354,11 +352,11 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_certificate,
         return SEC_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->certificate = __DECONST(SecCertificateRef, CFRetainSafe(_certificate));
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-    self->certificate = __DECONST(SecCertificateRef, CFRetainSafe(_certificate));
     return self;
 }
 
@@ -403,11 +401,11 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_trust,
         return SEC_NIL_BAD_INPUT;
     }
 
-    self = [super init];
-    if (self == nil) {
+    if ((self = [super init])) {
+        self->trust = __DECONST(SecTrustRef, CFRetainSafe(_trust));
+    } else {
         return SEC_NIL_OUT_OF_MEMORY;
     }
-    self->trust = __DECONST(SecTrustRef, CFRetainSafe(_trust));
     return self;
 }
 
@@ -461,9 +459,9 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration_builder,
 
 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration_builder)
 
-- (id)init {
-    self = [super init];
-    if (self) {
+- (id)init
+{
+    if (self = [super init]) {
         CFBundleRef bundle = CFBundleGetMainBundle();
         if (bundle != NULL) {
             CFTypeRef rawATS = CFBundleGetValueForInfoDictionaryKey(bundle, CFSTR(kATSInfoKey));
@@ -475,9 +473,10 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration_builder,
     return self;
 }
 
-- (id)initWithDictionary:(CFDictionaryRef)dict andInternalFlag:(bool)flag {
-    self = [super init];
-    if (self) {
+- (id)initWithDictionary:(CFDictionaryRef)dict
+         andInternalFlag:(bool)flag
+{
+    if ((self = [super init])) {
         self->dictionary = dict;
         CFRetainSafe(dict);
         self->is_apple = flag;
@@ -519,8 +518,7 @@ SEC_OBJECT_IMPL_INTERNAL_OBJC(sec_protocol_configuration,
 @implementation SEC_CONCRETE_CLASS_NAME(sec_protocol_configuration)
 
 - (id)init {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         self->dictionary = xpc_dictionary_create(NULL, NULL, 0);
     }
     return self;
index aa62c08e7c748c8a24390d33dd4e59b50d8f22cf..1930362b075c10269ab8d6aad06b6b369c3cf0a4 100644 (file)
@@ -2,7 +2,7 @@
        "NSAllowsArbitraryLoads": false,
        "NSAllowsArbitraryLoadsForMedia": false,
        "NSAllowsArbitraryLoadsInWebContent": false,
-       "NSAllowsLocalNetworking": false,
+       "NSAllowsLocalNetworking": true,
        "NSExceptionDomains": {
                "apple.com": {
                        "NSIncludesSubdomains": true,
@@ -45,6 +45,8 @@
                        "NSExceptionAllowsInsecureHTTPLoads": true,
                        "NSExceptionMinimumTLSVersion": "TLSv1.2",
                        "NSExceptionRequiresForwardSecrecy": false
-               }
+        },
+        "example.local": {
+        }
        }
-}
\ No newline at end of file
+}
index c635aaf3c1203e3237369b913854e077ecf8e15e..846bd4e3f1f32ec9c7ce68a692d49f26eda02d85 100644 (file)
@@ -18,5 +18,7 @@
        <array>
                <string>com.apple.security.sos</string>
        </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
index d9ca668f2afbd4974971985871034c2a68baa310..403823d95cbcada55855cfbfef31b8d5c73649d5 100644 (file)
        <true/>
        <key>com.apple.private.security.no-sandbox</key>
        <true/>
+       <key>com.apple.security.app-sandbox</key>
+       <false/>
        <key>keychain-cloud-circle</key>
        <true/>
        <key>com.apple.keystore.access-keychain-keys</key>
        <true/>
        <key>com.apple.keystore.device</key>
        <true/>
-       <key>com.apple.private.applecredentialmanager.allow</key>
+       <key>com.apple.keystore.lockassertion</key>
        <true/>
        <key>restore-keychain</key>
        <true/>
@@ -51,5 +53,7 @@
                <string>com.apple.ProtectedCloudStorage</string>
                <string>com.apple.security.ckks</string>
        </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
 </dict>
 </plist>
index 1a736d23bbe089768140e0bac12cce06925a7519..488deaba6347c73a8de8e7696e6258010cbdde09 100644 (file)
@@ -90,7 +90,7 @@
     _connection = [[SFKeychainServerFakeConnection alloc] init];
 
     self.keychainPartialMock = OCMPartialMock(_keychain);
-    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
+    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataWithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
 
     [_keychain _registerItemTypeForTesting:[TestItemType itemType]];
 }
     XCTAssertNotNil(keychain, @"should have been able to create a keychain instance");
 
     self.keychainPartialMock = OCMPartialMock(keychain);
-    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
+    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataWithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
 
     SecCDKeychainAccessControlEntity* owner = [SecCDKeychainAccessControlEntity accessControlEntityWithType:SecCDKeychainAccessControlEntityTypeAccessGroup stringRepresentation:@"com.apple.token"];
 
index a68d4f2d3264a5736a47624bf72e63cdf5c6a77a..f2a61b5f3085a0ab223d7210a7f9bc3bfb36eebb 100644 (file)
@@ -27,6 +27,7 @@
 #import "CKKS.h"
 #import "SecDbKeychainItemV7.h"
 #import "SecItemPriv.h"
+#include "SecItemInternal.h"
 #import "SecItemServer.h"
 #import "spi.h"
 #import "SecDbKeychainSerializedItemV7.h"
@@ -41,8 +42,8 @@
 #include <utilities/SecDb.h>
 #include <sys/stat.h>
 #include <utilities/SecFileLocations.h>
-
-void* testlist = NULL;
+#include "der_plist.h"
+#import "SecItemRateLimit_tests.h"
 
 #if USE_KEYSTORE
 
@@ -54,8 +55,6 @@ void* testlist = NULL;
 + (void)setUp
 {
     [super setUp];
-    SecCKKSDisable();
-    securityd_init(NULL);
 }
 
 - (NSString*)nameOfTest
@@ -152,6 +151,52 @@ void* testlist = NULL;
     XCTAssertEqual(errSecParam, SecItemDelete((CFDictionaryRef)attrs));
 }
 
+- (BOOL)passInternalAttributeToKeychainAPIsWithKey:(id)key value:(id)value {
+     NSDictionary* badquery = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+        key : value,
+    };
+    NSDictionary* badupdate = @{key : value};
+
+    NSDictionary* okquery = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    };
+    NSDictionary* okupdate = @{(id)kSecAttrService : @"DifferentService"};
+
+    if (SecItemAdd((__bridge CFDictionaryRef)badquery, NULL) != errSecParam) {
+        XCTFail("SecItemAdd did not return errSecParam");
+        return NO;
+    }
+    if (SecItemCopyMatching((__bridge CFDictionaryRef)badquery, NULL) != errSecParam) {
+        XCTFail("SecItemCopyMatching did not return errSecParam");
+        return NO;
+    }
+    if (SecItemUpdate((__bridge CFDictionaryRef)badquery, (__bridge CFDictionaryRef)okupdate) != errSecParam) {
+        XCTFail("SecItemUpdate with bad query did not return errSecParam");
+        return NO;
+    }
+    if (SecItemUpdate((__bridge CFDictionaryRef)okquery, (__bridge CFDictionaryRef)badupdate) != errSecParam) {
+        XCTFail("SecItemUpdate with bad update did not return errSecParam");
+        return NO;
+    }
+    if (SecItemDelete((__bridge CFDictionaryRef)badquery) != errSecParam) {
+        XCTFail("SecItemDelete did not return errSecParam");
+        return NO;
+    }
+    return YES;
+}
+
+// Expand this, rdar://problem/59297616
+- (void)testNotAllowedToPassInternalAttributes {
+    XCTAssert([self passInternalAttributeToKeychainAPIsWithKey:(__bridge NSString*)kSecAttrAppClipItem value:@YES], @"Expect errSecParam for 'clip' attribute");
+}
+
 #pragma mark - Corruption Tests
 
 const uint8_t keychain_data[] = {
@@ -280,6 +325,313 @@ static void SecDbTestCorruptionHandler(void)
     }
 }
 
+- (void)testInetBinaryFields {
+    NSData* note = [@"OBVIOUS_NOTES_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData* history = [@"OBVIOUS_HISTORY_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData* client0 = [@"OBVIOUS_CLIENT0_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData* client1 = [@"OBVIOUS_CLIENT1_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData* client2 = [@"OBVIOUS_CLIENT2_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+    NSData* client3 = [@"OBVIOUS_CLIENT3_DATA" dataUsingEncoding:NSUTF8StringEncoding];
+
+    NSData* originalPassword = [@"asdf" dataUsingEncoding:NSUTF8StringEncoding];
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassInternetPassword,
+        (id)kSecAttrAccessible : (id)kSecAttrAccessibleWhenUnlocked,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrDescription : @"desc",
+        (id)kSecAttrServer : @"server",
+        (id)kSecAttrAccount : @"test-account",
+        (id)kSecValueData : originalPassword,
+        (id)kSecDataInetExtraNotes : note,
+        (id)kSecDataInetExtraHistory : history,
+        (id)kSecDataInetExtraClientDefined0 : client0,
+        (id)kSecDataInetExtraClientDefined1 : client1,
+        (id)kSecDataInetExtraClientDefined2 : client2,
+        (id)kSecDataInetExtraClientDefined3 : client3,
+
+        (id)kSecReturnAttributes : @YES,
+    } mutableCopy];
+
+    CFTypeRef cfresult = nil;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, &cfresult), errSecSuccess, "Should be able to add an item using new binary fields");
+    NSDictionary* result = (NSDictionary*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(result, "Should have some sort of result");
+
+    XCTAssertNil(result[(id)kSecDataInetExtraNotes], "Notes field should not be returned as an attribute from add");
+    XCTAssertNil(result[(id)kSecDataInetExtraHistory], "Notes field should not be returned as an attribute from add");
+
+    NSDictionary* queryFind = @{
+        (id)kSecClass : (id)kSecClassInternetPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrAccount : @"test-account",
+    };
+
+    NSMutableDictionary* queryFindOneWithJustAttributes = [[NSMutableDictionary alloc] initWithDictionary:queryFind];
+    queryFindOneWithJustAttributes[(id)kSecReturnAttributes] = @YES;
+
+    NSMutableDictionary* queryFindAllWithJustAttributes = [[NSMutableDictionary alloc] initWithDictionary:queryFindOneWithJustAttributes];
+    queryFindAllWithJustAttributes[(id)kSecMatchLimit] = (id)kSecMatchLimitAll;
+
+    NSDictionary* queryFindOneWithAttributesAndData = @{
+        (id)kSecClass : (id)kSecClassInternetPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecReturnAttributes : @YES,
+        (id)kSecReturnData: @YES,
+        (id)kSecAttrAccount : @"test-account",
+    };
+
+    NSDictionary* queryFindAllWithAttributesAndData = @{
+        (id)kSecClass : (id)kSecClassInternetPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecReturnAttributes : @YES,
+        (id)kSecReturnData: @YES,
+        (id)kSecMatchLimit : (id)kSecMatchLimitAll,
+        (id)kSecAttrAccount : @"test-account",
+    };
+
+    /* Copy with a single record limite, but with attributes only */
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)queryFindOneWithJustAttributes, &cfresult), errSecSuccess, "Should be able to find an item");
+
+    result = (NSDictionary*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(result, "Should have some sort of result");
+
+    XCTAssertNil(result[(id)kSecDataInetExtraNotes], "Notes field should not be returned as an attribute from copymatching when finding a single item");
+    XCTAssertNil(result[(id)kSecDataInetExtraHistory], "Notes field should not be returned as an attribute from copymatching when finding a single item");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined0], "ClientDefined0 field should not be returned as an attribute from copymatching when finding a single item");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined1], "ClientDefined1 field should not be returned as an attribute from copymatching when finding a single item");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined2], "ClientDefined2 field should not be returned as an attribute from copymatching when finding a single item");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined3], "ClientDefined3 field should not be returned as an attribute from copymatching when finding a single item");
+
+    /* Copy with no limit, but with attributes only */
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)queryFindAllWithJustAttributes, &cfresult), errSecSuccess, "Should be able to find an item");
+    NSArray* arrayResult = (NSArray*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(arrayResult, "Should have some sort of result");
+    XCTAssertTrue([arrayResult isKindOfClass:[NSArray class]], "Should have received an array back from copymatching");
+    XCTAssertEqual(arrayResult.count, 1, "Array should have one element");
+
+    result = arrayResult[0];
+    XCTAssertNil(result[(id)kSecDataInetExtraNotes], "Notes field should not be returned as an attribute from copymatching when finding all items");
+    XCTAssertNil(result[(id)kSecDataInetExtraHistory], "Notes field should not be returned as an attribute from copymatching when finding all items");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined0], "ClientDefined0 field should not be returned as an attribute from copymatching when finding all items");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined1], "ClientDefined1 field should not be returned as an attribute from copymatching when finding all items");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined2], "ClientDefined2 field should not be returned as an attribute from copymatching when finding all items");
+    XCTAssertNil(result[(id)kSecDataInetExtraClientDefined3], "ClientDefined3 field should not be returned as an attribute from copymatching when finding all items");
+
+    /* Copy with single-record limit, but with attributes and data */
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)queryFindOneWithAttributesAndData, &cfresult), errSecSuccess, "Should be able to find an item");
+    result = (NSDictionary*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(result, "Should have some sort of result");
+
+    XCTAssertEqualObjects(note, result[(id)kSecDataInetExtraNotes], "Notes field should be returned as data");
+    XCTAssertEqualObjects(history, result[(id)kSecDataInetExtraHistory], "History field should be returned as data");
+    XCTAssertEqualObjects(client0, result[(id)kSecDataInetExtraClientDefined0], "Client Defined 0 field should be returned as data");
+    XCTAssertEqualObjects(client1, result[(id)kSecDataInetExtraClientDefined1], "Client Defined 1 field should be returned as data");
+    XCTAssertEqualObjects(client2, result[(id)kSecDataInetExtraClientDefined2], "Client Defined 2 field should be returned as data");
+    XCTAssertEqualObjects(client3, result[(id)kSecDataInetExtraClientDefined3], "Client Defined 3 field should be returned as data");
+
+    /* Copy with no limit, but with attributes and data */
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)queryFindAllWithAttributesAndData, &cfresult), errSecSuccess, "Should be able to find an item");
+    arrayResult = (NSArray*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(arrayResult, "Should have some sort of result");
+    XCTAssertTrue([arrayResult isKindOfClass:[NSArray class]], "Should have received an array back from copymatching");
+    XCTAssertEqual(arrayResult.count, 1, "Array should have one element");
+    result = arrayResult[0];
+    XCTAssertEqualObjects(note, result[(id)kSecDataInetExtraNotes], "Notes field should be returned as data");
+    XCTAssertEqualObjects(history, result[(id)kSecDataInetExtraHistory], "History field should be returned as data");
+    XCTAssertEqualObjects(client0, result[(id)kSecDataInetExtraClientDefined0], "Client Defined 0 field should be returned as data");
+    XCTAssertEqualObjects(client1, result[(id)kSecDataInetExtraClientDefined1], "Client Defined 1 field should be returned as data");
+    XCTAssertEqualObjects(client2, result[(id)kSecDataInetExtraClientDefined2], "Client Defined 2 field should be returned as data");
+    XCTAssertEqualObjects(client3, result[(id)kSecDataInetExtraClientDefined3], "Client Defined 3 field should be returned as data");
+
+    /* Copy just looking for the password */
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)@{
+        (id)kSecClass : (id)kSecClassInternetPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecReturnData: @YES,
+        (id)kSecAttrAccount : @"test-account",
+    }, &cfresult), errSecSuccess, "Should be able to find an item");
+
+    NSData* password = (NSData*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(password, "Should have some sort of password");
+    XCTAssertTrue([password isKindOfClass:[NSData class]], "Password is a data");
+    XCTAssertEqualObjects(originalPassword, password, "Should still be able to fetch the original password");
+
+    NSData* newHistoryContents = [@"gone" dataUsingEncoding:NSUTF8StringEncoding];
+
+    NSDictionary* updateQuery = @{
+        (id)kSecDataInetExtraHistory : newHistoryContents,
+    };
+
+    XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)queryFind, (__bridge CFDictionaryRef)updateQuery), errSecSuccess, "Should be able to update a history field");
+
+    // And find it again
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)queryFindOneWithAttributesAndData, &cfresult), errSecSuccess, "Should be able to find an item");
+    result = (NSDictionary*)CFBridgingRelease(cfresult);
+    XCTAssertNotNil(result, "Should have some sort of result");
+
+    XCTAssertEqualObjects(note, result[(id)kSecDataInetExtraNotes], "Notes field should be returned as data");
+    XCTAssertEqualObjects(newHistoryContents, result[(id)kSecDataInetExtraHistory], "History field should be updated");
+    XCTAssertEqualObjects(client0, result[(id)kSecDataInetExtraClientDefined0], "Client Defined 0 field should be returned as data");
+    XCTAssertEqualObjects(client1, result[(id)kSecDataInetExtraClientDefined1], "Client Defined 1 field should be returned as data");
+    XCTAssertEqualObjects(client2, result[(id)kSecDataInetExtraClientDefined2], "Client Defined 2 field should be returned as data");
+    XCTAssertEqualObjects(client3, result[(id)kSecDataInetExtraClientDefined3], "Client Defined 3 field should be returned as data");
+}
+
+// When this test starts failing, hopefully rdar://problem/60332379 got fixed
+- (void)testBadDateCausesDERDecodeValidationError {
+    // Wonky time calculation hastily stolen from SecGregorianDateGetAbsoluteTime and tweaked
+    // As of right now this causes CFCalendarDecomposeAbsoluteTime with Zulu calendar to give a seemingly incorrect date which then causes DER date validation issues
+    CFAbsoluteTime absTime = (CFAbsoluteTime)(((-(1902 * 365) + -38) * 24 + 0) * 60 + -1) * 60 + 1;
+    absTime -= 0.0004;  // Just to make sure the nanoseconds keep getting encoded/decoded properly
+    CFDateRef date = CFDateCreate(NULL, absTime);
+
+    CFErrorRef error = NULL;
+    size_t plistSize = der_sizeof_plist(date, &error);
+    XCTAssert(error == NULL);
+    XCTAssertGreaterThan(plistSize, 0);
+
+    // Encode without repair does not validate dates because that changes behavior I do not want to fiddle with
+    uint8_t* der = calloc(1, plistSize);
+    uint8_t* der_end = der + plistSize;
+    uint8_t* result = der_encode_plist(date, &error, der, der_end);
+    XCTAssert(error == NULL);
+    XCTAssertEqual(der, result);
+
+    // ...but decoding does and will complain
+    CFPropertyListRef decoded = NULL;
+    XCTAssert(der_decode_plist(NULL, &decoded, &error, der, der_end) == NULL);
+    XCTAssert(error != NULL);
+    XCTAssertEqual(CFErrorGetDomain(error), kCFErrorDomainOSStatus);
+    NSString* description = CFBridgingRelease(CFErrorCopyDescription(error));
+    XCTAssert([description containsString:@"Invalid date"]);
+
+    CFReleaseNull(error);
+    free(der);
+}
+
+// When this test starts failing, hopefully rdar://problem/60332379 got fixed
+- (void)testBadDateWithDEREncodingRepairProducesDefaultValue {
+    // Wonky time calculation hastily stolen from SecGregorianDateGetAbsoluteTime and tweaked
+    // As of right now this causes CFCalendarDecomposeAbsoluteTime with Zulu calendar to give a seemingly incorrect date which then causes DER date validation issues
+    CFAbsoluteTime absTime = (CFAbsoluteTime)(((-(1902 * 365) + -38) * 24 + 0) * 60 + -1) * 60 + 1;
+    absTime -= 0.0004;  // Just to make sure the nanoseconds keep getting encoded/decoded properly
+    CFDateRef date = CFDateCreate(NULL, absTime);
+
+    CFErrorRef error = NULL;
+    size_t plistSize = der_sizeof_plist(date, &error);
+    XCTAssert(error == NULL);
+    XCTAssertGreaterThan(plistSize, 0);
+
+    uint8_t* der = calloc(1, plistSize);
+    uint8_t* der_end = der + plistSize;
+    uint8_t* encoderesult = der_encode_plist_repair(date, &error, true, der, der_end);
+    XCTAssert(error == NULL);
+    XCTAssertEqual(der, encoderesult);
+
+    CFPropertyListRef decoded = NULL;
+    const uint8_t* decoderesult = der_decode_plist(NULL, &decoded, &error, der, der_end);
+    XCTAssertEqual(der_end, decoderesult);
+    XCTAssertEqual(CFGetTypeID(decoded), CFDateGetTypeID());
+    XCTAssertEqualWithAccuracy(CFDateGetAbsoluteTime(decoded), 0, 60 * 60 * 24);
+}
+
+#pragma mark - SecItemRateLimit
+
+// This is not super accurate in BATS, so put some margin around what you need
+- (void)sleepAlternativeForXCTest:(double)interval
+{
+    dispatch_semaphore_t localsema = dispatch_semaphore_create(0);
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * interval), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
+        dispatch_semaphore_signal(localsema);
+    });
+    dispatch_semaphore_wait(localsema, DISPATCH_TIME_FOREVER);
+}
+
+- (void)testSecItemRateLimitTimePasses {
+    SecItemRateLimit* rl = [SecItemRateLimit getStaticRateLimit];
+    [rl forceEnabled: true];
+
+    for (int idx = 0; idx < rl.roCapacity; ++idx) {
+        XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+    }
+
+    for (int idx = 0; idx < rl.rwCapacity; ++idx) {
+        XCTAssertTrue(isModifyingAPIRateWithinLimits());
+    }
+
+    [self sleepAlternativeForXCTest: 2];
+    XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+    XCTAssertTrue(isModifyingAPIRateWithinLimits());
+
+    [SecItemRateLimit resetStaticRateLimit];
+}
+
+- (void)testSecItemRateLimitResetAfterExceed {
+    SecItemRateLimit* rl = [SecItemRateLimit getStaticRateLimit];
+       [rl forceEnabled: true];
+
+    for (int idx = 0; idx < rl.roCapacity; ++idx) {
+        XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isReadOnlyAPIRateWithinLimits());
+       XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+
+    for (int idx = 0; idx < rl.rwCapacity; ++idx) {
+        XCTAssertTrue(isModifyingAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isModifyingAPIRateWithinLimits());
+    XCTAssertTrue(isModifyingAPIRateWithinLimits());
+
+    [SecItemRateLimit resetStaticRateLimit];
+}
+
+- (void)testSecItemRateLimitMultiplier {
+    SecItemRateLimit* rl = [SecItemRateLimit getStaticRateLimit];
+    [rl forceEnabled: true];
+
+    int ro_iterations_before = 0;
+    for (; ro_iterations_before < rl.roCapacity; ++ro_iterations_before) {
+        XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isReadOnlyAPIRateWithinLimits());
+
+    int rw_iterations_before = 0;
+    for (; rw_iterations_before < rl.rwCapacity; ++rw_iterations_before) {
+        XCTAssertTrue(isModifyingAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isModifyingAPIRateWithinLimits());
+
+
+    int ro_iterations_after = 0;
+    for (; ro_iterations_after < rl.roCapacity; ++ro_iterations_after) {
+        XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isReadOnlyAPIRateWithinLimits());
+
+    int rw_iterations_after = 0;
+    for (; rw_iterations_after < rl.rwCapacity; ++rw_iterations_after) {
+        XCTAssertTrue(isModifyingAPIRateWithinLimits());
+    }
+    XCTAssertFalse(isModifyingAPIRateWithinLimits());
+
+    XCTAssertEqualWithAccuracy(rl.limitMultiplier * ro_iterations_before, ro_iterations_after, 1);
+    XCTAssertEqualWithAccuracy(rl.limitMultiplier * rw_iterations_before, rw_iterations_after, 1);
+    [SecItemRateLimit resetStaticRateLimit];
+}
+
+// We stipulate that this test is run on an internal release.
+// If this were a platform binary limits would be enforced, but it should not be so they should not.
+- (void)testSecItemRateLimitInternalPlatformBinariesOnly {
+    SecItemRateLimit* rl = [SecItemRateLimit getStaticRateLimit];
+
+    for (int idx = 0; idx < 3 * MAX(rl.roCapacity, rl.rwCapacity); ++idx) {
+        XCTAssertTrue(isReadOnlyAPIRateWithinLimits());
+        XCTAssertTrue(isModifyingAPIRateWithinLimits());
+    }
+
+    [SecItemRateLimit resetStaticRateLimit];
+}
+
 @end
 
 #endif
diff --git a/secdxctests/KeychainAppClipTests.m b/secdxctests/KeychainAppClipTests.m
new file mode 100644 (file)
index 0000000..2bbefec
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2020 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 <Security/Security.h>
+#import <Security/SecItemPriv.h>
+#include <Security/SecEntitlements.h>
+#include <ipc/server_security_helpers.h>
+
+#import "KeychainXCTest.h"
+
+#if USE_KEYSTORE
+@interface KeychainAppClipTests : KeychainXCTest
+@end
+
+@implementation KeychainAppClipTests {
+    // App Clips are only permitted to store items with agrp == appID, so we set and track it
+    NSString* _applicationIdentifier;
+}
+
++ (void)setUp {
+    [super setUp];
+}
+
+- (void)setUp {
+    [super setUp];
+    SecSecurityClientAppClipToRegular();
+    _applicationIdentifier = @"com.apple.security.appcliptests";
+    SecSecurityClientSetApplicationIdentifier((__bridge CFStringRef)_applicationIdentifier);
+}
+
++ (void)tearDown {
+    SecSecurityClientAppClipToRegular();
+    SecSecurityClientSetApplicationIdentifier(NULL);
+    [super tearDown];
+}
+
+# pragma mark - Test App Clip API Restrictions (SecItemAdd)
+
+- (void)testAppclipCanAddItem {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    };
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+}
+
+- (void)testAppClipAddNoSyncAllowed {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrSynchronizable : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    };
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecRestrictedAPI);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+- (void)testAppClipAddNoAgrpAllowed {
+    SecSecurityClientRegularToAppClip();
+    // By not explicitly setting entitlements we get the default set which is not permitted for an app clip
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    };
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecRestrictedAPI);
+
+    SecSecurityClientAppClipToRegular();
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+# pragma mark - Test App Clip API Restrictions (SecItemUpdate)
+
+- (void)testAppClipCanUpdateItem {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    } mutableCopy];
+    SecItemAdd((__bridge CFDictionaryRef)query, NULL);
+
+    NSDictionary* update = @{
+        (id)kSecValueData : [@"different" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecAttrService : @"DifferentAppClipTestService",
+    };
+
+    XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecSuccess);
+    query[(id)kSecAttrService] = @"DifferentAppClipTestService";
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+}
+
+- (void)testAppClipUpdateNoSyncAllowed {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    } mutableCopy];
+    SecItemAdd((__bridge CFDictionaryRef)query, NULL);
+
+    NSDictionary* update = @{
+        (id)kSecValueData : [@"different" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecAttrSynchronizable : @YES,
+    };
+
+    XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecRestrictedAPI);
+    query[(id)kSecAttrSynchronizable] = @YES;
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+- (void)testAppClipUpdateNoAgrpAllowed {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    } mutableCopy];
+    SecItemAdd((__bridge CFDictionaryRef)query, NULL);
+
+    NSDictionary* update = @{
+        (id)kSecValueData : [@"different" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecAttrAccessGroup : @"someotheraccessgroup",
+    };
+
+    XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecMissingEntitlement);
+    query[(id)kSecAttrAccessGroup] = @"someotheraccessgroup";
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecMissingEntitlement);
+}
+
+# pragma mark - Test App Clip API Restrictions (SecItemCopyMatching)
+// For now SICM doesn't care about sync, because there shouldn't be any items where (clip == 1 && sync == 1)
+
+- (void)testAppClipCopyMatchingNoAgrpsAllowed {
+    SecSecurityClientRegularToAppClip();
+
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecReturnAttributes : @YES,
+    };
+
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecRestrictedAPI);
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+# pragma mark - Test App Clip API Restrictions (SecItemDelete)
+
+- (void)testAppClipDeleteNoAgrpsAllowed {
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+    };
+
+    XCTAssertEqual(SecItemDelete((__bridge CFDictionaryRef)query), errSecItemNotFound);
+    SecSecurityClientRegularToAppClip();
+    XCTAssertEqual(SecItemDelete((__bridge CFDictionaryRef)query), errSecRestrictedAPI);
+}
+
+# pragma mark - Test App Clip API Restrictions (Misc)
+
+- (void)testAppClipNoSecItemUpdateTokenItemsAllowed {
+    SecSecurityClientRegularToAppClip();
+    // Don't bother setting it up, app clips aren't even welcome at the door.
+    XCTAssertEqual(SecItemUpdateTokenItemsForAccessGroups(NULL, (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], NULL), errSecRestrictedAPI);
+}
+
+- (void)testAppClipCanPassAppIDAccessGroup {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrService : @"AppClipTestService",
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecReturnAttributes : @YES,
+        (id)kSecAttrAccessGroup : _applicationIdentifier,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    } mutableCopy];
+
+    NSDictionary* update = @{
+        (id)kSecValueData : [@"betterpassword" dataUsingEncoding:NSUTF8StringEncoding],
+    };
+
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    query[(id)kSecValueData] = nil;
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    query[(id)kSecReturnAttributes] = nil;
+    XCTAssertEqual(SecItemUpdate((__bridge CFDictionaryRef)query, (__bridge CFDictionaryRef)update), errSecSuccess);
+    XCTAssertEqual(SecItemDelete((__bridge CFDictionaryRef)query), errSecSuccess);
+}
+
+# pragma mark - Test Item Deletion SPI
+
+- (void)testDeletionSPINoEntitlement {
+    XCTAssertEqual(SecItemDeleteKeychainItemsForAppClip((__bridge CFStringRef)@"nonexistent"), errSecMissingEntitlement);
+}
+
+- (void)testDeletionSPINoItems {
+    SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateAppClipDeletion, kCFBooleanTrue);
+    XCTAssertEqual(SecItemDeleteKeychainItemsForAppClip((__bridge CFStringRef)@"nonexistent"), errSecSuccess);
+}
+
+- (void)testDeletionSPIDeleteAppClipItem {
+    // The SPI does not check if app clip, and the API does not check private entitlement
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateAppClipDeletion, kCFBooleanTrue);
+
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecReturnAttributes : @YES,
+    };
+
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemDeleteKeychainItemsForAppClip((__bridge CFStringRef)_applicationIdentifier), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+- (void)testDeletionSPILeaveRegularItemsAlone {
+    SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateAppClipDeletion, kCFBooleanTrue);
+    NSString* agrp = @"com.apple.keychain.test.notanappclip";
+    [self setEntitlements:@{ @"keychain-access-groups": @[agrp] } validated:YES];
+
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecAttrAccessGroup : agrp,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding]
+    };
+
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemDeleteKeychainItemsForAppClip((__bridge CFStringRef)agrp), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+}
+
+- (void)testDeletionSPILeaveOtherAppClipItemsAlone {
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    NSString* otherAppID = @"not-the-same-application-identifier";
+    SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementPrivateAppClipDeletion, kCFBooleanTrue);
+
+    NSDictionary* query = @{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecReturnAttributes : @YES,
+    };
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    [self setEntitlements:@{@"com.apple.application-identifier" : otherAppID} validated:YES];
+    SecSecurityClientSetApplicationIdentifier((__bridge CFStringRef)otherAppID);
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    XCTAssertEqual(SecItemDeleteKeychainItemsForAppClip((__bridge CFStringRef)_applicationIdentifier), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+    SecSecurityClientSetApplicationIdentifier((__bridge CFStringRef)_applicationIdentifier);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecItemNotFound);
+}
+
+@end
+#endif
diff --git a/secdxctests/KeychainBackupTests.m b/secdxctests/KeychainBackupTests.m
new file mode 100644 (file)
index 0000000..666d3dd
--- /dev/null
@@ -0,0 +1,118 @@
+#import "KeychainXCTest.h"
+#import <Security/Security.h>
+#import <Security/SecItemPriv.h>
+#include <Security/SecEntitlements.h>
+#include <ipc/server_security_helpers.h>
+
+@interface KeychainBackupTests : KeychainXCTest
+@end
+
+
+@implementation KeychainBackupTests {
+    NSString* _applicationIdentifier;
+}
+
+- (void)setUp {
+    // Put setup code here. This method is called before the invocation of each test method in the class.
+    [super setUp];
+    _applicationIdentifier = @"com.apple.security.backuptests";
+    SecSecurityClientSetApplicationIdentifier((__bridge CFStringRef)_applicationIdentifier);
+}
+
+- (void)tearDown {
+    // Put teardown code here. This method is called after the invocation of each test method in the class.
+}
+
+# pragma mark - Test OTA Backups
+
+// Code lovingly adapted from si-33-keychain-backup
+#if USE_KEYSTORE
+- (NSData*)createKeybagWithType:(keybag_handle_t)bag_type password:(NSData*)password
+{
+    keybag_handle_t handle = bad_keybag_handle;
+    kern_return_t bag_created = aks_create_bag(password ? password.bytes : NULL, password ? (int)password.length : 0, bag_type, &handle);
+    XCTAssertEqual(bag_created, kAKSReturnSuccess, @"Unable to create keybag");
+
+    void *bag = NULL;
+    int bagLen = 0;
+    kern_return_t bag_saved = aks_save_bag(handle, &bag, &bagLen);
+    XCTAssertEqual(bag_saved, kAKSReturnSuccess, @"Unable to save keybag");
+
+    NSData* bagData = [NSData dataWithBytes:bag length:bagLen];
+    XCTAssertNotNil(bagData, @"Unable to create NSData from bag bytes");
+
+    return bagData;
+}
+#endif
+
+// All backup paths ultimately lead to SecServerCopyKeychainPlist which does the actual exporting,
+// so this test ought to suffice for all backup configurations
+- (void)testAppClipDoesNotBackup {
+
+    // First add a "regular" item for each class, which we expect to be in the backup later
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecUseDataProtectionKeychain : @YES,
+        (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+    } mutableCopy];
+
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassInternetPassword;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassCertificate;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassKey;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    // Switch to being an app clip, add another item for each class, which we expect not to find in the backup
+    SecSecurityClientRegularToAppClip();
+    [self setEntitlements:@{@"com.apple.application-identifier" : _applicationIdentifier} validated:YES];
+
+    query[(id)kSecClass] = (id)kSecClassGenericPassword;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassInternetPassword;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassCertificate;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    query[(id)kSecClass] = (id)kSecClassKey;
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    SecSecurityClientAppClipToRegular();
+    SecAddLocalSecuritydXPCFakeEntitlement(kSecEntitlementRestoreKeychain, @YES);
+
+    // Code lovingly adapted from si-33-keychain-backup
+    NSData* keybag;
+#if USE_KEYSTORE
+    keybag = [self createKeybagWithType:kAppleKeyStoreBackupBag password:nil];
+#else
+    keybag = [NSData new];
+#endif
+
+    NSData* data = CFBridgingRelease(_SecKeychainCopyBackup((__bridge CFDataRef)keybag, nil));
+
+    XCTAssert(data);
+    XCTAssertGreaterThan([data length], 42, @"Got empty dictionary");
+    NSDictionary* keychain = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:nil error:nil];
+
+    // Only one item should be here for each class, which is the regular one.
+    XCTAssertEqual([keychain[@"genp"] count], 1);
+    XCTAssertEqual([keychain[@"inet"] count], 1);
+    XCTAssertEqual([keychain[@"cert"] count], 1);
+    XCTAssertEqual([keychain[@"keys"] count], 1);
+}
+
+@end
index bdf33b1bd2cbfb76461d7193686aacead7c1a9e0..3165c667d1878bceb3b8833be605b6538b7c6e12 100644 (file)
@@ -32,6 +32,7 @@
 #import "spi.h"
 #import "SecDbKeychainSerializedItemV7.h"
 #import "SecDbKeychainSerializedMetadata.h"
+#import "SecDbKeychainSerializedMetadataKey.h"
 #import "SecDbKeychainSerializedSecretData.h"
 #import "SecDbKeychainSerializedAKSWrappedKey.h"
 #import <utilities/SecCFWrappers.h>
@@ -138,6 +139,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     SecAccessControlRef ac = NULL;
 
     NSDictionary* secretData = @{(id)kSecValueData : @"secret here"};
+    CFDictionaryRef emptyDict = (__bridge CFDictionaryRef)@{};
 
     ac = SecAccessControlCreate(NULL, &error);
     XCTAssertNotNil((__bridge id)ac, @"failed to create access control with error: %@", (__bridge id)error);
@@ -145,16 +147,19 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     XCTAssertTrue(SecAccessControlSetProtection(ac, kSecAttrAccessibleWhenUnlocked, &error), @"failed to set access control protection with error: %@", error);
     XCTAssertNil((__bridge id)error, @"encountered error attempting to set access control protection: %@", (__bridge id)error);
 
-    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, (__bridge CFDictionaryRef)@{}, NULL, &enc, true, &error), @"failed to encrypt data with error: %@", error);
+    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, emptyDict, emptyDict, &enc, true, &error), @"failed to encrypt data with error: %@", error);
     XCTAssertTrue(enc != NULL, @"failed to get encrypted data from encryption function");
     XCTAssertNil((__bridge id)error, @"encountered error attempting to encrypt data: %@", (__bridge id)error);
     CFReleaseNull(ac);
 
     CFMutableDictionaryRef attributes = NULL;
     uint32_t version = 0;
+    NSData* dummyACM = [NSData dataWithBytes:"dummy" length:5];
+    const SecDbClass* class = kc_class_with_name(kSecClassGenericPassword);
+    NSArray* dummyArray = [NSArray array];
 
     keyclass_t keyclass = 0;
-    XCTAssertTrue(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, NULL, enc, NULL, NULL, &attributes, &version, true, &keyclass, &error), @"failed to decrypt data with error: %@", error);
+    XCTAssertTrue(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, (__bridge CFDataRef _Nonnull)dummyACM, enc, class, (__bridge CFArrayRef)dummyArray, &attributes, &version, true, &keyclass, &error), @"failed to decrypt data with error: %@", error);
     XCTAssertNil((__bridge id)error, @"encountered error attempting to decrypt data: %@", (__bridge id)error);
     XCTAssertEqual(keyclass, key_class_ak, @"failed to get back the keyclass from decryption");
 
@@ -277,9 +282,9 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     NSError* error;
     SecDbKeychainItemV7* item = [[SecDbKeychainItemV7 alloc] initWithSecretAttributes:@{(id)kSecValueData : password} metadataAttributes:metadata tamperCheck:[[NSUUID UUID] UUIDString] keyclass:9];
     [item encryptMetadataWithKeybag:0 error:&error];
-    XCTAssertNil(error, @"Successfully encrypted metadata");
+    XCTAssertNil(error, "error encrypting metadata with keybag 0");
     [item encryptSecretDataWithKeybag:0 accessControl:SecAccessControlCreate(NULL, NULL) acmContext:nil error:&error];
-    XCTAssertNil(error, @"Successfully encrypted secret data");
+    XCTAssertNil(error, "error encrypting secret data with keybag 0");
     SecDbKeychainSerializedItemV7* serializedItem = [[SecDbKeychainSerializedItemV7 alloc] init];
     serializedItem.encryptedMetadata = item.encryptedMetadataBlob;
     serializedItem.encryptedSecretData = item.encryptedSecretDataBlob;
@@ -341,6 +346,26 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
 }
 
 - (void)trashMetadataClassAKey
+{
+    __block CFErrorRef cferror = NULL;
+    kc_with_dbt(true, &cferror, ^bool(SecDbConnectionRef dbt) {
+        CFStringRef sql = CFSTR("UPDATE metadatakeys SET data = ? WHERE keyclass = '6'");
+        NSData* garbage = [@"super bad key" dataUsingEncoding:NSUTF8StringEncoding];
+        SecDbPrepare(dbt, sql, &cferror, ^(sqlite3_stmt *stmt) {
+            SecDbBindObject(stmt, 1, (__bridge CFDataRef)garbage, &cferror);
+            SecDbStep(dbt, stmt, &cferror, NULL);
+            XCTAssertEqual(cferror, NULL, "Should be no error trashing class A metadatakey");
+            CFReleaseNull(cferror);
+        });
+        XCTAssertEqual(cferror, NULL, "Should be no error completing SecDbPrepare for trashing class A metadatakey");
+        return true;
+    });
+    CFReleaseNull(cferror);
+
+    [[SecDbKeychainMetadataKeyStore sharedStore] dropClassAKeys];
+}
+
+- (void)deleteMetadataClassAKey
 {
     CFErrorRef cferror = NULL;
 
@@ -356,32 +381,31 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     [[SecDbKeychainMetadataKeyStore sharedStore] dropClassAKeys];
 }
 
-- (void)checkDatabaseExistenceOfMetadataKey:(keyclass_t)keyclass shouldExist:(bool)shouldExist
+- (void)checkDatabaseExistenceOfMetadataKey:(keyclass_t)keyclass shouldExist:(bool)shouldExist value:(NSData*)expectedData
 {
     CFErrorRef cferror = NULL;
-
+    __block NSData* wrappedKey;
     kc_with_dbt(true, &cferror, ^bool(SecDbConnectionRef dbt) {
         __block CFErrorRef errref = NULL;
 
         NSString* sql = [NSString stringWithFormat:@"SELECT data, actualKeyclass FROM metadatakeys WHERE keyclass = %d", keyclass];
         __block bool ok = true;
-        __block bool keyExists = false;
         ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &errref, ^(sqlite3_stmt *stmt) {
             ok &= SecDbStep(dbt, stmt, &errref, ^(bool *stop) {
-                NSData* wrappedKeyData = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
-                NSMutableData* unwrappedKeyData = [NSMutableData dataWithLength:wrappedKeyData.length];
-
-                keyExists = !!unwrappedKeyData;
+                wrappedKey = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
             });
         });
 
         XCTAssertTrue(ok, "Should have completed all operations correctly");
-        XCTAssertEqual(errref, NULL, "Should be no error deleting class A metadatakey");
+        XCTAssertEqual(errref, NULL, "Should be no error trying to find class A metadatakey");
 
         if(shouldExist) {
-            XCTAssertTrue(keyExists, "Metadata class key should exist");
+            XCTAssertNotNil(wrappedKey, "Metadata class key should exist");
+            if (expectedData) {
+                XCTAssertEqualObjects(wrappedKey, expectedData);
+            }
         } else {
-            XCTAssertFalse(keyExists, "Metadata class key should not exist");
+            XCTAssertNil(wrappedKey, "Metadata class key should not exist");
         }
         CFReleaseNull(errref);
         return true;
@@ -400,7 +424,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
 
     OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
     XCTAssertEqual(result, 0, @"failed to add test item to keychain");
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:true];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:true value:nil];
 
     NSMutableDictionary* dataQuery = item.mutableCopy;
     [dataQuery removeObjectForKey:(id)kSecValueData];
@@ -413,7 +437,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     CFReleaseNull(foundItem);
 
     [self trashMetadataClassAKey];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:false];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:true value:[@"super bad key" dataUsingEncoding:NSUTF8StringEncoding]];
 
     /* when metadata corrupted, we should not find the item */
     result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
@@ -421,7 +445,46 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     CFReleaseNull(foundItem);
 
     // Just calling SecItemCopyMatching shouldn't have created a new metadata key
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:false];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:true value:[@"super bad key" dataUsingEncoding:NSUTF8StringEncoding]];
+
+    /* CopyMatching will delete corrupt pre-emptively */
+    result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
+    XCTAssertEqual(result, -25300, @"corrupt item was not deleted for us");
+}
+
+- (void)testKeychainDeletionCopyMatching
+{
+    NSDictionary* item = @{ (id)kSecClass : (id)kSecClassGenericPassword,
+                            (id)kSecValueData : [@"password" dataUsingEncoding:NSUTF8StringEncoding],
+                            (id)kSecAttrAccount : @"TestAccount",
+                            (id)kSecAttrService : @"TestService",
+                            (id)kSecAttrAccessible : (id)kSecAttrAccessibleWhenUnlocked,
+                            (id)kSecUseDataProtectionKeychain : @YES };
+
+    OSStatus result = SecItemAdd((__bridge CFDictionaryRef)item, NULL);
+    XCTAssertEqual(result, 0, @"failed to add test item to keychain");
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:true value:nil];
+
+    NSMutableDictionary* dataQuery = item.mutableCopy;
+    [dataQuery removeObjectForKey:(id)kSecValueData];
+    dataQuery[(id)kSecReturnData] = @(YES);
+
+    CFTypeRef foundItem = NULL;
+
+    result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
+    XCTAssertEqual(result, 0, @"failed to find the data for the item we just added in the keychain");
+    CFReleaseNull(foundItem);
+
+    [self deleteMetadataClassAKey];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:false value:nil];
+
+    /* when metadata corrupted, we should not find the item */
+    result = SecItemCopyMatching((__bridge CFDictionaryRef)dataQuery, &foundItem);
+    XCTAssertEqual(result, errSecItemNotFound, @"failed to find the data for the item we just added in the keychain");
+    CFReleaseNull(foundItem);
+
+    // Just calling SecItemCopyMatching shouldn't have created a new metadata key
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ak shouldExist:false value:nil];
 
     /* CopyMatching will delete corrupt pre-emptively */
     result = SecItemDelete((__bridge CFDictionaryRef)dataQuery);
@@ -508,6 +571,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     self.allowDecryption = NO;
 
     NSDictionary* secretData = @{(id)kSecValueData : @"secret here"};
+    CFDictionaryRef emptyDict = (__bridge CFDictionaryRef)@{};
 
     ac = SecAccessControlCreate(NULL, &error);
     XCTAssertNotNil((__bridge id)ac, @"failed to create access control with error: %@", (__bridge id)error);
@@ -515,16 +579,19 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     XCTAssertTrue(SecAccessControlSetProtection(ac, kSecAttrAccessibleWhenUnlocked, &error), @"failed to set access control protection with error: %@", error);
     XCTAssertNil((__bridge id)error, @"encountered error attempting to set access control protection: %@", (__bridge id)error);
 
-    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, (__bridge CFDictionaryRef)@{}, NULL, &enc, true, &error), @"failed to encrypt data with error: %@", error);
+    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, emptyDict, emptyDict, &enc, true, &error), @"failed to encrypt data with error: %@", error);
     XCTAssertTrue(enc != NULL, @"failed to get encrypted data from encryption function");
     XCTAssertNil((__bridge id)error, @"encountered error attempting to encrypt data: %@", (__bridge id)error);
     CFReleaseNull(ac);
 
     CFMutableDictionaryRef attributes = NULL;
     uint32_t version = 0;
+    NSData* dummyACM = [NSData dataWithBytes:"dummy" length:5];
+    const SecDbClass* class = kc_class_with_name(kSecClassGenericPassword);
+    NSArray* dummyArray = [NSArray array];
 
     keyclass_t keyclass = 0;
-    XCTAssertNoThrow(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, NULL, enc, NULL, NULL, &attributes, &version, true, &keyclass, &error), @"unexpected exception when decryption fails");
+    XCTAssertNoThrow(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, (__bridge CFDataRef _Nonnull)dummyACM, enc, class, (__bridge CFArrayRef)dummyArray, &attributes, &version, true, &keyclass, &error), @"unexpected exception when decryption fails");
     XCTAssertEqual(keyclass, key_class_ak, @"failed to get back the keyclass when decryption failed");
 
     self.allowDecryption = YES;
@@ -744,18 +811,18 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     NSString* otherAccount = @"OtherAccount";
     NSString* thirdAccount = @"ThirdAccount";
     [self addTestItemExpecting:errSecSuccess account:testAccount accessible:(id)kSecAttrAccessibleAfterFirstUnlock];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:false];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true value:nil];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:false value:nil];
 
     // This should fail, and not create a CKU metadata key
     [self addTestItemExpecting:errSecDuplicateItem account:testAccount accessible:(id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:false];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true value:nil];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:false value:nil];
 
     // But successfully creating a new CKU item should create the key
     [self addTestItemExpecting:errSecSuccess account:otherAccount accessible:(id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:true];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true value:nil];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:true value:nil];
 
     // Drop all metadata key caches
     [SecDbKeychainMetadataKeyStore resetSharedStore];
@@ -765,8 +832,8 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
 
     // Adding another CKU item now should be fine
     [self addTestItemExpecting:errSecSuccess account:thirdAccount accessible:(id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true];
-    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:true];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_ck shouldExist:true value:nil];
+    [self checkDatabaseExistenceOfMetadataKey:key_class_cku shouldExist:true value:nil];
 
     // Drop all metadata key caches once more, to ensure we can find all three items from the persisted keys
     [SecDbKeychainMetadataKeyStore resetSharedStore];
@@ -796,6 +863,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     CFErrorRef error = NULL;
     
     NSDictionary* secretData = @{(id)kSecValueData : @"secret here"};
+    CFDictionaryRef emptyDict = (__bridge CFDictionaryRef)@{};
     
     ac = SecAccessControlCreate(NULL, &error);
     XCTAssertNotNil((__bridge id)ac, @"failed to create access control with error: %@", (__bridge id)error);
@@ -803,7 +871,7 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     XCTAssertTrue(SecAccessControlSetProtection(ac, accessibility, &error), @"failed to set access control protection with error: %@", error);
     XCTAssertNil((__bridge id)error, @"encountered error attempting to set access control protection: %@", (__bridge id)error);
     
-    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, (__bridge CFDictionaryRef)@{}, NULL, &enc, true, &error), @"failed to encrypt data with error: %@", error);
+    XCTAssertTrue(ks_encrypt_data(KEYBAG_DEVICE, ac, NULL, (__bridge CFDictionaryRef)secretData, emptyDict, emptyDict, &enc, true, &error), @"failed to encrypt data with error: %@", error);
     XCTAssertTrue(enc != NULL, @"failed to get encrypted data from encryption function");
     XCTAssertNil((__bridge id)error, @"encountered error attempting to encrypt data: %@", (__bridge id)error);
     CFReleaseNull(ac);
@@ -824,7 +892,11 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     XCTAssertNil((__bridge id)error, @"encountered error attempting to set access control protection: %@", (__bridge id)error);
     
     keyclass_t keyclass = 0;
-    XCTAssertTrue(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, NULL, (__bridge CFDataRef)encryptedData, NULL, NULL, &attributes, &version, false, &keyclass, &error), @"failed to decrypt data with error: %@", error);
+    NSData* dummyACM = [NSData dataWithBytes:"dummy" length:5];
+    const SecDbClass* class = kc_class_with_name(kSecClassGenericPassword);
+    NSArray* dummyArray = [NSArray array];
+
+    XCTAssertTrue(ks_decrypt_data(KEYBAG_DEVICE, kAKSKeyOpDecrypt, &ac, (__bridge CFDataRef _Nonnull)dummyACM, (__bridge CFDataRef)encryptedData, class, (__bridge CFArrayRef)dummyArray, &attributes, &version, false, &keyclass, &error), @"failed to decrypt data with error: %@", error);
     XCTAssertNil((__bridge id)error, @"encountered error attempting to decrypt data: %@", (__bridge id)error);
     XCTAssertEqual(keyclass & key_class_last, parse_keyclass(accessibility), @"failed to get back the keyclass from decryption");
     
@@ -881,13 +953,27 @@ static keyclass_t parse_keyclass(CFTypeRef value) {
     __block CFErrorRef error = NULL;
     __block bool ok = true;
     ok &= kc_with_dbt(true, &error, ^bool(SecDbConnectionRef dbt) {
-        NSString* sql = [NSString stringWithFormat:@"UPDATE metadatakeys SET actualKeyclass = %d WHERE keyclass = %d", 0, key_class_ak];
-        ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &error, ^(sqlite3_stmt* stmt) {
-            ok &= SecDbStep(dbt, stmt, &error, ^(bool* stop) {
-                // woohoo
+        if (checkV12DevEnabled()) { // item is in new format, turn it into an old format item
+            NSString* sql = [NSString stringWithFormat:@"SELECT metadatakeydata FROM metadatakeys WHERE keyclass = %d", key_class_ak];
+            __block NSData* key;
+            ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &error, ^(sqlite3_stmt* stmt) {
+                ok &= SecDbStep(dbt, stmt, &error, ^(bool *stop) {
+                    NSData* wrappedKey = [[NSData alloc] initWithBytes:sqlite3_column_blob(stmt, 0) length:sqlite3_column_bytes(stmt, 0)];
+                    SecDbKeychainSerializedMetadataKey* mdkdata = [[SecDbKeychainSerializedMetadataKey alloc] initWithData:wrappedKey];
+                    key = mdkdata.akswrappedkey;
+                });
             });
-        });
-        
+            sql = [NSString stringWithFormat:@"UPDATE metadatakeys SET actualKeyclass = 0, data = ?, metadatakeydata = ? WHERE keyclass = %d", key_class_ak];
+            ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &error, ^(sqlite3_stmt *stmt) {
+                ok &= SecDbBindBlob(stmt, 1, key.bytes, key.length, SQLITE_TRANSIENT, &error);
+                ok &= SecDbStep(dbt, stmt, &error, NULL);
+            });
+        } else {
+            NSString* sql = [NSString stringWithFormat:@"UPDATE metadatakeys SET actualKeyclass = %d WHERE keyclass = %d", 0, key_class_ak];
+            ok &= SecDbPrepare(dbt, (__bridge CFStringRef)sql, &error, ^(sqlite3_stmt* stmt) {
+                ok &= SecDbStep(dbt, stmt, &error, NULL);
+            });
+        }
         return ok;
     });
 
index d5be9242ebdf4b665375153ce8b289c53ca44752..b72a6c5d899e7423c8ac309d64bce895acb31e01 100644 (file)
@@ -23,6 +23,7 @@
 
 #import <Security/Security.h>
 #import <Security/SecItemPriv.h>
+#import <os/feature_private.h>
 
 #import "KeychainXCTest.h"
 
     // Application with no keychain-related entitlements at all, but CopyMatching must work in order to support
     // backward compatibility with smart-card-enabled macos applications (com.apple.token AG is added automatically in this case).
     [self setEntitlements:@{} validated:false];
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+#if TARGET_OS_OSX
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+#else
+        // On non-macOS targets, token items must be explicitly enabled, and that requires entitlements.
+        // But since this test has no entitlements, it will always fail with errSecMissingEntitlement.
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
+#endif
+    } else {
+        // If tokens are not enabled, this situation really means that there is an entitlement problem.
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
+    }
 
     // However, write access is declined for such application.
     XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
                 (id)kSecClass: (id)kSecClassGenericPassword,
                 (id)kSecAttrLabel: @"label",
                 (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, };
-    [self setEntitlements:@{ @"com.apple.application-identifier": (id)kSecAttrAccessGroupToken } validated:YES];
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    [self setEntitlements:@{ @"keychain-access-groups": @[ (id)kSecAttrAccessGroupToken ] } validated:YES];
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    } else {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
+    }
     XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
     XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
 }
                 (id)kSecAttrLabel: @"label", };
     [self setEntitlements:@{ @"com.apple.security.application-groups": @[@"com.apple.test-app-groups"] } validated:NO];
 
-    // Invalid access group entitlement should still allow querying com.apple.token
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    // Invalid access group entitlement should still allow querying com.apple.token, if tokens are enabled
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    } else {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
+    }
 
     // But write-access is forbidden,
     XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
     XCTAssertEqual(SecItemAdd((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
     XCTAssertEqual(SecItemDelete((CFDictionaryRef)params), errSecMissingEntitlement);
 
-    // Explicitly referring to com.apple.token should work fine too.
     params = @{ (id)kSecUseDataProtectionKeychain: @YES,
                 (id)kSecClass: (id)kSecClassGenericPassword,
                 (id)kSecAttrLabel: @"label",
                 (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, };
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    } else {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecMissingEntitlement);
+    }
 }
 #endif // TARGET_OS_OSX
 
 - (void)testTokenItemsGroup {
     NSDictionary *params;
 
+    [self setEntitlements:@{
+#if TARGET_OS_OSX
+        @"com.apple.application-identifier": @"com.apple.test-app-identifier",
+#else
+        @"application-identifier": @"com.apple.test-app-identifier",
+#endif
+        @"keychain-access-groups": @[ @"com.apple.token" ],
+    } validated:YES];
+
     // Add token items for testing into the keychain.
     NSArray *tokenItems = @[ @{
                                  (id)kSecClass: (id)kSecClassGenericPassword,
                                  (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken,
                                  (id)kSecAttrLabel: @"label",
                                  } ];
-    XCTAssertEqual(SecItemUpdateTokenItems(@"com.apple.testtoken", (__bridge CFArrayRef)tokenItems), errSecSuccess);
-
-    [self setEntitlements:@{ @"com.apple.application-identifier": @"com.apple.test-app-identifier" } validated:YES];
+    XCTAssertEqual(SecItemUpdateTokenItemsForAccessGroups(@"com.apple.testtoken", (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)tokenItems), errSecSuccess);
 
-    // Query without explicit access group, should find item on macOS and not find it on iOS.
+    // Query should find items, because we have token access group in entitlements.
     params = @{ (id)kSecUseDataProtectionKeychain: @YES,
                 (id)kSecClass: (id)kSecClassGenericPassword,
                 (id)kSecAttrLabel: @"label", };
+    if (os_feature_enabled(CryptoTokenKit, UseTokens)) {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecSuccess);
+    } else {
+        XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
+    }
+
 #if TARGET_OS_IPHONE
+    // Not having access group in entitlements will not find items.
+    [self setEntitlements:@{
+        @"application-identifier": @"com.apple.test-app-identifier",
+    } validated:YES];
     XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecItemNotFound);
-#else
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecSuccess);
 #endif
 
-    // Query with explicit AG should work the same on both platforms.
-    params = @{ (id)kSecUseDataProtectionKeychain: @YES,
-                (id)kSecClass: (id)kSecClassGenericPassword,
-                (id)kSecAttrLabel: @"label",
-                (id)kSecAttrAccessGroup: (id)kSecAttrAccessGroupToken, };
-    XCTAssertEqual(SecItemCopyMatching((CFDictionaryRef)params, NULL), errSecSuccess);
-
     // Delete all test token items.
-    SecItemUpdateTokenItems(@"com.apple.testtoken", (__bridge CFArrayRef)@[]);
+    [self setEntitlements:@{
+#if TARGET_OS_OSX
+        @"com.apple.application-identifier": @"com.apple.test-app-identifier",
+#else
+        @"application-identifier": @"com.apple.test-app-identifier",
+#endif
+        @"keychain-access-groups": @[ @"com.apple.token" ],
+    } validated:YES];
+    SecItemUpdateTokenItemsForAccessGroups(@"com.apple.testtoken", (__bridge CFArrayRef)@[(id)kSecAttrAccessGroupToken], (__bridge CFArrayRef)@[]);
 }
 
 - (void)testEntitlementForExplicitAccessGroupLacking {
index 4e1e27d9fb520c51d186085f9c778066cdde4a07..4335da6a83458665af21a63212c5a397b3df7750 100644 (file)
@@ -48,7 +48,7 @@ typedef enum {
 @property keyclass_t keyclassUsedForAKSDecryption;
 
 @property SFAESKeySpecifier* keySpecifier;
-@property SFAESKey* fakeAKSKey;
+@property NSData* fakeAKSKey;
 
 @property id keychainPartialMock;
 
@@ -56,7 +56,7 @@ typedef enum {
 
 - (void)setEntitlements:(NSDictionary<NSString *, id> *)entitlements validated:(BOOL)validated;
 
-- (NSData*)getDatabaseKeyDataithError:(NSError**)error;
+- (NSData*)getDatabaseKeyDataWithError:(NSError**)error;
 
 @end
 
index bab2a47caae6fa9516f3c557a7f02ae59222f77d..1ac55ceb84cc9fcdd5873976200a0232124a6fee 100644 (file)
@@ -27,6 +27,7 @@
 #import "CKKS.h"
 #import "SecDbKeychainItemV7.h"
 #import "SecDbKeychainMetadataKeyStore.h"
+#import "SecDbBackupManager_Internal.h"
 #import "SecAKSObjCWrappers.h"
 #import "SecItemPriv.h"
 #import "SecTaskPriv.h"
 #import <SecurityFoundation/SFKeychain.h>
 #import <XCTest/XCTest.h>
 #import <OCMock/OCMock.h>
+#include <corecrypto/ccpbkdf2.h>
+#include <corecrypto/ccsha2.h>
+#include <corecrypto/ccaes.h>
+#include <corecrypto/ccmode.h>
+#include <corecrypto/ccwrap.h>
+#include "CheckV12DevEnabled.h"
+
+void* testlist = NULL;
+
+// TODO: Switch to '1' closer to deployment, but leave at '0' for now to test not breaking people
+static int testCheckV12DevEnabled(void) {
+    return 0;
+}
 
 #if USE_KEYSTORE
 
 @implementation KeychainXCTest {
     id _keychainPartialMock;
     CFArrayRef _originalAccessGroups;
+    bool _simcrashenabled;
 }
 
 @synthesize keychainPartialMock = _keychainPartialMock;
 + (void)setUp
 {
     [super setUp];
-    
     SecCKKSDisable();
+    // Do not want test code to be allowed to init real keychain!
+    secd_test_setup_temp_keychain("keychaintestthrowaway", NULL);
     securityd_init(NULL);
 }
 
 - (void)setUp
 {
-    __security_simulatecrash_enable(true);
+    _simcrashenabled = __security_simulatecrash_enabled();
+    __security_simulatecrash_enable(false);
 
     [super setUp];
     
     
     self.keySpecifier = [[SFAESKeySpecifier alloc] initWithBitSize:SFAESKeyBitSize256];
     [self setNewFakeAKSKey:[NSData dataWithBytes:"1234567890123456789012345678901" length:32]];
-
-    [SecDbKeychainMetadataKeyStore resetSharedStore];
     
     self.mockSecDbKeychainItemV7 = OCMClassMock([SecDbKeychainItemV7 class]);
     [[[self.mockSecDbKeychainItemV7 stub] andCall:@selector(decryptionOperation) onObject:self] decryptionOperation];
     id refKeyMock = OCMClassMock([SecAKSRefKey class]);
     [[[refKeyMock stub] andCall:@selector(alloc) onObject:[FakeAKSRefKey class]] alloc];
 
+    checkV12DevEnabled = testCheckV12DevEnabled;
     NSArray* partsOfName = [self.name componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" ]"]];
+    // Calls SecKeychainDbReset which also resets metadata keys and backup manager
     secd_test_setup_temp_keychain([partsOfName[1] UTF8String], NULL);
 
     _originalAccessGroups = SecAccessGroupsGetCurrent();
+    SecResetLocalSecuritydXPCFakeEntitlements();
 }
 
 - (void)tearDown
 {
     [self.mockSecDbKeychainItemV7 stopMocking];
     [self.mockSecAKSObjCWrappers stopMocking];
+    [self resetEntitlements];
     SecAccessGroupsSetCurrent(_originalAccessGroups);
+    __security_simulatecrash_enable(_simcrashenabled);
+
+    [super tearDown];
+}
 
++ (void)tearDown {
+    SecResetLocalSecuritydXPCFakeEntitlements();
     [super tearDown];
 }
 
 
 - (bool)setNewFakeAKSKey:(NSData*)newKeyData
 {
-    NSError* error = nil;
-    self.fakeAKSKey = [[SFAESKey alloc] initWithData:newKeyData specifier:self.keySpecifier error:&error];
-    XCTAssertNil(error, "Should be no error making a fake AKS key");
-    XCTAssertNotNil(self.fakeAKSKey, "Should have received a fake AKS key");
+    self.fakeAKSKey = newKeyData;
     return true;
 }
 
+- (NSData*)wrapKey:(NSData*)plaintextKey withKey:(NSData*)wrappingKey
+{
+    const struct ccmode_ecb *ecb_mode = ccaes_ecb_encrypt_mode();
+    ccecb_ctx_decl(ccecb_context_size(ecb_mode), key);
+    NSMutableData* wrappedKey = [NSMutableData dataWithLength:ccwrap_wrapped_size(plaintextKey.length)];
+
+    ccecb_init(ecb_mode, key, wrappingKey.length, wrappingKey.bytes);
+
+    size_t obytes = 0;
+    int wrap_status = ccwrap_auth_encrypt(ecb_mode, key, plaintextKey.length, plaintextKey.bytes,
+                                          &obytes, wrappedKey.mutableBytes);
+    if (wrap_status == 0) {
+        assert(obytes == wrappedKey.length);
+    } else {
+        wrappedKey = nil;
+    }
+
+    ccecb_ctx_clear(ccecb_context_size(ecb_mode), key);
+    return wrappedKey;
+}
+
+- (NSData*)unwrapKey:(NSData*)ciphertextKey withKey:(NSData*)wrappingKey
+{
+    const struct ccmode_ecb *ecb_mode = ccaes_ecb_decrypt_mode();
+    ccecb_ctx_decl(ccecb_context_size(ecb_mode), key);
+    NSMutableData *unwrappedKey = [NSMutableData dataWithLength:ccwrap_unwrapped_size(ciphertextKey.length)];
+
+    ccecb_init(ecb_mode, key, wrappingKey.length, wrappingKey.bytes);
+
+    size_t obytes = 0;
+    int status = ccwrap_auth_decrypt(ecb_mode, key, ciphertextKey.length, ciphertextKey.bytes,
+                                            &obytes, unwrappedKey.mutableBytes);
+    if (status == 0) {
+        assert(obytes == (size_t)[unwrappedKey length]);
+    } else {
+        unwrappedKey = nil;
+    }
+
+    ccecb_ctx_clear(ccecb_context_size(ecb_mode), key);
+    return unwrappedKey;
+}
+
 - (bool)fakeAKSEncryptWithKeybag:(keybag_handle_t)keybag
                         keyclass:(keyclass_t)keyclass
                        plaintext:(NSData*)plaintext
         }
         return false;
     }
-    
-    uint32_t keyLength = (uint32_t)plaintext.length;
-    const uint8_t* keyBytes = plaintext.bytes;
-    
-    NSData* dataToEncrypt = [NSData dataWithBytes:keyBytes length:keyLength];
-    NSError* localError = nil;
-    
-    SFAuthenticatedEncryptionOperation* encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:self.keySpecifier];
-    encryptionOperation.authenticationCodeLength = 8;
-    SFAuthenticatedCiphertext* ciphertext = [encryptionOperation encrypt:dataToEncrypt withKey:self.fakeAKSKey error:&localError];
-    
-    if (error) {
-        *error = localError;
+
+    if (keybag == KEYBAG_DEVICE) {
+        XCTAssertLessThanOrEqual(ciphertextOut.length, APPLE_KEYSTORE_MAX_SYM_WRAPPED_KEY_LEN);
+    } else {    // this'll do for now: assume non-device bags are asymmetric backup bags
+        XCTAssertLessThanOrEqual(ciphertextOut.length, APPLE_KEYSTORE_MAX_ASYM_WRAPPED_KEY_LEN);
     }
 
-    if (ciphertext) {
-        void* wrappedKeyMutableBytes = ciphertextOut.mutableBytes;
-        memcpy(wrappedKeyMutableBytes, ciphertext.ciphertext.bytes, 32);
-        memcpy(wrappedKeyMutableBytes + 32, ciphertext.initializationVector.bytes, 32);
-        memcpy(wrappedKeyMutableBytes + 64, ciphertext.authenticationCode.bytes, 8);
-        
+    NSData* wrappedKey = [self wrapKey:plaintext withKey:self.fakeAKSKey];
+    if (ciphertextOut.length >= wrappedKey.length) {
+        memcpy(ciphertextOut.mutableBytes, wrappedKey.bytes, wrappedKey.length);
+        ciphertextOut.length = wrappedKey.length;   // simulate ks_crypt behavior
         if (self.simulateRolledAKSKey && outKeyclass) {
             *outKeyclass = keyclass | (key_class_last + 1);
         } else if (outKeyclass) {
             *outKeyclass = keyclass;
         }
-        
         return true;
-    }
-    else {
+    } else {
+        XCTFail(@"output buffer too small for wrapped key");
         return false;
     }
 }
         // let's make decryption fail like it would if this were an old metadata key entry made with a generational AKS key, but we didn't store that info in the database
         return false;
     }
-    
-    const uint8_t* wrappedKeyBytes = ciphertextIn.bytes;
-    
-    NSData* ciphertextData = [NSData dataWithBytes:wrappedKeyBytes length:32];
-    NSData* ivData = [NSData dataWithBytes:wrappedKeyBytes + 32 length:32];
-    NSData* authCodeData = [NSData dataWithBytes:wrappedKeyBytes + 64 length:8];
-    SFAuthenticatedCiphertext* ciphertext = [[SFAuthenticatedCiphertext alloc] initWithCiphertext:ciphertextData authenticationCode:authCodeData initializationVector:ivData];
-    
-    NSError* localError = nil;
-    
-    SFAuthenticatedEncryptionOperation* encryptionOperation = [[SFAuthenticatedEncryptionOperation alloc] initWithKeySpecifier:self.keySpecifier];
-    encryptionOperation.authenticationCodeLength = 8;
-    NSData* decryptedData = [encryptionOperation decrypt:ciphertext withKey:self.fakeAKSKey error:&localError];
-
-    // in real securityd, we go through AKS rather than SFCryptoServices
-    // we need to translate the error for proper handling
-    if ([localError.domain isEqualToString:SFCryptoServicesErrorDomain] && localError.code == SFCryptoServicesErrorDecryptionFailed) {
-        if (!self.simulateRolledAKSKey && keyclass > key_class_last) {
-            // for this case we want to simulate what happens when we try decrypting with a rolled keyclass on a device which has never been rolled, which is it ends up with a NotPermitted error from AKS which the security layer translates as locked keybag
-            localError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInteractionNotAllowed userInfo:nil];
-        }
-        else {
-            localError = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecDecode userInfo:nil];
-        }
-    }
-    
-    if (error) {
-        *error = localError;
-    }
-    
+
     self.keyclassUsedForAKSDecryption = keyclass;
-    if (decryptedData && decryptedData.length <= plaintext.length) {
-        memcpy(plaintext.mutableBytes, decryptedData.bytes, decryptedData.length);
-        plaintext.length = decryptedData.length;
+    NSData* unwrappedKey = [self unwrapKey:ciphertextIn withKey:self.fakeAKSKey];
+    if (unwrappedKey && plaintext.length >= unwrappedKey.length) {
+        memcpy(plaintext.mutableBytes, unwrappedKey.bytes, unwrappedKey.length);
+        plaintext.length = unwrappedKey.length;     // simulate ks_crypt behavior
         self.didAKSDecrypt = YES;
         return true;
-    }
-    else {
+    } else if (unwrappedKey) {
+        XCTFail(@"output buffer too small for unwrapped key");
+        return false;
+    } else {
+        if (error && !self.simulateRolledAKSKey && keyclass > key_class_last) {
+            // for this case we want to simulate what happens when we try decrypting with a rolled keyclass on a device which has never been rolled, which is it ends up with a NotPermitted error from AKS which the security layer translates as locked keybag
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecInteractionNotAllowed userInfo:nil];
+        }
+        else if (error) {
+            *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:errSecDecode userInfo:nil];
+        }
         return false;
     }
 }
 
-- (NSData*)getDatabaseKeyDataithError:(NSError**)error
+- (NSData*)getDatabaseKeyDataWithError:(NSError**)error
 {
     if (_lockState == LockStateUnlocked) {
         return [NSData dataWithBytes:"1234567890123456789012345678901" length:32];
 
 // Mock SecTask entitlement retrieval API, so that we can test access group entitlement parsing code in SecTaskCopyAccessGroups()
 static NSDictionary *currentEntitlements = nil;
-static BOOL currentEntitlementsValidated = false;
-static NSArray *currentAccessGroups = nil;
+static BOOL currentEntitlementsValidated = YES;
 
 CFTypeRef SecTaskCopyValueForEntitlement(SecTaskRef task, CFStringRef entitlement, CFErrorRef *error) {
     id value = currentEntitlements[(__bridge id)entitlement];
@@ -338,8 +371,13 @@ Boolean SecTaskEntitlementsValidated(SecTaskRef task) {
     currentEntitlements = entitlements;
     currentEntitlementsValidated = validated;
     id task = CFBridgingRelease(SecTaskCreateFromSelf(kCFAllocatorDefault));
-    currentAccessGroups = CFBridgingRelease(SecTaskCopyAccessGroups((__bridge SecTaskRef)task));
-    SecAccessGroupsSetCurrent((__bridge CFArrayRef)currentAccessGroups);
+    NSArray *currentAccessGroups = CFBridgingRelease(SecTaskCopyAccessGroups((__bridge SecTaskRef)task));
+    SecAccessGroupsSetCurrent((__bridge CFArrayRef)currentAccessGroups);    // SetCurrent retains the access groups
+}
+
+- (void)resetEntitlements {
+    currentEntitlements = nil;
+    currentEntitlementsValidated = YES;
 }
 
 @end
index 62aa116eccf5ac81bec30a86e89d56d36f3c05c9..cda02311d9436af5f8faa022819fe10d38070586 100644 (file)
 {
     [super setUp];
     self.keychainPartialMock = OCMPartialMock([(SFKeychainServer*)[[self.class serverProxyWithError:nil] server] _keychain]);
-    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
+    [[[[self.keychainPartialMock stub] andCall:@selector(getDatabaseKeyDataWithError:) onObject:self] ignoringNonObjectArgs] _onQueueGetDatabaseKeyDataWithError:NULL];
 
     _credentialStore = [[SFCredentialStore alloc] _init];
 }
diff --git a/secdxctests/secdxctests-entitlements.plist b/secdxctests/secdxctests-entitlements.plist
new file mode 100644 (file)
index 0000000..0614e94
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.secdxctests</string>
+       <key>application-identifier</key>
+       <string>com.apple.secdxctests</string>
+       <key>com.apple.keystore.access-keychain-keys</key>
+       <true/>
+       <key>com.apple.keystore.lockassertion</key>
+       <true/>
+       <key>com.apple.private.associated-domains</key>
+       <true/>
+       <key>com.apple.private.necp.match</key>
+       <true/>
+       <key>com.apple.mkb.usersession.info</key>
+       <true/>
+       <key>seatbelt-profiles</key>
+       <array>
+               <string>securityd</string>
+       </array>
+       <key>com.apple.security.app-sandbox</key>
+       <false/>
+       <key>com.apple.security.get-task-allow</key>
+       <true/>
+       <key>keychain-access-groups</key>
+       <array>
+               <string>SecDbBackupManager-UnitTests</string>
+       </array>
+</dict>
+</plist>
+
index 9dd2005d9e833a1fb7cedcd1137b6d374e84511f..46b854ff187f4083fde7e5cf76889cf65e6897f9 100644 (file)
@@ -47,10 +47,11 @@ __BEGIN_DECLS
  Note that iOS and macOS uses different value for the same constant.
  */
 
+#define kSecEntitlementAppleApplicationIdentifier CFSTR("com.apple.application-identifier")
+#define kSecEntitlementBasicApplicationIdentifier CFSTR("application-identifier")
 #if TARGET_OS_IPHONE
-#define kSecEntitlementApplicationIdentifier CFSTR("application-identifier")
+#define kSecEntitlementApplicationIdentifier kSecEntitlementBasicApplicationIdentifier
 #else
-#define kSecEntitlementAppleApplicationIdentifier CFSTR("com.apple.application-identifier")
 #define kSecEntitlementApplicationIdentifier kSecEntitlementAppleApplicationIdentifier
 #endif
 
@@ -151,6 +152,9 @@ __BEGIN_DECLS
 /* Entitlement to allow use of CKKS plaintext fields */
 #define kSecEntitlementPrivateCKKSPlaintextFields CFSTR("com.apple.private.ckks.plaintextfields")
 
+/* Entitlement to allow use of inet expansion fields */
+#define kSecEntitlementPrivateInetExpansionFields CFSTR("com.apple.private.keychain.inet_expansion_fields")
+
 /* Entitlement to allow use of CKKS 'current item' changing SPI */
 #define kSecEntitlementPrivateCKKSWriteCurrentItemPointers CFSTR("com.apple.private.ckks.currentitempointers_write")
 
@@ -165,12 +169,24 @@ __BEGIN_DECLS
 /* Entitlement to allow executing keychain control actions */
 #define kSecEntitlementKeychainControl CFSTR("com.apple.private.keychain.keychaincontrol")
 
+/* Entitlement to allow deletion of app clip keychain items */
+#define kSecEntitlementPrivateAppClipDeletion CFSTR("com.apple.private.keychain.appclipdeletion")
+
+/* Entitlements to allow executing SecItemUpdateTokenItemsForAccessGroups SPI */
+#define kSecEntitlementUpdateTokenItems CFSTR("com.apple.private.keychain.allow-update-tokens")
+
+/* Entitlement to control access to login keychain master key stashing (loginwindow) */
+#define kSecEntitlementPrivateStash CFSTR("com.apple.private.securityd.stash")
+
 #if __OBJC__
 /* Entitlement to control use of OT */
 #define kSecEntitlementPrivateOctagon @"com.apple.private.octagon"
 
 /* Entitlement to control use of Escrow Update */
 #define kSecEntitlementPrivateEscrowRequest @"com.apple.private.escrow-update"
+
+/* Entitlement for macOS securityd to connect to stash agent */
+#define kSecEntitlementPrivateStashService @"com.apple.private.securityd.stash-agent-client"
 #endif
 
 __END_DECLS
index a73416c7e31e113a349cbea5937bb8860e5f6df4..4b38f13d94f06551c15b7724dac18a9341f10f00 100644 (file)
@@ -25,6 +25,7 @@
 #include "SecTaskPriv.h"
 
 #include <utilities/debugging.h>
+#include <utilities/entitlements.h>
 
 #include <AssertMacros.h>
 #include <CoreFoundation/CFRuntime.h>
@@ -237,46 +238,44 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error)
     uint32_t bufferlen;
     int ret;
 
-    
     ret = csops_task(task, CS_OPS_ENTITLEMENTS_BLOB, &header, sizeof(header));
     /* Any other combination means no entitlements */
-       if (ret == -1) {
-               if (errno != ERANGE) {
+    if (ret == -1) {
+        if (errno != ERANGE) {
             int entitlementErrno = errno;
 
-                       uint32_t cs_flags = -1;
+            uint32_t cs_flags = -1;
             if (-1 == csops_task(task, CS_OPS_STATUS, &cs_flags, sizeof(cs_flags))) {
                 syslog(LOG_NOTICE, "Failed to get cs_flags, error=%d", errno);
             }
 
-                       if (cs_flags != 0) {    // was signed
-
-                               pid_t pid;
-                               audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
-                   syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, pid=%d", entitlementErrno, cs_flags, pid); // to ease diagnostics
-
-                               CFStringRef description = SecTaskCopyDebugDescription(task);
-                               char *descriptionBuf = NULL;
-                               CFIndex descriptionSize = CFStringGetLength(description) * 4;
-                               descriptionBuf = (char *)malloc(descriptionSize);
-                               if (!CFStringGetCString(description, descriptionBuf, descriptionSize, kCFStringEncodingUTF8)) {
-                                       descriptionBuf[0] = 0;
-                               }
-
-                               syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf);
-                               CFReleaseNull(description);
-                               free(descriptionBuf);
-                       }
-                       task->lastFailure = entitlementErrno;   // was overwritten by csops_task(CS_OPS_STATUS) above
-
-                       // EINVAL is what the kernel says for unsigned code, so we'll have to let that pass
-                       if (entitlementErrno == EINVAL) {
-                               task->entitlementsLoaded = true;
-                               return true;
-                       }
-                       ret = entitlementErrno; // what really went wrong
-                       goto out;               // bail out
-               }
+            if (cs_flags != 0) {       // was signed
+                pid_t pid;
+                audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
+                syslog(LOG_NOTICE, "SecTaskLoadEntitlements failed error=%d cs_flags=%x, pid=%d", entitlementErrno, cs_flags, pid);    // to ease diagnostics
+
+                CFStringRef description = SecTaskCopyDebugDescription(task);
+                char *descriptionBuf = NULL;
+                CFIndex descriptionSize = CFStringGetLength(description) * 4;
+                descriptionBuf = (char *)malloc(descriptionSize);
+                if (!CFStringGetCString(description, descriptionBuf, descriptionSize, kCFStringEncodingUTF8)) {
+                    descriptionBuf[0] = 0;
+                }
+
+                syslog(LOG_NOTICE, "SecTaskCopyDebugDescription: %s", descriptionBuf);
+                CFReleaseNull(description);
+                free(descriptionBuf);
+            }
+            task->lastFailure = entitlementErrno;      // was overwritten by csops_task(CS_OPS_STATUS) above
+
+            // EINVAL is what the kernel says for unsigned code, so we'll have to let that pass
+            if (entitlementErrno == EINVAL) {
+                task->entitlementsLoaded = true;
+                return true;
+            }
+            ret = entitlementErrno;    // what really went wrong
+            goto out;          // bail out
+        }
         bufferlen = ntohl(header.length);
         /* check for insane values */
         if (bufferlen > 1024 * 1024 || bufferlen < 8) {
@@ -298,10 +297,17 @@ static bool SecTaskLoadEntitlements(SecTaskRef task, CFErrorRef *error)
         entitlements = (CFMutableDictionaryRef) CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListMutableContainers, NULL, error);
         CFReleaseNull(data);
 
-        if((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){
+        if ((entitlements==NULL) || (CFGetTypeID(entitlements)!=CFDictionaryGetTypeID())){
             ret = EDOM;        // don't use EINVAL here; it conflates problems with syscall error returns
             goto out;
         }
+
+        bool entitlementsModified = updateCatalystEntitlements(entitlements);
+        if (entitlementsModified) {
+            pid_t pid;
+            audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL);
+            secinfo("SecTask", "Fixed catalyst entitlements for process %d", pid);
+        }
     }
 
     task->entitlements = entitlements ? CFRetain(entitlements) : NULL;
index c1bf28a0fae895cea9e7ec97612ccb3ea3484073..5a14de3cd177fcbf1bed4161d37172433ad257e9 100644 (file)
@@ -127,7 +127,7 @@ CFStringRef SecTaskCopySigningIdentifier(SecTaskRef task, CFErrorRef *error);
 */
 
 uint32_t SecTaskGetCodeSignStatus(SecTaskRef task)
-    API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0), iosmac(11.0)) SPI_AVAILABLE(macos(10.5));
+    API_AVAILABLE(ios(10.0), watchos(3.0), tvos(10.0), macCatalyst(11.0)) SPI_AVAILABLE(macos(10.5));
 
 
 CF_IMPLICIT_BRIDGING_DISABLED
diff --git a/sectask/SystemEntitlements.h b/sectask/SystemEntitlements.h
new file mode 100644 (file)
index 0000000..c854429
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SystemEntitlements_h
+#define SystemEntitlements_h
+
+/*
+ This file collects entitlements defined on the platform and in use by Security.
+ */
+
+#include <CoreFoundation/CFString.h>
+
+__BEGIN_DECLS
+
+/* Entitlement denoting client task is an App Clip */
+#define kSystemEntitlementOnDemandInstallCapable CFSTR("com.apple.developer.on-demand-install-capable")
+
+__END_DECLS
+
+#endif /* SystemEntitlements_h */
index 26672e55bcd076d468ba62bb60a1a5298db8bdc8..1045cdb86149278ebe9352ed3ea8d3d0254e6867 100644 (file)
@@ -50,7 +50,8 @@
        (global-name "com.apple.PowerManagement.control")
        (global-name "com.apple.security.syspolicy")
        (global-name "com.apple.security.agent")
-       (global-name "com.apple.security.agent.login"))
+       (global-name "com.apple.security.agent.login")
+       (global-name "com.apple.security.KeychainStasher"))
 
 (allow ipc-posix-shm 
     (ipc-posix-name "com.apple.AppleDatabaseChanged")
index 43ebb292be4a918ff0043342ff76e1ff4d2d2556..4d89a2bc10025cf7bac6c528faf49dfecd10ae2d 100644 (file)
                189D462D166AC95C001D8533 /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
-                               LastUpgradeCheck = 1120;
+                               LastUpgradeCheck = 1200;
                                ORGANIZATIONNAME = Apple;
                        };
                        buildConfigurationList = 189D4630166AC95C001D8533 /* Build configuration list for PBXProject "securityd_service" */;
                1843240F1714797D00196B52 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++2a";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                COMBINE_HIDPI_IMAGES = YES;
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu2x;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "DEBUG=1",
                                        "$(inherited)",
                184324101714797D00196B52 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++2a";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_NS_ASSERTIONS = NO;
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu2x;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                                INSTALL_PATH = /usr/local/lib;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                BUNDLE_LOADER = /usr/libexec/UserEventAgent;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++2a";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_ENUM_CONVERSION = YES;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                COMBINE_HIDPI_IMAGES = YES;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu2x;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                BUNDLE_LOADER = /usr/libexec/UserEventAgent;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++2a";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
                                CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
                                COMBINE_HIDPI_IMAGES = YES;
                                ENABLE_NS_ASSERTIONS = NO;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
+                               GCC_C_LANGUAGE_STANDARD = gnu2x;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
                                GCC_WARN_UNDECLARED_SELECTOR = YES;
index 496e3a052d12cd5d7aee81a5e7b93b63a8c9d427..be7d6e0ed218292b9b57f82b6def8e354822e230 100644 (file)
@@ -14,7 +14,7 @@
 #include <os/log.h>
 #include <stdio.h>
 #include <errno.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <unistd.h>
 #include <pwd.h>
 #include <uuid/uuid.h>
@@ -1356,9 +1356,7 @@ bool check_signature(xpc_connection_t connection)
 {
 #if !(DEBUG || RC_BUILDIT_YES)
     audit_token_t token;
-
     xpc_connection_get_audit_token(connection, &token);
-
     SecTaskRef task = SecTaskCreateWithAuditToken(NULL, token);
     if (task == NULL) {
         os_log(OS_LOG_DEFAULT, "failed getting SecTaskRef of the client");
@@ -1368,7 +1366,6 @@ bool check_signature(xpc_connection_t connection)
     uint32_t flags = SecTaskGetCodeSignStatus(task);
     /* check if valid and platform binary, but not platform path */
 
-
     if ((flags & (CS_VALID | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_VALID | CS_PLATFORM_BINARY)) {
                if (SecIsInternalRelease()) {
                        if ((flags & (CS_DEBUGGED | CS_PLATFORM_BINARY | CS_PLATFORM_PATH)) != (CS_DEBUGGED | CS_PLATFORM_BINARY)) {
@@ -1383,18 +1380,19 @@ bool check_signature(xpc_connection_t connection)
                }
     }
 
-    CFStringRef signingIdentity = SecTaskCopySigningIdentifier(task, NULL);
+    CFStringRef signingIdentifier = SecTaskCopySigningIdentifier(task, NULL);
     CFRelease(task);
-    if (signingIdentity == NULL) {
-        os_log(OS_LOG_DEFAULT, "client have no code sign identity");
+    if (signingIdentifier == NULL) {
+        os_log(OS_LOG_DEFAULT, "client has no code signing identifier");
         return false;
     }
 
-    bool res = CFEqual(signingIdentity, CFSTR("com.apple.securityd"));
-    CFRelease(signingIdentity);
+    bool res = CFEqual(signingIdentifier, CFSTR("com.apple.securityd"));
+    CFRelease(signingIdentifier);
 
-    if (!res)
-        os_log(OS_LOG_DEFAULT, "client is not not securityd");
+    if (!res) {
+        os_log(OS_LOG_DEFAULT, "client is not securityd");
+    }
 
     return res;
 #else
index fa8f8a107db8d037f328d5af5cc8a1ca318fdf48..ab0c1b1c2847d4503a7cb78dfd9e43ac75dd8298 100644 (file)
@@ -325,7 +325,7 @@ done:
 }
 
 int
-service_client_stash_get_key(service_context_t *context, void ** key, int * key_len)
+service_client_stash_get_key(service_context_t *context, void ** key, size_t * key_len)
 {
     int rc = KB_GeneralError;
     xpc_object_t message = NULL;
@@ -347,7 +347,7 @@ service_client_stash_get_key(service_context_t *context, void ** key, int * key_
         if (data) {
             *key = calloc(1u, data_len);
             memcpy(*key, data, data_len);
-            *key_len = (int)data_len;
+            *key_len = data_len;
         }
     }
 
index 293216fc567fc03004167795174fa7034f96b7b3..bd8f8c4dd753c98ce97a7065ce9fafb826886149 100644 (file)
@@ -44,7 +44,7 @@ int service_client_kb_unwrap_key(service_context_t *context, const void *wrapped
 
 int service_client_stash_set_key(service_context_t *context, const void * key, int key_len);
 int service_client_stash_load_key(service_context_t *context, const void * key, int key_len);
-int service_client_stash_get_key(service_context_t *context, void ** key, int * key_len);
+int service_client_stash_get_key(service_context_t *context, void ** key, size_t * key_len);
 
 #if defined(__cplusplus)
 }
index 155c8072a33c15411d9c7d32bf7352d9a16a8e62..eb061d359374c1256f521c092799dd4abafa7b83 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 #include <errno.h>
-#include <assert.h>
+#include <security_utilities/simulatecrash_assert.h>
 #include <stdio.h>                  // vsnprintf()
 #include <stdarg.h>                 // va_start(), et al.
 #include <syslog.h>
index fbd703a1ce9034465627f56466b2ef1cdab18fe2..3da55c7f272835dad134f5877e6764bead8bce7c 100644 (file)
@@ -132,10 +132,11 @@ CredentialImpl::merge(const CredentialImpl &other)
 {
     // try to ensure that the credentials are the same type
     assert(mRight == other.mRight);
-    if (mRight)
+    if (mRight) {
         assert(mName == other.mName);
-    else 
+    } else {
         assert(mUid == other.mUid);
+    }
 
     if (other.mValid && (!mValid || mCreationTime < other.mCreationTime))
     {
index 170a43cf90647f33c9947a9eb89f98838e50d580..bcdec0215271552b5cc472e08881f88fe210f07d 100644 (file)
 //  is locked or when the Session dies, whichever happens earlier.
 // There is (as yet) no global-scope Database object for Keychain databases.
 //
+
+#define __STDC_WANT_LIB_EXT1__ 1
+#include <string.h>
+
 #include "kcdatabase.h"
 #include "agentquery.h"
 #include "kckey.h"
@@ -44,6 +48,7 @@
 #include "session.h"
 #include "notifications.h"
 #include "SecRandom.h"
+#include "keychainstasherinterface.h"
 #include <vector>           // @@@  4003540 workaround
 #include <security_cdsa_utilities/acl_any.h>   // for default owner ACLs
 #include <security_cdsa_utilities/cssmendian.h>
@@ -875,32 +880,66 @@ void KeychainDatabase::makeUnlocked(const AccessCredentials *cred, bool unlockKe
        assert(mValidData);
 }
 
-//
-// Invoke the securityd_service to retrieve the keychain master
-// key from the AppleFDEKeyStore.
-//
+/**
+ Invoke securityd_service to load the keybag and retrieve the masterkey.
+ Also load masterkey from KeychainStasher and compare to make sure new stash works properly
+ */
 void KeychainDatabase::stashDbCheck()
-{    
+{
+    secnotice("KCdb", "Loading stashed key");
     CssmAutoData masterKey(Allocator::standard(Allocator::sensitive));
     CssmAutoData encKey(Allocator::standard(Allocator::sensitive));
 
-    // Fetch the key
-    int rc = 0;
-    void * stash_key = NULL;
-    int stash_key_len = 0;
+    // We're going to double-load during transition
+    void* s_key = NULL;
+    size_t s_keylen = 0;
     service_context_t context = common().session().get_current_service_context();
-    rc = service_client_stash_get_key(&context, &stash_key, &stash_key_len);
-    if (rc == 0) {
-        if (stash_key) {
-            masterKey.copy(CssmData((void *)stash_key,stash_key_len));
-            memset(stash_key, 0, stash_key_len);
-            free(stash_key);
-        }
+    // SIDE EFFECT: loads the user's keybag
+    int servicerc = service_client_stash_get_key(&context, &s_key, &s_keylen);
+    if (servicerc != KB_Success) {
+        secerror("KCdb: failed to load stash from securityd_service: %d", servicerc);
     } else {
-        secnotice("KCdb", "failed to get stash from securityd_service: %d", (int)rc);
-        CssmError::throwMe(rc);
+        secnotice("KCdb", "securityd_service claims get_key success");
     }
-    
+
+    void* a_key = NULL;
+    size_t a_keylen = 0;
+    OSStatus agentrc = loadKeyFromStashAgent(common().session().originatorUid(), &a_key, &a_keylen);
+    if (agentrc != errSecSuccess) {
+        secerror("KCdb: failed to load stash from KeychainStasher: %d", (int)agentrc);
+    } else {
+        secnotice("KCdb", "KeychainStasher claims loadKey success");
+    }
+
+    void* key = NULL;
+    size_t keylen = 0;
+    if (servicerc != KB_Success && agentrc != errSecSuccess) {
+        __security_simulatecrash(CFSTR("Both old and new stashes failed to load"), __sec_exception_code_BadStash);
+        CssmError::throwMe(servicerc);  // For now
+    } else if (servicerc == KB_Success && agentrc == errSecSuccess) {
+        if (s_keylen != a_keylen || a_keylen == 0) {
+            __security_simulatecrash(CFSTR("Stashed key lengths disagree or are zero"), __sec_exception_code_BadStash);
+        } else if (cc_cmp_safe(a_keylen, a_key, s_key) != 0) {
+            __security_simulatecrash(CFSTR("Keybytes disagree"), __sec_exception_code_BadStash);
+        }
+
+        key = a_key;
+        keylen = a_keylen;
+        memset_s(s_key, s_keylen, 0, s_keylen);
+        free(s_key);
+    } else if (servicerc == KB_Success) {
+        key = s_key;
+        keylen = s_keylen;
+    } else if (agentrc == errSecSuccess) {
+        key = a_key;
+        keylen = a_keylen;
+    }
+
+    masterKey.copy(CssmData(key, keylen));
+    memset_s(key, keylen, 0, keylen);
+    free(key);
+
+    secnotice("KCdb", "Retrieved stashed key, will establish");
     {
         StLock<Mutex> _(common());
 
@@ -914,8 +953,9 @@ void KeychainDatabase::stashDbCheck()
         hdr.blobFormat(CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
         common().setup(mBlob, key);
 
-        if (!decode())
+        if (!decode()) {
             CssmError::throwMe(CSSM_ERRCODE_OPERATION_AUTH_DENIED);
+        }
 
         common().get_encryption_key(encKey);
     }
@@ -934,11 +974,11 @@ void KeychainDatabase::stashDbCheck()
 //
 void KeychainDatabase::stashDb()
 {
+    secnotice("KCdb", "Let's stash a key");
     CssmAutoData data(Allocator::standard(Allocator::sensitive));
     
     {
         StLock<Mutex> _(common());
-
         if (!common().isValid()) {
             CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
         }
@@ -946,10 +986,28 @@ void KeychainDatabase::stashDb()
         CssmKey key = common().masterKey();
         data.copy(key.keyData());
     }
-    
+
+    // We're going to double-stash during transition
     service_context_t context = common().session().get_current_service_context();
-    int rc = service_client_stash_set_key(&context, data.data(), (int)data.length());
-    if (rc != 0) CssmError::throwMe(rc);
+    int servicerc = service_client_stash_set_key(&context, data.data(), (int)data.length());
+    if (servicerc != KB_Success) {
+        secerror("KCdb: securityd_service stash failed: %d", servicerc);
+    } else {
+        secnotice("KCdb", "securityd_service claims successful stash");
+    }
+
+    OSStatus agentrc = stashKeyWithStashAgent(common().session().originatorUid(), data.data(), data.length());
+    if (agentrc != errSecSuccess) {
+        secerror("KCdb: KeychainStasher stash failed: %d", (int)agentrc);
+    } else {
+        secnotice("KCdb", "KeychainStasher claims successful stash");
+    }
+
+    if (servicerc != KB_Success && agentrc != errSecSuccess) {
+        __security_simulatecrash(CFSTR("Both old and new stash mechanisms failed"), __sec_exception_code_BadStash);
+        CssmError::throwMe(servicerc);  // For now
+    }
+    secnotice("KCdb", "Key stashed");
 }
 
 //
diff --git a/securityd/src/keychainstasherinterface.h b/securityd/src/keychainstasherinterface.h
new file mode 100644 (file)
index 0000000..bac7bb5
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef keychainstasherinterface_h
+#define keychainstasherinterface_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+OSStatus stashKeyWithStashAgent(uid_t client, void const* keybytes, size_t keylen);
+OSStatus loadKeyFromStashAgent(uid_t client, void** keybytes, size_t* keylen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* keychainstasherinterface_h */
diff --git a/securityd/src/keychainstasherinterface.m b/securityd/src/keychainstasherinterface.m
new file mode 100644 (file)
index 0000000..dfb30b0
--- /dev/null
@@ -0,0 +1,88 @@
+#import <Foundation/Foundation.h>
+#import <Foundation/NSXPCConnection_Private.h>
+#import <Foundation/NSData_Private.h>
+
+#include "utilities/debugging.h"
+
+#import "KeychainStasherProtocol.h"
+#import "keychainstasherinterface.h"
+
+NSString* const KeychainStasherMachServiceName = @"com.apple.security.KeychainStasher";
+
+OSStatus stashKeyWithStashAgent(uid_t client, void const* keybytes, size_t keylen) {
+    if (!keybytes || keylen == 0) {
+        secerror("KeychainStasherInterface: No or truncated key, won't stash");
+        return errSecParam;
+    }
+
+    secnotice("KeychainStasherInterface", "Reaching out to agent to stash key");
+    __block OSStatus result = errSecInternalError;
+    @autoreleasepool {
+        NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:KeychainStasherMachServiceName options:0];
+        [connection _setTargetUserIdentifier: client];
+        connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(KeychainStasherProtocol)];
+        [connection resume];
+
+        id<KeychainStasherProtocol> proxy = [connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+            secerror("KeychainStasherInterface: errorhandler for agent called: %@", error);
+            result = errSecIO;
+        }];
+
+        NSData* key = [NSData _newZeroingDataWithBytes:keybytes length:keylen];
+        [proxy stashKey:key withReply:^(NSError* error) {
+            if (error) {
+                secerror("KeychainStasherInterface: agent failed to stash key: %@", error);
+                result = (int)error.code;
+            } else {
+                result = errSecSuccess;
+            }
+        }];
+
+        [connection invalidate];
+    }
+
+    if (result == errSecSuccess) {
+        secnotice("KeychainStasherInterface", "Successfully stashed key");
+    }
+    return result;
+}
+
+OSStatus loadKeyFromStashAgent(uid_t client, void** keybytes, size_t* keylen) {
+    if (!keybytes || !keylen) {
+        secerror("KeychainStasherInterface: No outparams for key, won't load");
+        return errSecParam;
+    }
+
+    secnotice("KeychainStasherInterface", "Reaching out to agent to retrieve key");
+    __block OSStatus result = errSecInternalError;
+    @autoreleasepool {
+        NSXPCConnection* connection = [[NSXPCConnection alloc] initWithMachServiceName:KeychainStasherMachServiceName options:0];
+        [connection _setTargetUserIdentifier: client];
+        connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(KeychainStasherProtocol)];
+        [connection resume];
+
+        id<KeychainStasherProtocol> proxy = [connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
+            secerror("KeychainStasherInterface: errorhandler for agent called: %@", error);
+            result = errSecIO;
+        }];
+
+        [proxy loadKeyWithReply:^(NSData *key, NSError *error) {
+            if (!key) {
+                secerror("KeychainStasherInterface: agent failed to load key: %@", error);
+                result = (int)error.code;
+                return;
+            }
+            *keybytes = calloc(1, key.length);
+            memcpy(*keybytes, key.bytes, key.length);
+            *keylen = key.length;
+            result = errSecSuccess;
+        }];
+
+        [connection invalidate];
+    }
+
+    if (result == errSecSuccess) {
+        secnotice("KeychainStasherInterface", "Successfully loaded key");
+    }
+    return result;
+}
index e94f68b1831e9835a4cb72444b4e3f6a03c04f34..d20356316104bfe14108d9522a116eb9be0d424a 100644 (file)
@@ -30,7 +30,6 @@
 #include "server.h"
 #include "session.h"
 #include "notifications.h"
-#include "pcscmonitor.h"
 #include "auditevents.h"
 #include "self.h"
 #include "util.h"
 //
 static void usage(const char *me) __attribute__((noreturn));
 static void handleSignals(int sig);
-static PCSCMonitor::ServiceLevel scOptions(const char *optionString);
-static bool legacyTokensEnabled(void);
 
 static Port gMainServerPort;
-PCSCMonitor *gPCSC;
 
 
 //
@@ -87,7 +83,7 @@ int main(int argc, char *argv[])
        // tell the keychain (client) layer to turn off the server interface
        SecKeychainSetServerMode();
 
-    const char *params[] = {"LEGACY_TOKENS_ENABLED", legacyTokensEnabled() ? "YES" : "NO", NULL};
+    const char *params[] = {"LEGACY_TOKENS_ENABLED", "NO", NULL};
     char* errorbuf = NULL;
     if (sandbox_init_with_parameters("com.apple.securityd", SANDBOX_NAMED, params, &errorbuf)) {
         seccritical("SecServer: unable to enter sandbox: %{public}s", errorbuf);
@@ -101,32 +97,24 @@ int main(int argc, char *argv[])
 
        // program arguments (preset to defaults)
        bool debugMode = false;
-       bool doFork = false;
-       bool reExecute = false;
        int workerTimeout = 0;
        int maxThreads = 0;
        bool waitForClients = true;
     bool mdsIsInstalled = false;
-       const char *tokenCacheDir = "/var/db/TokenCache";
-       const char *smartCardOptions = getenv("SMARTCARDS");
        uint32_t keychainAclDefault = CSSM_ACL_KEYCHAIN_PROMPT_INVALID | CSSM_ACL_KEYCHAIN_PROMPT_UNSIGNED;
        unsigned int verbose = 0;
        
        // check for the Installation-DVD environment and modify some default arguments if found
        if (access("/etc/rc.cdrom", F_OK) == 0) {       // /etc/rc.cdrom exists
         secnotice("SecServer", "starting in installmode");
-               smartCardOptions = "off";       // needs writable directories that aren't
        }
 
        // parse command line arguments
        extern char *optarg;
        extern int optind;
        int arg;
-       while ((arg = getopt(argc, argv, "c:dE:ims:t:T:uvWX")) != -1) {
+       while ((arg = getopt(argc, argv, ":dE:im:t:T:uvW")) != -1) {
                switch (arg) {
-               case 'c':
-                       tokenCacheDir = optarg;
-                       break;
                case 'd':
                        debugMode = true;
                        break;
@@ -139,9 +127,6 @@ int main(int argc, char *argv[])
         case 'm':
             mdsIsInstalled = true;
             break;
-               case 's':
-                       smartCardOptions = optarg;
-                       break;
                case 't':
                        if ((maxThreads = atoi(optarg)) < 0)
                                maxThreads = 0;
@@ -159,10 +144,6 @@ int main(int argc, char *argv[])
                case 'v':
                        verbose++;
                        break;
-               case 'X':
-                       doFork = true;
-                       reExecute = true;
-                       break;
                default:
                        usage(argv[0]);
                }
@@ -197,12 +178,8 @@ int main(int argc, char *argv[])
     }
     
     // turn into a properly diabolical daemon unless debugMode is on
-    if (!debugMode && getppid() != 1) {
-               if (!Daemon::incarnate(doFork))
-                       exit(1);        // can't daemonize
-               
-               if (reExecute && !Daemon::executeSelf(argv))
-                       exit(1);        // can't self-execute
+    if (!debugMode && getppid() != 1 && !Daemon::incarnate(false)) {
+               exit(1);        // can't daemonize
        }
         
     // arm signal handlers; code below may generate signals we want to see
@@ -253,10 +230,7 @@ int main(int argc, char *argv[])
        server.floatingThread(true);
        server.waitForClients(waitForClients);
        server.verbosity(verbose);
-    
-       // create a smartcard monitor to manage external token devices
-       gPCSC = new PCSCMonitor(server, tokenCacheDir, scOptions(smartCardOptions));
-    
+
     // create the RootSession object (if -d, give it graphics and tty attributes)
     RootSession rootSession(debugMode ? (sessionHasGraphicAccess | sessionHasTTY) : 0, server);
        
@@ -292,9 +266,7 @@ int main(int argc, char *argv[])
 static void usage(const char *me)
 {
        fprintf(stderr, "Usage: %s [-dwX]"
-               "\n\t[-c tokencache]                        smartcard token cache directory"
                "\n\t[-e equivDatabase]                                         path to code equivalence database"
-               "\n\t[-s off|on|conservative|aggressive]    smartcard operation level"
                "\n\t[-t maxthreads] [-T threadTimeout]     server thread control"
                "\n", me);
        exit(2);
@@ -303,44 +275,6 @@ static void usage(const char *me)
 const CFStringRef kTKSmartCardPreferencesDomain = CFSTR("com.apple.security.smartcard");
 const CFStringRef kTKLegacyTokendPreferencesKey  = CFSTR("Legacy");
 
-static bool legacyTokensEnabled() {
-    bool result = false;
-    CFPropertyListRef value = CFPreferencesCopyValue(kTKLegacyTokendPreferencesKey, kTKSmartCardPreferencesDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-    if (value) {
-        if (CFEqual(value, kCFBooleanTrue)) {
-            result = true;
-        }
-        CFRelease(value);
-    }
-    return result;
-}
-
-//
-// Translate strings (e.g. "conservative") into PCSCMonitor service levels
-//
-static PCSCMonitor::ServiceLevel scOptions(const char *optionString)
-{
-    if (!legacyTokensEnabled())
-        return PCSCMonitor::forcedOff;
-
-    if (optionString)
-               if (!strcmp(optionString, "off"))
-                       return PCSCMonitor::forcedOff;
-               else if (!strcmp(optionString, "on"))
-                       return PCSCMonitor::externalDaemon;
-               else if (!strcmp(optionString, "conservative"))
-                       return PCSCMonitor::externalDaemon;
-               else if (!strcmp(optionString, "aggressive"))
-                       return PCSCMonitor::externalDaemon;
-               else if (!strcmp(optionString, "external"))
-                       return PCSCMonitor::externalDaemon;
-               else
-                       usage("securityd");
-       else
-               return PCSCMonitor::externalDaemon;
-}
-
-
 //
 // Handle signals.
 // We send ourselves a message (through the "self" service), so actual
index 1efed3a503eb95d9de053e273671be2cdfac23b9..2b846445e863948df1725866492a95a7bd1369ef 100644 (file)
@@ -109,33 +109,6 @@ void Listener::sendNotification(Notification *message)
        }
 }
 
-
-//
-// Handle a port death or deallocation by removing all Listeners using that port.
-// Returns true iff we had one.
-//
-bool Listener::remove(Port port)
-{
-    typedef ListenerMap::iterator Iterator;
-    StLock<Mutex> _(setLock);
-    pair<Iterator, Iterator> range = listeners.equal_range(port);
-    if (range.first == range.second)
-        return false;  // not one of ours
-
-       assert(range.first != listeners.end());
-       secinfo("notify", "remove port %d", port.port());
-#if !defined(NDEBUG)
-    for (Iterator it = range.first; it != range.second; it++) {
-               assert(it->first == port);
-               secinfo("notify", "%p listener removed", it->second.get());
-       }
-#endif //NDEBUG
-    listeners.erase(range.first, range.second);
-       port.destroy();
-    return true;       // got it
-}
-
-
 //
 // Notification message objects
 //
index 4fd7f30322af0300e1b4ae4d9b9ca18d4aef9e9e..0097f34df873054f075a5cf2d5f467e8c59f6aa7 100644 (file)
@@ -74,7 +74,6 @@ public:
                NotificationEvent event, const CssmData &data);
     static void notify(NotificationDomain domain,
                NotificationEvent event, uint32 sequence, const CssmData &data, audit_token_t auditToken);
-    static bool remove(Port port);
 
     const NotificationDomain domain;
     const NotificationMask events;
index 9ab05df82cf75ed20e2f3bca061702bb09256366..496bff880f6642727aa543a9903169a933e280d1 100644 (file)
@@ -69,6 +69,9 @@ Process::Process(TaskPort taskPort,   const ClientSetupInfo *info, const CommonCri
                CssmError::throwMe(CSSMERR_CSSM_ADDIN_AUTHENTICATE_FAILED);
        }
        
+       // This is a "retain", matched by the deallocate call in ~Process
+       mTaskPort.modRefs(MACH_PORT_RIGHT_SEND, 1);
+
     // NB: ServerChild::find() should only be used to determine
     // *existence*.  Don't use the returned Child object for anything else, 
     // as it is not protected against its underlying process's destruction.  
index f569603b32cf419c85d547ab7b9269399e5f9f80..c825c10805dae59ee59208b177d3fca7105a0b8a 100644 (file)
@@ -10,5 +10,7 @@
        </array>
        <key>com.apple.private.security.storage.SystemKeychain</key>
        <true/>
+       <key>com.apple.private.securityd.stash-agent-client</key>
+       <true/>
 </dict>
 </plist>
index d510615c23aa803ccfaa7719c8604920ac5d3595..81fb8fced49926057aff6e1df70307e16fca81a4 100644 (file)
@@ -37,7 +37,6 @@
 #include <mach/mach_error.h>
 #include <security_utilities/ccaudit.h>
 #include <security_utilities/casts.h>
-#include "pcscmonitor.h"
 
 #include "agentquery.h"
 
@@ -330,11 +329,8 @@ kern_return_t self_server_handleSignal(mach_port_t sport,
 #endif //DEBUGDUMP
 
                case SIGUSR2:
-                       {
-                               extern PCSCMonitor *gPCSC;
-                               gPCSC->startSoftTokens();
-                               break;
-                       }
+            fprintf(stderr, "securityd ignoring SIGUSR2 received");
+            break;
 
                default:
                        assert(false);
@@ -509,6 +505,8 @@ bool Server::inDarkWake()
 //
 void Server::loadCssm(bool mdsIsInstalled)
 {
+    try {
+
        if (!mCssm->isActive()) {
                StLock<Mutex> _(*this);
         xpc_transaction_begin();
@@ -525,6 +523,23 @@ void Server::loadCssm(bool mdsIsInstalled)
                }
         xpc_transaction_end();
        }
+    } catch (const UnixError& err) {
+        secerror("load cssm failed: %s", err.what());
+        if (err.unixError() == ENOSPC) {
+            _exit(1);
+        } else {
+            abort();
+        }
+    } catch (const MacOSError& err) {
+        secerror("load cssm failed: %s", err.what());
+        abort();
+    } catch (const CommonError& err) {
+        secerror("load cssm failed: %d/%d", (int)err.osStatus(), err.unixError());
+        abort();
+    } catch (const std::exception& err) {
+        secerror("load cssm failed: %s", err.what());
+        abort();
+    }
 }
 
 
index c9d2f5d56edb255789212283243b0623b02055f0..f6aaaf054ef70a226e49bccbc03a2da7ca3ea7dd 100644 (file)
@@ -41,7 +41,6 @@
 #include <sys/wait.h>
 #include <grp.h>
 #include <pwd.h>
-#include <msgtracer_client.h>
 
 using namespace MDSClient;
 
@@ -436,15 +435,6 @@ void Token::notify(NotificationEvent event)
     free (data.data());
 }
 
-static void mt_log_ctk_tokend(const char *signature, const char *signature2)
-{
-    msgtracer_log_with_keys("com.apple.ctk.tokend", ASL_LEVEL_NOTICE,
-                            "com.apple.message.signature", signature,
-                            "com.apple.message.signature2", signature2,
-                            "com.apple.message.summarize", "YES",
-                            NULL);
-}
-
 //
 // Choose a token daemon for our card.
 //
@@ -503,7 +493,6 @@ RefPointer<TokenDaemon> Token::chooseTokend()
                        identifiers.append(";");
                identifiers.append(*i);
        }
-       mt_log_ctk_tokend(identifiers.c_str(), chosenIdentifier.c_str());
 
        return leader;
 }
index ff606b4c825618d199e8c07e6f29b20815e1f992..b2bd64d136c71631f99b40fcaf1e9e6888a7ea82 100644 (file)
@@ -51,6 +51,7 @@
 #include <Security/AuthorizationTagsPriv.h>
 #include <AssertMacros.h>
 #include <security_utilities/errors.h>
+#include <Security/SecEntitlements.h>
 
 #include <CoreFoundation/CFNumber.h>
 #include <CoreFoundation/CFDictionary.h>
@@ -65,7 +66,7 @@
 #define BEGIN_IPCN     *rcode = CSSM_OK; try {
 #define BEGIN_IPC(name)        BEGIN_IPCN RefPointer<Connection> connRef(&Server::connection(replyPort, auditToken)); \
                Connection &connection __attribute__((unused)) = *connRef; \
-        secinfo("SecServer", "request entry " #name " (pid:%d ession:%d)", connection.process().pid(), connection.session().sessionId());
+        secinfo("SecServer", "request entry " #name " (pid:%d session:%d)", connection.process().pid(), connection.session().sessionId());
 
 #define END_IPC(base)  END_IPCN(base) Server::requestComplete(*rcode); return KERN_SUCCESS;
 #define END_IPCN(base)         secinfo("SecServer", "request return: %d", *(rcode)); \
@@ -244,6 +245,7 @@ kern_return_t ucsp_server_setup(UCSP_ARGS, mach_port_t taskPort, ClientSetupInfo
        END_IPCN(CSSM)
        if (*rcode)
                Syslog::notice("setup(%s) failed rcode=%d", identity ? identity : "<NULL>", *rcode);
+       mach_port_deallocate(mach_task_self(), taskPort);
        return KERN_SUCCESS;
 }
 
@@ -256,6 +258,7 @@ kern_return_t ucsp_server_setupThread(UCSP_ARGS, mach_port_t taskPort)
        END_IPCN(CSSM)
        if (*rcode)
                Syslog::notice("setupThread failed rcode=%d", *rcode);
+       mach_port_deallocate(mach_task_self(), taskPort);
        return KERN_SUCCESS;
 }
 
@@ -735,7 +738,7 @@ static void check_stash_entitlement(Process & proc)
     }
     require(entitlements != NULL, done);
 
-    if (CFDictionaryGetValueIfPresent(entitlements, CFSTR("com.apple.private.securityd.stash"), &value)) {
+    if (CFDictionaryGetValueIfPresent(entitlements, kSecEntitlementPrivateStash, &value)) {
         if (CFGetTypeID(value) && CFBooleanGetTypeID()) {
             entitled = CFBooleanGetValue((CFBooleanRef)value);
         }
index 3cd0381efcfa0ecb22d338efc05f9954c1443e69..a9d405d8b8b879bfc30bb4f7c53e319a5d28b3f5 100644 (file)
@@ -778,23 +778,26 @@ static void showPeerTrust(SecTrustRef peerTrust, bool verbose) {
     if (info && CFDictionaryGetCount(info)) {
         showInfo(info);
     }
-    if (info)
+    if (info) {
         CFRelease(info);
+    }
 
-       numCerts = SecTrustGetCertificateCount(peerTrust);
-       for(i=0; i<numCerts; i++) {
+    numCerts = SecTrustGetCertificateCount(peerTrust);
+    for(i=0; i<numCerts; i++) {
         plist = SecTrustCopySummaryPropertiesAtIndex(peerTrust, i);
-               printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i);
+        printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i);
         print_plist(plist);
-        if (plist)
+        if (plist) {
             CFRelease(plist);
-               printf("\n============= Peer Trust Cert %lu Details =============\n\n", i);
-               plist = SecTrustCopyDetailedPropertiesAtIndex(peerTrust, i);
+        }
+        printf("\n============= Peer Trust Cert %lu Details =============\n\n", i);
+        plist = SecTrustCopyDetailedPropertiesAtIndex(peerTrust, i);
         print_plist(plist);
-        if (plist)
+        if (plist) {
             CFRelease(plist);
-               printf("\n============= End of Peer Trust Cert %lu ==============\n", i);
-       }
+        }
+        printf("\n============= End of Peer Trust Cert %lu ==============\n", i);
+    }
 #endif
 }
 
@@ -1192,7 +1195,7 @@ int main(int argc, char **argv)
                                doTlsV11 = true;
                 break;
             case '^':
-                               doSslV2 = doSslV3 = doTlsV1 = doTlsV12 = false;
+                               doSslV2 = doSslV3 = doTlsV1 = false;
                                doTlsV12 = true;
                 break;
                        case 'L':
index 20c99ffbe4712887e23472d5ea95fe309b6dee85..46bf4e96d6945937fb8ca57a40aa22c9a861f450 100644 (file)
@@ -348,17 +348,22 @@ static NSInteger _reporterWrites;
     OCMStub([mockTopic databasePathForCKKS]).andReturn(ckksPath);
     OCMStub([mockTopic databasePathForSOS]).andReturn(sosPath);
     OCMStub([mockTopic databasePathForPCS]).andReturn(pcsPath);
-    OCMStub([mockTopic databasePathForTLS]).andReturn(tlsPath);
+    OCMStub([mockTopic databasePathForTrust]).andReturn(tlsPath);
     OCMStub([mockTopic databasePathForSignIn]).andReturn(signInPath);
     OCMStub([mockTopic databasePathForCloudServices]).andReturn(cloudServicesPath);
 
     // These are not used for testing, but real data can pollute tests so point to empty DBs
     NSString *localpath = [_path stringByAppendingFormat:@"/local_empty_%ld.db", (long)_testnum];
-    NSString *trustPath = [_path stringByAppendingFormat:@"/trust_empty_%ld.db", (long)_testnum];
-    NSString *trustdhealthPath = [_path stringByAppendingFormat:@"/trustdhealth_empty_%ld.db", (long)_testnum];
+    NSString *networkingPath = [_path stringByAppendingFormat:@"/networking_empty_%ld.db", (long)_testnum];
     OCMStub([mockTopic databasePathForLocal]).andReturn(localpath);
-    OCMStub([mockTopic databasePathForTrust]).andReturn(trustPath);
-    OCMStub([mockTopic databasePathForTrustdHealth]).andReturn(trustdhealthPath);
+    OCMStub([mockTopic databasePathForNetworking]).andReturn(networkingPath);
+
+#if TARGET_OS_OSX
+    NSString *rootTrustPath = [_path stringByAppendingFormat:@"/root_trust_empty_%ld.db", (long)_testnum];
+    NSString *rootNetworkingPath = [_path stringByAppendingFormat:@"/root_networking_empty_%ld.db", (long)_testnum];
+    OCMStub([mockTopic databasePathForRootTrust]).andReturn(rootTrustPath);
+    OCMStub([mockTopic databasePathForRootNetworking]).andReturn(rootNetworkingPath);
+#endif
 
     _reporterWrites = 0;
     mockReporter = OCMClassMock([SFAnalyticsReporter class]);
diff --git a/supd/com.apple.securityuploadd.sb b/supd/com.apple.securityuploadd.sb
new file mode 100644 (file)
index 0000000..da7fda0
--- /dev/null
@@ -0,0 +1,81 @@
+(version 1)
+
+(deny default)
+(deny file-map-executable iokit-get-properties process-info* nvram*)
+(deny dynamic-code-generation)
+(deny mach-priv-host-port)
+
+(import "system.sb")
+(import "com.apple.corefoundation.sb")
+(corefoundation)
+
+;;; Homedir-relative path filters
+(define (home-regex home-relative-regex)
+    (regex (string-append "^" (regex-quote (param "HOME")) home-relative-regex)))
+
+(define (home-subpath home-relative-subpath)
+    (subpath (string-append (param "HOME") home-relative-subpath)))
+
+(define (home-prefix home-relative-prefix)
+    (prefix (string-append (param "HOME") home-relative-prefix)))
+
+(define (home-literal home-relative-literal)
+    (literal (string-append (param "HOME") home-relative-literal)))
+
+(allow process-info* (target self))
+
+;; For resolving symlinks, realpath(3), and equivalents.
+(allow file-read-metadata)
+
+;; For validating the entitlements of clients.
+(allow process-info-codesignature)
+
+(allow user-preference-read user-preference-write
+       (preference-domain "com.apple.security.analytics")
+       (preference-domain ".GlobalPreferences")
+       (preference-domain "com.apple.CFNetwork")
+       (preference-domain "com.apple.nsurlcache")
+       (preference-domain "kCFPreferencesAnyApplication"))
+
+(allow file-read*
+    (literal "/usr/libexec")
+    (literal "/usr/libexec/securityuploadd")
+    (subpath "/Library/Keychains/SupplementalsAssets/")
+    (literal "/Library/Application Support/CrashReporter/DiagnosticMessagesHistory.plist")
+    (regex "/private/var/db/mds/messages/([A-Za-z0-9]+/)?se_SecurityMessages"))
+
+;; Read/write access to analytics DBs and reports directories
+(allow file-read* file-write*
+       (subpath "/private/var/protected/")
+       (home-regex #"/Library/Keychains/[0-9A-F-]+/Analytics(/|$)")
+       (home-subpath #"/Library/Logs/DiagnosticReports/")
+       (home-subpath #"/Library/Application Support/com.apple.ProtectedCloudStorage/"))
+
+;; Read/write cache access
+(let ((cache-path-filter (home-subpath "/Library/Caches/com.apple.securityuploadd")))
+  (allow file-read* file-write* cache-path-filter)
+  (allow file-issue-extension
+    (require-all
+      (extension-class "com.apple.app-sandbox.read" "com.apple.app-sandbox.read-write")
+      cache-path-filter)))
+
+(allow mach-lookup
+    (global-name "com.apple.securityd.ckks")
+    (global-name "com.apple.accountsd.accountmanager")
+    (global-name "com.apple.SystemConfiguration.configd")
+    (global-name "com.apple.AppSSO.service-xpc")
+    (global-name "com.apple.dnssd.service")
+    (global-name "com.apple.usymptomsd")
+    (global-name "com.apple.ak.auth.xpc"))
+
+;; Legacy SecKey operations
+(allow file-read* file-write*
+    (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsDirectory\.db$")
+    (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mdsObject\.db$")
+    (regex #"^/private/var/folders/[^/]+/[^/]+/C/mds/mds\.lock$"))
+(allow mach-lookup
+    (global-name "com.apple.SecurityServer"))
+
+;; allow network
+(allow network-outbound)
+(allow system-socket)
index b4d4a38e0b9d3e2f3d286cf7a947f09917d38b61..d9f4b18867b1d43e0988bfb4e0adda45ad2ef5a1 100644 (file)
  */
 
 #include <TargetConditionals.h>
+#import <Foundation/NSError_Private.h>
+#import <dirhelper_priv.h>
+
+#if TARGET_OS_OSX
+#include <sandbox.h>
+#include <notify.h>
+#include <pwd.h>
+#endif
 
 #if TARGET_OS_SIMULATOR
 
@@ -61,9 +69,41 @@ int main(int argc, char** argv)
 
 @end
 
+static void securityuploadd_sandbox(void)
+{
+#if TARGET_OS_OSX
+    // Enter the sandbox on macOS
+    char homeDir[PATH_MAX] = {};
+    struct passwd* pwd = getpwuid(getuid());
+    if (pwd == NULL) {
+        secerror("Failed to get home directory for user: %d", errno);
+        exit(EXIT_FAILURE);
+    }
+
+    if (realpath(pwd->pw_dir, homeDir) == NULL) {
+        strlcpy(homeDir, pwd->pw_dir, sizeof(homeDir));
+    }
+
+    const char *sandbox_params[] = {
+        "HOME", homeDir,
+        NULL
+    };
+
+    char *sberror = NULL;
+    secerror("initializing securityuploadd sandbox with HOME=%s", homeDir);
+    if (sandbox_init_with_parameters("com.apple.securityuploadd", SANDBOX_NAMED, sandbox_params, &sberror) != 0) {
+        secerror("Failed to enter securityuploadd sandbox: %{public}s", sberror);
+        exit(EXIT_FAILURE);
+    }
+#endif
+}
+
 int main(int argc, const char *argv[])
 {
     secnotice("lifecycle", "supd lives!");
+    [NSError _setFileNameLocalizationEnabled:NO];
+    securityuploadd_sandbox();
+
     ServiceDelegate *delegate = [ServiceDelegate new];
 
     // kick the singleton so it can register its xpc activity handler
index ee1cb7513ec8dd8c9424e328c9fbcbcf038cbeae..b359175ec82ac238cef234f76ddab8bca2fcce72 100644 (file)
@@ -14,5 +14,7 @@
        <true/>
        <key>com.apple.security.network.client</key>
        <true/>
+       <key>com.apple.private.security.storage.SFAnalytics</key>
+       <true/>
 </dict>
 </plist>
index 9e4bf941a0a092dcb530b39263edbe5f64b44a6a..84fbd9e58cabe5eec0cfa3c59b2efa4a99512736 100644 (file)
 + (NSString*)databasePathForPCS;
 + (NSString*)databasePathForLocal;
 + (NSString*)databasePathForTrust;
-+ (NSString*)databasePathForTrustdHealth;
-+ (NSString*)databasePathForTLS;
++ (NSString*)databasePathForNetworking;
 + (NSString*)databasePathForSignIn;
 + (NSString*)databasePathForCloudServices;
+
+#if TARGET_OS_OSX
++ (NSString*)databasePathForRootTrust;
++ (NSString*)databasePathForRootNetworking;
+#endif
 @end
 
 @interface SFAnalyticsReporter : NSObject
index 9fe33d8773009a4e8a7852819cac6692877eea59..e084d76e3d317ebae801e4daf357bf69cd5f2533 100644 (file)
@@ -43,6 +43,7 @@
 
 #if TARGET_OS_OSX
 #include "dirhelper_priv.h"
+#include <membership.h>
 #endif
 
 #if TARGET_OS_OSX
@@ -59,6 +60,8 @@
 #import <AppleAccount/ACAccount+AppleAccount.h>
 #import <AppleAccount/ACAccountStore+AppleAccount.h>
 
+#import "utilities/simulatecrash_assert.h"
+
 
 NSString* const SFAnalyticsSplunkTopic = @"topic";
 NSString* const SFAnalyticsClientId = @"clientId";
@@ -341,18 +344,18 @@ _isiCloudAnalyticsEnabled()
                                                         deviceAnalytics:YES
                                                         iCloudAnalytics:NO]];
     } else if ([topicName isEqualToString:SFAnalyticsTopicTrust]) {
-#if TARGET_OS_OSX
-        _set_user_dir_suffix("com.apple.trustd"); // supd needs to read trustd's cache dir for these
-#endif
         [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForTrust]
                                                                    name:@"trust" deviceAnalytics:YES iCloudAnalytics:NO]];
-        [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForTrustdHealth]
-                                                                   name:@"trustdHealth" deviceAnalytics:YES iCloudAnalytics:NO]];
-        [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForTLS]
-                                                                   name:@"tls" deviceAnalytics:YES iCloudAnalytics:NO]];
-
 #if TARGET_OS_OSX
-        _set_user_dir_suffix(NULL); // set back to the default cache dir
+        [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForRootTrust]
+                                                                   name:@"rootTrust" deviceAnalytics:YES iCloudAnalytics:NO]];
+#endif
+    } else if ([topicName isEqualToString:SFAnalyticsTopicNetworking]) {
+        [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForNetworking]
+                                                                   name:@"networking" deviceAnalytics:YES iCloudAnalytics:NO]];
+#if TARGET_OS_OSX
+        [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForRootNetworking]
+                                                                   name:@"rootNetworking" deviceAnalytics:YES iCloudAnalytics:NO]];
 #endif
     } else if ([topicName isEqualToString:SFAnalyticsTopicTransparency]) {
         [clients addObject:[[SFAnalyticsClient alloc] initWithStorePath:[self.class databasePathForTransparency]
@@ -890,48 +893,50 @@ participatingClients:(NSMutableArray<SFAnalyticsClient*>**)clients
         accountID = accountAltDSID();
     }
     for (SFAnalyticsClient* client in self->_topicClients) {
-        if (!force && [client requireDeviceAnalytics] && !_isDeviceAnalyticsEnabled()) {
-            // Client required device analytics, yet the user did not opt in.
-            secnotice("getLoggingJSON", "Client '%@' requires device analytics yet user did not opt in.", [client name]);
-            continue;
-        }
-        if (!force && [client requireiCloudAnalytics] && !_isiCloudAnalyticsEnabled()) {
-            // Client required iCloud analytics, yet the user did not opt in.
-            secnotice("getLoggingJSON", "Client '%@' requires iCloud analytics yet user did not opt in.", [client name]);
-            continue;
-        }
-
-        SFAnalyticsSQLiteStore* store = [SFAnalyticsSQLiteStore storeWithPath:client.storePath schema:SFAnalyticsTableSchema];
-
-        if (upload) {
-            NSDate* uploadDate = store.uploadDate;
-            if (!force && uploadDate && [[NSDate date] timeIntervalSinceDate:uploadDate] < _secondsBetweenUploads) {
-                secnotice("json", "ignoring client '%@' for %@ because last upload too recent: %@",
-                          client.name, _internalTopicName, uploadDate);
+        @autoreleasepool {
+            if (!force && [client requireDeviceAnalytics] && !_isDeviceAnalyticsEnabled()) {
+                // Client required device analytics, yet the user did not opt in.
+                secnotice("getLoggingJSON", "Client '%@' requires device analytics yet user did not opt in.", [client name]);
                 continue;
             }
-
-            if (force) {
-                secnotice("json", "client '%@' for topic '%@' force-included", client.name, _internalTopicName);
-            } else {
-                secnotice("json", "including client '%@' for topic '%@' for upload", client.name, _internalTopicName);
+            if (!force && [client requireiCloudAnalytics] && !_isiCloudAnalyticsEnabled()) {
+                // Client required iCloud analytics, yet the user did not opt in.
+                secnotice("getLoggingJSON", "Client '%@' requires iCloud analytics yet user did not opt in.", [client name]);
+                continue;
             }
-            [localClients addObject:client];
-        }
 
-        NSMutableDictionary* healthSummary = [self healthSummaryWithName:client.name store:store uuid:linkedUUID];
-        if (healthSummary) {
-            if (ckdeviceID) {
-                healthSummary[SFAnalyticsDeviceID] = ckdeviceID;
+            SFAnalyticsSQLiteStore* store = [SFAnalyticsSQLiteStore storeWithPath:client.storePath schema:SFAnalyticsTableSchema];
+
+            if (upload) {
+                NSDate* uploadDate = store.uploadDate;
+                if (!force && uploadDate && [[NSDate date] timeIntervalSinceDate:uploadDate] < _secondsBetweenUploads) {
+                    secnotice("json", "ignoring client '%@' for %@ because last upload too recent: %@",
+                              client.name, _internalTopicName, uploadDate);
+                    continue;
+                }
+
+                if (force) {
+                    secnotice("json", "client '%@' for topic '%@' force-included", client.name, _internalTopicName);
+                } else {
+                    secnotice("json", "including client '%@' for topic '%@' for upload", client.name, _internalTopicName);
+                }
+                [localClients addObject:client];
             }
-            if (accountID) {
-                healthSummary[SFAnalyticsAltDSID] = accountID;
+
+            NSMutableDictionary* healthSummary = [self healthSummaryWithName:client.name store:store uuid:linkedUUID];
+            if (healthSummary) {
+                if (ckdeviceID) {
+                    healthSummary[SFAnalyticsDeviceID] = ckdeviceID;
+                }
+                if (accountID) {
+                    healthSummary[SFAnalyticsAltDSID] = accountID;
+                }
+                [localHealthSummaries addObject:healthSummary];
             }
-            [localHealthSummaries addObject:healthSummary];
-        }
 
-        [hardFailures addObject:store.hardFailures];
-        [softFailures addObject:store.softFailures];
+            [hardFailures addObject:store.hardFailures];
+            [softFailures addObject:store.softFailures];
+        }
     }
 
     if (upload && [localClients count] == 0) {
@@ -1255,33 +1260,50 @@ participatingClients:(NSMutableArray<SFAnalyticsClient*>**)clients
     return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory((__bridge CFStringRef)@"Analytics/localkeychain.db") path];
 }
 
-+ (NSString*)databasePathForTrustdHealth
++ (NSString*)databasePathForTrust
 {
 #if TARGET_OS_IPHONE
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/trustd_health_analytics.db")) path];
+    return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/trust_analytics.db")) path];
 #else
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInUserCacheDirectory(CFSTR("Analytics/trustd_health_analytics.db")) path];
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:@"trust_analytics"];
 #endif
 }
 
-+ (NSString*)databasePathForTrust
+#if TARGET_OS_OSX
++ (NSUUID *)rootUUID
 {
-#if TARGET_OS_IPHONE
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/trust_analytics.db")) path];
-#else
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInUserCacheDirectory(CFSTR("Analytics/trust_analytics.db")) path];
+    uuid_t rootUuid;
+    int ret = mbr_uid_to_uuid(0, rootUuid);
+    if (ret != 0) {
+        return nil;
+    }
+    return [[NSUUID alloc] initWithUUIDBytes:rootUuid];
+}
 #endif
+
+#if TARGET_OS_OSX
++ (NSString*)databasePathForRootTrust
+{
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:@"trust_analytics" uuid:[SFAnalyticsTopic rootUUID]];
 }
+#endif
 
-+ (NSString*)databasePathForTLS
++ (NSString*)databasePathForNetworking
 {
 #if TARGET_OS_IPHONE
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/TLS_analytics.db")) path];
+    return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/networking_analytics.db")) path];
 #else
-    return [(__bridge_transfer NSURL*)SecCopyURLForFileInUserCacheDirectory(CFSTR("Analytics/TLS_analytics.db")) path];
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:@"networking_analytics"];
 #endif
 }
 
+#if TARGET_OS_OSX
++ (NSString*)databasePathForRootNetworking
+{
+    return [SFAnalytics defaultProtectedAnalyticsDatabasePath:@"networking_analytics" uuid:[SFAnalyticsTopic rootUUID]];
+}
+#endif
+
 + (NSString*)databasePathForSignIn
 {
     return [(__bridge_transfer NSURL*)SecCopyURLForFileInKeychainDirectory(CFSTR("Analytics/signin_metrics.db")) path];
index 2920fd4c988d38f93c1ab7a58dc44e4d527bb3b9..5ce0e43d2da184109f0b0f117270121d4c636eb8 100644 (file)
@@ -30,8 +30,6 @@
 
 /* Internal Topic Names */
 NSString* const SFAnalyticsTopicKeySync = @"KeySyncTopic";
-NSString* const SFAnalyticsTopicTrust = @"TrustTopic";
-NSString* const SFAnalyticsTopicTransparency = @"TransparencyTopic";
 
 static void nsprintf(NSString *fmt, ...) NS_FORMAT_FUNCTION(1, 2);
 static void nsprintf(NSString *fmt, ...)
diff --git a/tests/SecDbBackupTests/Entitlements.plist b/tests/SecDbBackupTests/Entitlements.plist
deleted file mode 100644 (file)
index f63472f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>com.apple.application-identifier</key>
-       <string>com.apple.private.security.SecDbBackupTests</string>
-       <key>application-identifier</key>
-       <string>com.apple.private.security.SecDbBackupTests</string>
-       <key>com.apple.keystore.access-keychain-keys</key>
-       <true/>
-       <key>com.apple.keystore.lockassertion</key>
-       <true/>
-       <key>com.apple.private.associated-domains</key>
-       <true/>
-       <key>com.apple.private.necp.match</key>
-       <true/>
-       <key>com.apple.mkb.usersession.info</key>
-       <true/>
-       <key>seatbelt-profiles</key>
-       <array>
-               <string>securityd</string>
-       </array>
-       <key>com.apple.security.app-sandbox</key>
-       <false/>
-       <key>com.apple.security.get-task-allow</key>
-       <true/>
-       <key>keychain-access-groups</key>
-       <array>
-               <string>SecDbBackupManager-UnitTests</string>
-       </array>
-</dict>
-</plist>
diff --git a/tests/SecDbBackupTests/SecDbBackupTests-Entitlements.plist b/tests/SecDbBackupTests/SecDbBackupTests-Entitlements.plist
new file mode 100644 (file)
index 0000000..7f63b7f
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.private.security.SecDbBackupTests</string>
+       <key>application-identifier</key>
+       <string>com.apple.private.security.SecDbBackupTests</string>
+       <key>com.apple.keystore.access-keychain-keys</key>
+       <true/>
+       <key>com.apple.keystore.lockassertion</key>
+       <true/>
+       <key>com.apple.private.associated-domains</key>
+       <true/>
+       <key>com.apple.private.necp.match</key>
+       <true/>
+       <key>com.apple.mkb.usersession.info</key>
+       <true/>
+       <key>seatbelt-profiles</key>
+       <array>
+               <string>securityd</string>
+       </array>
+       <key>com.apple.security.app-sandbox</key>
+       <false/>
+       <key>com.apple.security.get-task-allow</key>
+       <true/>
+       <key>keychain-access-groups</key>
+       <array>
+               <string>SecDbBackupManager-UnitTests</string>
+       </array>
+       <key>com.apple.private.security.storage.Keychains</key>
+       <true/>
+</dict>
+</plist>
index cb8d0e726835aca3369b8854d250b428c44b49c9..ad5f3e41fb40260b3a94dd801fae4d016bb9d8b7 100644 (file)
@@ -1,11 +1,4 @@
-//
-//  SecDbBackupTests.m
-//  Security
-//
-//  Created by Wouter de Groot on 2018-12-12.
-//
-
-#import <XCTest/XCTest.h>
+#import "SecDbBackupTestsBase.h"
 #import "keychain/securityd/SecDbBackupManager.h"
 
 #if !SECDB_BACKUPS_ENABLED
 
 #import "keychain/securityd/SecDbBackupManager_Internal.h"
 
-#import "CKKS.h"
-#import <utilities/SecFileLocations.h>
-#import "spi.h"
-#import "SecItemServer.h"
+
 #import <objc/runtime.h>
 #include "utilities/der_plist.h"
 #include <Security/SecItemPriv.h>
 
-@interface SecDbBackupTests : XCTestCase
+@interface SecDbBackupTests : SecDbBackupTestsBase
 
 @end
 
 SecDbBackupManager* _manager;
-NSString* _uuidstring;
-
-@implementation SecDbBackupTests {
-    NSString* _testHomeDirectory;
-}
 
-static int testCheckV12DevEnabled(void) {
-    return 1;
-}
+@implementation SecDbBackupTests
 
 + (void)setUp {
     [super setUp];
-    checkV12DevEnabled = testCheckV12DevEnabled;
-    SecCKKSDisable();
-#if OCTAGON
-    SecCKKSTestSetDisableSOS(true);
-#endif
-    _uuidstring = [[NSUUID UUID] UUIDString];
 }
 
 + (void)tearDown {
-    SetCustomHomeURL(NULL);
-    SecKeychainDbReset(NULL);
-    resetCheckV12DevEnabled();
+       [super tearDown];
 }
 
 - (void)setUp {
     [super setUp];
-
-    NSString* testName = [self.name componentsSeparatedByString:@" "][1];
-    testName = [testName stringByReplacingOccurrencesOfString:@"]" withString:@""];
-    secnotice("secdbbackuptest", "Beginning test %@", testName);
-
-    // Make a new fake keychain
-    NSError* error;
-    _testHomeDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@/", _uuidstring, testName]];
-
-    NSLog(@"%@", _testHomeDirectory);
-
-    [[NSFileManager defaultManager] createDirectoryAtPath:_testHomeDirectory
-                              withIntermediateDirectories:YES
-                                               attributes:nil
-                                                    error:&error];
-    // No XCTAssert in class method
-    if (error) {
-        NSLog(@"Could not make directory at %@", _testHomeDirectory);
-    }
-
-    SetCustomHomeURLString((__bridge CFStringRef)_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; });
-
     [SecDbBackupManager resetManager];
     _manager = [SecDbBackupManager manager];
 }
@@ -359,9 +304,9 @@ static int testCheckV12DevEnabled(void) {
     void* aksunwrappedbytes = NULL;
     size_t aksunwrappedlen = 0;
     XCTAssertEqual(aks_ref_key_decrypt(refkey, NULL, 0, kcsk.aksWrappedKey.bytes, kcsk.aksWrappedKey.length, &aksunwrappedbytes, &aksunwrappedlen), kAKSReturnSuccess, @"Successfully unwrapped KCSK private key");
-    SFECKeyPair* aksunwrapped = [_manager ECKeyPairFromDerBytes:aksunwrappedbytes length:aksunwrappedlen error:&error];
+    SFECKeyPair* aksunwrapped = [_manager getECKeyPairFromDERBytes:aksunwrappedbytes length:aksunwrappedlen error:&error];
     XCTAssertNil(error, @"No error reconstructing AKS backup key");
-    XCTAssert(aksunwrapped, @"Got key from ECKeyPairFromDerBytes");
+    XCTAssert(aksunwrapped, @"Got key from getECKeyPairFromDERBytes");
     aks_ref_key_free(&refkey);
 
     // Verify backupWrappedKey
@@ -428,7 +373,7 @@ static int testCheckV12DevEnabled(void) {
 - (void)testWrapItemKey {
     SFAESKey* randomKey = [self randomAESKey];
     NSError* error;
-    SecDbBackupWrappedItemKey* itemKey = [_manager wrapItemKey:randomKey forKeyclass:key_class_akpu error:&error];
+    SecDbBackupWrappedKey* itemKey = [_manager wrapItemKey:randomKey forKeyclass:key_class_akpu error:&error];
     XCTAssertNil(itemKey, @"Do not expect result wrapping to akpu");
     XCTAssertEqual(error.code, SecDbBackupInvalidArgument, @"Expect invalid argument error wrapping to akpu");
 
@@ -437,7 +382,22 @@ static int testCheckV12DevEnabled(void) {
     XCTAssertNil(error, @"No error wrapping item to ak");
     XCTAssertEqualObjects(itemKey.baguuid, _manager.bagIdentity.baguuid, @"item wrapped under expected bag uuid");
 
-    // TODO: implement decryption and test it here
+    // TODO: implement decryption and test it
+}
+
+- (void)testWrapMetadataKey {
+    SFAESKey* randomKey = [self randomAESKey];
+    NSError* error;
+    SecDbBackupWrappedKey* itemKey = [_manager wrapMetadataKey:randomKey forKeyclass:key_class_akpu error:&error];
+    XCTAssertNil(itemKey, @"Do not expect result wrapping to akpu");
+    XCTAssertEqual(error.code, SecDbBackupInvalidArgument, @"Expect invalid argument error wrapping to akpu");
+
+    error = nil;
+    itemKey = [_manager wrapMetadataKey:randomKey forKeyclass:key_class_ak error:&error];
+    XCTAssertNil(error, @"No error wrapping item to ak");
+    XCTAssertEqualObjects(itemKey.baguuid, _manager.bagIdentity.baguuid, @"item wrapped under expected bag uuid");
+
+    // TODO: implement decryption and test it
 }
 
 // Does not inspect the item because it's encrypted and no code yet built to do recovery.
diff --git a/tests/SecDbBackupTests/SecDbBackupTests.plist b/tests/SecDbBackupTests/SecDbBackupTests.plist
deleted file mode 100644 (file)
index 817e23d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-    <dict>
-        <key>BATSConfigVersion</key>
-        <string>0.1.0</string>
-        <key>Project</key>
-        <string>Security</string>
-        <key>Tests</key>
-        <array>
-            <dict>
-                <key>TestName</key>
-                <string>SecDbBackupTests</string>
-                <key>WorkingDirectory</key>
-                <string>/AppleInternal/XCTests/com.apple.security/</string>
-                <key>ShowSubtestResults</key>
-                <true/>
-                <key>Timeout</key>
-                <integer>1200</integer>
-                <key>Command</key>
-                <array>
-                    <string>BATS_XCTEST_CMD SecDbBackupTests.xctest</string>
-                </array>
-            </dict>
-        </array>
-    </dict>
-</plist>
diff --git a/tests/SecDbBackupTests/SecDbBackupTestsBase.h b/tests/SecDbBackupTests/SecDbBackupTestsBase.h
new file mode 100644 (file)
index 0000000..c356c5e
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SecDbBackupTestsBase_h
+#define SecDbBackupTestsBase_h
+
+#import <XCTest/XCTest.h>
+
+// This isn't inheritance-based data hiding, this whole class is for convenience building tests
+#import "keychain/securityd/CheckV12DevEnabled.h"
+#import "CKKS.h"
+#import <utilities/SecFileLocations.h>
+#import "spi.h"
+#import "SecItemServer.h"
+
+@interface SecDbBackupTestsBase : XCTestCase
+
++ (void)setV12Development:(BOOL)newState;
+
+@end
+
+#endif /* SecDbBackupTestsBase_h */
diff --git a/tests/SecDbBackupTests/SecDbBackupTestsBase.m b/tests/SecDbBackupTests/SecDbBackupTestsBase.m
new file mode 100644 (file)
index 0000000..d99092e
--- /dev/null
@@ -0,0 +1,74 @@
+#import "SecDbBackupTestsBase.h"
+
+static int checkV12DevEnabledOn(void) {
+    return 1;
+}
+
+static int checkV12DevEnabledOff(void) {
+       return 0;
+}
+
+NSString* _uuidstring;
+
+@implementation SecDbBackupTestsBase {
+       NSString* _testHomeDirectory;
+}
+
++ (void)setV12Development:(BOOL)newState {
+       if (newState) {
+               checkV12DevEnabled = checkV12DevEnabledOn;
+       } else {
+               checkV12DevEnabled = checkV12DevEnabledOff;
+       }
+}
+
++ (void)setUp {
+    [super setUp];
+    checkV12DevEnabled = checkV12DevEnabledOn;
+    SecCKKSDisable();
+#if OCTAGON
+    SecCKKSTestSetDisableSOS(true);
+#endif
+       _uuidstring = [[NSUUID UUID] UUIDString];
+}
+
+- (void)setUp {
+    NSString* testName = [self.name componentsSeparatedByString:@" "][1];
+    testName = [testName stringByReplacingOccurrencesOfString:@"]" withString:@""];
+    secnotice("secdbbackuptest", "Beginning test %@", testName);
+
+    // Make a new fake keychain
+    NSError* error;
+    _testHomeDirectory = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@/", _uuidstring, testName]];
+
+    NSLog(@"%@", _testHomeDirectory);
+
+    [[NSFileManager defaultManager] createDirectoryAtPath:_testHomeDirectory
+                              withIntermediateDirectories:YES
+                                               attributes:nil
+                                                    error:&error];
+
+       XCTAssertNil(error, "Could not make directory at %@", _testHomeDirectory);
+
+    SetCustomHomeURLString((__bridge CFStringRef)_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 {
+    // Put teardown code here. This method is called after the invocation of each test method in the class.
+}
+
++ (void)tearDown {
+    SetCustomHomeURL(NULL);
+    SecKeychainDbReset(NULL);
+    resetCheckV12DevEnabled();
+}
+
+@end
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.h b/tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.h
new file mode 100644 (file)
index 0000000..25b7f00
--- /dev/null
@@ -0,0 +1,16 @@
+#import <TargetConditionals.h>
+
+#if TARGET_OS_OSX
+
+#import <Cocoa/Cocoa.h>
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+@end
+
+#else
+
+#import <UIKit/UIKit.h>
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+#endif
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.m b/tests/TestHostBinaries/KeychainEntitledTestApp/AppDelegate.m
new file mode 100644 (file)
index 0000000..febafd3
--- /dev/null
@@ -0,0 +1,25 @@
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+#if TARGET_OS_OSX
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {}
+- (void)applicationWillTerminate:(NSNotification *)aNotification {}
+
+#else
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {return YES;}
+- (void)applicationWillResignActive:(UIApplication *)application {}
+- (void)applicationDidEnterBackground:(UIApplication *)application {}
+- (void)applicationWillEnterForeground:(UIApplication *)application {}
+- (void)applicationDidBecomeActive:(UIApplication *)application {}
+- (void)applicationWillTerminate:(UIApplication *)application {}
+
+#endif
+
+@end
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/tests/TestHostBinaries/KeychainEntitledTestApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644 (file)
index 0000000..2db2b1c
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "images" : [
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/Info.plist b/tests/TestHostBinaries/KeychainEntitledTestApp/Info.plist
new file mode 100644 (file)
index 0000000..5315cf8
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+    <key>UIRequiresFullScreen</key>
+    <true/>
+#import <TargetConditionals.h>
+#if TARGET_OS_OSX
+       <key>LSMinimumSystemVersion</key>
+       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+#endif
+</dict>
+</plist>
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.h b/tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.h
new file mode 100644 (file)
index 0000000..8f76512
--- /dev/null
@@ -0,0 +1,15 @@
+#import <TargetConditionals.h>
+
+#if TARGET_OS_OSX
+
+#import <Cocoa/Cocoa.h>
+@interface ViewController : NSViewController
+@end
+
+#else
+
+#import <UIKit/UIKit.h>
+@interface ViewController : UIViewController
+@end
+
+#endif
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.m b/tests/TestHostBinaries/KeychainEntitledTestApp/ViewController.m
new file mode 100644 (file)
index 0000000..ab623ad
--- /dev/null
@@ -0,0 +1,25 @@
+#import "ViewController.h"
+
+#if TARGET_OS_OSX
+
+@implementation ViewController
+- (void)viewDidLoad {
+    [super viewDidLoad];
+}
+- (void)setRepresentedObject:(id)representedObject {
+    [super setRepresentedObject:representedObject];
+}
+@end
+
+#else
+
+@implementation ViewController
+- (void)viewDidLoad {
+    [super viewDidLoad];
+}
+- (void)didReceiveMemoryWarning {
+    [super didReceiveMemoryWarning];
+ }
+@end
+
+#endif
diff --git a/tests/TestHostBinaries/KeychainEntitledTestApp/main.m b/tests/TestHostBinaries/KeychainEntitledTestApp/main.m
new file mode 100644 (file)
index 0000000..80e84da
--- /dev/null
@@ -0,0 +1,22 @@
+#import <TargetConditionals.h>
+
+#if TARGET_OS_OSX
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, const char * argv[]) {
+    return NSApplicationMain(argc, argv);
+}
+
+#else
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}
+
+#endif
diff --git a/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements b/tests/TestHostBinaries/KeychainEntitledTestRunner.entitlements
new file mode 100644 (file)
index 0000000..8e213a9
--- /dev/null
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.application-identifier</key>
+       <string>com.apple.security.KeychainEntitledTestRunner</string>
+       <key>application-identifier</key>
+       <string>com.apple.security.KeychainEntitledTestRunner</string>
+       <key>com.apple.developer.icloud-services</key>
+       <array>
+               <string>CloudKit</string>
+       </array>
+       <key>com.apple.private.cloudkit.masquerade</key>
+       <true/>
+       <key>com.apple.private.cloudkit.customAccounts</key>
+       <true/>
+       <key>com.apple.developer.icloud-container-environment</key>
+       <string>Development</string>
+       <key>com.apple.private.aps-connection-initiate</key>
+       <true/>
+       <key>aps-connection-initiate</key>
+       <true/>
+       <key>aps-environment</key>
+       <string>serverPreferred</string>
+       <key>keychain-access-groups</key>
+       <array>
+               <string>com.apple.security.ckks</string>
+               <string>SecDbBackupManager-UnitTests</string>
+       </array>
+       <key>keychain-cloud-circle</key>
+       <true/>
+    <key>com.apple.security.app-sandbox</key>
+    <false/>
+    <key>com.apple.security.get-task-allow</key>
+    <true/>
+    <key>com.apple.keystore.access-keychain-keys</key>
+    <true/>
+    <key>com.apple.keystore.lockassertion</key>
+    <true/>
+    <key>com.apple.private.associated-domains</key>
+    <true/>
+    <key>com.apple.private.necp.match</key>
+    <true/>
+    <key>com.apple.mkb.usersession.info</key>
+    <true/>
+</dict>
+</plist>
diff --git a/tests/TestHostBinaries/KeychainEntitledTestRunner/KeychainEntitledTestRunner.m b/tests/TestHostBinaries/KeychainEntitledTestRunner/KeychainEntitledTestRunner.m
new file mode 100644 (file)
index 0000000..98d3766
--- /dev/null
@@ -0,0 +1,219 @@
+//
+//  KeychainEntitledTestRunner.m
+//  KeychainEntitledTestRunner
+//
+//  Stolen from Mark Pauley / CDEntitledTestRunner who stole it from Drew Terry / MobileContainerManager
+//  Copyright 2016-2017 Apple. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <unistd.h>
+#import <XCTest/XCTest.h>
+
+@interface TestRunner : NSObject <XCTestObservation> {
+    NSBundle *_bundle;
+    XCTestSuite *_testSuite;
+}
+
+- (instancetype)initWithBundlePath:(NSString *)path andTestNames:(NSArray *)names;
+- (NSUInteger)runUnitTestSuite;
+
+- (void)testLogWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1,2);
+- (void)testLogWithFormat:(NSString *)format arguments:(va_list)arguments NS_FORMAT_FUNCTION(1,0);
+
+@end
+
+@implementation TestRunner
+- (instancetype)initWithBundlePath:(NSString *)path andTestNames:(NSArray *)names
+{
+    if ((self = [super init])) {
+        NSError *error = nil;
+        
+        _bundle = [NSBundle bundleWithPath:path];
+        if (!_bundle) {
+            [self testLogWithFormat:@"No bundle at location %@ (%s)\n", path, strerror(errno)];
+            return nil;
+        }
+        if (![_bundle loadAndReturnError:&error]) {
+            [self testLogWithFormat:@"Test Bundle at %@ didn't load: %@\n", path, error];
+            return nil;
+        }
+
+        if(names) {
+            XCTestSuite* testSuite = [[XCTestSuite alloc] initWithName:[[path lastPathComponent] stringByDeletingPathExtension]];
+            XCTestSuite* loadedSuite = [XCTestSuite testSuiteForBundlePath:path];
+            // Filter out only the tests that were named.
+            [loadedSuite.tests enumerateObjectsUsingBlock:^(__kindof XCTest * _Nonnull test, NSUInteger __unused idx, BOOL * __unused _Nonnull stop) {
+                [self testLogWithFormat:@"Checking test %@\n", test.name];
+                if([names containsObject:test.name]) {
+                    [testSuite addTest:test];
+                }
+            }];
+            _testSuite = testSuite;
+        }
+        else {
+            _testSuite = [XCTestSuite testSuiteForBundlePath:path];
+        }
+    }
+    return self;
+}
+
+- (NSUInteger)runUnitTestSuite
+{
+    [[XCTestObservationCenter sharedTestObservationCenter] addTestObserver:self];
+    
+    [_testSuite runTest];
+    
+    XCTestRun *testRun = [_testSuite testRun];
+    
+    return testRun.totalFailureCount;
+}
+
+- (NSFileHandle *)logFileHandle
+{
+    return [NSFileHandle fileHandleWithStandardOutput];
+}
+
+- (void)testLogWithFormat:(NSString *)format, ...
+{
+    va_list ap;
+    va_start(ap, format);
+    [self testLogWithFormat:format arguments:ap];
+    va_end(ap);
+}
+
+- (void)testLogWithFormat:(NSString *)format arguments:(va_list)arguments
+{
+    NSString *message = [[NSString alloc] initWithFormat:format arguments:arguments];
+    [self.logFileHandle writeData:[message dataUsingEncoding:NSUTF8StringEncoding]];
+}
+
+- (NSDateFormatter *)dateFormatter
+{
+    static NSDateFormatter *dateFormatter;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        dateFormatter = [NSDateFormatter new];
+        dateFormatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
+    });
+    return dateFormatter;
+}
+
+/* -testBundleWillStart:                            // exactly once per test bundle
+ *      -testSuiteWillStart:                        // exactly once per test suite
+ *          -testCaseWillStart:                     // exactly once per test case
+ *          -testCase:didFailWithDescription:...    // zero or more times per test case, any time between test case start and finish
+ *          -testCaseDidFinish:                     // exactly once per test case
+ *      -testSuite:didFailWithDescription:...       // zero or more times per test suite, any time between test suite start and finish
+ *      -testSuiteDidFinish:                        // exactly once per test suite
+ * -testBundleDidFinish:                            // exactly once per test bundle
+ */
+
+- (void)testSuiteWillStart:(XCTestSuite *)testSuite
+{
+    [self testLogWithFormat:@"Test Suite '%@' started at %@\n", testSuite.name, [self.dateFormatter stringFromDate:testSuite.testRun.startDate]];
+}
+
+- (void)testSuite:(XCTestSuite *)testSuite didRecordIssue:(XCTIssue *)issue {
+       [self testLogWithFormat:@"(%@)%@:%lu: error: %@", testSuite.name, issue.sourceCodeContext.location.fileURL,
+                                                                                                          issue.sourceCodeContext.location.lineNumber, issue.compactDescription];
+}
+
+- (void)testSuiteDidFinish:(XCTestSuite *)testSuite
+{
+    XCTestRun *testRun = testSuite.testRun;
+    [self testLogWithFormat:@"Test Suite '%@' %s at %@.\n\t Executed %lu test%s, with %lu failure%s (%lu unexpected) in %.3f (%.3f) seconds\n",
+     testSuite.name,
+     (testRun.hasSucceeded ? "passed" : "failed"),
+     [self.dateFormatter stringFromDate:testRun.stopDate],
+     ((unsigned long)testRun.executionCount), (testRun.executionCount != 1 ? "s" : ""),
+     ((unsigned long)testRun.totalFailureCount), (testRun.totalFailureCount != 1 ? "s" : ""),
+     ((unsigned long)testRun.unexpectedExceptionCount),
+     testRun.testDuration,
+     testRun.totalDuration];
+}
+
+- (void)testCaseWillStart:(XCTestCase *)testCase
+{
+    [self testLogWithFormat:@"Test Case '%@' started.\n", testCase.name];
+}
+
+- (void)testCase:(XCTestCase *)testCase didRecordIssue:(XCTIssue *)issue {
+       [self testLogWithFormat:@"(%@)%@:%lu error: %@\n%@", testCase.name, issue.sourceCodeContext.location.fileURL, issue.sourceCodeContext.location.lineNumber, issue.detailedDescription, issue.sourceCodeContext.callStack];
+}
+
+- (void)testCaseDidFinish:(XCTestCase *)testCase
+{
+    [self testLogWithFormat:@"Test Case '%@' %s (%.3f seconds).\n", testCase.name, (testCase.testRun.hasSucceeded ? "passed" : "failed"), testCase.testRun.totalDuration];
+    
+}
+@end
+
+
+
+
+static char* gTestBundleDir = "/AppleInternal/XCTests/com.apple.security";
+static char* gTestBundleName = "CKKSCloudKitTests";
+
+static NSMutableArray* gTestCaseNames = nil;
+
+static const char* opt_str = "d:t:c:h";
+
+static void usage(char*const binName, bool longUsage) {
+    fprintf(stderr, "Usage: %s [-d <test_dir>] -t test_bundle_name [(-c test_case_name)*]\n", binName);
+    if (longUsage) {
+        fprintf(stderr, "-d: argument = path to directory where test bundles live\n");
+        fprintf(stderr, "-t: argument = name of test bundle to be run (without extension)\n");
+        fprintf(stderr, "-c: argument = name of test case to be run (multiple)\n");
+    }
+}
+
+static void getOptions(int argc, char *const *argv) {
+    int ch;
+    while ( (ch = getopt(argc, argv, opt_str)) != -1 ) {
+        switch(ch)
+        {
+            case 'd':
+                gTestBundleDir = optarg;
+                break;
+            case 't':
+                gTestBundleName = optarg;
+                break;
+            case 'c':
+                if(!gTestCaseNames) {
+                    gTestCaseNames = [NSMutableArray new];
+                }
+                [gTestCaseNames addObject:@(optarg)];
+                break;
+            case 'h':
+            case '?':
+            default:
+                usage(argv[0], true);
+                exit(0);
+                break;
+        }
+    }
+}
+
+int main (int argc, const char * argv[])
+{
+    @autoreleasepool {
+        getOptions(argc, (char*const*)argv);
+        NSString *testBundleDir = [NSString stringWithCString:gTestBundleDir encoding:NSUTF8StringEncoding];
+        NSString *testBundleName = [NSString stringWithCString:gTestBundleName encoding:NSUTF8StringEncoding];
+        NSString *testBundlePath = [[testBundleDir stringByAppendingPathComponent:testBundleName] stringByAppendingPathExtension:@"xctest"];
+        
+        printf("Running unit tests %s at: %s\n", gTestCaseNames?gTestCaseNames.description.UTF8String:"[All]", testBundlePath.UTF8String);
+        
+        TestRunner *unitTest = [[TestRunner alloc] initWithBundlePath:testBundlePath andTestNames:gTestCaseNames];
+        if (!unitTest) {
+            fprintf(stderr, "Failed to load unit test runner at: %s\n", testBundlePath.UTF8String);
+            return 1;
+        }
+        
+        //runUnitTestSuite returns the number of failures. 0 = success, non-zero means failure. This complies with BATS testing standards.
+        return (int)[unitTest runUnitTestSuite];
+        
+        return 0;
+    }
+}
diff --git a/tests/TrustTests/DaemonTests/PersonalizationTests.m b/tests/TrustTests/DaemonTests/PersonalizationTests.m
new file mode 100644 (file)
index 0000000..b73d06d
--- /dev/null
@@ -0,0 +1,19 @@
+//
+//  PersonalizationTests.m
+//  Security
+//
+//
+
+#import <XCTest/XCTest.h>
+#import <Foundation/Foundation.h>
+#import "trust/trustd/personalization.h"
+
+#import "TrustDaemonTestCase.h"
+
+@interface PersonalizationTests: TrustDaemonTestCase
+@end
+
+@implementation PersonalizationTests
+
+
+@end
index 95ac24f06dfb559b9b8f9f512d873b8fd7a99e11..ba0a45fc35afb25870d92c51e687a3a020a24c50 100644 (file)
@@ -21,7 +21,6 @@
 * @APPLE_LICENSE_HEADER_END@
 *
 */
-
 #ifndef _TRUSTTESTS_DAEMON_TESTCASE_H_
 #define _TRUSTTESTS_DAEMON_TESTCASE_H_
 
diff --git a/tests/TrustTests/EvaluationTests/AllowlistBlocklistTests.m b/tests/TrustTests/EvaluationTests/AllowlistBlocklistTests.m
new file mode 100644 (file)
index 0000000..2a80ae6
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+* Copyright (c) 2011-2019 Apple Inc. All Rights Reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#include <AssertMacros.h>
+#import <XCTest/XCTest.h>
+#import <Foundation/Foundation.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecPolicyPriv.h>
+#include <Security/SecTrust.h>
+#include <Security/SecTrustPriv.h>
+#include <utilities/SecCFRelease.h>
+
+#import "../TestMacroConversions.h"
+#import "TrustEvaluationTestCase.h"
+
+#import "AllowlistBlocklistTests_data.h"
+
+@interface BlocklistTests :TrustEvaluationTestCase
+@end
+
+@implementation BlocklistTests
+
+- (void)validate_one_cert:(uint8_t *)data length:(size_t)len chain_length:(int)chain_length trustResult:(SecTrustResultType)trust_result
+{
+    SecTrustRef trust = NULL;
+    SecCertificateRef cert = NULL, root = NULL;
+    SecPolicyRef policy = SecPolicyCreateSSL(false, NULL);
+    CFArrayRef certs = NULL;
+
+    isnt(cert = SecCertificateCreateWithBytes(NULL, data, len),
+        NULL, "create cert");
+    isnt(root = SecCertificateCreateWithBytes(NULL, UTNHardware_cer, sizeof(UTNHardware_cer)), NULL);
+    certs = CFArrayCreate(NULL, (const void **)&cert, 1, NULL);
+    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust),
+        "create trust with single cert");
+    ok_status(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)@[(__bridge id)root]));
+
+    SecTrustResultType trustResult;
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
+    is(SecTrustGetCertificateCount(trust), chain_length, "cert count");
+    is_status(trustResult, trust_result, "correct trustResult");
+    CFRelease(trust);
+    CFRelease(policy);
+    CFRelease(certs);
+    CFRelease(cert);
+    CFReleaseNull(root);
+}
+
+- (void)testBlocklistedCerts
+{
+    [self validate_one_cert:Global_Trustee_cer length:sizeof(Global_Trustee_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:login_yahoo_com_1_cer length:sizeof(login_yahoo_com_1_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+
+    /* this is the root, which isn't ok for ssl and fails here, but at the
+       same time it proves that kSecTrustResultFatalTrustFailure isn't
+       returned for policy failures that aren't blocklisting */
+    [self validate_one_cert:login_yahoo_com_2_cer length:sizeof(login_yahoo_com_2_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:addons_mozilla_org_cer length:sizeof(addons_mozilla_org_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:login_yahoo_com_cer length:sizeof(login_yahoo_com_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:login_live_com_cer length:sizeof(login_live_com_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:mail_google_com_cer length:sizeof(mail_google_com_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:login_skype_com_cer length:sizeof(login_skype_com_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+    [self validate_one_cert:www_google_com_cer length:sizeof(www_google_com_cer) chain_length:2 trustResult:kSecTrustResultFatalTrustFailure];
+}
+
+@end
+
+@interface AllowlistTests : TrustEvaluationTestCase
+@end
+
+@implementation AllowlistTests
+
+#if !TARGET_OS_BRIDGE
+static SecCertificateRef createCertFromStaticData(const UInt8 *certData, CFIndex certLength)
+{
+    SecCertificateRef cert = NULL;
+    CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, certData, certLength, kCFAllocatorNull);
+    if (data) {
+        cert = SecCertificateCreateWithData(NULL, data);
+        CFRelease(data);
+    }
+    return cert;
+}
+
+- (void)testLeafOnAllowList
+{
+    SecCertificateRef certs[3];
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    CFDateRef date = NULL;
+    CFArrayRef certArray = NULL;
+    CFArrayRef anchorsArray = NULL;
+
+    isnt(certs[0] = createCertFromStaticData(leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)),
+         NULL, "allowlist: create leaf cert");
+    isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
+         NULL, "allowlist: create intermediate ca 1");
+    isnt(certs[2] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
+         NULL, "allowlist: create root");
+
+    isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 3, &kCFTypeArrayCallBacks),
+         NULL, "allowlist: create cert array");
+
+    /* create a trust reference with ssl policy */
+    isnt(policy = SecPolicyCreateBasicX509(), NULL, "allowlist: create policy");
+    ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "allowlist: create trust");
+
+    /* set evaluate date: January 6, 2020 at 2:40:00 AM PST */
+    isnt(date = CFDateCreate(NULL, 600000000.0), NULL, "allowlist: create date");
+    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "allowlist: set verify date");
+
+    /* use a known root CA at this point in time to anchor the chain */
+    isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[2], 1, &kCFTypeArrayCallBacks),
+         NULL, "allowlist: create anchors array");
+    ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "allowlist: set anchors");
+
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "allowlist: evaluate");
+
+    /* expected result is kSecTrustResultUnspecified since cert is on allow list and its issuer chains to a trusted root */
+    ok(trustResult == kSecTrustResultUnspecified, "trustResult 4 expected (got %d)",
+       (int)trustResult);
+
+    /* clean up */
+    for(CFIndex idx=0; idx < 3; idx++) {
+        if (certs[idx]) { CFRelease(certs[idx]); }
+    }
+    if (policy) { CFRelease(policy); }
+    if (trust) { CFRelease(trust); }
+    if (date) { CFRelease(date); }
+    if (certArray) { CFRelease(certArray); }
+    if (anchorsArray) { CFRelease(anchorsArray); }
+}
+
+- (void)testLeafNotOnAllowList
+{
+    SecCertificateRef certs[3];
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    CFDateRef date = NULL;
+    CFArrayRef certArray = NULL;
+    CFArrayRef anchorsArray = NULL;
+
+    isnt(certs[0] = createCertFromStaticData(leafNotOnAllowList_Cert, sizeof(leafNotOnAllowList_Cert)),
+         NULL, "!allowlist: create leaf cert");
+    isnt(certs[1] = createCertFromStaticData(ca1_Cert, sizeof(ca1_Cert)),
+         NULL, "!allowlist: create intermediate ca 1");
+    isnt(certs[2] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
+         NULL, "!allowlist: create root");
+
+    isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 3, &kCFTypeArrayCallBacks),
+         NULL, "!allowlist: create cert array");
+
+    /* create a trust reference with basic policy */
+    isnt(policy = SecPolicyCreateBasicX509(), NULL, "!allowlist: create policy");
+    ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "!allowlist: create trust");
+
+    /* set evaluate date: January 6, 2020 at 2:40:00 AM PST */
+    isnt(date = CFDateCreate(NULL, 600000000.0), NULL, "allowlist: create date");
+    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "!allowlist: set verify date");
+
+    /* use a known root CA at this point in time to anchor the chain */
+    isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[2], 1, &kCFTypeArrayCallBacks),
+         NULL, "allowlist: create anchors array");
+    ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "!allowlist: set anchors");
+
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "!allowlist: evaluate");
+
+    /* expected result is kSecTrustResultFatalTrustFailure, since cert is not on allow list */
+    ok(trustResult == kSecTrustResultFatalTrustFailure,
+       "trustResult 6 expected (got %d)", (int)trustResult);
+
+    /* clean up */
+    for(CFIndex idx=0; idx < 3; idx++) {
+        if (certs[idx]) { CFRelease(certs[idx]); }
+    }
+    if (policy) { CFRelease(policy); }
+    if (trust) { CFRelease(trust); }
+    if (date) { CFRelease(date); }
+    if (certArray) { CFRelease(certArray); }
+    if (anchorsArray) { CFRelease(anchorsArray); }
+}
+
+- (void)testAllowListForRootCA
+{
+    SecCertificateRef certs[3];
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    CFDateRef date = NULL;
+    CFArrayRef certArray = NULL;
+    CFArrayRef anchorsArray = NULL;
+
+    isnt(certs[0] = createCertFromStaticData(leaf_subCANotOnAllowlist_Cert, sizeof(leaf_subCANotOnAllowlist_Cert)),
+         NULL, "!allowlist: create leaf cert");
+    isnt(certs[1] = createCertFromStaticData(subCANotOnAllowlist_Cert, sizeof(subCANotOnAllowlist_Cert)),
+         NULL, "!allowlist: create intermediate ca 1");
+    isnt(certs[2] = createCertFromStaticData(root_Cert, sizeof(root_Cert)),
+         NULL, "!allowlist: create root");
+
+    isnt(certArray = CFArrayCreate(kCFAllocatorDefault, (const void **)&certs[0], 3, &kCFTypeArrayCallBacks),
+         NULL, "!allowlist: create cert array");
+
+    /* create a trust reference with basic policy */
+    isnt(policy = SecPolicyCreateBasicX509(), NULL, "!allowlist: create policy");
+    ok_status(SecTrustCreateWithCertificates(certArray, policy, &trust), "!allowlist: create trust");
+
+    /* set evaluate date: January 6, 2020 at 2:40:00 AM PST */
+    isnt(date = CFDateCreate(NULL, 600000000.0), NULL, "allowlist: create date");
+    ok_status((date) ? SecTrustSetVerifyDate(trust, date) : errSecParam, "!allowlist: set verify date");
+
+    /* use a known root CA at this point in time to anchor the chain */
+    isnt(anchorsArray = CFArrayCreate(NULL, (const void **)&certs[2], 1, &kCFTypeArrayCallBacks),
+         NULL, "allowlist: create anchors array");
+    ok_status((anchorsArray) ? SecTrustSetAnchorCertificates(trust, anchorsArray) : errSecParam, "!allowlist: set anchors");
+
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "!allowlist: evaluate");
+
+    /* expected result is kSecTrustResultRecoverableTrustFailure (if issuer is distrusted)
+     or kSecTrustResultFatalTrustFailure (if issuer is revoked), since cert is not on allow list */
+    ok(trustResult == kSecTrustResultFatalTrustFailure,
+       "trustResult 6 expected (got %d)", (int)trustResult);
+
+    /* clean up */
+    for(CFIndex idx=0; idx < 3; idx++) {
+        if (certs[idx]) { CFRelease(certs[idx]); }
+    }
+    if (policy) { CFRelease(policy); }
+    if (trust) { CFRelease(trust); }
+    if (date) { CFRelease(date); }
+    if (certArray) { CFRelease(certArray); }
+    if (anchorsArray) { CFRelease(anchorsArray); }
+}
+
+- (void)testDateBasedAllowListForRootCA
+{
+    SecCertificateRef root = NULL, beforeInt = NULL, afterInt = NULL,
+    beforeLeaf = NULL, afterLeaf = NULL;
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    NSArray *anchors = nil, *certs = nil;
+    NSDate *verifyDate = nil;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+
+    require(root = SecCertificateCreateWithBytes(NULL, _datetest_root, sizeof(_datetest_root)), out);
+    require(beforeInt = SecCertificateCreateWithBytes(NULL, _datetest_before_int, sizeof(_datetest_before_int)), out);
+    require(afterInt = SecCertificateCreateWithBytes(NULL, _datetest_after_int, sizeof(_datetest_after_int)), out);
+    require(beforeLeaf = SecCertificateCreateWithBytes(NULL, _datetest_before_leaf, sizeof(_datetest_before_leaf)), out);
+    require(afterLeaf = SecCertificateCreateWithBytes(NULL, _datetest_after_leaf, sizeof(_datetest_after_leaf)), out);
+
+    anchors = @[(__bridge id)root];
+    require(policy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com")), out);
+    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:504000000.0];  /* 21 Dec 2016 */
+
+    /* Leaf issued before cutoff should pass */
+    certs = @[(__bridge id)beforeLeaf, (__bridge id)beforeInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation");
+    CFReleaseNull(trust);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Leaf issued after cutoff should fail */
+    certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation");
+    CFReleaseNull(trust);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Intermediate issued after cutoff should fail (even for leaf issued before) */
+    certs = @[(__bridge id)beforeLeaf, (__bridge id)afterInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued after cutoff succeeded evaluation");
+    CFReleaseNull(trust);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Intermediate issued after cutoff should fail */
+    certs = @[(__bridge id)afterLeaf, (__bridge id)afterInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultFatalTrustFailure, "intermediate issued before cutoff succeeded evaluation");
+    CFReleaseNull(trust);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Leaf issued before cutoff should choose acceptable path */
+    certs = @[(__bridge id)beforeLeaf, (__bridge id) afterInt, (__bridge id)beforeInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultUnspecified, "leaf issued before cutoff failed evaluation (multi-path)");
+    CFReleaseNull(trust);
+    trustResult = kSecTrustResultInvalid;
+
+    /* No good path for leaf issued after cutoff */
+    certs = @[(__bridge id)afterLeaf, (__bridge id)beforeInt, (__bridge id)afterInt];
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    is(trustResult, kSecTrustResultFatalTrustFailure, "leaf issued after cutoff succeeded evaluation (multi-path)");
+
+out:
+    CFReleaseNull(root);
+    CFReleaseNull(beforeInt);
+    CFReleaseNull(afterInt);
+    CFReleaseNull(beforeLeaf);
+    CFReleaseNull(afterLeaf);
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+}
+
+- (void)testLeafOnAllowListOtherFailures
+{
+    SecCertificateRef certs[3];
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    NSArray *anchors = nil, *certArray = nil;
+    NSDate *verifyDate = nil;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+
+    memset(certs, 0, 3 * sizeof(SecCertificateRef));
+
+    require(certs[0] = SecCertificateCreateWithBytes(NULL, leafOnAllowList_Cert, sizeof(leafOnAllowList_Cert)), out);
+    require(certs[1] = SecCertificateCreateWithBytes(NULL, ca1_Cert, sizeof(ca1_Cert)), out);
+    require(certs[2] = SecCertificateCreateWithBytes(NULL, root_Cert, sizeof(root_Cert)), out);
+
+    anchors = @[(__bridge id)certs[2]];
+    certArray = @[(__bridge id)certs[0], (__bridge id)certs[1], (__bridge id)certs[2]];
+    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]; // January 6, 2020 at 2:40:00 AM PST
+
+    /* Mismatched policy, should fail */
+    require(policy = SecPolicyCreateSSL(true, (__bridge CFStringRef)@"example.com"), out);
+    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certArray, policy, &trust), out);
+    require_noerr(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors), out);
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
+       "hostname failure with cert on allow list succeeded evaluation");
+    CFReleaseNull(policy);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Expired, should fail */
+    verifyDate = [NSDate dateWithTimeIntervalSinceReferenceDate:500000000.0]; // November 4, 2016 at 5:53:20 PM PDT
+    require_noerr(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verifyDate), out);
+    require_noerr(SecTrustSetPolicies(trust, policy), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
+       "EKU failure with cert on allow list succeeded evaluation");
+    CFReleaseNull(policy);
+    trustResult = kSecTrustResultInvalid;
+
+    /* Apple pinning policy, should fail */
+    require(policy = SecPolicyCreateAppleSSLPinned((__bridge CFStringRef)@"aPolicy",
+                                                   (__bridge CFStringRef)@"example.com", NULL,
+                                                   (__bridge CFStringRef)@"1.2.840.113635.100.6.27.12"), out);
+    require_noerr(SecTrustSetPolicies(trust, policy), out);
+    require_noerr(SecTrustGetTrustResult(trust, &trustResult), out);
+    ok(trustResult == kSecTrustResultRecoverableTrustFailure || trustResult == kSecTrustResultFatalTrustFailure,
+       "Apple pinning policy with cert on allow list succeeded evaluation");
+
+out:
+    CFReleaseNull(certs[0]);
+    CFReleaseNull(certs[1]);
+    CFReleaseNull(certs[2]);
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+}
+#else /* TARGET_OS_BRIDGE */
+/* Allowlists are provided by Valid, which is not supported on bridgeOS */
+- (void)testSkipTests
+{
+    XCTAssert(true);
+}
+#endif
+
+@end
diff --git a/tests/TrustTests/EvaluationTests/AllowlistBlocklistTests_data.h b/tests/TrustTests/EvaluationTests/AllowlistBlocklistTests_data.h
new file mode 100644 (file)
index 0000000..d52467c
--- /dev/null
@@ -0,0 +1,1691 @@
+//
+//  AllowlistBlocklistTests_data.h
+//  Security
+//
+
+#ifndef _TRUSTTESTS_ALLOWLIST_BLOCKLIST_TESTS_
+#define _TRUSTTESTS_ALLOWLIST_BLOCKLIST_TESTS_
+
+/* subject:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */
+/* issuer :/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN-USERFirst-Hardware */
+const uint8_t UTNHardware_cer[] = {
+    0x30,0x82,0x04,0x74,0x30,0x82,0x03,0x5C,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x44,
+    0xBE,0x0C,0x8B,0x50,0x00,0x24,0xB4,0x11,0xD3,0x36,0x2A,0xFE,0x65,0x0A,0xFD,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,
+    0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x0E,0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20,
+    0x43,0x69,0x74,0x79,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,
+    0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,
+    0x77,0x6F,0x72,0x6B,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,
+    0x75,0x73,0x74,0x2E,0x63,0x6F,0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,
+    0x13,0x16,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D,
+    0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x30,0x1E,0x17,0x0D,0x39,0x39,0x30,0x37,
+    0x30,0x39,0x31,0x38,0x31,0x30,0x34,0x32,0x5A,0x17,0x0D,0x31,0x39,0x30,0x37,0x30,
+    0x39,0x31,0x38,0x31,0x39,0x32,0x32,0x5A,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0E,
+    0x53,0x61,0x6C,0x74,0x20,0x4C,0x61,0x6B,0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1E,
+    0x30,0x1C,0x06,0x03,0x55,0x04,0x0A,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,
+    0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4E,0x65,0x74,0x77,0x6F,0x72,0x6B,0x31,0x21,
+    0x30,0x1F,0x06,0x03,0x55,0x04,0x0B,0x13,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,
+    0x77,0x77,0x77,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2E,0x63,0x6F,
+    0x6D,0x31,0x1F,0x30,0x1D,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,0x4E,0x2D,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,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,0xB1,0xF7,0xC3,0x38,0x3F,0xB4,0xA8,0x7F,0xCF,0x39,0x82,0x51,0x67,
+    0xD0,0x6D,0x9F,0xD2,0xFF,0x58,0xF3,0xE7,0x9F,0x2B,0xEC,0x0D,0x89,0x54,0x99,0xB9,
+    0x38,0x99,0x16,0xF7,0xE0,0x21,0x79,0x48,0xC2,0xBB,0x61,0x74,0x12,0x96,0x1D,0x3C,
+    0x6A,0x72,0xD5,0x3C,0x10,0x67,0x3A,0x39,0xED,0x2B,0x13,0xCD,0x66,0xEB,0x95,0x09,
+    0x33,0xA4,0x6C,0x97,0xB1,0xE8,0xC6,0xEC,0xC1,0x75,0x79,0x9C,0x46,0x5E,0x8D,0xAB,
+    0xD0,0x6A,0xFD,0xB9,0x2A,0x55,0x17,0x10,0x54,0xB3,0x19,0xF0,0x9A,0xF6,0xF1,0xB1,
+    0x5D,0xB6,0xA7,0x6D,0xFB,0xE0,0x71,0x17,0x6B,0xA2,0x88,0xFB,0x00,0xDF,0xFE,0x1A,
+    0x31,0x77,0x0C,0x9A,0x01,0x7A,0xB1,0x32,0xE3,0x2B,0x01,0x07,0x38,0x6E,0xC3,0xA5,
+    0x5E,0x23,0xBC,0x45,0x9B,0x7B,0x50,0xC1,0xC9,0x30,0x8F,0xDB,0xE5,0x2B,0x7A,0xD3,
+    0x5B,0xFB,0x33,0x40,0x1E,0xA0,0xD5,0x98,0x17,0xBC,0x8B,0x87,0xC3,0x89,0xD3,0x5D,
+    0xA0,0x8E,0xB2,0xAA,0xAA,0xF6,0x8E,0x69,0x88,0x06,0xC5,0xFA,0x89,0x21,0xF3,0x08,
+    0x9D,0x69,0x2E,0x09,0x33,0x9B,0x29,0x0D,0x46,0x0F,0x8C,0xCC,0x49,0x34,0xB0,0x69,
+    0x51,0xBD,0xF9,0x06,0xCD,0x68,0xAD,0x66,0x4C,0xBC,0x3E,0xAC,0x61,0xBD,0x0A,0x88,
+    0x0E,0xC8,0xDF,0x3D,0xEE,0x7C,0x04,0x4C,0x9D,0x0A,0x5E,0x6B,0x91,0xD6,0xEE,0xC7,
+    0xED,0x28,0x8D,0xAB,0x4D,0x87,0x89,0x73,0xD0,0x6E,0xA4,0xD0,0x1E,0x16,0x8B,0x14,
+    0xE1,0x76,0x44,0x03,0x7F,0x63,0xAC,0xE4,0xCD,0x49,0x9C,0xC5,0x92,0xF4,0xAB,0x32,
+    0xA1,0x48,0x5B,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xB9,0x30,0x81,0xB6,0x30,0x0B,
+    0x06,0x03,0x55,0x1D,0x0F,0x04,0x04,0x03,0x02,0x01,0xC6,0x30,0x0F,0x06,0x03,0x55,
+    0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xA1,0x72,0x5F,0x26,0x1B,0x28,0x98,0x43,0x95,
+    0x5D,0x07,0x37,0xD5,0x85,0x96,0x9D,0x4B,0xD2,0xC3,0x45,0x30,0x44,0x06,0x03,0x55,
+    0x1D,0x1F,0x04,0x3D,0x30,0x3B,0x30,0x39,0xA0,0x37,0xA0,0x35,0x86,0x33,0x68,0x74,
+    0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x75,0x73,0x65,0x72,0x74,0x72,0x75,
+    0x73,0x74,0x2E,0x63,0x6F,0x6D,0x2F,0x55,0x54,0x4E,0x2D,0x55,0x53,0x45,0x52,0x46,
+    0x69,0x72,0x73,0x74,0x2D,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2E,0x63,0x72,
+    0x6C,0x30,0x31,0x06,0x03,0x55,0x1D,0x25,0x04,0x2A,0x30,0x28,0x06,0x08,0x2B,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x05,
+    0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x06,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x03,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0x19,0x0F,0xDE,0x74,0xC6,0x99,0x97,
+    0xAF,0xFC,0xAD,0x28,0x5E,0x75,0x8E,0xEB,0x2D,0x67,0xEE,0x4E,0x7B,0x2B,0xD7,0x0C,
+    0xFF,0xF6,0xDE,0xCB,0x55,0xA2,0x0A,0xE1,0x4C,0x54,0x65,0x93,0x60,0x6B,0x9F,0x12,
+    0x9C,0xAD,0x5E,0x83,0x2C,0xEB,0x5A,0xAE,0xC0,0xE4,0x2D,0xF4,0x00,0x63,0x1D,0xB8,
+    0xC0,0x6C,0xF2,0xCF,0x49,0xBB,0x4D,0x93,0x6F,0x06,0xA6,0x0A,0x22,0xB2,0x49,0x62,
+    0x08,0x4E,0xFF,0xC8,0xC8,0x14,0xB2,0x88,0x16,0x5D,0xE7,0x01,0xE4,0x12,0x95,0xE5,
+    0x45,0x34,0xB3,0x8B,0x69,0xBD,0xCF,0xB4,0x85,0x8F,0x75,0x51,0x9E,0x7D,0x3A,0x38,
+    0x3A,0x14,0x48,0x12,0xC6,0xFB,0xA7,0x3B,0x1A,0x8D,0x0D,0x82,0x40,0x07,0xE8,0x04,
+    0x08,0x90,0xA1,0x89,0xCB,0x19,0x50,0xDF,0xCA,0x1C,0x01,0xBC,0x1D,0x04,0x19,0x7B,
+    0x10,0x76,0x97,0x3B,0xEE,0x90,0x90,0xCA,0xC4,0x0E,0x1F,0x16,0x6E,0x75,0xEF,0x33,
+    0xF8,0xD3,0x6F,0x5B,0x1E,0x96,0xE3,0xE0,0x74,0x77,0x74,0x7B,0x8A,0xA2,0x6E,0x2D,
+    0xDD,0x76,0xD6,0x39,0x30,0x82,0xF0,0xAB,0x9C,0x52,0xF2,0x2A,0xC7,0xAF,0x49,0x5E,
+    0x7E,0xC7,0x68,0xE5,0x82,0x81,0xC8,0x6A,0x27,0xF9,0x27,0x88,0x2A,0xD5,0x58,0x50,
+    0x95,0x1F,0xF0,0x3B,0x1C,0x57,0xBB,0x7D,0x14,0x39,0x62,0x2B,0x9A,0xC9,0x94,0x92,
+    0x2A,0xA3,0x22,0x0C,0xFF,0x89,0x26,0x7D,0x5F,0x23,0x2B,0x47,0xD7,0x15,0x1D,0xA9,
+    0x6A,0x9E,0x51,0x0D,0x2A,0x51,0x9E,0x81,0xF9,0xD4,0x3B,0x5E,0x70,0x12,0x7F,0x10,
+    0x32,0x9C,0x1E,0xBB,0x9D,0xF8,0x66,0xA8,
+};
+
+unsigned char Global_Trustee_cer[] = {
+    0x30,0x82,0x06,0xdd,0x30,0x82,0x05,0xc5,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0xd8,0xf3,0x5f,0x4e,
+    0xb7,0x87,0x2b,0x2d,0xab,0x06,0x92,0xe3,0x15,0x38,0x2f,0xb0,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xe3,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x07,0x13,0x05,0x54,0x61,0x6d,0x70,0x61,0x31,
+    0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,0x61,0x67,
+    0x65,0x20,0x31,0x30,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0a,0x13,0x0e,0x47,0x6c,0x6f,0x62,0x61,
+    0x6c,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x65,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x0b,0x13,0x0e,
+    0x47,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x54,0x72,0x75,0x73,0x74,0x65,0x65,0x31,0x28,0x30,0x26,0x06,0x03,
+    0x55,0x04,0x0b,0x13,0x1f,0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,
+    0x72,0x6f,0x75,0x70,0x20,0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,
+    0x06,0x03,0x55,0x04,0x0b,0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x17,
+    0x30,0x15,0x06,0x03,0x55,0x04,0x03,0x13,0x0e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x74,0x72,0x75,0x73,
+    0x74,0x65,0x65,0x30,0x82,0x02,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01,
+    0x05,0x00,0x03,0x82,0x02,0x0f,0x00,0x30,0x82,0x02,0x0a,0x02,0x82,0x02,0x01,0x00,0xd9,0x74,0xf2,0xaa,
+    0x41,0x1d,0xdf,0xf5,0xc2,0x16,0x43,0x49,0x5c,0x29,0xbf,0xb6,0x89,0x74,0x29,0xbc,0x9c,0x8d,0x0c,0x46,
+    0x4f,0x59,0x7e,0xb2,0x41,0x17,0x66,0x34,0x0c,0x65,0x89,0xe1,0x6c,0x25,0xe3,0x86,0x0a,0x9e,0x22,0x45,
+    0x22,0x8c,0xdd,0x9d,0xe6,0xa3,0x95,0xde,0xdc,0x88,0x02,0x55,0x5c,0xe3,0x5b,0x91,0x75,0xeb,0x26,0x69,
+    0x63,0xb9,0x2e,0xc6,0xca,0x2e,0x27,0xdf,0x88,0xba,0x02,0x20,0x6e,0xfe,0xb9,0x0b,0x29,0xd7,0xa7,0xd6,
+    0xd7,0x48,0x1a,0x1c,0xce,0xdd,0x1f,0xa9,0x27,0x0e,0x62,0x4f,0xa1,0x96,0x1e,0xdd,0x54,0x3a,0x34,0x63,
+    0x4a,0x76,0xf5,0x77,0x7d,0x59,0x67,0xd8,0x10,0xd4,0xb5,0x0f,0x3a,0x43,0x22,0x98,0xdb,0xf4,0x09,0xc4,
+    0x0a,0x70,0xce,0xdd,0x90,0xd4,0x2f,0xef,0x74,0x13,0xc3,0xcd,0xc2,0x89,0x39,0x62,0x15,0x9d,0xe6,0x74,
+    0xa8,0xe8,0x9b,0xf0,0x63,0x6e,0x9c,0x89,0xb6,0x0e,0xad,0x9b,0xf7,0xcc,0x82,0xe8,0xe8,0x2d,0xb8,0x0b,
+    0xda,0x22,0xec,0x49,0x85,0x07,0x88,0x99,0x98,0x3f,0xf4,0x74,0xa9,0x09,0xf7,0x81,0x7c,0x97,0x0b,0x59,
+    0x99,0x18,0x72,0x8b,0xdb,0x94,0x82,0x2b,0xa7,0xe8,0xaa,0x6b,0x97,0xbf,0x88,0x7e,0x75,0xb0,0x8b,0x45,
+    0x45,0x0c,0xc7,0xa8,0x09,0xea,0x1b,0x41,0x58,0x30,0x3b,0x5f,0x78,0x65,0x15,0x34,0xd2,0xe4,0x3c,0x34,
+    0x0d,0x1d,0xd8,0x64,0x3c,0x8a,0xa5,0x56,0x49,0x99,0x28,0x2d,0x4b,0xf2,0xcf,0xcd,0xd9,0x6e,0x49,0x64,
+    0x9b,0xa9,0x79,0x90,0x77,0x55,0xa9,0x08,0x1b,0xad,0x1a,0x74,0x9e,0xe0,0x03,0x93,0x0a,0x09,0xb7,0xad,
+    0xa7,0xb4,0x5c,0xef,0x83,0x6c,0xb7,0x9a,0xb4,0xc6,0x68,0x40,0x80,0x1d,0x42,0xd1,0x6e,0x79,0x9b,0xa9,
+    0x19,0x21,0x9a,0x9c,0xf9,0x86,0x2d,0x00,0xd1,0x34,0xfe,0xe0,0xb6,0xf9,0x55,0xb6,0xf5,0x26,0xc5,0x95,
+    0x16,0xa5,0x7c,0x73,0x9f,0x0a,0x29,0x89,0xac,0x3a,0x98,0xf7,0x9b,0x74,0x67,0xb7,0x90,0xb7,0x5d,0x09,
+    0x23,0x6a,0x6a,0xed,0x2c,0x10,0xee,0x53,0x0a,0x10,0xf0,0x16,0x1f,0x57,0xb3,0xb1,0x0d,0x79,0x91,0x19,
+    0xb0,0xeb,0xcd,0x30,0x3f,0xa0,0x14,0x5f,0xb3,0xc6,0xfd,0x5c,0x33,0xa7,0xb0,0xff,0x98,0xb0,0x55,0x8c,
+    0xb9,0xa5,0xf2,0x6f,0x47,0x24,0x49,0x21,0x69,0xcc,0x42,0xa2,0x51,0x00,0x40,0x85,0x8c,0x82,0x82,0xab,
+    0x32,0xa5,0xcb,0x9a,0xdc,0xd0,0xd9,0x18,0x0d,0xdf,0x19,0xf4,0xaf,0x83,0x0d,0xc1,0x3e,0x31,0xdb,0x24,
+    0x48,0xb6,0x75,0x80,0xa1,0xe1,0xc9,0x77,0x64,0x1e,0xa7,0xe5,0x8b,0x7f,0x15,0x4d,0x4b,0xa7,0xc2,0xd0,
+    0xed,0x79,0x95,0x5e,0x91,0x31,0xec,0x18,0xff,0x4e,0x9f,0x48,0x14,0xea,0x75,0xba,0x21,0xce,0x29,0x76,
+    0xe9,0x1f,0x4e,0x51,0x87,0x2e,0xb3,0xcc,0x04,0x60,0xba,0x23,0x1f,0x1f,0x65,0xb2,0x0a,0xb8,0xd5,0x6e,
+    0x8f,0x4b,0x42,0x89,0x47,0xa9,0x81,0x90,0x5b,0x2b,0xb2,0xb6,0xae,0xe6,0xa0,0x70,0x7b,0x78,0x90,0x0a,
+    0x7a,0xc5,0xe5,0xe7,0xc5,0xfb,0x0a,0xf6,0x2f,0x69,0x8c,0x8c,0x1f,0x57,0xe0,0x06,0x99,0xff,0x11,0xd5,
+    0x52,0x32,0x20,0x97,0x27,0x98,0xee,0x65,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xd4,0x30,0x82,0x01,
+    0xd0,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,
+    0x98,0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x0e,0x04,0x16,0x04,0x14,0xb7,0xc3,0xde,0x1a,0x43,0xed,0x41,0x97,0xa9,0x8f,0x29,0x78,0x9c,0x03,0xb9,
+    0xac,0x40,0x42,0x00,0xac,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,
+    0xa0,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,
+    0x1d,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,
+    0x0c,0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,
+    0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,
+    0x75,0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,
+    0x06,0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,
+    0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,
+    0x2f,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,
+    0x61,0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,
+    0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,
+    0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,
+    0x63,0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,
+    0x3b,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x63,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,
+    0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,
+    0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x19,
+    0x06,0x03,0x55,0x1d,0x11,0x04,0x12,0x30,0x10,0x82,0x0e,0x67,0x6c,0x6f,0x62,0x61,0x6c,0x20,0x74,0x72,
+    0x75,0x73,0x74,0x65,0x65,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x8f,0xba,0x75,0xba,0x39,0xd4,0x26,0xd3,0x70,0x0f,0xc4,0xb3,0x02,0xa7,0xc5,
+    0x12,0x23,0x71,0xc9,0xfe,0x63,0xe9,0xa3,0x62,0x78,0x24,0x44,0x4f,0xd4,0xb9,0x11,0x3e,0x1f,0xc7,0x28,
+    0xe7,0x55,0x6b,0xee,0xf4,0xe1,0x00,0x91,0x86,0x8a,0xc9,0x09,0x6b,0x9f,0x2e,0xa4,0x45,0x39,0xd1,0x61,
+    0x62,0x5e,0x93,0xa5,0x05,0x45,0x78,0x9f,0x60,0x12,0x2c,0xf4,0x6c,0x65,0x65,0x0d,0xcc,0x46,0x34,0x8b,
+    0x28,0xba,0xa0,0xc6,0xf4,0x99,0x71,0x64,0xf3,0x22,0x76,0xac,0x4f,0xf3,0x62,0xc9,0xa7,0x33,0x5a,0x07,
+    0x1f,0x3d,0xc9,0x86,0x80,0xdc,0xdb,0x04,0x2f,0x87,0x27,0xe8,0xbf,0x48,0x44,0x81,0xc0,0xf0,0x49,0x23,
+    0x6e,0x1f,0xe5,0xe4,0x03,0x86,0x24,0x13,0xa2,0x85,0x62,0x7c,0x58,0x04,0xca,0xe6,0x8d,0x13,0x72,0x0a,
+    0xba,0x56,0x44,0xa2,0x0f,0xbc,0xfb,0xa0,0x3d,0x0d,0x2a,0x7f,0xfb,0x9e,0xa9,0x09,0x3d,0xb7,0x5a,0xd4,
+    0x8a,0x8d,0xe1,0x25,0xe8,0xa4,0x09,0x84,0x70,0xad,0x12,0x44,0xb9,0xcf,0xb9,0x33,0x7a,0xba,0x5c,0xe6,
+    0x4b,0xa6,0xbb,0x05,0x06,0x98,0xff,0xf2,0x98,0x52,0x7b,0x77,0x80,0x27,0x4a,0xd9,0xe2,0xfa,0xb9,0x52,
+    0xd4,0xfb,0xfb,0xe6,0xd6,0x2d,0x9e,0x8f,0xc1,0x15,0x44,0x8d,0x9b,0x74,0x2f,0xee,0x94,0x5a,0x4e,0xd3,
+    0xc4,0x8b,0x8a,0xac,0x43,0x9d,0x73,0xf6,0xae,0x0c,0x87,0x89,0xad,0x87,0xc9,0xc9,0xc7,0xdd,0xba,0x14,
+    0x60,0x7a,0xf8,0xb5,0x35,0x9d,0xc2,0x8d,0xc6,0x96,0x81,0x0d,0xa9,0x52,0x8a,0x29,0x40,0x04,0xe9,0x19,
+    0xb4
+};
+unsigned int Global_Trustee_cer_len = 1761;
+
+unsigned char UTN_USERFirst_Hardware_cer[] = {
+    0x30,0x82,0x04,0x74,0x30,0x82,0x03,0x5c,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x44,0xbe,0x0c,0x8b,0x50,
+    0x00,0x24,0xb4,0x11,0xd3,0x36,0x2a,0xfe,0x65,0x0a,0xfd,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+    0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,0x79,
+    0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,
+    0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,
+    0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,0x72,
+    0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,
+    0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,
+    0x30,0x1e,0x17,0x0d,0x39,0x39,0x30,0x37,0x30,0x39,0x31,0x38,0x31,0x30,0x34,0x32,0x5a,0x17,0x0d,0x31,
+    0x39,0x30,0x37,0x30,0x39,0x31,0x38,0x31,0x39,0x32,0x32,0x5a,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,
+    0x54,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,
+    0x65,0x20,0x43,0x69,0x74,0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,
+    0x20,0x55,0x53,0x45,0x52,0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,
+    0x30,0x1f,0x06,0x03,0x55,0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,
+    0x75,0x73,0x65,0x72,0x74,0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x16,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,
+    0x72,0x64,0x77,0x61,0x72,0x65,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,0xb1,
+    0xf7,0xc3,0x38,0x3f,0xb4,0xa8,0x7f,0xcf,0x39,0x82,0x51,0x67,0xd0,0x6d,0x9f,0xd2,0xff,0x58,0xf3,0xe7,
+    0x9f,0x2b,0xec,0x0d,0x89,0x54,0x99,0xb9,0x38,0x99,0x16,0xf7,0xe0,0x21,0x79,0x48,0xc2,0xbb,0x61,0x74,
+    0x12,0x96,0x1d,0x3c,0x6a,0x72,0xd5,0x3c,0x10,0x67,0x3a,0x39,0xed,0x2b,0x13,0xcd,0x66,0xeb,0x95,0x09,
+    0x33,0xa4,0x6c,0x97,0xb1,0xe8,0xc6,0xec,0xc1,0x75,0x79,0x9c,0x46,0x5e,0x8d,0xab,0xd0,0x6a,0xfd,0xb9,
+    0x2a,0x55,0x17,0x10,0x54,0xb3,0x19,0xf0,0x9a,0xf6,0xf1,0xb1,0x5d,0xb6,0xa7,0x6d,0xfb,0xe0,0x71,0x17,
+    0x6b,0xa2,0x88,0xfb,0x00,0xdf,0xfe,0x1a,0x31,0x77,0x0c,0x9a,0x01,0x7a,0xb1,0x32,0xe3,0x2b,0x01,0x07,
+    0x38,0x6e,0xc3,0xa5,0x5e,0x23,0xbc,0x45,0x9b,0x7b,0x50,0xc1,0xc9,0x30,0x8f,0xdb,0xe5,0x2b,0x7a,0xd3,
+    0x5b,0xfb,0x33,0x40,0x1e,0xa0,0xd5,0x98,0x17,0xbc,0x8b,0x87,0xc3,0x89,0xd3,0x5d,0xa0,0x8e,0xb2,0xaa,
+    0xaa,0xf6,0x8e,0x69,0x88,0x06,0xc5,0xfa,0x89,0x21,0xf3,0x08,0x9d,0x69,0x2e,0x09,0x33,0x9b,0x29,0x0d,
+    0x46,0x0f,0x8c,0xcc,0x49,0x34,0xb0,0x69,0x51,0xbd,0xf9,0x06,0xcd,0x68,0xad,0x66,0x4c,0xbc,0x3e,0xac,
+    0x61,0xbd,0x0a,0x88,0x0e,0xc8,0xdf,0x3d,0xee,0x7c,0x04,0x4c,0x9d,0x0a,0x5e,0x6b,0x91,0xd6,0xee,0xc7,
+    0xed,0x28,0x8d,0xab,0x4d,0x87,0x89,0x73,0xd0,0x6e,0xa4,0xd0,0x1e,0x16,0x8b,0x14,0xe1,0x76,0x44,0x03,
+    0x7f,0x63,0xac,0xe4,0xcd,0x49,0x9c,0xc5,0x92,0xf4,0xab,0x32,0xa1,0x48,0x5b,0x02,0x03,0x01,0x00,0x01,
+    0xa3,0x81,0xb9,0x30,0x81,0xb6,0x30,0x0b,0x06,0x03,0x55,0x1d,0x0f,0x04,0x04,0x03,0x02,0x01,0xc6,0x30,
+    0x0f,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x05,0x30,0x03,0x01,0x01,0xff,0x30,0x1d,0x06,0x03,
+    0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,0x43,0x95,0x5d,0x07,0x37,0xd5,
+    0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x44,0x06,0x03,0x55,0x1d,0x1f,0x04,0x3d,0x30,0x3b,0x30,0x39,
+    0xa0,0x37,0xa0,0x35,0x86,0x33,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x75,0x73,0x65,
+    0x72,0x74,0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,
+    0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x31,0x06,
+    0x03,0x55,0x1d,0x25,0x04,0x2a,0x30,0x28,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,
+    0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x05,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x06,0x06,0x08,
+    0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x07,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,
+    0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x47,0x19,0x0f,0xde,0x74,0xc6,0x99,0x97,0xaf,0xfc,0xad,0x28,
+    0x5e,0x75,0x8e,0xeb,0x2d,0x67,0xee,0x4e,0x7b,0x2b,0xd7,0x0c,0xff,0xf6,0xde,0xcb,0x55,0xa2,0x0a,0xe1,
+    0x4c,0x54,0x65,0x93,0x60,0x6b,0x9f,0x12,0x9c,0xad,0x5e,0x83,0x2c,0xeb,0x5a,0xae,0xc0,0xe4,0x2d,0xf4,
+    0x00,0x63,0x1d,0xb8,0xc0,0x6c,0xf2,0xcf,0x49,0xbb,0x4d,0x93,0x6f,0x06,0xa6,0x0a,0x22,0xb2,0x49,0x62,
+    0x08,0x4e,0xff,0xc8,0xc8,0x14,0xb2,0x88,0x16,0x5d,0xe7,0x01,0xe4,0x12,0x95,0xe5,0x45,0x34,0xb3,0x8b,
+    0x69,0xbd,0xcf,0xb4,0x85,0x8f,0x75,0x51,0x9e,0x7d,0x3a,0x38,0x3a,0x14,0x48,0x12,0xc6,0xfb,0xa7,0x3b,
+    0x1a,0x8d,0x0d,0x82,0x40,0x07,0xe8,0x04,0x08,0x90,0xa1,0x89,0xcb,0x19,0x50,0xdf,0xca,0x1c,0x01,0xbc,
+    0x1d,0x04,0x19,0x7b,0x10,0x76,0x97,0x3b,0xee,0x90,0x90,0xca,0xc4,0x0e,0x1f,0x16,0x6e,0x75,0xef,0x33,
+    0xf8,0xd3,0x6f,0x5b,0x1e,0x96,0xe3,0xe0,0x74,0x77,0x74,0x7b,0x8a,0xa2,0x6e,0x2d,0xdd,0x76,0xd6,0x39,
+    0x30,0x82,0xf0,0xab,0x9c,0x52,0xf2,0x2a,0xc7,0xaf,0x49,0x5e,0x7e,0xc7,0x68,0xe5,0x82,0x81,0xc8,0x6a,
+    0x27,0xf9,0x27,0x88,0x2a,0xd5,0x58,0x50,0x95,0x1f,0xf0,0x3b,0x1c,0x57,0xbb,0x7d,0x14,0x39,0x62,0x2b,
+    0x9a,0xc9,0x94,0x92,0x2a,0xa3,0x22,0x0c,0xff,0x89,0x26,0x7d,0x5f,0x23,0x2b,0x47,0xd7,0x15,0x1d,0xa9,
+    0x6a,0x9e,0x51,0x0d,0x2a,0x51,0x9e,0x81,0xf9,0xd4,0x3b,0x5e,0x70,0x12,0x7f,0x10,0x32,0x9c,0x1e,0xbb,
+    0x9d,0xf8,0x66,0xa8
+};
+unsigned int UTN_USERFirst_Hardware_cer_len = 1144;
+
+unsigned char addons_mozilla_org_cer[] = {
+    0x30,0x82,0x05,0xf8,0x30,0x82,0x04,0xe0,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0x92,0x39,0xd5,0x34,
+    0x8f,0x40,0xd1,0x69,0x5a,0x74,0x54,0x70,0xe1,0xf2,0x3f,0x43,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xe2,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,
+    0x68,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,
+    0x61,0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,
+    0x67,0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,
+    0x65,0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,
+    0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,
+    0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,
+    0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x1b,0x30,0x19,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x12,0x61,0x64,0x64,0x6f,0x6e,0x73,0x2e,0x6d,0x6f,0x7a,0x69,0x6c,0x6c,0x61,0x2e,0x6f,
+    0x72,0x67,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,0xab,0xc6,0x6d,0x36,0xf3,
+    0x15,0x73,0x78,0x83,0x73,0xce,0x74,0x85,0xd5,0xae,0xec,0xb2,0xf0,0xe0,0x24,0x1f,0x13,0x83,0xb8,0x20,
+    0xac,0xbb,0x9a,0xfe,0x88,0xbb,0xab,0xa1,0x1d,0x0b,0x1f,0x45,0x00,0xaa,0x49,0xb7,0x35,0x37,0x0c,0x6a,
+    0xef,0x47,0x4c,0xb9,0xd1,0xbe,0xe3,0x57,0x12,0x04,0x8d,0x92,0xc7,0xb6,0xec,0x01,0xbc,0xb6,0xda,0xc7,
+    0x81,0x38,0x20,0xad,0x72,0x85,0xe6,0x0e,0xfc,0x81,0x6c,0x07,0xad,0x68,0x76,0x38,0xc5,0x44,0xd7,0xcc,
+    0xc6,0x4a,0xc5,0x97,0x3e,0x64,0xf4,0x51,0xe6,0xf0,0x7e,0xb2,0xec,0x56,0xf7,0x25,0x82,0x4d,0x49,0x98,
+    0xcb,0x16,0x98,0xdd,0x23,0xf1,0x89,0x91,0xd1,0x17,0x97,0x40,0x99,0x26,0xd6,0xe2,0xa2,0x2b,0x5e,0xdf,
+    0xbd,0x89,0xf2,0x1b,0x1a,0x53,0x2d,0xcc,0x50,0x41,0x7a,0xd0,0x3d,0x2a,0x0c,0x55,0x70,0x14,0x01,0xe9,
+    0x58,0x49,0x10,0x7a,0x0b,0x93,0x82,0x8b,0xe1,0x1e,0xed,0x3a,0x80,0x10,0x82,0xce,0x96,0x8a,0x34,0xf0,
+    0xcc,0xd7,0xd3,0xb9,0xb4,0x50,0x87,0x55,0x54,0x09,0xb8,0x9d,0x42,0x28,0x55,0x00,0xe5,0x8c,0x35,0x54,
+    0xbf,0xdd,0x25,0x91,0x46,0xb7,0x0d,0xe5,0x5d,0x83,0xa8,0xe5,0x8b,0xfb,0x84,0xe4,0x3c,0xae,0x76,0xda,
+    0xc4,0x43,0x2b,0x5b,0x74,0x0b,0xf8,0xbe,0x5d,0x68,0xf1,0x78,0x5b,0xb5,0xce,0x7d,0xf1,0x5d,0x99,0x40,
+    0xda,0xca,0xee,0x38,0x81,0x50,0xbe,0x98,0xa1,0x6c,0xb8,0x24,0xad,0xf3,0xaf,0x8c,0x0f,0xd7,0x11,0x28,
+    0x2c,0x84,0x18,0x4c,0x7d,0xb5,0xd9,0x8f,0x30,0xb5,0x1b,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xf0,
+    0x30,0x82,0x01,0xec,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,
+    0x26,0x1b,0x28,0x98,0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,
+    0x03,0x55,0x1d,0x0e,0x04,0x16,0x04,0x14,0xdd,0x80,0xd2,0x54,0x3d,0xf7,0x4c,0x70,0xca,0xa3,0xb0,0xdd,
+    0x34,0x7a,0x32,0xe4,0xe8,0x3b,0x5a,0x3b,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,
+    0x03,0x02,0x05,0xa0,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,
+    0x06,0x03,0x55,0x1d,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,
+    0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,
+    0x30,0x3b,0x06,0x0c,0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,
+    0x73,0x65,0x63,0x75,0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,
+    0x53,0x30,0x7b,0x06,0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,
+    0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,
+    0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,
+    0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,
+    0x74,0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,
+    0x30,0x63,0x30,0x3b,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,
+    0x63,0x72,0x74,0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,
+    0x70,0x3a,0x2f,0x2f,0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,
+    0x6d,0x30,0x35,0x06,0x03,0x55,0x1d,0x11,0x04,0x2e,0x30,0x2c,0x82,0x12,0x61,0x64,0x64,0x6f,0x6e,0x73,
+    0x2e,0x6d,0x6f,0x7a,0x69,0x6c,0x6c,0x61,0x2e,0x6f,0x72,0x67,0x82,0x16,0x77,0x77,0x77,0x2e,0x61,0x64,
+    0x64,0x6f,0x6e,0x73,0x2e,0x6d,0x6f,0x7a,0x69,0x6c,0x6c,0x61,0x2e,0x6f,0x72,0x67,0x30,0x0d,0x06,0x09,
+    0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x33,0x3b,0x63,0x15,
+    0xfc,0xb1,0xec,0x14,0x2c,0x93,0xdd,0x75,0x94,0xde,0x81,0x5a,0xd9,0x4e,0x99,0xbe,0xfb,0x4a,0xa4,0x39,
+    0x55,0x4d,0xa1,0x40,0x7a,0xde,0x13,0x2a,0x87,0xa9,0x37,0xcf,0xe8,0xd5,0xfb,0xad,0xd1,0x7b,0x6d,0x6f,
+    0x8c,0x20,0x87,0x82,0x54,0xe6,0x57,0x49,0xbc,0x20,0x28,0x84,0xcd,0xd6,0x01,0xd9,0x93,0x8b,0x17,0x6e,
+    0x23,0x66,0xe5,0x84,0xc8,0x80,0x3f,0xc6,0xa1,0x70,0x80,0xe4,0xec,0x4d,0x1d,0xf9,0xfc,0x91,0x5a,0x73,
+    0x62,0x29,0x9a,0xf7,0x20,0x1c,0x61,0xe0,0x8b,0x39,0x9f,0xca,0xbc,0x7e,0x8d,0xdd,0xbc,0xd9,0xb1,0xe3,
+    0x9f,0x9e,0xdf,0x15,0x53,0x91,0x21,0x52,0x0b,0xd9,0x1a,0x23,0x0f,0x66,0x36,0xdb,0xac,0x93,0x96,0x4a,
+    0xa3,0xa5,0x22,0xcf,0x29,0xf7,0xa2,0x99,0xa8,0xf6,0xb6,0xd9,0x40,0xae,0xd9,0x7e,0xb6,0xf6,0x58,0x2e,
+    0x9b,0xac,0x36,0xca,0x64,0x8f,0x65,0x52,0xdc,0x86,0x9c,0x82,0xab,0x6e,0x50,0x4b,0xda,0x5f,0xfa,0x05,
+    0x00,0x88,0x30,0x0e,0xde,0x8d,0x56,0xbf,0x81,0x47,0x8d,0x3d,0x06,0xe2,0xb2,0x62,0x92,0x67,0x8f,0x9e,
+    0xc8,0x9a,0xb2,0xe5,0x06,0xb8,0x70,0x24,0xb8,0x77,0x7c,0x23,0x0a,0x38,0xc3,0x79,0x08,0xd8,0xb1,0x51,
+    0x9d,0xac,0x95,0x11,0xc7,0x40,0x17,0x9e,0xa3,0x1c,0x8f,0xf2,0x11,0xa7,0x68,0x27,0xda,0x49,0x05,0x84,
+    0x18,0x7c,0x58,0x2d,0x01,0x67,0x5c,0xe5,0x9f,0xa1,0x29,0xbb,0x4a,0x39,0x45,0x2f,0xbf,0x11,0xaa,0x79,
+    0xa2,0xed,0xb4,0xd4,0xb5,0x65,0x43,0xb7,0x93,0x46,0x8a,0xd3
+};
+unsigned int addons_mozilla_org_cer_len = 1532;
+
+unsigned char login_live_com_cer[] = {
+    0x30,0x82,0x05,0xec,0x30,0x82,0x04,0xd4,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0xb0,0xb7,0x13,0x3e,
+    0xd0,0x96,0xf9,0xb5,0x6f,0xae,0x91,0xc8,0x74,0xbd,0x3a,0xc0,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xde,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,
+    0x68,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,
+    0x61,0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,
+    0x67,0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,
+    0x65,0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,
+    0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,
+    0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,
+    0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x17,0x30,0x15,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x0e,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x6c,0x69,0x76,0x65,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,0xf3,0xfc,0x2b,0x2f,0xef,0xe1,0xad,0x59,0xf0,
+    0x42,0x3c,0xc2,0xf1,0x82,0xbf,0x2c,0x41,0x93,0xd1,0xf6,0x98,0x33,0x95,0x4c,0xbc,0x62,0xf1,0x95,0x58,
+    0x08,0xb6,0xe9,0x7b,0x77,0x48,0xb0,0xd3,0xdc,0x17,0x3f,0xbc,0x6e,0xe6,0xec,0x1e,0xec,0x8d,0x17,0xfe,
+    0x1c,0x24,0xc6,0x3e,0x67,0x3d,0x92,0x95,0xa2,0x30,0xc0,0xa7,0x57,0x20,0xcf,0x70,0x88,0x97,0x4a,0x05,
+    0x93,0x79,0x93,0x42,0x97,0x2f,0x3e,0xff,0xc4,0x14,0x14,0x28,0xa2,0x13,0x36,0xb4,0xf8,0xee,0xbe,0x1d,
+    0xbc,0x78,0x5d,0x61,0x93,0x5f,0xeb,0x88,0xd7,0xd1,0xe4,0x2b,0x9a,0xcd,0x58,0xe2,0x07,0x45,0x9f,0x4f,
+    0xb8,0xb9,0x40,0x6a,0x33,0x2c,0x5b,0x21,0x03,0x5a,0x4a,0x94,0xf2,0x7a,0x97,0x59,0x1b,0xa8,0xb5,0x42,
+    0xd8,0x83,0x00,0xaa,0x34,0xcc,0xa7,0x76,0xd0,0x47,0x03,0x5f,0x05,0xaf,0x3b,0xe1,0xb9,0xa1,0x34,0x25,
+    0xb7,0x6c,0x5f,0x9a,0x30,0x84,0x98,0xc2,0xc2,0xd7,0xf2,0xb8,0x42,0x4a,0x10,0x55,0xbd,0xfa,0x53,0x81,
+    0x5d,0x8d,0x68,0x66,0x45,0x2c,0x52,0x7e,0xe5,0xc4,0x04,0xc3,0x54,0xe7,0xc3,0x39,0xda,0x7a,0x4a,0xc5,
+    0xb9,0x98,0x82,0x20,0xe1,0x2c,0x60,0x57,0xbf,0xba,0xf2,0x46,0x00,0xbc,0x5f,0x3a,0xdc,0xe3,0x33,0x97,
+    0xf8,0x4a,0x98,0xb9,0xec,0x33,0x4f,0x2d,0x60,0x6c,0x15,0x92,0xa6,0x81,0x4a,0x0b,0xe9,0xec,0x76,0x70,
+    0x34,0x31,0x17,0x70,0xe6,0x70,0x4b,0x8e,0x8b,0xd3,0x75,0xcb,0x78,0x49,0xab,0x66,0x9b,0x86,0x9f,0x8f,
+    0xa9,0xc4,0x01,0xe8,0xca,0x1b,0xe7,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xe8,0x30,0x82,0x01,0xe4,
+    0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,
+    0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,
+    0x04,0x16,0x04,0x14,0xd4,0x64,0xf6,0xa9,0xe8,0xa5,0x7e,0xd7,0xbf,0x63,0x52,0x03,0x83,0x53,0xdb,0xc5,
+    0x41,0x8d,0xea,0x80,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,
+    0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,0x01,
+    0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,
+    0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,0x75,
+    0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,0x06,
+    0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,0x2d,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,
+    0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3b,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,
+    0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x2d,0x06,
+    0x03,0x55,0x1d,0x11,0x04,0x26,0x30,0x24,0x82,0x0e,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x6c,0x69,0x76,0x65,
+    0x2e,0x63,0x6f,0x6d,0x82,0x12,0x77,0x77,0x77,0x2e,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x6c,0x69,0x76,0x65,
+    0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,
+    0x82,0x01,0x01,0x00,0x54,0xe3,0xa4,0x9a,0x24,0xd2,0xf3,0x1d,0x42,0xad,0x1b,0xf0,0x1e,0xab,0xfb,0xda,
+    0xd5,0xaa,0xe9,0xcf,0x5a,0xb3,0x1e,0x57,0x7b,0x31,0xf2,0x6e,0x57,0x4b,0x31,0xaf,0x33,0xbb,0xb6,0x0d,
+    0x15,0xc7,0x5e,0x59,0x01,0xce,0x44,0xb5,0xb7,0xbf,0x09,0xc9,0xd5,0xdc,0x69,0x84,0xe9,0xc5,0x1a,0xb7,
+    0xf0,0x3e,0xd4,0xc0,0x24,0xbd,0x29,0x5f,0xb4,0xe9,0xd6,0x58,0xeb,0x45,0x11,0x89,0x34,0x34,0xd3,0x11,
+    0xeb,0x34,0xce,0x2a,0x4f,0x00,0x3d,0xf6,0x72,0xef,0x69,0x66,0xc0,0x9f,0x9a,0xac,0x7e,0x70,0x50,0xac,
+    0x55,0x47,0xda,0xbe,0x43,0x5b,0xec,0x8b,0xc8,0xc5,0x23,0x84,0xc9,0x9f,0xb6,0x52,0x08,0xcf,0x91,0x1b,
+    0x2f,0x80,0x69,0xe6,0x34,0x33,0xe6,0xb3,0x9f,0xa4,0xe5,0x0d,0x9a,0x15,0xf9,0x57,0xfc,0x0b,0xa9,0x41,
+    0x0b,0xf5,0xff,0x58,0x41,0x92,0x22,0x27,0x66,0x12,0x06,0xc7,0x2a,0xd8,0x59,0xa7,0xc6,0xdf,0x44,0x12,
+    0x4f,0xc0,0xa8,0x7f,0xa7,0x41,0xc8,0xc8,0x69,0xff,0xba,0x05,0x2e,0x97,0xad,0x3b,0xd0,0xeb,0xf3,0x15,
+    0x6d,0x7e,0x1b,0xe5,0xba,0xdd,0x34,0xbe,0x22,0x11,0xec,0x68,0x98,0x33,0x81,0x02,0x6a,0x0b,0x13,0x55,
+    0x79,0x31,0x75,0x4e,0x3a,0xc8,0xb6,0x13,0xbd,0x97,0x6f,0x37,0x0a,0x0b,0x2d,0x88,0x0e,0xde,0x67,0x90,
+    0xc2,0xb3,0xca,0x20,0xca,0x9a,0x51,0xf4,0x64,0x3e,0xdb,0xf4,0x2e,0x45,0xf2,0xc7,0x47,0x17,0xa8,0xf4,
+    0xfa,0x90,0x5a,0x7f,0x80,0xa6,0x82,0xac,0xe4,0x6c,0x81,0x46,0xbb,0x52,0x85,0x20,0x24,0xf8,0x80,0xea
+};
+unsigned int login_live_com_cer_len = 1520;
+
+unsigned char login_skype_com_cer[] = {
+    0x30,0x82,0x05,0xef,0x30,0x82,0x04,0xd7,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0xe9,0x02,0x8b,0x95,
+    0x78,0xe4,0x15,0xdc,0x1a,0x71,0x0a,0x2b,0x88,0x15,0x44,0x47,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xdf,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,
+    0x68,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,
+    0x61,0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,
+    0x67,0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,
+    0x65,0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,
+    0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,
+    0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,
+    0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x73,0x6b,0x79,0x70,0x65,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,0xb0,0x78,0x99,0x86,0x0e,0xa2,0x73,0x23,
+    0xd4,0x5a,0xc3,0x49,0xeb,0xb1,0x36,0x8c,0x7c,0xca,0x84,0xae,0x3c,0xaf,0x38,0x88,0x28,0x99,0x8d,0x2d,
+    0x58,0x13,0xb1,0x97,0x78,0x3e,0x52,0x20,0x67,0xac,0x5b,0x73,0x98,0x6c,0x32,0x55,0xc9,0x70,0xd1,0xd9,
+    0xaa,0x15,0xe8,0x2e,0x26,0x85,0x81,0xbc,0x56,0xe4,0xbc,0x80,0x63,0xdb,0x4e,0xd7,0xf5,0x02,0xbe,0x51,
+    0x63,0x1e,0x3c,0xdb,0xdf,0xd7,0x00,0x5d,0x5a,0xb9,0xe5,0x7b,0x6a,0xea,0x38,0x20,0xb2,0x3b,0xb6,0xee,
+    0x75,0x54,0x84,0xf9,0xa6,0xca,0x38,0x70,0xdd,0xbf,0xb0,0xff,0xa5,0x85,0x5d,0xb4,0x41,0xfe,0xdd,0x3d,
+    0xd9,0x2a,0xe1,0x30,0x43,0x1a,0x98,0x79,0x93,0xa0,0x5f,0xe0,0x67,0x6c,0x95,0xfa,0x3e,0x7a,0xae,0x71,
+    0x7b,0xe3,0x6d,0x88,0x42,0x3f,0x25,0xd4,0xee,0xbe,0x68,0x68,0xac,0xad,0xac,0x60,0xe0,0x20,0xa3,0x39,
+    0x83,0xb9,0x5b,0x28,0xa3,0x93,0x6d,0xa1,0xbd,0x76,0x0a,0xe3,0xeb,0xae,0x87,0x27,0x0e,0x54,0x8f,0xb4,
+    0x48,0x0c,0x9a,0x54,0xf4,0x5d,0x8e,0x37,0x50,0xdc,0x5e,0xa4,0x8b,0x6b,0x4b,0xdc,0xa6,0xf3,0x34,0xbe,
+    0x77,0x59,0x22,0x88,0xff,0x19,0x2b,0x6d,0x76,0x64,0x73,0xda,0x0c,0x87,0x07,0x2b,0x9a,0x37,0x3a,0xd0,
+    0xe2,0x8c,0xf6,0x36,0x32,0x6b,0x9a,0x79,0xcc,0xd2,0x3b,0x93,0x6f,0x1a,0x4d,0x6c,0xe6,0xc1,0x9d,0x40,
+    0xac,0x2d,0x74,0xc3,0xbe,0xea,0x5c,0x73,0x65,0x01,0x29,0xb1,0x2a,0xbf,0x70,0x59,0xc1,0xce,0xc6,0xc3,
+    0xa2,0xc8,0x45,0x5f,0xba,0x67,0x3d,0x0f,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xea,0x30,0x82,0x01,
+    0xe6,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,
+    0x98,0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x0e,0x04,0x16,0x04,0x14,0xd5,0x8e,0x5a,0x51,0x13,0xb4,0x29,0x0d,0x31,0xb6,0x1c,0x8d,0x3e,0x51,0x51,
+    0x31,0x0a,0x33,0xaa,0x81,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,
+    0xa0,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,
+    0x1d,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,
+    0x0c,0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,
+    0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,
+    0x75,0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,
+    0x06,0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,
+    0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,
+    0x2f,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,
+    0x61,0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,
+    0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,
+    0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,
+    0x63,0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,
+    0x3b,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x63,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,
+    0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,
+    0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x2f,
+    0x06,0x03,0x55,0x1d,0x11,0x04,0x28,0x30,0x26,0x82,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x73,0x6b,0x79,
+    0x70,0x65,0x2e,0x63,0x6f,0x6d,0x82,0x13,0x77,0x77,0x77,0x2e,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x73,0x6b,
+    0x79,0x70,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,
+    0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x08,0xf2,0x81,0x75,0x91,0xbb,0xce,0x12,0x04,0x18,0xc2,0x4d,0x5a,
+    0xfb,0x46,0x90,0x0a,0x54,0x44,0xf4,0xf2,0xdd,0x07,0x81,0xf0,0x1f,0xa6,0x7a,0x6f,0x9f,0xcf,0xb8,0x0e,
+    0x2c,0x4f,0x9c,0xc4,0x9a,0xf5,0xa8,0xf6,0xba,0xa4,0xc9,0x7a,0x5d,0xb1,0xe2,0x5a,0xca,0x3c,0xfa,0x60,
+    0xa8,0x68,0x3e,0xcb,0xba,0x2d,0xe2,0xcd,0xd6,0xb6,0xe4,0x92,0x3c,0x69,0xad,0x57,0xea,0xa8,0x2f,0x38,
+    0x10,0x84,0x72,0xe5,0x68,0x71,0xed,0xbe,0xeb,0x6e,0x18,0xef,0x63,0x7a,0xbe,0xe7,0x24,0xff,0xc0,0x63,
+    0xfd,0x58,0x3b,0x4c,0x81,0x92,0xd8,0x29,0xab,0x8e,0x35,0x5d,0xd7,0xd3,0x09,0x6b,0x85,0xd3,0xd5,0x73,
+    0x05,0x44,0xe2,0xe5,0xbb,0x83,0x53,0x10,0xcb,0xf2,0xcf,0xb7,0x6e,0xe1,0x69,0xb7,0xa1,0x92,0x64,0xc5,
+    0xcf,0xcd,0x82,0xbb,0x36,0xa0,0x38,0xad,0xd7,0x24,0xdf,0x53,0xfc,0x3f,0x62,0xb7,0xb7,0xd5,0xc7,0x57,
+    0xe3,0x93,0x31,0x70,0x8e,0x24,0x89,0x86,0xca,0x63,0x2b,0x39,0xba,0x5d,0xd9,0x6a,0x60,0xec,0xa1,0x4e,
+    0x8a,0xfe,0x53,0xf8,0x5e,0x92,0xdf,0x2f,0x5c,0x26,0x17,0x6d,0x03,0x7d,0x02,0x0f,0x0f,0xaa,0x43,0x67,
+    0x6d,0xb0,0x62,0xbf,0x7e,0x53,0xdd,0xcc,0xec,0x78,0x73,0x95,0xe5,0xa5,0xf6,0x00,0xa3,0x04,0xfd,0x3f,
+    0x04,0x2a,0xb3,0x98,0xc5,0xb7,0x03,0x1c,0xdb,0xc9,0x50,0xab,0xb0,0x05,0x1d,0x1e,0xbe,0x56,0xb4,0xcf,
+    0x3e,0x42,0x13,0x94,0x9e,0xf9,0xe7,0x01,0x81,0xa5,0x78,0x6f,0x0c,0x7a,0x76,0xac,0x05,0x86,0xec,0xac,
+    0xc2,0x11,0xac
+};
+unsigned int login_skype_com_cer_len = 1523;
+
+unsigned char login_yahoo_com_1_cer[] = {
+    0x30,0x82,0x05,0xd9,0x30,0x82,0x04,0xc1,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x39,0x2a,0x43,0x4f,0x0e,
+    0x07,0xdf,0x1f,0x8a,0xa3,0x05,0xde,0x34,0xe0,0xc2,0x29,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+    0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,0x79,
+    0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,
+    0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,
+    0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,0x72,
+    0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,
+    0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,
+    0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,
+    0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xdf,0x31,0x0b,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,0x33,
+    0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,0x69,
+    0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,0x68,
+    0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,0x61,
+    0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,0x67,
+    0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,0x65,
+    0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,0x48,
+    0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,0x43,
+    0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,0x13,
+    0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,
+    0x03,0x13,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,0x6f,0x6f,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,0xa1,0xa4,0x05,0x3d,0xed,0x85,0x45,0x93,0x8a,
+    0x18,0x4d,0xc6,0x03,0x00,0x57,0xe2,0x40,0x77,0xf0,0x1c,0xeb,0xd0,0x19,0xdf,0x22,0x5d,0x08,0x7f,0xd1,
+    0x07,0x3c,0x41,0x89,0x46,0x17,0xa3,0x09,0xfa,0xfc,0xf8,0xa9,0x04,0xd1,0x96,0x8f,0xab,0xd7,0x4f,0x3c,
+    0xf9,0xad,0x18,0xa9,0x74,0x81,0xc4,0x57,0x0a,0x3a,0x26,0x16,0xce,0x62,0x3e,0xbc,0x3f,0x6c,0x21,0xee,
+    0x93,0x8d,0xcb,0x0d,0xa0,0x1f,0x9a,0x96,0xd0,0x8f,0xad,0xf5,0x93,0x93,0x82,0xee,0x72,0x0c,0xa1,0x75,
+    0x15,0xa3,0x7b,0x84,0x56,0xb8,0xad,0xff,0x52,0x11,0x71,0x84,0xbc,0x3a,0x30,0x0b,0x7e,0x98,0xa8,0xe1,
+    0xa8,0x3f,0x37,0x52,0xd0,0xf1,0x7c,0x6f,0x90,0xd8,0x45,0x0a,0xac,0x39,0x72,0x6a,0x61,0xd5,0xbb,0xc3,
+    0x8c,0xf9,0xc2,0xcc,0xdf,0xfd,0x3a,0x71,0xb9,0xaf,0xbc,0xdc,0x3a,0xdc,0x0c,0xb6,0xb1,0xd2,0xd1,0x89,
+    0xbb,0x41,0xb6,0xf2,0xde,0x57,0xd5,0x15,0xdf,0xfc,0xfd,0xe2,0x31,0xc5,0xdf,0xca,0xc1,0xd8,0x8f,0x2c,
+    0xbf,0xf0,0x0e,0x5b,0x71,0xe0,0x34,0x71,0xc3,0xc5,0x4d,0x7d,0x7a,0xd4,0xfa,0xed,0x30,0x4b,0x2f,0xea,
+    0xb6,0x2e,0x9e,0x93,0x3c,0xe2,0x3a,0xf8,0x42,0xa2,0x1a,0xee,0xdc,0xdf,0xcd,0x0f,0xa9,0xf6,0x79,0x84,
+    0x1a,0x8e,0x6c,0x02,0xb6,0x86,0xe5,0xbf,0x51,0x6a,0x66,0xf8,0xf3,0x9c,0xd3,0x59,0x0c,0x7b,0xa5,0x99,
+    0x78,0xcd,0x7c,0x99,0xfa,0xc6,0x96,0x47,0xd8,0x32,0xd4,0x74,0x76,0x0e,0x77,0x4b,0x20,0x74,0xa4,0xb7,
+    0x89,0x75,0x92,0x4a,0xb4,0x5b,0x55,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xd5,0x30,0x82,0x01,0xd1,
+    0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,
+    0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,
+    0x04,0x16,0x04,0x14,0x86,0x49,0x45,0xfc,0x33,0x19,0x33,0xd4,0x04,0xed,0x27,0x61,0xee,0xe8,0x01,0xc9,
+    0x0c,0x7f,0x2f,0x7e,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,
+    0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,0x01,
+    0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,
+    0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,0x75,
+    0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,0x06,
+    0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,0x2d,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,
+    0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3b,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,
+    0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x1a,0x06,
+    0x03,0x55,0x1d,0x11,0x04,0x13,0x30,0x11,0x82,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,0x6f,
+    0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x57,0x62,0xe1,0x77,0xeb,0xfc,0x1f,0xbf,0x88,0x53,0xaf,0x58,0xd3,0xd4,0xd6,
+    0x6d,0x67,0x30,0x17,0x40,0xbe,0xe0,0x1f,0x64,0xde,0x87,0x15,0xcc,0xe0,0xa4,0x56,0xa9,0xd1,0x9f,0xf9,
+    0x01,0xfe,0x02,0xb1,0xb1,0xea,0xe2,0x5f,0xee,0x71,0x16,0x31,0xf9,0x08,0xd5,0xc2,0xd7,0x9a,0x9b,0xb2,
+    0x5a,0x38,0xd7,0xa9,0x7f,0xe9,0x87,0x6b,0x31,0xf9,0x0b,0xac,0xd9,0xfd,0x50,0x71,0xe0,0xdb,0x82,0x92,
+    0x0f,0x81,0x9c,0x8d,0x77,0xe9,0xeb,0x2e,0xea,0xd4,0x23,0x41,0x87,0xec,0x2d,0xb2,0x78,0xb3,0x8e,0xb1,
+    0x67,0xd2,0xee,0x71,0x03,0x08,0x12,0x99,0xb3,0x02,0x29,0x6f,0xde,0x8b,0xde,0xc1,0xa9,0x03,0x0a,0x5a,
+    0x33,0x1c,0x3d,0x11,0x03,0xc6,0x48,0x0c,0x98,0x9c,0x15,0x2e,0xd9,0xa6,0x85,0x52,0xe7,0x05,0x8a,0xae,
+    0x30,0x23,0xeb,0xed,0x28,0x6c,0x60,0xe9,0x2d,0x7f,0x8f,0x47,0x8b,0x2f,0xd0,0xdc,0xe6,0xbb,0x0f,0x7e,
+    0x5f,0xf2,0x48,0x81,0x8e,0x50,0x04,0x63,0xb1,0x51,0x80,0x75,0x9a,0xa9,0xb6,0x10,0x1c,0x10,0x5f,0x6f,
+    0x18,0x6f,0xe0,0x0e,0x96,0x45,0xce,0xee,0xf1,0xb5,0x20,0xdb,0xef,0xda,0x6e,0xc8,0x95,0xe3,0xf6,0x45,
+    0xfd,0xca,0xfc,0xa5,0x5f,0x49,0x6d,0x06,0x1e,0xd2,0xde,0x61,0x3d,0x15,0x7d,0x37,0xe5,0x1c,0x35,0x8e,
+    0x06,0xc2,0x6b,0xf7,0xb4,0xa8,0x28,0x2c,0x31,0xcb,0xaa,0xb4,0xa7,0x97,0x4f,0x9d,0x8a,0xf6,0xaf,0x7e,
+    0x37,0xb9,0x7b,0x3d,0xdf,0x92,0x66,0x8b,0x8f,0x4e,0x9d,0xc6,0x36,0xe7,0x5c,0xa6,0xab,0x12,0x0f,0xd6,
+    0xcf
+};
+unsigned int login_yahoo_com_1_cer_len = 1501;
+
+unsigned char login_yahoo_com_2_cer[] = {
+    0x30,0x82,0x05,0xd9,0x30,0x82,0x04,0xc1,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x3e,0x75,0xce,0xd4,0x6b,
+    0x69,0x30,0x21,0x21,0x88,0x30,0xae,0x86,0xa8,0x2a,0x71,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+    0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,0x79,
+    0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,
+    0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,
+    0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,0x72,
+    0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,
+    0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,
+    0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,
+    0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xdf,0x31,0x0b,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,0x33,
+    0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,0x69,
+    0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,0x68,
+    0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,0x61,
+    0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,0x67,
+    0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,0x65,
+    0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,0x48,
+    0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,0x43,
+    0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,0x13,
+    0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,
+    0x03,0x13,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,0x6f,0x6f,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,0xa1,0xa4,0x05,0x3d,0xed,0x85,0x45,0x93,0x8a,
+    0x18,0x4d,0xc6,0x03,0x00,0x57,0xe2,0x40,0x77,0xf0,0x1c,0xeb,0xd0,0x19,0xdf,0x22,0x5d,0x08,0x7f,0xd1,
+    0x07,0x3c,0x41,0x89,0x46,0x17,0xa3,0x09,0xfa,0xfc,0xf8,0xa9,0x04,0xd1,0x96,0x8f,0xab,0xd7,0x4f,0x3c,
+    0xf9,0xad,0x18,0xa9,0x74,0x81,0xc4,0x57,0x0a,0x3a,0x26,0x16,0xce,0x62,0x3e,0xbc,0x3f,0x6c,0x21,0xee,
+    0x93,0x8d,0xcb,0x0d,0xa0,0x1f,0x9a,0x96,0xd0,0x8f,0xad,0xf5,0x93,0x93,0x82,0xee,0x72,0x0c,0xa1,0x75,
+    0x15,0xa3,0x7b,0x84,0x56,0xb8,0xad,0xff,0x52,0x11,0x71,0x84,0xbc,0x3a,0x30,0x0b,0x7e,0x98,0xa8,0xe1,
+    0xa8,0x3f,0x37,0x52,0xd0,0xf1,0x7c,0x6f,0x90,0xd8,0x45,0x0a,0xac,0x39,0x72,0x6a,0x61,0xd5,0xbb,0xc3,
+    0x8c,0xf9,0xc2,0xcc,0xdf,0xfd,0x3a,0x71,0xb9,0xaf,0xbc,0xdc,0x3a,0xdc,0x0c,0xb6,0xb1,0xd2,0xd1,0x89,
+    0xbb,0x41,0xb6,0xf2,0xde,0x57,0xd5,0x15,0xdf,0xfc,0xfd,0xe2,0x31,0xc5,0xdf,0xca,0xc1,0xd8,0x8f,0x2c,
+    0xbf,0xf0,0x0e,0x5b,0x71,0xe0,0x34,0x71,0xc3,0xc5,0x4d,0x7d,0x7a,0xd4,0xfa,0xed,0x30,0x4b,0x2f,0xea,
+    0xb6,0x2e,0x9e,0x93,0x3c,0xe2,0x3a,0xf8,0x42,0xa2,0x1a,0xee,0xdc,0xdf,0xcd,0x0f,0xa9,0xf6,0x79,0x84,
+    0x1a,0x8e,0x6c,0x02,0xb6,0x86,0xe5,0xbf,0x51,0x6a,0x66,0xf8,0xf3,0x9c,0xd3,0x59,0x0c,0x7b,0xa5,0x99,
+    0x78,0xcd,0x7c,0x99,0xfa,0xc6,0x96,0x47,0xd8,0x32,0xd4,0x74,0x76,0x0e,0x77,0x4b,0x20,0x74,0xa4,0xb7,
+    0x89,0x75,0x92,0x4a,0xb4,0x5b,0x55,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xd5,0x30,0x82,0x01,0xd1,
+    0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,
+    0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,
+    0x04,0x16,0x04,0x14,0x86,0x49,0x45,0xfc,0x33,0x19,0x33,0xd4,0x04,0xed,0x27,0x61,0xee,0xe8,0x01,0xc9,
+    0x0c,0x7f,0x2f,0x7e,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,
+    0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,0x01,
+    0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,
+    0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,0x75,
+    0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,0x06,
+    0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,0x2d,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,
+    0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3b,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,
+    0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x1a,0x06,
+    0x03,0x55,0x1d,0x11,0x04,0x13,0x30,0x11,0x82,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,0x6f,
+    0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x53,0x69,0x98,0x8e,0x28,0x4e,0x9c,0x2b,0x5b,0x1d,0xcc,0x6b,0x77,0x28,0x3d,
+    0xbb,0xfa,0xa5,0x4e,0x7e,0x56,0x29,0xa4,0xea,0x10,0xe2,0xf4,0xe6,0x2d,0x06,0xd1,0x84,0xdb,0x23,0xce,
+    0x97,0xf3,0x68,0xb6,0x0f,0x3a,0xde,0x15,0x0b,0x24,0x1d,0x91,0xe3,0x6c,0x2e,0x30,0xb7,0xe9,0x70,0xb0,
+    0xc3,0x46,0x80,0xf0,0xd3,0xb1,0x51,0xbf,0x4f,0xd6,0x78,0xa0,0xfc,0xac,0xc6,0xcf,0x31,0x04,0x63,0xe2,
+    0x34,0x55,0x05,0x4a,0x3d,0xf6,0x30,0xba,0xf3,0x33,0xe5,0xba,0xd2,0x96,0xf3,0xd5,0xb1,0xb6,0x93,0x89,
+    0x1a,0xa4,0x68,0xbe,0x7e,0xed,0x63,0xb4,0x1a,0x48,0xc0,0x53,0xe4,0xa3,0xf0,0x39,0x0c,0x32,0x92,0xc7,
+    0x43,0x0d,0x1a,0x71,0xed,0xd0,0x46,0x93,0xbf,0x93,0x62,0x6c,0x33,0x4b,0xcd,0x36,0x0d,0x69,0x5e,0xbb,
+    0x6c,0x96,0x99,0x21,0x69,0xc4,0x4b,0x67,0x72,0xdb,0x6c,0x6a,0xb8,0xf7,0x68,0xed,0xc5,0x8f,0xad,0x63,
+    0x65,0x95,0x0a,0x4c,0xe0,0xf9,0x0f,0x7e,0x37,0x3d,0xaa,0xd4,0x93,0xba,0x67,0x09,0xc3,0xa5,0xa4,0x0d,
+    0x03,0x5a,0x6d,0xd5,0x0b,0xfe,0xf0,0x40,0x14,0xb4,0xf6,0xb8,0x69,0x7c,0x6d,0xc2,0x32,0x4b,0x9f,0xb5,
+    0x1a,0xe7,0x46,0xae,0x4c,0x5a,0x2b,0xaa,0x7a,0x5e,0x90,0x57,0x95,0xfa,0xdb,0x66,0x02,0x20,0x1e,0x6a,
+    0x69,0x66,0x15,0x9c,0xc2,0xb6,0xf5,0xbc,0x50,0xb5,0xfd,0x45,0xc7,0x1f,0x68,0xb4,0x47,0x59,0xac,0xc4,
+    0x1b,0x28,0x93,0x4e,0x52,0x53,0x12,0x03,0x58,0x4b,0x71,0x83,0x9f,0x66,0xe6,0xac,0x79,0x48,0xfe,0xfe,
+    0x47
+};
+unsigned int login_yahoo_com_2_cer_len = 1501;
+
+unsigned char login_yahoo_com_cer[] = {
+    0x30,0x82,0x05,0xef,0x30,0x82,0x04,0xd7,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0xd7,0x55,0x8f,0xda,
+    0xf5,0xf1,0x10,0x5b,0xb2,0x13,0x28,0x2b,0x70,0x77,0x29,0xa3,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xdf,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,
+    0x68,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,
+    0x61,0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,
+    0x67,0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,
+    0x65,0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,
+    0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,
+    0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,
+    0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,0x6f,0x6f,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,0xa1,0xa4,0x05,0x3d,0xed,0x85,0x45,0x93,
+    0x8a,0x18,0x4d,0xc6,0x03,0x00,0x57,0xe2,0x40,0x77,0xf0,0x1c,0xeb,0xd0,0x19,0xdf,0x22,0x5d,0x08,0x7f,
+    0xd1,0x07,0x3c,0x41,0x89,0x46,0x17,0xa3,0x09,0xfa,0xfc,0xf8,0xa9,0x04,0xd1,0x96,0x8f,0xab,0xd7,0x4f,
+    0x3c,0xf9,0xad,0x18,0xa9,0x74,0x81,0xc4,0x57,0x0a,0x3a,0x26,0x16,0xce,0x62,0x3e,0xbc,0x3f,0x6c,0x21,
+    0xee,0x93,0x8d,0xcb,0x0d,0xa0,0x1f,0x9a,0x96,0xd0,0x8f,0xad,0xf5,0x93,0x93,0x82,0xee,0x72,0x0c,0xa1,
+    0x75,0x15,0xa3,0x7b,0x84,0x56,0xb8,0xad,0xff,0x52,0x11,0x71,0x84,0xbc,0x3a,0x30,0x0b,0x7e,0x98,0xa8,
+    0xe1,0xa8,0x3f,0x37,0x52,0xd0,0xf1,0x7c,0x6f,0x90,0xd8,0x45,0x0a,0xac,0x39,0x72,0x6a,0x61,0xd5,0xbb,
+    0xc3,0x8c,0xf9,0xc2,0xcc,0xdf,0xfd,0x3a,0x71,0xb9,0xaf,0xbc,0xdc,0x3a,0xdc,0x0c,0xb6,0xb1,0xd2,0xd1,
+    0x89,0xbb,0x41,0xb6,0xf2,0xde,0x57,0xd5,0x15,0xdf,0xfc,0xfd,0xe2,0x31,0xc5,0xdf,0xca,0xc1,0xd8,0x8f,
+    0x2c,0xbf,0xf0,0x0e,0x5b,0x71,0xe0,0x34,0x71,0xc3,0xc5,0x4d,0x7d,0x7a,0xd4,0xfa,0xed,0x30,0x4b,0x2f,
+    0xea,0xb6,0x2e,0x9e,0x93,0x3c,0xe2,0x3a,0xf8,0x42,0xa2,0x1a,0xee,0xdc,0xdf,0xcd,0x0f,0xa9,0xf6,0x79,
+    0x84,0x1a,0x8e,0x6c,0x02,0xb6,0x86,0xe5,0xbf,0x51,0x6a,0x66,0xf8,0xf3,0x9c,0xd3,0x59,0x0c,0x7b,0xa5,
+    0x99,0x78,0xcd,0x7c,0x99,0xfa,0xc6,0x96,0x47,0xd8,0x32,0xd4,0x74,0x76,0x0e,0x77,0x4b,0x20,0x74,0xa4,
+    0xb7,0x89,0x75,0x92,0x4a,0xb4,0x5b,0x55,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xea,0x30,0x82,0x01,
+    0xe6,0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,
+    0x98,0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x0e,0x04,0x16,0x04,0x14,0x86,0x49,0x45,0xfc,0x33,0x19,0x33,0xd4,0x04,0xed,0x27,0x61,0xee,0xe8,0x01,
+    0xc9,0x0c,0x7f,0x2f,0x7e,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,
+    0xa0,0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,
+    0x1d,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,
+    0x0c,0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,
+    0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,
+    0x75,0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,
+    0x06,0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,
+    0x70,0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,
+    0x2f,0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,
+    0x61,0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,
+    0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,
+    0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,
+    0x63,0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,
+    0x3b,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x63,0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,
+    0x41,0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,
+    0x30,0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x2f,
+    0x06,0x03,0x55,0x1d,0x11,0x04,0x28,0x30,0x26,0x82,0x0f,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,0x68,
+    0x6f,0x6f,0x2e,0x63,0x6f,0x6d,0x82,0x13,0x77,0x77,0x77,0x2e,0x6c,0x6f,0x67,0x69,0x6e,0x2e,0x79,0x61,
+    0x68,0x6f,0x6f,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,
+    0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x3d,0x57,0xc9,0x48,0x24,0x5c,0xee,0x64,0x81,0xf5,0xae,0xbe,0x55,
+    0x29,0x16,0xff,0x2a,0x2f,0x84,0xed,0xd9,0xf8,0xa3,0x03,0xc8,0x30,0x66,0xbb,0xc8,0xd4,0x81,0x2d,0x21,
+    0xf7,0x08,0xf7,0xac,0x96,0x42,0x9a,0x41,0x75,0x7a,0xba,0x5d,0x10,0x23,0xcb,0x92,0x42,0x61,0xfa,0x8a,
+    0xda,0x6d,0x65,0x34,0x19,0xe5,0xa9,0xd6,0x2d,0x13,0x78,0xd7,0x81,0x44,0x92,0xa9,0x6e,0x80,0x63,0x15,
+    0xcb,0xfe,0x35,0x1f,0x02,0xd1,0x8a,0x14,0xb0,0xa8,0xcc,0x94,0x20,0x3b,0xa8,0x1a,0xf0,0x5d,0x36,0x50,
+    0xdb,0x0d,0xae,0xe9,0x64,0xe4,0xf6,0x8d,0x69,0x7d,0x30,0xc8,0x14,0x17,0x00,0x4a,0xe5,0xa6,0x35,0xfb,
+    0x7d,0x0d,0x22,0x9d,0x79,0x76,0x52,0x2c,0xbc,0x97,0x06,0x88,0x9a,0x15,0xf4,0x73,0xe6,0xf1,0xf5,0x98,
+    0xa5,0xcd,0x07,0x44,0x91,0xb8,0xa7,0x68,0x67,0x45,0xd2,0x72,0x11,0x60,0xe2,0x71,0xb7,0x50,0x55,0xe2,
+    0x8a,0xa9,0x0d,0xd6,0x92,0xee,0x04,0x2a,0x8b,0x30,0xa0,0xa2,0x05,0x46,0x34,0x6d,0x92,0xc6,0x3b,0xaa,
+    0x4d,0xa0,0xd0,0xab,0x01,0x19,0x0a,0x32,0xb7,0xe8,0xe3,0xcf,0xf1,0xd2,0x97,0x49,0x7b,0xac,0xa4,0x97,
+    0xf7,0xf0,0x57,0xae,0x63,0x77,0x9a,0x7f,0x96,0xda,0x4d,0xfd,0xbe,0xdc,0x07,0x36,0xe3,0x25,0xbd,0x89,
+    0x79,0x8e,0x29,0x12,0x13,0x8b,0x88,0x07,0xfb,0x6b,0xdb,0xa4,0xcd,0xb3,0x2d,0x27,0xe9,0xd4,0xca,0x60,
+    0xd7,0x85,0x53,0xfb,0x74,0xc6,0x5c,0x35,0x8c,0x70,0x1f,0xf9,0xb2,0xb7,0x92,0x27,0x20,0xc7,0x94,0xd5,
+    0x67,0x14,0x30
+};
+unsigned int login_yahoo_com_cer_len = 1523;
+
+unsigned char mail_google_com_cer[] = {
+    0x30,0x82,0x05,0xee,0x30,0x82,0x04,0xd6,0xa0,0x03,0x02,0x01,0x02,0x02,0x10,0x04,0x7e,0xcb,0xe9,0xfc,
+    0xa5,0x5f,0x7b,0xd0,0x9e,0xae,0x36,0xe1,0x0c,0xae,0x1e,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,
+    0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,0x79,
+    0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,0x54,
+    0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,0x04,
+    0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,0x72,
+    0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,0x54,
+    0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,
+    0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,0x31,
+    0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xdf,0x31,0x0b,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,0x33,
+    0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,0x69,
+    0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,0x68,
+    0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,0x61,
+    0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,0x67,
+    0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,0x65,
+    0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,0x48,
+    0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,0x43,
+    0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,0x13,
+    0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x18,0x30,0x16,0x06,0x03,0x55,0x04,
+    0x03,0x13,0x0f,0x6d,0x61,0x69,0x6c,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,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,0xb0,0x73,0xf0,0xf2,0x04,0xee,0xc2,0xa2,0x46,
+    0xca,0x34,0x2a,0xaa,0xbb,0x60,0x23,0xd1,0x11,0x76,0x1f,0x1f,0x3a,0xd0,0x65,0x83,0x4e,0x9a,0x45,0xa8,
+    0x43,0x70,0x85,0x76,0xf0,0x1f,0x87,0x00,0x02,0x1f,0x6e,0x3b,0x17,0x17,0xc4,0xb5,0xe9,0x19,0x46,0xa2,
+    0x92,0x25,0x8d,0x62,0x2a,0xb4,0x63,0x30,0x1f,0xb9,0x85,0xf8,0x35,0xe1,0x16,0x5a,0x76,0x49,0xcc,0x50,
+    0x48,0x53,0x39,0x59,0x89,0xd6,0x84,0x02,0xfb,0x9a,0xec,0x1b,0xc7,0x51,0xd5,0x76,0x95,0x90,0xd4,0x3a,
+    0x2a,0xb8,0xa6,0xde,0x02,0x4d,0x06,0xfb,0xcd,0xed,0xa5,0x46,0x41,0x5f,0x55,0x74,0xe5,0xec,0x7e,0x40,
+    0xdc,0x50,0x9c,0xb5,0xe4,0x35,0x5d,0x1e,0x68,0x20,0xf8,0xe9,0xde,0xa3,0x6a,0x28,0xbf,0x41,0xd2,0xa1,
+    0xb3,0xe2,0x25,0x8d,0x0c,0x1b,0xca,0x3d,0x93,0x0c,0x18,0xae,0xdf,0xc5,0xbc,0xfd,0xbc,0x82,0xba,0x68,
+    0x00,0xd7,0x16,0x32,0x71,0x9f,0x65,0xb5,0x11,0xda,0x68,0x59,0xd0,0xa6,0x57,0x64,0x1b,0xc9,0xfe,0x98,
+    0xe5,0xf5,0xa5,0x65,0xea,0xe1,0xdb,0xee,0xf4,0xb3,0x9d,0xb3,0x8e,0xea,0x87,0xae,0x16,0xd2,0x1e,0xa0,
+    0x7c,0x7c,0x69,0x3f,0x29,0x16,0x85,0x01,0x53,0xa7,0x6c,0xf1,0x60,0xab,0xdd,0xa2,0xfc,0x25,0x47,0xd4,
+    0x32,0xd1,0x12,0xdd,0xf7,0x48,0x12,0xe0,0xfc,0x9c,0xa2,0x77,0x98,0xe9,0x89,0x99,0xb8,0xf8,0x38,0xf1,
+    0x8c,0x06,0xc2,0x7a,0x23,0x36,0x6d,0x9b,0x9d,0xcd,0x30,0xc8,0xc7,0x34,0x17,0x1e,0xbb,0x7d,0x42,0xc8,
+    0xab,0xe7,0x15,0x16,0xf6,0x73,0xb5,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xea,0x30,0x82,0x01,0xe6,
+    0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,
+    0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,
+    0x04,0x16,0x04,0x14,0x18,0x2a,0xa2,0xc8,0xd4,0x7a,0x3f,0x7b,0xad,0x04,0x8b,0xbd,0x6f,0x9e,0x10,0x46,
+    0x13,0x78,0x71,0x9d,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,
+    0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,0x01,
+    0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,
+    0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,0x75,
+    0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,0x06,
+    0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,0x2d,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,
+    0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3b,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,
+    0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x2f,0x06,
+    0x03,0x55,0x1d,0x11,0x04,0x28,0x30,0x26,0x82,0x0f,0x6d,0x61,0x69,0x6c,0x2e,0x67,0x6f,0x6f,0x67,0x6c,
+    0x65,0x2e,0x63,0x6f,0x6d,0x82,0x13,0x77,0x77,0x77,0x2e,0x6d,0x61,0x69,0x6c,0x2e,0x67,0x6f,0x6f,0x67,
+    0x6c,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,
+    0x00,0x03,0x82,0x01,0x01,0x00,0x67,0x06,0x08,0x0a,0x27,0xc5,0x93,0x6e,0x02,0xf2,0xde,0x17,0x3f,0xd0,
+    0xd3,0x1b,0x7c,0xff,0xb5,0xcd,0x7a,0xc7,0x77,0xc7,0xbe,0xdf,0x12,0xca,0x19,0xde,0xb0,0x13,0x57,0x0c,
+    0x03,0x91,0xc4,0x79,0x52,0xcf,0x7f,0xb7,0x5e,0x55,0x20,0x84,0x49,0xdd,0xf5,0xd0,0x29,0x2f,0x0e,0x04,
+    0xda,0x59,0x9e,0x0e,0x13,0x9f,0xf4,0xc0,0x32,0x9b,0xff,0xa1,0x11,0x24,0x2a,0x97,0xa3,0xf2,0x3f,0x3d,
+    0x2a,0x6b,0xa8,0xad,0x8c,0x19,0x75,0x95,0x0e,0x1d,0x25,0xfd,0x4f,0xc4,0x7a,0x15,0xc3,0x1d,0xc7,0x13,
+    0x40,0xc8,0x0d,0xbe,0x97,0x60,0x72,0xa6,0xfe,0x25,0xbe,0x8f,0xec,0xd5,0xa6,0x86,0xc3,0x21,0x5c,0x59,
+    0x52,0xd9,0x6a,0x0b,0x5c,0x9f,0x4b,0xde,0xb5,0xf9,0xec,0xe2,0xf4,0xc5,0xcc,0x62,0x53,0x76,0x89,0x65,
+    0xe4,0x29,0xda,0xb7,0xbf,0x96,0xe0,0x60,0x8d,0x0d,0xb7,0x09,0x55,0xd6,0x40,0x55,0x1d,0xc1,0xf2,0x96,
+    0x21,0x75,0xaf,0x89,0x86,0x1f,0x5d,0x81,0x97,0x29,0x28,0x1e,0x29,0xd7,0x96,0xc1,0x20,0x03,0x32,0x7b,
+    0x00,0x3b,0x6a,0x37,0x17,0x5a,0xa3,0xb3,0x1a,0x6f,0x32,0x3b,0x6e,0xf1,0xa3,0x5d,0xab,0xab,0xcc,0x2a,
+    0xcb,0x30,0x0c,0x1f,0x35,0x23,0x8b,0x69,0x44,0x5c,0xea,0xac,0x28,0x60,0xed,0xab,0x6b,0x63,0x9e,0xf6,
+    0x92,0xbc,0xbd,0x9a,0x5a,0x26,0x4c,0xc5,0x98,0xb8,0x0e,0x19,0x3e,0xfc,0x05,0x31,0xe3,0x16,0xd9,0xfd,
+    0x90,0x05,0x03,0x86,0xc6,0x57,0x01,0x1f,0x7f,0x78,0xa0,0xcf,0x33,0x6a,0xaa,0x66,0x6b,0x22,0xd0,0xa7,
+    0x49,0x23
+};
+unsigned int mail_google_com_cer_len = 1522;
+
+unsigned char www_google_com_cer[] = {
+    0x30,0x82,0x05,0xe4,0x30,0x82,0x04,0xcc,0xa0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,0xf5,0xc8,0x6a,0xf3,
+    0x61,0x62,0xf1,0x3a,0x64,0xf5,0x4f,0x6d,0xc9,0x58,0x7c,0x06,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,
+    0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x97,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x0b,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x13,0x02,0x55,0x54,0x31,0x17,0x30,0x15,
+    0x06,0x03,0x55,0x04,0x07,0x13,0x0e,0x53,0x61,0x6c,0x74,0x20,0x4c,0x61,0x6b,0x65,0x20,0x43,0x69,0x74,
+    0x79,0x31,0x1e,0x30,0x1c,0x06,0x03,0x55,0x04,0x0a,0x13,0x15,0x54,0x68,0x65,0x20,0x55,0x53,0x45,0x52,
+    0x54,0x52,0x55,0x53,0x54,0x20,0x4e,0x65,0x74,0x77,0x6f,0x72,0x6b,0x31,0x21,0x30,0x1f,0x06,0x03,0x55,
+    0x04,0x0b,0x13,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x75,0x73,0x65,0x72,0x74,
+    0x72,0x75,0x73,0x74,0x2e,0x63,0x6f,0x6d,0x31,0x1f,0x30,0x1d,0x06,0x03,0x55,0x04,0x03,0x13,0x16,0x55,
+    0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,
+    0x65,0x30,0x1e,0x17,0x0d,0x31,0x31,0x30,0x33,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x17,0x0d,
+    0x31,0x34,0x30,0x33,0x31,0x34,0x32,0x33,0x35,0x39,0x35,0x39,0x5a,0x30,0x81,0xde,0x31,0x0b,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x0e,0x30,0x0c,0x06,0x03,0x55,0x04,0x11,0x13,0x05,
+    0x33,0x38,0x34,0x37,0x37,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x08,0x13,0x07,0x46,0x6c,0x6f,0x72,
+    0x69,0x64,0x61,0x31,0x10,0x30,0x0e,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x45,0x6e,0x67,0x6c,0x69,0x73,
+    0x68,0x31,0x17,0x30,0x15,0x06,0x03,0x55,0x04,0x09,0x13,0x0e,0x53,0x65,0x61,0x20,0x56,0x69,0x6c,0x6c,
+    0x61,0x67,0x65,0x20,0x31,0x30,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0a,0x13,0x0b,0x47,0x6f,0x6f,
+    0x67,0x6c,0x65,0x20,0x4c,0x74,0x64,0x2e,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0b,0x13,0x0a,0x54,
+    0x65,0x63,0x68,0x20,0x44,0x65,0x70,0x74,0x2e,0x31,0x28,0x30,0x26,0x06,0x03,0x55,0x04,0x0b,0x13,0x1f,
+    0x48,0x6f,0x73,0x74,0x65,0x64,0x20,0x62,0x79,0x20,0x47,0x54,0x49,0x20,0x47,0x72,0x6f,0x75,0x70,0x20,
+    0x43,0x6f,0x72,0x70,0x6f,0x72,0x61,0x74,0x69,0x6f,0x6e,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0b,
+    0x13,0x0b,0x50,0x6c,0x61,0x74,0x69,0x6e,0x75,0x6d,0x53,0x53,0x4c,0x31,0x17,0x30,0x15,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x0e,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,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,0xb0,0x73,0xf0,0xf2,0x04,0xee,0xc2,0xa2,0x46,
+    0xca,0x34,0x2a,0xaa,0xbb,0x60,0x23,0xd1,0x11,0x76,0x1f,0x1f,0x3a,0xd0,0x65,0x83,0x4e,0x9a,0x45,0xa8,
+    0x43,0x70,0x85,0x76,0xf0,0x1f,0x87,0x00,0x02,0x1f,0x6e,0x3b,0x17,0x17,0xc4,0xb5,0xe9,0x19,0x46,0xa2,
+    0x92,0x25,0x8d,0x62,0x2a,0xb4,0x63,0x30,0x1f,0xb9,0x85,0xf8,0x35,0xe1,0x16,0x5a,0x76,0x49,0xcc,0x50,
+    0x48,0x53,0x39,0x59,0x89,0xd6,0x84,0x02,0xfb,0x9a,0xec,0x1b,0xc7,0x51,0xd5,0x76,0x95,0x90,0xd4,0x3a,
+    0x2a,0xb8,0xa6,0xde,0x02,0x4d,0x06,0xfb,0xcd,0xed,0xa5,0x46,0x41,0x5f,0x55,0x74,0xe5,0xec,0x7e,0x40,
+    0xdc,0x50,0x9c,0xb5,0xe4,0x35,0x5d,0x1e,0x68,0x20,0xf8,0xe9,0xde,0xa3,0x6a,0x28,0xbf,0x41,0xd2,0xa1,
+    0xb3,0xe2,0x25,0x8d,0x0c,0x1b,0xca,0x3d,0x93,0x0c,0x18,0xae,0xdf,0xc5,0xbc,0xfd,0xbc,0x82,0xba,0x68,
+    0x00,0xd7,0x16,0x32,0x71,0x9f,0x65,0xb5,0x11,0xda,0x68,0x59,0xd0,0xa6,0x57,0x64,0x1b,0xc9,0xfe,0x98,
+    0xe5,0xf5,0xa5,0x65,0xea,0xe1,0xdb,0xee,0xf4,0xb3,0x9d,0xb3,0x8e,0xea,0x87,0xae,0x16,0xd2,0x1e,0xa0,
+    0x7c,0x7c,0x69,0x3f,0x29,0x16,0x85,0x01,0x53,0xa7,0x6c,0xf1,0x60,0xab,0xdd,0xa2,0xfc,0x25,0x47,0xd4,
+    0x32,0xd1,0x12,0xdd,0xf7,0x48,0x12,0xe0,0xfc,0x9c,0xa2,0x77,0x98,0xe9,0x89,0x99,0xb8,0xf8,0x38,0xf1,
+    0x8c,0x06,0xc2,0x7a,0x23,0x36,0x6d,0x9b,0x9d,0xcd,0x30,0xc8,0xc7,0x34,0x17,0x1e,0xbb,0x7d,0x42,0xc8,
+    0xab,0xe7,0x15,0x16,0xf6,0x73,0xb5,0x02,0x03,0x01,0x00,0x01,0xa3,0x82,0x01,0xe0,0x30,0x82,0x01,0xdc,
+    0x30,0x1f,0x06,0x03,0x55,0x1d,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xa1,0x72,0x5f,0x26,0x1b,0x28,0x98,
+    0x43,0x95,0x5d,0x07,0x37,0xd5,0x85,0x96,0x9d,0x4b,0xd2,0xc3,0x45,0x30,0x1d,0x06,0x03,0x55,0x1d,0x0e,
+    0x04,0x16,0x04,0x14,0x18,0x2a,0xa2,0xc8,0xd4,0x7a,0x3f,0x7b,0xad,0x04,0x8b,0xbd,0x6f,0x9e,0x10,0x46,
+    0x13,0x78,0x71,0x9d,0x30,0x0e,0x06,0x03,0x55,0x1d,0x0f,0x01,0x01,0xff,0x04,0x04,0x03,0x02,0x05,0xa0,
+    0x30,0x0c,0x06,0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x02,0x30,0x00,0x30,0x1d,0x06,0x03,0x55,0x1d,
+    0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2b,0x06,0x01,
+    0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,0x1d,0x20,0x04,0x3f,0x30,0x3d,0x30,0x3b,0x06,0x0c,
+    0x2b,0x06,0x01,0x04,0x01,0xb2,0x31,0x01,0x02,0x01,0x03,0x04,0x30,0x2b,0x30,0x29,0x06,0x08,0x2b,0x06,
+    0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1d,0x68,0x74,0x74,0x70,0x73,0x3a,0x2f,0x2f,0x73,0x65,0x63,0x75,
+    0x72,0x65,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x63,0x6f,0x6d,0x2f,0x43,0x50,0x53,0x30,0x7b,0x06,
+    0x03,0x55,0x1d,0x1f,0x04,0x74,0x30,0x72,0x30,0x38,0xa0,0x36,0xa0,0x34,0x86,0x32,0x68,0x74,0x74,0x70,
+    0x3a,0x2f,0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,
+    0x55,0x54,0x4e,0x2d,0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,
+    0x72,0x65,0x2e,0x63,0x72,0x6c,0x30,0x36,0xa0,0x34,0xa0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3a,0x2f,
+    0x2f,0x63,0x72,0x6c,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x2e,0x6e,0x65,0x74,0x2f,0x55,0x54,0x4e,0x2d,
+    0x55,0x53,0x45,0x52,0x46,0x69,0x72,0x73,0x74,0x2d,0x48,0x61,0x72,0x64,0x77,0x61,0x72,0x65,0x2e,0x63,
+    0x72,0x6c,0x30,0x71,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3b,
+    0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2f,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x63,
+    0x72,0x74,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x2f,0x55,0x54,0x4e,0x41,
+    0x64,0x64,0x54,0x72,0x75,0x73,0x74,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2e,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2b,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,
+    0x6f,0x63,0x73,0x70,0x2e,0x63,0x6f,0x6d,0x6f,0x64,0x6f,0x63,0x61,0x2e,0x63,0x6f,0x6d,0x30,0x25,0x06,
+    0x03,0x55,0x1d,0x11,0x04,0x1e,0x30,0x1c,0x82,0x0e,0x77,0x77,0x77,0x2e,0x67,0x6f,0x6f,0x67,0x6c,0x65,
+    0x2e,0x63,0x6f,0x6d,0x82,0x0a,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x0d,0x06,0x09,
+    0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x71,0xc0,0x99,0x3f,
+    0x5e,0xf6,0xbd,0x33,0xff,0x9e,0x16,0xcb,0xa8,0xbf,0xdd,0x70,0xf9,0xd2,0x53,0x3b,0x36,0xae,0xc9,0x17,
+    0xc8,0xae,0x5e,0x4d,0xdd,0x62,0xf7,0xb7,0xd3,0x3e,0x77,0xa3,0xfe,0xc0,0x7b,0x32,0xb5,0xc9,0x94,0x05,
+    0x52,0x50,0xf2,0x5f,0x3d,0x79,0x84,0x49,0x4f,0x5d,0x6c,0xb0,0xd7,0x59,0xbd,0xd4,0x6c,0x88,0xfa,0xfc,
+    0xc5,0x65,0x86,0xeb,0x28,0x52,0xa2,0x42,0xf6,0x7c,0xbc,0x6a,0xc7,0x07,0x2e,0x25,0xd1,0x90,0x62,0x20,
+    0xc6,0x8d,0x51,0xc2,0x2c,0x45,0x39,0x4e,0x03,0xda,0xf7,0x18,0xe8,0xcc,0x0a,0x3a,0xd9,0x45,0xd8,0x6c,
+    0x6e,0x34,0x8b,0x62,0x9c,0x4e,0x15,0xf9,0x43,0xee,0xe5,0x97,0xc0,0x3f,0xad,0x35,0x13,0xc5,0x2b,0x06,
+    0xc7,0x41,0xfd,0xe2,0xf7,0x7e,0x45,0xad,0x9b,0xd1,0xe1,0x66,0xed,0xf8,0x7a,0x4b,0x94,0x39,0x7a,0x2f,
+    0xeb,0xe8,0x3f,0x43,0xd8,0x35,0xd6,0x56,0xfa,0x74,0xe7,0x6d,0xe6,0xed,0xac,0x65,0x84,0xfe,0xd0,0x4d,
+    0x06,0x12,0xde,0xda,0x59,0x00,0x3c,0x09,0x5c,0xcf,0x88,0x4b,0xe8,0x3d,0xb4,0x15,0x21,0x92,0xcc,0x6d,
+    0xa6,0x51,0xe2,0x8e,0x97,0xf1,0xf4,0x82,0x46,0xcb,0xc4,0x53,0x5e,0xda,0x5c,0x9d,0x65,0x92,0x01,0x65,
+    0x89,0x00,0xe5,0xb6,0x99,0xff,0x26,0x40,0xf1,0x2f,0x19,0x31,0x08,0x1a,0xb1,0x67,0x55,0x86,0x0d,0xae,
+    0x35,0x33,0x86,0xbc,0x97,0x48,0x92,0xd7,0x96,0x60,0xf8,0xce,0xfc,0x96,0xeb,0x87,0xc4,0x73,0xcc,0x94,
+    0x9b,0x58,0x5b,0xf3,0x7a,0xa4,0x27,0x13,0xd6,0x4f,0xf4,0x69
+};
+unsigned int www_google_com_cer_len = 1512;
+
+/* subject:/CN=Leaf revoked ok1/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=CA revoked/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char leaf_subCANotOnAllowlist_Cert[] = {
+    0x30,0x82,0x04,0x41,0x30,0x82,0x03,0x29,0xA0,0x03,0x02,0x01,0x02,0x02,0x05,0x00,
+    0xFA,0x6B,0x46,0x67,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x30,0x7C,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x0C,0x0A,
+    0x43,0x41,0x20,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x31,0x22,0x30,0x20,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,
+    0x63,0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
+    0x6E,0x63,0x2E,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x02,0x43,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
+    0x53,0x30,0x20,0x17,0x0D,0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x34,0x30,0x30,
+    0x37,0x5A,0x18,0x0F,0x32,0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x34,0x30,
+    0x30,0x37,0x5A,0x30,0x81,0x82,0x31,0x19,0x30,0x17,0x06,0x03,0x55,0x04,0x03,0x0C,
+    0x10,0x4C,0x65,0x61,0x66,0x20,0x72,0x65,0x76,0x6F,0x6B,0x65,0x64,0x20,0x6F,0x6B,
+    0x31,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,
+    0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x43,
+    0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,
+    0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,0x30,0x10,0x06,0x03,
+    0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,
+    0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC0,0x08,0xBA,0xCA,0x52,0x4C,0x3F,
+    0xD7,0x80,0x14,0x2A,0x58,0xD7,0x3B,0xC2,0xB3,0x30,0xF5,0xA9,0x91,0xCA,0x28,0xE0,
+    0xA3,0xF3,0x4B,0xB3,0x5F,0x10,0xBF,0x15,0x48,0xB0,0xE2,0xD7,0x60,0x57,0xC6,0xEA,
+    0x9D,0x08,0x57,0xF7,0x1F,0x54,0x63,0xEB,0x8F,0x33,0x9D,0xD1,0xB0,0xFE,0x5D,0x28,
+    0x99,0xA4,0xCC,0xBB,0xF3,0x07,0x3D,0xED,0xC3,0x07,0x4A,0x0B,0x92,0x66,0xA1,0x06,
+    0xAC,0xA6,0x89,0xCC,0xCD,0x48,0xC5,0x34,0x54,0xB0,0x68,0x9D,0x50,0xAC,0xC6,0x3A,
+    0x6C,0x5E,0xC7,0x4C,0x11,0xC5,0x43,0x4A,0x59,0xB4,0x74,0xE5,0xC3,0x5D,0xA7,0xB8,
+    0x4C,0x55,0x6D,0x84,0x66,0x63,0xEE,0xAA,0xDC,0xF0,0x4B,0x7B,0x90,0xCE,0xA2,0x8D,
+    0x5A,0x58,0x7B,0xC0,0x12,0xF6,0xA5,0x4F,0x79,0xAD,0x06,0x22,0xDA,0xA0,0xE7,0xD5,
+    0xBE,0x2E,0x46,0xF2,0x4C,0x6B,0x1E,0x0A,0xED,0xF9,0x5E,0xBB,0x73,0x6F,0x8B,0xE6,
+    0xAC,0xDB,0x18,0x2B,0x01,0xFB,0x58,0x7A,0xB2,0x9B,0x52,0x0D,0x41,0xCA,0xD4,0x18,
+    0x0C,0x84,0x42,0xE8,0x70,0x12,0x99,0xC8,0x95,0xF3,0x19,0x0C,0xF0,0x75,0xB3,0x49,
+    0xFC,0x9A,0x7A,0x58,0xE9,0xD1,0xFB,0xCD,0x39,0x3B,0x27,0x58,0xED,0x14,0xF9,0x47,
+    0x1F,0xCE,0x31,0x2D,0x5B,0xA1,0x1E,0x2A,0x78,0x83,0x5F,0x18,0x55,0x66,0xAE,0xAA,
+    0x47,0x50,0xB2,0x42,0x7C,0x6D,0xA6,0x63,0x75,0x32,0x32,0x3E,0xBD,0xA3,0x2F,0x7D,
+    0xE8,0x69,0xD1,0x61,0xD9,0x02,0x86,0x60,0xBF,0xC7,0x5E,0x0B,0xDE,0x87,0x9D,0x18,
+    0xAF,0x42,0x37,0x98,0x2F,0x56,0x19,0xB7,0xF1,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,
+    0xC0,0x30,0x81,0xBD,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
+    0x03,0x02,0x07,0x80,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,
+    0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xF8,
+    0xA6,0xB9,0x3E,0xE8,0xBA,0x5A,0xED,0x7C,0x5C,0x96,0x07,0xFE,0x75,0x0C,0x79,0xE8,
+    0xBF,0xB6,0x12,0x30,0x41,0x06,0x03,0x55,0x1D,0x1F,0x04,0x3A,0x30,0x38,0x30,0x36,
+    0xA0,0x34,0xA0,0x32,0x86,0x30,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x76,0x61,0x6C,
+    0x69,0x64,0x74,0x65,0x73,0x74,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x67,0x65,0x6F,
+    0x66,0x66,0x6B,0x2E,0x6E,0x65,0x74,0x2F,0x76,0x32,0x2D,0x72,0x65,0x76,0x6F,0x6B,
+    0x65,0x64,0x2E,0x63,0x72,0x6C,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x01,0x01,0x04,0x2D,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x30,0x01,0x86,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6B,0x6E,0x6F,0x77,0x6E,
+    0x2D,0x61,0x6E,0x73,0x77,0x65,0x72,0x2D,0x6F,0x63,0x73,0x70,0x2F,0x6F,0x63,0x73,
+    0x70,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x90,0x28,0xA2,0xBF,0x5B,0x3F,0x46,0xFB,0xF1,0x6D,0xDF,
+    0x7B,0xED,0x92,0x2C,0xCA,0xB3,0x38,0xF9,0xE3,0x7F,0xA6,0xD6,0xBA,0x22,0x5A,0x06,
+    0x27,0x21,0xBA,0xC6,0x1C,0xDA,0x64,0x3B,0xB8,0x70,0x89,0x06,0xF8,0x04,0x8F,0x69,
+    0xC2,0x69,0x46,0xF5,0x22,0x8A,0x91,0xE3,0x77,0x21,0x46,0xF7,0x8E,0xDF,0xDE,0x46,
+    0xD4,0x19,0x62,0xDC,0xC7,0x02,0x9E,0xE6,0x31,0x0A,0x13,0xA1,0x54,0x3B,0xE6,0x5C,
+    0x17,0x3F,0xAB,0xDC,0x29,0x0F,0x93,0x74,0xC0,0xD9,0xA3,0xD4,0x76,0xA2,0x1D,0x7E,
+    0x79,0xDF,0x8D,0xFC,0xAE,0x11,0xBD,0x83,0x95,0x12,0x70,0xA3,0xE9,0x39,0xCF,0x06,
+    0x49,0x93,0xD8,0x05,0x53,0x07,0xB9,0xCF,0xD9,0x8E,0x1D,0xA2,0xBB,0x79,0x54,0x94,
+    0xF8,0x9D,0xB4,0x38,0xE6,0x98,0x65,0x3C,0xD0,0x7E,0x16,0x8F,0x11,0x84,0x76,0xA4,
+    0x4A,0x55,0xC3,0x09,0xED,0x68,0xA8,0x62,0xD1,0x97,0x51,0x8C,0x64,0x33,0xFD,0xFA,
+    0x3F,0xD7,0xA5,0x3B,0xD1,0x0B,0xC0,0xCF,0x34,0x77,0x66,0x9F,0x15,0x0D,0xB0,0x0C,
+    0x8C,0x5F,0x57,0x72,0xFC,0xB9,0xB6,0x5A,0x34,0xF3,0xC4,0x78,0x5D,0x9F,0xAC,0xD1,
+    0x99,0x6D,0x98,0xBE,0x80,0x68,0x1F,0xAA,0xF6,0xEE,0x3C,0x1D,0x8B,0xBF,0x59,0x2A,
+    0xC5,0x67,0xAA,0x52,0x9A,0xFD,0x8A,0x14,0x65,0x3C,0x71,0xB8,0xE9,0x0E,0xAF,0x20,
+    0x6A,0x42,0x90,0x22,0xCB,0xE5,0x79,0x99,0xAC,0x91,0xAE,0x63,0x1A,0xDB,0x4E,0xD9,
+    0xCC,0x2A,0x52,0xD4,0x02,0x51,0x42,0xAF,0x27,0x0C,0xA8,0x41,0xFE,0x33,0xBC,0xF5,
+    0x91,0x7E,0x15,0x6A,0x5A,
+};
+
+/* subject:/CN=CA revoked/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=Valid Test CA Root V2/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char subCANotOnAllowlist_Cert[] = {
+    0x30,0x82,0x04,0x2C,0x30,0x82,0x03,0x14,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x3E,
+    0x1D,0x6A,0x98,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,
+    0x05,0x00,0x30,0x81,0x87,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,0x15,
+    0x56,0x61,0x6C,0x69,0x64,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,0x6F,
+    0x6F,0x74,0x20,0x56,0x32,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,
+    0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,
+    0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
+    0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,
+    0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,
+    0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x20,0x17,0x0D,
+    0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x34,0x30,0x30,0x36,0x5A,0x18,0x0F,0x32,
+    0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x34,0x30,0x30,0x36,0x5A,0x30,0x7C,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x03,0x0C,0x0A,0x43,0x41,0x20,0x72,0x65,
+    0x76,0x6F,0x6B,0x65,0x64,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,
+    0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,
+    0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
+    0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,
+    0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,
+    0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xCA,0x23,0x02,
+    0x7B,0x12,0x84,0x9C,0x8D,0x0E,0x43,0x70,0xD8,0xAB,0x93,0x8D,0x20,0xB0,0xF0,0xC0,
+    0xDA,0xE6,0xFB,0xBD,0x96,0x26,0x1A,0x5B,0x74,0x24,0x21,0x97,0x90,0xFF,0x7F,0x75,
+    0xF6,0x47,0x3C,0x7C,0x79,0xD9,0x0A,0x9A,0xA3,0x84,0x1C,0x3A,0x3E,0x63,0xC0,0xA7,
+    0x3C,0x0A,0xB6,0xD1,0x16,0x8D,0x3E,0x5F,0xEF,0x97,0x11,0x91,0x18,0x19,0x42,0xA7,
+    0xC5,0xCA,0x81,0xB2,0xD7,0xE4,0x8F,0x18,0x65,0xAC,0x42,0xB1,0xE1,0x43,0x1D,0x46,
+    0xF0,0x80,0x45,0xFC,0x10,0xE5,0x7B,0xE1,0x7C,0xF7,0x49,0xC1,0x8D,0x8F,0xF2,0x2D,
+    0xE6,0x28,0x51,0x45,0xA8,0xBB,0x83,0x5B,0xAD,0xB8,0x95,0xBF,0x92,0xD2,0xF8,0x9A,
+    0xB3,0x31,0x50,0x58,0x4A,0xBA,0xA5,0xC7,0x3F,0x54,0xCC,0x3A,0xE0,0x58,0xCA,0xA2,
+    0x3D,0x76,0x41,0xE5,0x5A,0x6F,0x7D,0xD6,0xD0,0x74,0xBC,0xE5,0x99,0xCD,0xBD,0x11,
+    0x1C,0x28,0x24,0x96,0xDE,0x63,0x3B,0xDC,0xF8,0xE9,0x22,0x9E,0xCD,0x3D,0x82,0xE7,
+    0x3C,0x5A,0x03,0xFA,0xE6,0x01,0x7B,0xA4,0xB6,0x4D,0x37,0xCE,0x18,0x2C,0xF1,0xFA,
+    0xE1,0xB8,0x86,0x45,0x1E,0xAA,0x61,0xD2,0x89,0xF2,0x43,0x8E,0x8D,0x70,0x64,0x3F,
+    0x1A,0x45,0x7C,0x9C,0xA6,0x1B,0x75,0xB6,0x44,0x81,0x0A,0xBA,0x90,0x00,0x54,0xDB,
+    0x62,0xE1,0xC5,0x4B,0x2E,0x0D,0x49,0x9F,0xDC,0x4E,0xCF,0xE1,0xB1,0xC1,0xDD,0x88,
+    0xA1,0xBA,0x8F,0x96,0x13,0xAB,0x14,0x6C,0xF7,0x2E,0xE4,0x46,0x49,0xE1,0x07,0xFF,
+    0xA1,0xBC,0x85,0x3C,0x56,0x83,0x40,0x32,0xE4,0x4B,0xC6,0x80,0x43,0x02,0x03,0x01,
+    0x00,0x01,0xA3,0x81,0xA7,0x30,0x81,0xA4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,
+    0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,
+    0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xF8,0xA6,0xB9,0x3E,0xE8,0xBA,0x5A,0xED,0x7C,
+    0x5C,0x96,0x07,0xFE,0x75,0x0C,0x79,0xE8,0xBF,0xB6,0x12,0x30,0x1F,0x06,0x03,0x55,
+    0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xBA,0x56,0xD8,0x57,0x66,0xBD,0xFC,0x5B,
+    0xE2,0x10,0xF2,0x39,0xB3,0xAF,0xB2,0x72,0xED,0x55,0x0F,0x1C,0x30,0x3E,0x06,0x03,
+    0x55,0x1D,0x1F,0x04,0x37,0x30,0x35,0x30,0x33,0xA0,0x31,0xA0,0x2F,0x86,0x2D,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x76,0x61,0x6C,0x69,0x64,0x74,0x65,0x73,0x74,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x67,0x65,0x6F,0x66,0x66,0x6B,0x2E,0x6E,0x65,0x74,
+    0x2F,0x76,0x32,0x2D,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
+    0xBF,0xC5,0x46,0x37,0x47,0x5A,0x47,0xE9,0x14,0xB8,0xDC,0x68,0x1C,0xF1,0xAA,0x2E,
+    0x5B,0x2B,0xF0,0xEE,0x7A,0x7D,0xF2,0x6B,0x44,0x77,0x57,0x56,0x58,0xEB,0xFC,0x9A,
+    0x19,0x9B,0xDF,0xE7,0x58,0x98,0xF0,0x5C,0xC7,0x3A,0x22,0x85,0x84,0x46,0xFB,0x71,
+    0x09,0x2F,0xFC,0x22,0x51,0x49,0xF6,0x28,0xEF,0xC5,0xB6,0x5C,0x71,0xFC,0x61,0x12,
+    0xC1,0xA3,0xE1,0xD4,0x77,0x71,0xCC,0xDF,0x12,0x85,0xB4,0x7D,0x43,0xCF,0x7D,0x2A,
+    0x4F,0xF1,0x3A,0x09,0x6E,0xE4,0xC4,0xD5,0xB6,0x8D,0xC7,0x03,0xEB,0x07,0xBC,0x1C,
+    0x0A,0xB4,0x17,0x3E,0xBF,0xC7,0x3E,0xE7,0x9F,0x98,0x51,0xC1,0xA4,0x69,0x09,0x58,
+    0x88,0xD9,0xA4,0xAE,0xB2,0xE7,0x53,0x5F,0xCA,0x8E,0xE9,0x1B,0x84,0x04,0xEA,0x4F,
+    0xFD,0xE2,0x86,0x6F,0xF4,0x1E,0xD3,0x3F,0xF7,0x2D,0x40,0xDF,0x22,0x0E,0x9F,0x76,
+    0x91,0xC8,0x99,0x6F,0x79,0x54,0x23,0xFE,0xBC,0xE7,0xD8,0xDF,0xD9,0x86,0x55,0x1D,
+    0x9B,0xF8,0x67,0xF4,0xD0,0xC3,0x8D,0xF3,0x47,0xAC,0xD2,0x04,0x7B,0xCC,0x4D,0x0A,
+    0xF9,0x1E,0xEF,0x5C,0x1D,0x0F,0x55,0x28,0x73,0x59,0x5F,0x91,0x84,0x2E,0xE3,0xBA,
+    0x59,0xA1,0x66,0x5F,0x62,0x3E,0x5C,0x26,0xBF,0x1C,0x5E,0xBA,0x51,0x9B,0xCB,0x08,
+    0x59,0x3D,0xDD,0xF7,0xFF,0x8D,0x02,0xAB,0xC2,0x15,0x8D,0x61,0x54,0x9A,0xFB,0xBB,
+    0x89,0x92,0x58,0x3A,0x27,0xBE,0xB1,0xE5,0xDF,0x91,0x16,0x94,0x8F,0x16,0x88,0x8D,
+    0xDD,0x64,0xC4,0xF9,0x9B,0x7C,0x19,0x4B,0x9E,0x4F,0x6C,0xFC,0xBF,0x2A,0x7A,0x1D,
+};
+
+/* subject:/CN=Leaf sha256 valid complete ok1/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=CA sha256 valid complete/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char leafOnAllowList_Cert[] = {
+    0x30,0x82,0x04,0x6C,0x30,0x82,0x03,0x54,0xA0,0x03,0x02,0x01,0x02,0x02,0x05,0x00,
+    0xC9,0x44,0x22,0x78,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x30,0x81,0x8A,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,
+    0x18,0x43,0x41,0x20,0x73,0x68,0x61,0x32,0x35,0x36,0x20,0x76,0x61,0x6C,0x69,0x64,
+    0x20,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65,0x31,0x22,0x30,0x20,0x06,0x03,0x55,
+    0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,
+    0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,
+    0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,
+    0x63,0x2E,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,
+    0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x02,0x43,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,
+    0x30,0x20,0x17,0x0D,0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x34,0x30,0x30,0x37,
+    0x5A,0x18,0x0F,0x32,0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x34,0x30,0x30,
+    0x37,0x5A,0x30,0x81,0x90,0x31,0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x0C,0x1E,
+    0x4C,0x65,0x61,0x66,0x20,0x73,0x68,0x61,0x32,0x35,0x36,0x20,0x76,0x61,0x6C,0x69,
+    0x64,0x20,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65,0x20,0x6F,0x6B,0x31,0x31,0x22,
+    0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,
+    0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,
+    0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,
+    0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,
+    0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,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,0xB4,0x45,0x14,0x8C,0x97,0x75,0x09,0xD1,0x43,0x55,
+    0x8F,0x80,0x19,0x11,0x13,0x83,0xB2,0x6C,0x38,0x23,0xCE,0x1C,0x61,0xFE,0x41,0xD7,
+    0xB4,0x78,0x98,0xF9,0xE9,0x72,0xCA,0x45,0xB4,0x0F,0xEB,0x32,0x57,0x45,0x93,0x6F,
+    0x7F,0xC8,0xDC,0xEC,0xE1,0x2D,0x77,0x8A,0x8C,0x8D,0x9E,0x65,0xE0,0xE9,0x09,0x02,
+    0xA1,0x1E,0x5F,0xDA,0x00,0xED,0xDD,0x49,0x34,0xCA,0xD8,0xA2,0x8E,0x3F,0xF3,0x5F,
+    0x3E,0x6C,0x86,0x31,0x83,0x01,0xB4,0xCA,0x95,0xD3,0x5F,0x5A,0xBF,0x09,0x7E,0x3D,
+    0x2A,0xBC,0x03,0x96,0xB7,0xC5,0x66,0x04,0x77,0xB7,0x37,0x43,0xA3,0x08,0x3B,0x0C,
+    0x39,0x7D,0x98,0xAD,0x97,0xF3,0x69,0x65,0x07,0x4A,0x0E,0xF3,0xB9,0xD1,0xD5,0xE2,
+    0xB8,0x91,0x39,0xBB,0xBE,0x3C,0xE7,0x37,0xCD,0xB4,0x22,0x3A,0x22,0xE8,0xFB,0x65,
+    0xC8,0x52,0x88,0x30,0xFC,0x84,0x00,0xE0,0x17,0xB7,0x46,0xF0,0xF1,0x14,0xC3,0x7B,
+    0x10,0x6A,0x26,0x5A,0xD8,0x09,0x86,0x91,0xC7,0x2A,0xEE,0xC7,0xA6,0x12,0x30,0x32,
+    0x38,0x6D,0x78,0x38,0x59,0x72,0xC8,0x5A,0xC9,0x9E,0x3C,0xB5,0xAD,0x82,0xD7,0x83,
+    0xC4,0xC3,0x30,0x15,0x46,0x2F,0x24,0xE0,0x9B,0xDD,0x12,0x97,0x6E,0x54,0x6C,0x8C,
+    0x31,0x30,0xD4,0x24,0x40,0x48,0x46,0x58,0x51,0xF9,0x86,0x2B,0xA4,0x8E,0x16,0x63,
+    0xAE,0x35,0x8E,0xCD,0x64,0x4B,0xA8,0x9D,0x68,0xD5,0x8C,0xBE,0xCF,0x06,0x4C,0x91,
+    0xAC,0x77,0x81,0xCE,0x16,0x6C,0x92,0xCE,0x30,0x03,0x51,0x79,0xDF,0xA4,0x11,0xC0,
+    0x4F,0xAC,0xF7,0x28,0x8F,0x09,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xCE,0x30,0x81,
+    0xCB,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,
+    0x80,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
+    0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x49,0x96,0xB4,0x72,
+    0xB2,0x4C,0x90,0x9B,0xA3,0x22,0x66,0x52,0x66,0x72,0x25,0x3A,0x51,0x93,0xE6,0xC7,
+    0x30,0x4F,0x06,0x03,0x55,0x1D,0x1F,0x04,0x48,0x30,0x46,0x30,0x44,0xA0,0x42,0xA0,
+    0x40,0x86,0x3E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x76,0x61,0x6C,0x69,0x64,0x74,
+    0x65,0x73,0x74,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x67,0x65,0x6F,0x66,0x66,0x6B,
+    0x2E,0x6E,0x65,0x74,0x2F,0x76,0x32,0x2D,0x73,0x68,0x61,0x32,0x35,0x36,0x2D,0x76,
+    0x61,0x6C,0x69,0x64,0x2D,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65,0x2E,0x63,0x72,
+    0x6C,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x2D,0x30,
+    0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x1D,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6B,0x6E,0x6F,0x77,0x6E,0x2D,0x61,0x6E,0x73,0x77,
+    0x65,0x72,0x2D,0x6F,0x63,0x73,0x70,0x2F,0x6F,0x63,0x73,0x70,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
+    0x2F,0x35,0xE8,0xE8,0xF5,0x5C,0x7E,0x48,0x81,0xC9,0xCF,0xF5,0x45,0x08,0xB9,0x47,
+    0x08,0xCD,0x5C,0x4A,0xD5,0xD3,0xB2,0x4C,0x9E,0x9F,0xDD,0x7F,0xC6,0xF1,0x76,0xFC,
+    0xCB,0xC0,0x7C,0x50,0xCC,0x63,0xA8,0xE3,0xB3,0x79,0xA7,0x80,0xE4,0x77,0xC3,0x8A,
+    0x9E,0x25,0x93,0xB2,0x51,0x00,0x5C,0x4D,0xE1,0x9F,0x16,0xFD,0xC7,0x30,0x28,0xA7,
+    0x91,0x5E,0xE5,0x33,0x2A,0xE7,0xB3,0x19,0x12,0x0D,0x6B,0xC6,0x09,0xA9,0xF9,0x2C,
+    0x32,0x4A,0xB6,0x3F,0x8E,0xBB,0x5F,0x14,0x39,0x32,0x87,0xBB,0x23,0xDF,0x81,0x72,
+    0x40,0xEB,0x54,0xF6,0xA8,0x33,0x1E,0xE2,0xB7,0x54,0xD8,0x80,0xB4,0xFA,0x74,0xA2,
+    0xC2,0xEB,0x26,0x11,0x60,0xFD,0x0B,0x37,0x83,0x7F,0x1C,0x14,0xE6,0xCA,0x45,0x8A,
+    0xA7,0xF9,0x47,0x94,0xA8,0xCD,0xCE,0x0D,0x5E,0x14,0x63,0x0A,0xCB,0x6D,0xE6,0x7C,
+    0xED,0xF0,0x57,0xFD,0x0F,0x29,0xB7,0x47,0x3A,0x7A,0xE6,0x62,0x58,0xD9,0x55,0x80,
+    0x5B,0xF6,0xD7,0x98,0x5B,0xE4,0x47,0xAE,0x60,0xC5,0x79,0x1D,0x53,0x94,0x81,0x87,
+    0x20,0xC8,0x27,0x95,0xF2,0x41,0xE7,0xA3,0xA4,0xB8,0xE5,0x7E,0x59,0xDD,0xFF,0xA3,
+    0x79,0x64,0x4A,0x65,0x0A,0x42,0x29,0xD0,0x0A,0x35,0x41,0xF6,0xCA,0x05,0x5A,0x72,
+    0xBE,0xAA,0x4A,0x77,0x9A,0xC5,0x1B,0x59,0x46,0x40,0xF7,0x9D,0x75,0xAE,0xAF,0x92,
+    0x12,0xF6,0x82,0xEA,0xCF,0xF9,0x6E,0x4F,0x94,0xB7,0x17,0x90,0xA9,0xAF,0x45,0xEA,
+    0xAE,0x76,0xB4,0x52,0x2E,0x10,0x4C,0x74,0x7C,0x92,0x70,0xD4,0xEA,0x4D,0x65,0x6B,
+};
+
+/* subject:/CN=Leaf sha256 valid complete revoked1/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=CA sha256 valid complete/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char leafNotOnAllowList_Cert[] = {
+    0x30,0x82,0x04,0x70,0x30,0x82,0x03,0x58,0xA0,0x03,0x02,0x01,0x02,0x02,0x04,0x20,
+    0x11,0x11,0xF5,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,
+    0x05,0x00,0x30,0x81,0x8A,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,
+    0x43,0x41,0x20,0x73,0x68,0x61,0x32,0x35,0x36,0x20,0x76,0x61,0x6C,0x69,0x64,0x20,
+    0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,
+    0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,
+    0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,
+    0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,
+    0x43,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,
+    0x20,0x17,0x0D,0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x34,0x30,0x30,0x37,0x5A,
+    0x18,0x0F,0x32,0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x34,0x30,0x30,0x37,
+    0x5A,0x30,0x81,0x95,0x31,0x2C,0x30,0x2A,0x06,0x03,0x55,0x04,0x03,0x0C,0x23,0x4C,
+    0x65,0x61,0x66,0x20,0x73,0x68,0x61,0x32,0x35,0x36,0x20,0x76,0x61,0x6C,0x69,0x64,
+    0x20,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,0x65,0x20,0x72,0x65,0x76,0x6F,0x6B,0x65,
+    0x64,0x31,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,
+    0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,0x73,0x74,0x20,
+    0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,
+    0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,0x30,0x10,0x06,
+    0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,0x0B,0x30,0x09,
+    0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xB1,0x1D,0xC6,0x90,0xDB,0xE4,
+    0x97,0x45,0x2E,0xBB,0x6C,0x70,0x6D,0x89,0xE6,0x98,0x0D,0xA7,0x3C,0x7D,0x9C,0x36,
+    0xE6,0xEC,0x96,0xA7,0xBE,0xC3,0xE0,0x3F,0x73,0xA7,0xCB,0xDA,0xE9,0xEA,0x56,0xE1,
+    0xE8,0x55,0x9E,0xFF,0x72,0x43,0x37,0x88,0x1C,0x79,0x8B,0xA6,0xCD,0x3B,0xFB,0xDC,
+    0x00,0xA2,0xB1,0xF6,0xF9,0x01,0x6B,0x2F,0xD7,0xA3,0x9A,0x31,0xC6,0xD2,0x94,0x48,
+    0x34,0x01,0x4C,0x20,0x5A,0x4B,0xBE,0xDB,0x4D,0xDD,0xB2,0xB3,0x0F,0xEC,0x5A,0x94,
+    0x08,0x19,0x77,0x6C,0xE0,0x46,0x87,0xD8,0x07,0x63,0x72,0x06,0x7B,0x42,0x82,0xEA,
+    0x18,0xCE,0x43,0x10,0xC6,0xD2,0xB6,0x6A,0x51,0xF0,0x19,0xBD,0xF3,0x1B,0xB0,0x78,
+    0x92,0x97,0x25,0xDF,0x16,0xA4,0x99,0xE0,0x36,0x50,0x37,0x67,0x47,0xCE,0x7D,0x62,
+    0x07,0xFB,0x94,0x37,0xA6,0x29,0xF7,0x1F,0x3F,0x63,0x70,0x26,0x81,0x06,0x57,0x23,
+    0x74,0x2B,0x16,0xA3,0x3A,0x1C,0xE7,0xF6,0x2E,0x51,0x3B,0x38,0x7B,0x3F,0x43,0xE4,
+    0xEC,0xC1,0x35,0x43,0x66,0xC1,0x32,0x7D,0xB2,0x91,0xB7,0x40,0x1E,0x80,0xFD,0x39,
+    0x25,0xF8,0xDB,0x4A,0x57,0xBE,0x41,0x97,0xF5,0xF8,0xA3,0xFA,0xC5,0xC1,0xF0,0xDF,
+    0x6F,0x9F,0x07,0x41,0xA0,0xFB,0x21,0x7C,0x35,0x64,0xA3,0xB5,0xD6,0xE1,0xFF,0x0E,
+    0x34,0x22,0xD8,0xD8,0x84,0x75,0x5A,0xDD,0xC3,0xCB,0x33,0x6F,0x98,0x82,0xF6,0x69,
+    0x1A,0x4C,0x3E,0x50,0x3D,0x35,0xE6,0xA9,0xE2,0x64,0x7C,0x0F,0x3E,0xD8,0xC0,0x93,
+    0x52,0xDB,0x87,0xA1,0x0B,0x4C,0x36,0x57,0x91,0x67,0x02,0x03,0x01,0x00,0x01,0xA3,
+    0x81,0xCE,0x30,0x81,0xCB,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,
+    0x04,0x03,0x02,0x07,0x80,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,
+    0x02,0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
+    0x49,0x96,0xB4,0x72,0xB2,0x4C,0x90,0x9B,0xA3,0x22,0x66,0x52,0x66,0x72,0x25,0x3A,
+    0x51,0x93,0xE6,0xC7,0x30,0x4F,0x06,0x03,0x55,0x1D,0x1F,0x04,0x48,0x30,0x46,0x30,
+    0x44,0xA0,0x42,0xA0,0x40,0x86,0x3E,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x76,0x61,
+    0x6C,0x69,0x64,0x74,0x65,0x73,0x74,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x67,0x65,
+    0x6F,0x66,0x66,0x6B,0x2E,0x6E,0x65,0x74,0x2F,0x76,0x32,0x2D,0x73,0x68,0x61,0x32,
+    0x35,0x36,0x2D,0x76,0x61,0x6C,0x69,0x64,0x2D,0x63,0x6F,0x6D,0x70,0x6C,0x65,0x74,
+    0x65,0x2E,0x63,0x72,0x6C,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x01,
+    0x01,0x04,0x2D,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,
+    0x01,0x86,0x1D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6B,0x6E,0x6F,0x77,0x6E,0x2D,
+    0x61,0x6E,0x73,0x77,0x65,0x72,0x2D,0x6F,0x63,0x73,0x70,0x2F,0x6F,0x63,0x73,0x70,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
+    0x82,0x01,0x01,0x00,0x65,0xFD,0x30,0xA6,0x32,0x7D,0x2A,0xB7,0xB7,0xC3,0xD8,0x66,
+    0x49,0x91,0x9C,0x39,0x17,0xB2,0x3F,0x9F,0x62,0xB4,0x8A,0x07,0x9A,0xA8,0xE5,0x1C,
+    0x6A,0x62,0xEA,0x77,0x4B,0x7A,0xC0,0xE6,0x24,0x2C,0xAE,0xAE,0x0F,0xE6,0xE6,0x82,
+    0x7F,0x02,0xA2,0x3B,0xC8,0x4C,0xB3,0x7C,0x0E,0x7B,0x3C,0x2E,0x52,0x95,0xDB,0x29,
+    0xBF,0xFE,0x11,0x5D,0xE2,0xEE,0xE2,0xFC,0xE2,0x48,0x10,0xDE,0xF2,0xD6,0x24,0x66,
+    0xD8,0x81,0x76,0xDF,0x0F,0xA5,0x26,0x82,0x8D,0xEB,0xA0,0xDE,0xD8,0x59,0x53,0x69,
+    0x0D,0x47,0x9A,0xB2,0xFE,0xB4,0x1D,0xFB,0x32,0x56,0x49,0x09,0xA4,0x52,0xB4,0xB9,
+    0x19,0x54,0x4E,0xEC,0x29,0x8A,0x59,0x5D,0x63,0x1B,0xB9,0x09,0x4D,0xF1,0xB0,0x85,
+    0xF2,0x91,0xE8,0x7A,0x76,0x38,0x28,0x5C,0x08,0x36,0x9E,0xAC,0x74,0x31,0xD5,0xFF,
+    0xDA,0x15,0xCE,0x80,0x15,0x6F,0x23,0xDC,0xB6,0x93,0x01,0xC7,0x12,0x8A,0x06,0xD4,
+    0x42,0xE9,0x81,0x29,0xB9,0x2A,0xC7,0xD0,0xA9,0xFA,0xD6,0x6C,0xA4,0x26,0x4D,0x54,
+    0x16,0xA7,0x65,0x52,0xB9,0xEF,0x4A,0x68,0xDF,0x14,0xFF,0x73,0x4B,0xED,0x18,0x9B,
+    0xDB,0x27,0x66,0x38,0xBF,0x03,0x13,0xCC,0xBC,0xE5,0xBA,0x1C,0x7F,0x62,0x36,0x04,
+    0x39,0xA2,0x6E,0x32,0x65,0xA1,0x03,0x7A,0x63,0xC8,0x3C,0x01,0x85,0xE3,0x60,0xAF,
+    0x3D,0x1B,0xA9,0x86,0xB6,0xBA,0xD0,0x23,0xDC,0x82,0x05,0x0B,0x6A,0x4F,0x7B,0x82,
+    0xC1,0xF6,0xC7,0x23,0xB3,0x6C,0xBC,0x10,0x88,0x89,0xFF,0xBE,0x45,0xF6,0x5A,0xA1,
+    0x00,0x0F,0xD9,0x83,
+};
+
+/* subject:/CN=CA sha256 valid complete/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=Valid Test CA Root V2/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char ca1_Cert[] = {
+    0x30,0x82,0x04,0x3C,0x30,0x82,0x03,0x24,0xA0,0x03,0x02,0x01,0x02,0x02,0x05,0x00,
+    0xE4,0xF5,0x4B,0x6E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x30,0x81,0x87,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,
+    0x15,0x56,0x61,0x6C,0x69,0x64,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,
+    0x6F,0x6F,0x74,0x20,0x56,0x32,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,
+    0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,
+    0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,
+    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x20,0x17,
+    0x0D,0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x34,0x30,0x30,0x35,0x5A,0x18,0x0F,
+    0x32,0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x34,0x30,0x30,0x35,0x5A,0x30,
+    0x81,0x8A,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,0x43,0x41,0x20,
+    0x73,0x68,0x61,0x32,0x35,0x36,0x20,0x76,0x61,0x6C,0x69,0x64,0x20,0x63,0x6F,0x6D,
+    0x70,0x6C,0x65,0x74,0x65,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,0x19,
+    0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,0x65,
+    0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,0x55,
+    0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x12,
+    0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,
+    0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xDE,0x13,0x51,
+    0x00,0x15,0x31,0xFE,0x34,0x3D,0x25,0x3F,0x63,0x7B,0x77,0x40,0x41,0x67,0xFE,0xD4,
+    0xEF,0xE2,0xE1,0x83,0x3C,0x27,0x29,0x76,0x41,0x55,0xBE,0x00,0x71,0xEA,0x78,0x5B,
+    0x60,0xA5,0x6B,0xD7,0xE8,0xD3,0x20,0x49,0xDA,0xED,0xD8,0x55,0xA5,0x5A,0xDF,0x01,
+    0x0C,0x7E,0x41,0x0B,0xAA,0x61,0xCF,0xBD,0xBF,0x87,0x2F,0xCC,0x02,0x79,0x92,0x51,
+    0x00,0x29,0x1E,0x6F,0x09,0x9F,0x1D,0xA9,0x85,0xA8,0xB6,0x0B,0xF6,0x8F,0x07,0x46,
+    0x08,0xD2,0x0F,0x92,0x70,0x25,0x82,0xA4,0x73,0xA8,0xF4,0xE6,0x8F,0x5D,0x6D,0x49,
+    0x0F,0xE4,0x05,0xD2,0xEF,0xA5,0xE8,0x49,0xAD,0xA5,0x08,0xC0,0x89,0x4F,0xEF,0xA7,
+    0x36,0xA1,0xF2,0x0D,0xBD,0x41,0xAD,0x63,0x6B,0xC4,0x65,0xD1,0x79,0x94,0xAF,0x3A,
+    0x35,0xA3,0x7A,0x5B,0xE7,0xA0,0x78,0x16,0x4E,0xB7,0x0A,0x1A,0x3A,0xF5,0xC6,0xA5,
+    0x6B,0x9C,0x14,0x0F,0x15,0xEB,0xBE,0xA1,0x29,0xA6,0xA7,0xB2,0x92,0x3A,0xD6,0xFA,
+    0x91,0xEF,0xCB,0xC4,0x7C,0xDB,0x49,0x11,0x73,0x0D,0x94,0xCA,0x0C,0xEA,0x53,0xAE,
+    0x9C,0xCA,0x07,0xC7,0x48,0xC2,0xC0,0xE3,0x0C,0x58,0x1C,0xA5,0xE0,0x27,0x45,0xE3,
+    0xCD,0xEC,0x17,0x50,0xE7,0xC5,0xD1,0x58,0x5A,0x19,0x3E,0xA5,0xDA,0xE3,0x19,0xB0,
+    0x63,0x53,0x0B,0x53,0xDB,0xF0,0x40,0xF2,0xAF,0xBA,0x20,0xA5,0x96,0xB2,0x5E,0xD0,
+    0x0F,0x28,0xED,0x5F,0xCC,0xEB,0x69,0x16,0xF0,0xCD,0x22,0xDF,0x7B,0xBF,0x8F,0x32,
+    0x11,0x9F,0xF8,0x29,0x48,0x5D,0x6A,0x0A,0xDB,0x46,0x70,0x80,0x19,0x02,0x03,0x01,
+    0x00,0x01,0xA3,0x81,0xA7,0x30,0x81,0xA4,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,
+    0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,
+    0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x49,0x96,0xB4,0x72,0xB2,0x4C,0x90,0x9B,0xA3,
+    0x22,0x66,0x52,0x66,0x72,0x25,0x3A,0x51,0x93,0xE6,0xC7,0x30,0x1F,0x06,0x03,0x55,
+    0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xBA,0x56,0xD8,0x57,0x66,0xBD,0xFC,0x5B,
+    0xE2,0x10,0xF2,0x39,0xB3,0xAF,0xB2,0x72,0xED,0x55,0x0F,0x1C,0x30,0x3E,0x06,0x03,
+    0x55,0x1D,0x1F,0x04,0x37,0x30,0x35,0x30,0x33,0xA0,0x31,0xA0,0x2F,0x86,0x2D,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x76,0x61,0x6C,0x69,0x64,0x74,0x65,0x73,0x74,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x67,0x65,0x6F,0x66,0x66,0x6B,0x2E,0x6E,0x65,0x74,
+    0x2F,0x76,0x32,0x2D,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
+    0x75,0xDE,0xCF,0x34,0xBD,0xF4,0xAF,0x9C,0x50,0xDA,0x36,0x78,0xE1,0xE1,0xCD,0x54,
+    0x35,0x61,0xB0,0x4C,0x46,0x17,0x55,0x7D,0x9F,0x1E,0x69,0xCD,0x66,0x62,0x2B,0xF5,
+    0x30,0xD9,0xAE,0x36,0xD2,0xF6,0x21,0x03,0x59,0x3B,0xAB,0xFF,0x79,0xA7,0xF8,0x16,
+    0xF3,0x79,0x49,0x19,0xF5,0x05,0x4F,0x70,0xB5,0x26,0xA8,0x41,0xB0,0x66,0x33,0xA1,
+    0x3C,0xF9,0xF9,0x61,0x77,0x5F,0x52,0xA7,0x5A,0xC1,0xA1,0x1D,0xA9,0x2B,0x7A,0x44,
+    0x8C,0x01,0x4C,0x8A,0x5B,0x2C,0xF0,0x10,0xB8,0x17,0xEF,0x45,0xAA,0x1E,0xC9,0x46,
+    0xF8,0x19,0x0A,0xE0,0x25,0x9D,0xC1,0xBF,0x6D,0x34,0x1F,0xFA,0xC9,0xFF,0x62,0x5C,
+    0x44,0x96,0x01,0x2B,0x4B,0xBF,0xD0,0xD5,0x56,0x07,0xA9,0x43,0x0D,0xF6,0x85,0x7C,
+    0x49,0x0B,0x43,0xA9,0xD7,0xAA,0xC2,0xBF,0x0A,0x5B,0xC0,0xD1,0xA1,0x82,0x9F,0x5F,
+    0xB8,0xF4,0x0B,0xC5,0x9A,0x40,0x0B,0xC2,0x2D,0xC9,0xF0,0x4A,0x76,0xA9,0x9B,0x58,
+    0x25,0xCA,0x13,0x48,0x63,0xE7,0xD5,0x58,0x58,0x91,0x4D,0xEE,0x21,0x14,0x83,0x5E,
+    0x2E,0x9B,0xBF,0x74,0x9E,0x03,0x8C,0x86,0xAF,0xB0,0xCC,0xD8,0xC1,0xC2,0x3D,0xFE,
+    0xF8,0x2F,0x6E,0x9E,0x42,0xEF,0x8E,0x20,0xE7,0x94,0x56,0xB6,0xDA,0xC1,0x84,0xC6,
+    0x77,0xF1,0x27,0x8B,0xA7,0x68,0x0F,0x8A,0x43,0xD5,0xC6,0x99,0x37,0x43,0x4D,0xAF,
+    0xAD,0x9C,0xDC,0x3D,0x10,0x7E,0xDF,0xBF,0xDD,0x76,0xE5,0xE6,0xD7,0x90,0x94,0x9D,
+    0xCE,0x46,0x27,0xD7,0x10,0xB7,0xC6,0x07,0xA7,0x6D,0xC9,0x9A,0x8E,0xE3,0x71,0xA6,
+};
+
+/* subject:/CN=Valid Test CA Root V2/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+/* issuer :/CN=Valid Test CA Root V2/OU=Valid Project Test CAs V2/O=Apple Inc./L=Cupertino/ST=CA/C=US */
+unsigned char root_Cert[] = {
+    0x30,0x82,0x03,0xD7,0x30,0x82,0x02,0xBF,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0x8C,0x0C,0x8D,0x50,0x34,0x29,0x1D,0xB6,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x87,0x31,0x1E,0x30,0x1C,0x06,0x03,
+    0x55,0x04,0x03,0x0C,0x15,0x56,0x61,0x6C,0x69,0x64,0x20,0x54,0x65,0x73,0x74,0x20,
+    0x43,0x41,0x20,0x52,0x6F,0x6F,0x74,0x20,0x56,0x32,0x31,0x22,0x30,0x20,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,
+    0x63,0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
+    0x6E,0x63,0x2E,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x02,0x43,0x41,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
+    0x53,0x30,0x20,0x17,0x0D,0x31,0x37,0x30,0x35,0x30,0x31,0x32,0x32,0x33,0x35,0x33,
+    0x32,0x5A,0x18,0x0F,0x32,0x31,0x31,0x37,0x30,0x34,0x30,0x37,0x32,0x32,0x33,0x35,
+    0x33,0x32,0x5A,0x30,0x81,0x87,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,
+    0x15,0x56,0x61,0x6C,0x69,0x64,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x20,0x52,
+    0x6F,0x6F,0x74,0x20,0x56,0x32,0x31,0x22,0x30,0x20,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x19,0x56,0x61,0x6C,0x69,0x64,0x20,0x50,0x72,0x6F,0x6A,0x65,0x63,0x74,0x20,0x54,
+    0x65,0x73,0x74,0x20,0x43,0x41,0x73,0x20,0x56,0x32,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,
+    0x69,0x6E,0x6F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x08,0x0C,0x02,0x43,0x41,
+    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xC3,0x6D,
+    0x14,0x60,0xB3,0xD3,0x0A,0x8A,0xF6,0xBE,0xA7,0x42,0xBF,0xC7,0x11,0xC2,0x6C,0x8A,
+    0x94,0xF1,0x0E,0x3D,0x67,0x1C,0x9D,0x4A,0xD6,0x2E,0xC1,0xEA,0x77,0xA2,0x6E,0xAA,
+    0x99,0x67,0xBE,0x9F,0xA7,0xBE,0xBD,0x24,0xD1,0x43,0xC8,0x3A,0x88,0x77,0x70,0x24,
+    0x9D,0xC6,0x5E,0x53,0x59,0x31,0xA9,0xB1,0x1B,0x1F,0xBA,0x67,0xA7,0x57,0x55,0x0D,
+    0xB3,0xD4,0x01,0xAE,0xE4,0xA8,0xC4,0xE7,0x29,0x1C,0xA1,0x39,0x6F,0x1A,0x1C,0x2D,
+    0xC1,0x56,0x0A,0x16,0x3F,0x26,0x2F,0x20,0x49,0x33,0x35,0xD2,0xF9,0x6D,0x3B,0x5E,
+    0x98,0x59,0x4A,0x70,0xCE,0xFF,0xA4,0x23,0xE6,0x23,0x43,0x23,0xE5,0x8B,0x2F,0xEE,
+    0x6A,0x28,0x28,0x4B,0x31,0xA0,0xC8,0x08,0x6C,0x0F,0x38,0x11,0xBC,0x27,0x7F,0x61,
+    0xCF,0xB0,0x36,0xB9,0x8C,0xBA,0xBA,0x3E,0x00,0x1E,0xD0,0xFF,0x71,0x92,0xDB,0xA1,
+    0x8C,0x1F,0x03,0x29,0x13,0x7C,0xAF,0x87,0xA2,0x41,0x2A,0x5E,0x07,0xFE,0xEF,0x37,
+    0xC8,0xB4,0x72,0xC7,0x89,0x03,0x81,0x69,0x01,0xC8,0x7B,0xBE,0x82,0x0A,0x45,0xE2,
+    0x88,0xD6,0x63,0x80,0x54,0x29,0x00,0xF6,0xAF,0x58,0xB7,0x65,0x4A,0xD0,0x1A,0x7F,
+    0x75,0x01,0x06,0xF6,0xB2,0x94,0x2D,0x5E,0x1D,0x02,0xB8,0xEE,0xFA,0x55,0xC8,0xDD,
+    0x84,0x29,0xE7,0x59,0xAA,0xD6,0xEB,0x6C,0x11,0x26,0x16,0xEF,0xF4,0xDA,0x73,0xD8,
+    0x39,0xD8,0xEC,0xF1,0x8F,0x1C,0x13,0xD6,0x2C,0x7A,0xD9,0x8A,0x12,0xF1,0xE1,0x3D,
+    0xAB,0x81,0x6F,0x7D,0x95,0x74,0x20,0x6A,0xC0,0x1D,0xF4,0x5B,0x7C,0xDD,0x02,0x03,
+    0x01,0x00,0x01,0xA3,0x42,0x30,0x40,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,
+    0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,
+    0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,
+    0x16,0x04,0x14,0xBA,0x56,0xD8,0x57,0x66,0xBD,0xFC,0x5B,0xE2,0x10,0xF2,0x39,0xB3,
+    0xAF,0xB2,0x72,0xED,0x55,0x0F,0x1C,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB6,0x57,0xE2,0x6C,0x23,
+    0x90,0x87,0xD5,0x40,0xF4,0xE2,0x39,0x35,0x2F,0x1B,0xFB,0x31,0x0E,0x14,0xF9,0xFF,
+    0x97,0x5C,0xED,0x7A,0x6D,0x5F,0x80,0x1F,0x98,0x93,0x0A,0x13,0xA5,0x8F,0x9B,0x2B,
+    0x20,0x0E,0xAF,0x62,0x1B,0xB0,0xF8,0xBB,0x00,0xBD,0xDC,0x56,0x3B,0xD9,0x4B,0x6C,
+    0x7B,0x80,0xEA,0x18,0xC7,0x32,0x8A,0x38,0xAE,0x9F,0xEE,0x1F,0x17,0x0D,0x1C,0x82,
+    0xEB,0x92,0xE5,0x87,0x1B,0x9E,0x3E,0xE2,0x32,0x7B,0xB5,0x9F,0xBC,0x52,0x1F,0x07,
+    0xB1,0x77,0x16,0xA9,0xC2,0xB6,0x9F,0xC1,0xE4,0xCA,0x27,0x45,0x18,0xF7,0x07,0x7F,
+    0x74,0x95,0x5E,0x8C,0x67,0x3D,0xEA,0x20,0x39,0x4A,0x4A,0x79,0xB6,0xEC,0xCE,0x98,
+    0x3F,0x60,0x51,0x26,0xF3,0x37,0x0E,0x0C,0xFC,0x3E,0x14,0xBF,0xEA,0x75,0xA7,0x68,
+    0x0F,0xA4,0x1C,0x57,0x04,0xF8,0xC1,0x11,0x6D,0xD0,0x1F,0x93,0x30,0x5C,0xB4,0x99,
+    0x91,0x67,0x3C,0x72,0x95,0x63,0x7F,0x2D,0x66,0xE0,0x32,0x11,0xC4,0x76,0xF5,0xC0,
+    0x36,0x23,0x20,0xBC,0xE4,0x4F,0xDA,0xE7,0xDC,0x10,0x62,0x49,0xC0,0xC7,0x91,0xFE,
+    0x4C,0xCC,0x09,0x40,0xB9,0x33,0x0D,0xD5,0x90,0x4E,0xD9,0x83,0x54,0x2C,0x42,0x81,
+    0x17,0xFA,0xDF,0x57,0x3A,0x15,0x76,0x05,0x1F,0x11,0x40,0xCE,0x85,0xEC,0xA2,0xA3,
+    0xF6,0xAC,0xB6,0x67,0xA6,0x78,0xD0,0xA9,0xA7,0xF2,0x60,0xF4,0xFC,0xD1,0x78,0x9E,
+    0x00,0x00,0xD9,0xE7,0xE7,0xE5,0xED,0xE4,0x10,0x8D,0x8E,0x5B,0xCC,0x8E,0xB6,0xD6,
+    0x71,0xCF,0x54,0x16,0xD4,0x99,0xCD,0x6D,0x40,0x2A,0x8A,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Test CA */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Test CA */
+/* SHA256: 51a0f31fc01dec8732b6fd136a434d6c87cd62e038b4fbd640b0fd624d1fcf6d */
+unsigned char _datetest_root[994]={
+    0x30,0x82,0x03,0xDE,0x30,0x82,0x02,0xC6,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xAB,0x16,0xC1,0x56,0x85,0x86,0xE5,0xC8,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x30,0x81,0x8A,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,0x15,0x44,
+    0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x44,0x61,0x74,0x65,0x20,0x54,0x65,0x73,
+    0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x36,0x31,0x30,0x31,0x32,0x31,0x38,
+    0x31,0x35,0x34,0x39,0x5A,0x17,0x0D,0x32,0x36,0x31,0x30,0x31,0x30,0x31,0x38,0x31,
+    0x35,0x34,0x39,0x5A,0x30,0x81,0x8A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,
+    0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,
+    0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,
+    0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,
+    0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,
+    0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,
+    0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,
+    0x67,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,0x15,0x44,0x65,0x6E,0x79,
+    0x6C,0x69,0x73,0x74,0x20,0x44,0x61,0x74,0x65,0x20,0x54,0x65,0x73,0x74,0x20,0x43,
+    0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,
+    0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,
+    0x01,0x00,0xF0,0x5A,0x62,0x0B,0xEA,0xD6,0xD6,0x78,0x94,0xEE,0x71,0xB5,0xF8,0x42,
+    0xBB,0xF2,0x2F,0xC6,0xFB,0x53,0x7E,0xE4,0xF5,0xC9,0x8F,0x94,0xBC,0x02,0xB9,0x12,
+    0x8E,0x5D,0xB4,0x12,0xE3,0x73,0xBD,0xD8,0x1A,0x3F,0x2D,0xBC,0x39,0x31,0x42,0x02,
+    0x74,0xE7,0x93,0xB4,0x2B,0x6F,0xA9,0x42,0x8A,0xD4,0x0E,0xC9,0x96,0x90,0xE5,0xF6,
+    0xAD,0xD7,0x7E,0x58,0xBA,0x6B,0xBD,0xBF,0xFC,0x8F,0x1E,0xD4,0xBE,0xD1,0x11,0x4B,
+    0x7D,0x8A,0xD0,0x36,0xAD,0x2A,0x9A,0x37,0x5B,0xDF,0xCB,0x66,0x85,0x85,0x4F,0xD6,
+    0x6F,0xEB,0xB3,0xC8,0xF7,0x6C,0x42,0x2E,0xE9,0xD6,0x84,0xD7,0x0F,0xD5,0x97,0xFD,
+    0x4F,0x31,0x33,0x1B,0x5B,0x23,0x56,0x1B,0x7C,0x1E,0x11,0x51,0xE8,0x14,0x22,0x50,
+    0x15,0x3D,0x01,0x1F,0x02,0x36,0x44,0x64,0x70,0xB3,0x7A,0xF7,0xF6,0xDA,0x14,0x9E,
+    0x39,0xC3,0xD1,0x9E,0xED,0x70,0x2C,0x4E,0xA5,0xA5,0x1C,0xB7,0xEE,0xEF,0x4E,0x90,
+    0x5D,0xF9,0x34,0xBB,0xA7,0xDF,0xD4,0xC5,0xEB,0x84,0xC4,0x3B,0x3D,0xCA,0x9A,0x9C,
+    0xAD,0xB1,0x24,0xD4,0xD1,0x82,0xCC,0x1A,0xC4,0xEF,0xAE,0xB1,0xF0,0x12,0x28,0x37,
+    0x40,0x45,0x83,0xBF,0x39,0xC7,0x90,0xB6,0x23,0x63,0xAD,0xC8,0xB9,0xF4,0x80,0x4B,
+    0x91,0x91,0x64,0xDD,0x05,0x5E,0x0A,0x36,0xAB,0x7A,0x32,0xBA,0x05,0xBC,0x62,0x93,
+    0xDE,0x5D,0xBA,0x2B,0x91,0xF2,0xD6,0x49,0x61,0x08,0x98,0xA2,0xD2,0x6E,0xF2,0x2D,
+    0x4D,0x90,0x65,0x51,0x9C,0xC0,0x79,0x33,0x08,0xE1,0x7F,0xC0,0x09,0xCF,0x4D,0xB3,
+    0x25,0x1F,0x02,0x03,0x01,0x00,0x01,0xA3,0x45,0x30,0x43,0x30,0x12,0x06,0x03,0x55,
+    0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x02,0x30,
+    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,
+    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x4D,0xA5,0xDB,0xEF,0x4F,0xCD,
+    0x74,0xE6,0x2A,0xB1,0xDC,0x5C,0xBE,0x12,0x04,0x94,0xEC,0x4A,0x66,0xD3,0x30,0x0D,
+    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x05,0x05,0x00,0x03,0x82,0x01,
+    0x01,0x00,0x06,0x5E,0xFD,0x98,0x73,0xA7,0x69,0xE2,0xAE,0x1C,0x06,0x00,0xD1,0x7C,
+    0x59,0x70,0xB9,0x85,0xAF,0xB8,0xC0,0xAB,0x3B,0x60,0x64,0x0B,0x1B,0x81,0xA7,0x7D,
+    0x5A,0xC4,0xDA,0x94,0x2B,0xBC,0xA7,0xDA,0x24,0x4E,0x83,0x21,0x12,0xFA,0x93,0x3E,
+    0x67,0x38,0x37,0xBD,0x2B,0xEB,0x19,0xA4,0x08,0x73,0xB1,0x27,0x84,0x67,0x10,0x48,
+    0x50,0x94,0x4C,0x55,0x0D,0x23,0x9F,0x0A,0xB2,0x18,0x6F,0xC1,0xE0,0x13,0xC2,0x2D,
+    0x29,0x52,0xBA,0x4F,0x01,0x2C,0xD6,0x9E,0x73,0x5B,0x74,0x8A,0x0D,0x8C,0x1E,0x15,
+    0x70,0x7E,0x9B,0xE0,0xCC,0xB2,0x6E,0xFE,0x44,0xD4,0xD0,0x76,0x41,0x95,0xFE,0x11,
+    0xAA,0x4E,0x07,0xC6,0xBA,0x4B,0x46,0x02,0x0E,0xFC,0x4A,0xB9,0x15,0x2D,0x80,0xB5,
+    0x33,0xE3,0x4E,0x41,0x46,0x05,0xEB,0x0A,0x15,0x43,0xC6,0x6A,0xC5,0x2B,0x53,0x49,
+    0x49,0x61,0x57,0x0D,0x8D,0x42,0x63,0xB2,0xA6,0xC5,0xA5,0x23,0x3B,0xAC,0x50,0xDC,
+    0x05,0x41,0x53,0x74,0xC5,0x67,0xA1,0x69,0xA6,0x66,0x4D,0x0F,0xF8,0x94,0x54,0x4B,
+    0xA5,0x31,0x81,0xE8,0x3A,0x5C,0x02,0x84,0x56,0xFF,0xBE,0x13,0x15,0x95,0xC9,0xAF,
+    0x17,0x77,0xD0,0x38,0x38,0x12,0xF9,0xA8,0x93,0x77,0x2F,0xCD,0x40,0x60,0xBC,0xCF,
+    0x35,0x1C,0xE4,0xBD,0x5E,0x8D,0x96,0x19,0xB7,0x50,0x7E,0xED,0x44,0x1C,0x8C,0x08,
+    0x6B,0xEE,0xEE,0xC9,0x8C,0xD6,0xDC,0x61,0x2C,0xD2,0x35,0x5E,0xB7,0x4C,0x58,0xFC,
+    0x5D,0x62,0xEA,0xED,0x68,0xE8,0x1F,0xB1,0x0A,0x39,0x5C,0x29,0xBC,0x42,0x09,0xBA,
+    0x4F,0x35,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Testing Intermediate CA 1 */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Test CA */
+/* Not Before: Oct 15 00:00:00 2016 GMT */
+/* X509v3 Subject Key Identifier: E7:C3:06:5B:22:E0:EC:DA:8C:80:00:D9:0C:AC:0B:78:D4:68:C5:B7 */
+unsigned char _datetest_before_int[1050]={
+    0x30,0x82,0x04,0x16,0x30,0x82,0x02,0xFE,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,
+    0x9A,0x17,0xF8,0x6F,0x33,0x3D,0xAB,0x4C,0xD3,0xFB,0x3A,0x6D,0xCF,0x05,0x94,0xEC,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,
+    0x81,0x8A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
+    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
+    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
+    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
+    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x1E,0x30,0x1C,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x15,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,
+    0x44,0x61,0x74,0x65,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,
+    0x31,0x36,0x31,0x30,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,
+    0x37,0x31,0x30,0x31,0x32,0x31,0x38,0x32,0x38,0x31,0x38,0x5A,0x30,0x81,0x9C,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,
+    0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,
+    0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,
+    0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,
+    0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x30,0x30,0x2E,0x06,0x03,0x55,
+    0x04,0x03,0x0C,0x27,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x44,0x61,0x74,
+    0x65,0x20,0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x20,0x49,0x6E,0x74,0x65,0x72,0x6D,
+    0x65,0x64,0x69,0x61,0x74,0x65,0x20,0x43,0x41,0x20,0x31,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,0xF0,0xCB,0x1D,0x6C,
+    0x7D,0xC1,0x90,0xB7,0xD9,0xB5,0x66,0x61,0x5E,0x34,0x76,0x14,0xFA,0xF8,0xB4,0xE1,
+    0x6D,0x67,0xB0,0x9E,0xB9,0x93,0xB0,0xBE,0x15,0xA4,0xAB,0x76,0x23,0x0D,0x5C,0xC0,
+    0x4D,0xB6,0x9F,0xCC,0x9B,0x3A,0x7E,0x50,0x13,0xE6,0x46,0x39,0xB1,0xE9,0x5F,0xB3,
+    0xD7,0x86,0xA4,0x23,0xA5,0x27,0xDC,0x20,0x6A,0x64,0xD8,0x0A,0xCD,0x5F,0xEE,0x40,
+    0x16,0xCE,0x4D,0xB9,0xCF,0xA2,0x62,0xC8,0x01,0x70,0x7F,0x8D,0x42,0x46,0xB1,0xF2,
+    0x80,0x57,0xD5,0x82,0x53,0xEF,0xF2,0x16,0xA4,0xD5,0x07,0xE2,0xA7,0x7A,0x5E,0xD5,
+    0x5A,0x4F,0x58,0x88,0xF7,0xEB,0x1B,0x58,0x91,0x6D,0x4E,0xD8,0xCC,0x9F,0xA6,0x98,
+    0x05,0xE6,0xFB,0xC2,0x55,0xCA,0xD9,0x7E,0xC8,0xAA,0xC2,0x92,0xC1,0x73,0xBB,0xEC,
+    0x89,0x51,0x1C,0x6B,0x0C,0xE5,0x7D,0xF8,0x54,0xBE,0xF7,0x67,0x8C,0xEE,0xE4,0xBB,
+    0xFF,0xB9,0x15,0x4F,0xD7,0x1B,0x76,0xF7,0x37,0xEF,0xB0,0xA0,0x2A,0x22,0x4D,0x4B,
+    0x2A,0xDE,0x3D,0x37,0x28,0x4A,0x79,0xF6,0xC7,0xE3,0x51,0xEC,0xC4,0x2F,0xDA,0xC1,
+    0xBA,0x1A,0xFF,0xDD,0x43,0x2A,0x44,0xD4,0x94,0xDC,0xEE,0xDB,0xC3,0xF2,0xB4,0x76,
+    0x01,0xF7,0x69,0x48,0x11,0x67,0xAC,0x3C,0x1C,0xE0,0xEF,0x88,0x77,0x70,0x66,0x39,
+    0x17,0xAA,0xD8,0x2C,0x67,0xE3,0xC3,0x2B,0xCD,0xC4,0xB9,0xC8,0xCD,0xA9,0xA4,0xC1,
+    0x24,0xDF,0x8E,0x4D,0xE0,0x03,0x1E,0x40,0xAB,0xDD,0x10,0xE7,0xB5,0x93,0x1F,0xF2,
+    0xC9,0xCC,0x91,0x3A,0x8D,0x52,0xC9,0x3D,0x7D,0x4D,0xA0,0xBB,0x02,0x03,0x01,0x00,
+    0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,
+    0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,
+    0x04,0x04,0x03,0x02,0x02,0x04,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
+    0x14,0xE7,0xC3,0x06,0x5B,0x22,0xE0,0xEC,0xDA,0x8C,0x80,0x00,0xD9,0x0C,0xAC,0x0B,
+    0x78,0xD4,0x68,0xC5,0xB7,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
+    0x80,0x14,0x4D,0xA5,0xDB,0xEF,0x4F,0xCD,0x74,0xE6,0x2A,0xB1,0xDC,0x5C,0xBE,0x12,
+    0x04,0x94,0xEC,0x4A,0x66,0xD3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
+    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x08,0xDC,0x9E,0xA4,0x60,0xDF,
+    0x04,0x27,0xB5,0x01,0x63,0xDA,0xE3,0x6C,0x58,0x1D,0xB8,0xE8,0x17,0x06,0x4F,0x86,
+    0xC8,0x97,0x65,0xF5,0x6D,0x39,0x51,0x0F,0xD4,0xF9,0xAD,0xCF,0x8C,0x08,0x7C,0xAC,
+    0x26,0xD1,0x43,0xB2,0x79,0x7E,0x13,0xCD,0xF2,0x9D,0x30,0xC4,0x63,0xF2,0x5E,0x72,
+    0x1A,0x0F,0x41,0x47,0x69,0x98,0x00,0xF0,0x4D,0x93,0x44,0x8A,0x26,0xDE,0x24,0xC0,
+    0x66,0xA3,0xB0,0x20,0xAD,0x33,0xEB,0xF2,0x0A,0xDD,0x65,0xF4,0x9D,0x29,0x10,0x88,
+    0x5B,0xFF,0x1C,0x76,0x71,0x42,0xE9,0x6F,0xBD,0xAE,0xA6,0xBB,0x4B,0xFF,0x30,0xA0,
+    0x6E,0x47,0x85,0x12,0x6E,0x81,0xFC,0xB0,0x51,0x5F,0xB4,0xE9,0xCC,0x83,0x0E,0xC5,
+    0xEC,0x41,0x6F,0x28,0x28,0xF0,0x51,0x4A,0x42,0x7C,0xCF,0xAE,0x8B,0xD8,0x09,0x44,
+    0x32,0x27,0x07,0x57,0x86,0x1B,0xB6,0xF3,0xAF,0xCA,0x1C,0x2F,0xDD,0x1C,0x58,0x17,
+    0xF4,0x13,0xA3,0x4F,0x72,0x60,0x71,0x39,0xEE,0x8E,0xF2,0x9D,0x40,0xCA,0x39,0x63,
+    0xFD,0x1F,0x8C,0x2C,0xFD,0x62,0xA8,0x0E,0xC3,0x04,0x62,0x9D,0x79,0x11,0xD2,0x5C,
+    0x09,0xE5,0x27,0x50,0x3A,0x62,0x93,0xC5,0xA5,0x60,0xFB,0xE5,0x7F,0xB6,0x46,0xD5,
+    0xA8,0xF8,0x38,0x05,0x94,0xCD,0x47,0x5B,0xA0,0xA4,0x67,0xB8,0x81,0x99,0xA2,0x92,
+    0xEB,0x13,0x37,0x56,0xD6,0xAC,0x80,0xA6,0x7F,0x1A,0xBB,0x14,0x68,0x72,0x04,0xBD,
+    0xD7,0xEE,0x8F,0x48,0x56,0xC7,0xDF,0x86,0xBB,0x76,0xE4,0xE3,0xE3,0x46,0xF3,0x8B,
+    0x51,0x22,0xD6,0xD2,0xB9,0xAA,0x15,0xA2,0xB4,0xAC,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Testing Intermediate CA 1 */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Test CA */
+/* Not Before: Dec  1 00:01:00 2016 GMT */
+/* X509v3 Subject Key Identifier: E7:C3:06:5B:22:E0:EC:DA:8C:80:00:D9:0C:AC:0B:78:D4:68:C5:B7 */
+unsigned char _datetest_after_int[1050]={
+    0x30,0x82,0x04,0x16,0x30,0x82,0x02,0xFE,0xA0,0x03,0x02,0x01,0x02,0x02,0x11,0x00,
+    0x9A,0x17,0xF8,0x6F,0x33,0x3D,0xAB,0x4C,0xD3,0xFB,0x3A,0x6D,0xCF,0x05,0x94,0xEE,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,
+    0x81,0x8A,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
+    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
+    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
+    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
+    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x1E,0x30,0x1C,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x15,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,
+    0x44,0x61,0x74,0x65,0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,
+    0x31,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x31,0x30,0x30,0x5A,0x17,0x0D,0x31,
+    0x37,0x31,0x30,0x31,0x32,0x32,0x30,0x33,0x34,0x34,0x38,0x5A,0x30,0x81,0x9C,0x31,
+    0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,
+    0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,
+    0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,
+    0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,
+    0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x30,0x30,0x2E,0x06,0x03,0x55,
+    0x04,0x03,0x0C,0x27,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x44,0x61,0x74,
+    0x65,0x20,0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x20,0x49,0x6E,0x74,0x65,0x72,0x6D,
+    0x65,0x64,0x69,0x61,0x74,0x65,0x20,0x43,0x41,0x20,0x31,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,0xF0,0xCB,0x1D,0x6C,
+    0x7D,0xC1,0x90,0xB7,0xD9,0xB5,0x66,0x61,0x5E,0x34,0x76,0x14,0xFA,0xF8,0xB4,0xE1,
+    0x6D,0x67,0xB0,0x9E,0xB9,0x93,0xB0,0xBE,0x15,0xA4,0xAB,0x76,0x23,0x0D,0x5C,0xC0,
+    0x4D,0xB6,0x9F,0xCC,0x9B,0x3A,0x7E,0x50,0x13,0xE6,0x46,0x39,0xB1,0xE9,0x5F,0xB3,
+    0xD7,0x86,0xA4,0x23,0xA5,0x27,0xDC,0x20,0x6A,0x64,0xD8,0x0A,0xCD,0x5F,0xEE,0x40,
+    0x16,0xCE,0x4D,0xB9,0xCF,0xA2,0x62,0xC8,0x01,0x70,0x7F,0x8D,0x42,0x46,0xB1,0xF2,
+    0x80,0x57,0xD5,0x82,0x53,0xEF,0xF2,0x16,0xA4,0xD5,0x07,0xE2,0xA7,0x7A,0x5E,0xD5,
+    0x5A,0x4F,0x58,0x88,0xF7,0xEB,0x1B,0x58,0x91,0x6D,0x4E,0xD8,0xCC,0x9F,0xA6,0x98,
+    0x05,0xE6,0xFB,0xC2,0x55,0xCA,0xD9,0x7E,0xC8,0xAA,0xC2,0x92,0xC1,0x73,0xBB,0xEC,
+    0x89,0x51,0x1C,0x6B,0x0C,0xE5,0x7D,0xF8,0x54,0xBE,0xF7,0x67,0x8C,0xEE,0xE4,0xBB,
+    0xFF,0xB9,0x15,0x4F,0xD7,0x1B,0x76,0xF7,0x37,0xEF,0xB0,0xA0,0x2A,0x22,0x4D,0x4B,
+    0x2A,0xDE,0x3D,0x37,0x28,0x4A,0x79,0xF6,0xC7,0xE3,0x51,0xEC,0xC4,0x2F,0xDA,0xC1,
+    0xBA,0x1A,0xFF,0xDD,0x43,0x2A,0x44,0xD4,0x94,0xDC,0xEE,0xDB,0xC3,0xF2,0xB4,0x76,
+    0x01,0xF7,0x69,0x48,0x11,0x67,0xAC,0x3C,0x1C,0xE0,0xEF,0x88,0x77,0x70,0x66,0x39,
+    0x17,0xAA,0xD8,0x2C,0x67,0xE3,0xC3,0x2B,0xCD,0xC4,0xB9,0xC8,0xCD,0xA9,0xA4,0xC1,
+    0x24,0xDF,0x8E,0x4D,0xE0,0x03,0x1E,0x40,0xAB,0xDD,0x10,0xE7,0xB5,0x93,0x1F,0xF2,
+    0xC9,0xCC,0x91,0x3A,0x8D,0x52,0xC9,0x3D,0x7D,0x4D,0xA0,0xBB,0x02,0x03,0x01,0x00,
+    0x01,0xA3,0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,
+    0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,
+    0x04,0x04,0x03,0x02,0x02,0x04,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
+    0x14,0xE7,0xC3,0x06,0x5B,0x22,0xE0,0xEC,0xDA,0x8C,0x80,0x00,0xD9,0x0C,0xAC,0x0B,
+    0x78,0xD4,0x68,0xC5,0xB7,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
+    0x80,0x14,0x4D,0xA5,0xDB,0xEF,0x4F,0xCD,0x74,0xE6,0x2A,0xB1,0xDC,0x5C,0xBE,0x12,
+    0x04,0x94,0xEC,0x4A,0x66,0xD3,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
+    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x82,0xDE,0x0F,0x06,0xD4,0xC3,
+    0x55,0xD1,0xC9,0x9A,0xDF,0x87,0x69,0xA8,0xA2,0x11,0x12,0x73,0xF4,0x8B,0x98,0x02,
+    0xA6,0xE0,0xB1,0x11,0x0E,0xEB,0xC3,0x3B,0x1D,0x8B,0xBF,0x45,0x4B,0x24,0xEA,0x7A,
+    0xEF,0x70,0x2A,0xAB,0xE4,0xB6,0xA1,0xB1,0x66,0x5E,0x12,0x09,0x49,0x93,0x6A,0x4B,
+    0x3A,0x10,0xD1,0xEE,0xA0,0x6D,0xC7,0x19,0x5B,0xE0,0x75,0x2F,0x3F,0xFB,0x66,0x1F,
+    0x91,0x86,0x30,0x5A,0xC6,0x77,0xED,0x06,0x85,0xF8,0x65,0x96,0x48,0x30,0x32,0x25,
+    0x93,0x59,0x51,0x2D,0x7D,0x20,0x12,0x9A,0x87,0x07,0x40,0x8C,0x8F,0x81,0xD8,0xF8,
+    0xF2,0xF2,0x3E,0xF3,0xF3,0xC8,0x7D,0x7A,0xAA,0xE3,0xF7,0xCD,0x9D,0x69,0x6F,0x85,
+    0x15,0xCD,0x18,0xC0,0xBB,0x6E,0x27,0xAD,0xD3,0x9A,0xD2,0x6A,0x42,0x02,0x0C,0xDB,
+    0xF5,0x0C,0x85,0xC3,0xB3,0xDB,0x4C,0x28,0x61,0x82,0xC8,0x88,0x44,0x95,0x08,0xBE,
+    0x24,0x07,0xEA,0xD2,0x4C,0x0A,0xA9,0x2E,0x47,0x28,0xDE,0xF3,0x24,0xDC,0x22,0x57,
+    0xA4,0x5D,0x04,0x22,0x28,0xC6,0x4F,0xBD,0x2E,0xB7,0xD4,0x2C,0x06,0x0E,0x22,0xF5,
+    0x05,0xA6,0x76,0x8E,0x77,0xFD,0x1C,0xA1,0x4E,0x10,0x1D,0x82,0x74,0x73,0x06,0x47,
+    0xC2,0xD2,0xF7,0x59,0xD5,0xBF,0x64,0x77,0xBB,0x47,0x15,0x23,0x4B,0x78,0x7C,0x51,
+    0x34,0xF0,0xF7,0x04,0xE1,0x5C,0xED,0x28,0x55,0x7B,0xC1,0x07,0x52,0x2A,0x86,0x48,
+    0xEB,0x8C,0xC2,0x55,0x56,0xDA,0x98,0xF3,0x5C,0x8F,0x21,0x70,0xDD,0xFB,0xA4,0x61,
+    0x2F,0x57,0xE7,0x0B,0x70,0x2F,0x00,0x72,0x79,0x3C,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Testing Before Leaf */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Testing Intermediate CA 1 */
+/* Not Before: Oct 15 00:00:00 2016 GMT */
+unsigned char _datetest_before_leaf[1109]={
+    0x30,0x82,0x04,0x51,0x30,0x82,0x03,0x39,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4C,
+    0x3E,0x59,0xB4,0xB4,0x96,0x67,0xC6,0x13,0xB0,0xB4,0x67,0x03,0xB9,0x27,0xAE,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,
+    0x9C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,
+    0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
+    0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,
+    0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,
+    0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x30,0x30,0x2E,0x06,
+    0x03,0x55,0x04,0x03,0x0C,0x27,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x44,
+    0x61,0x74,0x65,0x20,0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x20,0x49,0x6E,0x74,0x65,
+    0x72,0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x20,0x43,0x41,0x20,0x31,0x30,0x1E,0x17,
+    0x0D,0x31,0x36,0x31,0x30,0x31,0x35,0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,
+    0x31,0x37,0x31,0x30,0x31,0x32,0x31,0x38,0x33,0x38,0x30,0x38,0x5A,0x30,0x81,0x91,
+    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,
+    0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,
+    0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,
+    0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,
+    0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,
+    0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,
+    0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x25,0x30,0x23,0x06,0x03,
+    0x55,0x04,0x03,0x0C,0x1C,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x54,0x65,
+    0x73,0x74,0x69,0x6E,0x67,0x20,0x42,0x65,0x66,0x6F,0x72,0x65,0x20,0x4C,0x65,0x61,
+    0x66,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,0xB5,0x10,0x30,0xBE,0xE6,0x80,0x11,0x8B,0x5B,0xD8,0xDD,0xFE,0x66,0x19,
+    0x8A,0xBC,0x01,0x29,0xA8,0x85,0x25,0xDB,0xF0,0x33,0xA9,0x5F,0x34,0xFC,0x7A,0xB7,
+    0x19,0xD1,0x4A,0x7C,0xC9,0xBE,0x9C,0x8E,0xD3,0xB6,0xAA,0x48,0x97,0x53,0xBF,0x20,
+    0x1D,0x81,0xAC,0x87,0xCA,0x60,0xC0,0xD5,0xC5,0x9E,0x86,0x48,0xA4,0xBD,0xB2,0x9E,
+    0x88,0x92,0x2C,0x6C,0x8D,0xAC,0xC5,0x65,0x6C,0x5C,0x38,0x4E,0x1A,0xDC,0x00,0x70,
+    0xCA,0x68,0x33,0x38,0x10,0xE0,0x5F,0xAC,0x8C,0x47,0x73,0xA5,0xC6,0xC7,0x2C,0x4C,
+    0xB8,0xBB,0xE7,0x6C,0x42,0x6C,0x11,0x8C,0x2C,0x5E,0xBC,0x4C,0x87,0x1E,0xDE,0x2C,
+    0xDE,0x40,0x7E,0xB9,0x32,0x7D,0x73,0x5B,0xF8,0x59,0x50,0x71,0x1E,0x43,0x06,0x89,
+    0x09,0xC3,0x3B,0xC2,0xEB,0xD5,0x26,0x50,0x0D,0x98,0x09,0xE7,0x50,0x39,0x87,0x3C,
+    0x06,0x5E,0xFF,0x4E,0xD4,0x9C,0x53,0xF9,0xBD,0x3E,0x5E,0x73,0x8B,0xBC,0xE5,0x3E,
+    0xD2,0x96,0x4D,0xE5,0x1E,0x24,0x3D,0x34,0xA8,0x7C,0xB9,0x55,0xC0,0xA6,0x61,0x69,
+    0xC2,0xCF,0x1F,0x67,0x45,0xC6,0x3A,0x56,0x1F,0xD2,0x93,0x32,0x3F,0x1A,0x60,0x6B,
+    0x5B,0xCD,0x1A,0x6D,0x54,0x8C,0xF4,0x3F,0x4D,0x2B,0xA8,0xE7,0x2D,0xF8,0x12,0x39,
+    0xCC,0xE6,0x41,0x35,0xD0,0x27,0xE5,0x20,0x15,0xFD,0xF0,0xC4,0xDF,0x7C,0x13,0x65,
+    0x1B,0xD8,0x54,0x9D,0x68,0xDC,0xAA,0x51,0xD3,0x6C,0x4F,0x6C,0x16,0x83,0xC6,0x3F,
+    0xF9,0x95,0xFF,0xE6,0x4B,0x23,0x4B,0xE1,0x5D,0x02,0xC5,0x14,0x03,0x3A,0x0A,0xFB,
+    0xAB,0x1B,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x97,0x30,0x81,0x94,0x30,0x0C,0x06,
+    0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x0E,0x06,0x03,0x55,
+    0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x13,0x06,0x03,0x55,
+    0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,
+    0x30,0x1F,0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,0x82,0x14,0x74,0x65,0x73,
+    0x74,0x73,0x65,0x72,0x76,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
+    0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x52,0xBB,0x5E,0x78,
+    0x5F,0x54,0xE6,0xD9,0x56,0x8B,0xE9,0x31,0xE7,0x9A,0x68,0xF2,0x96,0xB5,0x34,0xA4,
+    0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xE7,0xC3,0x06,
+    0x5B,0x22,0xE0,0xEC,0xDA,0x8C,0x80,0x00,0xD9,0x0C,0xAC,0x0B,0x78,0xD4,0x68,0xC5,
+    0xB7,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x2B,0x8A,0xFF,0xC4,0x3F,0x5C,0x0C,0x98,0x78,0x65,0xC2,
+    0x5C,0x41,0x26,0xA1,0x1F,0x08,0xAB,0x6C,0xB2,0xF9,0xF3,0x6C,0x71,0xDA,0xD6,0xCB,
+    0x40,0x2C,0xE8,0xA2,0x06,0x66,0xF0,0xD0,0x93,0x7B,0x0A,0x29,0xBB,0x9C,0x12,0xF5,
+    0xE0,0xFF,0xC5,0x58,0xB2,0x95,0x25,0x29,0x1E,0x8B,0xFE,0xCC,0x8F,0xC7,0x5E,0x76,
+    0x58,0x5E,0x27,0x29,0x47,0xC4,0x1B,0xC1,0xEB,0x22,0x2E,0xDB,0xE2,0x7F,0x38,0x09,
+    0x14,0xAC,0x94,0xF6,0xFB,0x16,0x21,0x08,0x11,0x20,0x2B,0x2A,0xB5,0x22,0xD3,0x31,
+    0x43,0xB0,0x4E,0xE8,0x33,0x3B,0xDC,0x10,0x56,0xDE,0x55,0xC8,0x9A,0x31,0x6C,0x52,
+    0x6D,0xE9,0x79,0x70,0xEB,0xCD,0xD8,0x27,0x32,0xF6,0x30,0x7D,0x48,0xAF,0xB5,0xD8,
+    0xBD,0xF3,0x68,0xEC,0xB0,0x7F,0x5A,0x52,0x9A,0x5A,0xF1,0x8E,0xCD,0x94,0x37,0x16,
+    0xA2,0x75,0x3C,0x0E,0xDA,0xDE,0x12,0x33,0xAE,0x04,0xAB,0x27,0xDE,0xD1,0x60,0x13,
+    0x0C,0x67,0x07,0x2A,0x7C,0xF2,0x46,0x74,0x3C,0x79,0x9B,0x6D,0xF3,0x2D,0x2E,0x69,
+    0xDD,0xF4,0xEA,0xEC,0xD2,0xDD,0x85,0x79,0x77,0xCD,0x20,0xA9,0x19,0x3F,0x99,0xBB,
+    0xA4,0x8A,0x78,0xBE,0x0E,0xEC,0xB9,0x91,0xAD,0xB6,0xFC,0xFB,0xCF,0xCF,0x71,0xBF,
+    0x3C,0x13,0x2F,0xEB,0xD8,0xC8,0x22,0xC3,0x07,0xBB,0xCB,0x95,0x39,0xD4,0x61,0xDF,
+    0x4F,0x87,0x41,0xCA,0xDD,0xD8,0x54,0xD7,0xDE,0x9C,0x13,0xF6,0x69,0x90,0xEE,0xE8,
+    0xF8,0x0B,0x83,0x38,0x31,0x4C,0x67,0x96,0xF6,0x4A,0x77,0x00,0x41,0x11,0x91,0x77,
+    0xC2,0x05,0x60,0x30,0x8C,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Testing After Leaf */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Denylist Date Testing Intermediate CA 1 */
+/* Not Before: Dec  1 00:01:00 2016 GMT */
+unsigned char _datetest_after_leaf[1108]={
+    0x30,0x82,0x04,0x50,0x30,0x82,0x03,0x38,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x4C,
+    0x3E,0x59,0xB4,0xB4,0x96,0x67,0xC6,0x13,0xB0,0xB4,0x67,0x03,0xB9,0x27,0xAF,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,
+    0x9C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,
+    0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
+    0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,
+    0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,
+    0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x30,0x30,0x2E,0x06,
+    0x03,0x55,0x04,0x03,0x0C,0x27,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x44,
+    0x61,0x74,0x65,0x20,0x54,0x65,0x73,0x74,0x69,0x6E,0x67,0x20,0x49,0x6E,0x74,0x65,
+    0x72,0x6D,0x65,0x64,0x69,0x61,0x74,0x65,0x20,0x43,0x41,0x20,0x31,0x30,0x1E,0x17,
+    0x0D,0x31,0x36,0x31,0x32,0x30,0x31,0x30,0x30,0x30,0x31,0x30,0x30,0x5A,0x17,0x0D,
+    0x31,0x37,0x31,0x30,0x31,0x32,0x31,0x38,0x33,0x38,0x34,0x37,0x5A,0x30,0x81,0x90,
+    0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,
+    0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,
+    0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,
+    0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,
+    0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,
+    0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,
+    0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,
+    0x55,0x04,0x03,0x0C,0x1B,0x44,0x65,0x6E,0x79,0x6C,0x69,0x73,0x74,0x20,0x54,0x65,
+    0x73,0x74,0x69,0x6E,0x67,0x20,0x41,0x66,0x74,0x65,0x72,0x20,0x4C,0x65,0x61,0x66,
+    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,0xE9,0xD1,0x18,0x04,0x41,0x52,0x27,0x4F,0x91,0x31,0xBD,0xF2,0x9F,0x11,0x8F,
+    0x50,0xF6,0x5C,0xD2,0x6F,0x8B,0x7F,0xDA,0x20,0x50,0x92,0x7F,0x7D,0x61,0x6E,0x52,
+    0x74,0xE1,0x66,0x14,0x70,0xAD,0x9E,0x84,0xF2,0x71,0x23,0xC7,0xC6,0xFD,0x58,0xE3,
+    0x5B,0x37,0xFF,0x8F,0x72,0xC9,0x4D,0x71,0x20,0xA0,0x7F,0x23,0xD5,0xF5,0xC1,0x37,
+    0x01,0x57,0x1C,0x8F,0x8E,0xD1,0x59,0xED,0x26,0x41,0xED,0xE7,0x47,0x86,0xCE,0xBB,
+    0x27,0x45,0xAC,0x08,0x51,0xAB,0x3E,0xD8,0x92,0x98,0x6D,0x88,0x24,0xD1,0x56,0x8D,
+    0xED,0x81,0xCE,0xBA,0x8F,0x9E,0x8E,0x9E,0x81,0x29,0xC5,0x9C,0x32,0x75,0xC6,0x5D,
+    0xDE,0x1E,0x61,0x38,0xD7,0x89,0x41,0x17,0xAC,0xDC,0xB9,0x98,0xC4,0x7E,0xA7,0xC0,
+    0x3B,0xB9,0xF2,0xA0,0xB0,0x88,0x3E,0x84,0xBC,0x28,0x1D,0x5B,0x35,0x92,0xCC,0xCB,
+    0x9B,0x4E,0xD3,0xF2,0x2F,0x9B,0x77,0xC5,0xB1,0x08,0x18,0x86,0xF1,0x1E,0x47,0xDD,
+    0x9A,0x94,0x5E,0xEF,0xE7,0x32,0xAD,0xD0,0x3C,0x65,0x81,0x5D,0xD7,0x94,0x56,0xCA,
+    0x95,0xEA,0x4C,0x87,0xE1,0x48,0xC0,0xB9,0xA7,0x23,0xED,0x0F,0xFC,0x56,0x38,0x10,
+    0x4E,0x7F,0xB3,0x73,0x0B,0x3A,0xCB,0xB9,0x89,0x15,0xA9,0xBD,0x81,0xB9,0x9F,0xD9,
+    0x53,0x2E,0x73,0x95,0x2D,0xA9,0x81,0x85,0xA7,0xC2,0x0B,0xA2,0xDE,0x6F,0x41,0x72,
+    0x05,0x50,0xE5,0xB4,0x10,0xD4,0xE7,0xF2,0x76,0x48,0xCC,0x2A,0x2C,0x44,0x74,0xF1,
+    0x5E,0x0A,0xB5,0x02,0x55,0x25,0x54,0x29,0x92,0x6F,0x0A,0x78,0x33,0xBB,0x8C,0x01,
+    0x1F,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x97,0x30,0x81,0x94,0x30,0x0C,0x06,0x03,
+    0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,
+    0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x13,0x06,0x03,0x55,0x1D,
+    0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,
+    0x1F,0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,0x82,0x14,0x74,0x65,0x73,0x74,
+    0x73,0x65,0x72,0x76,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,
+    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x1F,0xBA,0x32,0x4F,0x63,
+    0xBA,0x31,0x1E,0xA3,0x91,0xFC,0x59,0x84,0x62,0xA9,0x52,0x22,0xC6,0xF1,0xAB,0x30,
+    0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xE7,0xC3,0x06,0x5B,
+    0x22,0xE0,0xEC,0xDA,0x8C,0x80,0x00,0xD9,0x0C,0xAC,0x0B,0x78,0xD4,0x68,0xC5,0xB7,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
+    0x82,0x01,0x01,0x00,0x86,0xFF,0xC5,0xB6,0xB6,0x57,0x9A,0x6B,0xA3,0x83,0xFA,0x97,
+    0xA3,0xCB,0x4F,0xA3,0x44,0xB9,0x0A,0x89,0xC7,0x09,0xE3,0x9F,0x61,0x45,0x80,0x11,
+    0x1C,0x8F,0x81,0x12,0x96,0x55,0x91,0xD7,0x93,0x70,0x7A,0x24,0x1D,0xA5,0xFE,0x8C,
+    0xD9,0x0C,0x74,0x2A,0xB8,0x0C,0xF9,0xBC,0xA7,0xFE,0xC8,0x03,0x1F,0xC8,0x55,0xEF,
+    0xC2,0x54,0x81,0x4D,0xA1,0x88,0x1F,0x88,0x74,0x12,0xE3,0xA2,0x58,0x9D,0x66,0x89,
+    0x8F,0xBB,0x0F,0xB7,0xE5,0x9F,0xF0,0x81,0x0E,0xFC,0x0E,0x3D,0x33,0xB1,0x9D,0xDD,
+    0x82,0x3E,0xF8,0xF2,0x10,0x50,0x1B,0xEB,0x19,0x44,0x5F,0x74,0x2E,0x98,0x68,0x3C,
+    0xF7,0x08,0x2F,0x8B,0xB7,0x67,0x14,0xC5,0xC1,0x33,0xBB,0xA8,0xDF,0x47,0xFE,0x3D,
+    0x24,0x36,0xD3,0xA7,0x8F,0xAC,0x9E,0x2E,0x49,0xFC,0xB1,0x68,0x93,0x9E,0x10,0x99,
+    0x35,0x7F,0xC6,0xBF,0xFD,0x90,0x32,0xCB,0x73,0x57,0x65,0x11,0xDF,0xEB,0x64,0x23,
+    0xDD,0x67,0xCC,0x8A,0x00,0xDA,0x0F,0x09,0x66,0xEE,0x72,0xCC,0x73,0x93,0x92,0xC5,
+    0x53,0xF4,0x60,0xF1,0xAB,0x3E,0x8B,0x4B,0xEF,0x2C,0xCF,0xDA,0x70,0x4D,0x50,0xB0,
+    0x10,0x87,0x97,0x87,0x26,0xA2,0x39,0x16,0xD2,0xEA,0xDC,0x42,0xE7,0xF0,0xED,0x53,
+    0xD5,0xFF,0x61,0x1E,0x93,0x22,0xD7,0x59,0xDA,0xAC,0xCD,0x81,0x9E,0xD8,0x72,0x13,
+    0x52,0x6B,0xEE,0x86,0xA1,0x37,0x6C,0xBA,0xA2,0x60,0xB2,0xCC,0xA1,0x51,0xA8,0x57,
+    0x80,0xCA,0x9C,0xAF,0x03,0xAB,0xBD,0xC3,0x13,0xAA,0x46,0xBD,0x3B,0x99,0xE6,0x6F,
+    0x7B,0x93,0x90,0xB6,
+};
+
+#endif /* _TRUSTTESTS_ALLOWLIST_BLOCKLIST_TESTS_ */
diff --git a/tests/TrustTests/EvaluationTests/CAIssuerTests.m b/tests/TrustTests/EvaluationTests/CAIssuerTests.m
new file mode 100644 (file)
index 0000000..da4d364
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+* Copyright (c) 2006-2019 Apple Inc. All Rights Reserved.
+*/
+
+#include <AssertMacros.h>
+#import <XCTest/XCTest.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecPolicyPriv.h>
+#include <Security/SecTrustPriv.h>
+#include <utilities/array_size.h>
+#include <utilities/SecCFRelease.h>
+
+#import "../TestMacroConversions.h"
+#import "../TrustEvaluationTestHelpers.h"
+#import "TrustEvaluationTestCase.h"
+
+#import "CAIssuerTests_data.h"
+
+@interface CAIssuerTests: TrustEvaluationTestCase
+@end
+
+@implementation CAIssuerTests
+
+#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE
+- (void) test_aia
+{
+    if (!ping_host("crt.comodoca.com")) {
+        XCTAssert(false, "Unable to contact required network resource");
+        return;
+    }
+
+    SecCertificateRef ovh = NULL, comodo_ev = NULL, comodo_aia = NULL;
+    CFMutableArrayRef certs = NULL, policies = NULL;
+    SecPolicyRef sslPolicy = NULL, revPolicy = NULL;
+    CFDateRef verifyDate = NULL;
+    SecTrustRef trust = NULL;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+
+    /* Initialize common variables */
+    isnt(ovh = SecCertificateCreateWithBytes(NULL, ovh_certificate,
+        sizeof(ovh_certificate)), NULL, "create ovh cert");
+    isnt(comodo_ev = SecCertificateCreateWithBytes(NULL, comodo_ev_certificate,
+        sizeof(comodo_ev_certificate)), NULL, "create comodo_ev cert");
+    isnt(comodo_aia = SecCertificateCreateWithBytes(NULL,
+        comodo_aia_certificate, sizeof(comodo_aia_certificate)), NULL,
+        "create comodo_aia cert");
+    certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+        &kCFTypeArrayCallBacks);
+    policies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+        &kCFTypeArrayCallBacks);
+    sslPolicy = SecPolicyCreateSSL(false, NULL); // For now, use SSL client policy to avoid SHA-1 deprecation
+    revPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
+    CFArrayAppendValue(policies, sslPolicy);
+    CFArrayAppendValue(policies, revPolicy);
+    /* May 9th 2018. */
+    verifyDate = CFDateCreate(NULL, 547600500);
+
+    /* First run with no intermediate and disallow network fetching.
+     * Evaluation should fail because it couldn't get the intermediate. */
+    CFArrayAppendValue(certs, ovh);
+    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
+              "create trust");
+    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
+    ok_status(SecTrustSetNetworkFetchAllowed(trust, false), "set no network");
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
+    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
+       "trust is kSecTrustResultRecoverableTrustFailure");
+
+    /* Now allow networking. Evaluation should succeed after fetching
+     * the intermediate. */
+    ok_status(SecTrustSetNetworkFetchAllowed(trust, true), "set allow network");
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
+    is_status(trustResult, kSecTrustResultUnspecified,
+       "trust is kSecTrustResultUnspecified");
+    CFReleaseNull(trust);
+
+    /* Common variable cleanup. */
+    CFReleaseSafe(sslPolicy);
+    CFReleaseSafe(revPolicy);
+    CFReleaseSafe(certs);
+    CFReleaseSafe(policies);
+    CFReleaseSafe(comodo_aia);
+    CFReleaseSafe(comodo_ev);
+    CFReleaseSafe(ovh);
+    CFReleaseSafe(verifyDate);
+}
+
+- (void) test_aia_https {
+    SecCertificateRef leaf = NULL;
+    SecPolicyRef policy = NULL;
+    SecTrustRef trust = NULL;
+    CFArrayRef certs = NULL;
+    CFDateRef verifyDate = NULL;
+    CFErrorRef error = NULL;
+
+    leaf = SecCertificateCreateWithBytes(NULL, _caissuer_https, sizeof(_caissuer_https));
+    const void *v_certs[] = { leaf };
+
+    certs = CFArrayCreate(NULL, v_certs, 1, &kCFTypeArrayCallBacks);
+    policy = SecPolicyCreateSSL(true, CFSTR("example.com"));
+    require_noerr_action(SecTrustCreateWithCertificates(certs, policy, &trust), errOut, fail("failed to create trust object"));
+
+    verifyDate = CFDateCreate(NULL, 546700000.0); // April 29, 2018 at 6:06:40 AM PDT
+    require_noerr_action(SecTrustSetVerifyDate(trust, verifyDate), errOut, fail("failed to set verify date"));
+
+    /* Evaluate trust. This cert does not chain to anything trusted and we can't fetch an
+     * intermediate because the URI is https. */
+    is(SecTrustEvaluateWithError(trust, &error), false, "leaf with missing intermediate and https CAIssuer URI succeeded");
+    if (error) {
+        is(CFErrorGetCode(error), errSecCreateChainFailed, "got wrong error code for revoked cert, got %ld, expected %d",
+           (long)CFErrorGetCode(error), errSecCreateChainFailed);
+    } else {
+        fail("expected trust evaluation to fail and it did not.");
+    }
+
+errOut:
+    CFReleaseNull(leaf);
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+    CFReleaseNull(certs);
+    CFReleaseNull(verifyDate);
+    CFReleaseNull(error);
+}
+#else /* TARGET_OS_WATCH || TARGET_OS_BRIDGE */
+- (void) testNoNetworking
+{
+    SecCertificateRef ovh = NULL, comodo_ev = NULL, comodo_aia = NULL;
+    CFMutableArrayRef certs = NULL, policies = NULL;
+    SecPolicyRef sslPolicy = NULL, revPolicy = NULL;
+    CFDateRef verifyDate = NULL;
+    SecTrustRef trust = NULL;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
+
+    /* Initialize common variables */
+    isnt(ovh = SecCertificateCreateWithBytes(NULL, ovh_certificate,
+        sizeof(ovh_certificate)), NULL, "create ovh cert");
+    isnt(comodo_ev = SecCertificateCreateWithBytes(NULL, comodo_ev_certificate,
+        sizeof(comodo_ev_certificate)), NULL, "create comodo_ev cert");
+    isnt(comodo_aia = SecCertificateCreateWithBytes(NULL,
+        comodo_aia_certificate, sizeof(comodo_aia_certificate)), NULL,
+        "create comodo_aia cert");
+    certs = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+        &kCFTypeArrayCallBacks);
+    policies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+        &kCFTypeArrayCallBacks);
+    sslPolicy = SecPolicyCreateSSL(false, NULL); // For now, use SSL client policy to avoid SHA-1 deprecation
+    revPolicy = SecPolicyCreateRevocation(kSecRevocationUseAnyAvailableMethod);
+    CFArrayAppendValue(policies, sslPolicy);
+    CFArrayAppendValue(policies, revPolicy);
+    /* May 9th 2018. */
+    verifyDate = CFDateCreate(NULL, 547600500);
+
+    /* Evaluation should fail because it couldn't get the intermediate. */
+    CFArrayAppendValue(certs, ovh);
+    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust),
+              "create trust");
+    ok_status(SecTrustSetVerifyDate(trust, verifyDate), "set date");
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
+    is_status(trustResult, kSecTrustResultRecoverableTrustFailure,
+       "trust is kSecTrustResultRecoverableTrustFailure");
+
+    /* Common variable cleanup. */
+    CFReleaseSafe(sslPolicy);
+    CFReleaseSafe(revPolicy);
+    CFReleaseSafe(certs);
+    CFReleaseSafe(policies);
+    CFReleaseSafe(comodo_aia);
+    CFReleaseSafe(comodo_ev);
+    CFReleaseSafe(ovh);
+    CFReleaseSafe(verifyDate);
+}
+#endif
+
+@end
diff --git a/tests/TrustTests/EvaluationTests/CAIssuerTests_data.h b/tests/TrustTests/EvaluationTests/CAIssuerTests_data.h
new file mode 100644 (file)
index 0000000..5ccd431
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+* Copyright (c) 2006-2019 Apple Inc. All Rights Reserved.
+*/
+
+#ifndef _TRUSTTESTS_CA_ISSUER_TESTS_H_
+#define _TRUSTTESTS_CA_ISSUER_TESTS_H_
+
+/* subject:/serialNumber=424761419/jurisdictionC=FR/businessCategory=Private Organization/C=FR/postalCode=59100/ST=Nord/L=Roubaix/street=2 rue Kellermann/O=OVH SAS/OU=IT/OU=COMODO EV SSL/CN=ovh.com */
+/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
+static unsigned char ovh_certificate[1884]={
+    0x30,0x82,0x07,0x58,0x30,0x82,0x06,0x40,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x40,
+    0x46,0x47,0xDC,0xC2,0x4B,0x04,0x42,0xD4,0x89,0x8D,0x08,0x4D,0x4B,0xC2,0x01,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,
+    0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
+    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
+    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
+    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
+    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,
+    0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,
+    0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,
+    0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x34,0x32,0x38,0x30,0x30,0x30,
+    0x30,0x30,0x30,0x5A,0x17,0x0D,0x31,0x39,0x30,0x34,0x32,0x38,0x32,0x33,0x35,0x39,
+    0x35,0x39,0x5A,0x30,0x81,0xEA,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x05,0x13,
+    0x09,0x34,0x32,0x34,0x37,0x36,0x31,0x34,0x31,0x39,0x31,0x13,0x30,0x11,0x06,0x0B,
+    0x2B,0x06,0x01,0x04,0x01,0x82,0x37,0x3C,0x02,0x01,0x03,0x13,0x02,0x46,0x52,0x31,
+    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0F,0x13,0x14,0x50,0x72,0x69,0x76,0x61,0x74,
+    0x65,0x20,0x4F,0x72,0x67,0x61,0x6E,0x69,0x7A,0x61,0x74,0x69,0x6F,0x6E,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x46,0x52,0x31,0x0E,0x30,0x0C,0x06,
+    0x03,0x55,0x04,0x11,0x13,0x05,0x35,0x39,0x31,0x30,0x30,0x31,0x0D,0x30,0x0B,0x06,
+    0x03,0x55,0x04,0x08,0x13,0x04,0x4E,0x6F,0x72,0x64,0x31,0x10,0x30,0x0E,0x06,0x03,
+    0x55,0x04,0x07,0x13,0x07,0x52,0x6F,0x75,0x62,0x61,0x69,0x78,0x31,0x19,0x30,0x17,
+    0x06,0x03,0x55,0x04,0x09,0x13,0x10,0x32,0x20,0x72,0x75,0x65,0x20,0x4B,0x65,0x6C,
+    0x6C,0x65,0x72,0x6D,0x61,0x6E,0x6E,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x0A,
+    0x13,0x07,0x4F,0x56,0x48,0x20,0x53,0x41,0x53,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x0B,0x13,0x02,0x49,0x54,0x31,0x16,0x30,0x14,0x06,0x03,0x55,0x04,0x0B,0x13,
+    0x0D,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x45,0x56,0x20,0x53,0x53,0x4C,0x31,0x10,
+    0x30,0x0E,0x06,0x03,0x55,0x04,0x03,0x13,0x07,0x6F,0x76,0x68,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,0x93,0xA1,0x5D,0x05,0x5F,0x1A,0x26,0x56,0x3D,0xDC,0xC2,0x7C,0x1B,0xA1,0x7A,
+    0x63,0x16,0x4F,0xBD,0xE0,0x77,0x85,0x04,0xB0,0x9B,0x49,0xE9,0x2B,0x5C,0xB1,0x51,
+    0xFD,0x8A,0x14,0x51,0xC7,0xD9,0x50,0xDE,0x64,0x2F,0xFE,0x8C,0x27,0xC3,0x01,0x48,
+    0x64,0x7C,0x85,0x3F,0x93,0xD4,0x09,0xE6,0x42,0xDF,0xC1,0xE4,0xEB,0x6A,0xC0,0x87,
+    0x90,0xA5,0xF6,0x9C,0xD4,0x6B,0x08,0x77,0xFB,0x56,0x44,0x2B,0x8A,0xE0,0x05,0x73,
+    0x14,0x6B,0x02,0x7D,0x76,0x44,0x7B,0x3E,0xA6,0xE5,0x23,0xA9,0xE1,0x8F,0x99,0xDD,
+    0x15,0xCD,0xD9,0xD9,0x6D,0xB9,0x95,0x5B,0xE8,0xB6,0xE2,0x52,0xDD,0xF0,0xB0,0x80,
+    0x1B,0xC1,0x95,0x4B,0x2C,0x9D,0x5E,0x8D,0x02,0x6B,0x59,0x6C,0x26,0x8B,0xC3,0x19,
+    0x0D,0x3E,0xA8,0x34,0xD0,0x43,0x81,0xD7,0xBD,0xB3,0xA7,0x04,0xE1,0x05,0x82,0xA6,
+    0x1F,0x4D,0x70,0x67,0x05,0x96,0x88,0xE8,0xE9,0x2E,0x95,0xD2,0x36,0x75,0xD6,0xC8,
+    0x0C,0x59,0xBF,0x9F,0x1F,0x9F,0xB4,0xFF,0xF0,0x10,0x8C,0xC3,0xE6,0x8B,0x9F,0xE2,
+    0x8E,0x00,0x60,0x58,0xCB,0x6F,0xAD,0x84,0x7B,0xA5,0x36,0xDB,0xB2,0xA4,0xEB,0xC6,
+    0xC8,0xD8,0x61,0x6E,0x4A,0xDC,0x5C,0x3E,0x2C,0x33,0xCB,0x1E,0x16,0x8B,0x8C,0xA3,
+    0x5F,0x0F,0x30,0x4E,0x0A,0x5D,0xA0,0x53,0x7C,0xCE,0xAB,0x29,0x9A,0xC6,0x64,0xC5,
+    0x5A,0xD7,0x94,0x3D,0x81,0xB1,0x05,0x3F,0x2A,0x6D,0xD7,0xB8,0x9D,0xF1,0x6D,0x13,
+    0xFD,0x82,0xB4,0xF9,0x88,0x77,0xAB,0xB8,0x2C,0x7A,0x81,0x6E,0x68,0xFF,0x6E,0x04,
+    0xC1,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,0x03,0x4E,0x30,0x82,0x03,0x4A,0x30,0x1F,
+    0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x39,0xDA,0xFF,0xCA,0x28,
+    0x14,0x8A,0xA8,0x74,0x13,0x08,0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,
+    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x0B,0x0F,0xAD,0xA6,0xC3,0xBF,
+    0x98,0xA1,0xEC,0xCD,0x20,0xB3,0x2C,0x75,0x03,0x56,0x3A,0xA6,0xD3,0xE6,0x30,0x0E,
+    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x0C,
+    0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,
+    0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x46,0x06,0x03,0x55,
+    0x1D,0x20,0x04,0x3F,0x30,0x3D,0x30,0x3B,0x06,0x0C,0x2B,0x06,0x01,0x04,0x01,0xB2,
+    0x31,0x01,0x02,0x01,0x05,0x01,0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x02,0x01,0x16,0x1D,0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,
+    0x63,0x75,0x72,0x65,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,
+    0x43,0x50,0x53,0x30,0x56,0x06,0x03,0x55,0x1D,0x1F,0x04,0x4F,0x30,0x4D,0x30,0x4B,
+    0xA0,0x49,0xA0,0x47,0x86,0x45,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,
+    0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,
+    0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x56,
+    0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x53,0x65,0x63,0x75,0x72,0x65,0x53,
+    0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,0x6C,0x30,0x81,0x87,0x06,0x08,
+    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x7B,0x30,0x79,0x30,0x51,0x06,0x08,
+    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x45,0x68,0x74,0x74,0x70,0x3A,0x2F,
+    0x2F,0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,
+    0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x45,0x78,0x74,0x65,0x6E,
+    0x64,0x65,0x64,0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x53,0x65,0x63,
+    0x75,0x72,0x65,0x53,0x65,0x72,0x76,0x65,0x72,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,
+    0x24,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,
+    0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,
+    0x61,0x2E,0x63,0x6F,0x6D,0x30,0x1F,0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,
+    0x82,0x07,0x6F,0x76,0x68,0x2E,0x63,0x6F,0x6D,0x82,0x0B,0x77,0x77,0x77,0x2E,0x6F,
+    0x76,0x68,0x2E,0x63,0x6F,0x6D,0x30,0x82,0x01,0x7E,0x06,0x0A,0x2B,0x06,0x01,0x04,
+    0x01,0xD6,0x79,0x02,0x04,0x02,0x04,0x82,0x01,0x6E,0x04,0x82,0x01,0x6A,0x01,0x68,
+    0x00,0x76,0x00,0xA4,0xB9,0x09,0x90,0xB4,0x18,0x58,0x14,0x87,0xBB,0x13,0xA2,0xCC,
+    0x67,0x70,0x0A,0x3C,0x35,0x98,0x04,0xF9,0x1B,0xDF,0xB8,0xE3,0x77,0xCD,0x0E,0xC8,
+    0x0D,0xDC,0x10,0x00,0x00,0x01,0x5B,0xB5,0x7B,0xC8,0x2D,0x00,0x00,0x04,0x03,0x00,
+    0x47,0x30,0x45,0x02,0x21,0x00,0xD5,0x1B,0x6C,0xAE,0x75,0x46,0x62,0x0C,0x8B,0x2E,
+    0x14,0xB1,0xDE,0x7C,0xA5,0xFE,0x5C,0x4F,0x3E,0xB0,0xFF,0xFF,0x33,0xA2,0x84,0x58,
+    0x51,0x57,0x97,0x09,0xAF,0x09,0x02,0x20,0x49,0xD7,0x12,0x12,0x6C,0x2A,0x00,0x21,
+    0x5E,0x48,0xF8,0xD0,0xF2,0xA5,0x81,0x2A,0x4E,0xE9,0x22,0x0A,0x4E,0x46,0x8F,0xDB,
+    0xA5,0x9C,0x4B,0x43,0x7E,0x51,0x24,0xE4,0x00,0x76,0x00,0x56,0x14,0x06,0x9A,0x2F,
+    0xD7,0xC2,0xEC,0xD3,0xF5,0xE1,0xBD,0x44,0xB2,0x3E,0xC7,0x46,0x76,0xB9,0xBC,0x99,
+    0x11,0x5C,0xC0,0xEF,0x94,0x98,0x55,0xD6,0x89,0xD0,0xDD,0x00,0x00,0x01,0x5B,0xB5,
+    0x7B,0xC5,0xC8,0x00,0x00,0x04,0x03,0x00,0x47,0x30,0x45,0x02,0x20,0x36,0xA9,0x1D,
+    0x52,0x63,0x04,0x11,0x1F,0x65,0xC6,0x97,0x7C,0x17,0xFC,0x17,0x8D,0xDB,0x9D,0xA7,
+    0xB7,0x84,0x66,0x03,0x55,0x95,0x7D,0x42,0x39,0x98,0x60,0xDE,0x19,0x02,0x21,0x00,
+    0x8B,0xB7,0x16,0xC0,0x20,0x17,0xBF,0x31,0x36,0xBD,0xBC,0x1C,0x12,0x61,0x42,0xC0,
+    0x5C,0x19,0x97,0x0A,0xFA,0x85,0xDB,0x5D,0xC3,0x65,0xBE,0x18,0xBF,0x89,0x6F,0xB9,
+    0x00,0x76,0x00,0xEE,0x4B,0xBD,0xB7,0x75,0xCE,0x60,0xBA,0xE1,0x42,0x69,0x1F,0xAB,
+    0xE1,0x9E,0x66,0xA3,0x0F,0x7E,0x5F,0xB0,0x72,0xD8,0x83,0x00,0xC4,0x7B,0x89,0x7A,
+    0xA8,0xFD,0xCB,0x00,0x00,0x01,0x5B,0xB5,0x7B,0xC7,0xFA,0x00,0x00,0x04,0x03,0x00,
+    0x47,0x30,0x45,0x02,0x21,0x00,0xF8,0xFE,0x02,0xC9,0xAF,0x02,0x18,0xF4,0x12,0x00,
+    0x39,0x3C,0x15,0xE0,0x9C,0x78,0x04,0x19,0x55,0xAE,0x8F,0xB4,0x22,0xB9,0x08,0x66,
+    0x9E,0x21,0x3E,0xF0,0x7D,0xC6,0x02,0x20,0x47,0x45,0x31,0xC7,0x2C,0xC3,0xBE,0xC7,
+    0x5B,0xD8,0x31,0x0A,0xD6,0xAF,0x9D,0xAF,0x04,0x45,0xAA,0x51,0x7D,0x43,0xEF,0x35,
+    0x4D,0x81,0xB3,0x0A,0x2F,0x8D,0xD8,0x61,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x6C,0x8E,0xB5,0x58,
+    0x8A,0xC5,0x66,0xAC,0x99,0x68,0xF9,0x80,0x68,0x8E,0xC5,0x10,0xF7,0xD7,0x37,0x5E,
+    0x09,0x8C,0x6B,0xCF,0x30,0x2B,0x98,0x3F,0x76,0x4D,0x69,0xBA,0xE8,0x61,0x1D,0xDE,
+    0x1A,0x14,0x4F,0x5A,0x0B,0x54,0x0F,0x66,0xEF,0xB9,0xB3,0x51,0x6C,0x9B,0x86,0x1D,
+    0xB9,0x13,0xC8,0x54,0x24,0x6C,0x82,0x6E,0x4B,0x3C,0x53,0xC7,0x7D,0x0B,0x40,0x4A,
+    0x7E,0x23,0xF2,0x79,0x6B,0xC3,0xFF,0x9D,0xDF,0xC0,0x16,0x7B,0xFF,0x7B,0x04,0xC9,
+    0xE0,0xEB,0x3F,0x28,0xC6,0xD2,0x79,0xEE,0xAE,0x7E,0x38,0x5F,0x0D,0xDF,0x71,0xE7,
+    0xAA,0x38,0x7E,0xF3,0x28,0xE8,0xB2,0xAC,0x69,0xB9,0x69,0xD4,0x05,0x8E,0xF1,0x00,
+    0x71,0x77,0x97,0x7F,0x94,0x36,0x45,0xE5,0x9C,0x15,0xA3,0xF1,0x40,0xD7,0xB5,0xEA,
+    0x95,0x56,0x75,0x60,0x86,0xFB,0xCD,0xB7,0x81,0x5A,0x34,0x1A,0x83,0x1E,0xC2,0x50,
+    0xA2,0x57,0x16,0x13,0x53,0x95,0xFA,0x95,0xD0,0x64,0x1E,0x09,0x45,0x50,0x05,0x63,
+    0x3A,0x86,0xB2,0x1D,0x9B,0x19,0x0E,0x89,0x7E,0x75,0x17,0xDA,0xC5,0x4D,0x4F,0x71,
+    0x55,0x82,0x3E,0x5F,0x41,0x25,0x2F,0x86,0x9E,0x3D,0xF1,0x32,0xFA,0x77,0x7C,0x30,
+    0x6C,0x50,0x2F,0xE7,0x11,0x7B,0xE1,0x3F,0xA8,0x2E,0xEF,0xAC,0x36,0x94,0x8F,0xF0,
+    0x92,0xB4,0xCA,0x1A,0x53,0x8E,0x12,0x26,0x48,0xC4,0xA8,0x25,0x19,0x96,0x19,0x11,
+    0xA2,0xA2,0x48,0xEB,0x8C,0x12,0x59,0x7F,0xCE,0xFC,0x4B,0xC9,0x19,0x10,0x61,0x2B,
+    0xB3,0xA6,0x6B,0xB4,0xBA,0x68,0xB9,0x22,0x58,0xE4,0x82,0x27,
+};
+
+/* This is the cert the ssl server returns to us. */
+/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
+/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */
+static unsigned char comodo_ev_certificate[1554]={
+    0x30,0x82,0x06,0x0E,0x30,0x82,0x03,0xF6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x06,
+    0xA7,0x43,0x80,0xD4,0xEB,0xFE,0xD4,0x35,0xB5,0xA3,0xF7,0xE1,0x6A,0xBD,0xD8,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81,
+    0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
+    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
+    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
+    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
+    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,
+    0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,
+    0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x32,0x30,0x32,0x31,0x32,
+    0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x32,0x31,0x31,0x32,
+    0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,
+    0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,
+    0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,
+    0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,
+    0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,
+    0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,
+    0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,
+    0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,
+    0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,
+    0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x95,0x56,0xDE,0x54,
+    0xB4,0xDF,0xD5,0x02,0x49,0x7B,0xD1,0x5B,0x5C,0xA2,0xB2,0x1E,0x8F,0x9C,0x2B,0x62,
+    0x4C,0x2B,0x8D,0x12,0x28,0xF3,0x1A,0x95,0xA3,0xC6,0x10,0xFD,0x29,0xDE,0xE1,0x9F,
+    0x0B,0x38,0x40,0x93,0xD1,0xEF,0x6E,0x95,0x10,0xFC,0xE1,0x90,0x17,0x77,0x2C,0xEE,
+    0x75,0x3E,0x7B,0x63,0xEC,0x61,0x92,0x6E,0x4F,0x3B,0xAB,0x80,0x49,0x6B,0xDF,0x00,
+    0xEA,0x03,0x00,0x7F,0x2F,0x75,0xD5,0x28,0x2F,0xEC,0x56,0x67,0x8F,0x80,0x83,0xA3,
+    0xBD,0xDC,0x03,0x99,0x93,0x8B,0x94,0x91,0x56,0x5B,0xA1,0xB8,0x6A,0x3A,0x3F,0x06,
+    0xBD,0x0E,0x92,0xCC,0x60,0x9C,0xFD,0xB5,0xE0,0x9F,0x66,0x30,0x5F,0xDB,0xE6,0x94,
+    0xF0,0x95,0x6A,0xAF,0xC8,0x8A,0xAF,0x80,0xD9,0xE6,0x88,0x39,0x01,0x7C,0x1C,0xC0,
+    0xC5,0x2A,0xF7,0x7B,0x95,0xA0,0xF2,0x76,0xAB,0x6D,0x9B,0x72,0x39,0x30,0xEB,0xD1,
+    0x57,0x55,0x01,0x9D,0x58,0x11,0x9D,0x7C,0x6D,0x84,0x8F,0x49,0xE8,0x9D,0x09,0xFC,
+    0x3C,0xFD,0x0A,0x4A,0x76,0x14,0x21,0x5C,0x16,0x73,0x40,0x23,0x19,0x74,0xC3,0xBA,
+    0x58,0x0A,0xA6,0x96,0x2E,0xDE,0x36,0xE5,0x9F,0xD0,0xC2,0xF0,0xE1,0xE0,0xC1,0x62,
+    0xE3,0xC2,0x18,0x45,0x19,0x51,0xAA,0x17,0x1E,0xE8,0x23,0x75,0xD4,0xC8,0xD0,0x96,
+    0x13,0xFF,0xC7,0x24,0xD1,0x8C,0x0B,0x27,0xAE,0x9E,0x7A,0xDC,0x3A,0x61,0x63,0x60,
+    0x88,0x97,0x2D,0x5D,0x05,0x0B,0xE5,0x3B,0xEB,0xAE,0xCE,0x3A,0x47,0x73,0x76,0xA8,
+    0xFA,0x2C,0xDD,0xC0,0x87,0x17,0xE9,0xAC,0x30,0x99,0xF8,0x1F,0x02,0x03,0x01,0x00,
+    0x01,0xA3,0x82,0x01,0x69,0x30,0x82,0x01,0x65,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
+    0x04,0x18,0x30,0x16,0x80,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,
+    0x8E,0xAD,0xEE,0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,
+    0x0E,0x04,0x16,0x04,0x14,0x39,0xDA,0xFF,0xCA,0x28,0x14,0x8A,0xA8,0x74,0x13,0x08,
+    0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
+    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
+    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x3E,0x06,
+    0x03,0x55,0x1D,0x20,0x04,0x37,0x30,0x35,0x30,0x33,0x06,0x04,0x55,0x1D,0x20,0x00,
+    0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1D,
+    0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,0x63,0x75,0x72,0x65,0x2E,0x63,
+    0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x4C,0x06,
+    0x03,0x55,0x1D,0x1F,0x04,0x45,0x30,0x43,0x30,0x41,0xA0,0x3F,0xA0,0x3D,0x86,0x3B,
+    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,
+    0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,
+    0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,
+    0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x71,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3B,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2F,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,
+    0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,
+    0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x41,0x64,0x64,0x54,0x72,0x75,
+    0x73,0x74,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,
+    0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x0D,
+    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,
+    0x01,0x00,0x44,0x42,0x9D,0x41,0x51,0x2B,0x48,0x88,0x5D,0x97,0x9B,0x79,0x5E,0x11,
+    0x01,0x4A,0x52,0x19,0x7B,0x41,0x2C,0xC7,0x89,0x3C,0xD0,0x72,0xDC,0x85,0xFA,0x58,
+    0xAF,0xD5,0x25,0xE4,0x13,0xF8,0x58,0x65,0x67,0x9F,0x0D,0xFF,0x57,0x8B,0xA9,0x85,
+    0x5E,0xCA,0xA6,0x4B,0xB0,0xA7,0xB2,0x2D,0xE0,0x8C,0x22,0xCD,0xFB,0xFF,0x79,0xA4,
+    0x8C,0x2B,0x8D,0xFE,0x02,0x3D,0x24,0xDE,0xA9,0x5D,0x5F,0xE4,0x0F,0x47,0xD0,0xDB,
+    0x66,0x25,0x3E,0x87,0x47,0x0C,0xAE,0x22,0xC5,0x50,0x22,0x84,0xD7,0xED,0x4A,0x59,
+    0x1A,0xF6,0x93,0xA5,0x93,0xB0,0xE0,0x1B,0x81,0xF2,0x56,0xC4,0xC8,0x10,0x53,0xE4,
+    0xD4,0x76,0xB1,0xD1,0x5B,0x69,0x4B,0x77,0xB2,0xE0,0x4F,0xC4,0x84,0xE7,0xD4,0xA0,
+    0x50,0xEE,0x3C,0xFA,0x44,0xFC,0xD0,0x57,0xB9,0xE1,0x28,0x53,0xFD,0x53,0xCD,0xDC,
+    0xB9,0x1F,0x7A,0x40,0xBD,0x30,0x3F,0xD8,0x6C,0xD2,0xF3,0xE7,0x07,0x9F,0x1F,0x22,
+    0xB5,0xEA,0x22,0x71,0xCB,0x2A,0xF0,0x56,0x7C,0xFE,0xAC,0xA8,0xD1,0x06,0x0F,0x14,
+    0x14,0x52,0x4C,0xFE,0x64,0x2B,0x0C,0x69,0x2A,0xB8,0x0D,0x50,0x6E,0x3E,0x04,0x07,
+    0xBF,0x7A,0x20,0x8B,0xF8,0xEE,0x65,0x09,0xE1,0xC7,0x49,0x08,0x32,0x3D,0x0D,0x28,
+    0x7E,0x49,0x1D,0xB7,0x4A,0xEF,0x02,0xE7,0x0D,0x80,0x17,0xC8,0x5C,0xE0,0x61,0x62,
+    0xCB,0xEC,0xB3,0x60,0x79,0x25,0xDA,0x1A,0x65,0x73,0x9C,0x38,0x10,0xA0,0x26,0x3A,
+    0xB0,0xC8,0x16,0x7D,0x93,0x31,0x22,0xEE,0x74,0x0B,0x88,0xC0,0x5C,0x89,0x41,0x00,
+    0x28,0xA9,0x47,0x31,0xDF,0x7D,0x49,0x45,0x9A,0xF5,0xE6,0xA7,0x45,0x1A,0xD2,0x8E,
+    0x13,0x10,0xDF,0x83,0xAF,0x9B,0x0D,0xAD,0x7E,0x7E,0x9D,0x35,0x50,0x34,0x04,0xCE,
+    0xE9,0x20,0xD6,0x9E,0xDB,0x9D,0xD4,0xA8,0xDA,0x64,0xB4,0xD1,0x2F,0x59,0x2E,0x5E,
+    0xA2,0x36,0x61,0xD4,0x24,0xA0,0x82,0x33,0x33,0x8A,0xA1,0xD1,0x6C,0xEF,0x61,0x68,
+    0xA3,0xE5,0xD2,0x56,0xAD,0xC5,0xFD,0x5E,0x62,0xEB,0x15,0xA8,0x74,0x12,0x4C,0x2F,
+    0x31,0x8C,0xE9,0xC1,0xDF,0x10,0x4B,0x01,0xEA,0xF6,0x54,0x1B,0xCD,0x7F,0x3B,0xBD,
+    0x5C,0x9F,0xC1,0xDB,0xCF,0x01,0xCA,0xF2,0xBA,0x60,0x12,0x21,0x31,0xED,0xA9,0x64,
+    0xB8,0xB2,0x49,0x58,0x17,0x6D,0x5A,0xD7,0xCD,0x8C,0x6D,0xBE,0x9E,0x7F,0xE2,0x02,
+    0x58,0xA7,0xDB,0xC3,0x2D,0x58,0xF6,0x74,0x06,0x6A,0x9A,0xF6,0x61,0xF9,0xF6,0x00,
+    0xB6,0x69,0xD8,0x3A,0x8B,0x31,0x59,0xDD,0x91,0xE6,0x7C,0x27,0x23,0x87,0xDD,0x03,
+    0x0F,0x8F,0x2A,0x8C,0x1E,0x83,0x01,0x4E,0x01,0x61,0x0C,0x52,0x73,0x6D,0xFC,0x08,
+    0xA2,0xB9,0x2A,0x66,0xE4,0x76,0x4D,0x31,0xA0,0x56,0x9B,0xD9,0x53,0x8D,0xA2,0xB6,
+    0x8F,0x02,0xC8,0xE6,0x3A,0xA6,0x04,0xD1,0x48,0xFB,0xC3,0x4A,0x02,0x76,0xFD,0x2F,
+    0xD2,0xBC,0x13,0xB6,0xE8,0x6D,0x34,0x24,0xFA,0x9D,0x29,0x8A,0xC7,0xA1,0x2B,0x14,
+    0xF1,0x96,0x00,0x73,0xB9,0x13,0xE9,0xC0,0xB9,0x3A,0x47,0x56,0x02,0x71,0x80,0x27,
+    0xA4,0xBC,0x25,0xB6,0xE9,0xBD,0xE4,0xE9,0x98,0x74,0x16,0xF1,0x37,0x84,0x81,0x07,
+    0xB4,0x82,
+};
+
+/* This is the cert we get when we get the url in the AIA extension of the ovh leaf. */
+/* subject:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Extended Validation Secure Server CA */
+/* issuer :/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority */
+static unsigned char comodo_aia_certificate[1554]={
+    0x30,0x82,0x06,0x0E,0x30,0x82,0x03,0xF6,0xA0,0x03,0x02,0x01,0x02,0x02,0x10,0x06,
+    0xA7,0x43,0x80,0xD4,0xEB,0xFE,0xD4,0x35,0xB5,0xA3,0xF7,0xE1,0x6A,0xBD,0xD8,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x30,0x81,
+    0x85,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,
+    0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,
+    0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,
+    0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,
+    0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,
+    0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,0x64,0x31,0x2B,0x30,0x29,0x06,0x03,0x55,
+    0x04,0x03,0x13,0x22,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x43,
+    0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,
+    0x68,0x6F,0x72,0x69,0x74,0x79,0x30,0x1E,0x17,0x0D,0x31,0x32,0x30,0x32,0x31,0x32,
+    0x30,0x30,0x30,0x30,0x30,0x30,0x5A,0x17,0x0D,0x32,0x37,0x30,0x32,0x31,0x31,0x32,
+    0x33,0x35,0x39,0x35,0x39,0x5A,0x30,0x81,0x92,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x47,0x42,0x31,0x1B,0x30,0x19,0x06,0x03,0x55,0x04,0x08,0x13,
+    0x12,0x47,0x72,0x65,0x61,0x74,0x65,0x72,0x20,0x4D,0x61,0x6E,0x63,0x68,0x65,0x73,
+    0x74,0x65,0x72,0x31,0x10,0x30,0x0E,0x06,0x03,0x55,0x04,0x07,0x13,0x07,0x53,0x61,
+    0x6C,0x66,0x6F,0x72,0x64,0x31,0x1A,0x30,0x18,0x06,0x03,0x55,0x04,0x0A,0x13,0x11,
+    0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x20,0x43,0x41,0x20,0x4C,0x69,0x6D,0x69,0x74,0x65,
+    0x64,0x31,0x38,0x30,0x36,0x06,0x03,0x55,0x04,0x03,0x13,0x2F,0x43,0x4F,0x4D,0x4F,
+    0x44,0x4F,0x20,0x52,0x53,0x41,0x20,0x45,0x78,0x74,0x65,0x6E,0x64,0x65,0x64,0x20,
+    0x56,0x61,0x6C,0x69,0x64,0x61,0x74,0x69,0x6F,0x6E,0x20,0x53,0x65,0x63,0x75,0x72,
+    0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,
+    0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0x95,0x56,0xDE,0x54,
+    0xB4,0xDF,0xD5,0x02,0x49,0x7B,0xD1,0x5B,0x5C,0xA2,0xB2,0x1E,0x8F,0x9C,0x2B,0x62,
+    0x4C,0x2B,0x8D,0x12,0x28,0xF3,0x1A,0x95,0xA3,0xC6,0x10,0xFD,0x29,0xDE,0xE1,0x9F,
+    0x0B,0x38,0x40,0x93,0xD1,0xEF,0x6E,0x95,0x10,0xFC,0xE1,0x90,0x17,0x77,0x2C,0xEE,
+    0x75,0x3E,0x7B,0x63,0xEC,0x61,0x92,0x6E,0x4F,0x3B,0xAB,0x80,0x49,0x6B,0xDF,0x00,
+    0xEA,0x03,0x00,0x7F,0x2F,0x75,0xD5,0x28,0x2F,0xEC,0x56,0x67,0x8F,0x80,0x83,0xA3,
+    0xBD,0xDC,0x03,0x99,0x93,0x8B,0x94,0x91,0x56,0x5B,0xA1,0xB8,0x6A,0x3A,0x3F,0x06,
+    0xBD,0x0E,0x92,0xCC,0x60,0x9C,0xFD,0xB5,0xE0,0x9F,0x66,0x30,0x5F,0xDB,0xE6,0x94,
+    0xF0,0x95,0x6A,0xAF,0xC8,0x8A,0xAF,0x80,0xD9,0xE6,0x88,0x39,0x01,0x7C,0x1C,0xC0,
+    0xC5,0x2A,0xF7,0x7B,0x95,0xA0,0xF2,0x76,0xAB,0x6D,0x9B,0x72,0x39,0x30,0xEB,0xD1,
+    0x57,0x55,0x01,0x9D,0x58,0x11,0x9D,0x7C,0x6D,0x84,0x8F,0x49,0xE8,0x9D,0x09,0xFC,
+    0x3C,0xFD,0x0A,0x4A,0x76,0x14,0x21,0x5C,0x16,0x73,0x40,0x23,0x19,0x74,0xC3,0xBA,
+    0x58,0x0A,0xA6,0x96,0x2E,0xDE,0x36,0xE5,0x9F,0xD0,0xC2,0xF0,0xE1,0xE0,0xC1,0x62,
+    0xE3,0xC2,0x18,0x45,0x19,0x51,0xAA,0x17,0x1E,0xE8,0x23,0x75,0xD4,0xC8,0xD0,0x96,
+    0x13,0xFF,0xC7,0x24,0xD1,0x8C,0x0B,0x27,0xAE,0x9E,0x7A,0xDC,0x3A,0x61,0x63,0x60,
+    0x88,0x97,0x2D,0x5D,0x05,0x0B,0xE5,0x3B,0xEB,0xAE,0xCE,0x3A,0x47,0x73,0x76,0xA8,
+    0xFA,0x2C,0xDD,0xC0,0x87,0x17,0xE9,0xAC,0x30,0x99,0xF8,0x1F,0x02,0x03,0x01,0x00,
+    0x01,0xA3,0x82,0x01,0x69,0x30,0x82,0x01,0x65,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
+    0x04,0x18,0x30,0x16,0x80,0x14,0xBB,0xAF,0x7E,0x02,0x3D,0xFA,0xA6,0xF1,0x3C,0x84,
+    0x8E,0xAD,0xEE,0x38,0x98,0xEC,0xD9,0x32,0x32,0xD4,0x30,0x1D,0x06,0x03,0x55,0x1D,
+    0x0E,0x04,0x16,0x04,0x14,0x39,0xDA,0xFF,0xCA,0x28,0x14,0x8A,0xA8,0x74,0x13,0x08,
+    0xB9,0xE4,0x0E,0xA9,0xD2,0xFA,0x7E,0x9D,0x69,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,
+    0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
+    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x3E,0x06,
+    0x03,0x55,0x1D,0x20,0x04,0x37,0x30,0x35,0x30,0x33,0x06,0x04,0x55,0x1D,0x20,0x00,
+    0x30,0x2B,0x30,0x29,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x1D,
+    0x68,0x74,0x74,0x70,0x73,0x3A,0x2F,0x2F,0x73,0x65,0x63,0x75,0x72,0x65,0x2E,0x63,
+    0x6F,0x6D,0x6F,0x64,0x6F,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x50,0x53,0x30,0x4C,0x06,
+    0x03,0x55,0x1D,0x1F,0x04,0x45,0x30,0x43,0x30,0x41,0xA0,0x3F,0xA0,0x3D,0x86,0x3B,
+    0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x63,0x6F,0x6D,0x6F,0x64,
+    0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,
+    0x41,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x41,0x75,
+    0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x2E,0x63,0x72,0x6C,0x30,0x71,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x65,0x30,0x63,0x30,0x3B,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x2F,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,
+    0x63,0x72,0x74,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,
+    0x2F,0x43,0x4F,0x4D,0x4F,0x44,0x4F,0x52,0x53,0x41,0x41,0x64,0x64,0x54,0x72,0x75,
+    0x73,0x74,0x43,0x41,0x2E,0x63,0x72,0x74,0x30,0x24,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x30,0x01,0x86,0x18,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,
+    0x70,0x2E,0x63,0x6F,0x6D,0x6F,0x64,0x6F,0x63,0x61,0x2E,0x63,0x6F,0x6D,0x30,0x0D,
+    0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0C,0x05,0x00,0x03,0x82,0x02,
+    0x01,0x00,0x44,0x42,0x9D,0x41,0x51,0x2B,0x48,0x88,0x5D,0x97,0x9B,0x79,0x5E,0x11,
+    0x01,0x4A,0x52,0x19,0x7B,0x41,0x2C,0xC7,0x89,0x3C,0xD0,0x72,0xDC,0x85,0xFA,0x58,
+    0xAF,0xD5,0x25,0xE4,0x13,0xF8,0x58,0x65,0x67,0x9F,0x0D,0xFF,0x57,0x8B,0xA9,0x85,
+    0x5E,0xCA,0xA6,0x4B,0xB0,0xA7,0xB2,0x2D,0xE0,0x8C,0x22,0xCD,0xFB,0xFF,0x79,0xA4,
+    0x8C,0x2B,0x8D,0xFE,0x02,0x3D,0x24,0xDE,0xA9,0x5D,0x5F,0xE4,0x0F,0x47,0xD0,0xDB,
+    0x66,0x25,0x3E,0x87,0x47,0x0C,0xAE,0x22,0xC5,0x50,0x22,0x84,0xD7,0xED,0x4A,0x59,
+    0x1A,0xF6,0x93,0xA5,0x93,0xB0,0xE0,0x1B,0x81,0xF2,0x56,0xC4,0xC8,0x10,0x53,0xE4,
+    0xD4,0x76,0xB1,0xD1,0x5B,0x69,0x4B,0x77,0xB2,0xE0,0x4F,0xC4,0x84,0xE7,0xD4,0xA0,
+    0x50,0xEE,0x3C,0xFA,0x44,0xFC,0xD0,0x57,0xB9,0xE1,0x28,0x53,0xFD,0x53,0xCD,0xDC,
+    0xB9,0x1F,0x7A,0x40,0xBD,0x30,0x3F,0xD8,0x6C,0xD2,0xF3,0xE7,0x07,0x9F,0x1F,0x22,
+    0xB5,0xEA,0x22,0x71,0xCB,0x2A,0xF0,0x56,0x7C,0xFE,0xAC,0xA8,0xD1,0x06,0x0F,0x14,
+    0x14,0x52,0x4C,0xFE,0x64,0x2B,0x0C,0x69,0x2A,0xB8,0x0D,0x50,0x6E,0x3E,0x04,0x07,
+    0xBF,0x7A,0x20,0x8B,0xF8,0xEE,0x65,0x09,0xE1,0xC7,0x49,0x08,0x32,0x3D,0x0D,0x28,
+    0x7E,0x49,0x1D,0xB7,0x4A,0xEF,0x02,0xE7,0x0D,0x80,0x17,0xC8,0x5C,0xE0,0x61,0x62,
+    0xCB,0xEC,0xB3,0x60,0x79,0x25,0xDA,0x1A,0x65,0x73,0x9C,0x38,0x10,0xA0,0x26,0x3A,
+    0xB0,0xC8,0x16,0x7D,0x93,0x31,0x22,0xEE,0x74,0x0B,0x88,0xC0,0x5C,0x89,0x41,0x00,
+    0x28,0xA9,0x47,0x31,0xDF,0x7D,0x49,0x45,0x9A,0xF5,0xE6,0xA7,0x45,0x1A,0xD2,0x8E,
+    0x13,0x10,0xDF,0x83,0xAF,0x9B,0x0D,0xAD,0x7E,0x7E,0x9D,0x35,0x50,0x34,0x04,0xCE,
+    0xE9,0x20,0xD6,0x9E,0xDB,0x9D,0xD4,0xA8,0xDA,0x64,0xB4,0xD1,0x2F,0x59,0x2E,0x5E,
+    0xA2,0x36,0x61,0xD4,0x24,0xA0,0x82,0x33,0x33,0x8A,0xA1,0xD1,0x6C,0xEF,0x61,0x68,
+    0xA3,0xE5,0xD2,0x56,0xAD,0xC5,0xFD,0x5E,0x62,0xEB,0x15,0xA8,0x74,0x12,0x4C,0x2F,
+    0x31,0x8C,0xE9,0xC1,0xDF,0x10,0x4B,0x01,0xEA,0xF6,0x54,0x1B,0xCD,0x7F,0x3B,0xBD,
+    0x5C,0x9F,0xC1,0xDB,0xCF,0x01,0xCA,0xF2,0xBA,0x60,0x12,0x21,0x31,0xED,0xA9,0x64,
+    0xB8,0xB2,0x49,0x58,0x17,0x6D,0x5A,0xD7,0xCD,0x8C,0x6D,0xBE,0x9E,0x7F,0xE2,0x02,
+    0x58,0xA7,0xDB,0xC3,0x2D,0x58,0xF6,0x74,0x06,0x6A,0x9A,0xF6,0x61,0xF9,0xF6,0x00,
+    0xB6,0x69,0xD8,0x3A,0x8B,0x31,0x59,0xDD,0x91,0xE6,0x7C,0x27,0x23,0x87,0xDD,0x03,
+    0x0F,0x8F,0x2A,0x8C,0x1E,0x83,0x01,0x4E,0x01,0x61,0x0C,0x52,0x73,0x6D,0xFC,0x08,
+    0xA2,0xB9,0x2A,0x66,0xE4,0x76,0x4D,0x31,0xA0,0x56,0x9B,0xD9,0x53,0x8D,0xA2,0xB6,
+    0x8F,0x02,0xC8,0xE6,0x3A,0xA6,0x04,0xD1,0x48,0xFB,0xC3,0x4A,0x02,0x76,0xFD,0x2F,
+    0xD2,0xBC,0x13,0xB6,0xE8,0x6D,0x34,0x24,0xFA,0x9D,0x29,0x8A,0xC7,0xA1,0x2B,0x14,
+    0xF1,0x96,0x00,0x73,0xB9,0x13,0xE9,0xC0,0xB9,0x3A,0x47,0x56,0x02,0x71,0x80,0x27,
+    0xA4,0xBC,0x25,0xB6,0xE9,0xBD,0xE4,0xE9,0x98,0x74,0x16,0xF1,0x37,0x84,0x81,0x07,
+    0xB4,0x82,
+};
+
+uint8_t _caissuer_https[] = {
+    0x30,0x82,0x04,0x68,0x30,0x82,0x03,0x50,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x7A,
+    0x22,0xA1,0x88,0x18,0x9E,0x75,0x77,0xE6,0xEF,0x7E,0xC0,0x33,0x8E,0xE8,0x90,0xE8,
+    0x7B,0xC4,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
+    0x00,0x30,0x81,0x81,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
+    0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,
+    0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,
+    0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
+    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x15,
+    0x30,0x13,0x06,0x03,0x55,0x04,0x03,0x0C,0x0C,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,
+    0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x38,0x30,0x34,0x32,0x38,0x32,
+    0x30,0x32,0x31,0x34,0x31,0x5A,0x17,0x0D,0x31,0x39,0x30,0x34,0x32,0x38,0x32,0x30,
+    0x32,0x31,0x34,0x31,0x5A,0x30,0x81,0x8D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,
+    0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,
+    0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
+    0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,
+    0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,
+    0x6E,0x67,0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,0x48,0x54,0x54,
+    0x50,0x53,0x20,0x43,0x41,0x49,0x73,0x73,0x75,0x65,0x72,0x20,0x54,0x65,0x73,0x74,
+    0x20,0x43,0x65,0x72,0x74,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,0xC1,0x68,0xC2,0x47,0x1E,0x07,0x82,0x66,0x47,0xC9,
+    0x5C,0x22,0xDD,0x8B,0x93,0x6A,0xA7,0x22,0x00,0xB8,0xDA,0x8C,0x3C,0x52,0xA7,0x47,
+    0x73,0xBB,0x7A,0xD7,0x8C,0x1E,0xAE,0xDA,0x34,0x25,0x4E,0xEB,0x1F,0x33,0x0B,0x8A,
+    0xC7,0x6D,0x2A,0x93,0xDB,0x0D,0xD0,0x47,0x85,0x9C,0x14,0xD5,0x23,0xE3,0xE4,0x94,
+    0xE0,0x17,0x9F,0x56,0x64,0x8E,0xE0,0x08,0xE9,0x1B,0x4C,0x7C,0x77,0xF9,0x35,0x74,
+    0x52,0x43,0x90,0x13,0xFA,0x51,0x9A,0xA2,0x93,0x47,0x94,0xE7,0xBD,0x07,0xE5,0xFB,
+    0x67,0x8B,0xF0,0xE2,0x0C,0x97,0xFD,0x29,0x51,0xBD,0x85,0x6C,0xBE,0x36,0xFD,0xDD,
+    0xCC,0x99,0x4D,0x68,0x37,0x96,0xB2,0x20,0x85,0x55,0xA5,0x99,0xA4,0x7E,0xD7,0x19,
+    0x06,0x15,0x20,0x10,0x50,0x51,0x2E,0x74,0x5C,0x43,0x49,0x94,0x6B,0x0E,0x9E,0xFB,
+    0xDF,0xB2,0xEB,0xD9,0x28,0xA8,0xF1,0x25,0x49,0xC8,0xFE,0x3B,0xE1,0x45,0x95,0x47,
+    0xD1,0x53,0xCD,0x34,0x9A,0x6F,0xC4,0x3F,0x63,0xC2,0x60,0xC6,0x40,0xBB,0xF7,0x20,
+    0x8A,0xB8,0xB7,0xD7,0xC2,0xBB,0x48,0x24,0x64,0xA2,0x4A,0xE4,0x2A,0x17,0x68,0xE2,
+    0xAC,0x47,0x2D,0xCC,0xBD,0xB7,0xCE,0x73,0xDF,0x96,0x8C,0x12,0x56,0xE3,0x29,0xE3,
+    0x4D,0xB4,0x55,0x28,0xAB,0x28,0x24,0x45,0x7F,0x55,0x66,0xCD,0x46,0x29,0x89,0x58,
+    0xFF,0xA6,0xD1,0x67,0xAC,0x50,0xEE,0x55,0x6D,0x6A,0x2A,0xCF,0xD6,0x09,0xE9,0xDA,
+    0x22,0xB0,0xAF,0x90,0xD7,0x02,0xB2,0xCE,0x5F,0x09,0x96,0x5E,0x88,0xAE,0xB5,0xB6,
+    0xA1,0xC3,0x9D,0x1A,0x2F,0x2D,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xCA,0x30,0x81,
+    0xC7,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
+    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,0x80,0x30,
+    0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x03,0x01,0x30,0x16,0x06,0x03,0x55,0x1D,0x11,0x04,0x0F,0x30,0x0D,0x82,
+    0x0B,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,
+    0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xDF,0xC7,0x68,0x26,0x64,0x95,0x5D,0x73,0x36,
+    0x84,0xE8,0xE3,0x1D,0xC8,0x28,0x5E,0xA8,0x27,0x73,0x8C,0x30,0x1F,0x06,0x03,0x55,
+    0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xB5,0xA9,0x53,0x08,0x10,0x38,0x1A,0xA5,
+    0xB3,0x84,0xC9,0xEE,0xC4,0xAB,0x0F,0xB8,0x5F,0x68,0x10,0xA2,0x30,0x3A,0x06,0x08,
+    0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,0x04,0x2E,0x30,0x2C,0x30,0x2A,0x06,0x08,
+    0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,0x86,0x1E,0x68,0x74,0x74,0x70,0x73,0x3A,
+    0x2F,0x2F,0x65,0x78,0x61,0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x74,0x65,
+    0x73,0x74,0x43,0x41,0x2E,0x64,0x65,0x72,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xC4,0x48,0xDF,0x5E,
+    0x73,0xD1,0x43,0x28,0x7D,0x69,0x71,0x32,0x1F,0xCC,0x1A,0xEB,0x5B,0x98,0x9D,0xCE,
+    0xFF,0xCA,0x16,0xA9,0x96,0xE7,0x4D,0xC4,0xAE,0x53,0xE2,0x5D,0xDB,0xDA,0x40,0x80,
+    0xE5,0xFB,0xF3,0xD7,0x21,0x9A,0x77,0x1D,0x67,0xFC,0x04,0x62,0x18,0xFF,0x10,0x59,
+    0xF4,0xDD,0xF4,0xC6,0x8F,0xB4,0xEF,0x9F,0x05,0xA6,0xF1,0xCB,0x44,0x24,0x02,0x19,
+    0x75,0xF9,0x3C,0x28,0x8A,0xAA,0x57,0x6B,0xFF,0x64,0xFF,0xD7,0xE2,0x62,0x67,0x70,
+    0x20,0x4D,0xAE,0xD2,0x67,0xED,0x92,0xA4,0xFA,0x8A,0xC3,0x24,0x9C,0x2F,0x4D,0x2C,
+    0xA9,0xA5,0x92,0x5E,0x5C,0x6F,0xDB,0xAB,0x96,0xA6,0xB1,0x5B,0xF1,0x8D,0x97,0x08,
+    0xBC,0x5B,0x27,0xD5,0x9E,0x2D,0xF0,0x49,0x68,0xA6,0x92,0x00,0x13,0xAD,0x60,0x9E,
+    0x78,0x72,0xC2,0x18,0xB8,0xE5,0x9D,0x72,0xA5,0x87,0x61,0xA8,0x95,0x8A,0x2B,0xB2,
+    0xCC,0xCA,0x7F,0x1E,0x1E,0xC5,0xFB,0x5A,0x0C,0x77,0x17,0xB0,0xBE,0x7B,0x5A,0x50,
+    0x05,0x32,0x40,0x98,0x3A,0x8B,0x22,0x3F,0x3B,0xA5,0xA8,0xA9,0x59,0x3B,0x55,0x92,
+    0xD1,0x8A,0x34,0x73,0xA6,0xD6,0x5D,0x5E,0x85,0x59,0x00,0xD5,0x55,0x94,0x80,0xC1,
+    0xB9,0xF1,0xCA,0x2B,0xC5,0x96,0xEE,0x49,0x6A,0x2C,0xDD,0x62,0x98,0xB3,0x74,0x09,
+    0x09,0xDE,0x3D,0x59,0x5B,0x21,0x76,0x6E,0x27,0x66,0xED,0x7B,0x74,0x7F,0xE7,0xA9,
+    0xAE,0xEB,0x40,0x83,0xB9,0xBC,0xE6,0x0C,0x1E,0x53,0xB2,0xEA,0x79,0xC4,0xA9,0x30,
+    0x2B,0x1F,0xC4,0x34,0x82,0x3E,0xFC,0x1E,0x2D,0x66,0x75,0xD0,
+};
+
+#endif /* _TRUSTTESTS_CA_ISSUER_TESTS_H_ */
index 7d058ee740c84fcec12cb258efdb117f2d15e8c7..40fdd7c43f1631991cd422bff3d9dddc5e23d0ac 100644 (file)
 #include "trust/trustd/OTATrustUtilities.h"
 
 #if !TARGET_OS_BRIDGE
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wquoted-include-in-framework-header"
 #import <OCMock/OCMock.h>
+#pragma clang diagnostic pop
 #endif
 
 #if TARGET_OS_IPHONE
@@ -1894,4 +1897,50 @@ errOut:
     CFReleaseNull(trust);
 }
 
+- (void) testCheckCTRequired {
+    SecCertificateRef system_root = NULL,  system_server_after = NULL;
+    SecTrustRef trust = NULL;
+    NSArray *enforce_anchors = nil;
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:562340800.0]; // October 27, 2018 at 6:46:40 AM PDT
+    CFErrorRef error = nil;
+
+    // A policy with CTRequired set
+    SecPolicyRef policy = SecPolicyCreateBasicX509();
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckCTRequired, kCFBooleanTrue);
+
+    require_action(system_root = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"enforcement_system_root"],
+                   errOut, fail("failed to create system root"));
+    require_action(system_server_after = (__bridge SecCertificateRef)[CTTests SecCertificateCreateFromResource:@"enforcement_system_server_after"],
+                   errOut, fail("failed to create system server cert issued after flag day"));
+
+    enforce_anchors = @[ (__bridge id)system_root ];
+    require_noerr_action(SecTrustCreateWithCertificates(system_server_after, policy, &trust), errOut, fail("failed to create trust"));
+    require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)enforce_anchors), errOut, fail("failed to set anchors"));
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)date), errOut, fail("failed to set verify date"));
+
+    require_noerr_action(SecTrustSetTrustedLogs(trust, (__bridge CFArrayRef)trustedCTLogs), errOut, fail("failed to set trusted logs"));
+
+    // test system cert without CT fails (with trusted logs)
+#if !TARGET_OS_BRIDGE
+    is(SecTrustEvaluateWithError(trust, &error), false, "system post-flag-date non-CT cert with trusted logs succeeded");
+    if (error) {
+        is(CFErrorGetCode(error), errSecNotTrusted, "got wrong error code for non-ct cert, got %ld, expected %d",
+           (long)CFErrorGetCode(error), (int)errSecNotTrusted);
+    } else {
+        fail("expected trust evaluation to fail and it did not.");
+    }
+#else
+    /* BridgeOS doesn't enforce */
+    ok(SecTrustEvaluateWithError(trust, NULL), "system post-flag-date non-CT cert with trusted logs failed");
+#endif
+
+errOut:
+    CFReleaseNull(system_root);
+    CFReleaseNull(system_server_after);
+    CFReleaseNull(policy);
+    CFReleaseNull(trust);
+    CFReleaseNull(error);
+
+}
+
 @end
index e905b822fb111d53ea2185319c191d7d45f020de..f0aae4b98ea68376a9a15a3da48660c5291b7774 100644 (file)
@@ -108,7 +108,7 @@ errOut:
     ok_status(SecTrustSetVerifyDate(trust, date),
               "set owa.prt-forest.fi trust date to May 2013");
     
-    SecKeyRef pubkey = SecTrustCopyPublicKey(trust);
+    SecKeyRef pubkey = SecTrustCopyKey(trust);
     isnt(pubkey, NULL, "pubkey returned");
     
     CFReleaseNull(certs);
index 7f6a8d756a5f247b7f0916a52115dcf0174efaab..f0871ab75582a017bc133e45ac82a0723fc1d2ec 100644 (file)
@@ -493,6 +493,8 @@ exit:
     return result;
 }
 
+#if !TARGET_OS_WATCH
+// Skip test on watchOS due to size constraints (rdar://66792084)
 - (void) testBetterTLS {
     NSArray<NSDictionary *> *testsArray = [self getTestsArray];
     if([self untar_test_certs]) {
@@ -539,5 +541,6 @@ exit:
 
     [[NSFileManager defaultManager] removeItemAtURL:tmpCertsDir error:nil];
 }
+#endif //!TARGET_OS_WATCH
 
 @end
index 2d65d23f208b16eb9ec63d6e3c1c5f62c7730a04..103643893a10a0b5825fa21e5195cc4ce26f8e25 100644 (file)
@@ -76,20 +76,17 @@ const NSString *kSecTestPathFailureResources = @"si-18-certificate-parse/PathFai
 
 - (void)testUnparseableExtensions {
     SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _bad_extension_leaf, sizeof(_bad_extension_leaf));
-    SecCertificateRef root = NULL;
+    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _bad_extension_root, sizeof(_bad_extension_root));
     SecTrustRef trust = NULL;
     SecPolicyRef policy = SecPolicyCreateBasicX509();
     CFErrorRef error = NULL;
-
-    NSURL *rootURL = [[NSBundle bundleForClass:[self class]]URLForResource:@"root" withExtension:@".cer" subdirectory:@"si-18-certificate-parse"];
-    XCTAssert(root = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)[NSData dataWithContentsOfURL:rootURL]), "Unable to create root cert");
     NSArray *anchors = @[(__bridge id)root];
 
     require_noerr_action(SecTrustCreateWithCertificates(leaf, policy, &trust), errOut,
                          fail("Unable to create trust with certificate with unparseable extension"));
     require_noerr_action(SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors),
                          errOut, fail("Unable to set trust anchors"));
-    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)[NSDate dateWithTimeIntervalSinceReferenceDate:507200000.0]),
+    require_noerr_action(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)[NSDate dateWithTimeIntervalSinceReferenceDate:620000000.0]),
                          errOut, fail("Unable to set verify date"));
     XCTAssertFalse(SecTrustEvaluateWithError(trust, &error), "Got wrong trust result cert");
     XCTAssert(error != NULL);
index 507cb672623938485a714821cdaf80544b2d563f..af473be485ad3ee4df3c0ce76166a606100c7508 100644 (file)
@@ -5,50 +5,90 @@
 #ifndef _TRUSTTESTS_EVALUATION_PATH_PARSE_TESTS_H_
 #define _TRUSTTESTS_EVALUATION_PATH_PARSE_TESTS_H_
 
-/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=CoreTrust Test Leaf 1 */
-/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=CoreTrust Test CA */
+const uint8_t _bad_extension_root[] = {
+    0x30,0x82,0x02,0x55,0x30,0x82,0x01,0xFD,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xA7,0x97,0x3B,0x17,0xE9,0x68,0x62,0x01,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,
+    0x3D,0x04,0x01,0x30,0x81,0x8D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,
+    0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,
+    0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
+    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
+    0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,0x4F,0x43,0x53,0x50,0x20,
+    0x52,0x65,0x73,0x70,0x6F,0x6E,0x64,0x65,0x72,0x20,0x54,0x65,0x73,0x74,0x20,0x52,
+    0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x32,0x30,0x30,0x37,0x31,0x33,0x32,0x30,0x31,
+    0x30,0x31,0x37,0x5A,0x17,0x0D,0x33,0x30,0x30,0x37,0x31,0x31,0x32,0x30,0x31,0x30,
+    0x31,0x37,0x5A,0x30,0x81,0x8D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,
+    0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,
+    0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,
+    0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
+    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
+    0x31,0x21,0x30,0x1F,0x06,0x03,0x55,0x04,0x03,0x0C,0x18,0x4F,0x43,0x53,0x50,0x20,
+    0x52,0x65,0x73,0x70,0x6F,0x6E,0x64,0x65,0x72,0x20,0x54,0x65,0x73,0x74,0x20,0x52,
+    0x6F,0x6F,0x74,0x30,0x59,0x30,0x13,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,
+    0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0x45,0xA3,
+    0x6E,0x77,0x59,0x2B,0x7D,0xD4,0x9D,0x44,0xD7,0xDA,0x3E,0x5C,0xE1,0xB3,0xF8,0x34,
+    0xE8,0xE8,0xEC,0x53,0x5A,0x5B,0x88,0x79,0x62,0x20,0x00,0xE1,0x82,0x42,0x3F,0x9D,
+    0x78,0xCD,0x6D,0x1C,0xF2,0xF6,0x7A,0x66,0xCA,0x1B,0xEA,0x40,0xFD,0x9B,0x9D,0x8B,
+    0x31,0x63,0xE7,0x95,0x10,0xB8,0x91,0x24,0xAE,0xF3,0x30,0xE4,0x1F,0x35,0xA3,0x45,
+    0x30,0x43,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x08,0x30,0x06,
+    0x01,0x01,0xFF,0x02,0x01,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,
+    0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
+    0x14,0x59,0xB5,0xB1,0x6E,0x89,0x9B,0xAC,0x7E,0x19,0x13,0x2C,0x75,0x68,0x3D,0x9F,
+    0x05,0x15,0x54,0x05,0x16,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01,
+    0x03,0x47,0x00,0x30,0x44,0x02,0x20,0x48,0x3A,0xED,0x1D,0x9A,0xA1,0x82,0x4B,0x49,
+    0x7D,0x92,0xF0,0xAD,0x8E,0x04,0x8E,0x0C,0x95,0x02,0x7A,0x7D,0x93,0xFD,0xDD,0x4D,
+    0xDA,0x00,0xDA,0xBA,0x85,0x8A,0x6F,0x02,0x20,0x38,0xB0,0x4B,0x32,0xD0,0x61,0x6A,
+    0x3A,0xBB,0x4C,0x24,0x6B,0x73,0x7A,0x97,0x44,0x63,0xEA,0x77,0xAB,0xB9,0x55,0xBF,
+    0x40,0x96,0xEC,0xD5,0x2C,0x30,0x47,0x4E,0x2C,
+};
+
 const uint8_t _bad_extension_leaf[] = {
-    0x30,0x82,0x02,0x85,0x30,0x82,0x02,0x2C,0xA0,0x03,0x02,0x01,0x02,0x02,0x15,0x00,
-    0xD5,0xEC,0xDB,0x27,0x18,0xA7,0xEC,0x88,0x42,0xBA,0xC8,0xCD,0xE6,0xFC,0x34,0x9A,
-    0x4D,0x36,0xD3,0x4C,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01,0x30,
-    0x81,0x86,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
-    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
-    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
-    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
-    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
-    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x1A,0x30,0x18,
-    0x06,0x03,0x55,0x04,0x03,0x0C,0x11,0x43,0x6F,0x72,0x65,0x54,0x72,0x75,0x73,0x74,
-    0x20,0x54,0x65,0x73,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x37,0x30,0x31,
-    0x32,0x36,0x32,0x33,0x32,0x33,0x33,0x32,0x5A,0x17,0x0D,0x31,0x37,0x30,0x31,0x32,
-    0x37,0x32,0x33,0x32,0x33,0x33,0x32,0x5A,0x30,0x81,0x8A,0x31,0x0B,0x30,0x09,0x06,
-    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
-    0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,
-    0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,
-    0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
-    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
-    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
-    0x65,0x72,0x69,0x6E,0x67,0x31,0x1E,0x30,0x1C,0x06,0x03,0x55,0x04,0x03,0x0C,0x15,
-    0x43,0x6F,0x72,0x65,0x54,0x72,0x75,0x73,0x74,0x20,0x54,0x65,0x73,0x74,0x20,0x4C,
-    0x65,0x61,0x66,0x20,0x31,0x30,0x56,0x30,0x10,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,
-    0x02,0x01,0x06,0x05,0x2B,0x81,0x04,0x00,0x0A,0x03,0x42,0x00,0x04,0xFA,0x43,0x00,
-    0x5E,0xEF,0xEF,0x33,0xBA,0x03,0x5F,0x7B,0x42,0xE2,0xCF,0x7D,0x2A,0x61,0x69,0xE2,
-    0xEB,0x7A,0xE1,0x98,0x49,0x60,0x0D,0xD8,0xCB,0x99,0x09,0x91,0x4E,0x8B,0x12,0xA4,
-    0x7F,0x19,0xAE,0xF4,0x62,0x8D,0x36,0x1A,0x34,0x9C,0x64,0xFE,0xE9,0xB2,0x02,0x3E,
-    0xFD,0x83,0x9D,0x7E,0x40,0x7D,0x21,0x0E,0xD4,0xDA,0x97,0x12,0xE2,0xA3,0x75,0x30,
-    0x73,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
-    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,
-    0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x31,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,
-    0x05,0x07,0x03,0x02,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xBB,
-    0x3E,0xCE,0xF4,0xBA,0x9A,0xBC,0x9F,0x1E,0xF9,0x73,0xDB,0x11,0xEB,0x55,0x93,0xA3,
-    0x59,0x5B,0x6C,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
-    0xEC,0xC0,0x39,0x7A,0xDF,0x66,0x7B,0x15,0xB1,0x13,0x9E,0x8D,0xD6,0xB2,0x77,0xA6,
-    0xBA,0xEE,0x2A,0xA1,0x30,0x09,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x01,0x03,
-    0x48,0x00,0x30,0x45,0x02,0x20,0x2B,0x9C,0xC9,0xD3,0x86,0x66,0x7A,0xCD,0x58,0xFC,
-    0x48,0x06,0xF6,0xC6,0xCC,0xE2,0x0F,0xA8,0xE4,0x66,0x16,0x2C,0xA8,0xCC,0x51,0xB6,
-    0x1B,0x56,0xAC,0xBB,0x9F,0xD4,0x02,0x21,0x00,0xA2,0x51,0xAC,0x76,0xE6,0x3B,0x3B,
-    0x0D,0x79,0xCD,0xB6,0x71,0x66,0x9E,0xEF,0x3C,0xB8,0x56,0xEA,0xBF,0x64,0x48,0x5B,
-    0x0B,0x9B,0x38,0x06,0xBE,0xBA,0xE5,0xC9,0x17,
+    0x30,0x82,0x02,0x94,0x30,0x82,0x02,0x3A,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x25,
+    0xF3,0xFF,0xBB,0x76,0x44,0x44,0x8A,0xC2,0xC2,0xF6,0xC6,0x0D,0xEF,0x53,0x19,0xBE,
+    0x01,0x1F,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x30,0x81,
+    0x8D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,
+    0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
+    0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,
+    0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,
+    0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x21,0x30,0x1F,0x06,
+    0x03,0x55,0x04,0x03,0x0C,0x18,0x4F,0x43,0x53,0x50,0x20,0x52,0x65,0x73,0x70,0x6F,
+    0x6E,0x64,0x65,0x72,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,
+    0x17,0x0D,0x32,0x30,0x30,0x37,0x31,0x34,0x30,0x30,0x30,0x34,0x30,0x37,0x5A,0x17,
+    0x0D,0x32,0x31,0x30,0x37,0x31,0x34,0x30,0x30,0x30,0x34,0x30,0x37,0x5A,0x30,0x81,
+    0x8F,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,
+    0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,
+    0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,
+    0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,
+    0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,
+    0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x23,0x30,0x21,0x06,
+    0x03,0x55,0x04,0x03,0x0C,0x1A,0x4F,0x43,0x53,0x50,0x20,0x52,0x65,0x73,0x70,0x6F,
+    0x6E,0x64,0x65,0x72,0x20,0x54,0x65,0x73,0x74,0x3A,0x20,0x56,0x61,0x6C,0x69,0x64,
+    0x30,0x59,0x30,0x13,0x06,0x07,0x2A,0x86,0x48,0xCE,0x3D,0x02,0x01,0x06,0x08,0x2A,
+    0x86,0x48,0xCE,0x3D,0x03,0x01,0x07,0x03,0x42,0x00,0x04,0x4D,0xFC,0xED,0x57,0xD8,
+    0xEA,0x29,0xC6,0xE5,0x25,0x87,0x51,0xAA,0x73,0x6A,0x5F,0x00,0x4C,0x64,0x42,0xE0,
+    0x53,0xAE,0xEE,0x9E,0x3F,0x4B,0xBC,0x2B,0x7B,0xFB,0x24,0x33,0x53,0x9F,0x42,0x33,
+    0x99,0xC4,0x1A,0x33,0xC8,0x09,0xCC,0x8E,0x50,0x74,0xC1,0x3E,0x9A,0x42,0x9E,0x6F,
+    0x46,0x4E,0x73,0x34,0xE4,0xF1,0x7A,0x7E,0xE1,0x40,0x61,0xA3,0x75,0x30,0x73,0x30,
+    0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x0E,0x06,
+    0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x82,0x30,0x13,0x06,
+    0x03,0x55,0x1D,0x25,0x04,0x0C,0x31,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x03,0x09,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x09,0x35,0xC3,
+    0xB1,0x7D,0x12,0x8D,0xBC,0xB0,0x3C,0xF7,0xC4,0xA9,0x7D,0xA1,0x2A,0x84,0x9C,0xEE,
+    0x67,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x59,0xB5,
+    0xB1,0x6E,0x89,0x9B,0xAC,0x7E,0x19,0x13,0x2C,0x75,0x68,0x3D,0x9F,0x05,0x15,0x54,
+    0x05,0x16,0x30,0x0A,0x06,0x08,0x2A,0x86,0x48,0xCE,0x3D,0x04,0x03,0x02,0x03,0x48,
+    0x00,0x30,0x45,0x02,0x20,0x13,0x00,0x46,0x93,0x44,0x1D,0x80,0x74,0x0A,0x59,0xE3,
+    0x79,0x43,0xFD,0x04,0x2A,0x6C,0x19,0x5A,0x79,0x53,0x46,0x9E,0x8F,0x3A,0x31,0x47,
+    0x05,0x9F,0xF8,0xE0,0xB4,0x02,0x21,0x00,0xAA,0x3D,0xBC,0x3E,0x68,0x47,0x71,0xCC,
+    0x36,0x90,0x33,0xF3,0xC4,0xEA,0x12,0xF4,0x4C,0x96,0x65,0xE3,0x65,0xB4,0x7E,0x24,
+    0xAB,0x6C,0x64,0xFA,0x13,0x6C,0xF9,0x4C,
 };
 
 
index e844ab745defe6a2c1cfabacd27d63406f0efbf3..f1161142f2945e0ec8c11bf1c12b684e218e1a9e 100644 (file)
 
 #include <utilities/SecInternalReleasePriv.h>
 #include <utilities/SecCFRelease.h>
+#include <utilities/SecCFWrappers.h>
 #include <Security/SecCertificate.h>
 #include <Security/SecCertificatePriv.h>
 #include <Security/SecPolicyPriv.h>
+#include <Security/SecPolicyInternal.h>
 #include <Security/SecTrust.h>
 #include <Security/SecTrustPriv.h>
 
@@ -61,6 +63,7 @@
 #include "../TrustEvaluationTestHelpers.h"
 
 const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies-data";
+const NSString *kSecTrustTestPinnningTest = @"PinningPolicyTrustTest";
 
 @interface PolicyTests : TrustEvaluationTestCase
 @end
@@ -74,8 +77,8 @@ const NSString *kSecTrustTestPinningPolicyResources = @"si-20-sectrust-policies-
     testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:@"debugging" withExtension:@"plist"
                                                           subdirectory:(NSString *)kSecTrustTestPinningPolicyResources];
     if (!testPlist) {
-        testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:nil withExtension:@"plist"
-                                                              subdirectory:(NSString *)kSecTrustTestPinningPolicyResources ];
+        testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:(NSString *)kSecTrustTestPinnningTest withExtension:@"plist"
+                                                              subdirectory:(NSString *)kSecTrustTestPinningPolicyResources];
     }
     if (!testPlist) {
         fail("Failed to get tests plist from %@", kSecTrustTestPinningPolicyResources);
@@ -142,4 +145,164 @@ errOut:
     CFReleaseNull(trust);
 }
 
+- (void)testSecPolicyReconcilePinningRequiredIfInfoSpecified
+{
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("www.example.org"));
+    CFMutableArrayRef emptySPKISHA256 = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+
+    CFMutableArrayRef nonemtpySPKISHA256 = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+    uint8_t _random_data256[256/sizeof(uint8_t)];
+    (void)SecRandomCopyBytes(NULL, sizeof(_random_data256), _random_data256);
+    CFDataRef random_data256 = CFDataCreate(kCFAllocatorDefault, _random_data256, sizeof(_random_data256));
+    CFArrayAppendValue(nonemtpySPKISHA256, random_data256);
+    CFReleaseNull(random_data256);
+
+    // kSecPolicyCheckPinningRequired should be unset after reconciliation.
+    // Empty values for both SPKI policies signal a pinning exception.
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckLeafSPKISHA256, emptySPKISHA256);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckCAspkiSHA256, emptySPKISHA256);
+    CFDictionaryRef policyOptions = SecPolicyGetOptions(policy);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), true);
+    SecPolicyReconcilePinningRequiredIfInfoSpecified((CFMutableDictionaryRef)policyOptions);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), false);
+
+    // kSecPolicyCheckPinningRequired overrules the other two policies.
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckLeafSPKISHA256, nonemtpySPKISHA256);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckCAspkiSHA256, emptySPKISHA256);
+    policyOptions = SecPolicyGetOptions(policy);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), true);
+    SecPolicyReconcilePinningRequiredIfInfoSpecified((CFMutableDictionaryRef)policyOptions);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), false);
+
+    // kSecPolicyCheckPinningRequired overrules the other two policies.
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckPinningRequired, kCFBooleanTrue);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckLeafSPKISHA256, emptySPKISHA256);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckCAspkiSHA256, nonemtpySPKISHA256);
+    policyOptions = SecPolicyGetOptions(policy);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), true);
+    SecPolicyReconcilePinningRequiredIfInfoSpecified((CFMutableDictionaryRef)policyOptions);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), false);
+
+    // In the absence of kSecPolicyCheckPinningRequired there is nothing to reconcile.
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSSL(true, CFSTR("www.example.org"));
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckLeafSPKISHA256, emptySPKISHA256);
+    SecPolicySetOptionsValue(policy, kSecPolicyCheckCAspkiSHA256, emptySPKISHA256);
+    policyOptions = SecPolicyGetOptions(policy);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), true);
+    SecPolicyReconcilePinningRequiredIfInfoSpecified((CFMutableDictionaryRef)policyOptions);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckPinningRequired), false);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckLeafSPKISHA256), true);
+    is(CFDictionaryContainsKey(policyOptions, kSecPolicyCheckCAspkiSHA256), true);
+
+    CFReleaseNull(policy);
+    CFReleaseNull(emptySPKISHA256);
+    CFReleaseNull(nonemtpySPKISHA256);
+}
+
+- (CFDictionaryRef)getNSPinnedDomainsFromDictionaryInfoFile:(NSString *)fileName
+{
+    NSURL *infoPlist = [[NSBundle bundleForClass:[self class]] URLForResource:fileName withExtension:@"plist"
+                                                                 subdirectory:(NSString *)kSecTrustTestPinningPolicyResources];
+    if (!infoPlist) {
+        fail("Failed to access plist file \"%@\"", fileName);
+        return NULL;
+    }
+
+    NSDictionary *infoDictionary = [NSDictionary dictionaryWithContentsOfURL:infoPlist];
+    if (!infoDictionary) {
+        fail("Failed to create dictionary from plist file \"%@\"", fileName);
+        return NULL;
+    }
+
+    CFTypeRef nsAppTransportSecurityDict = CFDictionaryGetValue((__bridge CFDictionaryRef)infoDictionary, CFSTR("NSAppTransportSecurity"));
+    if (!isDictionary(nsAppTransportSecurityDict)) {
+        fail("NSAppTransportSecurity dictionary entry is missing from plist file \"%@\"", fileName);
+        return NULL;
+    }
+
+    CFDictionaryRef nsPinnedDomainsDict = CFDictionaryGetValue(nsAppTransportSecurityDict, CFSTR("NSPinnedDomains"));
+    if (!isDictionary(nsPinnedDomainsDict)) {
+        fail("NSPinnedDomains dictionary entry is missing from plist file \"%@\"", fileName);
+        return NULL;
+    }
+
+    return nsPinnedDomainsDict;
+}
+
+- (void)testParseNSPinnedDomains
+{
+    NSURL *testPlist = nil;
+    NSArray *testsArray = nil;
+
+
+    testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:@"NSPinnedDomainsParsingTest_debugging" withExtension:@"plist"
+                                                          subdirectory:(NSString *)kSecTrustTestPinningPolicyResources];
+    if (!testPlist) {
+        testPlist = [[NSBundle bundleForClass:[self class]] URLForResource:@"NSPinnedDomainsParsingTest" withExtension:@"plist"
+                                                              subdirectory:(NSString *)kSecTrustTestPinningPolicyResources];
+    }
+    if (!testPlist) {
+        fail("Failed to get tests plist from \"%@\"", kSecTrustTestPinningPolicyResources);
+        return;
+    }
+
+    testsArray = [NSArray arrayWithContentsOfURL: testPlist];
+    if (!testsArray) {
+        fail("Failed to create array from plist");
+        return;
+    }
+
+    [testsArray enumerateObjectsUsingBlock:^(NSDictionary *testDict, NSUInteger idx, BOOL * _Nonnull stop) {
+        NSString *plistFileName = testDict[@"PlistFileName"];
+        if (!plistFileName) {
+            fail("Failed to read plist file name from \"%@\":%lu", plistFileName, (unsigned long)idx);
+            return;
+        }
+
+        NSDictionary *expectedProperties = testDict[@"ExpectedProperties"];
+        if (!expectedProperties) {
+            fail("Missing the expected results in \"%@\"", plistFileName);
+            return;
+        }
+        bool hasNSPinnedLeafIdentities = [expectedProperties[@"NSPinnedLeafIdentities"] boolValue];
+        int NSPinnedLeafIdentitiesCount = [expectedProperties[@"NSPinnedLeafIdentitiesCount"] intValue];
+        bool hasNSPinnedCAIdentities = [expectedProperties[@"NSPinnedCAIdentities"] boolValue];
+        int NSPinnedCAIdentitiesCount = [expectedProperties[@"NSPinnedCAIdentitiesCount"] intValue];
+        bool hasNSIncludesSubdomains = [expectedProperties[@"NSIncludesSubdomains"] boolValue];
+
+        CFDictionaryRef nsPinnedDomainsDict = [self getNSPinnedDomainsFromDictionaryInfoFile:plistFileName];
+        if (!isDictionary(nsPinnedDomainsDict)) {
+            fail("Unable to read %@", plistFileName);
+            return;
+        }
+        CFArrayRef leafSPKISHA256 = parseNSPinnedDomains(nsPinnedDomainsDict, CFSTR("example.org"), CFSTR("NSPinnedLeafIdentities"));
+        is(leafSPKISHA256 != NULL, hasNSPinnedLeafIdentities, "leafSPKISHA256 test failed in \"%@\"", plistFileName);
+        is(leafSPKISHA256 != NULL && CFArrayGetCount(leafSPKISHA256) != 0, NSPinnedLeafIdentitiesCount != 0, "leafSPKISHA256 count test failed in \"%@\"", plistFileName);
+
+        CFArrayRef caSPKISHA256 = parseNSPinnedDomains(nsPinnedDomainsDict, CFSTR("example.org"), CFSTR("NSPinnedCAIdentities"));
+        is(caSPKISHA256 != NULL, hasNSPinnedCAIdentities, "caSPKISHA256 test failed in \"%@\"", plistFileName);
+        is(caSPKISHA256 != NULL && CFArrayGetCount(caSPKISHA256) != 0, NSPinnedCAIdentitiesCount != 0, "caSPKISHA256 count test failed in \"%@\"", plistFileName);
+
+        caSPKISHA256 = parseNSPinnedDomains(nsPinnedDomainsDict, CFSTR("subdomain.example.org."), CFSTR("NSPinnedCAIdentities"));
+        is(caSPKISHA256 != NULL, hasNSIncludesSubdomains, "caSPKISHA256 subdomain test failed in \"%@\"", plistFileName);
+    }];
+}
+
 @end
diff --git a/tests/TrustTests/EvaluationTests/SMIMEPolicyTests.m b/tests/TrustTests/EvaluationTests/SMIMEPolicyTests.m
new file mode 100644 (file)
index 0000000..5f95a8f
--- /dev/null
@@ -0,0 +1,439 @@
+//
+//  SMIMEPolicyTests.m
+//  Security
+//
+//  Created by Bailey Basile on 11/5/19.
+//
+
+#import <Foundation/Foundation.h>
+
+#include <Security/SecPolicyPriv.h>
+#include <utilities/SecCFWrappers.h>
+
+#import "../TrustEvaluationTestHelpers.h"
+#import "TrustEvaluationTestCase.h"
+
+@interface SMIMEPolicyTests : TrustEvaluationTestCase
+@end
+
+NSString *testDir = @"SMIMEPolicyTests-data";
+const CFStringRef emailAddr = CFSTR("test@example.com");
+
+@implementation SMIMEPolicyTests
+
+- (NSArray *)anchors
+{
+    id root = [self SecCertificateCreateFromResource:@"root" subdirectory:testDir];
+    NSArray *anchors = @[root];
+    CFRelease((SecCertificateRef)root);
+    return anchors;
+}
+
+- (NSDate *)verifyDate
+{
+    return [NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]; // January 6, 2020 at 2:40:00 AM PST
+}
+
+- (bool)runTrustEvalForLeaf:(id)leaf policy:(SecPolicyRef)policy
+{
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[leaf] policies:@[(__bridge id)policy]];
+    XCTAssertNotNil(eval);
+    [eval setAnchors:[self anchors]];
+    [eval setVerifyDate:[self verifyDate]];
+    return [eval evaluate:nil];
+}
+
+// MARK: Expiration tests
+
+- (void)testCheckExpiration
+{
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, emailAddr);
+    id leaf = [self SecCertificateCreateFromResource:@"email_protection" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Within validity
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[leaf] policies:@[(__bridge id)policy]];
+    XCTAssertNotNil(eval);
+    [eval setAnchors:[self anchors]];
+    [eval setVerifyDate:[self verifyDate]];
+    XCTAssert([eval evaluate:nil]);
+
+    // Expired
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:630000000.0]]; // December 18, 2020 at 8:00:00 AM PST
+    XCTAssertFalse([eval evaluate:nil]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testIgnoreExpiration
+{
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage | kSecIgnoreExpirationSMIMEUsage, emailAddr);
+    id leaf = [self SecCertificateCreateFromResource:@"email_protection" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Within validity
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[leaf] policies:@[(__bridge id)policy]];
+    XCTAssertNotNil(eval);
+    [eval setAnchors:[self anchors]];
+    [eval setVerifyDate:[self verifyDate]];
+    XCTAssert([eval evaluate:nil]);
+
+    // Expired
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:630000000.0]]; // December 18, 2020 at 8:00:00 AM PST
+    XCTAssert([eval evaluate:nil]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+// MARK: Name tests
+
+- (void)testNoEmailName
+{
+    id leaf = [self SecCertificateCreateFromResource:@"no_name" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Check Email name
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Skip email name check
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, NULL);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testEmailNameSAN
+{
+    id leaf = [self SecCertificateCreateFromResource:@"san_name" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Address match
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Address mismatch
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, CFSTR("wrong@example.com"));
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Case-insensitive match
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, CFSTR("TEST@example.com"));
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testEmailCommonName
+{
+    id leaf = [self SecCertificateCreateFromResource:@"common_name" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Address match but common name matches not supported
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testEmailAddressField
+{
+    id leaf = [self SecCertificateCreateFromResource:@"email_field" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Address match but subject name matches not supported
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Address mismatch
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, CFSTR("wrong@example.com"));
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Case-insensitive match
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME | kSecSignSMIMEUsage, CFSTR("TEST@example.com"));
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+// MARK: KU tests
+- (void)testNoKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"san_name" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for sign KU (which allows unspecified KU)
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for sign KU or any encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage | kSecAnyEncryptSMIME, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Don't look at KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(0, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testSignKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"digital_signature" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for sign KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for sign KU or any encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage | kSecAnyEncryptSMIME, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testNonRepudiationKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"non_repudiation" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for sign KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for sign KU or any encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage | kSecAnyEncryptSMIME, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // No KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(0, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testKeyEncipherKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"key_encipher" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Key Encipher KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecKeyEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for any encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Data Encipher KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecDataEncryptSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testDataEncipherKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"data_encipher" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Data Encipher KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecDataEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for any encrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Encipher KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyEncryptSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testKeyAgreementKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"key_agreement" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Key Agreement Encrypt KU /* <rdar://57130017> */
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecKeyExchangeEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Decrypt KU /* <rdar://57130017> */
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeDecryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Both KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Digital Signature KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testKeyAgreementEncipherOnlyKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"key_agreement_encipher_only" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Key Agreement Encrypt KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecKeyExchangeEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Decrypt KU /* <rdar://57130017> */
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeDecryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Both KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Digital Signature KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testKeyAgreementDecipherOnlyKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"key_agreement_decipher_only" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Key Agreement Encrypt KU /* <rdar://57130017> */
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecKeyExchangeEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Decrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeDecryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Both KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Digital Signature KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testKeyAgreementBothKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"key_agreement_encipher_decipher" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    // Look for Key Agreement Encrypt KU
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecKeyExchangeEncryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Decrypt KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeDecryptSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Key Agreement Both KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    // Look for Digital Signature KU
+    CFReleaseNull(policy);
+    policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+// MARK: EKU tests
+- (void)testNoEKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"digital_signature" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testAnyEKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"any_eku" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssertFalse([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+- (void)testEmailEKU
+{
+    id leaf = [self SecCertificateCreateFromResource:@"email_protection" subdirectory:testDir];
+    XCTAssertNotNil(leaf);
+
+    SecPolicyRef policy = SecPolicyCreateSMIME(kSecSignSMIMEUsage, emailAddr);
+    XCTAssert([self runTrustEvalForLeaf:leaf policy:policy]);
+
+    CFReleaseNull(policy);
+    CFRelease((SecCertificateRef)leaf);
+}
+
+@end
index 79f32b67b35bdef730b0706f3988f9e4acd23264..df056ea2aa440acca07b748a7a9d4e5294af1040 100644 (file)
@@ -36,6 +36,8 @@
 #include "SSLPolicyTests_data.h"
 #import "TrustEvaluationTestCase.h"
 
+NSString * const testDirectory = @"ssl-policy-certs";
+
 @interface SSLPolicyTests : TrustEvaluationTestCase
 @end
 
@@ -43,7 +45,7 @@
 
 - (void)testSSLPolicyCerts
 {
-    NSArray *testPlistURLs = [[NSBundle bundleForClass:[self class]] URLsForResourcesWithExtension:@"plist" subdirectory:@"ssl-policy-certs"];
+    NSArray *testPlistURLs = [[NSBundle bundleForClass:[self class]] URLsForResourcesWithExtension:@"plist" subdirectory:testDirectory];
     if (testPlistURLs.count != 1) {
         fail("failed to find the test plist");
         return;
@@ -75,7 +77,7 @@
         require_action_quiet(file, cleanup, fail("%@: Unable to load filename from plist", test_name));
 
         /* get leaf certificate from file */
-        cert_file_url = [[NSBundle bundleForClass:[self class]] URLForResource:(__bridge NSString *)file withExtension:@"cer" subdirectory:@"ssl-policy-certs"];
+        cert_file_url = [[NSBundle bundleForClass:[self class]] URLForResource:(__bridge NSString *)file withExtension:@"cer" subdirectory:testDirectory];
         require_action_quiet(cert_file_url, cleanup, fail("%@: Unable to get url for cert file %@",
                                                           test_name, file));
 
 }
 
 - (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors error:(NSError **)error
+{
+    return [self runTrustEvaluation:certs anchors:anchors date:590000000.0 error:error]; // September 12, 2019 at 9:53:20 AM PDT
+}
+
+- (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors date:(NSTimeInterval)evalTime error:(NSError **)error
 {
     SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("example.com"));
-    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:590000000.0]; // September 12, 2019 at 9:53:20 AM PDT
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:evalTime];
     SecTrustRef trustRef = NULL;
     BOOL result = NO;
     CFErrorRef cferror = NULL;
@@ -224,6 +231,116 @@ errOut:
     CFReleaseNull(root);
 }
 
+- (void)testSystemTrust_subCAMissingEKU
+{
+    SecCertificateRef systemRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_Root"
+                                                                                         subdirectory:testDirectory];
+    NSData *rootHash = CFBridgingRelease(SecCertificateCopySHA256Digest(systemRoot));
+    [self setTestRootAsSystem:(const uint8_t *)[rootHash bytes]];
+
+    SecCertificateRef subCa = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_noEKU_ca"
+                                                                                    subdirectory:testDirectory];
+    SecCertificateRef leaf = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_noEKU_leaf"
+                                                                                    subdirectory:testDirectory];
+    NSArray *certs = @[(__bridge id)leaf, (__bridge id)subCa];
+    NSError *error = nil;
+    XCTAssertTrue([self runTrustEvaluation:certs anchors:@[(__bridge id)systemRoot] date:620000000.0 error:&error], //August 24, 2020 at 3:13:20 PM PDT
+                  "system-trusted no EKU subCA cert failed: %@", error);
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(systemRoot);
+    CFReleaseNull(subCa);
+    CFReleaseNull(leaf);
+}
+
+- (void)testSystemTrust_subCAAnyEKU
+{
+    SecCertificateRef systemRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_Root"
+                                                                                         subdirectory:testDirectory];
+    NSData *rootHash = CFBridgingRelease(SecCertificateCopySHA256Digest(systemRoot));
+    [self setTestRootAsSystem:(const uint8_t *)[rootHash bytes]];
+
+    SecCertificateRef subCa = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_anyEKU_ca"
+                                                                                    subdirectory:testDirectory];
+    SecCertificateRef leaf = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_anyEKU_leaf"
+                                                                                    subdirectory:testDirectory];
+    NSArray *certs = @[(__bridge id)leaf, (__bridge id)subCa];
+    NSError *error = nil;
+    XCTAssertTrue([self runTrustEvaluation:certs anchors:@[(__bridge id)systemRoot] date:620000000.0 error:&error], //August 24, 2020 at 3:13:20 PM PDT
+                  "system-trusted anyEKU subCA cert failed: %@", error);
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(systemRoot);
+    CFReleaseNull(subCa);
+    CFReleaseNull(leaf);
+}
+
+- (void)testSystemTrust_subCAServerAuthEKU
+{
+    SecCertificateRef systemRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_Root"
+                                                                                         subdirectory:testDirectory];
+    NSData *rootHash = CFBridgingRelease(SecCertificateCopySHA256Digest(systemRoot));
+    [self setTestRootAsSystem:(const uint8_t *)[rootHash bytes]];
+
+    SecCertificateRef subCa = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_ssl_ca"
+                                                                                    subdirectory:testDirectory];
+    SecCertificateRef leaf = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_ssl_leaf"
+                                                                                    subdirectory:testDirectory];
+    NSArray *certs = @[(__bridge id)leaf, (__bridge id)subCa];
+    NSError *error = nil;
+    XCTAssertTrue([self runTrustEvaluation:certs anchors:@[(__bridge id)systemRoot] date:620000000.0 error:&error], //August 24, 2020 at 3:13:20 PM PDT
+                  "system-trusted SSL EKU subCA cert failed: %@", error);
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(systemRoot);
+    CFReleaseNull(subCa);
+    CFReleaseNull(leaf);
+}
+
+- (void)testSystemTrust_subCA_SMIME_EKU
+{
+    SecCertificateRef systemRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_Root"
+                                                                                         subdirectory:testDirectory];
+    NSData *rootHash = CFBridgingRelease(SecCertificateCopySHA256Digest(systemRoot));
+    [self setTestRootAsSystem:(const uint8_t *)[rootHash bytes]];
+
+    SecCertificateRef subCa = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_smime_ca"
+                                                                                    subdirectory:testDirectory];
+    SecCertificateRef leaf = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_smime_leaf"
+                                                                                    subdirectory:testDirectory];
+    NSArray *certs = @[(__bridge id)leaf, (__bridge id)subCa];
+    NSError *error = nil;
+    XCTAssertFalse([self runTrustEvaluation:certs anchors:@[(__bridge id)systemRoot] date:620000000.0 error:&error], //August 24, 2020 at 3:13:20 PM PDT
+                   "system-trusted SMIME subCA cert succeeded");
+    XCTAssertNotNil(error);
+    if (error) {
+        XCTAssertEqual(error.code, errSecInvalidExtendedKeyUsage);
+    }
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(systemRoot);
+    CFReleaseNull(subCa);
+    CFReleaseNull(leaf);
+}
+
+- (void)testAppTrust_subCA_SMIME_EKU
+{
+    SecCertificateRef systemRoot = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_Root"
+                                                                                         subdirectory:testDirectory];
+    SecCertificateRef subCa = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_smime_ca"
+                                                                                    subdirectory:testDirectory];
+    SecCertificateRef leaf = (__bridge SecCertificateRef)[self SecCertificateCreateFromResource:@"subCA_EKU_smime_leaf"
+                                                                                    subdirectory:testDirectory];
+    NSArray *certs = @[(__bridge id)leaf, (__bridge id)subCa];
+    NSError *error = nil;
+    XCTAssertTrue([self runTrustEvaluation:certs anchors:@[(__bridge id)systemRoot] date:620000000.0 error:&error], //August 24, 2020 at 3:13:20 PM PDT
+                  "app-trusted smime subCA cert failed: %@", error);
+
+    CFReleaseNull(systemRoot);
+    CFReleaseNull(subCa);
+    CFReleaseNull(leaf);
+}
+
 // Other app trust of root SSL EKU tests of certs issued before July 2019 occur in testSSLPolicyCerts (Test4, Test17)
 
 - (void)testAppTrustRoot_AnyEKU_BeforeJul2019
@@ -396,4 +513,74 @@ errOut:
 }
 #endif // !TARGET_OS_BRIDGE
 
+- (void)testIPAddressInDNSField
+{
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _ipAddress_dnsField, sizeof(_ipAddress_dnsField));
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("10.0.0.1"));
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[(__bridge id)cert]
+                                                                         policies:@[(__bridge id)policy]];
+    [eval setAnchors:@[(__bridge id)cert]];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]];
+    XCTAssertFalse([eval evaluate:nil]);
+
+    CFReleaseNull(cert);
+    CFReleaseNull(policy);
+}
+
+- (void)testIPAddressInSAN_Match
+{
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _ipAddress_SAN, sizeof(_ipAddress_SAN));
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("10.0.0.1"));
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[(__bridge id)cert]
+                                                                         policies:@[(__bridge id)policy]];
+    [eval setAnchors:@[(__bridge id)cert]];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]];
+    XCTAssert([eval evaluate:nil]);
+
+    CFReleaseNull(cert);
+    CFReleaseNull(policy);
+}
+
+- (void)testIPAddressInSAN_Mismatch
+{
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _ipAddress_SAN, sizeof(_ipAddress_SAN));
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("10.0.0.2"));
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[(__bridge id)cert]
+                                                                         policies:@[(__bridge id)policy]];
+    [eval setAnchors:@[(__bridge id)cert]];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]];
+    XCTAssertFalse([eval evaluate:nil]);
+
+    CFReleaseNull(cert);
+    CFReleaseNull(policy);
+}
+
+- (void)testIPAddressInCN
+{
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _ipAddress_CN, sizeof(_ipAddress_CN));
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("10.0.0.1"));
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[(__bridge id)cert]
+                                                                         policies:@[(__bridge id)policy]];
+    [eval setAnchors:@[(__bridge id)cert]];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]];
+    XCTAssertFalse([eval evaluate:nil]);
+
+    CFReleaseNull(cert);
+    CFReleaseNull(policy);
+}
+
+- (void)testBadIPAddressInSAN
+{
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _ipAddress_bad, sizeof(_ipAddress_bad));
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("10.0.0.1"));
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[(__bridge id)cert]
+                                                                         policies:@[(__bridge id)policy]];
+    [eval setAnchors:@[(__bridge id)cert]];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]];
+    XCTAssertFalse([eval evaluate:nil]);
+
+    CFReleaseNull(cert);
+    CFReleaseNull(policy);
+}
+
 @end
index 3a03abbfe880ca55ebb490f7629829da1f713c31..52fcd7ca5c1b480144f02321a5a42f307baf03bc 100644 (file)
@@ -619,4 +619,294 @@ const uint8_t _anyEKU_AfterJul2019[] = {
     0x49,0x64,0x81,0x31,0x5C,0x52,0x1A,0x7C,0x32,0x4A,0xB8,0xA6,0xE7,0xDD,0x95,0xD3,
     0x2A,0x2C,0x2D,0x1C,0x57,0xC2,0x69,0xA2,0x3F,0xF9,0x6D,0xD3,0x0B,
 };
+
+/*  X509v3 Subject Alternative Name:
+       DNS:10.0.0.1 */
+const uint8_t _ipAddress_dnsField[] = {
+    0x30,0x82,0x04,0x4D,0x30,0x82,0x03,0x35,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xD6,0xAF,0xD0,0x9F,0x40,0x03,0x75,0x00,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x9E,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x0C,0x29,0x53,
+    0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,
+    0x20,0x49,0x50,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x20,0x69,0x6E,0x20,0x44,
+    0x4E,0x53,0x20,0x66,0x69,0x65,0x6C,0x64,0x30,0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,
+    0x30,0x38,0x30,0x30,0x30,0x32,0x30,0x39,0x5A,0x17,0x0D,0x32,0x30,0x31,0x31,0x30,
+    0x37,0x30,0x30,0x30,0x32,0x30,0x39,0x5A,0x30,0x81,0x9E,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,
+    0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,
+    0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
+    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
+    0x65,0x72,0x69,0x6E,0x67,0x31,0x32,0x30,0x30,0x06,0x03,0x55,0x04,0x03,0x0C,0x29,
+    0x53,0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x54,0x65,0x73,0x74,0x73,
+    0x3A,0x20,0x49,0x50,0x20,0x61,0x64,0x64,0x72,0x65,0x73,0x73,0x20,0x69,0x6E,0x20,
+    0x44,0x4E,0x53,0x20,0x66,0x69,0x65,0x6C,0x64,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,0xCD,0x1E,0x25,0xBC,0xE6,0xAA,
+    0x54,0x69,0x1C,0xA2,0x0F,0x2F,0x25,0xA5,0xFB,0xB3,0x05,0xAB,0x88,0x6A,0x8E,0x0C,
+    0x00,0xC7,0x5C,0x1A,0x3C,0x2A,0xBA,0xCE,0xEA,0x0B,0xEC,0x20,0xA4,0xC1,0xEB,0x80,
+    0xDB,0x04,0xE5,0x17,0xFA,0x9C,0x6A,0x3C,0xE1,0xB5,0x29,0x74,0x43,0x49,0x6C,0xAB,
+    0x11,0x10,0xB9,0xF3,0xB4,0x8C,0x62,0xA0,0x26,0x9B,0x54,0xDA,0x5F,0x6C,0x09,0x95,
+    0xFB,0xE3,0xBA,0x3E,0xB4,0x68,0x28,0x19,0x36,0xB4,0x7C,0x13,0x48,0xE8,0x68,0xA5,
+    0x15,0x3B,0xBD,0x57,0xD7,0x21,0x2C,0xC1,0x26,0x82,0xC1,0x66,0x96,0x71,0xF8,0x72,
+    0xBD,0xB5,0x8A,0x93,0x9A,0xF2,0x26,0xC8,0xEE,0x15,0x1F,0xBF,0x82,0x5D,0x14,0x52,
+    0x69,0x12,0x14,0x2A,0x6F,0x0E,0x2C,0xEE,0x67,0x6A,0xEB,0xC0,0xF9,0x38,0x27,0xD1,
+    0x4E,0xF3,0x94,0x2E,0x0B,0x93,0xB9,0x0F,0x81,0xA0,0x1E,0x6E,0x0D,0x6E,0x35,0x82,
+    0x96,0x1F,0x1A,0x76,0xEA,0x5C,0x89,0x09,0xFE,0x6F,0x8B,0x56,0x82,0xB6,0x02,0x5A,
+    0x38,0x31,0x87,0x15,0xE0,0x55,0xFF,0xE9,0xF4,0x39,0xF7,0xFA,0xC0,0xE5,0xA2,0x1B,
+    0x2A,0xAF,0x53,0xF0,0x4F,0xB8,0xE8,0xA6,0x01,0xF9,0x84,0xFE,0x6F,0xAE,0xFF,0xFD,
+    0x65,0x7C,0x7A,0xFF,0xC4,0xB4,0xA5,0x69,0xD0,0x6F,0xDF,0x19,0xC6,0xEC,0x42,0x1C,
+    0x2D,0x5D,0xCC,0x71,0x3E,0x02,0xE3,0x5A,0xCA,0xDB,0x62,0x06,0x19,0xBE,0xCB,0x1E,
+    0xDD,0x27,0x7D,0x00,0x8F,0x31,0x73,0x43,0x27,0x0A,0x5B,0x5C,0x9B,0xDF,0x20,0x5F,
+    0xF1,0x76,0x31,0xAB,0x34,0xA9,0x20,0x1A,0xCB,0xE7,0x02,0x03,0x01,0x00,0x01,0xA3,
+    0x81,0x8B,0x30,0x81,0x88,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,
+    0x02,0x30,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,
+    0x02,0x07,0x80,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,
+    0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x13,0x06,0x03,0x55,0x1D,0x11,0x04,
+    0x0C,0x30,0x0A,0x82,0x08,0x31,0x30,0x2E,0x30,0x2E,0x30,0x2E,0x31,0x30,0x1D,0x06,
+    0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x83,0xE0,0x4A,0x14,0xAD,0x61,0x5B,0xD2,
+    0x79,0xA2,0x5E,0x9C,0x45,0xAC,0xD8,0x35,0x8B,0xF4,0x43,0x09,0x30,0x1F,0x06,0x03,
+    0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x83,0xE0,0x4A,0x14,0xAD,0x61,0x5B,
+    0xD2,0x79,0xA2,0x5E,0x9C,0x45,0xAC,0xD8,0x35,0x8B,0xF4,0x43,0x09,0x30,0x0D,0x06,
+    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,
+    0x00,0x45,0x79,0xD6,0x5F,0x71,0x88,0x20,0x8C,0x6D,0x5C,0x89,0x7D,0xD8,0x6E,0x48,
+    0x21,0x8B,0xA7,0x14,0xD3,0xC5,0xA7,0xE1,0xFE,0xB4,0x9A,0x6A,0x72,0xD5,0x40,0xFF,
+    0xBE,0x02,0x49,0x89,0x13,0x4D,0xAE,0xCD,0x9E,0x27,0xA2,0x0E,0xD1,0xBA,0xA5,0xB9,
+    0x08,0x30,0xEB,0x8E,0xE9,0xCF,0xD5,0x80,0xA0,0x0A,0x0D,0x38,0x71,0x2B,0x31,0x02,
+    0x14,0x42,0x98,0x41,0x3F,0x26,0x32,0x8D,0x1B,0x56,0xAB,0x9F,0x3D,0x94,0xFD,0xBB,
+    0xD2,0xF7,0x2E,0xE2,0xA9,0xD3,0xFF,0x0C,0xDA,0x8D,0x8B,0x56,0x55,0x80,0x9A,0xF3,
+    0xA2,0x44,0xB8,0x23,0xD5,0x03,0x27,0x11,0xC9,0x03,0x64,0xE9,0x24,0xAA,0x60,0x4A,
+    0x93,0x04,0xF8,0xEA,0x66,0x9C,0x7A,0xE9,0x99,0x7E,0xA2,0x22,0x72,0x37,0xA7,0xCC,
+    0xD5,0x0A,0xFA,0xC2,0xEA,0x25,0x0A,0xD0,0x7A,0xAD,0x60,0xD6,0x81,0xA3,0x80,0xD6,
+    0xE6,0xB2,0xA9,0x6E,0x88,0xC2,0x58,0xD0,0xC7,0x0B,0xBD,0xD8,0xF6,0xD0,0x51,0x08,
+    0x00,0x93,0x07,0x35,0x35,0x29,0x7B,0xA7,0x59,0x4E,0xD8,0x17,0x15,0x50,0xE6,0xEA,
+    0xA2,0xB6,0x94,0x78,0xE9,0x76,0x3A,0xFF,0xB0,0xD5,0x9E,0xE8,0xBE,0xD5,0xD8,0x3F,
+    0xA1,0xA0,0xC6,0x79,0x54,0x4A,0x1A,0xE0,0xAA,0xFE,0x51,0x82,0x3B,0x75,0xC8,0x03,
+    0xD9,0x02,0x98,0xE9,0x30,0x79,0x58,0x93,0xD1,0x27,0x1F,0x11,0x58,0x49,0x33,0x82,
+    0xE5,0x09,0x6F,0xE2,0xD0,0xA2,0x9D,0x29,0x49,0x85,0xAF,0x5E,0xB2,0xE7,0x9C,0x56,
+    0x4E,0x73,0x5E,0x85,0x64,0x58,0x7D,0xE6,0xB4,0x07,0x8B,0x7B,0x12,0x80,0x6F,0x7A,
+    0x3C,
+};
+
+/*  X509v3 Subject Alternative Name:
+        IP Address:10.0.0.1 */
+const uint8_t _ipAddress_SAN[] = {
+    0x30,0x82,0x04,0x37,0x30,0x82,0x03,0x1F,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xC7,0x90,0xC5,0x69,0xCA,0xE3,0xB4,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,
+    0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,
+    0x20,0x49,0x50,0x20,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x20,0x53,0x41,0x4E,0x30,
+    0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,0x30,0x38,0x30,0x30,0x31,0x34,0x32,0x31,0x5A,
+    0x17,0x0D,0x32,0x30,0x31,0x31,0x30,0x37,0x30,0x30,0x31,0x34,0x32,0x31,0x5A,0x30,
+    0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
+    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
+    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
+    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
+    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,
+    0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,0x20,0x49,0x50,0x20,0x41,0x64,0x64,0x72,
+    0x65,0x73,0x73,0x20,0x53,0x41,0x4E,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,0xC1,0x80,0xDE,0x51,0x33,0xB8,0x28,0xA8,
+    0x7D,0x94,0x12,0x73,0x6F,0x0E,0xFC,0xF5,0xF0,0xC6,0x18,0xD2,0x87,0xB8,0x37,0xEE,
+    0xF9,0xB1,0x69,0x1D,0xF9,0xE1,0x65,0x8D,0x47,0x34,0x50,0xBD,0x72,0x41,0x32,0x7A,
+    0x02,0x0F,0x72,0x85,0xB8,0xE1,0x3D,0x7C,0x78,0x90,0x0A,0x81,0x06,0x25,0x9B,0x13,
+    0xCA,0xD6,0xAA,0x77,0xDC,0x4A,0x9B,0x32,0xB7,0x1D,0xF1,0xEF,0x52,0x33,0xE3,0x5D,
+    0x80,0xE0,0xE1,0xBB,0xF2,0x5E,0x91,0x55,0xA1,0xF8,0xE4,0x25,0x62,0xAB,0xBA,0x3D,
+    0x42,0xEB,0x9B,0xD7,0x95,0x92,0x18,0x26,0x5F,0xB1,0x28,0x9B,0x01,0xDB,0x52,0x18,
+    0xFE,0xF4,0x4F,0xD6,0x3A,0x49,0x13,0xE2,0xB0,0x06,0xEF,0x28,0x6C,0x89,0xFD,0x23,
+    0x19,0x56,0xF7,0x1A,0x51,0x89,0x5C,0x13,0xDD,0xD6,0x55,0x70,0x17,0xCA,0x05,0x59,
+    0x77,0xEA,0x75,0xA4,0x44,0x05,0x49,0xD3,0xD6,0xE4,0x04,0x74,0xC8,0x5F,0xF9,0x19,
+    0x75,0x27,0xB2,0x17,0x6B,0x2E,0x45,0xE5,0x07,0xBD,0x17,0x70,0xFD,0xA2,0x6A,0xF7,
+    0xF1,0xD8,0x43,0xBC,0xF6,0xCD,0xD1,0x2D,0xE0,0xF0,0x55,0xE7,0x60,0xA5,0x09,0x42,
+    0xE6,0x67,0xB6,0x40,0x56,0x4E,0x3E,0xDF,0x7B,0x89,0x44,0x36,0x78,0x83,0x30,0x25,
+    0x12,0xFF,0x48,0x97,0xC1,0x04,0x87,0xC7,0xA3,0x06,0xCE,0x06,0xCE,0x2F,0xAE,0x01,
+    0x42,0x57,0x62,0x3B,0xDA,0xEB,0xD8,0xDB,0x96,0x5E,0xFC,0x1E,0x30,0x4B,0xE4,0x80,
+    0xE1,0xD9,0x34,0x03,0x9C,0xD4,0x92,0x39,0x17,0xA8,0xCD,0xCA,0x96,0x54,0xEB,0x2D,
+    0x12,0x77,0xE3,0x96,0x09,0x6D,0xBB,0x93,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x87,
+    0x30,0x81,0x84,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,
+    0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,
+    0x80,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x0F,0x06,0x03,0x55,0x1D,0x11,0x04,0x08,0x30,
+    0x06,0x87,0x04,0x0A,0x00,0x00,0x01,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,
+    0x04,0x14,0xE0,0xA6,0x7D,0x62,0x28,0x6C,0xC0,0xCE,0x46,0xC8,0x04,0xB0,0xBA,0xB9,
+    0x9B,0xF6,0x4A,0x60,0xBF,0xA9,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,
+    0x16,0x80,0x14,0xE0,0xA6,0x7D,0x62,0x28,0x6C,0xC0,0xCE,0x46,0xC8,0x04,0xB0,0xBA,
+    0xB9,0x9B,0xF6,0x4A,0x60,0xBF,0xA9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x55,0xBB,0x48,0x72,0x61,
+    0x8F,0xAF,0x7F,0x18,0x2F,0x31,0xF9,0xAA,0xFF,0x4A,0xC1,0x5B,0xBF,0x45,0xFE,0x82,
+    0x3C,0xBE,0xFC,0xBB,0x58,0xA7,0x4A,0xF3,0x84,0xF8,0x10,0xB4,0x51,0x33,0x91,0xA0,
+    0x58,0x1C,0x5F,0x67,0x91,0x31,0xD8,0xEC,0xA0,0x6A,0x85,0x84,0x71,0xBE,0xB5,0x18,
+    0xAC,0xB8,0x7E,0xC3,0xFC,0x1C,0x74,0x84,0x48,0x2C,0x99,0xE9,0x52,0xBB,0x36,0x00,
+    0x35,0x8C,0x50,0xC8,0x13,0x2A,0xFA,0x1E,0xF8,0x15,0x72,0xEF,0xF0,0x20,0x28,0xA0,
+    0xCD,0xC7,0x85,0xEF,0x48,0x8C,0x27,0xF9,0x0E,0x15,0x9F,0xB8,0x54,0xD1,0x44,0x08,
+    0x31,0xB0,0xC8,0x24,0x53,0x4A,0x63,0x97,0xB5,0xB3,0x83,0x07,0xCD,0x6D,0xC5,0x10,
+    0xDD,0xC0,0x90,0xA2,0xFF,0x8E,0xD5,0x2F,0xC4,0xBC,0x8A,0xE0,0x90,0xAA,0x79,0x09,
+    0xB5,0x23,0x72,0x6A,0xFB,0x9B,0xE5,0x0E,0xD9,0x30,0x41,0x70,0xF1,0x17,0x9C,0x5F,
+    0xD7,0x0A,0x10,0x8E,0x77,0xD9,0x2F,0x59,0xE4,0xB4,0xF6,0x8D,0x16,0x90,0x84,0xBB,
+    0xB6,0xAF,0xEE,0x86,0x4D,0x21,0xAE,0x3E,0x7B,0x2F,0xAD,0xBD,0xC4,0x38,0x9C,0x9E,
+    0xB5,0x7C,0x8D,0x36,0x72,0x2C,0x78,0xC7,0xD4,0x54,0xD9,0x93,0x18,0xC8,0x00,0x5E,
+    0xFE,0x12,0xE4,0x50,0x90,0x88,0xFB,0x82,0xFE,0x94,0xA5,0x4C,0xEB,0x7F,0xB7,0x39,
+    0x99,0x24,0x0B,0x23,0xF9,0xB4,0x92,0xA8,0x6F,0xA6,0x46,0xBB,0xFB,0xDA,0xCD,0x8F,
+    0xB9,0x14,0xE8,0x9B,0xBB,0x1B,0x80,0x9E,0x9D,0x9A,0x16,0xFF,0xF1,0x55,0xFF,0xDF,
+    0x3E,0x32,0x73,0x16,0x9D,0xEA,0xF0,0xB1,0x5A,0x12,0xAB,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=10.0.0.1 */
+const uint8_t _ipAddress_CN[] = {
+    0x30,0x82,0x03,0xF2,0x30,0x82,0x02,0xDA,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xD8,0xED,0xBE,0x22,0x56,0xD4,0x12,0x16,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x7D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,
+    0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,
+    0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,
+    0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,
+    0x69,0x6E,0x67,0x31,0x11,0x30,0x0F,0x06,0x03,0x55,0x04,0x03,0x0C,0x08,0x31,0x30,
+    0x2E,0x30,0x2E,0x30,0x2E,0x31,0x30,0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,0x30,0x38,
+    0x30,0x31,0x32,0x32,0x32,0x32,0x5A,0x17,0x0D,0x32,0x30,0x31,0x31,0x30,0x37,0x30,
+    0x31,0x32,0x32,0x32,0x32,0x5A,0x30,0x7D,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,
+    0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,
+    0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,
+    0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,
+    0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,
+    0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,
+    0x6E,0x67,0x31,0x11,0x30,0x0F,0x06,0x03,0x55,0x04,0x03,0x0C,0x08,0x31,0x30,0x2E,
+    0x30,0x2E,0x30,0x2E,0x31,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,0xF3,0x54,0x35,0x8B,0xF0,0x54,0x65,0xA4,0x26,0x6D,
+    0xFE,0x08,0x28,0x12,0x36,0x03,0x05,0xD7,0x23,0x92,0x7A,0xEB,0x61,0x9D,0xEE,0x67,
+    0x5E,0x48,0x86,0x1F,0x2F,0x66,0x6B,0x71,0x56,0xC3,0xA0,0x20,0x13,0x76,0xEC,0x6A,
+    0x53,0x59,0xAE,0xD3,0x61,0x1E,0xE7,0xEC,0x15,0xBD,0xB7,0x46,0x6C,0x8D,0x65,0x1F,
+    0xAA,0x1C,0x7C,0x9A,0xB6,0xFD,0xEF,0x94,0x63,0xDC,0x12,0x0A,0x65,0x86,0x6D,0x1B,
+    0xAC,0xD7,0xD0,0x47,0x92,0x10,0x9E,0x21,0x50,0xD5,0x2D,0x2F,0xA3,0xB8,0x1F,0xA3,
+    0xB4,0xB6,0xA9,0x5C,0xED,0x3B,0x49,0xB7,0x3B,0xEA,0x02,0x9F,0xFB,0xE3,0x1C,0x6A,
+    0xBB,0xE4,0x10,0x64,0x77,0xF9,0x8A,0x7B,0x4D,0x3E,0xC7,0xFF,0xE4,0x41,0x10,0xDE,
+    0xB5,0xDD,0xB9,0xFA,0x02,0x3B,0xBA,0x10,0x83,0x0C,0x82,0x5C,0x6D,0xEF,0x64,0xEC,
+    0xA8,0x12,0xAA,0x0B,0xC9,0x48,0x43,0xD0,0x6F,0x06,0x6E,0x8F,0xB6,0x87,0xBC,0x57,
+    0x01,0xB7,0xD0,0x2F,0xC7,0x6F,0xAC,0x95,0xDA,0xE0,0xD7,0x64,0x9B,0xD5,0xE0,0xFD,
+    0x62,0xF8,0xD1,0x46,0x20,0xD8,0x67,0x45,0xD3,0xC0,0x48,0x54,0xFD,0x0E,0x0D,0xBE,
+    0x05,0xAB,0x81,0x23,0x25,0x90,0x51,0xB8,0x4D,0xA8,0x97,0xDE,0x2F,0xD3,0x7B,0x1B,
+    0x24,0xEF,0x83,0x0B,0xC1,0x25,0x9C,0x7D,0x6E,0x47,0x1D,0x3A,0xE0,0x4D,0x64,0x03,
+    0x11,0x79,0x15,0xB4,0xB2,0x88,0x29,0x37,0x02,0x71,0xF4,0x3A,0x73,0xB2,0x03,0x4F,
+    0xD6,0x5B,0xEB,0x2E,0xB5,0xF6,0x1B,0x0E,0x14,0xD5,0x89,0x79,0xBC,0x38,0xA2,0xF1,
+    0x9F,0x26,0xB5,0xC1,0x26,0xC7,0x02,0x03,0x01,0x00,0x01,0xA3,0x75,0x30,0x73,0x30,
+    0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,0x0E,0x06,
+    0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,0x80,0x30,0x13,0x06,
+    0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x03,0x01,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x40,0x73,0xD8,
+    0x0F,0xE3,0xF0,0x6B,0x0A,0x00,0x5B,0x94,0x31,0x23,0x56,0xC1,0xC2,0x12,0xF6,0xA8,
+    0x33,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x40,0x73,
+    0xD8,0x0F,0xE3,0xF0,0x6B,0x0A,0x00,0x5B,0x94,0x31,0x23,0x56,0xC1,0xC2,0x12,0xF6,
+    0xA8,0x33,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
+    0x00,0x03,0x82,0x01,0x01,0x00,0xBA,0x76,0xA7,0x28,0x46,0xFD,0x2A,0x5A,0x96,0x51,
+    0xEC,0xC7,0x5A,0x6A,0x98,0x76,0x7C,0x41,0x2B,0xE0,0xF5,0xD6,0x85,0x59,0x5F,0xCA,
+    0x5F,0x10,0xC0,0xE9,0x23,0x58,0x89,0xCB,0x89,0xCD,0x8F,0xB7,0x37,0xA0,0x47,0x28,
+    0x70,0x3A,0x17,0x0A,0x87,0x87,0x10,0x61,0xB1,0xBD,0x57,0x32,0x1F,0x03,0xD6,0x14,
+    0x5D,0x53,0xB0,0xBA,0x91,0x2E,0x86,0x62,0xB9,0xB7,0xC8,0xFF,0x5A,0xC7,0xF9,0xA3,
+    0x6D,0x9F,0x12,0x1B,0x9C,0x7B,0xB6,0x0B,0x9D,0x12,0xE6,0x1A,0x2A,0xD3,0x9C,0x2E,
+    0x1C,0x75,0x0C,0xC3,0xAC,0xD6,0x4F,0x41,0x31,0xDB,0x2D,0x62,0x39,0xE7,0xB6,0x2B,
+    0xFC,0xA8,0x21,0x15,0xEF,0xD3,0x8A,0xB8,0x1E,0xD9,0x5C,0xB6,0x04,0xE0,0xCB,0x0F,
+    0x0C,0xC1,0xE5,0x91,0xAB,0x3A,0x30,0xBA,0xD5,0x0A,0xE0,0x88,0x2B,0x97,0x7C,0x79,
+    0x50,0xBC,0x8F,0xB5,0x3D,0xA2,0x70,0xC8,0xB4,0x30,0xC4,0xDE,0x12,0x25,0x14,0xAA,
+    0x82,0xAB,0x36,0x9A,0x24,0xA5,0x16,0xE0,0xB2,0x47,0xA6,0x5E,0x7E,0xD0,0xDA,0x95,
+    0xA2,0xEF,0x46,0x6B,0xEB,0xD3,0x30,0xD8,0xC1,0xEC,0x92,0x21,0xD0,0x54,0x8D,0x12,
+    0xD1,0x27,0x5F,0xA6,0x3D,0x9F,0x92,0x3A,0x81,0x66,0xB4,0xF0,0x54,0xD0,0xED,0xC7,
+    0xC1,0x88,0x68,0xC3,0xD8,0x63,0xD0,0x3C,0x11,0x46,0x31,0x70,0xC1,0x88,0xC1,0x37,
+    0x7C,0x84,0x7E,0xCA,0xF9,0x6F,0x97,0x47,0x1D,0x4C,0x09,0x1C,0x36,0xF9,0x89,0x11,
+    0x1D,0x89,0x48,0xB0,0x23,0x2F,0x58,0xE6,0x8F,0xB7,0xED,0x69,0xF2,0xAD,0x45,0xD7,
+    0x03,0x4E,0xAB,0xB6,0x81,0x0C,
+};
+
+/* subjectAltName=DER:30:07:87:05:0a:00:00:00:01
+ * (IP address with 5 bytes) */
+const uint8_t _ipAddress_bad[] = {
+    0x30,0x82,0x04,0x38,0x30,0x82,0x03,0x20,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xD5,0x17,0xAC,0x1D,0x94,0x23,0xB1,0x70,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,
+    0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,
+    0x20,0x42,0x61,0x64,0x20,0x49,0x50,0x20,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x30,
+    0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,0x30,0x38,0x30,0x32,0x35,0x34,0x32,0x33,0x5A,
+    0x17,0x0D,0x32,0x30,0x31,0x31,0x30,0x37,0x30,0x32,0x35,0x34,0x32,0x33,0x5A,0x30,
+    0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
+    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
+    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
+    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
+    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,
+    0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,0x20,0x42,0x61,0x64,0x20,0x49,0x50,0x20,
+    0x41,0x64,0x64,0x72,0x65,0x73,0x73,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,0xBB,0x94,0xF8,0x59,0x6D,0x04,0x9E,0x53,
+    0x0C,0xC2,0x96,0x89,0x7A,0xE8,0x66,0x9B,0x1D,0x1A,0x5A,0x12,0x86,0x61,0xAB,0x5D,
+    0x00,0xC9,0x40,0x2D,0x1F,0x4C,0x5F,0x76,0xFF,0xD4,0xBE,0xD0,0x08,0xD6,0x0C,0x1C,
+    0xE5,0xC6,0xE3,0xA5,0xDC,0x65,0x2A,0x53,0xAB,0xC9,0x64,0x27,0x0C,0xAF,0x56,0x00,
+    0x93,0x53,0x99,0x16,0x59,0x29,0xD8,0x7A,0x89,0x0B,0x11,0xCD,0x47,0xFD,0xD3,0xBD,
+    0xF0,0x8A,0x4E,0x97,0xFA,0xA1,0x0F,0xCD,0xBA,0xD3,0x18,0x29,0x44,0xBD,0x27,0x59,
+    0x3C,0xF6,0x43,0x30,0xB8,0xB2,0x0F,0xE4,0xE5,0x2A,0x77,0x6A,0xC1,0x35,0x96,0x2E,
+    0x9A,0x0D,0x75,0x23,0x09,0xDF,0x37,0x30,0x76,0xAC,0xF2,0x30,0x5E,0x38,0xC9,0x96,
+    0x53,0x6B,0x78,0xB7,0xCF,0x23,0x34,0xA4,0x79,0xEC,0xFD,0x23,0x93,0xB2,0x92,0x24,
+    0x7E,0x84,0xB4,0x09,0x84,0x4F,0xD6,0x99,0x06,0x60,0x52,0xE7,0x3C,0x13,0x27,0x72,
+    0x34,0x5F,0x8D,0xE3,0x0E,0x81,0xCF,0x6E,0x66,0x79,0xBA,0xA2,0x2B,0x62,0xE1,0xBF,
+    0x5D,0xFA,0x66,0x47,0x26,0x7A,0x2A,0xAC,0x89,0x2D,0x44,0x35,0x40,0x60,0xA5,0x92,
+    0xA0,0xF5,0x8C,0x86,0xF1,0x04,0x55,0xAB,0xF1,0x1E,0xEA,0x42,0x26,0x0D,0x5D,0x80,
+    0x20,0x8F,0xF7,0x2A,0xF8,0x73,0x6F,0x7B,0xED,0xBA,0x9B,0xFB,0xB4,0x57,0x13,0xC2,
+    0xB5,0x11,0x8B,0x29,0x37,0x52,0xCD,0x86,0x47,0xE0,0x80,0xB4,0x7B,0xF8,0x92,0xA4,
+    0xCC,0x52,0x29,0x52,0xB1,0xC9,0x5A,0x12,0xE4,0x70,0xFB,0xB2,0x29,0xAF,0xC5,0x8A,
+    0x00,0xDF,0xD1,0xEC,0x16,0xDE,0x41,0x4D,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x88,
+    0x30,0x81,0x85,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,
+    0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,
+    0x80,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x10,0x06,0x03,0x55,0x1D,0x11,0x04,0x09,0x30,
+    0x07,0x87,0x05,0x0A,0x00,0x00,0x00,0x01,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,
+    0x16,0x04,0x14,0x5B,0xE9,0x2F,0x45,0xBA,0x5B,0x72,0x64,0x55,0x96,0x5B,0xB9,0x29,
+    0x94,0x08,0xB9,0x4E,0x79,0x8C,0x28,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,
+    0x30,0x16,0x80,0x14,0x5B,0xE9,0x2F,0x45,0xBA,0x5B,0x72,0x64,0x55,0x96,0x5B,0xB9,
+    0x29,0x94,0x08,0xB9,0x4E,0x79,0x8C,0x28,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xB5,0xA9,0xF0,0x60,
+    0xC1,0xD6,0xC5,0x35,0xA2,0x01,0x7B,0xBD,0x0F,0x3D,0x19,0xFE,0xED,0x51,0xCA,0x2B,
+    0xCE,0x3C,0xB2,0x0B,0xFF,0x33,0xD2,0x72,0x74,0x93,0xD1,0x93,0xB6,0xA3,0xCF,0x61,
+    0x4B,0x18,0xA5,0x07,0x71,0xCF,0x9D,0xA9,0xDC,0x20,0xA5,0xD2,0x71,0x77,0x4A,0xAC,
+    0x66,0x08,0x3D,0x6C,0x0E,0x6F,0x4E,0xFE,0x85,0x4F,0xF1,0xE2,0xFD,0x44,0x06,0xA2,
+    0xA0,0x02,0xCA,0x33,0x09,0x40,0xBA,0xCE,0xD6,0xAB,0xBA,0x07,0x79,0x20,0x81,0x7A,
+    0x12,0x89,0x19,0x82,0x5C,0xFB,0xDC,0x3F,0x8C,0x72,0x31,0x2D,0x08,0x1A,0x19,0x2F,
+    0xF2,0x13,0x89,0x7A,0xF3,0xCD,0x93,0x29,0x1C,0x76,0xBF,0x7A,0xE1,0x94,0xE9,0xBF,
+    0xF0,0xC7,0x8A,0x63,0xA9,0x90,0x0F,0xDA,0x2C,0x6B,0x49,0x14,0x8D,0xCC,0x30,0x40,
+    0xEC,0xD3,0x6B,0x07,0x12,0x0E,0x63,0x21,0x79,0xD3,0x52,0x23,0xA9,0x2F,0xA9,0xA6,
+    0x72,0x60,0x83,0x2F,0xED,0xB9,0xFC,0x77,0x2B,0xD8,0xAD,0x3C,0x6F,0x9B,0x67,0x48,
+    0x69,0x35,0x26,0xF0,0xEA,0x9D,0x29,0xD6,0x96,0x68,0x53,0xA9,0xB7,0x87,0x5E,0xFE,
+    0xCA,0x0D,0xAA,0x17,0x4C,0x8E,0x7C,0xEA,0x50,0x9E,0xB5,0xE2,0x92,0xC4,0x4B,0x8E,
+    0x93,0x26,0x0F,0x65,0xCF,0x3A,0x65,0xB8,0x39,0x73,0xD7,0x6C,0x49,0x8C,0x94,0xD5,
+    0x80,0x1F,0xE2,0xAD,0x16,0xF7,0xE9,0xCB,0xED,0x61,0xEB,0xD5,0xA2,0x69,0x3E,0xDD,
+    0x17,0xF6,0x52,0x8A,0x33,0x7C,0x8A,0xDD,0x51,0x3F,0x15,0x09,0x96,0x0B,0x6C,0x79,
+    0xC1,0xF3,0x86,0x30,0xB9,0xDB,0x5A,0x70,0x6B,0xE8,0x23,0xF2,
+};
+
 #endif /* _TRUSTTESTS_EVALUATION_SSL_TESTS_H_ */
index 021a4a1619f7aaeaf0cea52ec6fd55b801b629e0..967d8b473b25031a8a263b6a66f7a74b59f62176 100644 (file)
@@ -51,6 +51,12 @@ CF_RETURNS_RETAINED _Nullable
 SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * der_bytes, CFIndex der_length);
 CF_RETURNS_RETAINED _Nullable
 SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef cert);
+CF_RETURNS_RETAINED
+SecPolicyRef SecFrameworkPolicyCreateSSL(Boolean server, CFStringRef __nullable hostname);
+CF_RETURNS_RETAINED
+SecPolicyRef SecFrameworkPolicyCreateBasicX509(void);
+CF_RETURNS_RETAINED
+SecPolicyRef SecFrameworkPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef __nullable email);
 
 NS_ASSUME_NONNULL_END
 
index 712566e91d70262fb02cd1e4b3fd0b049394b0df..ff29a3efe1367ed71e63263c216c1bc214074d20 100644 (file)
@@ -27,6 +27,7 @@
 #include <Security/SecCertificatePriv.h>
 #include <Security/SecTrustPriv.h>
 #include <Security/SecPolicy.h>
+#include <Security/SecPolicyPriv.h>
 #include <Security/SecTrustSettings.h>
 #include <Security/SecTrustSettingsPriv.h>
 #include "OSX/utilities/SecCFWrappers.h"
@@ -339,11 +340,13 @@ exit:
 
 @end
 
-typedef SecCertificateRef (*create_f)(CFAllocatorRef allocator,
+/* MARK: Framework type conversion functions */
+
+typedef SecCertificateRef (*cert_create_f)(CFAllocatorRef allocator,
                            const UInt8 *der_bytes, CFIndex der_length);
 CF_RETURNS_RETAINED _Nullable
 SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * _Nonnull der_bytes, CFIndex der_length) {
-    static create_f FrameworkCertCreateFunctionPtr = NULL;
+    static cert_create_f FrameworkCertCreateFunctionPtr = NULL;
     static dispatch_once_t onceToken;
 
     dispatch_once(&onceToken, ^{
@@ -364,3 +367,63 @@ SecCertificateRef SecFrameworkCertificateCreate(const uint8_t * _Nonnull der_byt
 SecCertificateRef SecFrameworkCertificateCreateFromTestCert(SecCertificateRef cert) {
     return SecFrameworkCertificateCreate(SecCertificateGetBytePtr(cert), SecCertificateGetLength(cert));
 }
+
+typedef  SecPolicyRef (*ssl_policy_create_f)(Boolean server, CFStringRef hostname);
+SecPolicyRef SecFrameworkPolicyCreateSSL(Boolean server, CFStringRef __nullable hostname) {
+    static ssl_policy_create_f FrameworkPolicyCreateFunctionPtr = NULL;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+        void *framework = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY);
+        if (framework) {
+            FrameworkPolicyCreateFunctionPtr  = dlsym(framework, "SecPolicyCreateSSL");
+        }
+    });
+
+    if (FrameworkPolicyCreateFunctionPtr) {
+        return FrameworkPolicyCreateFunctionPtr(server, hostname);
+    } else {
+        NSLog(@"WARNING: not using Security framework policy");
+        return SecPolicyCreateSSL(server, hostname);
+    }
+}
+
+typedef  SecPolicyRef (*basic_policy_create_f)(void);
+SecPolicyRef SecFrameworkPolicyCreateBasicX509(void) {
+    static basic_policy_create_f FrameworkPolicyCreateFunctionPtr = NULL;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+        void *framework = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY);
+        if (framework) {
+            FrameworkPolicyCreateFunctionPtr  = dlsym(framework, "SecPolicyCreateBasicX509");
+        }
+    });
+
+    if (FrameworkPolicyCreateFunctionPtr) {
+        return FrameworkPolicyCreateFunctionPtr();
+    } else {
+        NSLog(@"WARNING: not using Security framework policy");
+        return SecPolicyCreateBasicX509();
+    }
+}
+
+typedef  SecPolicyRef (*smime_policy_create_f)(CFIndex smimeUsage, CFStringRef email);
+SecPolicyRef SecFrameworkPolicyCreateSMIME(CFIndex smimeUsage, CFStringRef email) {
+    static smime_policy_create_f FrameworkPolicyCreateFunctionPtr = NULL;
+    static dispatch_once_t onceToken;
+
+    dispatch_once(&onceToken, ^{
+        void *framework = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY);
+        if (framework) {
+            FrameworkPolicyCreateFunctionPtr  = dlsym(framework, "SecPolicyCreateSMIME");
+        }
+    });
+
+    if (FrameworkPolicyCreateFunctionPtr) {
+        return FrameworkPolicyCreateFunctionPtr(smimeUsage, email);
+    } else {
+        NSLog(@"WARNING: not using Security framework policy");
+        return SecPolicyCreateSMIME(smimeUsage, email);
+    }
+}
diff --git a/tests/TrustTests/EvaluationTests/TrustSettingsTests.m b/tests/TrustTests/EvaluationTests/TrustSettingsTests.m
new file mode 100644 (file)
index 0000000..070093e
--- /dev/null
@@ -0,0 +1,689 @@
+/*
+ * Copyright (c) 2008-2010,2012,2016 Apple Inc. All Rights Reserved.
+ */
+
+#include <Foundation/Foundation.h>
+#include <Security/SecCertificate.h>
+#include <Security/SecCertificatePriv.h>
+#include <Security/SecItem.h>
+#include <Security/SecItemPriv.h>
+#include <Security/SecPolicy.h>
+#include <Security/SecPolicyPriv.h>
+#include <Security/SecTrust.h>
+#include <Security/SecTrustSettings.h>
+#include <Security/SecTrustSettingsPriv.h>
+#include <Security/SecTrustPriv.h>
+#include <utilities/SecCFRelease.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if TARGET_OS_IPHONE
+#include <Security/SecTrustStore.h>
+#else
+#include <Security/SecKeychain.h>
+#endif
+
+#include "../TestMacroConversions.h"
+#include "TrustSettingsTests_data.h"
+#import "TrustEvaluationTestCase.h"
+
+@interface TrustSettingsTests : TrustEvaluationTestCase
+@end
+
+/* bridgeOS doesn't support trust settings */
+#if !TARGET_OS_BRIDGE
+
+#if TARGET_OS_IPHONE
+#define setTS(cert, settings) \
+{ \
+    ok_status(SecTrustStoreSetTrustSettings(defaultStore, cert, settings), \
+        "set trust settings"); \
+}
+#else
+/* Use admin store on OS X to avoid user prompts.
+ * Need a framework cert since we're interacting with keychain and trust settings.
+ * Sleep a little so trustd has time to get the KeychainEvent. */
+#define setTS(cert, settings) \
+{ \
+    SecCertificateRef frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert); \
+    ok_status(SecTrustSettingsSetTrustSettings(frameworkCert, kSecTrustSettingsDomainAdmin, \
+        settings), "set trust settings"); \
+    CFReleaseNull(frameworkCert); \
+    usleep(20000); \
+}
+#endif
+
+#if TARGET_OS_IPHONE
+#define setTSFail(cert, settings) \
+{ \
+    is(SecTrustStoreSetTrustSettings(defaultStore, cert, settings), errSecParam, \
+        "set trust settings"); \
+}
+#else
+#define setTSFail(cert, settings) \
+{ \
+    SecCertificateRef frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert); \
+    is(SecTrustSettingsSetTrustSettings(frameworkCert, kSecTrustSettingsDomainAdmin, \
+        settings), errSecParam, "set trust settings"); \
+    CFReleaseNull(frameworkCert); \
+}
+#endif
+
+#if TARGET_OS_IPHONE
+#define removeTS(cert) \
+{ \
+    ok_status(SecTrustStoreRemoveCertificate(defaultStore, cert), \
+        "remove trust settings"); \
+}
+#else
+#define removeTS(cert) \
+{ \
+    SecCertificateRef frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert); \
+    ok_status(SecTrustSettingsRemoveTrustSettings(cert, kSecTrustSettingsDomainAdmin), \
+        "remove trust settings"); \
+    CFReleaseNull(frameworkCert); \
+}
+#endif
+
+#define check_trust(certs, policy, valid_date, expected) \
+{ \
+    SecTrustRef trust = NULL; \
+    SecTrustResultType trust_result; \
+    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), \
+        "create trust with " #policy " policy"); \
+    ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)valid_date), \
+        "set trust verify date"); \
+    (void)SecTrustEvaluateWithError(trust, nil); \
+    ok_status(SecTrustGetTrustResult(trust, &trust_result), "get trust result"); \
+    is(trust_result, expected, \
+        "check trust result for " #policy " policy"); \
+    CFReleaseSafe(trust); \
+}
+
+static SecCertificateRef cert0 = NULL;
+static SecCertificateRef cert1 = NULL;
+static SecCertificateRef cert2 = NULL;
+static SecCertificateRef cert3 = NULL;
+static SecPolicyRef sslPolicy = NULL;
+static SecPolicyRef smimePolicy = NULL;
+static SecPolicyRef basicPolicy = NULL;
+static CFArrayRef sslChain = NULL;
+static CFArrayRef smimeChain = NULL;
+static NSDate *verify_date = nil;
+
+#if TARGET_OS_IPHONE
+static SecTrustStoreRef defaultStore = NULL;
+#define sslFrameworkPolicy sslPolicy
+#else
+#define kSystemLoginKeychainPath "/Library/Keychains/System.keychain"
+static NSMutableArray *deleteMeCertificates = NULL;
+static SecPolicyRef sslFrameworkPolicy = NULL;
+#endif
+
+@implementation TrustSettingsTests
+
++ (void)setUp
+{
+    [super setUp];
+    cert0 = SecCertificateCreateWithBytes(NULL, _trustSettingsRoot, sizeof(_trustSettingsRoot));
+    cert1 = SecCertificateCreateWithBytes(NULL, _trustSettingsInt, sizeof(_trustSettingsInt));
+    cert2 = SecCertificateCreateWithBytes(NULL, _trustSettingsSSLLeaf, sizeof(_trustSettingsSSLLeaf));
+    cert3 = SecCertificateCreateWithBytes(NULL, _trustSettingsSMIMELeaf, sizeof(_trustSettingsSMIMELeaf));
+
+    sslPolicy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com"));
+    smimePolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("username@apple.com"));
+    basicPolicy = SecPolicyCreateBasicX509();
+
+    const void *v_certs1[] = { cert2, cert1, cert0 };
+    sslChain = CFArrayCreate(NULL, v_certs1, sizeof(v_certs1)/sizeof(*v_certs1), &kCFTypeArrayCallBacks);
+
+    const void *v_certs2[] = { cert3, cert1, cert0 };
+    smimeChain = CFArrayCreate(NULL, v_certs2, sizeof(v_certs2)/sizeof(*v_certs2), &kCFTypeArrayCallBacks);
+
+    verify_date = [NSDate dateWithTimeIntervalSinceReferenceDate:482000000.0]; // Apr 10 2016
+
+#if TARGET_OS_IPHONE
+    defaultStore = SecTrustStoreForDomain(kSecTrustStoreDomainUser);
+#else
+    /* We need a framework version of the policies in order to set policies in the trust settings */
+    sslFrameworkPolicy = SecFrameworkPolicyCreateSSL(true, CFSTR("testserver.apple.com"));
+
+    /* Since we're putting trust settings in the admin domain,
+     * we need to add the certs to the system keychain.
+     * Need a framework cert since we're interacting with keychain. */
+    SecKeychainRef kcRef = NULL;
+    CFArrayRef certRef = NULL;
+    NSDictionary *attrs = nil;
+    SecCertificateRef frameworkCert =  NULL;
+
+    SecKeychainOpen(kSystemLoginKeychainPath, &kcRef);
+    if (!kcRef) {
+        return;
+    }
+
+    deleteMeCertificates = [[NSMutableArray alloc] init];
+
+    frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert0);
+    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)frameworkCert,
+              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+              (__bridge NSString*)kSecReturnPersistentRef: @YES};
+    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
+    CFReleaseNull(certRef);
+    CFReleaseNull(frameworkCert);
+
+    frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert1);
+    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)frameworkCert,
+              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+              (__bridge NSString*)kSecReturnPersistentRef: @YES};
+    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
+    CFReleaseNull(certRef);
+    CFReleaseNull(frameworkCert);
+
+    frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert2);
+    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)frameworkCert,
+                             (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+                             (__bridge NSString*)kSecReturnPersistentRef: @YES};
+    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
+    CFReleaseNull(certRef);
+    CFReleaseNull(frameworkCert);
+
+    frameworkCert = SecFrameworkCertificateCreateFromTestCert(cert3);
+    attrs = @{(__bridge NSString*)kSecValueRef: (__bridge id)frameworkCert,
+              (__bridge NSString*)kSecUseKeychain: (__bridge id)kcRef,
+              (__bridge NSString*)kSecReturnPersistentRef: @YES};
+    if (SecItemAdd((CFDictionaryRef)attrs, (void *)&certRef) == 0)
+        [deleteMeCertificates addObject:(__bridge NSArray *)certRef];
+    CFReleaseNull(certRef);
+    CFReleaseNull(frameworkCert);
+
+    CFReleaseNull(kcRef);
+#endif
+}
+
++ (void)tearDown
+{
+#if !TARGET_OS_IPHONE
+    [deleteMeCertificates enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        SecItemDelete((CFDictionaryRef)@{ (__bridge NSString*)kSecValuePersistentRef: [obj objectAtIndex:0]});
+    }];
+#endif
+
+    CFReleaseNull(cert0);
+    CFReleaseNull(cert1);
+    CFReleaseNull(cert2);
+    CFReleaseNull(cert3);
+    CFReleaseNull(sslPolicy);
+    CFReleaseNull(sslFrameworkPolicy);
+    CFReleaseNull(smimePolicy);
+    CFReleaseNull(basicPolicy);
+    CFReleaseNull(sslChain);
+    CFReleaseNull(smimeChain);
+    [super tearDown];
+}
+
+- (void)test_no_constraints
+{
+    /* root with the default TrustRoot result succeeds */
+    setTS(cert0, NULL);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+
+    /* intermediate with the default TrustRoot result fails */
+    setTSFail(cert1, NULL);
+
+    /* root with TrustRoot result succeeds */
+    NSDictionary *trustRoot = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
+    setTS(cert0, (__bridge CFDictionaryRef)trustRoot);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+
+    /* intermediate with TrustRoot fails to set */
+    setTSFail(cert1, (__bridge CFDictionaryRef)trustRoot);
+
+    /* root with TrustAsRoot fails to set */
+    NSDictionary *trustAsRoot = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    setTSFail(cert0, (__bridge CFDictionaryRef)trustAsRoot);
+
+    /* intermediate with TrustAsRoot result succeeds */
+    setTS(cert1, (__bridge CFDictionaryRef)trustAsRoot);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert1);
+
+    /* trusting the root but denying the intermediate fails */
+    NSDictionary *deny = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)};
+    setTS(cert0, NULL);
+    setTS(cert1, (__bridge CFDictionaryRef)deny);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultDeny);
+    removeTS(cert1);
+    removeTS(cert0);
+
+    /* the unspecified result gives us default behavior */
+    NSDictionary *unspecified = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
+    setTS(cert1, (__bridge CFDictionaryRef)unspecified);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert1);
+
+    /* trusting one leaf doesn't make other leaf trusted */
+    setTS(cert2, (__bridge CFDictionaryRef)trustAsRoot);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    check_trust(smimeChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert2);
+}
+
+- (void)test_policy_constraints
+{
+    /* Trust only for SSL server. SSL server policy succeeds. */
+    NSDictionary *sslServerAllowed = @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                        (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) };
+    setTS(cert1, (__bridge CFDictionaryRef)sslServerAllowed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
+
+    /* SSL client policy fails. */
+    SecPolicyRef sslClient = SecPolicyCreateSSL(false, NULL);
+    check_trust(sslChain, sslClient, verify_date, kSecTrustResultRecoverableTrustFailure);
+    CFReleaseNull(sslClient);
+
+    /* Basic policy fails */
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert1);
+}
+
+- (void)test_policy_string_constraints
+{
+    NSArray *hostnameAllowed = @[ @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                     (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongname.apple.com"),
+                                     (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) },
+                                  @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                     (__bridge NSString*)kSecTrustSettingsPolicyString: @("testserver.apple.com"),
+                                     (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) }
+                                  ];
+    setTS(cert2, (__bridge CFArrayRef)hostnameAllowed);
+    /* evaluating against trusted hostname passes */
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
+
+    /* evaluating against hostname not in trust settings is recoverable failure */
+    SecPolicyRef weirdnamePolicy = SecPolicyCreateSSL(true, CFSTR("weirdname.apple.com"));
+    check_trust(sslChain, weirdnamePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    CFReleaseNull(weirdnamePolicy);
+
+    /* evaluating against hostname denied by trust settings is denied */
+    SecPolicyRef wrongnamePolicy = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
+    check_trust(sslChain, wrongnamePolicy, verify_date, kSecTrustResultDeny);
+    CFReleaseNull(wrongnamePolicy);
+    removeTS(cert2);
+
+#if TARGET_OS_IPHONE
+    #define smimeFrameworkPolicy smimePolicy
+#else
+    SecPolicyRef smimeFrameworkPolicy= SecFrameworkPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("username@apple.com"));
+#endif
+
+    NSArray *emailAllowed = @[ @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)smimeFrameworkPolicy,
+                                  (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongemail@apple.com"),
+                                  (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) },
+                               @{ (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)smimeFrameworkPolicy,
+                                  (__bridge NSString*)kSecTrustSettingsPolicyString: @("username@apple.com"),
+                                  (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot) }
+                               ];
+    setTS(cert3, (__bridge CFArrayRef)emailAllowed);
+    /* evaluating against trusted email passes */
+    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultProceed);
+
+    /* evaluating against hostname not in trust settings is recoverable failure */
+    SecPolicyRef weirdemailPolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("weirdemail@apple.com"));
+    check_trust(smimeChain, weirdemailPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    CFReleaseNull(weirdemailPolicy);
+
+    /* evaluating against hostname denied by trust settings is denied */
+    SecPolicyRef wrongemailPolicy = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("wrongemail@apple.com"));
+    check_trust(smimeChain, wrongemailPolicy, verify_date, kSecTrustResultDeny);
+    CFReleaseNull(wrongemailPolicy);
+    removeTS(cert3);
+
+#if TARGET_OS_OSX
+    CFReleaseNull(smimeFrameworkPolicy);
+#endif
+}
+
+#if TARGET_OS_OSX
+#include <Security/SecTrustedApplicationPriv.h>
+- (void)test_application_constraints
+{
+    SecTrustedApplicationRef thisApp = NULL, someOtherApp = NULL;
+
+    #pragma clang diagnostic push
+    #pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    ok_status(SecTrustedApplicationCreateFromPath("/AppleInternal/CoreOS/tests/Security/TrustTests", &thisApp),
+              "create TrustedApplicationRef for this app");
+    ok_status(SecTrustedApplicationCreateFromPath("/Applications/Safari.app", &someOtherApp),
+              "create TrustedApplicationRef for Safari");
+    #pragma clang diagnostic pop
+
+    NSDictionary *thisAppTS = @{ (__bridge NSString*)kSecTrustSettingsApplication: (__bridge id)thisApp,
+                                 (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
+
+    NSDictionary *someOtherAppTS = @{ (__bridge NSString*)kSecTrustSettingsApplication: (__bridge id)someOtherApp,
+                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
+
+    /* This application Trust Setting succeeds */
+    setTS(cert0, (__bridge CFDictionaryRef)thisAppTS);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+
+    /* Some other application Trust Setting fails */
+    setTS(cert0, (__bridge CFDictionaryRef)someOtherAppTS);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert0);
+
+    CFReleaseNull(thisApp);
+    CFReleaseNull(someOtherApp);
+}
+#endif // TARGET_OS_OSX
+
+- (void)test_key_usage_constraints {
+    /* any key usage succeeds */
+    NSDictionary *anyKeyUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseAny),
+                                 (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
+    setTS(cert0, (__bridge CFDictionaryRef)anyKeyUse);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+
+    /* signCert key usage on an intermediate or root succeeds */
+    NSDictionary *signCertUseRoot = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignCert),
+                                   (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)};
+    setTS(cert0, (__bridge CFDictionaryRef)signCertUseRoot);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0)
+
+    NSDictionary *signCertUseInt = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignCert),
+                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    setTS(cert1, (__bridge CFDictionaryRef)signCertUseInt);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert1);
+
+    /* intermediate without signCert key usage fails */
+    NSDictionary *signatureUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseSignature),
+                                   (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    setTS(cert1, (__bridge CFDictionaryRef)signatureUse);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert1);
+
+    /* brief interlude to create a bunch of SMIME policies with different key usages */
+    SecPolicyRef smimeSignature = SecPolicyCreateSMIME(kSecSignSMIMEUsage, CFSTR("username@apple.com"));
+    SecPolicyRef smimeDataEncrypt = SecPolicyCreateSMIME(kSecDataEncryptSMIMEUsage, CFSTR("username@apple.com"));
+    SecPolicyRef smimeKeyEncrypt = SecPolicyCreateSMIME(kSecKeyEncryptSMIMEUsage, CFSTR("username@apple.com"));
+    SecPolicyRef smimeKeyExchange = SecPolicyCreateSMIME(kSecKeyExchangeBothSMIMEUsage, CFSTR("username@apple.com"));
+    SecPolicyRef smimeMultiple = SecPolicyCreateSMIME((kSecSignSMIMEUsage | kSecKeyEncryptSMIMEUsage),
+                                                      CFSTR("username@apple.com"));
+
+    /* signature smime policy passes for signature use TS*/
+    setTS(cert3, (__bridge CFDictionaryRef)signatureUse);
+    check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultProceed);
+
+    /* any use policy fails for signature use TS */
+    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+
+    /* multiple use smime policy against signature use */
+    check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert3);
+
+    /* key encrypt smime policy passes for key encrypt use */
+    NSDictionary *keyEncryptUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseEnDecryptKey),
+                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    setTS(cert3, (__bridge CFDictionaryRef)keyEncryptUse);
+    check_trust(smimeChain, smimeKeyEncrypt, verify_date, kSecTrustResultProceed);
+    removeTS(cert3);
+
+    /* multiple use smime policy against multiple uses */
+    NSDictionary *multipleUse = @{ (__bridge NSString*)kSecTrustSettingsKeyUsage: @(kSecTrustSettingsKeyUseEnDecryptKey |
+                                       kSecTrustSettingsKeyUseSignature),
+                                      (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)};
+    setTS(cert3, (__bridge CFDictionaryRef)multipleUse)
+    check_trust(smimeChain, smimeMultiple, verify_date, kSecTrustResultProceed);
+
+    /* signature smime policy against multiple uses */
+    check_trust(smimeChain, smimeSignature, verify_date, kSecTrustResultRecoverableTrustFailure);
+
+    /* any use smime policy against multiple uses */
+    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert3);
+
+    CFReleaseNull(smimeSignature);
+    CFReleaseNull(smimeDataEncrypt);
+    CFReleaseNull(smimeKeyEncrypt);
+    CFReleaseNull(smimeKeyExchange);
+    CFReleaseNull(smimeMultiple);
+}
+
+- (void)test_allowed_errors
+{
+    setTS(cert0, NULL);
+
+    /* allow expired errors */
+    NSDate *expired_date = [NSDate dateWithTimeIntervalSinceReferenceDate:520000000.0]; // Jun 24 2017
+    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultRecoverableTrustFailure);
+
+    NSDictionary *allowExpired = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147409654),
+                                    (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
+    setTS(cert1, (__bridge CFDictionaryRef)allowExpired)
+    setTS(cert2, (__bridge CFDictionaryRef)allowExpired);
+    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultProceed);
+    removeTS(cert2);
+    removeTS(cert1);
+
+    /* allow hostname mismatch errors */
+    SecPolicyRef wrongNameSSL = NULL;
+    wrongNameSSL = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
+    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultRecoverableTrustFailure);
+
+    NSDictionary *allowHostnameMismatch = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408896),
+                                             (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) };
+    setTS(cert2, (__bridge CFDictionaryRef)allowHostnameMismatch);
+    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
+    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed);
+    removeTS(cert2);
+    CFReleaseNull(wrongNameSSL);
+
+    /* allow email mismatch errors */
+    SecPolicyRef wrongNameSMIME = NULL;
+    wrongNameSMIME = SecPolicyCreateSMIME(kSecAnyEncryptSMIME, CFSTR("test@apple.com"));
+    check_trust(smimeChain, wrongNameSMIME, verify_date, kSecTrustResultRecoverableTrustFailure);
+
+    NSDictionary *allowEmailMismatch = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408872),
+                                          (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) };
+    setTS(cert3, (__bridge CFDictionaryRef)allowEmailMismatch);
+    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
+    check_trust(smimeChain, wrongNameSMIME, verify_date, kSecTrustResultProceed);
+    removeTS(cert3);
+    CFReleaseNull(wrongNameSMIME);
+
+    /* allowed error with a policy constraint */
+    NSDictionary *allowExpiredConstrained = @{ (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147409654),
+                                               (__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)};
+    setTS(cert1, (__bridge CFDictionaryRef)allowExpiredConstrained)
+    setTS(cert2, (__bridge CFDictionaryRef)allowExpiredConstrained);
+    check_trust(sslChain, sslPolicy, expired_date, kSecTrustResultProceed);
+    check_trust(sslChain, basicPolicy, expired_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert2);
+    removeTS(cert1);
+
+    removeTS(cert0);
+}
+
+- (void)test_multiple_constraints
+{
+    /* deny all but */
+    NSArray *denyAllBut = @[
+                            @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy ,
+                              (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot)},
+                            @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny) }
+                            ];
+    setTS(cert0, (__bridge CFArrayRef)denyAllBut);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultDeny);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+
+    /* allow all but */
+    NSArray *allowAllBut = @[
+                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy ,
+                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
+                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
+                             ];
+    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert0);
+
+#if TARGET_OS_IPHONE
+#define basicFrameworkPolicy basicPolicy
+#else
+    SecPolicyRef basicFrameworkPolicy = SecFrameworkPolicyCreateBasicX509();
+#endif
+
+    /* different results for specific policies */
+    NSArray *specifyPolicyResult = @[
+                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)},
+                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)basicFrameworkPolicy,
+                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
+                                     ];
+    setTS(cert0, (__bridge CFArrayRef)specifyPolicyResult);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultDeny);
+    check_trust(smimeChain, smimePolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert0);
+
+    /* different results for additional constraint with same policy */
+    NSArray *policyConstraintResult = @[
+                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                       (__bridge NSString*)kSecTrustSettingsPolicyString: @("wrongname.apple.com"),
+                                       (__bridge NSString*)kSecTrustSettingsAllowedError: @(-2147408896),
+                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustAsRoot)},
+                                     @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy,
+                                       (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified) }
+                                     ];
+    SecPolicyRef wrongNameSSL = NULL;
+    wrongNameSSL = SecPolicyCreateSSL(true, CFSTR("wrongname.apple.com"));
+    setTS(cert2, (__bridge CFArrayRef)policyConstraintResult);
+    sleep(1); // sleep a little extra so trustd gets trust settings event before evaluating leaf
+    check_trust(sslChain, wrongNameSSL, verify_date, kSecTrustResultProceed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+    removeTS(cert2);
+    CFReleaseNull(wrongNameSSL);
+
+#if TARGET_OS_OSX
+    CFReleaseNull(basicFrameworkPolicy);
+#endif
+}
+
+- (void)test_change_constraints
+{
+    /* allow all but */
+    NSArray *allowAllBut = @[
+                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)sslFrameworkPolicy ,
+                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
+                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
+                             ];
+    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultRecoverableTrustFailure);
+
+    /* Don't clear trust settings. Just change them. */
+
+    /* root with the default TrustRoot result succeeds */
+    setTS(cert0, NULL);
+    check_trust(sslChain, basicPolicy, verify_date, kSecTrustResultProceed);
+    check_trust(sslChain, sslPolicy, verify_date, kSecTrustResultProceed);
+    removeTS(cert0);
+}
+
+- (void)test_policy_name_pinning_constraints
+{
+    /* need a new policy object for this test so we don't mess up the policy used by the other tests */
+    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("testserver.apple.com"));
+#if TARGET_OS_IPHONE
+#define frameworkPolicy policy
+#else
+    SecPolicyRef frameworkPolicy = SecFrameworkPolicyCreateSSL(true, CFSTR("testserver.apple.com"));
+#endif
+
+    /* allow all but */
+    NSArray *allowAllBut = @[
+                             @{(__bridge NSString*)kSecTrustSettingsPolicy: (__bridge id)frameworkPolicy ,
+                               (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)},
+                             @{(__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultTrustRoot) }
+                             ];
+    setTS(cert0, (__bridge CFArrayRef)allowAllBut);
+
+    SecTrustRef trust = NULL;
+    ok_status(SecTrustCreateWithCertificates(sslChain, policy, &trust), "create trust with ssl policy");
+    ok_status(SecTrustSetVerifyDate(trust, (__bridge CFDateRef)verify_date), "set trust verify date");
+    ok_status(SecTrustSetPinningPolicyName(trust, CFSTR("not-a-db-policy-name")), "set policy name");
+    XCTAssertFalse(SecTrustEvaluateWithError(trust, nil), "evaluate trust");
+    CFReleaseSafe(trust);
+    CFReleaseNull(policy);
+    CFReleaseNull(frameworkPolicy);
+
+    removeTS(cert0);
+}
+
+
+- (void)testDistrustSystemRoot
+{
+    // Users can distrust system roots
+    id systemRoot = [self SecCertificateCreateFromResource:@"DigiCertGlobalRootG3" subdirectory:@"si-20-sectrust-policies-data"];
+    NSDictionary *deny = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)};
+    id persistentRef = [self addTrustSettingsForCert:(__bridge SecCertificateRef)systemRoot trustSettings:deny];
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[systemRoot] policies:nil];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]]; // January 6, 2020 at 2:40:00 AM PST
+    XCTAssertFalse([eval evaluate:nil]);
+    XCTAssertEqual(eval.trustResult, kSecTrustResultDeny);
+    [self removeTrustSettingsForCert:(__bridge SecCertificateRef)systemRoot persistentRef:persistentRef];
+}
+
+- (void)testDistrustAppleRoot
+{
+    // Users cannot distrust the Apple Roots
+    id appleRoot = [self SecCertificateCreateFromResource:@"AppleRootCA" subdirectory:@"si-20-sectrust-policies-data"];
+    NSDictionary *deny = @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)};
+    id persistentRef = [self addTrustSettingsForCert:(__bridge SecCertificateRef)appleRoot trustSettings:deny];
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[appleRoot] policies:nil];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:600000000.0]]; // January 6, 2020 at 2:40:00 AM PST
+    XCTAssert([eval evaluate:nil]);
+    XCTAssertEqual(eval.trustResult, kSecTrustResultProceed);
+    [self removeTrustSettingsForCert:(__bridge SecCertificateRef)appleRoot persistentRef:persistentRef];
+}
+
+- (void)testFatalResultsNonOverride
+{
+    id root = [self SecCertificateCreateFromPEMResource:@"ca-ki" subdirectory:@"si-88-sectrust-valid-data"];
+    id revokedLeaf = [self SecCertificateCreateFromPEMResource:@"leaf-ki-revoked1" subdirectory:@"si-88-sectrust-valid-data"];
+    TestTrustEvaluation *eval = [[TestTrustEvaluation alloc] initWithCertificates:@[revokedLeaf, root] policies:nil];
+    [eval setVerifyDate:[NSDate dateWithTimeIntervalSinceReferenceDate:542400000.0]]; // March 10, 2018 at 10:40:00 AM PST
+    [eval setAnchors:@[root]];
+    XCTAssertFalse([eval evaluate:nil]);
+    XCTAssertEqual(eval.trustResult, kSecTrustResultFatalTrustFailure);
+
+    /* still fatal failure if trust settings on root */
+    id persistentRef = [self addTrustSettingsForCert:(__bridge SecCertificateRef)root];
+    [eval setNeedsEvaluation];
+    XCTAssertFalse([eval evaluate:nil]);
+    XCTAssertEqual(eval.trustResult, kSecTrustResultFatalTrustFailure);
+    [self removeTrustSettingsForCert:(__bridge SecCertificateRef)root persistentRef:persistentRef];
+}
+
+@end
+
+#else // TARGET_OS_BRIDGE
+@implementation TrustSettingsTests
+- (void)testSkipTests
+{
+    XCTAssert(true);
+}
+@end
+
+#endif
diff --git a/tests/TrustTests/EvaluationTests/TrustSettingsTests_data.h b/tests/TrustTests/EvaluationTests/TrustSettingsTests_data.h
new file mode 100644 (file)
index 0000000..19d7ad8
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved.
+ */
+
+#ifndef _TRUSTTESTS_EVALUATION_TRUST_SETTINGS_TESTS_H_
+#define _TRUSTTESTS_EVALUATION_TRUST_SETTINGS_TESTS_H_
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
+unsigned char _trustSettingsRoot[1008]={
+    0x30,0x82,0x03,0xEC,0x30,0x82,0x02,0xD4,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xEE,0xAD,0xE6,0x5E,0x2C,0x5C,0x7C,0x40,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x91,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,
+    0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
+    0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,
+    0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,
+    0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,
+    0x36,0x30,0x33,0x31,0x39,0x32,0x33,0x33,0x30,0x34,0x34,0x5A,0x17,0x0D,0x32,0x36,
+    0x30,0x33,0x31,0x37,0x32,0x33,0x33,0x30,0x34,0x34,0x5A,0x30,0x81,0x91,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,
+    0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,
+    0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,
+    0x74,0x69,0x6E,0x6F,0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,
+    0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,
+    0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,
+    0x04,0x03,0x0C,0x1B,0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,
+    0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,
+    0x82,0x01,0x22,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,
+    0x05,0x00,0x03,0x82,0x01,0x0F,0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,
+    0xC6,0xB5,0x94,0x9F,0x10,0xC7,0x49,0x4F,0xAF,0xA5,0xE4,0x98,0xEE,0xEB,0x9C,0x39,
+    0xCA,0xF0,0x47,0x54,0xCA,0x26,0x4A,0xDD,0x6E,0x1E,0x33,0x4F,0x5E,0xF5,0x9F,0x4A,
+    0x41,0x3F,0xC3,0xCF,0xEB,0x30,0x51,0xD8,0x85,0xAB,0xD6,0xDD,0x45,0xBF,0x0D,0x67,
+    0x0D,0xDA,0x88,0x07,0xD8,0xB2,0x6D,0x6C,0x56,0xEE,0x27,0x74,0xDE,0x81,0xAC,0x35,
+    0x9F,0xBC,0x9E,0x4A,0x97,0x0E,0xB4,0x84,0xA4,0xFA,0x24,0x21,0xBE,0x74,0x40,0xB4,
+    0x9E,0xFC,0x81,0x9B,0xE6,0x82,0xB8,0xB6,0xAD,0x33,0x88,0xEC,0x30,0x5B,0x88,0x56,
+    0x7E,0x3D,0x03,0x7A,0xC7,0xC2,0x58,0xF9,0x7C,0x68,0x77,0x75,0x8B,0x59,0x82,0x28,
+    0xFC,0x0B,0x69,0x25,0x61,0x1E,0xCA,0x1F,0x7C,0x4D,0x3E,0x74,0xE5,0xE1,0xA0,0xDD,
+    0xB3,0xD8,0xBD,0x11,0x4A,0x57,0xB9,0xAA,0xB3,0x92,0x53,0x9C,0x2A,0xE5,0x91,0xD8,
+    0x57,0xCC,0xAD,0xB9,0x7F,0x4B,0x94,0x0F,0xCD,0xE0,0xEF,0xF7,0xE9,0x2A,0xE4,0x90,
+    0xEF,0xA2,0x69,0x53,0x46,0x68,0x5D,0x39,0xD5,0x08,0x24,0x33,0x3D,0x81,0xF5,0x34,
+    0xCD,0x06,0xC4,0xDB,0xC7,0x59,0xF9,0x9C,0xD9,0x00,0xD1,0x33,0x8F,0xE5,0x9D,0xF5,
+    0x7A,0xD0,0x91,0x3A,0x1F,0xE2,0x5C,0x24,0xB4,0xFD,0xF1,0x86,0x04,0x66,0x10,0xEC,
+    0x8F,0xB5,0x50,0xEF,0xBC,0x13,0xC2,0x32,0x52,0xFD,0x55,0x8D,0x9A,0x3E,0xB1,0xA0,
+    0x94,0x02,0x96,0xF4,0x64,0xE3,0x23,0x4F,0x18,0x19,0xAF,0x82,0xD0,0x25,0xA2,0x8C,
+    0x76,0x6B,0xDA,0xBA,0xF9,0xE8,0x0D,0xBA,0x32,0x74,0xF1,0x2F,0xB9,0xE3,0xD2,0x93,
+    0x02,0x03,0x01,0x00,0x01,0xA3,0x45,0x30,0x43,0x30,0x12,0x06,0x03,0x55,0x1D,0x13,
+    0x01,0x01,0xFF,0x04,0x08,0x30,0x06,0x01,0x01,0xFF,0x02,0x01,0x03,0x30,0x0E,0x06,
+    0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x1D,0x06,
+    0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x68,0x31,0x64,0x1E,0x5C,0x68,0x6A,0x83,
+    0xBD,0x39,0x22,0x44,0xF6,0xD3,0x6C,0x70,0xF7,0xDD,0x22,0x53,0x30,0x0D,0x06,0x09,
+    0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,
+    0x01,0xDF,0xE1,0x02,0xED,0x2A,0x55,0xC3,0xFF,0x9A,0xD7,0x43,0xCF,0xD9,0x5F,0x3C,
+    0xD5,0xAF,0xB1,0xEF,0x1F,0xF1,0x15,0x88,0x17,0x37,0x69,0x25,0xC1,0x42,0xFC,0xE3,
+    0x18,0xBC,0x02,0x6A,0x0B,0xAD,0xDB,0x49,0xE0,0xCB,0xBE,0x84,0xC0,0xF8,0x26,0xD0,
+    0xA6,0x4C,0xCB,0x3D,0xF4,0x52,0xBA,0xF2,0x3B,0x2C,0x3F,0xD6,0x46,0xAA,0xC8,0xE7,
+    0xE5,0x4A,0x41,0x7D,0xCA,0xC3,0x3A,0xEF,0xD0,0xFF,0xA2,0x1A,0x07,0x4E,0x18,0x70,
+    0xC6,0xBD,0xA2,0x37,0xD9,0x72,0xFB,0x95,0xC9,0x0A,0x4E,0x39,0x0D,0x67,0x45,0xF2,
+    0x92,0x34,0x2E,0x94,0x02,0x51,0x97,0x96,0x82,0x75,0x1C,0x7D,0x14,0x40,0x15,0x38,
+    0xB5,0x4D,0x17,0xBE,0xCE,0xDB,0x54,0x12,0x68,0xF6,0xCE,0xFA,0xE0,0x73,0xD3,0x3B,
+    0x7B,0x01,0xDC,0x43,0x17,0x46,0x00,0x2F,0x82,0x1F,0x4D,0x09,0x78,0x22,0x84,0x76,
+    0x2B,0xB6,0xA4,0xA8,0x87,0xC3,0x3F,0x13,0x4D,0x99,0xEF,0x23,0x52,0x92,0xCE,0x65,
+    0x1C,0x00,0x4A,0xCC,0xEE,0x3B,0x73,0xEB,0x52,0x86,0xA3,0xBC,0x22,0xAF,0xE2,0x88,
+    0x5A,0xED,0x34,0x51,0xC4,0x67,0x9F,0xA2,0x7E,0x4B,0xCC,0x65,0xFC,0xD6,0x38,0x42,
+    0x5A,0x24,0xB8,0x02,0x6F,0x99,0xA0,0xF7,0x38,0x86,0x8A,0x02,0xCD,0x28,0x9B,0xEA,
+    0xD9,0xA0,0x24,0x57,0x1E,0x40,0x02,0x89,0x29,0x4C,0x3F,0xF5,0xEF,0x8F,0xE7,0x4C,
+    0xDB,0x42,0xFA,0x8D,0x4C,0xD3,0x30,0xF7,0x71,0x7F,0xC2,0x41,0x66,0x19,0x7D,0x47,
+    0x99,0x26,0xF5,0x74,0x39,0xFE,0xB8,0xDF,0x60,0x36,0x02,0x0E,0x77,0x28,0x12,0x84,
+};
+
+/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Root CA */
+unsigned char _trustSettingsInt[1016]={
+    0x30,0x82,0x03,0xF4,0x30,0x82,0x02,0xDC,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xBE,0x29,0xEC,0x6D,0x40,0x7E,0x44,0x9A,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x91,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,
+    0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,
+    0x65,0x72,0x69,0x6E,0x67,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,
+    0x54,0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,
+    0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,
+    0x36,0x30,0x33,0x31,0x39,0x32,0x33,0x34,0x30,0x31,0x33,0x5A,0x17,0x0D,0x31,0x37,
+    0x30,0x33,0x31,0x39,0x32,0x33,0x34,0x30,0x31,0x33,0x5A,0x30,0x7C,0x31,0x0B,0x30,
+    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,
+    0x14,0x30,0x12,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,
+    0x72,0x75,0x73,0x74,0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,
+    0x73,0x74,0x20,0x53,0x75,0x62,0x20,0x43,0x41,0x30,0x82,0x01,0x22,0x30,0x0D,0x06,
+    0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x01,0x05,0x00,0x03,0x82,0x01,0x0F,
+    0x00,0x30,0x82,0x01,0x0A,0x02,0x82,0x01,0x01,0x00,0xC3,0x98,0xDB,0xB7,0x52,0xC3,
+    0xC9,0xD3,0xB8,0x35,0x57,0xAE,0xF4,0x93,0x21,0xDD,0xAD,0x17,0xA8,0xE3,0x39,0xB0,
+    0x27,0xF3,0x9F,0x12,0x77,0xF3,0xF0,0x03,0xED,0xAE,0xE7,0x79,0x86,0x17,0x07,0x1C,
+    0xDE,0x34,0x41,0x25,0x39,0xCA,0xFE,0xD1,0x13,0x3B,0xBB,0x7E,0x77,0x7E,0x32,0x99,
+    0xDD,0xEB,0xBA,0xDC,0x6D,0xB9,0xF5,0x8A,0x1C,0x19,0x71,0xE3,0xE4,0x7F,0x39,0x0C,
+    0x3F,0x09,0x46,0x22,0x28,0x60,0x1A,0x42,0xA2,0x6E,0xE4,0x64,0xCF,0x02,0x68,0xAC,
+    0x74,0xD1,0xBD,0xE4,0xC7,0x69,0x90,0xA5,0xA4,0x4F,0x1C,0x6E,0x08,0x79,0x28,0xE8,
+    0x3E,0xE3,0x62,0x15,0xF8,0xB9,0xC1,0x56,0x1A,0xB0,0xE3,0x27,0x02,0xC6,0x29,0x20,
+    0x7B,0x34,0x54,0xCC,0x0F,0xDB,0x5B,0x5E,0x81,0x0F,0x20,0xB7,0xB4,0x43,0xB3,0x29,
+    0xE7,0xB7,0x83,0xCB,0x01,0xB3,0x57,0x3E,0x7B,0xBC,0x21,0x2F,0xED,0x24,0x99,0xB4,
+    0xCD,0x64,0x9F,0x47,0xA3,0x5E,0x7B,0x99,0x69,0x8D,0xEB,0x6C,0x9D,0x60,0x7C,0x2F,
+    0x2D,0xF5,0xC9,0x9D,0x11,0x7B,0x61,0x4A,0x0D,0x70,0x11,0x14,0x6C,0xE1,0xCB,0xC1,
+    0x20,0xAF,0x55,0xBF,0xBE,0x8B,0xB6,0x9A,0x03,0x6C,0xFD,0x7A,0xCF,0xFB,0x92,0xD1,
+    0x85,0xEE,0x5B,0x1E,0xEA,0xDC,0x58,0xF3,0xF1,0x0B,0x88,0x9E,0xA5,0xB4,0xD2,0xCD,
+    0x74,0x47,0x18,0xA8,0xE3,0xFD,0x45,0xC2,0xE1,0x4D,0x97,0x77,0x89,0x48,0xF9,0x66,
+    0xA4,0xEF,0x9E,0x33,0x3E,0xF0,0xED,0x55,0xF7,0x92,0xF4,0x1B,0xF7,0xF6,0xF9,0x90,
+    0xCE,0xD5,0xA1,0x3F,0xE7,0xB7,0x2E,0x33,0x8F,0x9D,0x02,0x03,0x01,0x00,0x01,0xA3,
+    0x63,0x30,0x61,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,
+    0x03,0x01,0x01,0xFF,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
+    0x03,0x02,0x02,0x04,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xFD,
+    0x26,0x89,0x9C,0xA6,0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,0x2F,0xA6,0xC8,
+    0x22,0x30,0x70,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,
+    0x68,0x31,0x64,0x1E,0x5C,0x68,0x6A,0x83,0xBD,0x39,0x22,0x44,0xF6,0xD3,0x6C,0x70,
+    0xF7,0xDD,0x22,0x53,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xA0,0xCA,0xAB,0x34,0xCF,0x6A,0x97,0x40,
+    0x58,0x49,0xEE,0xA5,0x03,0x98,0xDB,0x6B,0x8D,0x19,0x11,0x83,0x5C,0x52,0xA5,0xD0,
+    0xA2,0x3B,0x5E,0x59,0x13,0x53,0xCA,0xAA,0x6B,0x26,0x6D,0x14,0x4A,0x6D,0x8A,0x61,
+    0xA7,0xDD,0x3E,0x2D,0x8B,0x4A,0x62,0xA4,0x3D,0x06,0xEE,0x76,0xB5,0x6F,0x93,0x30,
+    0xD1,0x29,0xEA,0x34,0x01,0xB3,0x6B,0x1A,0xF3,0xCA,0x26,0x1E,0x76,0x2E,0x46,0xB3,
+    0x73,0xE1,0x97,0x95,0x2F,0x16,0xC8,0x1F,0xF8,0x79,0x0E,0xEA,0x36,0xB0,0xEA,0x49,
+    0xBE,0x5A,0x40,0xFE,0x83,0x51,0x94,0x78,0x74,0xD0,0x22,0x87,0x34,0xF5,0xEE,0x44,
+    0x55,0x4B,0x4A,0xFF,0xF9,0xCD,0x84,0x68,0x32,0x94,0x98,0xCF,0xE0,0x51,0x66,0xEC,
+    0x93,0x12,0x26,0x37,0xBD,0xA1,0x71,0x3B,0xF6,0x7A,0x40,0x48,0x62,0xC8,0xDD,0xE8,
+    0x74,0x2C,0x14,0x09,0x18,0xDA,0x23,0x85,0xFF,0x2A,0x65,0xBF,0x0E,0x72,0x32,0xE2,
+    0xD8,0x89,0x36,0x99,0x51,0x00,0xBD,0x16,0x48,0x46,0xFB,0x02,0xFA,0x7A,0xC3,0x73,
+    0xBC,0x3B,0xB4,0x34,0x1C,0xBD,0x63,0x8D,0x12,0x97,0x66,0x8E,0x89,0x6C,0x79,0x8C,
+    0xA9,0x77,0x49,0x92,0x7E,0xB2,0xF8,0xDE,0x58,0xB9,0xF1,0xEA,0xAF,0x74,0x94,0x46,
+    0x1A,0x7B,0x5F,0x65,0x8D,0x08,0x38,0xBA,0xE4,0xB2,0xC2,0x27,0x05,0x76,0x38,0x1F,
+    0x2B,0xFD,0x29,0x86,0xDA,0x38,0xB3,0x1E,0x37,0x38,0xE4,0x6F,0x81,0x35,0xA7,0x82,
+    0x85,0xF5,0x8B,0xEC,0x24,0xD1,0xA1,0x12,0xFB,0x54,0xC4,0x51,0xA4,0x97,0xF2,0x0B,
+    0xD4,0xE5,0x79,0x49,0x60,0x27,0x0D,0x5D,
+};
+
+/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test SSL Leaf */
+/* issuer :/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
+unsigned char _trustSettingsSSLLeaf[1059]={
+    0x30,0x82,0x04,0x1F,0x30,0x82,0x03,0x07,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0x81,0x94,0x54,0x10,0xDC,0xA5,0x98,0x17,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,
+    0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
+    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
+    0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,0x72,0x75,0x73,0x74,
+    0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,
+    0x75,0x62,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x33,0x32,0x30,0x30,
+    0x30,0x31,0x30,0x35,0x37,0x5A,0x17,0x0D,0x31,0x37,0x30,0x33,0x32,0x30,0x30,0x30,
+    0x31,0x30,0x35,0x37,0x5A,0x30,0x7E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,
+    0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,
+    0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,0x03,0x55,
+    0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
+    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x25,
+    0x30,0x23,0x06,0x03,0x55,0x04,0x03,0x0C,0x1C,0x54,0x72,0x75,0x73,0x74,0x20,0x53,
+    0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,0x53,0x4C,
+    0x20,0x4C,0x65,0x61,0x66,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,0xBC,0x1C,0xAC,0x0E,0x78,0xFC,0xFA,0x63,0x97,0x5B,
+    0xE3,0xFB,0xE9,0x31,0x60,0x9C,0xAE,0x81,0x9F,0xE1,0x19,0x95,0xF1,0xE2,0x27,0x14,
+    0x33,0x86,0xA3,0x11,0x16,0x35,0x36,0x93,0x05,0xB6,0x88,0xC1,0x97,0x52,0xAB,0x0D,
+    0xA6,0x22,0xF2,0x5E,0xDF,0x9E,0x27,0x9F,0x82,0x4F,0x0B,0xAD,0x96,0x9D,0xD4,0x7A,
+    0x85,0xEA,0x62,0x89,0x6E,0xD5,0xC1,0x0D,0xCD,0x0D,0x15,0x4D,0x66,0x1F,0xA9,0xA8,
+    0xB3,0xFA,0xC1,0x59,0x74,0x69,0xE6,0xA5,0x4A,0xF2,0xA3,0xC9,0x5F,0x29,0x7D,0x9E,
+    0x49,0x5B,0x02,0x41,0x11,0x80,0x5C,0xD0,0x69,0x41,0x7C,0x05,0xFB,0xBA,0x0B,0xB6,
+    0x10,0x6D,0x30,0xF3,0xB7,0x76,0x4A,0x32,0xCE,0xF0,0x50,0x74,0x70,0x1C,0x7A,0xE7,
+    0x05,0x2A,0x01,0x00,0xB0,0xBB,0x22,0xB0,0xAD,0x7C,0x19,0xFD,0x5A,0xE3,0xC5,0xCD,
+    0x51,0x15,0x97,0xF4,0xE4,0xEF,0x60,0x56,0x2C,0x92,0xB1,0xD4,0x9D,0xF9,0x26,0x1F,
+    0x0C,0x11,0x2F,0x2F,0xA5,0xFA,0xD6,0x8E,0x87,0x1D,0xCC,0xA7,0xA0,0x3C,0x23,0xBB,
+    0x52,0x30,0x11,0x13,0x43,0x7C,0xFE,0x63,0xEE,0xAE,0xAF,0xE6,0xED,0x07,0xD2,0x89,
+    0xCB,0xC0,0xFE,0xF1,0xBF,0x75,0x18,0xA8,0xFF,0x34,0x9A,0x5C,0x28,0xEC,0x18,0x55,
+    0x68,0xF7,0x24,0x30,0x94,0x49,0x23,0xCB,0xF1,0xE3,0xBE,0x1D,0x51,0xA3,0x2B,0x21,
+    0x7D,0xFC,0x6E,0x93,0x19,0xE7,0xA5,0x26,0xFE,0xE2,0x5D,0xED,0x4A,0xD4,0xB9,0x60,
+    0xE4,0xE7,0x77,0xA8,0xFF,0x13,0x06,0x0D,0x58,0x82,0x25,0x6D,0xEB,0xAC,0xA9,0x56,
+    0xF9,0x2C,0x60,0xBB,0x66,0x77,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0xA1,0x30,0x81,
+    0x9E,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,0x00,0x30,
+    0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,
+    0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,
+    0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x1F,
+    0x06,0x03,0x55,0x1D,0x11,0x04,0x18,0x30,0x16,0x82,0x14,0x74,0x65,0x73,0x74,0x73,
+    0x65,0x72,0x76,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,
+    0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0xC6,0xED,0xD2,0x4E,0x23,0xC9,
+    0xA9,0xC8,0x64,0x3A,0x55,0x51,0x0F,0x27,0x52,0xD6,0x18,0x12,0x66,0xC8,0x30,0x1F,
+    0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0xFD,0x26,0x89,0x9C,0xA6,
+    0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,0x2F,0xA6,0xC8,0x22,0x30,0x70,0x30,
+    0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,
+    0x01,0x01,0x00,0xB1,0x56,0x55,0xC7,0x1F,0xF6,0x15,0x59,0xA6,0x0B,0xC4,0xBB,0x48,
+    0x53,0x1B,0xE7,0xC1,0x7F,0x72,0x65,0x0E,0xE9,0x08,0x22,0xF6,0x30,0x9C,0xB3,0xCA,
+    0xCF,0xDE,0x16,0x2C,0x90,0x30,0x59,0xC4,0xB2,0xE7,0x1E,0xD2,0xF3,0xD6,0x29,0x94,
+    0xA3,0xD5,0xFA,0x98,0xC1,0xBF,0xD7,0xC3,0x52,0xBC,0xFF,0x6D,0xB6,0xE1,0xCE,0x1A,
+    0x59,0xF9,0x68,0x6D,0x98,0x8B,0x48,0x7D,0xE6,0xD0,0x1F,0xFE,0xF7,0x9C,0x73,0x09,
+    0x73,0x9B,0x5D,0xAF,0x88,0x37,0x35,0x1C,0x3F,0x9A,0x07,0xE0,0x3B,0x29,0x24,0x7F,
+    0x04,0x9A,0xD2,0x3F,0xDE,0xF3,0x68,0x1D,0x16,0x8D,0xD0,0x4F,0xB6,0x83,0x19,0x70,
+    0xBB,0x1F,0x21,0x91,0x49,0x3F,0x12,0x89,0xF6,0x88,0x8A,0x2F,0xDC,0x55,0x54,0xBE,
+    0x78,0xDD,0x2F,0xC9,0x0C,0x7B,0x8C,0xA8,0x33,0x33,0x1D,0xA0,0x6D,0xA4,0xA6,0x6A,
+    0xA4,0x49,0xD6,0x37,0x6D,0x95,0x15,0x0C,0xFA,0xA5,0xCF,0x5A,0x28,0xD9,0x37,0x5D,
+    0xC5,0xC5,0x3A,0x30,0x8D,0x54,0xE4,0xAB,0x19,0x7A,0xF0,0x33,0xAE,0x64,0xA9,0x42,
+    0x83,0xD2,0xF2,0x68,0x39,0xA2,0xE1,0x71,0x68,0x19,0x81,0x5A,0x9B,0xB4,0xDD,0xBC,
+    0xA6,0xC7,0x19,0x40,0x87,0x50,0x6F,0x49,0xD2,0xC1,0x92,0x57,0xE4,0x5B,0x5F,0x41,
+    0x85,0x22,0x33,0x8D,0xC7,0x0B,0x3F,0x55,0xC1,0x46,0x2C,0xB6,0xDE,0xF7,0x80,0x54,
+    0xA5,0x62,0x0E,0xA3,0x24,0x14,0x9B,0xF1,0xEE,0x9D,0x7F,0x65,0xA2,0x1D,0x0C,0x32,
+    0x86,0x81,0xDE,0xDC,0xD7,0xB6,0x06,0x3A,0xF6,0xF0,0x81,0x6A,0xBE,0xC4,0xA0,0x87,
+    0xEA,0x6A,0x6C,
+};
+
+/* subject:/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test SMIME Leaf */
+/* issuer :/C=US/ST=California/O=Apple, Inc./OU=Security Engineering/CN=Trust Settings Test Sub CA */
+unsigned char _trustSettingsSMIMELeaf[1050]={
+    0x30,0x82,0x04,0x16,0x30,0x82,0x02,0xFE,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0x81,0x94,0x54,0x10,0xDC,0xA5,0x98,0x18,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x7C,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,
+    0x03,0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,
+    0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,
+    0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,0x54,0x72,0x75,0x73,0x74,
+    0x20,0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,
+    0x75,0x62,0x20,0x43,0x41,0x30,0x1E,0x17,0x0D,0x31,0x36,0x30,0x33,0x32,0x30,0x30,
+    0x30,0x31,0x31,0x35,0x32,0x5A,0x17,0x0D,0x31,0x37,0x30,0x33,0x32,0x30,0x30,0x30,
+    0x31,0x31,0x35,0x32,0x5A,0x30,0x81,0x80,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,
+    0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,
+    0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x14,0x30,0x12,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0B,0x41,0x70,0x70,0x6C,0x65,0x2C,0x20,0x49,0x6E,0x63,0x2E,
+    0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,
+    0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,
+    0x27,0x30,0x25,0x06,0x03,0x55,0x04,0x03,0x0C,0x1E,0x54,0x72,0x75,0x73,0x74,0x20,
+    0x53,0x65,0x74,0x74,0x69,0x6E,0x67,0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x53,0x4D,
+    0x49,0x4D,0x45,0x20,0x4C,0x65,0x61,0x66,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,0xE7,0x42,0xF7,0x3B,0x41,0xB4,0x91,
+    0xF6,0xC3,0x4F,0x5B,0x52,0x9C,0x4D,0x1E,0x0D,0x1F,0x1A,0xE8,0x07,0x14,0x00,0x48,
+    0x00,0x18,0x13,0xA6,0xD0,0xC4,0x49,0x6A,0xC7,0x47,0xBE,0xC6,0x07,0x9F,0xED,0x81,
+    0xC8,0x49,0x7C,0xC8,0x69,0x14,0x2D,0xAD,0xD4,0x98,0x58,0x1A,0x6D,0xCC,0x28,0x54,
+    0xA1,0x13,0xAF,0x2A,0xB5,0xF5,0x4B,0x6F,0x97,0x85,0x33,0xE0,0x12,0xF8,0x06,0x95,
+    0xA0,0x57,0x81,0xD1,0x51,0x4E,0x1B,0x29,0x80,0x9F,0x3C,0x49,0x34,0x28,0x61,0x59,
+    0x6A,0x56,0xA1,0x13,0x52,0x1B,0x41,0x6E,0xE2,0xA7,0xE1,0x6E,0x10,0xCC,0x07,0x48,
+    0x0C,0x36,0x25,0x35,0xD3,0xBB,0x8F,0x45,0xF9,0x37,0x4D,0xB4,0xC7,0x9E,0xFA,0x7F,
+    0x99,0xFC,0xB5,0x35,0xD7,0x96,0xC6,0xF7,0xF0,0x19,0x34,0xB6,0xD9,0x3C,0x82,0x38,
+    0xBF,0x23,0x04,0x21,0x4A,0xFC,0xC1,0x8C,0x89,0xB1,0x45,0xFC,0x9B,0x4D,0xAE,0x28,
+    0x4F,0xF6,0xD3,0x69,0xBB,0x3B,0xC5,0x5F,0x72,0xC7,0xD3,0xDF,0x70,0x97,0x7B,0xEE,
+    0xD6,0x09,0xD6,0x21,0xF3,0xCF,0x8D,0x50,0xAF,0x48,0xDA,0x2C,0xEB,0x90,0x8E,0x1D,
+    0xEE,0x94,0xA7,0xAB,0x21,0x0E,0xC8,0xE2,0xA1,0x7F,0x36,0x98,0x1A,0x99,0xDD,0x85,
+    0x3A,0xEE,0xF0,0xE6,0x34,0x15,0x98,0x6D,0xA8,0x22,0x4E,0x4F,0x54,0x06,0xF1,0x1F,
+    0xE0,0xDD,0x8E,0xB1,0xA5,0x94,0xA2,0xC5,0xD2,0xA3,0xEA,0xD9,0xD9,0x28,0x1B,0x4B,
+    0x98,0x82,0x89,0x18,0x2D,0x7B,0x17,0xD6,0x92,0x5F,0x20,0x44,0xAF,0xD5,0x27,0x02,
+    0x2C,0x2E,0x8F,0x14,0x20,0x70,0xA1,0xD4,0x65,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,
+    0x95,0x30,0x81,0x92,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,
+    0x30,0x00,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x03,0x04,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,
+    0xFF,0x04,0x04,0x03,0x02,0x05,0xA0,0x30,0x1D,0x06,0x03,0x55,0x1D,0x11,0x04,0x16,
+    0x30,0x14,0x81,0x12,0x75,0x73,0x65,0x72,0x6E,0x61,0x6D,0x65,0x40,0x61,0x70,0x70,
+    0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,
+    0x14,0xC6,0xD8,0x0B,0xD7,0xD4,0x9E,0x84,0x41,0xB3,0x59,0x05,0x41,0xDF,0xC3,0x2A,
+    0x77,0xBB,0x41,0x20,0x85,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,
+    0x80,0x14,0xFD,0x26,0x89,0x9C,0xA6,0x9A,0xF6,0x33,0x48,0xA9,0x5D,0x0B,0xF6,0x90,
+    0x2F,0xA6,0xC8,0x22,0x30,0x70,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,
+    0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x4B,0x02,0x37,0x7F,0xBA,0x3D,
+    0xD5,0xDF,0xE9,0xD6,0x52,0x6D,0x39,0x23,0x83,0x1B,0xFB,0x17,0x15,0x1A,0x45,0x9E,
+    0xF2,0x55,0xA3,0x2C,0x18,0xF1,0x01,0xA1,0x2D,0xAA,0x78,0x39,0xA8,0x5A,0xD5,0x9E,
+    0x37,0xE4,0x50,0x31,0x7A,0x07,0x61,0xD8,0xE9,0x2A,0x32,0x1F,0x04,0x3F,0x27,0x03,
+    0xDC,0x77,0x7F,0x1B,0xD7,0x45,0x55,0x1F,0x5B,0xCC,0x7A,0xF1,0x5C,0x74,0x9E,0xA5,
+    0x2A,0xA3,0xAC,0x63,0xBE,0x8B,0xEB,0x38,0x39,0xEC,0x53,0x9E,0x09,0x5A,0x86,0x2D,
+    0x25,0x9C,0x78,0x85,0x02,0x07,0xE5,0xE2,0x98,0xB3,0x70,0x50,0x1A,0xAE,0x4F,0xF4,
+    0x9F,0x89,0xA9,0x84,0xBF,0x6F,0x03,0x42,0x6B,0x12,0x0A,0x15,0x73,0x3F,0xC6,0x8B,
+    0x32,0xDA,0x52,0x17,0xC5,0xC2,0x96,0x68,0xF7,0x31,0x1B,0x5D,0xB1,0x49,0x4C,0x2D,
+    0xE7,0x3E,0x42,0xD6,0xF1,0x14,0xA9,0xBE,0x2F,0xD9,0x65,0xEB,0x0F,0x51,0x58,0x09,
+    0x7D,0x4D,0x07,0x4B,0xE4,0x49,0x13,0x8B,0x70,0xA9,0x90,0x6C,0x9F,0x10,0xD2,0x8B,
+    0x90,0xBE,0x63,0xF9,0x8E,0xF8,0x73,0x22,0xBE,0x54,0xEE,0x96,0x56,0x66,0xBC,0x2F,
+    0x2A,0xC6,0x6B,0x84,0x67,0x4D,0xD8,0xF7,0xBA,0xCD,0x75,0x3B,0x73,0xEF,0x05,0x46,
+    0x52,0xA4,0xF9,0xA7,0x03,0x29,0xA4,0x9A,0x11,0xAE,0x79,0xE5,0x53,0x3E,0xC5,0xD7,
+    0x75,0x39,0x2D,0x82,0xC3,0x60,0x5F,0x12,0x9B,0x90,0x19,0xD6,0xB1,0xA4,0xF7,0x8B,
+    0x62,0xF9,0x44,0x4E,0x15,0xA5,0xD3,0xFF,0x75,0x4E,0x44,0x84,0x78,0xCF,0x68,0x18,
+    0xFE,0x46,0xEB,0xFE,0x0E,0x11,0xCB,0x34,0x53,0xAB,
+};
+
+/* subject:/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateRoot[] = {
+    0x30,0x82,0x03,0xB1,0x30,0x82,0x02,0x99,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x14,
+    0x99,0x6B,0x4A,0x6A,0xE4,0x40,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
+    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
+    0x17,0x0D,0x31,0x33,0x30,0x37,0x31,0x36,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x17,
+    0x0D,0x32,0x39,0x30,0x37,0x31,0x37,0x31,0x39,0x32,0x30,0x34,0x35,0x5A,0x30,0x66,
+    0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,
+    0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,
+    0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,
+    0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,
+    0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,
+    0x04,0x06,0x13,0x02,0x55,0x53,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,0xB5,0x3B,0xE3,0x9F,0x6A,0x1D,0x0E,0x46,0x51,
+    0x1E,0xD0,0xB5,0x17,0x6B,0x06,0x4B,0x92,0xAF,0x38,0x10,0x25,0xA1,0xEE,0x1E,0x4E,
+    0xEF,0x19,0xE0,0x73,0xB5,0x37,0x33,0x72,0x21,0x21,0xCB,0x62,0x4A,0x3D,0xA9,0x68,
+    0xD8,0x07,0xB4,0xEB,0x8D,0x0A,0xDB,0x30,0x33,0x21,0x2F,0x6F,0xD3,0xF7,0x5D,0xCE,
+    0x20,0x0A,0x04,0xDB,0xFF,0xBF,0x75,0x08,0x42,0x3F,0x3E,0xD8,0xC8,0xEF,0xA4,0xF8,
+    0x56,0x7B,0x13,0x64,0x6B,0xF3,0xA2,0x38,0x10,0xFA,0xEE,0x9D,0x83,0x93,0x1D,0xFB,
+    0xEF,0x13,0x6C,0x38,0x49,0xDD,0xEB,0x71,0xA6,0x92,0x58,0x04,0xDE,0x01,0x41,0x2B,
+    0x99,0x5E,0xBD,0x24,0x3F,0x69,0xA8,0x44,0xF2,0xAA,0x01,0x78,0xB9,0x38,0x06,0x10,
+    0x77,0x36,0xF8,0xF2,0xA3,0x3E,0xD9,0x5F,0xEA,0xF5,0x8B,0x6A,0xA6,0x5F,0xE6,0x51,
+    0xD0,0x9B,0x50,0xA0,0x1E,0xF5,0x85,0x9E,0x49,0x50,0x4A,0x61,0x78,0xDA,0x29,0xA7,
+    0x33,0x72,0x8B,0x83,0xEE,0x7B,0xA7,0x79,0x4E,0x8E,0x02,0x6F,0x9D,0x25,0x97,0x26,
+    0x86,0x0C,0x82,0xC5,0x8C,0x16,0x7E,0x49,0x61,0xFD,0xFF,0x1A,0xA0,0x0D,0x28,0xE1,
+    0x68,0xF5,0xAE,0x85,0x72,0xF3,0xAB,0xE0,0x74,0x75,0xCC,0x57,0x64,0x3C,0x2C,0x55,
+    0x05,0xC9,0x8D,0xAA,0xB3,0xEC,0xC8,0x62,0x88,0x15,0x2A,0xC4,0x59,0x60,0x37,0xC1,
+    0xED,0x6B,0xCE,0xE9,0xCA,0xAF,0xB0,0xA5,0x45,0xBA,0xFF,0x16,0x32,0xAA,0x92,0x86,
+    0xD9,0xB9,0xA1,0x13,0x75,0x95,0x9B,0x97,0x5C,0x2D,0xB5,0x12,0xCA,0x6B,0x6B,0x39,
+    0xD6,0x9B,0x4B,0x34,0x47,0xAB,0x35,0x02,0x03,0x01,0x00,0x01,0xA3,0x63,0x30,0x61,
+    0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,0x35,0x20,0x26,0xCE,0x85,
+    0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,
+    0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,
+    0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,
+    0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,
+    0xF5,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,
+    0x06,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,
+    0x03,0x82,0x01,0x01,0x00,0x73,0x02,0x4A,0xA6,0x77,0x02,0xA7,0xE1,0xCB,0x52,0x97,
+    0x9D,0x89,0x11,0xA0,0x8F,0xBC,0xF3,0x8F,0x14,0x01,0x29,0xF3,0xA5,0x45,0x17,0x06,
+    0xF8,0x04,0xF2,0x6D,0xD5,0xC3,0x77,0xB8,0x00,0xC2,0x0A,0x1A,0x09,0x32,0x36,0x36,
+    0x69,0xC1,0x2A,0xF0,0x44,0x37,0xBC,0x7E,0x5F,0x15,0xF7,0x08,0x9C,0x19,0x27,0x1D,
+    0x70,0x4F,0xDC,0x17,0x94,0x3C,0xBB,0x24,0xB4,0xE6,0xFC,0x71,0x9A,0xD4,0xCF,0x2C,
+    0x12,0xBA,0xF0,0xB6,0x8F,0x78,0x99,0xAA,0x8C,0x17,0x7E,0x94,0x0C,0x6A,0x37,0x5B,
+    0x35,0x91,0x52,0xFA,0x64,0xA3,0x33,0x34,0x99,0x37,0x00,0x3C,0xB4,0x4E,0x6E,0x63,
+    0xED,0xC3,0x1D,0x37,0x5B,0x45,0xB4,0xDF,0x82,0xCD,0xFE,0xAA,0x92,0x64,0xC8,0x2F,
+    0xD6,0x2D,0x2E,0xB1,0xED,0x6A,0x04,0xF1,0xC2,0x48,0x8D,0x4B,0xB4,0x84,0x39,0xA3,
+    0x31,0x4D,0xF6,0x63,0xB4,0xC3,0x6E,0xA1,0xA5,0x2F,0xD2,0x1E,0xB0,0xC6,0x0C,0xD1,
+    0x04,0x3A,0x31,0xBC,0x87,0x49,0xF8,0x26,0x0B,0xD3,0x0C,0x08,0x29,0xBB,0x9F,0x4D,
+    0x08,0xF0,0x9C,0x11,0xD3,0xA5,0x2C,0x8D,0x98,0xB1,0x1B,0xB1,0x57,0xD3,0x69,0xAE,
+    0x9E,0x2D,0xD5,0x64,0x38,0x58,0xC9,0xB2,0x84,0x04,0xAB,0x10,0x1D,0xCA,0x6B,0x29,
+    0xA5,0xAB,0xCC,0xFE,0xBB,0x74,0xF4,0x35,0x03,0x8F,0x65,0x2A,0x0B,0xBB,0xC7,0x17,
+    0x6A,0x49,0x34,0x83,0x30,0x92,0x8D,0xD7,0xAE,0x95,0xD0,0xD7,0x23,0xA7,0xE3,0x29,
+    0x09,0xA1,0xB1,0x34,0xC3,0x95,0x49,0xC3,0xA4,0xF1,0x36,0x00,0x09,0xD3,0xA4,0x09,
+    0xAD,0xF2,0x5C,0x97,0xB2,
+};
+
+/* subject:/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
+/* issuer :/CN=Apple Corporate Root CA/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateServerCA[] = {
+    0x30,0x82,0x04,0x40,0x30,0x82,0x03,0x28,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x0D,
+    0x5D,0xDF,0x69,0x27,0x9B,0x23,0x11,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x66,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x17,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x52,0x6F,0x6F,0x74,0x20,0x43,0x41,0x31,0x20,0x30,0x1E,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,
+    0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,
+    0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,
+    0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x30,0x1E,
+    0x17,0x0D,0x31,0x34,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x17,
+    0x0D,0x32,0x39,0x30,0x33,0x32,0x36,0x31,0x36,0x35,0x33,0x33,0x37,0x5A,0x30,0x6A,
+    0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,
+    0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,
+    0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,
+    0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,
+    0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xE3,0xE9,0x68,0xA1,0xE7,
+    0x9B,0xBC,0xF7,0x87,0x48,0x22,0x9B,0x09,0x5F,0xC8,0xC9,0xA6,0x9A,0xCC,0xCD,0x40,
+    0x16,0xF8,0xA1,0xD0,0xF6,0x27,0x15,0x4C,0xE7,0xD3,0xC1,0x6E,0xDF,0x11,0x06,0x9A,
+    0x63,0xC5,0x87,0x55,0xDA,0xDF,0xAF,0x15,0x31,0x98,0x45,0xF4,0x8C,0xC2,0x3C,0x93,
+    0xA2,0x1C,0xC0,0xF0,0x2A,0x77,0xF4,0x19,0x94,0x96,0xF4,0x7B,0x52,0x74,0x84,0x86,
+    0x5A,0x66,0x7D,0x68,0x92,0xA1,0x5E,0xE1,0xA9,0x21,0xE0,0x14,0x38,0x84,0x21,0x32,
+    0x8B,0x21,0x95,0x47,0x27,0x17,0xA0,0xBA,0x7B,0xD7,0xD8,0xD7,0x25,0x20,0x77,0xCB,
+    0x62,0x8B,0xC6,0x0F,0xC1,0x49,0xC6,0x2B,0x42,0xE9,0x02,0x70,0x9E,0x99,0x44,0x77,
+    0x51,0x05,0x62,0x78,0xBC,0xB0,0xD2,0xA7,0xA6,0x91,0x71,0x25,0x58,0x13,0x8D,0x8A,
+    0xC8,0x46,0x41,0xDB,0x89,0x41,0xC5,0x23,0x7D,0x84,0xE9,0x02,0xB0,0x1A,0xF8,0x5D,
+    0x66,0xD0,0xE1,0xE1,0x72,0xF4,0xA4,0x65,0x79,0x97,0x0A,0x7B,0xC0,0xE3,0x24,0x74,
+    0x83,0x4A,0x81,0x5E,0xC3,0xA2,0xBF,0x51,0x32,0x96,0x8F,0x28,0x32,0x08,0x49,0xFB,
+    0x02,0x43,0x62,0x42,0xB3,0x84,0x84,0x30,0x1B,0x28,0xE4,0x05,0xB9,0xBB,0xD6,0xB5,
+    0xC4,0xA2,0xAB,0x8E,0x57,0x53,0x29,0xBC,0x0B,0x4F,0xD6,0x1E,0xA4,0x52,0xDC,0x16,
+    0x1C,0x95,0xC2,0x8D,0x97,0x6B,0xBB,0x3E,0xC8,0x93,0xC7,0x01,0x97,0x1E,0x18,0x09,
+    0x59,0x39,0x0F,0x5D,0x73,0x4E,0xA9,0x8F,0x49,0xFD,0x49,0x16,0xBD,0x25,0xEC,0xD9,
+    0x05,0xEA,0xE3,0xB0,0x04,0x0E,0xD9,0x09,0x9E,0xC0,0xB7,0x02,0x03,0x01,0x00,0x01,
+    0xA3,0x81,0xED,0x30,0x81,0xEA,0x30,0x41,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x01,0x01,0x04,0x35,0x30,0x33,0x30,0x31,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x30,0x01,0x86,0x25,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,
+    0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x34,
+    0x2D,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,
+    0x04,0x16,0x04,0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,
+    0xD0,0xAD,0x5C,0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x0F,0x06,0x03,0x55,0x1D,0x13,0x01,
+    0x01,0xFF,0x04,0x05,0x30,0x03,0x01,0x01,0xFF,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,
+    0x04,0x18,0x30,0x16,0x80,0x14,0x35,0x20,0x26,0xCE,0x85,0xBE,0x49,0x26,0x20,0x01,
+    0xDD,0xC8,0xEE,0xFF,0x3D,0x68,0xC8,0xD0,0xDF,0xF5,0x30,0x32,0x06,0x03,0x55,0x1D,
+    0x1F,0x04,0x2B,0x30,0x29,0x30,0x27,0xA0,0x25,0xA0,0x23,0x86,0x21,0x68,0x74,0x74,
+    0x70,0x3A,0x2F,0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,
+    0x6D,0x2F,0x63,0x6F,0x72,0x70,0x72,0x6F,0x6F,0x74,0x2E,0x63,0x72,0x6C,0x30,0x0E,
+    0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x01,0x06,0x30,0x10,
+    0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,0x06,0x18,0x04,0x04,0x02,0x05,0x00,
+    0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,
+    0x82,0x01,0x01,0x00,0x0D,0x34,0x2F,0xB2,0xC2,0xF1,0xF0,0xDC,0xA2,0x9F,0x8F,0x41,
+    0x9C,0x84,0xCA,0x66,0xDC,0x90,0x9C,0xC4,0x90,0xC9,0xDA,0xD9,0x37,0x4F,0xAE,0xC9,
+    0xD9,0xCF,0xE2,0x4B,0x8E,0x59,0x47,0x9A,0x83,0x32,0xDF,0xA7,0x97,0x45,0x9D,0x1E,
+    0x46,0x58,0x5D,0xD7,0x1C,0x17,0xC5,0x1C,0x9E,0xA2,0x74,0xF6,0x73,0x77,0xF9,0x35,
+    0xAD,0x67,0xC3,0x3C,0xD5,0x87,0x1E,0x96,0x16,0x3D,0x8B,0x40,0x51,0xA8,0x16,0xA0,
+    0x53,0x1C,0xF5,0xCB,0x32,0xC4,0xA8,0xC5,0x2A,0x3A,0x21,0xD9,0xFD,0x51,0x81,0x59,
+    0x6F,0x1B,0xF9,0x40,0x86,0x96,0xCF,0xA0,0x73,0xA3,0x5B,0x60,0x02,0xB6,0x21,0xAD,
+    0x39,0xF5,0xFA,0xFC,0xA8,0x6E,0x34,0x01,0x7C,0x59,0xF3,0x73,0xFC,0xBA,0xBE,0xF4,
+    0x4E,0x16,0x36,0x9E,0x51,0x77,0x80,0xF5,0xA1,0xC7,0xAE,0xFF,0x04,0x71,0x6B,0xB3,
+    0xBE,0x3E,0xA7,0xD1,0x74,0x2B,0x4D,0x58,0x58,0x3B,0x94,0x74,0xA3,0x65,0x27,0xC1,
+    0x74,0xA9,0xD2,0xF9,0x8A,0x81,0xB3,0x47,0xB3,0x06,0x8E,0x9C,0xE6,0x42,0x86,0x77,
+    0xF8,0x96,0x99,0x1F,0xED,0x30,0x8F,0x4B,0xD5,0x0F,0x5E,0x71,0x6C,0xAC,0xDB,0x48,
+    0xE3,0x3C,0x58,0x2B,0xE8,0x9B,0x9E,0x24,0x8A,0x5D,0xCD,0x56,0x5F,0xA9,0x07,0xEA,
+    0xCD,0x2C,0x94,0x3D,0xA7,0x7F,0x1B,0xE8,0x10,0xB8,0xD2,0x1E,0x43,0x5A,0x0D,0x13,
+    0xDA,0xF5,0x3F,0x10,0x9D,0x2D,0x1F,0xE6,0x94,0x11,0x2F,0x40,0xFF,0x5F,0x21,0x96,
+    0x02,0xF0,0x5F,0x54,0x56,0x32,0x90,0xD5,0x67,0xAE,0x29,0x0E,0x22,0x70,0xE3,0x2B,
+    0x7A,0x95,0xC0,0xC7,
+};
+
+/* subject:/CN=bbasile-test.scv.apple.com/OU=management:idms.group.631731/O=Apple Inc./ST=California/C=US */
+/* issuer :/CN=Apple Corporate Server CA 1/OU=Certification Authority/O=Apple Inc./C=US */
+uint8_t _corporateServerCert[] = {
+    0x30,0x82,0x05,0xF4,0x30,0x82,0x04,0xDC,0xA0,0x03,0x02,0x01,0x02,0x02,0x08,0x54,
+    0x32,0x9C,0xE6,0xE6,0xD7,0x87,0x7E,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x6A,0x31,0x24,0x30,0x22,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x1B,0x41,0x70,0x70,0x6C,0x65,0x20,0x43,0x6F,0x72,0x70,0x6F,0x72,0x61,
+    0x74,0x65,0x20,0x53,0x65,0x72,0x76,0x65,0x72,0x20,0x43,0x41,0x20,0x31,0x31,0x20,
+    0x30,0x1E,0x06,0x03,0x55,0x04,0x0B,0x0C,0x17,0x43,0x65,0x72,0x74,0x69,0x66,0x69,
+    0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x41,0x75,0x74,0x68,0x6F,0x72,0x69,0x74,0x79,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,
+    0x55,0x53,0x30,0x1E,0x17,0x0D,0x31,0x38,0x30,0x39,0x32,0x37,0x30,0x34,0x32,0x30,
+    0x34,0x31,0x5A,0x17,0x0D,0x32,0x30,0x31,0x30,0x32,0x36,0x30,0x34,0x32,0x30,0x34,
+    0x31,0x5A,0x30,0x81,0x83,0x31,0x23,0x30,0x21,0x06,0x03,0x55,0x04,0x03,0x0C,0x1A,
+    0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,
+    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x31,0x25,0x30,0x23,0x06,0x03,
+    0x55,0x04,0x0B,0x0C,0x1C,0x6D,0x61,0x6E,0x61,0x67,0x65,0x6D,0x65,0x6E,0x74,0x3A,
+    0x69,0x64,0x6D,0x73,0x2E,0x67,0x72,0x6F,0x75,0x70,0x2E,0x36,0x33,0x31,0x37,0x33,
+    0x31,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,
+    0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,
+    0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x0B,0x30,0x09,0x06,
+    0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,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,0xAF,0x8C,0xB9,0x3F,0x56,0x41,0xF9,
+    0xA5,0x93,0x89,0x95,0x58,0x31,0x90,0x84,0xD5,0x3E,0xBB,0xE4,0x7C,0x68,0xD4,0x5B,
+    0x95,0x97,0x04,0xEF,0xE6,0x3C,0x8E,0x6A,0x98,0xD0,0xAD,0xDD,0x7A,0xF1,0x5E,0x4D,
+    0xCF,0x40,0xEF,0x05,0xF7,0x02,0x8C,0x01,0x0B,0x74,0x9D,0x0C,0x7E,0xD1,0xF8,0x80,
+    0x6E,0xAA,0xBF,0x96,0xB3,0x50,0x8F,0xB4,0x68,0x0C,0xFA,0xD0,0xDB,0xE7,0x93,0xA0,
+    0x6A,0x84,0xF2,0xA3,0x90,0x62,0x54,0xBD,0xB0,0xB3,0x1F,0xD6,0x0E,0xD1,0x2B,0xBA,
+    0x13,0x38,0x0A,0xD1,0x84,0x36,0x75,0x77,0xFB,0x3B,0x1E,0x61,0x1B,0x85,0x22,0xA9,
+    0xF9,0x42,0xD6,0xA2,0x9B,0xCB,0x34,0x76,0xC0,0xAE,0x2B,0xB0,0x64,0x95,0x5B,0xC7,
+    0x61,0x2A,0x0B,0x81,0xE0,0x01,0x34,0xB8,0x50,0xDC,0x26,0x77,0x55,0xF7,0x95,0xE1,
+    0xEC,0x01,0x4F,0xA8,0x0E,0x89,0x25,0xFE,0x8E,0xAB,0x40,0x6E,0x17,0x14,0xAA,0xA8,
+    0x6C,0x79,0x52,0xDC,0xE3,0xDA,0x15,0xBF,0xAF,0x3C,0x96,0x2B,0xA3,0x4D,0xFA,0xC5,
+    0xB5,0x36,0xCD,0x2F,0x88,0xFF,0xD1,0x1E,0xB1,0xE6,0x7C,0x0E,0xBD,0x60,0x0A,0x78,
+    0xF7,0x8A,0x22,0x86,0xAD,0xC7,0x43,0x73,0xD7,0x22,0x64,0x32,0xA8,0xEC,0xEB,0x4F,
+    0x41,0x90,0xCC,0x2F,0xB5,0x1A,0xA4,0xE6,0x91,0x34,0x86,0xCA,0x0A,0x17,0x0B,0x28,
+    0x5F,0x94,0xAE,0x4C,0xDB,0x94,0x7A,0xD9,0xC3,0x4A,0x09,0x11,0xFA,0x33,0x6A,0x99,
+    0x85,0x66,0x12,0x0A,0x70,0x7D,0x99,0x88,0xBE,0xC8,0x4E,0xCF,0x01,0xD8,0xD1,0x54,
+    0x46,0x85,0x66,0x31,0x37,0xB3,0x7E,0x0F,0x45,0x02,0x03,0x01,0x00,0x01,0xA3,0x82,
+    0x02,0x82,0x30,0x82,0x02,0x7E,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,
+    0x04,0x02,0x30,0x00,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,0x16,0x80,
+    0x14,0xB6,0x23,0xB5,0x5A,0xEB,0x7E,0xEB,0xB6,0xF3,0x28,0x1E,0x04,0xD0,0xAD,0x5C,
+    0x93,0xA9,0xA4,0x9A,0x6D,0x30,0x81,0x83,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x01,0x01,0x04,0x77,0x30,0x75,0x30,0x39,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,
+    0x30,0x02,0x86,0x2D,0x68,0x74,0x74,0x70,0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x73,
+    0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,0x70,0x70,0x6C,0x65,
+    0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x2E,0x64,0x65,
+    0x72,0x30,0x38,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,0x86,0x2C,0x68,
+    0x74,0x74,0x70,0x3A,0x2F,0x2F,0x6F,0x63,0x73,0x70,0x2E,0x61,0x70,0x70,0x6C,0x65,
+    0x2E,0x63,0x6F,0x6D,0x2F,0x6F,0x63,0x73,0x70,0x30,0x33,0x2D,0x63,0x6F,0x72,0x70,
+    0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,0x31,0x30,0x34,0x30,0x25,0x06,0x03,0x55,
+    0x1D,0x11,0x04,0x1E,0x30,0x1C,0x82,0x1A,0x62,0x62,0x61,0x73,0x69,0x6C,0x65,0x2D,
+    0x74,0x65,0x73,0x74,0x2E,0x73,0x63,0x76,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,
+    0x6F,0x6D,0x30,0x82,0x01,0x12,0x06,0x03,0x55,0x1D,0x20,0x04,0x82,0x01,0x09,0x30,
+    0x82,0x01,0x05,0x30,0x82,0x01,0x01,0x06,0x0A,0x2A,0x86,0x48,0x86,0xF7,0x63,0x64,
+    0x05,0x0F,0x02,0x30,0x81,0xF2,0x30,0x81,0xA4,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,
+    0x07,0x02,0x02,0x30,0x81,0x97,0x0C,0x81,0x94,0x52,0x65,0x6C,0x69,0x61,0x6E,0x63,
+    0x65,0x20,0x6F,0x6E,0x20,0x74,0x68,0x69,0x73,0x20,0x63,0x65,0x72,0x74,0x69,0x66,
+    0x69,0x63,0x61,0x74,0x65,0x20,0x62,0x79,0x20,0x61,0x6E,0x79,0x20,0x70,0x61,0x72,
+    0x74,0x79,0x20,0x61,0x73,0x73,0x75,0x6D,0x65,0x73,0x20,0x61,0x63,0x63,0x65,0x70,
+    0x74,0x61,0x6E,0x63,0x65,0x20,0x6F,0x66,0x20,0x61,0x6E,0x79,0x20,0x61,0x70,0x70,
+    0x6C,0x69,0x63,0x61,0x62,0x6C,0x65,0x20,0x74,0x65,0x72,0x6D,0x73,0x20,0x61,0x6E,
+    0x64,0x20,0x63,0x6F,0x6E,0x64,0x69,0x74,0x69,0x6F,0x6E,0x73,0x20,0x6F,0x66,0x20,
+    0x75,0x73,0x65,0x20,0x61,0x6E,0x64,0x2F,0x6F,0x72,0x20,0x63,0x65,0x72,0x74,0x69,
+    0x66,0x69,0x63,0x61,0x74,0x69,0x6F,0x6E,0x20,0x70,0x72,0x61,0x63,0x74,0x69,0x63,
+    0x65,0x20,0x73,0x74,0x61,0x74,0x65,0x6D,0x65,0x6E,0x74,0x73,0x2E,0x30,0x49,0x06,
+    0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x02,0x01,0x16,0x3D,0x68,0x74,0x74,0x70,0x73,
+    0x3A,0x2F,0x2F,0x63,0x65,0x72,0x74,0x69,0x66,0x69,0x63,0x61,0x74,0x65,0x6D,0x61,
+    0x6E,0x61,0x67,0x65,0x72,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,
+    0x23,0x68,0x65,0x6C,0x70,0x2F,0x70,0x6F,0x6C,0x69,0x63,0x69,0x65,0x73,0x2F,0x63,
+    0x6F,0x72,0x70,0x6F,0x72,0x61,0x74,0x65,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,
+    0x16,0x30,0x14,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x03,0x02,0x30,0x3C,0x06,0x03,0x55,0x1D,0x1F,0x04,0x35,
+    0x30,0x33,0x30,0x31,0xA0,0x2F,0xA0,0x2D,0x86,0x2B,0x68,0x74,0x74,0x70,0x3A,0x2F,
+    0x2F,0x63,0x72,0x6C,0x2E,0x61,0x70,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x2F,0x61,
+    0x70,0x70,0x6C,0x65,0x63,0x6F,0x72,0x70,0x73,0x65,0x72,0x76,0x65,0x72,0x63,0x61,
+    0x31,0x2E,0x63,0x72,0x6C,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,0x04,0x14,
+    0x62,0xF3,0x37,0xB1,0x58,0x48,0x8F,0x49,0xEA,0x12,0x39,0x93,0x4C,0x17,0x91,0x07,
+    0x2F,0x71,0x09,0x4B,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,
+    0x03,0x02,0x05,0xA0,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,
+    0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0xE3,0xCE,0x7C,0xAC,0x0A,0xDE,0x21,0xB9,
+    0xB0,0x9E,0x1C,0xE9,0x6B,0xD5,0xBC,0xB7,0x53,0xE7,0x16,0x62,0xB0,0x1D,0x3E,0x53,
+    0xFE,0x47,0x1A,0x1A,0xA3,0x7A,0x69,0xC5,0xC0,0x8B,0xC9,0x0B,0xE1,0xBC,0xF6,0xE6,
+    0xAC,0x7E,0x05,0x60,0xC2,0xC2,0x3C,0xBA,0xB4,0x39,0xF7,0xDD,0xA4,0x60,0xC8,0x5B,
+    0x29,0x90,0x59,0x29,0xCF,0xC1,0x6D,0x38,0x38,0x83,0x81,0xFA,0x8A,0xB6,0x13,0xE6,
+    0xC6,0xDA,0x64,0xD5,0x19,0x40,0x82,0x8C,0x38,0xC9,0xBE,0xC4,0x81,0xBA,0x88,0xC6,
+    0x62,0xEC,0x42,0xED,0xCE,0x22,0xD2,0x52,0xE2,0x96,0x8C,0x3C,0xBC,0xCA,0xD4,0xF0,
+    0xC8,0x24,0x09,0xA1,0xC6,0xD3,0x44,0x4F,0x22,0x36,0xF8,0x6F,0x28,0x20,0x9C,0x0C,
+    0x71,0x10,0xCC,0x13,0x46,0x40,0xCF,0x15,0xF6,0x16,0x59,0xB2,0xC4,0xE6,0xDA,0x3D,
+    0x9C,0xB4,0x01,0x33,0x4E,0x01,0x87,0xFC,0xEB,0x4B,0x45,0x0E,0x6C,0x14,0x93,0x48,
+    0xA0,0x78,0xFA,0x0C,0x01,0xB0,0xEB,0xF1,0x6F,0x7B,0xE9,0xF4,0xED,0x42,0x92,0x07,
+    0x3B,0xFC,0x14,0x15,0x69,0xE7,0x1E,0x33,0xD8,0x7C,0xE1,0xD6,0x37,0xBB,0x13,0x50,
+    0x3E,0x3C,0x4A,0xD4,0x29,0xC7,0x29,0x3B,0x99,0x79,0xD5,0x92,0x96,0x64,0x28,0x0A,
+    0x7A,0x4F,0x8C,0x4A,0x32,0xC6,0x49,0x9D,0x05,0x0E,0x25,0x2F,0x46,0x6D,0x60,0x83,
+    0xA6,0x06,0x05,0x07,0x3F,0x50,0xFF,0x01,0x6C,0x3E,0xE2,0x71,0x09,0x74,0xD2,0x94,
+    0xEB,0x17,0xF4,0xE7,0x2B,0xB0,0xFD,0x41,0x52,0xEF,0x25,0x71,0x9C,0x1C,0x36,0xA6,
+    0x05,0x15,0xA6,0xD5,0x1E,0x23,0xB7,0xC2,
+};
+
+#endif /* _TRUSTTESTS_EVALUATION_TRUST_SETTINGS_TESTS_H_ */
diff --git a/tests/TrustTests/EvaluationTests/ValidTests.m b/tests/TrustTests/EvaluationTests/ValidTests.m
new file mode 100644 (file)
index 0000000..016b53f
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  Copyright (c) 2017-2019 Apple Inc. All Rights Reserved.
+ *
+ */
+
+#import <XCTest/XCTest.h>
+#import <Foundation/Foundation.h>
+
+#include <Security/Security.h>
+#include <Security/SecTrust.h>
+#include <Security/SecPolicy.h>
+#include <Security/SecCertificatePriv.h>
+#include <utilities/SecCFWrappers.h>
+#include "trust/trustd/OTATrustUtilities.h"
+
+#import "../TestMacroConversions.h"
+#import "TrustEvaluationTestCase.h"
+
+enum {
+    kBasicPolicy = 0,
+    kSSLServerPolicy = 1,
+};
+
+@interface ValidTests : TrustEvaluationTestCase
+@end
+
+@implementation ValidTests
+
+#if !TARGET_OS_BRIDGE
+- (void) run_valid_trust_test:(SecCertificateRef)leaf
+                           ca:(SecCertificateRef)ca
+                        subca:(SecCertificateRef)subca
+                      anchors:(CFArrayRef)anchors
+                         date:(CFDateRef)date
+                     policyID:(CFIndex)policyID
+                     expected:(SecTrustResultType)expected
+                    test_name:(const char *)test_name
+{
+    CFArrayRef policies=NULL;
+    SecPolicyRef policy=NULL;
+    SecTrustRef trust=NULL;
+    SecTrustResultType trustResult;
+    CFMutableArrayRef certs=NULL;
+
+    printf("Starting %s\n", test_name);
+    isnt(certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create cert array");
+    if (certs) {
+        if (leaf) {
+            CFArrayAppendValue(certs, leaf);
+        }
+        if (ca) {
+            CFArrayAppendValue(certs, ca);
+        }
+        if (subca) {
+            CFArrayAppendValue(certs, subca);
+        }
+    }
+
+    if (policyID == kSSLServerPolicy) {
+        isnt(policy = SecPolicyCreateSSL(true, NULL), NULL, "create ssl policy");
+    } else {
+        isnt(policy = SecPolicyCreateBasicX509(), NULL, "create basic policy");
+    }
+    isnt(policies = CFArrayCreate(kCFAllocatorDefault, (const void **)&policy, 1, &kCFTypeArrayCallBacks), NULL, "create policies");
+    ok_status(SecTrustCreateWithCertificates(certs, policies, &trust), "create trust");
+
+    assert(trust); // silence analyzer
+    ok_status(SecTrustSetAnchorCertificates(trust, anchors), "set anchors");
+    ok_status(SecTrustSetVerifyDate(trust, date), "set date");
+    ok_status(SecTrustGetTrustResult(trust, &trustResult), "evaluate trust");
+    ok(trustResult == expected, "trustResult %d expected (got %d) for %s",
+       (int)expected, (int)trustResult, test_name);
+
+    CFReleaseSafe(certs);
+    CFReleaseSafe(policy);
+    CFReleaseSafe(policies);
+    CFReleaseSafe(trust);
+}
+
+- (SecCertificateRef) CF_RETURNS_RETAINED createCertFromResource:(NSString *)name
+{
+    id cert = [self SecCertificateCreateFromPEMResource:name subdirectory:@"si-88-sectrust-valid-data"];
+    return (__bridge SecCertificateRef)cert;
+}
+
+- (void)test_date_constraints
+{
+    SecCertificateRef ca_na=NULL, ca_nb=NULL, root=NULL;
+    SecCertificateRef leaf_na_ok1=NULL, leaf_na_ok2=NULL;
+    SecCertificateRef leaf_nb_ok1=NULL, leaf_nb_ok2=NULL, leaf_nb_revoked1=NULL;
+
+    isnt(ca_na = [self createCertFromResource:@"ca-na"], NULL, "create ca-na cert");
+    isnt(ca_nb = [self createCertFromResource:@"ca-nb"], NULL, "create ca-nb cert");
+    isnt(root = [self createCertFromResource:@"root"], NULL, "create root cert");
+    isnt(leaf_na_ok1 = [self createCertFromResource:@"leaf-na-ok1"], NULL, "create leaf-na-ok1 cert");
+    isnt(leaf_na_ok2 = [self createCertFromResource:@"leaf-na-ok2"], NULL, "create leaf-na-ok2 cert");
+    isnt(leaf_nb_ok1 = [self createCertFromResource:@"leaf-nb-ok1"], NULL, "create leaf-nb-ok1 cert");
+    isnt(leaf_nb_ok2 = [self createCertFromResource:@"leaf-nb-ok2"], NULL, "create leaf-nb-ok2 cert");
+    isnt(leaf_nb_revoked1 = [self createCertFromResource:@"leaf-nb-revoked1"], NULL, "create leaf-nb-revoked1 cert");
+
+    CFMutableArrayRef anchors=NULL;
+    isnt(anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create anchors array");
+    if (anchors && root) {
+        CFArrayAppendValue(anchors, root);
+    }
+    CFCalendarRef cal = NULL;
+    CFAbsoluteTime at;
+    CFDateRef date_20180102 = NULL; // a date when our test certs would all be valid, in the absence of Valid db info
+
+    isnt(cal = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar), NULL, "create calendar");
+    ok(CFCalendarComposeAbsoluteTime(cal, &at, "yMd", 2018, 1, 2), "create verify absolute time 20180102");
+    isnt(date_20180102 = CFDateCreate(kCFAllocatorDefault, at), NULL, "create verify date 20180102");
+
+    /* Case 0: leaf_na_ok1 (not revoked) */
+    /* -- OK: cert issued 2017-10-20, before the CA not-after date of 2017-10-21 */
+    /*        test cert has no SCT, but is expected to be OK since we now only apply the CT restriction for SSL. */
+    [self run_valid_trust_test:leaf_na_ok1 ca:ca_na subca:NULL anchors:anchors date:date_20180102
+                      policyID:kBasicPolicy expected:kSecTrustResultUnspecified
+                     test_name:"leaf_na_ok1 basic"];
+
+    /* Case 1: leaf_na_ok1 (not revoked) */
+    /* -- BAD: since a not-after date now requires CT (for SSL) and the test cert has no SCT, this is fatal. */
+    /* Mock a successful mobile asset check-in so that we enforce CT */
+    XCTAssertTrue(UpdateOTACheckInDate(), "failed to set check-in date as now");
+    [self run_valid_trust_test:leaf_na_ok1 ca:ca_na subca:NULL anchors:anchors date:date_20180102
+                      policyID:kSSLServerPolicy expected:kSecTrustResultFatalTrustFailure
+                     test_name:"leaf_na_ok1 ssl"];
+
+    /* Case 2: leaf_na_ok2 (revoked) */
+    /* -- BAD: cert issued 2017-10-26, after the CA not-after date of 2017-10-21 */
+    [self run_valid_trust_test:leaf_na_ok2 ca:ca_na subca:NULL anchors:anchors date:date_20180102
+                      policyID:kBasicPolicy expected:kSecTrustResultFatalTrustFailure
+                     test_name:"leaf_na_ok2 basic"];
+
+    /* Case 3: leaf_nb_ok1 (revoked) */
+    /* -- BAD: cert issued 2017-10-20, before the CA not-before date of 2017-10-22 */
+    [self run_valid_trust_test:leaf_nb_ok1 ca:ca_nb subca:NULL anchors:anchors date:date_20180102
+                      policyID:kBasicPolicy expected:kSecTrustResultFatalTrustFailure
+                     test_name:"leaf_nb_ok1 basic"];
+
+    /* Case 4: leaf_nb_ok2 (not revoked) */
+    /* -- OK: cert issued 2017-10-26, after the CA not-before date of 2017-10-22 */
+    [self run_valid_trust_test:leaf_nb_ok2 ca:ca_nb subca:NULL anchors:anchors date:date_20180102
+                      policyID:kBasicPolicy expected:kSecTrustResultUnspecified
+                     test_name:"leaf_nb_ok2 basic"];
+
+    /* Case 5: leaf_nb_revoked1 (revoked) */
+    /* -- BAD: cert issued 2017-10-20, before the CA not-before date of 2017-10-22 */
+    [self run_valid_trust_test:leaf_nb_revoked1 ca:ca_nb subca:NULL anchors:anchors date:date_20180102
+                      policyID:kBasicPolicy expected:kSecTrustResultFatalTrustFailure
+                     test_name:"leaf_nb_revoked1 basic"];
+
+    CFReleaseSafe(ca_na);
+    CFReleaseSafe(ca_nb);
+    CFReleaseSafe(leaf_na_ok1);
+    CFReleaseSafe(leaf_na_ok2);
+    CFReleaseSafe(leaf_nb_ok1);
+    CFReleaseSafe(leaf_nb_ok2);
+    CFReleaseSafe(leaf_nb_revoked1);
+    CFReleaseSafe(root);
+    CFReleaseSafe(anchors);
+    CFReleaseSafe(cal);
+    CFReleaseSafe(date_20180102);
+}
+
+- (void)test_known_intermediate
+{
+    SecCertificateRef ca_ki=NULL, root=NULL;
+    SecCertificateRef leaf_ki_ok1=NULL, leaf_ki_revoked1=NULL;
+    SecCertificateRef leaf_unknown=NULL, ca_unknown=NULL;
+
+    isnt(ca_ki = [self createCertFromResource:@"ca-ki"], NULL, "create ca-ki cert");
+    isnt(root = [self createCertFromResource:@"root"], NULL, "create root cert");
+    isnt(leaf_ki_ok1 = [self createCertFromResource:@"leaf-ki-ok1"], NULL, "create leaf-ki-ok1 cert");
+    isnt(leaf_ki_revoked1 = [self createCertFromResource:@"leaf-ki-revoked1"], NULL, "create leaf-ki-revoked1 cert");
+    isnt(ca_unknown = [self createCertFromResource:@"ca-unknown"], NULL, "create ca-unknown cert");
+    isnt(leaf_unknown = [self createCertFromResource:@"leaf-unknown"], NULL, "create leaf-unknown cert");
+
+    CFMutableArrayRef anchors=NULL;
+    isnt(anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks), NULL, "create anchors array");
+    if (anchors && root) {
+        CFArrayAppendValue(anchors, root);
+    }
+    CFCalendarRef cal = NULL;
+    CFAbsoluteTime at;
+    CFDateRef date_20180310 = NULL; // a date when our test certs would all be valid, in the absence of Valid db info
+
+    isnt(cal = CFCalendarCreateWithIdentifier(kCFAllocatorDefault, kCFGregorianCalendar), NULL, "create calendar");
+    ok(CFCalendarComposeAbsoluteTime(cal, &at, "yMd", 2018, 3, 10), "create verify absolute time 20180310");
+    isnt(date_20180310 = CFDateCreate(kCFAllocatorDefault, at), NULL, "create verify date 20180310");
+
+    /* Case 1: leaf_ki_ok1 */
+    /* -- OK: cert issued by a known intermediate */
+    [self run_valid_trust_test:leaf_ki_ok1 ca:ca_ki subca:NULL anchors:anchors date:date_20180310 policyID:kBasicPolicy expected:kSecTrustResultUnspecified test_name:"leaf_ki_ok1"];
+
+    /* Case 2: leaf_ki_revoked1 */
+    /* -- BAD: CA specifies known-only+complete serial blocklist; this cert is on the blocklist. */
+    [self run_valid_trust_test:leaf_ki_revoked1 ca:ca_ki subca:NULL anchors:anchors date:date_20180310 policyID:kBasicPolicy expected:kSecTrustResultFatalTrustFailure test_name:"leaf_ki_revoked"];
+
+    /* Case 3: leaf_unknown */
+    /* -- BAD: ca_unknown issued from ca_ki, but is not a known intermediate.
+     * ca_ki has a path len of 0 which would normally result in kSecTrustResultRecoverableTrustFailure;
+     * however, since known-intermediates is asserted for ca_ki (non-overridable), we expect a fatal failure. */
+    [self run_valid_trust_test:leaf_unknown ca:ca_unknown subca:ca_ki anchors:anchors date:date_20180310 policyID:kBasicPolicy expected:kSecTrustResultFatalTrustFailure test_name:"leaf_unknown test"];
+
+    CFReleaseSafe(ca_ki);
+    CFReleaseSafe(leaf_ki_ok1);
+    CFReleaseSafe(leaf_ki_revoked1);
+    CFReleaseSafe(ca_unknown);
+    CFReleaseSafe(leaf_unknown);
+    CFReleaseSafe(root);
+    CFReleaseSafe(anchors);
+    CFReleaseSafe(cal);
+    CFReleaseSafe(date_20180310);
+}
+#else /* TARGET_OS_BRIDGE */
+/* Valid is not supported on bridgeOS */
+- (void)testSkipTests
+{
+    XCTAssert(true);
+}
+#endif
+
+@end
index d102547eec879c103378acb5ae68cb1da202ef3c..b980d64a753e5345c3e8106423f9a6b70510fa27 100644 (file)
@@ -102,10 +102,10 @@ static SecTrustRef trust = nil;
 @implementation ValidityPeriodRestrictionTests
 // Note that the dates described in the test names are the issuance date not the VerifyDate
 
-- (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors error:(NSError **)error
+- (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors verifyTime:(NSTimeInterval)time error:(NSError **)error
 {
     SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("example.com"));
-    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:590000000.0]; // September 12, 2019 at 9:53:20 AM PDT
+    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:time];
     SecTrustRef trustRef = NULL;
     BOOL result = NO;
     CFErrorRef cferror = NULL;
@@ -129,6 +129,11 @@ errOut:
     return result;
 }
 
+- (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors error:(NSError **)error
+{
+    return [self runTrustEvaluation:certs anchors:anchors verifyTime:590000000.0 error:error]; // September 12, 2019 at 9:53:20 AM PDT
+}
+
 - (void)testSystemTrust_MoreThan5Years
 {
     [self setTestRootAsSystem:_testValidityPeriodsRootHash];
@@ -220,6 +225,42 @@ errOut:
     CFReleaseNull(leaf);
 }
 
+- (void)testSystemTrust_MoreThan398Days_AfterSep2020
+{
+    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
+    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
+    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_2Years, sizeof(_testLeaf_2Years));
+
+    NSError *error = nil;
+    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf]
+                                    anchors:@[(__bridge id)root]
+                                 verifyTime:621000000.0 // September 5, 2020 at 5:00:00 AM PDT
+                                      error:&error],
+                  "system-trusted 2 year cert issued after 1 Sept 2020 failed: %@", error);
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(root);
+    CFReleaseNull(leaf);
+}
+
+- (void)testSystemTrust_398Days_AfterSep2020
+{
+    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
+    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
+    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_398Days, sizeof(_testLeaf_398Days));
+
+    NSError *error = nil;
+    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf]
+                                   anchors:@[(__bridge id)root]
+                                verifyTime:621000000.0 // September 5, 2020 at 5:00:00 AM PDT
+                                     error:&error],
+                  "system-trusted 398 day cert issued after 1 Sept 2020 failed: %@", error);
+
+    [self removeTestRootAsSystem];
+    CFReleaseNull(root);
+    CFReleaseNull(leaf);
+}
+
 - (void)testAppTrustRoot_MoreThan825Days_AfterJul2019
 {
     SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
index 3948974f3d33d269827aa1e0d877fc763160f446..a03e8a08b7d691dc4b9013d911546310938b07be 100644 (file)
@@ -825,4 +825,191 @@ const uint8_t _testLeaf_825Days[] = {
     0x2B,0x61,0x37,0x1B,0x25,0xFF,0xC6,0x02,0x2F,0x83,0xEE,0xF3,0x27,0x00,0xE9,0x73,
     0xC8,0xDC,0x49,0xDE,0x0B,0x80,0x4B,0x17,0x17,0x7B,0x13,0x79,0x56,
 };
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Validity Period Maximums 2 Year Leaf */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Validity Period Maximums Test Root */
+/*  Not Before: Sep  1 00:05:55 2020 GMT
+    Not After : Sep  1 00:05:55 2022 GMT */
+const uint8_t _testLeaf_2Years[] = {
+    0x30,0x82,0x05,0x58,0x30,0x82,0x03,0x40,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x4B,
+    0x8D,0xD7,0x1D,0x8B,0x58,0x14,0x25,0xFD,0x5A,0xF1,0xBF,0xD9,0xA3,0x44,0x41,0x38,
+    0xBA,0xF1,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
+    0x00,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
+    0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,
+    0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,
+    0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
+    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x2B,
+    0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x0C,0x22,0x56,0x61,0x6C,0x69,0x64,0x69,0x74,
+    0x79,0x20,0x50,0x65,0x72,0x69,0x6F,0x64,0x20,0x4D,0x61,0x78,0x69,0x6D,0x75,0x6D,
+    0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x32,
+    0x30,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x35,0x35,0x35,0x5A,0x17,0x0D,0x32,0x32,
+    0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x35,0x35,0x35,0x5A,0x30,0x81,0x99,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,
+    0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,
+    0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,
+    0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,
+    0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,
+    0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,
+    0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x2D,0x30,0x2B,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x24,0x56,0x61,0x6C,0x69,0x64,0x69,0x74,0x79,0x20,0x50,0x65,0x72,0x69,
+    0x6F,0x64,0x20,0x4D,0x61,0x78,0x69,0x6D,0x75,0x6D,0x73,0x20,0x32,0x20,0x59,0x65,
+    0x61,0x72,0x20,0x4C,0x65,0x61,0x66,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,0xC8,0xF2,0x3C,0xD6,0x71,0xC6,0xD7,0x8A,
+    0xC1,0xC9,0xC4,0x99,0xD6,0x51,0x52,0x64,0xCB,0x8A,0x92,0x48,0x7C,0x83,0x15,0x82,
+    0xE3,0x35,0x9E,0x2C,0x43,0xC3,0x38,0x7F,0xC0,0xF1,0xC9,0x44,0xC0,0x9D,0x52,0x3B,
+    0x4A,0x0F,0x8A,0xD3,0x8E,0xA9,0xE9,0xA1,0x5D,0x93,0xA7,0xB3,0xD0,0x20,0x9C,0x53,
+    0x62,0xE5,0x8D,0xBF,0xD8,0x3C,0x33,0x49,0x2C,0x82,0x65,0xF5,0x48,0xAA,0xF3,0xD7,
+    0x8F,0x23,0x4B,0x3F,0x89,0xC3,0x8E,0xD2,0xAB,0xF6,0xFA,0x56,0x51,0xD2,0x42,0xBD,
+    0x88,0x9D,0x43,0x75,0xE4,0xE8,0x6D,0xB7,0xF3,0xD1,0xEC,0x9F,0xD8,0xAB,0x23,0xEC,
+    0xFC,0x5F,0x87,0xCB,0xB8,0xC4,0xD5,0xE5,0xDD,0x2B,0x79,0x53,0xCF,0x43,0x2A,0x57,
+    0x10,0x19,0xA5,0x57,0x92,0x9A,0xD0,0xB7,0xF0,0xE8,0x7C,0xAA,0xCB,0xF1,0xB8,0xC3,
+    0xC0,0x53,0x5C,0xDE,0x5D,0xB0,0x47,0x38,0xC2,0x81,0xE5,0xD3,0x39,0x84,0xB5,0x64,
+    0xB0,0x59,0xE7,0x7C,0xEB,0x92,0x5B,0xB1,0xF9,0x82,0x95,0x45,0x14,0x5D,0x17,0x5C,
+    0x4F,0x49,0x54,0x36,0xF0,0xCB,0xF5,0x7E,0x3E,0xAF,0x14,0x00,0x06,0x73,0x77,0x59,
+    0xD7,0xB4,0xA8,0x49,0xCE,0x7C,0x55,0x1C,0xC4,0x79,0x6E,0x0D,0xD1,0x04,0xF0,0x2E,
+    0xC5,0xF3,0x8A,0xA7,0xC5,0x9F,0xB0,0xED,0x3D,0x13,0x80,0x94,0x1E,0xDC,0xF3,0x81,
+    0x97,0x52,0x4F,0x62,0x83,0xD6,0x02,0xFB,0x9B,0x03,0xE1,0x29,0xD0,0x7D,0x18,0x4B,
+    0xDB,0xEE,0x69,0xF4,0xC7,0x98,0xA1,0xBB,0x62,0xCE,0xD2,0x7B,0x2E,0x0F,0xD5,0x06,
+    0xE8,0x5E,0x47,0x00,0x20,0x00,0xC5,0x11,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x98,
+    0x30,0x81,0x95,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,
+    0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,
+    0x80,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x02,
+    0x30,0x16,0x06,0x03,0x55,0x1D,0x11,0x04,0x0F,0x30,0x0D,0x82,0x0B,0x65,0x78,0x61,
+    0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,
+    0x16,0x04,0x14,0xD3,0x39,0x1B,0x96,0x50,0xE7,0x23,0x59,0x7C,0x88,0xF9,0x64,0x2B,
+    0xF9,0x60,0x70,0x72,0xE7,0x78,0xE6,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,
+    0x30,0x16,0x80,0x14,0xDE,0xEB,0xFD,0x98,0xFD,0xCA,0x44,0xC1,0xFA,0xB7,0xF9,0x2B,
+    0xF5,0x96,0x67,0x08,0x11,0x35,0x27,0x75,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x37,0x45,0x43,0xE5,
+    0x3A,0x7C,0xFC,0xFF,0x49,0xE2,0xC6,0x70,0xD8,0xB6,0x51,0x7D,0x61,0x6D,0x1A,0x87,
+    0x5F,0x86,0x2B,0xE4,0xFF,0x30,0x5B,0xBB,0xD5,0x2D,0x4B,0x95,0x9C,0x7B,0xDA,0x57,
+    0xC8,0xA7,0x12,0x12,0x55,0x48,0x16,0x04,0xBD,0xE2,0x2A,0xC1,0xE0,0x34,0x0D,0xC3,
+    0x18,0x25,0xD1,0xA7,0x1E,0x74,0xF6,0x0A,0xB0,0x70,0x41,0xF3,0x80,0xDA,0xBC,0xF0,
+    0xE3,0x84,0x5E,0x8A,0xFA,0x9C,0x2E,0x00,0x41,0x1B,0xB6,0x1D,0x82,0x3D,0x40,0xF4,
+    0x00,0xF1,0x88,0xCC,0x00,0x06,0xFC,0x61,0x94,0x93,0x55,0xD2,0x21,0x9B,0x3D,0xFE,
+    0xF7,0x82,0xE6,0x86,0xF6,0x39,0x4E,0xFA,0x3C,0x37,0x4E,0x25,0x7F,0x0A,0x5E,0x05,
+    0x43,0x4D,0x4E,0x22,0xED,0xB0,0xAA,0xAC,0x81,0x29,0xD4,0x6C,0xE1,0x21,0x2D,0x8E,
+    0x21,0x29,0x8A,0x44,0x29,0xD6,0x95,0x55,0x75,0x74,0x66,0xAB,0xC7,0xF2,0xC3,0xA6,
+    0x9B,0xE5,0x55,0x80,0x84,0xB5,0x9F,0x0C,0x2F,0x89,0x8E,0x35,0x26,0xDC,0x0C,0xA0,
+    0x72,0x1F,0xC2,0xCA,0x04,0x15,0x4D,0x4F,0xC6,0x01,0x25,0xDF,0xB4,0x76,0x8B,0x0F,
+    0xF0,0xC3,0xE0,0x76,0x02,0x01,0x6B,0x84,0x9D,0xC2,0xE3,0x3B,0x7A,0x9F,0x54,0x0E,
+    0xA0,0x0A,0x2A,0xC5,0x72,0x66,0x94,0x88,0x55,0xEC,0xCA,0x69,0x44,0x05,0x00,0x6C,
+    0x03,0xF6,0xCB,0x73,0xD5,0xE9,0xAE,0xE0,0x85,0x92,0x39,0x62,0xEB,0xDB,0xCC,0xDD,
+    0x89,0x82,0x07,0xA1,0xAB,0x60,0x97,0x4D,0x7A,0xC4,0xA1,0xA1,0x47,0xCA,0xA7,0xCC,
+    0xB5,0xE7,0xB4,0xB6,0x01,0x38,0xF9,0x4C,0x2F,0xC2,0xC1,0x44,0xC6,0xAF,0x5C,0xDD,
+    0x82,0xD8,0x8D,0xEE,0x42,0x8D,0xB5,0xE8,0x58,0x73,0x0E,0x0A,0xFC,0x0C,0xCC,0x35,
+    0xFE,0x5E,0x09,0x12,0x70,0xD0,0xA5,0xD2,0x38,0x27,0xBB,0xD0,0xA0,0xF6,0x61,0x44,
+    0xEA,0x2D,0xCE,0x54,0xEB,0xA4,0x57,0x52,0xF4,0x81,0xE2,0xFD,0x7B,0x0D,0x08,0x53,
+    0xD4,0x0D,0x6E,0x8B,0x4F,0xA2,0xD4,0xCF,0xBF,0x01,0xB4,0x0B,0x34,0x37,0xEE,0x89,
+    0x81,0xBD,0x36,0x87,0x39,0x5D,0x2D,0xE0,0x0E,0x19,0x28,0x26,0xDC,0x80,0xDB,0x22,
+    0x49,0x4B,0x5E,0xAF,0x17,0xB8,0x83,0xC5,0x32,0x66,0xF3,0x81,0x01,0x36,0x95,0xC5,
+    0xF2,0x49,0x81,0xDC,0xD8,0x07,0xF7,0x01,0xEE,0x8D,0x0F,0xDD,0x6A,0xDE,0x9E,0xDD,
+    0x5D,0x98,0x82,0xCD,0x2C,0x2B,0x02,0xD4,0xEC,0x55,0x9F,0x95,0x63,0x4C,0x2B,0x58,
+    0x16,0x8B,0x52,0x24,0x98,0x51,0x7C,0x0D,0xA9,0x47,0xE9,0xAA,0x70,0x94,0xC7,0xC1,
+    0x41,0x55,0x44,0x71,0x55,0x1D,0x05,0x4C,0xF3,0xCE,0xEB,0x40,0x4A,0xED,0x40,0x3D,
+    0xD1,0xAD,0x8A,0xF7,0xBF,0x0E,0x30,0xE0,0x20,0x60,0x64,0x0A,0xEB,0x9C,0x89,0x60,
+    0xC8,0x8D,0xF3,0x3A,0xE4,0x76,0x50,0xE2,0x2B,0x92,0xB1,0x0D,0xCD,0x66,0xCC,0x48,
+    0x16,0x84,0x26,0x54,0xF4,0x9F,0x0F,0x1C,0xC6,0x53,0x37,0xC9,0x11,0x18,0xAE,0x41,
+    0xED,0xE4,0x17,0xBE,0x5D,0x54,0xF1,0x9E,0x10,0x34,0x5E,0x28,0x32,0x65,0xB2,0x46,
+    0x25,0x63,0x5E,0x43,0xCB,0x6D,0x5E,0xEA,0xAC,0x4A,0x50,0x75,0x7E,0x6C,0x61,0xF4,
+    0xE6,0x5B,0xB6,0x7B,0xF6,0x6B,0xAD,0x96,0xD7,0xF3,0xF8,0x44,
+};
+
+/* subject:/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Validity Period Maximums 398 Day Leaf */
+/* issuer :/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=Security Engineering/CN=Validity Period Maximums Test Root */
+/*  Not Before: Sep  1 00:06:20 2020 GMT
+    Not After : Oct  4 00:06:20 2021 GMT */
+const uint8_t _testLeaf_398Days[] = {
+    0x30,0x82,0x05,0x59,0x30,0x82,0x03,0x41,0xA0,0x03,0x02,0x01,0x02,0x02,0x13,0x4B,
+    0x8D,0xD7,0x1D,0x8B,0x58,0x14,0x25,0xFD,0x5A,0xF1,0xBF,0xD9,0xA3,0x44,0x41,0x38,
+    0xBA,0xF2,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,
+    0x00,0x30,0x81,0x97,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,
+    0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,
+    0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,
+    0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,
+    0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,
+    0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,
+    0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x2B,
+    0x30,0x29,0x06,0x03,0x55,0x04,0x03,0x0C,0x22,0x56,0x61,0x6C,0x69,0x64,0x69,0x74,
+    0x79,0x20,0x50,0x65,0x72,0x69,0x6F,0x64,0x20,0x4D,0x61,0x78,0x69,0x6D,0x75,0x6D,
+    0x73,0x20,0x54,0x65,0x73,0x74,0x20,0x52,0x6F,0x6F,0x74,0x30,0x1E,0x17,0x0D,0x32,
+    0x30,0x30,0x39,0x30,0x31,0x30,0x30,0x30,0x36,0x32,0x30,0x5A,0x17,0x0D,0x32,0x31,
+    0x31,0x30,0x30,0x34,0x30,0x30,0x30,0x36,0x32,0x30,0x5A,0x30,0x81,0x9A,0x31,0x0B,
+    0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,
+    0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,
+    0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,
+    0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,
+    0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,
+    0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,
+    0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x2E,0x30,0x2C,0x06,0x03,0x55,0x04,
+    0x03,0x0C,0x25,0x56,0x61,0x6C,0x69,0x64,0x69,0x74,0x79,0x20,0x50,0x65,0x72,0x69,
+    0x6F,0x64,0x20,0x4D,0x61,0x78,0x69,0x6D,0x75,0x6D,0x73,0x20,0x33,0x39,0x38,0x20,
+    0x44,0x61,0x79,0x20,0x4C,0x65,0x61,0x66,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,0xA4,0xDD,0xA6,0x75,0x21,0xFC,0x44,
+    0x4D,0xF9,0x5D,0x69,0x5D,0xCF,0xE7,0xD1,0x88,0x37,0xAA,0x9A,0x60,0x25,0x0C,0x2C,
+    0x65,0xAA,0xF2,0x2A,0xDF,0x2F,0xA9,0x0C,0x61,0x40,0xCE,0xF1,0x87,0x81,0x74,0xA9,
+    0xCE,0xAE,0x2E,0x6E,0x4D,0x9E,0x72,0x34,0x51,0x9B,0x0A,0xD2,0x6F,0x46,0xEE,0xB1,
+    0x9B,0xAA,0xCF,0x2D,0xBA,0x32,0x4F,0x86,0x04,0x54,0x27,0x3C,0x95,0xEC,0xD2,0xC7,
+    0x26,0xD1,0x9B,0x02,0x33,0x90,0x38,0x7F,0x92,0xF9,0x1B,0x15,0xA4,0x19,0x83,0xBB,
+    0x51,0x38,0x2D,0x6C,0x4B,0x7A,0x68,0x54,0xCD,0x30,0x2F,0xC1,0x26,0x01,0xA0,0x60,
+    0xBB,0x79,0x9F,0xAD,0x28,0x2F,0xA5,0x17,0x69,0xA7,0xCD,0xEE,0xE3,0x61,0x83,0xB5,
+    0xBC,0xC2,0x6C,0xFA,0x85,0x75,0x7C,0x06,0x4D,0xEA,0xCB,0x39,0x42,0x21,0xB4,0x2F,
+    0x9C,0x81,0xAA,0x39,0x3F,0xAA,0xEC,0xF8,0xA1,0x65,0xF5,0x64,0x0A,0xB2,0xA3,0x71,
+    0x29,0xA2,0x74,0x12,0xE7,0x66,0xB5,0x1F,0xED,0xDF,0x2C,0xA8,0x0C,0xB7,0xD3,0x96,
+    0x33,0x92,0x1D,0xF4,0xA8,0x94,0xD7,0x08,0x58,0x65,0xDD,0x6C,0x99,0x52,0x05,0x31,
+    0xB6,0x0E,0x88,0xE2,0xE5,0xEB,0xCA,0x5A,0x30,0x9D,0x0C,0x68,0xC6,0x2B,0xB4,0x36,
+    0xF2,0xA0,0xD1,0x97,0xDB,0x49,0x78,0xAB,0x79,0x90,0xE5,0x7B,0xA5,0xAD,0xE5,0xB0,
+    0x13,0x85,0x74,0x75,0x15,0x82,0xC6,0x04,0x27,0x18,0x7C,0xE8,0x91,0x36,0x6E,0xF2,
+    0x64,0xE3,0x37,0x2E,0x0B,0x8D,0x4D,0x8D,0x6B,0xC2,0x44,0x18,0x01,0x95,0xDE,0x08,
+    0xAC,0x8D,0x00,0x5A,0xE9,0x09,0xEA,0xD1,0x0D,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,
+    0x98,0x30,0x81,0x95,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,
+    0x30,0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,
+    0x07,0x80,0x30,0x1D,0x06,0x03,0x55,0x1D,0x25,0x04,0x16,0x30,0x14,0x06,0x08,0x2B,
+    0x06,0x01,0x05,0x05,0x07,0x03,0x01,0x06,0x08,0x2B,0x06,0x01,0x05,0x05,0x07,0x03,
+    0x02,0x30,0x16,0x06,0x03,0x55,0x1D,0x11,0x04,0x0F,0x30,0x0D,0x82,0x0B,0x65,0x78,
+    0x61,0x6D,0x70,0x6C,0x65,0x2E,0x63,0x6F,0x6D,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,
+    0x04,0x16,0x04,0x14,0x81,0xE5,0x84,0xC1,0xB3,0x5E,0x70,0xD8,0x3A,0xF2,0x45,0x17,
+    0x92,0x8B,0x24,0xD5,0x07,0xB1,0x5D,0x96,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,
+    0x18,0x30,0x16,0x80,0x14,0xDE,0xEB,0xFD,0x98,0xFD,0xCA,0x44,0xC1,0xFA,0xB7,0xF9,
+    0x2B,0xF5,0x96,0x67,0x08,0x11,0x35,0x27,0x75,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,
+    0x86,0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x02,0x01,0x00,0x1B,0x19,0xDC,
+    0x50,0x5C,0x92,0x48,0x4F,0x0B,0x3D,0xAF,0x1B,0x9C,0x22,0x36,0xB2,0x24,0x2F,0xBB,
+    0xCB,0x05,0x5D,0xC8,0xA5,0x5F,0x43,0x47,0x0C,0x9A,0xCF,0xB5,0x1F,0x01,0x3F,0xE0,
+    0x84,0xCE,0xA9,0xC7,0x05,0xFD,0x6E,0xE7,0xD2,0xF6,0x07,0x7B,0xDF,0x57,0xD6,0x0F,
+    0x03,0x33,0xFE,0xB1,0xB6,0xBF,0x73,0xDF,0x69,0xEA,0x04,0xEA,0xFF,0x7C,0xBB,0x9E,
+    0xC4,0x01,0x9A,0xE5,0x6A,0x10,0x45,0x42,0xB2,0xDB,0xA2,0xC3,0x85,0xF4,0x82,0x1A,
+    0xE9,0x7B,0xDB,0xF4,0x53,0x3D,0x6B,0x2B,0xA0,0x1E,0x92,0x50,0x89,0x66,0xF3,0xF2,
+    0x58,0x8E,0x61,0xBC,0x1D,0x33,0xE8,0x13,0xAA,0xBF,0x2B,0x17,0x36,0x95,0x51,0xA1,
+    0x5C,0x9E,0x6B,0x3F,0xEF,0xBA,0x45,0x32,0x84,0xB1,0x81,0xEF,0x10,0xCA,0x05,0xB3,
+    0xD7,0x31,0x79,0x76,0x28,0x38,0xB0,0x2E,0x30,0xAC,0x74,0xFF,0xF4,0xFB,0x8F,0x08,
+    0x22,0x08,0x41,0x1B,0x67,0xB4,0x72,0x82,0x84,0x6E,0xC3,0x12,0x93,0x65,0xD4,0x9B,
+    0xD4,0x2E,0x55,0x6C,0x22,0x6A,0x22,0x36,0x26,0x2C,0x9F,0x5C,0xFC,0x85,0xB2,0x71,
+    0x0E,0x58,0x79,0x83,0x75,0x7E,0x65,0x50,0x18,0x05,0x95,0x2F,0xB6,0x05,0x6A,0xA8,
+    0x9F,0x1C,0x66,0xFC,0x6F,0x30,0xBE,0xC6,0x20,0x7A,0xF8,0xFC,0xB4,0x24,0x5E,0x4A,
+    0x26,0x4C,0xEC,0x48,0xF2,0x5A,0x7D,0x83,0xB1,0x86,0x69,0x48,0x69,0xC7,0xF3,0x2A,
+    0xFA,0xB1,0x58,0x69,0x77,0x96,0x67,0xE5,0x7E,0xE6,0xE9,0x07,0xFC,0xA4,0x24,0xC6,
+    0xC1,0x64,0x69,0xB4,0x36,0x59,0x81,0xA7,0xD4,0x14,0xEE,0xA5,0xDE,0x44,0x46,0x72,
+    0x52,0xB6,0x28,0xF7,0x33,0x5B,0xFA,0x71,0x8F,0xC9,0x9F,0xBE,0xBB,0xEF,0xB4,0x4B,
+    0x6A,0xA0,0x01,0xF1,0xA2,0x06,0x41,0xA4,0x8E,0x75,0xC8,0xAF,0x6C,0x31,0xCD,0xCB,
+    0x6E,0xB3,0xD1,0x4F,0x46,0x39,0x74,0xD1,0x82,0x75,0x3D,0x71,0x8C,0xD8,0xDE,0xD6,
+    0xDE,0x25,0x8A,0xD7,0x77,0xA7,0xD4,0xCA,0xCF,0x2A,0x35,0xA9,0xF4,0x19,0x81,0x98,
+    0x81,0x64,0x16,0xBD,0x0C,0xE7,0xED,0xAA,0x05,0xEB,0xED,0x4B,0x1B,0xEE,0x78,0xC4,
+    0x6C,0x93,0xDB,0x81,0xB2,0xD0,0x78,0x9D,0x66,0x41,0x91,0xF7,0xCD,0x82,0x45,0x8A,
+    0x81,0x3D,0xC3,0x79,0x15,0x9E,0x1D,0xE8,0x25,0xB8,0x8D,0xA7,0xA7,0xA7,0x74,0x43,
+    0xF7,0x43,0x80,0xF9,0x01,0xD3,0x81,0xDD,0xE4,0xFF,0x4A,0xC0,0x7C,0x44,0x30,0xB4,
+    0xFA,0x9E,0xA3,0x5E,0xE2,0x2B,0x23,0xFB,0x68,0xE9,0x1C,0xA2,0xA9,0xF1,0xD0,0x45,
+    0x50,0x3B,0xEC,0xEB,0x22,0xAC,0xBF,0x4E,0xE2,0x64,0xD7,0x0B,0xFE,0xB9,0xBE,0x28,
+    0xC2,0xFB,0xA8,0xC5,0x93,0xD9,0x35,0x88,0x48,0x0A,0x24,0x22,0xAF,0x85,0x21,0xC3,
+    0x9D,0x02,0x6E,0x9E,0x03,0xF6,0x78,0x66,0xCB,0x16,0x9E,0x74,0xF7,0xEB,0x85,0x63,
+    0x9B,0xD8,0x11,0xAF,0x60,0x9E,0xF8,0x9E,0x4E,0x8E,0xEC,0xAD,0x99,0x65,0xEE,0x57,
+    0x9C,0x59,0x53,0x7E,0xFE,0x1D,0xCA,0xED,0x17,0xAA,0x1C,0xF3,0xD9,0xC4,0x76,0xDF,
+    0x9A,0x64,0x77,0xD6,0x41,0x2D,0x16,0xE7,0xAD,0x7E,0xBF,0x0B,0xF1,0x87,0x6A,0xCF,
+    0x2A,0x7B,0x2B,0x8F,0x96,0xFF,0xA2,0xDC,0xE2,0x07,0xF0,0x0C,0x31,
+};
+
 #endif /* _TRUSTTESTS_EVALUATION_VERIFY_DATE_TESTS_H_ */
index 2e5c8dea163c6487dcbdb685ffb457630e7d1883..5194d302ebb5fb4903b00c0e403cff8023539dad 100644 (file)
@@ -38,6 +38,7 @@
 #include <utilities/SecCFRelease.h>
 #include "../TestMacroConversions.h"
 #include "TrustFrameworkTestCase.h"
+#include <libDER/oids.h>
 
 #include "CertificateInterfaceTests_data.h"
 
@@ -501,4 +502,38 @@ errOut:
     CFRelease(result6);
 }
 
+- (void)testCopyIPAddresses {
+    SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, _IPAddressCert, sizeof(_IPAddressCert));
+    NSArray *ipAddresses = CFBridgingRelease(SecCertificateCopyIPAddresses(cert));
+    XCTAssertNotNil(ipAddresses);
+    XCTAssertEqual(ipAddresses.count, 1);
+    XCTAssertEqualObjects(ipAddresses[0], @"10.0.0.1");
+    CFReleaseNull(cert);
+
+    cert = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1));
+    ipAddresses = CFBridgingRelease(SecCertificateCopyIPAddresses(cert));
+    XCTAssertNil(ipAddresses);
+    CFReleaseNull(cert);
+}
+
+- (void)testCopySubjectAttributeValue {
+    // ATV not present
+    SecCertificateRef devCert = SecCertificateCreateWithBytes(NULL, _new_developer_cert, sizeof(_new_developer_cert));
+    NSString *locality = CFBridgingRelease(SecCertificateCopySubjectAttributeValue(devCert, (DERItem *)&oidLocalityName));
+    XCTAssertNil(locality);
+
+    // ATV present
+    NSString *ou = CFBridgingRelease(SecCertificateCopySubjectAttributeValue(devCert, (DERItem *)&oidOrganizationalUnitName));
+    XCTAssertNotNil(ou);
+    XCTAssert([ou isEqualToString:@"PV45XFU466"]);
+    CFReleaseNull(devCert);
+
+    // pick the last value for multiple attributes
+    SecCertificateRef multipleValues = SecCertificateCreateWithBytes(NULL, two_common_names, sizeof(two_common_names));
+    NSString *commonName = CFBridgingRelease(SecCertificateCopySubjectAttributeValue(multipleValues, (DERItem *)&oidCommonName));
+    XCTAssertNotNil(commonName);
+    XCTAssert([commonName isEqualToString:@"certxauthsplit"]);
+    CFReleaseNull(multipleValues);
+}
+
 @end
index 50f227e32511818ef81f1a378c027166a722f50a..1a6bc4b1828b5573fc3703dd3ec942111ae41607 100644 (file)
@@ -994,4 +994,77 @@ const uint8_t _new_developer_cert[] = {
     0xA4,0x85,0x74,
 };
 
+/*  X509v3 Subject Alternative Name:
+        IP Address:10.0.0.1 */
+const uint8_t _IPAddressCert[] = {
+    0x30,0x82,0x04,0x37,0x30,0x82,0x03,0x1F,0xA0,0x03,0x02,0x01,0x02,0x02,0x09,0x00,
+    0xC7,0x90,0xC5,0x69,0xCA,0xE3,0xB4,0x07,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,
+    0xF7,0x0D,0x01,0x01,0x0B,0x05,0x00,0x30,0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,
+    0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,
+    0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,
+    0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,
+    0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,
+    0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,
+    0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,
+    0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,
+    0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,
+    0x20,0x49,0x50,0x20,0x41,0x64,0x64,0x72,0x65,0x73,0x73,0x20,0x53,0x41,0x4E,0x30,
+    0x1E,0x17,0x0D,0x31,0x39,0x31,0x31,0x30,0x38,0x30,0x30,0x31,0x34,0x32,0x31,0x5A,
+    0x17,0x0D,0x32,0x30,0x31,0x31,0x30,0x37,0x30,0x30,0x31,0x34,0x32,0x31,0x5A,0x30,
+    0x81,0x95,0x31,0x0B,0x30,0x09,0x06,0x03,0x55,0x04,0x06,0x13,0x02,0x55,0x53,0x31,
+    0x13,0x30,0x11,0x06,0x03,0x55,0x04,0x08,0x0C,0x0A,0x43,0x61,0x6C,0x69,0x66,0x6F,
+    0x72,0x6E,0x69,0x61,0x31,0x12,0x30,0x10,0x06,0x03,0x55,0x04,0x07,0x0C,0x09,0x43,
+    0x75,0x70,0x65,0x72,0x74,0x69,0x6E,0x6F,0x31,0x13,0x30,0x11,0x06,0x03,0x55,0x04,
+    0x0A,0x0C,0x0A,0x41,0x70,0x70,0x6C,0x65,0x20,0x49,0x6E,0x63,0x2E,0x31,0x1D,0x30,
+    0x1B,0x06,0x03,0x55,0x04,0x0B,0x0C,0x14,0x53,0x65,0x63,0x75,0x72,0x69,0x74,0x79,
+    0x20,0x45,0x6E,0x67,0x69,0x6E,0x65,0x65,0x72,0x69,0x6E,0x67,0x31,0x29,0x30,0x27,
+    0x06,0x03,0x55,0x04,0x03,0x0C,0x20,0x53,0x53,0x4C,0x20,0x50,0x6F,0x6C,0x69,0x63,
+    0x79,0x20,0x54,0x65,0x73,0x74,0x73,0x3A,0x20,0x49,0x50,0x20,0x41,0x64,0x64,0x72,
+    0x65,0x73,0x73,0x20,0x53,0x41,0x4E,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,0xC1,0x80,0xDE,0x51,0x33,0xB8,0x28,0xA8,
+    0x7D,0x94,0x12,0x73,0x6F,0x0E,0xFC,0xF5,0xF0,0xC6,0x18,0xD2,0x87,0xB8,0x37,0xEE,
+    0xF9,0xB1,0x69,0x1D,0xF9,0xE1,0x65,0x8D,0x47,0x34,0x50,0xBD,0x72,0x41,0x32,0x7A,
+    0x02,0x0F,0x72,0x85,0xB8,0xE1,0x3D,0x7C,0x78,0x90,0x0A,0x81,0x06,0x25,0x9B,0x13,
+    0xCA,0xD6,0xAA,0x77,0xDC,0x4A,0x9B,0x32,0xB7,0x1D,0xF1,0xEF,0x52,0x33,0xE3,0x5D,
+    0x80,0xE0,0xE1,0xBB,0xF2,0x5E,0x91,0x55,0xA1,0xF8,0xE4,0x25,0x62,0xAB,0xBA,0x3D,
+    0x42,0xEB,0x9B,0xD7,0x95,0x92,0x18,0x26,0x5F,0xB1,0x28,0x9B,0x01,0xDB,0x52,0x18,
+    0xFE,0xF4,0x4F,0xD6,0x3A,0x49,0x13,0xE2,0xB0,0x06,0xEF,0x28,0x6C,0x89,0xFD,0x23,
+    0x19,0x56,0xF7,0x1A,0x51,0x89,0x5C,0x13,0xDD,0xD6,0x55,0x70,0x17,0xCA,0x05,0x59,
+    0x77,0xEA,0x75,0xA4,0x44,0x05,0x49,0xD3,0xD6,0xE4,0x04,0x74,0xC8,0x5F,0xF9,0x19,
+    0x75,0x27,0xB2,0x17,0x6B,0x2E,0x45,0xE5,0x07,0xBD,0x17,0x70,0xFD,0xA2,0x6A,0xF7,
+    0xF1,0xD8,0x43,0xBC,0xF6,0xCD,0xD1,0x2D,0xE0,0xF0,0x55,0xE7,0x60,0xA5,0x09,0x42,
+    0xE6,0x67,0xB6,0x40,0x56,0x4E,0x3E,0xDF,0x7B,0x89,0x44,0x36,0x78,0x83,0x30,0x25,
+    0x12,0xFF,0x48,0x97,0xC1,0x04,0x87,0xC7,0xA3,0x06,0xCE,0x06,0xCE,0x2F,0xAE,0x01,
+    0x42,0x57,0x62,0x3B,0xDA,0xEB,0xD8,0xDB,0x96,0x5E,0xFC,0x1E,0x30,0x4B,0xE4,0x80,
+    0xE1,0xD9,0x34,0x03,0x9C,0xD4,0x92,0x39,0x17,0xA8,0xCD,0xCA,0x96,0x54,0xEB,0x2D,
+    0x12,0x77,0xE3,0x96,0x09,0x6D,0xBB,0x93,0x02,0x03,0x01,0x00,0x01,0xA3,0x81,0x87,
+    0x30,0x81,0x84,0x30,0x0C,0x06,0x03,0x55,0x1D,0x13,0x01,0x01,0xFF,0x04,0x02,0x30,
+    0x00,0x30,0x0E,0x06,0x03,0x55,0x1D,0x0F,0x01,0x01,0xFF,0x04,0x04,0x03,0x02,0x07,
+    0x80,0x30,0x13,0x06,0x03,0x55,0x1D,0x25,0x04,0x0C,0x30,0x0A,0x06,0x08,0x2B,0x06,
+    0x01,0x05,0x05,0x07,0x03,0x01,0x30,0x0F,0x06,0x03,0x55,0x1D,0x11,0x04,0x08,0x30,
+    0x06,0x87,0x04,0x0A,0x00,0x00,0x01,0x30,0x1D,0x06,0x03,0x55,0x1D,0x0E,0x04,0x16,
+    0x04,0x14,0xE0,0xA6,0x7D,0x62,0x28,0x6C,0xC0,0xCE,0x46,0xC8,0x04,0xB0,0xBA,0xB9,
+    0x9B,0xF6,0x4A,0x60,0xBF,0xA9,0x30,0x1F,0x06,0x03,0x55,0x1D,0x23,0x04,0x18,0x30,
+    0x16,0x80,0x14,0xE0,0xA6,0x7D,0x62,0x28,0x6C,0xC0,0xCE,0x46,0xC8,0x04,0xB0,0xBA,
+    0xB9,0x9B,0xF6,0x4A,0x60,0xBF,0xA9,0x30,0x0D,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,
+    0x0D,0x01,0x01,0x0B,0x05,0x00,0x03,0x82,0x01,0x01,0x00,0x55,0xBB,0x48,0x72,0x61,
+    0x8F,0xAF,0x7F,0x18,0x2F,0x31,0xF9,0xAA,0xFF,0x4A,0xC1,0x5B,0xBF,0x45,0xFE,0x82,
+    0x3C,0xBE,0xFC,0xBB,0x58,0xA7,0x4A,0xF3,0x84,0xF8,0x10,0xB4,0x51,0x33,0x91,0xA0,
+    0x58,0x1C,0x5F,0x67,0x91,0x31,0xD8,0xEC,0xA0,0x6A,0x85,0x84,0x71,0xBE,0xB5,0x18,
+    0xAC,0xB8,0x7E,0xC3,0xFC,0x1C,0x74,0x84,0x48,0x2C,0x99,0xE9,0x52,0xBB,0x36,0x00,
+    0x35,0x8C,0x50,0xC8,0x13,0x2A,0xFA,0x1E,0xF8,0x15,0x72,0xEF,0xF0,0x20,0x28,0xA0,
+    0xCD,0xC7,0x85,0xEF,0x48,0x8C,0x27,0xF9,0x0E,0x15,0x9F,0xB8,0x54,0xD1,0x44,0x08,
+    0x31,0xB0,0xC8,0x24,0x53,0x4A,0x63,0x97,0xB5,0xB3,0x83,0x07,0xCD,0x6D,0xC5,0x10,
+    0xDD,0xC0,0x90,0xA2,0xFF,0x8E,0xD5,0x2F,0xC4,0xBC,0x8A,0xE0,0x90,0xAA,0x79,0x09,
+    0xB5,0x23,0x72,0x6A,0xFB,0x9B,0xE5,0x0E,0xD9,0x30,0x41,0x70,0xF1,0x17,0x9C,0x5F,
+    0xD7,0x0A,0x10,0x8E,0x77,0xD9,0x2F,0x59,0xE4,0xB4,0xF6,0x8D,0x16,0x90,0x84,0xBB,
+    0xB6,0xAF,0xEE,0x86,0x4D,0x21,0xAE,0x3E,0x7B,0x2F,0xAD,0xBD,0xC4,0x38,0x9C,0x9E,
+    0xB5,0x7C,0x8D,0x36,0x72,0x2C,0x78,0xC7,0xD4,0x54,0xD9,0x93,0x18,0xC8,0x00,0x5E,
+    0xFE,0x12,0xE4,0x50,0x90,0x88,0xFB,0x82,0xFE,0x94,0xA5,0x4C,0xEB,0x7F,0xB7,0x39,
+    0x99,0x24,0x0B,0x23,0xF9,0xB4,0x92,0xA8,0x6F,0xA6,0x46,0xBB,0xFB,0xDA,0xCD,0x8F,
+    0xB9,0x14,0xE8,0x9B,0xBB,0x1B,0x80,0x9E,0x9D,0x9A,0x16,0xFF,0xF1,0x55,0xFF,0xDF,
+    0x3E,0x32,0x73,0x16,0x9D,0xEA,0xF0,0xB1,0x5A,0x12,0xAB,
+};
+
 #endif /* _TRUSTTESTS_CERTIFICATE_INTERFACE_H_ */
index a1a30b67c76a5bee0ae257f4b5cd0e80aca21514..d65c91132b4c6d35e53977109863166e67026f78 100644 (file)
@@ -38,6 +38,7 @@ const NSString *kSecTestParseSuccessResources = @"si-18-certificate-parse/ParseS
 const NSString *kSecTestKeyFailureResources = @"si-18-certificate-parse/KeyFailureCerts";
 const NSString *kSecTestTODOFailureResources = @"si-18-certificate-parse/TODOFailureCerts";
 const NSString *kSecTestExtensionFailureResources = @"si-18-certificate-parse/ExtensionFailureCerts";
+const NSString *kSecTestNameFailureResources = @"si-18-certificate-parse/NameFailureCerts";
 
 @interface CertificateParseTests : TrustFrameworkTestCase
 
@@ -129,4 +130,20 @@ const NSString *kSecTestExtensionFailureResources = @"si-18-certificate-parse/Ex
     }
 }
 
+- (void)testUnparseableSubjectName {
+    /* A bunch of certificates with different parsing errors the subject name */
+    NSArray <NSURL *>* certURLs = [[NSBundle bundleForClass:[self class]]URLsForResourcesWithExtension:@".cer" subdirectory:(NSString *)kSecTestNameFailureResources];
+    XCTAssertTrue([certURLs count] > 0, "Unable to find parse test name failure certs in bundle.");
+
+    if ([certURLs count] > 0) {
+        [certURLs enumerateObjectsUsingBlock:^(NSURL *url, __unused NSUInteger idx, __unused BOOL *stop) {
+            NSData *certData = [NSData dataWithContentsOfURL:url];
+            SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
+            isnt(cert, NULL, "Failed to parse bad cert with unparseable name: %@", url);
+            is(CFBridgingRelease(SecCertificateCopyCountry(cert)), nil, "Success parsing name for failure cert: %@", url);
+            CFReleaseNull(cert);
+        }];
+    }
+}
+
 @end
index e44c6c2d7d4f6814dbfd085d4f9cd7af2f5609cc..9ab7c00bb3e8b665b980780d57223965486a572e 100644 (file)
     is_status(trustResult, kSecTrustResultInvalid, "trustResult is kSecTrustResultInvalid");
     is(SecTrustGetCertificateCount(trust), 1, "cert count is 1 without securityd running");
     SecKeyRef pubKey = NULL;
-    ok(pubKey = SecTrustCopyPublicKey(trust), "copy public key without securityd running");
+    ok(pubKey = SecTrustCopyKey(trust), "copy public key without securityd running");
     CFReleaseNull(pubKey);
     SecServerSetTrustdMachServiceName("com.apple.trustd");
     // End of Restore OS environment tests
@@ -371,7 +371,8 @@ errOut:
     ok_status(SecTrustEvaluateAsync(trust, queue, ^(SecTrustRef  _Nonnull trustRef, SecTrustResultType trustResult) {
         if ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified)) {
             // Evaluation succeeded!
-            SecKeyRef publicKey = SecTrustCopyPublicKey(trustRef);
+            SecKeyRef publicKey = SecTrustCopyKey(trustRef);
+            XCTAssert(publicKey !=  NULL);
             CFReleaseSafe(publicKey);
         } else if (trustResult == kSecTrustResultRecoverableTrustFailure) {
             // Evaluation failed, but may be able to recover . . .
@@ -891,4 +892,37 @@ errOut:
     }];
 }
 
+- (void)testCopyKey
+{
+    SecTrustRef trust = NULL;
+    CFArrayRef certs = NULL;
+    SecCertificateRef cert0 = NULL, cert1 = NULL;
+    SecPolicyRef policy = NULL;
+
+    isnt(cert0 = SecCertificateCreateWithBytes(NULL, _c0, sizeof(_c0)),
+         NULL, "create cert0");
+    isnt(cert1 = SecCertificateCreateWithBytes(NULL, _c1, sizeof(_c1)),
+         NULL, "create cert1");
+    const void *v_certs[] = { cert0, cert1 };
+
+    certs = CFArrayCreate(NULL, v_certs, array_size(v_certs), &kCFTypeArrayCallBacks);
+    policy = SecPolicyCreateSSL(false, NULL);
+
+    ok_status(SecTrustCreateWithCertificates(certs, policy, &trust), "create trust");
+
+    SecKeyRef trustPubKey = NULL, certPubKey = NULL;
+    ok(trustPubKey = SecTrustCopyKey(trust), "copy public key without securityd running");
+    ok(certPubKey = SecCertificateCopyKey(cert0));
+    XCTAssert(CFEqualSafe(trustPubKey, certPubKey));
+
+
+    CFReleaseNull(trustPubKey);
+    CFReleaseNull(certPubKey);
+    CFReleaseNull(trust);
+    CFReleaseNull(cert0);
+    CFReleaseNull(cert1);
+    CFReleaseNull(certs);
+    CFReleaseNull(policy);
+}
+
 @end
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/any_eku.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/any_eku.cer
new file mode 100644 (file)
index 0000000..3e16b5e
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/any_eku.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/common_name.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/common_name.cer
new file mode 100644 (file)
index 0000000..feb0300
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/common_name.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/data_encipher.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/data_encipher.cer
new file mode 100644 (file)
index 0000000..b00612a
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/data_encipher.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/digital_signature.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/digital_signature.cer
new file mode 100644 (file)
index 0000000..4b03c9c
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/digital_signature.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_field.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_field.cer
new file mode 100644 (file)
index 0000000..5665299
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_field.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_protection.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_protection.cer
new file mode 100644 (file)
index 0000000..94b8641
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/email_protection.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement.cer
new file mode 100644 (file)
index 0000000..f40d920
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_decipher_only.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_decipher_only.cer
new file mode 100644 (file)
index 0000000..083b21c
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_decipher_only.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_decipher.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_decipher.cer
new file mode 100644 (file)
index 0000000..372ba02
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_decipher.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_only.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_only.cer
new file mode 100644 (file)
index 0000000..67f81d0
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_agreement_encipher_only.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_encipher.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_encipher.cer
new file mode 100644 (file)
index 0000000..2170c42
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/key_encipher.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/no_name.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/no_name.cer
new file mode 100644 (file)
index 0000000..9959faf
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/no_name.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/non_repudiation.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/non_repudiation.cer
new file mode 100644 (file)
index 0000000..9033ce1
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/non_repudiation.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/root.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/root.cer
new file mode 100644 (file)
index 0000000..579d3a4
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/root.cer differ
diff --git a/tests/TrustTests/TestData/SMIMEPolicyTests-data/san_name.cer b/tests/TrustTests/TestData/SMIMEPolicyTests-data/san_name.cer
new file mode 100644 (file)
index 0000000..ea9d74d
Binary files /dev/null and b/tests/TrustTests/TestData/SMIMEPolicyTests-data/san_name.cer differ
index d110b1cee158408b4be95c682843e7f044e0e43c..b51f2ae4dee197e9ac23f28352b8dc7ce40178c1 100644 (file)
                        </dict>
                </array>
        </dict>
-       <dict>
-               <key>CertDirectory</key>
-               <string>si-20-sectrust-policies-data</string>
-               <key>BridgeOSDisable</key>
-               <true/>
-               <key>MajorTestName</key>
-               <string>AnchorSHA1</string>
-               <key>MinorTestName</key>
-               <string>OnlyFailure</string>
-               <key>Policies</key>
-               <dict>
-                       <key>PolicyIdentifier</key>
-                       <string>1.2.840.113635.100.1.51</string>
-               </dict>
-               <key>Leaf</key>
-               <string>escrow_service_key_049F9D11</string>
-               <key>Intermediates</key>
-               <string>EscrowServiceRootCA101</string>
-               <key>Anchors</key>
-               <string>EscrowServiceRootCA101</string>
-               <key>ExpectedProperties</key>
-               <array>
-                       <dict>
-                               <key>type</key>
-                               <string>error</string>
-                               <key>value</key>
-                               <string>Root certificate is not trusted.</string>
-                       </dict>
-               </array>
-       </dict>
        <dict>
                <key>CertDirectory</key>
                <string>si-20-sectrust-policies-data</string>
diff --git a/tests/TrustTests/TestRunners/Base.lproj/LaunchScreen.storyboard b/tests/TrustTests/TestRunners/Base.lproj/LaunchScreen.storyboard
deleted file mode 100644 (file)
index bfa3612..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
-    <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="EHf-IW-A2E">
-            <objects>
-                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
-            </objects>
-            <point key="canvasLocation" x="53" y="375"/>
-        </scene>
-    </scenes>
-</document>
diff --git a/tests/TrustTests/TestRunners/Base.lproj/Main.storyboard b/tests/TrustTests/TestRunners/Base.lproj/Main.storyboard
deleted file mode 100644 (file)
index 942f0bc..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
-    <dependencies>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <scenes>
-        <!--View Controller-->
-        <scene sceneID="tne-QT-ifu">
-            <objects>
-                <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
-                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
-                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
-                    </view>
-                </viewController>
-                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
-            </objects>
-        </scene>
-    </scenes>
-</document>
index c34bf518b20772362b15cb07375aca61b3a126d0..ab6c189b36e6cab107dbd2432cf7615f1d9887b2 100644 (file)
@@ -23,8 +23,7 @@
 @implementation TestRunner
 - (instancetype)initWithBundlePath:(NSString *)path andTestNames:(NSArray *)names
 {
-    self = [super init];
-    if (self) {
+    if ((self = [super init])) {
         NSError *error = nil;
         
         _bundle = [NSBundle bundleWithPath:path];
     [self testLogWithFormat:@"Test Suite '%@' started at %@\n", testSuite.name, [self.dateFormatter stringFromDate:testSuite.testRun.startDate]];
 }
 
-- (void)testSuite:(XCTestSuite *)testSuite didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber
+- (void)testSuite:(XCTestSuite *)testSuite didRecordIssue:(XCTIssue *)issue
 {
+    NSString *filePath = [issue.sourceCodeContext.location.fileURL absoluteString];
+    NSInteger lineNumber = issue.sourceCodeContext.location.lineNumber;
+    NSString *description = issue.description;
     [self testLogWithFormat:@"%@:%lu: error: %@ : %@\n", ((nil != filePath) ? filePath : @"<unknown>"), ((unsigned long)((nil != filePath) ? lineNumber : 0)), testSuite.name, description];
 }
 
     [self testLogWithFormat:@"Test Case '%@' started.\n", testCase.name];
 }
 
-- (void)testCase:(XCTestCase *)testCase didFailWithDescription:(NSString *)description inFile:(nullable NSString *)filePath atLine:(NSUInteger)lineNumber
+- (void)testCase:(XCTestCase *)testCase didRecordIssue:(XCTIssue *)issue
 {
+    NSString *filePath = [issue.sourceCodeContext.location.fileURL absoluteString];
+    NSInteger lineNumber = issue.sourceCodeContext.location.lineNumber;
+    NSString *description = issue.description;
     [self testLogWithFormat:@"%@:%lu: error: %@ : %@\n", ((nil != filePath) ? filePath : @"<unknown>"), ((unsigned long)((nil != filePath) ? lineNumber : 0)), testCase.name, description];
 }
 
index 8df24b43d5c98a2f007d8595bcea4f7802151310..bac16a086839bd536ac522ab2e7d8415b2e2ff55 100644 (file)
        <array>
                <string>com.apple.MobileAsset.PKITrustSupplementals</string>
        </array>
+       <key>com.apple.security.exception.files.absolute-path.read-only</key>
+       <array>
+               <string>/System/Library/Caches/apticket.der</string>
+       </array>
+       <key>com.apple.system.diagnostics.iokit-properties</key>
+       <true/>
+       <key>com.apple.private.AuthorizationServices</key>
+       <array>
+               <string>com.apple.trust-settings.admin</string>
+       </array>
 </dict>
 </plist>
index a7ee45d9d96d092eaf43f50e50828e9930411b3e..1a7900996226648ff1f9bf408a2d329acddb15d8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <utilities/SecInternalReleasePriv.h>
 #include <utilities/SecCFRelease.h>
+#include <utilities/SecCFWrappers.h>
 #include <Security/SecCertificate.h>
 #include <Security/SecCertificatePriv.h>
 #include <Security/SecPolicyPriv.h>
@@ -288,6 +289,50 @@ errOut:
     return false;
 }
 
+- (bool)addThirdPartyPinningPolicyChecks:(CFDictionaryRef)properties
+                                  policy:(SecPolicyRef)policy
+{
+    if (!properties) {
+        return true;
+    }
+
+    CFStringRef spkiSHA256Options[] = {
+        kSecPolicyCheckLeafSPKISHA256,
+        kSecPolicyCheckCAspkiSHA256,
+    };
+
+    for (size_t i = 0; i < sizeof(spkiSHA256Options)/sizeof(spkiSHA256Options[0]); i++) {
+        CFArrayRef spkiSHA256StringArray = CFDictionaryGetValue(properties, spkiSHA256Options[i]);
+        // Relevant property is not set.
+        if (!spkiSHA256StringArray) {
+            continue;
+        }
+        require_string(isArray(spkiSHA256StringArray), errOut, "SPKISHA256 property is not an array");
+
+        CFMutableArrayRef spkiSHA256DataArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
+        require_string(spkiSHA256DataArray, errOut, "failed to allocate memory for the SPKISHA256 data array");
+
+        for (CFIndex j = 0; j < CFArrayGetCount(spkiSHA256StringArray); j++) {
+            CFStringRef spkiSHA256String = CFArrayGetValueAtIndex(spkiSHA256StringArray, j);
+            require_string(isString(spkiSHA256String), errOut, "SPKISHA256 property array element is not a string");
+            CFDataRef spkiSHA256Data = CreateCFDataFromBase64CFString(spkiSHA256String);
+            // 'spkiSHA256Data' is optional because we want to allow empty strings.
+            if (spkiSHA256Data) {
+                CFArrayAppendValue(spkiSHA256DataArray, spkiSHA256Data);
+            }
+            CFReleaseNull(spkiSHA256Data);
+        }
+
+        SecPolicySetOptionsValue(policy, spkiSHA256Options[i], spkiSHA256DataArray);
+        CFReleaseNull(spkiSHA256DataArray);
+    }
+
+    return true;
+
+errOut:
+    return false;
+}
+
 - (bool)addPolicy:(NSDictionary *)policyDict
 {
     SecPolicyRef policy = NULL;
@@ -295,14 +340,17 @@ errOut:
     NSDictionary *policyProperties = [(NSDictionary *)policyDict objectForKey:kSecTrustTestPolicyProperties];
     require_string(policyIdentifier, errOut, "failed to get policy OID");
 
+    CFDictionaryRef properties = (__bridge CFDictionaryRef)policyProperties;
     policy = SecPolicyCreateWithProperties((__bridge CFStringRef)policyIdentifier,
-                                           (__bridge CFDictionaryRef)policyProperties);
+                                           properties);
     require_string(policy, errOut, "failed to create properties for policy OID");
+    require_string([self addThirdPartyPinningPolicyChecks:properties policy:policy], errOut, "failed to parse properties for third-party-pinning policy checks");
     [self.policies addObject:(__bridge id)policy];
     CFReleaseNull(policy);
 
     return true;
 errOut:
+    CFReleaseNull(policy);
     return false;
 }
 
index ee7c73073c2a4e983cfbcede4bfb2d3c19353c92..c6a3767915352bd497e99d777e007fd0d63a6079 100644 (file)
@@ -32,8 +32,10 @@ for filename in test_files:
 
             test_command = Foundation.NSMutableArray.array()
             test_command.append('/AppleInternal/CoreOS/tests/Security/TrustTests')
-            test_command.append('-c ' + match.group(1))
-            test_command.append('-t TrustTests')
+            test_command.append('-c')
+            test_command.append(match.group(1))
+            test_command.append('-t')
+            test_command.append('TrustTests')
 
             test_dictionary['Command'] = test_command
 
index 068c33fbb20754ca230abf0264c7d48cf9a15283..a27a51ce450d85d5e9bdd5a87d6907328a81bd8d 100644 (file)
@@ -80,6 +80,8 @@ int MKBForegroundUserSessionID( CFErrorRef _Nullable * _Nullable error);
 + (void)failNextDecryptRefKey:(NSError* _Nonnull) decryptRefKeyError;
 + (NSError * _Nullable)popDecryptRefKeyFailure;
 
++ (void)setOperationsUntilUnlock:(int)val;
+
 @end
 
 #endif // OBJC2
index 4bf815b80822cb82d2780efd56985525a8eca486..ca4f9a56250a48a16536743e25783958bd62e5cd 100644 (file)
@@ -52,6 +52,8 @@
 #import "tests/secdmockaks/generated_source/MockAKSRefKey.h"
 #import "tests/secdmockaks/generated_source/MockAKSOptionalParameters.h"
 
+#include "utilities/simulatecrash_assert.h"
+
 bool hwaes_key_available(void)
 {
     return false;
@@ -70,6 +72,8 @@ static NSMutableDictionary* _lockedStates = nil;
 static dispatch_queue_t _mutabilityQueue = nil;
 static keybag_state_t _keybag_state = keybag_state_unlocked | keybag_state_been_unlocked;
 static NSMutableArray<NSError *>* _decryptRefKeyErrors = nil;
+static int _operationsUntilUnlock = -1;      // -1: don't care, 0: be unlocked, posnum: decrement and be locked
+
 /*
  * Method that limit where this rather in-secure version of AKS can run
  */
@@ -222,6 +226,24 @@ static NSMutableArray<NSError *>* _decryptRefKeyErrors = nil;
     return error;
 }
 
++ (void)setOperationsUntilUnlock:(int)val {
+    _operationsUntilUnlock = val;
+}
+
++ (void)updateOperationsUntilUnlock {
+    if (_operationsUntilUnlock == -1) {
+        return;
+    }
+
+    if (_operationsUntilUnlock == 0) {
+        _operationsUntilUnlock = -1;
+        [SecMockAKS unlockAllClasses];
+        return;
+    }
+
+    --_operationsUntilUnlock;
+}
+
 
 @end
 
@@ -309,6 +331,8 @@ aks_wrap_key(const void * key, int key_size, keyclass_t key_class, keybag_handle
         return kAKSReturnBusy;
     }
 
+    [SecMockAKS updateOperationsUntilUnlock];
+
     // Assumes non-device keybags are asym
     if ([SecMockAKS isLocked:key_class] && handle == KEYBAG_DEVICE) {
         return kAKSReturnNoPermission;
@@ -349,6 +373,8 @@ aks_unwrap_key(const void * wrapped_key, int wrapped_key_size, keyclass_t key_cl
         return kAKSReturnBusy;
     }
 
+    [SecMockAKS updateOperationsUntilUnlock];
+
     if ([SecMockAKS isLocked:key_class]) {
         return kAKSReturnNoPermission;
     }
@@ -408,7 +434,7 @@ aks_unwrap_key(const void * wrapped_key, int wrapped_key_size, keyclass_t key_cl
             CFTypeRef cf = NULL;
             CFErrorRef cferror = NULL;
             uint8_t *der = (uint8_t *)params.externalData.bytes;
-            der_decode_plist(NULL, false, &cf, &cferror, der, der + params.externalData.length);
+            der_decode_plist(NULL, &cf, &cferror, der, der + params.externalData.length);
             if (cf == NULL) {
                 *error = [NSError errorWithDomain:@"foo" code:kAKSReturnBadArgument userInfo:nil];
                 return NULL;
@@ -610,6 +636,14 @@ aks_ref_key_delete(aks_ref_key_t handle, const uint8_t *der_params, size_t der_p
     return kAKSReturnSuccess;
 }
 
+const uint8_t *
+aks_ref_key_get_public_key(aks_ref_key_t handle, size_t *pub_key_len)
+{
+    static const uint8_t dummy_key[0x41] = { 0 };
+    *pub_key_len = sizeof(dummy_key);
+    return dummy_key;
+}
+
 int
 aks_operation_optional_params(const uint8_t * access_groups, size_t access_groups_len, const uint8_t * external_data, size_t external_data_len, const void * acm_handle, int acm_handle_len, void ** out_der, size_t * out_der_len)
 {
@@ -720,132 +754,176 @@ aks_generation(keybag_handle_t handle,
     return kAKSReturnSuccess;
 }
 
-CFStringRef kMKBDeviceModeMultiUser = CFSTR("kMKBDeviceModeMultiUser");
-CFStringRef kMKBDeviceModeSingleUser = CFSTR("kMKBDeviceModeSingleUser");
-CFStringRef kMKBDeviceModeKey = CFSTR("kMKBDeviceModeKey");
+kern_return_t
+aks_get_device_state(keybag_handle_t handle, aks_device_state_s *device_state)
+{
+    // Probably not legal
+    return kAKSReturnError;
+}
 
-static CFStringRef staticKeybagHandle = CFSTR("keybagHandle");
+int
+aks_system_key_get_public(aks_system_key_type_t type, aks_system_key_generation_t generation, const uint8_t *der_params, size_t der_params_len, uint8_t **pub_out, size_t *pub_len_out)
+{
+    return kAKSReturnError;
+}
 
 int
-MKBKeyBagCreateWithData(CFDataRef keybagBlob, MKBKeyBagHandleRef* newHandle)
+aks_system_key_operate(aks_system_key_type_t type, aks_system_key_operation_t operation, const uint8_t *der_params, size_t der_params_len)
 {
-    *newHandle = (MKBKeyBagHandleRef)staticKeybagHandle;
-    return kMobileKeyBagSuccess;
+    return kAKSReturnError;
 }
 
 int
-MKBKeyBagUnlock(MKBKeyBagHandleRef keybag, CFDataRef passcode)
+aks_system_key_collection(aks_system_key_type_t type, aks_system_key_generation_t generation, const uint8_t *der_params, size_t der_params_len, uint8_t **out_der, size_t *out_der_len)
 {
-    if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
-        abort();
-    }
-    return kMobileKeyBagSuccess;
+    return kAKSReturnError;
 }
 
-int MKBKeyBagGetAKSHandle(MKBKeyBagHandleRef keybag, int32_t *handle)
+int
+aks_system_key_attest(aks_system_key_type_t type, aks_system_key_generation_t generation, aks_ref_key_t ref_key, const uint8_t *der_params, size_t der_params_len, uint8_t **out_der, size_t *out_der_len)
 {
-    if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
-        abort();
-    }
-    *handle = 17;
-    return kMobileKeyBagSuccess;
+    return kAKSReturnError;
 }
 
-int MKBGetDeviceLockState(CFDictionaryRef options)
+int
+aks_gid_attest(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, void **out_der, size_t *out_der_len)
 {
-    if ([SecMockAKS isLocked:key_class_ak]) {
-        return kMobileKeyBagDeviceIsLocked;
-    }
-    return kMobileKeyBagDeviceIsUnlocked;
+    return kAKSReturnError;
 }
 
-CF_RETURNS_RETAINED CFDictionaryRef
-MKBUserTypeDeviceMode(CFDictionaryRef options, CFErrorRef * error)
+int
+aks_sik_attest(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, void **out_der, size_t *out_der_len)
 {
-    return CFBridgingRetain(@{
-        (__bridge NSString *)kMKBDeviceModeKey : (__bridge NSString *)kMKBDeviceModeSingleUser,
-    });
+    return kAKSReturnError;
 }
 
-int MKBForegroundUserSessionID( CFErrorRef * error)
+/* Unimplemented aks_ref_key functions */
+
+int
+aks_ref_key_compute_key(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, const uint8_t *pub_key, size_t pub_key_len, void **out_der, size_t *out_der_len)
 {
-    return kMobileKeyBagSuccess;
+    return kAKSReturnError;
 }
 
-const CFTypeRef kAKSKeyAcl = (CFTypeRef)CFSTR("kAKSKeyAcl");
-const CFTypeRef kAKSKeyAclParamRequirePasscode = (CFTypeRef)CFSTR("kAKSKeyAclParamRequirePasscode");
+int
+aks_ref_key_attest(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, aks_ref_key_t handle2, void **out_der, size_t *out_der_len)
+{
+    return kAKSReturnError;
+}
 
-const CFTypeRef kAKSKeyOpDefaultAcl = (CFTypeRef)CFSTR("kAKSKeyOpDefaultAcl");
-const CFTypeRef kAKSKeyOpEncrypt = (CFTypeRef)CFSTR("kAKSKeyOpEncrypt");
-const CFTypeRef kAKSKeyOpDecrypt = (CFTypeRef)CFSTR("kAKSKeyOpDecrypt");
-const CFTypeRef kAKSKeyOpSync = (CFTypeRef)CFSTR("kAKSKeyOpSync");
-const CFTypeRef kAKSKeyOpDelete = (CFTypeRef)CFSTR("kAKSKeyOpDelete");
-const CFTypeRef kAKSKeyOpCreate = (CFTypeRef)CFSTR("kAKSKeyOpCreate");
-const CFTypeRef kAKSKeyOpSign = (CFTypeRef)CFSTR("kAKSKeyOpSign");
-const CFTypeRef kAKSKeyOpSetKeyClass = (CFTypeRef)CFSTR("kAKSKeyOpSetKeyClass");
-const CFTypeRef kAKSKeyOpWrap = (CFTypeRef)CFSTR("kAKSKeyOpWrap");
-const CFTypeRef kAKSKeyOpUnwrap = (CFTypeRef)CFSTR("kAKSKeyOpUnwrap");
-const CFTypeRef kAKSKeyOpComputeKey = (CFTypeRef)CFSTR("kAKSKeyOpComputeKey");
-const CFTypeRef kAKSKeyOpAttest = (CFTypeRef)CFSTR("kAKSKeyOpAttest");
-const CFTypeRef kAKSKeyOpTranscrypt = (CFTypeRef)CFSTR("kAKSKeyOpTranscrypt");
-const CFTypeRef kAKSKeyOpECIESEncrypt = (CFTypeRef)CFSTR("kAKSKeyOpECIESEncrypt");
-const CFTypeRef kAKSKeyOpECIESDecrypt = (CFTypeRef)CFSTR("kAKSKeyOpECIESDecrypt");
-const CFTypeRef kAKSKeyOpECIESTranscode = (CFTypeRef)CFSTR("kAKSKeyOpECIESTranscode");
+int
+aks_ref_key_sign(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, const uint8_t *digest, size_t digest_len, void **out_der, size_t *out_der_len)
+{
+    return kAKSReturnError;
+}
 
+int
+aks_ref_key_ecies_transcode(aks_ref_key_t handle, uint8_t *der_params, size_t der_params_len, const uint8_t *public_key, size_t public_key_len, const uint8_t *cipher_txt_in, size_t cipher_txt_in_len, uint8_t **cipher_txt_out, size_t *cipher_txt_out_len)
+{
+    return kAKSReturnError;
+}
 
-TKTokenRef TKTokenCreate(CFDictionaryRef attributes, CFErrorRef *error)
+keyclass_t
+aks_ref_key_get_key_class(aks_ref_key_t handle)
 {
-    return NULL;
+    return key_class_a;
 }
 
-CFTypeRef TKTokenCopyObjectData(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
+aks_key_type_t
+aks_ref_key_get_type(aks_ref_key_t handle)
 {
-    return NULL;
+    return key_type_sym;
 }
 
-CFDataRef TKTokenCreateOrUpdateObject(TKTokenRef token, CFDataRef objectID, CFMutableDictionaryRef attributes, CFErrorRef *error)
+/* AKS Params (unimplemented) */
+
+aks_params_t aks_params_create(const uint8_t *der_params, size_t der_params_len)
 {
     return NULL;
 }
 
-CFDataRef TKTokenCopyObjectAccessControl(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
+int aks_params_free(aks_params_t *params)
 {
-    return NULL;
+    return kAKSReturnSuccess;
 }
-bool TKTokenDeleteObject(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
+
+int
+aks_params_set_data(aks_params_t params, aks_params_key_t key, const void *value, size_t length)
 {
-    return false;
+    return kAKSReturnError;
 }
 
-CFDataRef TKTokenCopyPublicKeyData(TKTokenRef token, CFDataRef objectID, CFErrorRef *error)
+int
+aks_params_get_der(aks_params_t params, uint8_t **out_der, size_t *out_der_len)
 {
-    return NULL;
+    return kAKSReturnError;
 }
 
-CFTypeRef TKTokenCopyOperationResult(TKTokenRef token, CFDataRef objectID, CFIndex secKeyOperationType, CFArrayRef algorithm,
-                                     CFIndex secKeyOperationMode, CFTypeRef in1, CFTypeRef in2, CFErrorRef *error)
+int
+aks_params_set_number(aks_params_t params, aks_params_key_t key, int64_t *num)
 {
-    return NULL;
+    return kAKSReturnError;
 }
 
-CF_RETURNS_RETAINED CFDictionaryRef TKTokenControl(TKTokenRef token, CFDictionaryRef attributes, CFErrorRef *error)
+// This is in libaks_internal.h, which doesn't appear to be in the SDK.
+int aks_ref_key_enable_test_keys(keybag_handle_t handle, const uint8_t *passcode, size_t passcode_len);
+int
+aks_ref_key_enable_test_keys(keybag_handle_t handle, const uint8_t *passcode, size_t passcode_len)
 {
-    return NULL;
+    abort();
+    return kAKSReturnError;
 }
 
-CFTypeRef LACreateNewContextWithACMContext(CFDataRef acmContext, CFErrorRef *error)
+CFStringRef kMKBDeviceModeMultiUser = CFSTR("kMKBDeviceModeMultiUser");
+CFStringRef kMKBDeviceModeSingleUser = CFSTR("kMKBDeviceModeSingleUser");
+CFStringRef kMKBDeviceModeKey = CFSTR("kMKBDeviceModeKey");
+
+static CFStringRef staticKeybagHandle = CFSTR("keybagHandle");
+
+int
+MKBKeyBagCreateWithData(CFDataRef keybagBlob, MKBKeyBagHandleRef* newHandle)
 {
-    return NULL;
+    *newHandle = (MKBKeyBagHandleRef)staticKeybagHandle;
+    return kMobileKeyBagSuccess;
 }
 
-CFDataRef LACopyACMContext(CFTypeRef context, CFErrorRef *error)
+int
+MKBKeyBagUnlock(MKBKeyBagHandleRef keybag, CFDataRef passcode)
 {
-    return NULL;
+    if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
+        abort();
+    }
+    return kMobileKeyBagSuccess;
 }
 
-bool LAEvaluateAndUpdateACL(CFTypeRef context, CFDataRef acl, CFTypeRef operation, CFDictionaryRef hints, CFDataRef *updatedACL, CFErrorRef *error)
+int MKBKeyBagGetAKSHandle(MKBKeyBagHandleRef keybag, int32_t *handle)
 {
-    return false;
+    if (keybag == NULL || !CFEqual(keybag, staticKeybagHandle)) {
+        abort();
+    }
+    *handle = 17;
+    return kMobileKeyBagSuccess;
+}
+
+int MKBGetDeviceLockState(CFDictionaryRef options)
+{
+    if ([SecMockAKS isLocked:key_class_ak]) {
+        return kMobileKeyBagDeviceIsLocked;
+    }
+    return kMobileKeyBagDeviceIsUnlocked;
+}
+
+CF_RETURNS_RETAINED CFDictionaryRef
+MKBUserTypeDeviceMode(CFDictionaryRef options, CFErrorRef * error)
+{
+    return CFBridgingRetain(@{
+        (__bridge NSString *)kMKBDeviceModeKey : (__bridge NSString *)kMKBDeviceModeSingleUser,
+    });
+}
+
+int MKBForegroundUserSessionID( CFErrorRef * error)
+{
+    return kMobileKeyBagSuccess;
 }
 
 ACMContextRef
index 9a5280f3a5d453cccd28edef6f24da8caecce3f0..e1941e0d7eded04c17f1bf2e259462b91f7ea584 100644 (file)
 #import <sqlite3.h>
 #import "mockaks.h"
 
+#import <TargetConditionals.h>
+
+#import <LocalAuthentication/LocalAuthentication.h>
+
 #import "secdmock_db_version_10_5.h"
 #import "secdmock_db_version_11_1.h"
 
 }
 
 #if !TARGET_OS_WATCH
-/* this should be enabled for watch too, but that cause a crash in the mock aks layer */
+/* this should be enabled for watch too, but that causes a crash in the mock aks layer */
 
 - (void)testUpgradeWithBadACLKey
 {
 
             NSMutableData *mutatedData = [data mutableCopy];
 
-            if (counter < mutatedData.length) {
+            // This used to loop over all (~850!) bytes of the data but that's too slow. We now do first 50, last 50 and 20 random bytes
+            if (counter < 50) {
                 mutatedDatabase = true;
                 ((uint8_t *)[mutatedData mutableBytes])[counter] = 'X';
-                counter++;
+                ++counter;
+            } else if (counter < 70) {
+                mutatedDatabase = true;
+                size_t idx = 50 + arc4random_uniform((uint32_t)(mutatedData.length - 100));
+                ((uint8_t *)[mutatedData mutableBytes])[idx] = 'X';
+                ++counter;
+            } else if (counter < 120) {
+                mutatedDatabase = true;
+                size_t idx = mutatedData.length - (counter - 70 - 1);
+                ((uint8_t *)[mutatedData mutableBytes])[idx] = 'X';
+                ++counter;
             } else {
                 counter = 0;
             }
 
-
             NSString *mutateString = [NSString stringWithFormat:@"UPDATE genp SET data=x'%@'",
                                       [mutatedData hexString]];
 
             ok &= SecDbPrepare(dbt, (__bridge CFStringRef)mutateString, &localError2, ^(sqlite3_stmt *stmt) {
-                ok = SecDbStep(dbt, stmt, NULL, ^(bool *stop) {
-                });
+                ok = SecDbStep(dbt, stmt, NULL, NULL);
             });
             XCTAssertTrue(ok, "corruption should be successful: %@", localError2);
             CFReleaseNull(localError2);
     XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "should successfully get item");
 }
 
+// This test fails before rdar://problem/60028419 because the keystore fails to check for errSecInteractionNotAllowed,
+// tries to recreate the "broken" metadata key and if the keychain unlocks at the exact right moment succeeds and causes
+// data loss.
+- (void)testMetadataKeyRaceConditionFixed
+{
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccount : @"TestAccount-0",
+        (id)kSecAttrService : @"TestService",
+        (id)kSecValueData : [@"data" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecUseDataProtectionKeychain : @(YES),
+        (id)kSecAttrAccessible : (id)kSecAttrAccessibleWhenUnlocked,
+    } mutableCopy];
+
+    // Create item 1
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    // Drop metadata keys
+    SecKeychainDbReset(NULL);
+    [SecMockAKS setOperationsUntilUnlock:1];    // The first call is the metadata key unwrap to allow encrypting the item
+    [SecMockAKS lockClassA];
+
+    query[(id)kSecAttrAccount] = @"TestAcount-1";
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecInteractionNotAllowed);
+
+    query[(id)kSecAttrAccount] = @"TestAccount-0";
+    query[(id)kSecValueData] = nil;
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL), errSecSuccess);
+
+    [SecMockAKS setOperationsUntilUnlock:-1];
+}
+
+// A test for if LAContext can reasonably be used
+// Note that this test can currently _only_ run on iOS in the simulator; on the actual platforms it tries to access
+// real AKS/biometrics, which fails in automation environments.
+#if TARGET_OS_OSX || TARGET_OS_SIMULATOR
+ - (void)testLAContext
+{
+    NSMutableDictionary* simplequery = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccount : @"TestAccount-0",
+        (id)kSecAttrService : @"TestService",
+        (id)kSecValueData : [@"data" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecUseDataProtectionKeychain : @(YES),
+        (id)kSecAttrAccessible : (id)kSecAttrAccessibleWhenUnlocked,
+    } mutableCopy];
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)simplequery, NULL), errSecSuccess, "Succeeded in adding simple item to keychain");
+
+    CFErrorRef cferror = NULL;
+    SecAccessControlRef access = SecAccessControlCreateWithFlags(nil,
+                                                                 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
+                                                                 kSecAccessControlUserPresence,
+                                                                 &cferror);
+
+    XCTAssertNil((__bridge NSError*)cferror, "Should be no error creating an access control");
+
+    LAContext* context = [[LAContext alloc] init];
+
+#if TARGET_OS_IPHONE || TARGET_OS_OSX
+    // This field is only usable on iPhone/macOS. It isn't stricly necessary for this test, though.
+    context.touchIDAuthenticationAllowableReuseDuration = 10;
+#endif
+
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccount : @"TestAccount-LAContext",
+        (id)kSecAttrService : @"TestService",
+        (id)kSecValueData : [@"data" dataUsingEncoding:NSUTF8StringEncoding],
+        (id)kSecUseDataProtectionKeychain : @(YES),
+        (id)kSecAttrAccessControl : (__bridge id)access,
+        (id)kSecUseAuthenticationContext : context,
+    } mutableCopy];
+
+    XCTAssertEqual(SecItemAdd((__bridge CFDictionaryRef)query, NULL), errSecSuccess, "Succeeded in adding LA-protected item to keychain");
 
+    NSMutableDictionary* findquery = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccount : @"TestAccount-LAContext",
+        (id)kSecAttrService : @"TestService",
+        (id)kSecUseDataProtectionKeychain : @(YES),
+        (id)kSecUseAuthenticationContext : context,
+        (id)kSecReturnAttributes: @YES,
+        (id)kSecReturnData: @YES,
+    } mutableCopy];
+
+    CFTypeRef output = NULL;
+    XCTAssertEqual(SecItemCopyMatching((__bridge CFDictionaryRef)findquery, &output), errSecSuccess, "Found key in keychain");
+
+    XCTAssertNotNil((__bridge id)output, "Should have received something back from keychain");
+    CFReleaseNull(output);
+}
+#endif // TARGET_OS_OSX || TARGET_OS_SIMULATOR
 
 #endif /* USE_KEYSTORE */
 
diff --git a/tests/stashtester/main.m b/tests/stashtester/main.m
new file mode 100644 (file)
index 0000000..b75eb83
--- /dev/null
@@ -0,0 +1,193 @@
+#import <Foundation/Foundation.h>
+#import <Security/SecKeychainPriv.h>
+#include <MobileKeyBag/MobileKeyBag.h>
+
+static void print(NSString* str) {
+    if (![str hasSuffix:@"\n"]) {
+        str = [str stringByAppendingString:@"\n"];
+    }
+    [str writeToFile:@"/dev/stdout" atomically:NO encoding:NSUTF8StringEncoding error:nil];
+}
+
+static void usage() {
+    print(@"Usage: stashtester [commands]");
+    print(@"");
+    print(@"Commands:");
+    print(@"  -c          Combine stash and load requests (equivalent to -s and -l)");
+    print(@"  -l          Send stash login request to securityd (SecKeychainLogin)");
+    print(@"  -s          Send stash request to securityd (SecKeychainStash)");
+    print(@"  -t          Test the complete operation");
+}
+
+static bool performStash() {
+    NSLog(@"attempting stash");
+    OSStatus result = SecKeychainStash();
+    NSLog(@"result from stash: %ld", (long)result);
+    return result == errSecSuccess;
+}
+
+static bool performLoad() {
+    NSLog(@"attempting load");
+    OSStatus result = SecKeychainLogin(0, NULL, 0, NULL);
+    NSLog(@"result from load: %ld", (long)result);
+    return result == errSecSuccess;
+}
+
+static NSMutableDictionary* makeQuery(bool includeData) {
+    NSMutableDictionary* query = [@{
+        (id)kSecClass : (id)kSecClassGenericPassword,
+        (id)kSecAttrAccount : @"stashtester",
+        (id)kSecUseDataProtectionKeychain : @NO,
+    } mutableCopy];
+    if (includeData) {
+        query[(id)kSecValueData] = [@"sekrit" dataUsingEncoding:NSUTF8StringEncoding];
+    }
+    return query;
+}
+
+static bool performTest() {
+    NSLog(@"Begin test");
+    NSLog(@"Adding item to keychain");
+    NSMutableDictionary* addQ = makeQuery(true);
+    OSStatus result = SecItemAdd((__bridge CFDictionaryRef)addQ, NULL);
+    if (result != errSecSuccess) {
+        NSLog(@"Failed to add item pre-stash: %d; aborting test", (int)result);
+        return false;
+    }
+
+    if (!performStash()) {
+        NSLog(@"Stash failed; aborting test");
+        return false;
+    }
+
+    NSLog(@"Locking legacy keychain");
+    SecKeychainRef loginkc = NULL;
+    SecKeychainCopyLogin(&loginkc);
+    result = SecKeychainCopyLogin(&loginkc);
+    if (result != errSecSuccess) {
+        NSLog(@"Unable to obtain reference to login keychain; aborting test");
+        return false;
+    }
+    result = SecKeychainLock(loginkc);
+    if (result != errSecSuccess) {
+        NSLog(@"Unable to lock login keychain; aborting test");
+        return false;
+    }
+
+    SecKeychainStatus status = 0;
+    result = SecKeychainGetStatus(loginkc, &status);
+    CFRelease(loginkc);
+    if (result != errSecSuccess) {
+        NSLog(@"Unable to get login keychain status; aborting test");
+        return false;
+    }
+
+    if (status & kSecUnlockStateStatus) {
+        NSLog(@"Login keychain not locked after locking; aborting test");
+        return false;
+    }
+
+    NSLog(@"Locking keybag");
+    int rc = MKBLockDevice((__bridge CFDictionaryRef)@{(id)kKeyBagLockDeviceNow : @YES});
+    if (rc != kIOReturnSuccess) {
+        NSLog(@"Failed to lock keybag (%d); aborting test", rc);
+        return false;
+    }
+
+    // MKB asynchronously locks bag, make sure we don't race it
+    NSLog(@"Twiddling thumbs for 11 seconds");
+    sleep(11);
+
+    NSLog(@"Verifying keybag is locked");
+    NSMutableDictionary* checkQ = makeQuery(false);
+    checkQ[(id)kSecUseDataProtectionKeychain] = @YES;
+    result = SecItemAdd((__bridge CFDictionaryRef)checkQ, NULL);
+    if (result != errSecInteractionNotAllowed) {
+        NSLog(@"Data protection keychain unexpectedly not locked; aborting test");
+        return false;
+    }
+
+    if (!performLoad()) {
+        NSLog(@"Failed to load stash (%d); aborting test", result);
+        return false;
+    }
+
+    NSMutableDictionary* findQ = makeQuery(false);
+    findQ[(id)kSecReturnData] = @YES;
+    CFTypeRef object = NULL;
+    result = SecItemCopyMatching((__bridge CFDictionaryRef)findQ, &object);
+    NSData* password;
+    if (object) {
+        password = CFBridgingRelease(object);
+    }
+    if (result != errSecSuccess || !password || ![[@"sekrit" dataUsingEncoding:NSUTF8StringEncoding] isEqual:password]) {
+        NSLog(@"Unable to find item post-stashload (%d, %@); aborting test", result, password);
+        return false;
+    }
+
+    NSLog(@"Test succeeded");
+    return true;
+}
+
+static bool cleanup() {
+    NSLog(@"Cleaning up");
+    NSMutableDictionary* query = makeQuery(false);
+    OSStatus result = SecItemDelete((__bridge CFDictionaryRef)query);
+    if (result != errSecSuccess) {
+        NSLog(@"Cleanup: failed to delete item");
+        return false;
+    }
+    return true;
+}
+
+int main(int argc, const char * argv[]) {
+    @autoreleasepool {
+        bool stash = false;
+        bool load = false;
+        bool test = false;
+        int arg = 0;
+        char * const *gargv = (char * const *)argv;
+        while ((arg = getopt(argc, gargv, "clst")) != -1) {
+            switch (arg) {
+                case 'c':
+                    stash = true;
+                    load = true;
+                    break;
+                case 'l':
+                    load = true;
+                    break;
+                case 's':
+                    stash = true;
+                    break;
+                case 't':
+                    test = true;
+                    break;
+                default:
+                    usage();
+                    return 1;
+            }
+        }
+
+        if ((!stash && !load && !test) ||
+            (test && (stash || load)))
+        {
+            usage();
+            return 1;
+        }
+
+        if (test) {
+            bool testresult = performTest();
+            bool cleanresult = cleanup();
+            return (testresult && cleanresult) ? 0 : -1;
+        }
+
+        if (stash && !performStash()) {
+            return -1;
+        }
+
+        if (load && !performLoad()) {
+            return -1;
+        }
+    }
+    return 0;
+}
diff --git a/tests/stashtester/stashtester.entitlements b/tests/stashtester/stashtester.entitlements
new file mode 100644 (file)
index 0000000..cac4472
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>application-identifier</key>
+    <string>com.apple.security.private.stashtester</string>
+    <key>com.apple.private.securityd.stash</key>
+    <true/>
+    <key>com.apple.keystore.device</key>
+    <true/>
+</dict>
+</plist>
index fcadd01d39cb385f8d8a054b8224264e42ebb505..bd29bac27c4527f5e196fa6d91e3a26ed88e652f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -154,7 +154,13 @@ CFDataRef SecCertificateCopyNormalizedSubjectSequence(SecCertificateRef certific
  */
 __nullable CF_RETURNS_RETAINED
 SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate)
-    API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0));
+    API_AVAILABLE(macos(10.14), ios(12.0), watchos(5.0), tvos(12.0), bridgeos(3.0));
+
+#if TARGET_OS_OSX && TARGET_CPU_ARM64
+#define SEC_SUFFIX_LEGACYMAC(symbol) __asm("_" __STRING(symbol) "$LEGACYMAC")
+#else
+#define SEC_SUFFIX_LEGACYMAC(symbol) /**/
+#endif
 
 #if TARGET_OS_IPHONE
 /*!
@@ -166,7 +172,7 @@ SecKeyRef SecCertificateCopyKey(SecCertificateRef certificate)
  */
 __nullable
 SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
-    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", ios(10.3, 12.0)) API_UNAVAILABLE(macos, iosmac);
+    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", ios(10.3, 12.0)) API_UNAVAILABLE(macos, macCatalyst);
 #endif
 
 #if TARGET_OS_OSX
@@ -179,7 +185,8 @@ SecKeyRef SecCertificateCopyPublicKey(SecCertificateRef certificate)
  @discussion NOTE: Deprecated in macOS 10.14; use SecCertificateCopyKey instead for cross-platform availability.
  */
 OSStatus SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef * __nonnull CF_RETURNS_RETAINED key)
-    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", macos(10.3, 10.14)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
+    SEC_SUFFIX_LEGACYMAC(SecCertificateCopyPublicKey)
+    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopyKey", macos(10.3, 10.14)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
 #endif
 
 /*!
@@ -191,7 +198,7 @@ OSStatus SecCertificateCopyPublicKey(SecCertificateRef certificate, SecKeyRef *
  */
 __nullable
 CFDataRef SecCertificateCopySerialNumberData(SecCertificateRef certificate, CFErrorRef *error)
-    __OSX_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);
+    API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0), bridgeos(3.0));
 
 #if TARGET_OS_IPHONE
 /*!
@@ -202,7 +209,7 @@ CFDataRef SecCertificateCopySerialNumberData(SecCertificateRef certificate, CFEr
  */
 __nullable
 CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate)
-    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", ios(10.3, 11.0)) API_UNAVAILABLE(macos, iosmac);
+    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", ios(10.3, 11.0)) API_UNAVAILABLE(macos, macCatalyst);
 #endif
 
 #if TARGET_OS_OSX
@@ -215,7 +222,8 @@ CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate)
  */
 __nullable
 CFDataRef SecCertificateCopySerialNumber(SecCertificateRef certificate, CFErrorRef *error)
-    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", macos(10.7, 10.13)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, iosmac);
+    SEC_SUFFIX_LEGACYMAC(SecCertificateCopySerialNumber)
+    API_DEPRECATED_WITH_REPLACEMENT("SecCertificateCopySerialNumberData", macos(10.7, 10.13)) API_UNAVAILABLE(ios, tvos, watchos, bridgeos, macCatalyst);
 #endif
 
 /*
@@ -463,8 +471,8 @@ extern const CFStringRef kSecPropertyTypeData __OSX_AVAILABLE_STARTING(__MAC_10_
 extern const CFStringRef kSecPropertyTypeString __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
 extern const CFStringRef kSecPropertyTypeURL __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
 extern const CFStringRef kSecPropertyTypeDate __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_NA);
-extern const CFStringRef kSecPropertyTypeArray API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0));
-extern const CFStringRef kSecPropertyTypeNumber API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), iosmac(13.0));
+extern const CFStringRef kSecPropertyTypeArray API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), macCatalyst(13.0));
+extern const CFStringRef kSecPropertyTypeNumber API_AVAILABLE(macos(10.15)) SPI_AVAILABLE(ios(13.0), watchos(6.0), tvos(13.0), macCatalyst(13.0));
 
 /*!
     @function SecCertificateCopyValues
index 086f48ac1a3d720f4ba4d0921faab423b094ca8c..417e8ecdbcf52b0817668dbf1a5719521d6c3857 100644 (file)
@@ -463,6 +463,15 @@ bool SecCertificateGetDeveloperIDDate(SecCertificateRef certificate, CFAbsoluteT
 
 CFAbsoluteTime SecAbsoluteTimeFromDateContentWithError(DERTag tag, const uint8_t *bytes, size_t length, CFErrorRef *error);
 
+/* Return the (last) attribute value from the Subject DN with the indicated Attribute OID.
+ * This suits as a replacement for SecCertificateCopySubjectComponent */
+CFStringRef SecCertificateCopySubjectAttributeValue(SecCertificateRef cert, DERItem *attributeOID)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+
+/* Return the external roots (for use with SecTrustSetAnchorCertificates) */
+CFArrayRef SecCertificateCopyAppleExternalRoots(void)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+
 /*
  * Legacy functions (OS X only)
  */
@@ -579,7 +588,7 @@ OSStatus SecCertificateReleaseFirstFieldValue(SecCertificateRef certificate, con
  */
 OSStatus SecCertificateCopySubjectComponent(SecCertificateRef certificate, const CSSM_OID *component,
      CFStringRef *result)
-    __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopySubjectComponent is deprecated. Use SecCertificateCopyCommonNames,SecCertificateCopyOrganization,SecCertificateCopyOrganizationalUnit, etc. instead.");
+    __OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_0, __MAC_10_12_4, __IPHONE_NA, __IPHONE_NA, "SecCertificateCopySubjectComponent is deprecated. Use SecCertificateCopySubjectAttributeValue instead.");
 
 /*     Convenience functions for searching.
  */
index 59e95b54fca30ec7803eb111693ef56d469e1407..a3c19456cd93e6c2b6a52b448dc05a55c56e7c7c 100644 (file)
@@ -73,9 +73,9 @@ extern const CFStringRef kSecPolicyAppleiChat
     __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_7, __MAC_10_9, __IPHONE_NA, __IPHONE_NA);
 #endif
 extern const CFStringRef kSecPolicyApplePKINITClient
-    API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 extern const CFStringRef kSecPolicyApplePKINITServer
-    API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, iosmac);
+    API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos, bridgeos, macCatalyst);
 extern const CFStringRef kSecPolicyAppleCodeSigning
     __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_7_0);
 extern const CFStringRef kSecPolicyMacAppStoreReceipt
index 3927772ee035431aa4036432aff99bd8847c7fef..85f6237f021e5347898f0eb4011bef0ac625db15 100644 (file)
@@ -59,12 +59,6 @@ extern const CFStringRef kSecPolicyAppleQAProfileSigner
     __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0);
 extern const CFStringRef kSecPolicyAppleServerAuthentication
     __OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0);
-extern const CFStringRef kSecPolicyAppleOTAPKISigner
-    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3);
-extern const CFStringRef kSecPolicyAppleTestOTAPKISigner
-    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3);
-extern const CFStringRef kSecPolicyAppleIDValidationRecordSigningPolicy
-    API_DEPRECATED_WITH_REPLACEMENT("kSecPolicyAppleIDValidationRecordSigning", ios(7.0,10.0), macos(10.9,10.12));
 extern const CFStringRef kSecPolicyAppleIDValidationRecordSigning
     __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0);
 extern const CFStringRef kSecPolicyAppleSMPEncryption
@@ -191,10 +185,18 @@ extern const CFStringRef kSecPolicyAppleAlisha
     API_AVAILABLE(macos(10.15.4), ios(13.4), watchos(6.2), tvos(13.4));
 extern const CFStringRef kSecPolicyAppleMeasuredBootPolicySigning
     API_AVAILABLE(macos(10.15.4), ios(13.4), watchos(6.2), tvos(13.4));
+extern const CFStringRef kSecPolicyApplePayQRCodeEncryption
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+extern const CFStringRef kSecPolicyApplePayQRCodeSigning
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+extern const CFStringRef kSecPolicyAppleAccessoryUpdateSigning
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
 extern const CFStringRef kSecPolicyAppleEscrowServiceIdKeySigning
     API_AVAILABLE(macos(10.15.6), ios(13.5.5));
 extern const CFStringRef kSecPolicyApplePCSEscrowServiceIdKeySigning
     API_AVAILABLE(macos(10.15.6), ios(13.5.5));
+extern const CFStringRef kSecPolicyAppleAggregateMetricTransparency
+    API_AVAILABLE(macos(10.15.6), ios(13.6), watchos(6.2), tvos(13.4));
 
 
 /*!
@@ -219,6 +221,7 @@ extern const CFStringRef kSecPolicyApplePCSEscrowServiceIdKeySigning
     @constant kSecPolicyNameAppleSiriService
     @constant kSecPolicyNameAppleHomeAppClipUploadService
     @constant kSecPolicyNameAppleUpdatesService
+    @constant kSecPolicyNameApplePushCertPortal
  */
 extern const CFStringRef kSecPolicyNameAppleAST2Service
     __OSX_AVAILABLE(10.13) __IOS_AVAILABLE(11.0) __TVOS_AVAILABLE(11.0) __WATCHOS_AVAILABLE(4.0);
@@ -256,6 +259,8 @@ extern const CFStringRef kSecPolicyNameAppleHomeAppClipUploadService
     API_AVAILABLE(macos(10.15.1), ios(13.2), watchos(6.1), tvos(13.1));
 extern const CFStringRef kSecPolicyNameAppleUpdatesService
     API_AVAILABLE(macos(10.15.4), ios(13.4), watchos(6.2), tvos(13.4));
+extern const CFStringRef kSecPolicyNameApplePushCertPortal
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
 
 /*!
  @enum Policy Value Constants
@@ -335,10 +340,7 @@ CF_ENUM(CFOptionFlags) {
  in the leaf certificate.
  @discussion The resulting policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if the value true is set for the key
-    "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the
-    com.apple.security preferences for the user of the calling application.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID matching the intermediateMarkerOID
     parameter.
@@ -365,16 +367,12 @@ SecPolicyRef SecPolicyCreateApplePinned(CFStringRef policyName,
  in the leaf certificate.
  @discussion The resulting policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if the value true is set for the key
-    "ApplePinningAllowTestCerts%@" (where %@ is the policyName parameter) in the
-    com.apple.security preferences for the user of the calling application.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID matching the intermediateMarkerOID
     parameter, or 1.2.840.113635.100.6.2.12 if NULL is passed.
     * The leaf has a marker extension with OID matching the leafMarkerOID parameter.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
     * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger.
@@ -392,8 +390,7 @@ SecPolicyRef SecPolicyCreateAppleSSLPinned(CFStringRef policyName, CFStringRef h
  certificate chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in chain.
     * The intermediate has Common Name "Apple iPhone Certification Authority".
     * The leaf has Common Name "iPhone Activation".
@@ -409,8 +406,7 @@ SecPolicyRef SecPolicyCreateiPhoneActivation(void);
  chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+     * The chain is anchored to any of the Apple Root CAs
      * There are exactly 4 certs in chain.
      * The first intermediate has Common Name "Apple iPhone Device CA".
  @result A policy object. The caller is responsible for calling CFRelease
@@ -502,8 +498,7 @@ SecPolicyRef SecPolicyCreateIPSec(Boolean server, CFStringRef __nullable  hostna
  @abstract Returns a policy object for evaluating SW update signing certs.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate ExtendedKeyUsage Extension contains 1.2.840.113635.100.4.1.
      * The leaf ExtendedKeyUsage extension contains 1.2.840.113635.100.4.1.
@@ -518,8 +513,7 @@ SecPolicyRef SecPolicyCreateAppleSWUpdateSigning(void);
  @abstract Returns a policy object for evaluating installer package signing certs.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The leaf KeyUsage extension has the digital signature bit set.
      * The leaf ExtendedKeyUsage extension has the CodeSigning OID.
@@ -535,8 +529,7 @@ SecPolicyRef SecPolicyCreateApplePackageSigning(void);
  signatures.  This is for apps signed directly by the app store.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has Common Name "Apple iPhone Certification Authority".
      * The leaf has Common Name "Apple iPhone OS Application Signing".
@@ -556,8 +549,7 @@ SecPolicyRef SecPolicyCreateiPhoneApplicationSigning(void);
  signatures.  This is for VPN plugins signed directly by the VPN team.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has Common Name "Apple iPhone Certification Authority".
      * The leaf has Common Name "Apple iPhone OS Application Signing".
@@ -578,8 +570,7 @@ SecPolicyRef SecPolicyCreateiPhoneVPNApplicationSigning(void)
  profile.
  @discussion This policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1 (WWDR CA).
     * The leaf has a marker extension with OID matching one of the following:
@@ -602,8 +593,7 @@ SecPolicyRef SecPolicyCreateiPhoneProfileApplicationSigning(void);
  profile.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The leaf has a marker extension with OID matching one of the following:
         * 1.2.840.113635.100.6.1.7  ("3rd Party Mac Developer Application" leaf)
@@ -624,8 +614,7 @@ SecPolicyRef SecPolicyCreateMacOSProfileApplicationSigning(void)
  @abstract Returns a policy object for evaluating provisioning profile signatures.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has Common Name "Apple iPhone Certification Authority".
      * The leaf has Common Name "Apple iPhone OS Provisioning Profile Signing".
@@ -645,7 +634,7 @@ SecPolicyRef SecPolicyCreateiPhoneProvisioningProfileSigning(void);
  and allows for both the prod and the dev/test certs.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs.
+     * The chain is anchored to any of the Apple Root CAs.
        Test roots are never permitted.
      * There are exactly 3 certs in the chain.
      * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1.
@@ -693,8 +682,7 @@ enum {
  @discussion This policy uses the Basic X.509 policy with validity check and
  requires the leaf to have
      * a KeyUsage matching the smimeUsage,
-     * an ExtendedKeyUsage, if any, with the AnyExtendedKeyUsage OID or the
-       EmailProtection OID, and
+     * an ExtendedKeyUsage, if any, with the EmailProtection OID, and
      * if the email param is specified, the email address in the RFC822Name in the
        SubjectAlternativeName extension or in the Email Address field of the
        Subject Name.
@@ -745,8 +733,7 @@ SecPolicyRef SecPolicyCreateURLBag(void);
  @abstract  Returns a policy object for evaluating certificate chains for signing OTA Tasking.
  @discussion This policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple iPhone Certification Authority".
     * The leaf has Common Name "OTA Task Signing".
@@ -761,8 +748,7 @@ SecPolicyRef SecPolicyCreateOTATasking(void);
  @abstract  Returns a policy object for evaluating certificate chains for signing Mobile Assets.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple iPhone Certification Authority".
     * The leaf has Common Name "Asset Manifest Signing".
@@ -778,8 +764,7 @@ SecPolicyRef SecPolicyCreateMobileAsset(void);
  Mobile Assets.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.55.1.
@@ -795,8 +780,7 @@ SecPolicyRef SecPolicyCreateMobileAssetDevelopment(void)
  @abstract Returns a policy object for evaluating certificate chains for Apple ID Authority.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3
       or OID 1.2.840.113635.100.6.2.7.
     * The leaf has a marker extension with OID 1.2.840.113635.100.4.7.
@@ -813,8 +797,7 @@ SecPolicyRef SecPolicyCreateAppleIDAuthorityPolicy(void);
  Mac App Store Receipts.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1.
     * The leaf has CertificatePolicy extension with OID 1.2.840.113635.100.5.6.1.
@@ -834,8 +817,7 @@ SecPolicyRef SecPolicyCreateMacAppStoreReceipt(void);
  team ID to match the organizationalUnit field in the leaf certificate's subject.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.16 and containing the
       cardIssuer.
     * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.14.
@@ -852,8 +834,7 @@ SecPolicyRef SecPolicyCreatePassbookCardSigner(CFStringRef cardIssuer,
  @abstract Returns a policy object for evaluating Mobile Store certificate chains.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple System Integration 2 Certification Authority".
     * The leaf has KeyUsage with the DigitalSignature bit set.
@@ -869,8 +850,7 @@ SecPolicyRef SecPolicyCreateMobileStoreSigner(void);
  @abstract  Returns a policy object for evaluating Test Mobile Store certificate chains.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple System Integration 2 Certification Authority".
     * The leaf has KeyUsage with the DigitalSignature bit set.
@@ -886,7 +866,6 @@ SecPolicyRef SecPolicyCreateTestMobileStoreSigner(void);
  @abstract Returns a policy object for evaluating Escrow Service certificate chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to the current Escrow Roots in the OTAPKI asset.
     * There are exactly 2 certs in the chain.
     * The leaf has KeyUsage with the KeyEncipherment bit set.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -900,7 +879,6 @@ SecPolicyRef SecPolicyCreateEscrowServiceSigner(void);
  @abstract Returns a policy object for evaluating PCS Escrow Service certificate chains.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to the current PCS Escrow Roots in the OTAPKI asset.
     * There are exactly 2 certs in the chain.
     * The leaf has KeyUsage with the KeyEncipherment bit set.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -915,8 +893,7 @@ SecPolicyRef SecPolicyCreatePCSEscrowServiceSigner(void);
  Provisioning Profiles.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.1.
     * The leaf has KeyUsage with the DigitalSignature bit set.
     * The leaf has a marker extension with OID 1.2.840.113635.100.4.11.
@@ -933,8 +910,7 @@ SecPolicyRef SecPolicyCreateOSXProvisioningProfileSigning(void);
  Configuration Profiles.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3.
     * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.16.
@@ -951,8 +927,7 @@ SecPolicyRef SecPolicyCreateConfigurationProfileSigner(void);
  policy as SecPolicyCreateConfigurationProfileSigner.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3.
     * The leaf has ExtendedKeyUsage with OID 1.2.840.113635.100.4.17.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -961,42 +936,13 @@ SecPolicyRef SecPolicyCreateConfigurationProfileSigner(void);
 __nullable CF_RETURNS_RETAINED
 SecPolicyRef SecPolicyCreateQAConfigurationProfileSigner(void);
 
-/*!
- @function SecPolicyCreateOTAPKISigner
- @abstract Returns a policy object for evaluating OTA PKI certificate chains.
- @discussion This policy uses the Basic X.509 policy with validity check
- and pinning options:
-    * The chain is anchored to Apple PKI Settings CA.
-    * There are exactly 2 certs in the chain.
- @result A policy object. The caller is responsible for calling CFRelease
-       on this when it is no longer needed.
-*/
-__nullable CF_RETURNS_RETAINED
-SecPolicyRef SecPolicyCreateOTAPKISigner(void)
-    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3);
-
-/*!
- @function SecPolicyCreateTestOTAPKISigner
- @abstract Returns a policy object for evaluating OTA PKI certificate chains.
- @discussion This policy uses the Basic X.509 policy with validity check
- and pinning options:
-    * The chain is anchored to Apple Test PKI Settings CA.
-    * There are exactly 2 certs in the chain.
- @result A policy object. The caller is responsible for calling CFRelease
-       on this when it is no longer needed.
-*/
-__nullable CF_RETURNS_RETAINED
-SecPolicyRef SecPolicyCreateTestOTAPKISigner(void)
-    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_12, __MAC_10_13_4, __IPHONE_7_0, __IPHONE_11_3);
-
 /*!
  @function SecPolicyCreateAppleIDValidationRecordSigningPolicy
  @abstract Returns a policy object for evaluating certificate chains for signing
  Apple ID Validation Records.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate(s) has(have) a marker extension with OID 1.2.840.113635.100.6.2.3
       or OID 1.2.840.113635.100.6.2.10.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.25.
@@ -1012,8 +958,7 @@ SecPolicyRef SecPolicyCreateAppleIDValidationRecordSigningPolicy(void);
  @abstract Returns a policy object for evaluating SMP certificate chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.13.
     * The leaf has KeyUsage with the KeyEncipherment bit set.
@@ -1046,8 +991,7 @@ SecPolicyRef SecPolicyCreateTestAppleSMPEncryption(void);
  @abstract Returns a policy object for verifying production PPQ Signing certificates.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple System Integration 2 Certification
       Authority".
@@ -1066,8 +1010,7 @@ SecPolicyRef SecPolicyCreateApplePPQSigning(void);
  customer builds, this function returns the same policy as SecPolicyCreateApplePPQSigning.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple System Integration 2 Certification
       Authority".
@@ -1083,7 +1026,16 @@ SecPolicyRef SecPolicyCreateTestApplePPQSigning(void);
 /*!
  @function SecPolicyCreateAppleIDSService
  @abstract Ensure we're appropriately pinned to the IDS service (SSL + Apple restrictions)
- @discussion This policy uses the SSL server policy.
+ @discussion This policy uses the Basic X.509 policy with validity check
+ and pinning options:
+    * The chain is anchored to any of the Apple Root CAs.
+    * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
+    * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.4.2 or,
+      if Test Roots are allowed, OID 1.2.840.113635.100.6.27.4.1.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
+      extension.
+    * The leaf has ExtendedKeyUsage with the ServerAuth OID.
+    * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
      on this when it is no longer needed.
  */
@@ -1098,15 +1050,11 @@ SecPolicyRef SecPolicyCreateAppleIDSService(CFStringRef __nullable hostname);
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted only on internal releases either using the context dictionary or with
-      defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.4.2 or,
       if Test Roots are allowed, OID 1.2.840.113635.100.6.27.4.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1123,15 +1071,11 @@ SecPolicyRef SecPolicyCreateAppleIDSServiceContext(CFStringRef hostname, CFDicti
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted only on internal releases either using the context dictionary or with
-      defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.5.2 or,
       if Test Roots are allowed, OID 1.2.840.113635.100.6.27.5.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1147,9 +1091,7 @@ SecPolicyRef SecPolicyCreateApplePushService(CFStringRef hostname, CFDictionaryR
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
     * The chain is anchored to an Entrust Intermediate.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1166,12 +1108,11 @@ SecPolicyRef SecPolicyCreateApplePushServiceLegacy(CFStringRef hostname);
  Boolean true will allow Test Apple roots and test OIDs on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or, if
     enabled, OID 1.2.840.113635.100.6.27.11.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1192,9 +1133,7 @@ SecPolicyRef SecPolicyCreateAppleMMCSService(CFStringRef hostname, CFDictionaryR
     * The chain length is 3.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.11.2 or
     OID 1.2.840.113635.100.6.27.11.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
  @result A policy object. The caller is responsible for calling CFRelease
  on this when it is no longer needed.
@@ -1211,14 +1150,10 @@ SecPolicyRef SecPolicyCreateAppleCompatibilityMMCSService(CFStringRef hostname)
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted only on internal releases either using the context dictionary or with
-      defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.2.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1236,15 +1171,11 @@ SecPolicyRef SecPolicyCreateAppleGSService(CFStringRef hostname, CFDictionaryRef
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted only on internal releases either using the context dictionary or with
-      defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.3.2 or,
       if Test Roots are allowed, OID 1.2.840.113635.100.6.27.3.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1262,14 +1193,11 @@ SecPolicyRef SecPolicyCreateApplePPQService(CFStringRef hostname, CFDictionaryRe
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted either using the context dictionary or with defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.8.2 or,
       if Test Roots are allowed, OID 1.2.840.113635.100.6.27.8.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1287,15 +1215,11 @@ SecPolicyRef SecPolicyCreateAppleAST2Service(CFStringRef hostname, CFDictionaryR
 Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
 and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs via full certificate
-      comparison. Test Apple Root CAs are permitted only on internal releases either
-      using the context dictionary or with defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or,
       if Test Roots are allowed, OID 1.2.840.113635.100.6.27.7.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-      extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1318,9 +1242,7 @@ SecPolicyRef SecPolicyCreateAppleEscrowProxyService(CFStringRef hostname, CFDict
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.7.2 or,
     if UAT is enabled with a defaults write (internal devices only),
     OID 1.2.840.113635.100.6.27.7.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
  @result A policy object. The caller is responsible for calling CFRelease
  on this when it is no longer needed.
@@ -1337,15 +1259,11 @@ __OSX_AVAILABLE_STARTING(__MAC_10_12, __IPHONE_10_0);
  Boolean true will allow Test Apple roots on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs via full certificate
-    comparison. Test Apple Root CAs are permitted only on internal releases either
-    using the context dictionary or with defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.6.2 or,
     if Test Roots are allowed, OID 1.2.840.113635.100.6.27.6.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1361,13 +1279,10 @@ SecPolicyRef SecPolicyCreateAppleFMiPService(CFStringRef hostname, CFDictionaryR
  @param hostname Optional; hostname to verify the certificate name against.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.1
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage, if any, with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1392,8 +1307,7 @@ SecPolicyRef SecPolicyCreateAppleTimeStamping(void);
  @abstract  Returns a policy object for evaluating Apple Pay Issuer Encryption certificate chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has Common Name "Apple Worldwide Developer Relations CA - G2".
     * The leaf has KeyUsage with the KeyEncipherment bit set.
@@ -1410,8 +1324,7 @@ SecPolicyRef SecPolicyCreateApplePayIssuerEncryption(void)
  @abstract  Returns a policy object for evaluating Apple TV VPN Profile certificate chains.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Test Apple Root CAs
-      are permitted only on internal releases.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.43.
@@ -1429,13 +1342,10 @@ SecPolicyRef SecPolicyCreateAppleATVVPNProfileSigning(void)
  @param hostname Required; hostname to verify the certificate name against.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs via full certificate
-    comparison. Test Apple Root CAs are permitted only on internal releases with defaults write.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.16
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.9.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1451,8 +1361,7 @@ SecPolicyRef SecPolicyCreateAppleHomeKitServerAuth(CFStringRef hostname)
  certificates.
  @discussion The resulting policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID matching 1.2.840.113635.100.6.2.1
     (WWDR CA) or 1.2.840.113635.100.6.2.6 (Developer ID CA).
@@ -1484,8 +1393,7 @@ SecPolicyRef SecPolicyCreateAppleExternalDeveloper(void)
  @abstract Returns a policy object for verifying the Apple Software Signing certificate.
  @discussion The resulting policy uses the Basic X.509 policy with no validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has the Common Name "Apple Code Signing Certification Authority".
     * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.22.
@@ -1544,8 +1452,7 @@ SecPolicyRef SecPolicyCreateAppleUniqueDeviceCertificate(CFDataRef __nullable te
  @abstract Returns a policy object for verifying signed Warsaw assets.
  @discussion The resulting policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.14.
     * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.29.
@@ -1562,8 +1469,7 @@ SecPolicyRef SecPolicyCreateAppleWarsaw(void)
  @abstract Returns a policy object for verifying signed static assets for Secure IO.
  @discussion The resulting policy uses the Basic X.509 policy with no validity check and
  pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has an extension with OID matching 1.2.840.113635.100.6.2.10.
     * The leaf has a marker extension with OID matching 1.2.840.113635.100.6.50.
@@ -1583,12 +1489,11 @@ SecPolicyRef SecPolicyCreateAppleSecureIOStaticAsset(void)
  Boolean true will allow Test Apple roots and test OIDs on internal releases.
  @discussion This policy uses the Basic X.509 policy with validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs.
+    * The chain is anchored to any of the Apple Root CAs.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.12.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or, if
     enabled, OID 1.2.840.113635.100.6.27.15.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
     * Revocation is checked via any available method.
  @result A policy object. The caller is responsible for calling CFRelease
@@ -1610,9 +1515,7 @@ SecPolicyRef SecPolicyCreateAppleiCloudSetupService(CFStringRef hostname, CFDict
     * The chain length is 3.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.27.15.2 or
     OID 1.2.840.113635.100.6.27.15.1.
-    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName
-    extension or Common Name.
-    * The leaf is checked against the Black and Gray lists.
+    * The leaf has the provided hostname in the DNSName of the SubjectAlternativeName extension.
     * The leaf has ExtendedKeyUsage with the ServerAuth OID.
  @result A policy object. The caller is responsible for calling CFRelease
  on this when it is no longer needed.
@@ -1639,8 +1542,7 @@ SecPolicyRef SecPolicyCreateAppleAppTransportSecurity(void)
  @abstract  Returns a policy object for evaluating certificate chains for signing Mobile Software Updates.
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-    * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-    the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+    * The chain is anchored to any of the Apple Root CAs.
     * There are exactly 3 certs in the chain.
     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.18.
     * The leaf has a marker extension with OID 1.2.840.113635.100.6.57.2, or on internal releases,
@@ -1720,8 +1622,7 @@ SecPolicyRef SecPolicyCreateDemoDigitalCatalogSigning(void)
  @abstract  Returns a policy object for evaluating certificate chains for signing Asset Receipts
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs. Internal releases allow
-     the chain to be anchored to Test Apple Root CAs if a defaults write for the policy is set.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.10.
      * The leaf has a marker extension with OID 1.2.840.113635.100.6.61.
@@ -1738,7 +1639,7 @@ SecPolicyRef SecPolicyCreateAppleAssetReceipt(void)
  @abstract  Returns a policy object for evaluating certificate chains for signing Developer ID+ Tickets
  @discussion This policy uses the Basic X.509 policy with no validity check
  and pinning options:
-     * The chain is anchored to any of the production Apple Root CAs.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.17.
      * The leaf has a marker extension with OID 1.2.840.113635.100.6.1.30.
@@ -1800,7 +1701,7 @@ SecPolicyRef SecPolicyCreateAppleComponentCertificate(CFDataRef __nullable testR
  @param applicationId A string that identifies the applicationId.
  @discussion The resulting policy uses the Basic X.509 policy with no validity check and
  pinning options:
-     * The chain is anchored to any of the production Apple Root CAs.
+     * The chain is anchored to any of the Apple Root CAs.
      * There are exactly 3 certs in the chain.
      * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.3".
      * The leaf has a marker extension with OID 1.2.840.113635.100.6.69.1 and value
@@ -1845,6 +1746,10 @@ SecPolicyRef SecPolicyCreateLegacySSL(Boolean server, CFStringRef __nullable hos
 __nullable CF_RETURNS_RETAINED
 SecPolicyRef SecPolicyCreateAlisha(void)
     API_AVAILABLE(macos(10.15.4), ios(13.4), watchos(6.2), tvos(13.4));
+extern const CFStringRef kSecPolicyAppleEscrowServiceIdKeySigning
+    API_AVAILABLE(macos(10.15.6), ios(13.5.5));
+extern const CFStringRef kSecPolicyApplePCSEscrowServiceIdKeySigning
+    API_AVAILABLE(macos(10.15.6), ios(13.5.5));
 
 /*!
  @function SecPolicyCreateMeasuredBootPolicySigning
@@ -1865,36 +1770,87 @@ SecPolicyRef SecPolicyCreateMeasuredBootPolicySigning(void)
     API_AVAILABLE(macos(10.15.4), ios(13.4), watchos(6.2), tvos(13.4));
 
 /*!
- @function SecPolicyCreateEscrowServiceIdKeySigning
- @abstract Returns a policy object for verifying Escrow Service ID keys.
- @discussion The resulting policy uses the Basic X.509 policy with no validity check and
+ @function SecPolicyCreateApplePayQRCodeEncryption
+ @abstract Returns a policy object for verifying ApplePay QRCode Encryption certificates
+ @discussion The resulting policy uses the Basic X.509 policy with validity check and
  pinning options:
-    * The chain is anchored to the current Escrow Roots in the OTAPKI asset.
-    * There are exactly 2 certs in the chain.
-    * The leaf has KeyUsage with the DigitalSignature bit set.
-    * CN matching the name generated by escrow service.
+     * The root matches the "Apple External EC Root", or on internal builds, "Test Apple External EC Root"
+     * There are exactly 3 certs in the chain.
+     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.22.
+     * The leaf has a marker extension with OID 1.2.840.113635.100.13.3
+     * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger.
+     * Revocation is checked via any available method
+ Because the "Apple External" roots are not trusted by default, the caller must use
+ SecTrustSetAnchorCertificates with the expected roots.
  @result A policy object. The caller is responsible for calling CFRelease on this when
  it is no longer needed.
  */
 __nullable CF_RETURNS_RETAINED
-SecPolicyRef SecPolicyCreateEscrowServiceIdKeySigning(void)
-    API_AVAILABLE(macos(10.15.6), ios(13.6));
+SecPolicyRef SecPolicyCreateApplePayQRCodeEncryption(void)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
 
 /*!
- @function SecPolicyCreatePCSEscrowServiceIdKeySigning
- @abstract Returns a policy object for verifying PCS Escrow Service ID keys.
+ @function SecPolicyCreateApplePayQRCodeSigning
+ @abstract Returns a policy object for verifying ApplePay QRCode Signing certificates
+ @discussion The resulting policy uses the Basic X.509 policy with validity check and
+ pinning options:
+     * The root matches the "Apple External EC Root", or on internal builds, "Test Apple External EC Root"
+     * There are exactly 3 certs in the chain.
+     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.22.
+     * The leaf has a marker extension with OID 1.2.840.113635.100.12.12
+     * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger.
+     * Revocation is checked via any available method
+ Because the "Apple External" roots are not trusted by default, the caller must use
+ SecTrustSetAnchorCertificates with the expected roots.
+ @result A policy object. The caller is responsible for calling CFRelease on this when
+ it is no longer needed.
+ */
+__nullable CF_RETURNS_RETAINED
+SecPolicyRef SecPolicyCreateApplePayQRCodeSigning(void)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+
+/*!
+ @function SecPolicyCreateAppleAccessoryUpdateSigning
+ @abstract Returns a policy object for verifying Accessory Firmware Update Signing certificates
  @discussion The resulting policy uses the Basic X.509 policy with no validity check and
  pinning options:
-    * The chain is anchored to the current Escrow Roots in the OTAPKI asset.
-    * There are exactly 2 certs in the chain.
-    * The leaf has KeyUsage with the DigitalSignature bit set.
-    * CN matching the name generated by escrow service.
+     * The chain is anchored to any of the Apple Root CAs.
+     * There are exactly 3 certs in the chain.
+     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.17.
+     * The leaf has a marker extension with OID 1.2.840.113635.100.12.9, or, if
+        "AllowAccessoryUpdateSigningBeta" is set to true in the com.apple.security
+        preference/defaults domain, OID 1.2.840.113635.100.12.10
+     * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger.
+     * Revocation is checked via any available method
  @result A policy object. The caller is responsible for calling CFRelease on this when
  it is no longer needed.
  */
 __nullable CF_RETURNS_RETAINED
-SecPolicyRef SecPolicyCreatePCSEscrowServiceIdKeySigning(void)
-    API_AVAILABLE(macos(10.15.6), ios(13.6));
+SecPolicyRef SecPolicyCreateAppleAccessoryUpdateSigning(void)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
+
+/*!
+ @function SecPolicyCreateAggregateMetricTransparency
+ @abstract Returns a policy object for verifying Aggregate Metric Transparency certificates
+ @param facilitator A boolean to indicate whether the facilitator or partner transparency
+ certificate is being checked.
+ @discussion The resulting policy uses the Basic X.509 policy with validity check and
+ pinning options:
+     * The chain is anchored to any of the Apple Root CAs.
+     * There are exactly 3 certs in the chain.
+     * The intermediate has a marker extension with OID 1.2.840.113635.100.6.2.26.
+     * The leaf has a marker extension with OID 1.2.840.113635.100.12.17 if facilitator is true or
+      1.2.840.113635.100.12.18 if facilitator is false. The contents of this marker extension
+      are not checked.
+     * Revocation is checked via any available method.
+     * RSA key sizes are 2048-bit or larger. EC key sizes are P-256 or larger.
+     * Require a positive CT verification result.
+ @result A policy object. The caller is responsible for calling CFRelease on this when
+ it is no longer needed.
+ */
+__nullable CF_RETURNS_RETAINED
+SecPolicyRef SecPolicyCreateAggregateMetricTransparency(bool facilitator)
+    API_AVAILABLE(macos(10.15.6), ios(13.6), watchos(6.2), tvos(13.4));
 
 /*
  *  Legacy functions (OS X only)
@@ -1914,21 +1870,6 @@ SecPolicyRef SecPolicyCreatePCSEscrowServiceIdKeySigning(void)
 OSStatus SecPolicyCopy(CSSM_CERT_TYPE certificateType, const CSSM_OID *policyOID, SecPolicyRef * __nonnull CF_RETURNS_RETAINED policy)
     __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA);
 
-/*!
-     @function SecPolicyCopyAll
-     @abstract Returns an array of all known policies based on certificate type.
-     @param certificateType A certificate type. This is a optional parameter. Pass CSSM_CERT_UNKNOWN if the certificate type is unknown.
-     @param policies The returned array of policies. This is a required parameter.
-     @result A result code.  See "Security Error Codes" (SecBase.h).
-     @discussion This function is deprecated in Mac OS X 10.7 and later;
-     to obtain a policy reference, use one of the SecPolicyCreate* functions in SecPolicy.h. (Note: there is normally
-     no reason to iterate over multiple disjointed policies, except to provide a way to edit trust settings for each
-     policy, as is done in certain certificate UI views. In that specific case, your code should call SecPolicyCreateWithOID
-     for each desired policy from the list of supported OID constants in SecPolicy.h.)
- */
-OSStatus SecPolicyCopyAll(CSSM_CERT_TYPE certificateType, CFArrayRef * __nonnull CF_RETURNS_RETAINED policies)
-    __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_10_3, __MAC_10_7, __IPHONE_NA, __IPHONE_NA);
-
 /* Given a unified SecPolicyRef, return a copy with a legacy
  C++ ItemImpl-based Policy instance. Only for internal use;
  legacy references cannot be used by SecPolicy API functions. */
@@ -1964,7 +1905,6 @@ CFArrayRef SecPolicyCreateAppleTimeStampingAndRevocationPolicies(CFTypeRef polic
  policy. Use outside of the Security project at your own peril.
  */
 extern const CFStringRef kSecPolicyCheckAnchorApple;
-extern const CFStringRef kSecPolicyCheckAnchorSHA1;
 extern const CFStringRef kSecPolicyCheckAnchorSHA256;
 extern const CFStringRef kSecPolicyCheckAnchorTrusted;
 extern const CFStringRef kSecPolicyCheckBasicCertificateProcessing;
@@ -1983,6 +1923,7 @@ extern const CFStringRef kSecPolicyCheckExtendedKeyUsage;
 extern const CFStringRef kSecPolicyCheckExtendedValidation;
 extern const CFStringRef kSecPolicyCheckGrayListedKey;
 extern const CFStringRef kSecPolicyCheckGrayListedLeaf;
+extern const CFStringRef kSecPolicyCheckLeafSPKISHA256;
 extern const CFStringRef kSecPolicyCheckIdLinkage;
 extern const CFStringRef kSecPolicyCheckIntermediateCountry;
 extern const CFStringRef kSecPolicyCheckIntermediateEKU;
@@ -1990,6 +1931,7 @@ extern const CFStringRef kSecPolicyCheckIntermediateMarkerOid;
 extern const CFStringRef kSecPolicyCheckIntermediateMarkerOidWithoutValueCheck;
 extern const CFStringRef kSecPolicyCheckIntermediateOrganization;
 extern const CFStringRef kSecPolicyCheckIntermediateSPKISHA256;
+extern const CFStringRef kSecPolicyCheckCAspkiSHA256;
 extern const CFStringRef kSecPolicyCheckIssuerCommonName;
 extern const CFStringRef kSecPolicyCheckIssuerPolicyConstraints;
 extern const CFStringRef kSecPolicyCheckIssuerNameConstraints;
@@ -2002,6 +1944,7 @@ extern const CFStringRef kSecPolicyCheckMissingIntermediate;
 extern const CFStringRef kSecPolicyCheckNameConstraints;
 extern const CFStringRef kSecPolicyCheckNoNetworkAccess;
 extern const CFStringRef kSecPolicyCheckNonEmptySubject;
+extern const CFStringRef kSecPolicyCheckNotCA;
 extern const CFStringRef kSecPolicyCheckNotValidBefore;
 extern const CFStringRef kSecPolicyCheckPinningRequired;
 extern const CFStringRef kSecPolicyCheckPolicyConstraints;
@@ -2053,6 +1996,38 @@ extern const CFStringRef kSecPolicyNameCodeSigning;
 extern const CFStringRef kSecPolicyNameTimeStamping;
 extern const CFStringRef kSecPolicyNameOCSPSigner;
 
+/*!
+ @function SecPolicyCreateEscrowServiceIdKeySigning
+ @abstract Returns a policy object for verifying Escrow Service ID keys.
+ @discussion The resulting policy uses the Basic X.509 policy with no validity check and
+ pinning options:
+    * The chain is anchored to the current Escrow Roots in the OTAPKI asset.
+    * There are exactly 2 certs in the chain.
+    * The leaf has KeyUsage with the DigitalSignature bit set.
+    * CN matching the name generated by escrow service.
+ @result A policy object. The caller is responsible for calling CFRelease on this when
+ it is no longer needed.
+ */
+__nullable CF_RETURNS_RETAINED
+SecPolicyRef SecPolicyCreateEscrowServiceIdKeySigning(void)
+    API_AVAILABLE(macos(10.15.6), ios(13.6));
+
+/*!
+ @function SecPolicyCreatePCSEscrowServiceIdKeySigning
+ @abstract Returns a policy object for verifying PCS Escrow Service ID keys.
+ @discussion The resulting policy uses the Basic X.509 policy with no validity check and
+ pinning options:
+    * The chain is anchored to the current Escrow Roots in the OTAPKI asset.
+    * There are exactly 2 certs in the chain.
+    * The leaf has KeyUsage with the DigitalSignature bit set.
+    * CN matching the name generated by escrow service.
+ @result A policy object. The caller is responsible for calling CFRelease on this when
+ it is no longer needed.
+ */
+__nullable CF_RETURNS_RETAINED
+SecPolicyRef SecPolicyCreatePCSEscrowServiceIdKeySigning(void)
+    API_AVAILABLE(macos(10.15.6), ios(13.6));
+
 /*
  * MARK: SecPolicyCheckCert functions
  */
@@ -2080,6 +2055,7 @@ bool SecPolicyCheckCertCertificatePolicy(SecCertificateRef cert, CFTypeRef pvcVa
 bool SecPolicyCheckCertCriticalExtensions(SecCertificateRef cert, CFTypeRef __nullable pvcValue);
 bool SecPolicyCheckCertSubjectCountry(SecCertificateRef cert, CFTypeRef pvcValue);
 bool SecPolicyCheckCertUnparseableExtension(SecCertificateRef cert, CFTypeRef pvcValue);
+bool SecPolicyCheckCertNotCA(SecCertificateRef cert, CFTypeRef pvcValue);
 
 void SecPolicySetName(SecPolicyRef policy, CFStringRef policyName);
 __nullable CFArrayRef SecPolicyXPCArrayCopyArray(xpc_object_t xpc_policies, CFErrorRef *error);
@@ -2088,6 +2064,10 @@ void SecPolicySetOptionsValue(SecPolicyRef policy, CFStringRef key, CFTypeRef va
 
 bool SecDNSIsTLD(CFStringRef reference);
 
+CFDataRef CreateCFDataFromBase64CFString(CFStringRef base64string);
+CFArrayRef parseNSPinnedDomains(CFDictionaryRef nsPinnedDomainsDict, CFStringRef hostName, CFStringRef nsPinnedIdentityType);
+void SecPolicyReconcilePinningRequiredIfInfoSpecified(CFMutableDictionaryRef options);
+
 CF_IMPLICIT_BRIDGING_DISABLED
 CF_ASSUME_NONNULL_END
 
index a48083cddc7c44a3524d51919157f8cdb076901a..a8c7f975c5fa4d1ab270492fd67134f3fd468102 100644 (file)
@@ -463,7 +463,22 @@ OSStatus SecTrustGetTrustResult(SecTrustRef trust,
  */
 __nullable
 SecKeyRef SecTrustCopyPublicKey(SecTrustRef trust)
-    __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_2_0);
+    API_DEPRECATED_WITH_REPLACEMENT("SecTrustCopyKey", macos(10.7, 10.16), ios(2.0, 14.0), watchos(1.0, 7.0), tvos(9.0, 14.0));
+
+/*!
+    @function SecTrustCopyKey
+    @abstract Return the public key for a leaf certificate after it has
+    been evaluated.
+    @param trust A reference to the trust object which has been evaluated.
+    @result The certificate's public key, or NULL if it the public key could
+    not be extracted (this can happen if the public key algorithm is not
+    supported).  The caller is responsible for calling CFRelease on the
+    returned key when it is no longer needed.
+    @discussion RSA and ECDSA public keys are supported. All other public key algorithms are unsupported.
+ */
+__nullable
+SecKeyRef SecTrustCopyKey(SecTrustRef trust)
+    API_AVAILABLE(macos(10.16), ios(14.0), watchos(7.0), tvos(14.0));
 
 /*!
     @function SecTrustGetCertificateCount
index 5bf6e60b47a29732379614c56a8a2f1856026fa9..f58f0c0370d4fc824f72329ce0af0062feb6523b 100644 (file)
@@ -296,6 +296,14 @@ uint64_t SecTrustOTASecExperimentGetUpdatedAsset(CFErrorRef _Nullable * _Nullabl
  */
 CFDictionaryRef SecTrustOTASecExperimentCopyAsset(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error);
 
+/*
+ @function SecTrustTriggerValidUpdate
+ @abstract Trigger trustd to fetch a valid update.
+ @param error A returned error if trustd failed to trigger the update.
+ @result True if the update was triggered, false if not.
+ */
+bool SecTrustTriggerValidUpdate(CFErrorRef _Nullable * _Nullable CF_RETURNS_RETAINED error);
+
 /*!
  @function SecTrustFlushResponseCache
  @abstract Removes all OCSP responses from the per-user response cache.
@@ -442,7 +450,7 @@ OSStatus SecTrustSetPinningException(SecTrustRef trust)
   @discussion Exceptions tagged with an older epoch are not trusted.
   */
 uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error)
-    API_UNAVAILABLE(macos, iosmac) API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0));
+    API_UNAVAILABLE(macos, macCatalyst) API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0));
 
 /*!
   @function SecTrustIncrementExceptionResetCount
@@ -452,7 +460,7 @@ uint64_t SecTrustGetExceptionResetCount(CFErrorRef *error)
   @discussion By increasing the current epoch any existing exceptions, tagged with the old epoch, become distrusted.
   */
 OSStatus SecTrustIncrementExceptionResetCount(CFErrorRef *error)
-    __API_UNAVAILABLE(macos, iosmac) __API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0));
+    __API_UNAVAILABLE(macos, macCatalyst) __API_AVAILABLE(ios(12.0), tvos(12.0), watchos(5.0));
 #endif
 
 #ifdef __BLOCKS__
index 62b1c9b4e656cce371a14d47fff699d8dde350bf..21046ff251474bf8646473b804f277d91bf4c01e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2017 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2002-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -58,15 +58,15 @@ extern const CFStringRef kSecCTExceptionsSPKIHashKey;
 /*
  @function SecTrustStoreSetCTExceptions
  @abstract Set the certificate transparency enforcement exceptions
- @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the callers entitlements.
+ @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the caller's entitlements.
  @param exceptions Dictionary of exceptions to set for this application. These exceptions replace existing exceptions for the keys in the dictionary. Exceptions for omitted keys are not affected. Null removes all exceptions for this application. See the discussion sections below for a complete overview of options.
- @param error Upon failure describes cause of the failure.
+ @param error On failure, describes the cause of the failure; otherwise, null.
  @result boolean indicating success of the operation. If false, error will be filled in with a description of the error.
  @discussions An exceptions dictionary has two optional keys:
  kSecCTExceptionsDomainsKey takes an array of strings. These strings are the domains that are excluded from enforcing CT. A leading "." is supported to signify subdomains. Wildcard domains are not supported.
  kSecCTExceptionsCAsKey takes an array of dictionaries. Each dictionary has two required keys:
-    kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currenlty only "sha256" is supported.
-    kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificates SubjectPublicKeyInfo.
+    kSecCTExceptionsHashAlgorithmKey takes a string indicating the hash algorithm. Currently only "sha256" is supported.
+    kSecCTExceptionsSPKIHashKey takes a data containing hash of a certificate's SubjectPublicKeyInfo.
  */
 bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionaryRef exceptions, CFErrorRef *error);
 
@@ -74,12 +74,41 @@ bool SecTrustStoreSetCTExceptions(CFStringRef applicationIdentifier, CFDictionar
  @function SecTrustStoreCopyCTExceptions
  @abstract Return the certificate transparency enforcement exceptions
  @param applicationIdentifier Identifier for the caller's exceptions to fetch. If null, all set exceptions will be returned (regardless of which caller set them).
- @param error Upon failure describes cause of the failure.
+ @param error On failure, describes the cause of the failure; otherwise, null.
  @result The dictionary of currently set exceptions. Null if none exist or upon failure.
  @discussion The returned exceptions dictionary has the same options as input exceptions. See the discussion of SecTrustStoreSetCTExceptions.
  */
 CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCTExceptions(CFStringRef applicationIdentifier, CFErrorRef *error);
 
+
+extern const CFStringRef kSecCARevocationAdditionsKey;
+extern const CFStringRef kSecCARevocationHashAlgorithmKey;
+extern const CFStringRef kSecCARevocationSPKIHashKey;
+
+/*
+ @function SecTrustStoreSetCARevocationAdditions
+ @abstract Set a list of certificate authorities (specified by subject public key info hash) for which revocation should be explicitly checked.
+ @param applicationIdentifier Identifier for the caller. If null, the application-identifier will be read from the caller's entitlements.
+ @param additions Dictionary of SPKI hashes for which revocation should be explicitly checked. Existing entries for the keys in the dictionary will be replaced. Null removes all CA revocation additions for this application. See the discussion sections below for a complete overview of options.
+ @param error On failure, describes the cause of the failure; otherwise, null.
+ @result boolean indicating success of the operation. If false, error will be filled in with a description of the error.
+ @discussions An additions dictionary currently has one defined key:
+ kSecCARevocationAdditionsKey takes an array of dictionaries. Each dictionary has two required keys:
+    kSecCARevocationHashAlgorithmKey takes a string indicating the hash algorithm. Currently only "sha256" is supported.
+    kSecCARevocationSPKIHashKey takes a data containing hash of a certificate's SubjectPublicKeyInfo.
+ */
+bool SecTrustStoreSetCARevocationAdditions(CFStringRef applicationIdentifier, CFDictionaryRef additions, CFErrorRef *error);
+
+/*
+ @function SecTrustStoreCopyCARevocationAdditions
+ @abstract Return the certificate authority SPKI hashes for which revocation should be explicitly checked.
+ @param applicationIdentifier Identifier for the caller's additions to fetch. If null, all set exceptions will be returned (regardless of which caller set them).
+ @param error On failure, describes cause of the failure; otherwise, null.
+ @result The dictionary of currently set CA revocation additions. Null if none exist or upon failure.
+ @discussion The returned additions dictionary has the same options as input additions. See the discussion of SecTrustStoreSetCARevocationAdditions.
+ */
+CF_RETURNS_RETAINED CFDictionaryRef SecTrustStoreCopyCARevocationAdditions(CFStringRef applicationIdentifier, CFErrorRef *error);
+
 #if SEC_OS_OSX
 
 /*
@@ -211,6 +240,19 @@ void SecTrustSettingsPurgeUserAdminCertsCache(void);
  */
 OSStatus SecTrustSettingsCopyCertificatesForUserAdminDomains(
     CFArrayRef CF_RETURNS_RETAINED *certArray);
+
+/* Just like the API version (SecTrustSettingsCopyTrustSettings) but
+ * uses the cached version of trust settings to avoid disk reads. */
+OSStatus SecTrustSettingsCopyTrustSettings_Cached(
+    SecCertificateRef certRef,
+    SecTrustSettingsDomain domain,
+    CFArrayRef CF_RETURNS_RETAINED *trustSettings);
+
+/* Purge the trust settings cache (used by the above) */
+void SecTrustSettingsPurgeCache(void);
+
+/* Determines if the given cert has any trust settings in the admin or user domains */
+bool SecTrustSettingsUserAdminDomainsContain(SecCertificateRef certRef);
 #endif /* SEC_OS_OSX_INCLUDES */
 
 __END_DECLS
index 4a1d490d6276fc8f87b32a381706de53987c9996..d524d573a63f97d179457463a6105241c5107517 100644 (file)
  *
  */
 
+/* We need to guard against the other copy of libDER.
+ * This is outside this header's guards because DERItem.h currently guards
+ * the DERItem type against this header (legacy from when this header also
+ * defined the type). */
+#ifndef _LIB_DER_H_
+#include <libDER/DERItem.h>
+#endif    /* _LIB_DER_H_ */
+
 #ifndef        _SECURITY_OIDS_H_
 #define _SECURITY_OIDS_H_
 
 
 __BEGIN_DECLS
 
-/* This is a subset of libDER's oids.h. If the types header has
- * already been included, we should skip these typedef declarations. */
-#ifndef _LIB_DER_H_
-/*
- * Basic data types
- */
-typedef uint8_t DERByte;
-typedef size_t DERSize;
-
-/*
- * Primary representation of a block of memory.
- */
-typedef struct {
-    DERByte            *data;
-    DERSize            length;
-} DERItem;
-#endif    /* _LIB_DER_H_ */
-
 /* Algorithm oids. */
 extern const DERItem
     oidRsa,             /* PKCS1 RSA encryption, used to identify RSA keys */
index f3e597093db03b844e1c4bdacc1a33491f92f45b..4ac7be77d67d0b0212c190b4c8673586a3891ddd 100644 (file)
@@ -272,9 +272,9 @@ static void LogRemotelyWithAttributes(OTATrustLogLevel level, NSError **error, N
 #if ENABLE_TRUSTD_ANALYTICS
     /* only report errors and notices */
     if (error && level == OTATrustLogLevelError) {
-        [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:YES result:*error withAttributes:attributes];
+        [[TrustAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:YES result:*error withAttributes:attributes];
     } else if (error && level == OTATrustLogLevelNotice) {
-        [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:NO result:*error withAttributes:attributes];
+        [[TrustAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventOTAPKIEvent hardFailure:NO result:*error withAttributes:attributes];
     }
 #endif // ENABLE_TRUSTD_ANALYTICS
 }
@@ -536,7 +536,7 @@ static NSNumber *PKIUpdateAndPurgeAsset(MAAsset *asset, NSNumber *asset_version,
         UpdateFromAsset([asset getLocalFileUrl], asset_version, error)) {
         secnotice("OTATrust", "finished update to version %@ from installed asset. purging asset.", asset_version);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logSuccessForEventNamed:TrustdHealthAnalyticsEventOTAPKIEvent];
+        [[TrustAnalytics logger] logSuccessForEventNamed:TrustdHealthAnalyticsEventOTAPKIEvent];
 #endif // ENABLE_TRUSTD_ANALYTICS
         [asset purge:^(MAPurgeResult purge_result) {
             if (purge_result != MAPurgeSucceeded) {
index ebd9350f5aff080237b937af876bd63d049b5f10..71233beb274ea0dcbbf83a2b4b283805223248c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2017-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -37,6 +37,7 @@
 #include <Security/SecCertificateInternal.h>
 #include <Security/SecItem.h>
 #include <Security/SecInternal.h>
+#include <Security/SecTrustSettingsPriv.h>
 
 #include <utilities/SecIOFormat.h>
 #include <utilities/SecCFError.h>
@@ -47,6 +48,7 @@
 #include "trust/trustd/SecPolicyServer.h"
 #include "trust/trustd/SecCertificateServer.h"
 #include "trust/trustd/SecRevocationServer.h"
+#include "trust/trustd/SecTrustStoreServer.h"
 
 // MARK: -
 // MARK: SecCertificateVC
@@ -254,6 +256,11 @@ struct SecCertificatePathVC {
     bool                is_allowlisted;
     bool                hasStrongHashes;
 
+    /* revocationCAIndex contains the index of the last CA with a SPKI-based
+     * revocation match, or -1 (kCFNotFound) if no CA match was found.
+     * A value of 0 means the path has not yet been checked for a match. */
+    CFIndex             revocationCAIndex;
+
     void *              rvcs;
     CFIndex             rvcCount;
 
@@ -757,7 +764,7 @@ bool SecCertificatePathVCHasWeakKeySize(SecCertificatePathVCRef certificatePath)
             *stop = true;
         }
     });
-    
+
 errOut:
     CFReleaseSafe(keySizes);
     CFReleaseSafe(rsaSize);
@@ -768,19 +775,19 @@ errOut:
 /* Return a score for this certificate chain. */
 CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbsoluteTime verifyTime) {
     CFIndex score = 0;
-    
+
     /* Paths that don't verify score terribly.c */
     if (certificatePath->lastVerifiedSigner != certificatePath->count - 1) {
         secdebug("trust", "lvs: %" PRIdCFIndex " count: %" PRIdCFIndex,
                  certificatePath->lastVerifiedSigner, certificatePath->count);
         score -= 100000;
     }
-    
+
     if (certificatePath->isAnchored) {
         /* Anchored paths for the win! */
         score += 10000;
     }
-    
+
     if (certificatePath->isSelfSigned && (certificatePath->selfIssued == certificatePath->count - 1)) {
         /* Chains that terminate in a self-signed certificate are preferred,
          even if they don't end in an anchor. */
@@ -791,19 +798,19 @@ CFIndex SecCertificatePathVCScore(SecCertificatePathVCRef certificatePath, CFAbs
         /* Longer chains are preferred when the chain doesn't end in a self-signed cert. */
         score += 1 * certificatePath->count;
     }
-    
+
     if (SecCertificatePathVCIsValid(certificatePath, verifyTime)) {
         score += 100;
     }
-    
+
     if (!SecCertificatePathVCHasWeakHash(certificatePath)) {
         score += 10;
     }
-    
+
     if (!SecCertificatePathVCHasWeakKeySize(certificatePath)) {
         score += 10;
     }
-    
+
     return score;
 }
 
@@ -1001,6 +1008,63 @@ void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath,
     certificatePath->requiresCT = requiresCT;
 }
 
+static bool has_ca_additions_key(SecCertificatePathVCRef path, CFDictionaryRef ca_entry) {
+    bool result = false;
+    CFDataRef hash = CFDictionaryGetValue(ca_entry, kSecCARevocationSPKIHashKey);
+    if (!hash) {
+        return false;
+    }
+    /* only check issuing CAs and not the leaf */
+    for (CFIndex certIX = 1; certIX < SecCertificatePathVCGetCount(path); certIX++) {
+        SecCertificateRef ca = SecCertificatePathVCGetCertificateAtIndex(path, certIX);
+        CFDataRef spkiHash = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(ca);
+        bool matched = CFEqualSafe(hash, spkiHash);
+        CFReleaseNull(spkiHash);
+        if (!matched) {
+            continue;
+        }
+        /* this SPKI is a match; remember highest index */
+        if (certIX > path->revocationCAIndex) {
+            path->revocationCAIndex = certIX;
+        }
+        result = true;
+    }
+    return result;
+}
+
+static void SecCertificatePathVCCheckCARevocationAdditions(SecCertificatePathVCRef path) {
+    CFDictionaryRef additions = _SecTrustStoreCopyCARevocationAdditions(NULL, NULL);
+    path->revocationCAIndex = kCFNotFound;
+    if (!additions) {
+        return;
+    }
+
+    __block bool result = false;
+    CFArrayRef ca_list = CFDictionaryGetValue(additions, kSecCARevocationAdditionsKey);
+    if (ca_list) {
+        CFArrayForEach(ca_list, ^(const void *value) {
+            result = result || has_ca_additions_key(path, value);
+        });
+    }
+
+    if (result) {
+        secinfo("ocsp", "key-based CA revocation applies at index %lld",
+                (long long)path->revocationCAIndex);
+    }
+
+    CFReleaseNull(additions);
+    return;
+}
+
+CFIndex SecCertificatePathVCIndexOfCAWithRevocationAdditions(SecCertificatePathVCRef certificatePath) {
+    if (!certificatePath) { return kCFNotFound; }
+    if (0 == certificatePath->revocationCAIndex) {
+        /* we haven't checked this path yet, do it now */
+        SecCertificatePathVCCheckCARevocationAdditions(certificatePath);
+    }
+    return certificatePath->revocationCAIndex;
+}
+
 CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath) {
     if (!certificatePath) { return 0; }
     return certificatePath->issuanceTime;
index 8a14434001d146800b55fb5a14129aa438b395c0..e3b694957d67be5ea4ca596d8c5765353b170ef1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2017-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -166,6 +166,12 @@ void SecCertificatePathVCSetRequiresCT(SecCertificatePathVCRef certificatePath,
 CFAbsoluteTime SecCertificatePathVCIssuanceTime(SecCertificatePathVCRef certificatePath);
 void SecCertificatePathVCSetIssuanceTime(SecCertificatePathVCRef certificatePath, CFAbsoluteTime issuanceTime);
 
+/* CA Revocation Additions */
+/* Returns the index of the highest issuing CA which has matching key-based
+ * revocation additions in the given path, or kCFNotFound if none is found.
+ */
+CFIndex SecCertificatePathVCIndexOfCAWithRevocationAdditions(SecCertificatePathVCRef certificatePath);
+
 /* Allowlist */
 bool SecCertificatePathVCIsAllowlisted(SecCertificatePathVCRef certificatePath);
 void SecCertificatePathVCSetIsAllowlisted(SecCertificatePathVCRef certificatePath, bool isAllowlisted);
index 1c7932e7c9d1c476ca8bf4dad6c60eb8267a212b..63924442cba2de77edc4560ffbebbe14f8596dc7 100644 (file)
@@ -416,8 +416,6 @@ struct SecCertificateSource _kSecSystemAnchorSource = {
 
 const SecCertificateSourceRef kSecSystemAnchorSource = &_kSecSystemAnchorSource;
 
-
-#if TARGET_OS_IPHONE
 // MARK: -
 // MARK: SecUserAnchorSource
 /********************************************************
@@ -461,7 +459,6 @@ struct SecCertificateSource _kSecUserAnchorSource = {
 };
 
 const SecCertificateSourceRef kSecUserAnchorSource = &_kSecUserAnchorSource;
-#endif
 
 // MARK: -
 // MARK: SecMemoryCertificateSource
@@ -629,30 +626,33 @@ const SecCertificateSourceRef kSecLegacyCertificateSource = &_kSecLegacyCertific
 static bool SecLegacyAnchorSourceCopyParents(SecCertificateSourceRef source, SecCertificateRef certificate,
                                              void *context, SecCertificateSourceParents callback) {
     CFMutableArrayRef anchors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    CFArrayRef parents = SecItemCopyParentCertificates_osx(certificate, NULL);
     CFArrayRef trusted = NULL;
-    if (parents == NULL) {
+    CFDataRef normalizedIssuer = SecCertificateCopyNormalizedIssuerSequence(certificate);
+    if (!normalizedIssuer) {
         goto finish;
     }
+
     /* Get the custom anchors which have been trusted in the user and admin domains.
      * We don't need system domain roots here, since SecSystemAnchorSource provides those.
      */
     OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
     if (status == errSecSuccess && trusted) {
-        CFIndex index, count = CFArrayGetCount(parents);
+        CFIndex index, count = CFArrayGetCount(trusted);
         for (index = 0; index < count; index++) {
-            SecCertificateRef parent = (SecCertificateRef)CFArrayGetValueAtIndex(parents, index);
-            if (parent && CFArrayContainsValue(trusted, CFRangeMake(0, CFArrayGetCount(trusted)), parent)) {
-                CFArrayAppendValue(anchors, parent);
+            SecCertificateRef potentialParent = (SecCertificateRef)CFArrayGetValueAtIndex(trusted, index);
+            CFDataRef normalizedSubject = SecCertificateCopyNormalizedSubjectSequence(potentialParent);
+            if (CFEqualSafe(normalizedIssuer, normalizedSubject)) {
+                CFArrayAppendValue(anchors, potentialParent);
             }
+            CFReleaseSafe(normalizedSubject);
         }
     }
 
 finish:
     callback(context, anchors);
     CFReleaseSafe(anchors);
-    CFReleaseSafe(parents);
     CFReleaseSafe(trusted);
+    CFReleaseSafe(normalizedIssuer);
     return true;
 }
 
@@ -661,19 +661,19 @@ static CFArrayRef SecLegacyAnchorSourceCopyUsageConstraints(SecCertificateSource
     CFArrayRef result = NULL;
     CFArrayRef userTrustSettings = NULL, adminTrustSettings = NULL;
 
-    OSStatus status = SecTrustSettingsCopyTrustSettings(certificate,
-                                                        kSecTrustSettingsDomainUser,
-                                                        &userTrustSettings);
-    if ((status == errSecSuccess) && (userTrustSettings != NULL)) {
-        result = CFRetain(userTrustSettings);
+    OSStatus status = SecTrustSettingsCopyTrustSettings_Cached(certificate,
+                                                               kSecTrustSettingsDomainAdmin,
+                                                               &adminTrustSettings);
+    if ((status == errSecSuccess) && (adminTrustSettings != NULL)) {
+        /* admin trust settings overrule user trust settings (rdar://37052515) */
+        return adminTrustSettings;
     }
 
-    status = SecTrustSettingsCopyTrustSettings(certificate,
-                                               kSecTrustSettingsDomainAdmin,
-                                               &adminTrustSettings);
-    /* user trust settings overrule admin trust settings */
-    if ((status == errSecSuccess) && (adminTrustSettings != NULL) && (result == NULL)) {
-        result = CFRetain(adminTrustSettings);
+    status =  SecTrustSettingsCopyTrustSettings_Cached(certificate,
+                                                       kSecTrustSettingsDomainUser,
+                                                       &userTrustSettings);
+    if (status == errSecSuccess) {
+        result = CFRetainSafe(userTrustSettings);
     }
 
     CFReleaseNull(userTrustSettings);
@@ -686,31 +686,39 @@ static bool SecLegacyAnchorSourceContains(SecCertificateSourceRef source,
     if (certificate == NULL) {
         return false;
     }
-    CFArrayRef trusted = NULL;
-    bool result = false;
-    OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
-    if ((status == errSecSuccess) && (trusted != NULL)) {
-        CFIndex index, count = CFArrayGetCount(trusted);
-        for (index = 0; index < count; index++) {
-            SecCertificateRef anchor = (SecCertificateRef)CFRetainSafe(CFArrayGetValueAtIndex(trusted, index));
-            if (anchor && (CFGetTypeID(anchor) != CFGetTypeID(certificate))) {
-                /* This should only happen if trustd and the Security framework are using different SecCertificate TypeIDs.
+
+    if (SecTrustSettingsUserAdminDomainsContain(certificate)) {
+        return true;
+    } else {
+        CFArrayRef trusted = NULL;
+        bool result = false;
+        OSStatus status = SecTrustSettingsCopyCertificatesForUserAdminDomains(&trusted);
+        if ((status == errSecSuccess) && (trusted != NULL)) {
+            if ((CFArrayGetCount(trusted) > 0) && CFGetTypeID(CFArrayGetValueAtIndex(trusted, 0)) != CFGetTypeID(certificate)) {
+                /* This fallback should only happen if trustd and the Security framework are using different SecCertificate TypeIDs.
                  * This occurs in TrustTests where we rebuild SecCertificate.c for code coverage purposes, so we end up with
                  * two registered SecCertificate types. So we'll make a SecCertificate of our type. */
-                SecCertificateRef temp = SecCertificateCreateWithBytes(NULL, SecCertificateGetBytePtr(anchor), SecCertificateGetLength(anchor));
-                CFAssignRetained(anchor, temp);
-            }
-            if (anchor && CFEqual(anchor, certificate)) {
-                result = true;
-            }
-            CFReleaseNull(anchor);
-            if (result) {
-                break;
+                CFIndex index, count = CFArrayGetCount(trusted);
+                for (index = 0; index < count; index++) {
+                    SecCertificateRef anchor = (SecCertificateRef)CFRetainSafe(CFArrayGetValueAtIndex(trusted, index));
+                    if (anchor && (CFGetTypeID(anchor) != CFGetTypeID(certificate))) {
+                        SecCertificateRef temp = SecCertificateCreateWithBytes(NULL, SecCertificateGetBytePtr(anchor), SecCertificateGetLength(anchor));
+                        CFAssignRetained(anchor, temp);
+                    }
+                    if (anchor && CFEqual(anchor, certificate)) {
+                        result = true;
+                    }
+                    CFReleaseNull(anchor);
+                    if (result) {
+                        break;
+                    }
+                }
             }
+            CFReleaseSafe(trusted);
+            return result;
         }
     }
-    CFReleaseSafe(trusted);
-    return result;
+    return false;
 }
 
 struct SecCertificateSource _kSecLegacyAnchorSource = {
index c2c9990773451466fd9424902a0db2637611d451..b99b822a48c5fd493addcf79b64ed05eecc3c37c 100644 (file)
@@ -78,10 +78,8 @@ void SecMemoryCertificateSourceDestroy(SecCertificateSourceRef source);
 /* SecSystemAnchorSource */
 extern const SecCertificateSourceRef kSecSystemAnchorSource;
 
-#if TARGET_OS_IPHONE
 /* SecUserAnchorSource */
 extern const SecCertificateSourceRef kSecUserAnchorSource;
-#endif
 
 /* SecCAIssuerCertificateSource */
 extern const SecCertificateSourceRef kSecCAIssuerSource;
index 0d1995a6d846450fc134c901bc68358397e0d1ff..2b422449a98d8cda79593dd94c73c9c046eeecfc 100644 (file)
@@ -692,3 +692,20 @@ SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this, SecCertific
     /* We couldn't find who signed this ocspResponse, give up. */
     return NULL;
 }
+
+bool SecOCSPResponseIsWeakHash(SecOCSPResponseRef response) {
+    SecAsn1AlgId algId = response->basicResponse.algId;
+    const DERItem algOid = {
+        .data = algId.algorithm.Data,
+        .length = algId.algorithm.Length,
+    };
+    SecSignatureHashAlgorithm algorithm = SecSignatureHashAlgorithmForAlgorithmOid(&algOid);
+    if (algorithm == kSecSignatureHashAlgorithmUnknown ||
+        algorithm == kSecSignatureHashAlgorithmMD2 ||
+        algorithm == kSecSignatureHashAlgorithmMD4 ||
+        algorithm == kSecSignatureHashAlgorithmMD5 ||
+        algorithm == kSecSignatureHashAlgorithmSHA1) {
+        return true;
+    }
+    return false;
+}
index 91eec7977190e0c720e5e7b9cbe183ff81ead1cd..2bbaf3fc554fc944139dd80d1da4a1779253367e 100644 (file)
@@ -160,6 +160,8 @@ void SecOCSPSingleResponseDestroy(SecOCSPSingleResponseRef this);
 SecCertificateRef SecOCSPResponseCopySigner(SecOCSPResponseRef this,
     SecCertificateRef issuerPath);
 
+bool SecOCSPResponseIsWeakHash(SecOCSPResponseRef response);
+
 __END_DECLS
 
 #endif /* !_SECURITY_SECOCSPRESPONSE_H_ */
index a62b9256233198f6decc8ecc3cc37be15850ff94..55fc3193be485550af1e861f24d34a5a8ebe59ae 100644 (file)
@@ -341,7 +341,7 @@ static inline bool isNSDictionary(id nsType) {
     if (!ok || error) {
         secerror("SecPinningDb: error installing updated pinning list version %@: %@", [pinningList objectAtIndex:0], error);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error
+        [[TrustAnalytics logger] logHardError:(__bridge NSError *)error
                                        withEventName:TrustdHealthAnalyticsEventDatabaseEvent
                                       withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb),
                                                        TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationWrite) }];
@@ -471,7 +471,7 @@ static inline bool isNSDictionary(id nsType) {
                  if (!ok) {
                      secerror("SecPinningDb: %s failed: %@", didCreate ? "Create" : "Open", error ? *error : NULL);
 #if ENABLE_TRUSTD_ANALYTICS
-                     [[TrustdHealthAnalytics logger] logHardError:(error ? (__bridge NSError *)*error : nil)
+                     [[TrustAnalytics logger] logHardError:(error ? (__bridge NSError *)*error : nil)
                                                     withEventName:TrustdHealthAnalyticsEventDatabaseEvent
                                                    withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb),
                                                                     TrustdHealthAnalyticsAttributeDatabaseOperation : didCreate ? @(TAOperationCreate) : @(TAOperationOpen)}];
@@ -699,7 +699,7 @@ static void verify_create_path(const char *path)
     if (!ok || error) {
         secerror("SecPinningDb: error querying DB for hostname: %@", error);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error
+        [[TrustAnalytics logger] logHardError:(__bridge NSError *)error
                                        withEventName:TrustdHealthAnalyticsEventDatabaseEvent
                                       withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb),
                                                        TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}];
@@ -774,7 +774,7 @@ static void verify_create_path(const char *path)
     if (!ok || error) {
         secerror("SecPinningDb: error querying DB for policyName: %@", error);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error
+        [[TrustAnalytics logger] logHardError:(__bridge NSError *)error
                                        withEventName:TrustdHealthAnalyticsEventDatabaseEvent
                                       withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb),
                                                        TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}];
@@ -809,7 +809,7 @@ void SecPinningDbInitialize(void) {
             if (!ok || error) {
                 secerror("SecPinningDb: unable to initialize db: %@", error);
 #if ENABLE_TRUSTD_ANALYTICS
-                [[TrustdHealthAnalytics logger] logHardError:(__bridge NSError *)error
+                [[TrustAnalytics logger] logHardError:(__bridge NSError *)error
                                                withEventName:TrustdHealthAnalyticsEventDatabaseEvent
                                               withAttributes:@{TrustdHealthAnalyticsAttributeAffectedDatabase : @(TAPinningDb),
                                                                TrustdHealthAnalyticsAttributeDatabaseOperation : @(TAOperationRead)}];
@@ -823,15 +823,18 @@ void SecPinningDbInitialize(void) {
 CFDictionaryRef _Nullable SecPinningDbCopyMatching(CFDictionaryRef query) {
     @autoreleasepool {
         SecPinningDbInitialize();
-
         NSDictionary *nsQuery = (__bridge NSDictionary*)query;
-        NSString *hostname = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyHostname];
 
-        NSDictionary *results = [pinningDb queryForDomain:hostname];
-        if (results) { return CFBridgingRetain(results); }
+        /* prefer rules queried by policy name */
         NSString *policyName = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyPolicyName];
-        results = [pinningDb queryForPolicyName:policyName];
-        if (!results) { return nil; }
+        NSDictionary *results = [pinningDb queryForPolicyName:policyName];
+        if (results) {
+            return CFBridgingRetain(results);
+        }
+
+        /* then rules queried by hostname */
+        NSString *hostname = [nsQuery objectForKey:(__bridge NSString*)kSecPinningDbKeyHostname];
+        results = [pinningDb queryForDomain:hostname];
         return CFBridgingRetain(results);
     }
 }
index e826197be057d701d6295a9313fb534539f6f196..e0abcb940787357aabb5bb6959bdf651a84319e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008-2018 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2008-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -308,9 +308,26 @@ static void SecPolicyCheckExtendedKeyUsage(SecPVCRef pvc, CFStringRef key) {
     SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
     SecPolicyRef policy = SecPVCGetPolicy(pvc);
     CFTypeRef xeku = CFDictionaryGetValue(policy->_options, key);
+    /* leaf check enforced */
     if (!SecPolicyCheckCertExtendedKeyUsage(leaf, xeku)){
         SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
     }
+
+    /* subCA check produces metrics */
+    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(pvc->builder);
+    CFIndex ix, count = SecPVCGetCertificateCount(pvc);
+    if (count > 2 && analytics) {
+        for (ix = 1; ix < count - 1 ; ++ix) {
+            SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
+            CFArrayRef ekus = SecCertificateCopyExtendedKeyUsage(cert);
+            if (ekus && CFArrayGetCount(ekus) &&  // subCA has ekus
+                !SecPolicyCheckCertExtendedKeyUsage(cert, CFSTR("2.5.29.37.0")) && // but not the anyEKU
+                !SecPolicyCheckCertExtendedKeyUsage(cert, xeku)) { // and not the EKUs specified by the policy
+                analytics->ca_fail_eku_check = true;
+            }
+            CFReleaseNull(ekus);
+        }
+    }
 }
 
 static void SecPolicyCheckBasicConstraints(SecPVCRef pvc,
@@ -557,26 +574,8 @@ static void SecPolicyCheckAnchorSHA256(SecPVCRef pvc, CFStringRef key) {
     return;
 }
 
-
-/* AUDIT[securityd](done):
-   policy->_options is a caller provided dictionary, only its cf type has
-   been checked.
- */
-static void SecPolicyCheckAnchorSHA1(SecPVCRef pvc,
-       CFStringRef key) {
-    CFIndex count = SecPVCGetCertificateCount(pvc);
-       SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, count - 1);
-    CFDataRef anchorSHA1 = SecCertificateGetSHA1Digest(cert);
-
-    if (!isDigestInPolicy(pvc, key, anchorSHA1))
-        if (!SecPVCSetResult(pvc, kSecPolicyCheckAnchorSHA1, count-1, kCFBooleanFalse))
-            return;
-
-    return;
-}
-
 /*
-   Check the SHA256 of SPKI of the first intermediate CA certificate in the path
+   Check the SHA256 of SPKI of the first intermediate CA certificate in the path.
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
  */
@@ -599,6 +598,73 @@ static void SecPolicyCheckIntermediateSPKISHA256(SecPVCRef pvc,
     CFReleaseNull(digest);
 }
 
+/*
+   Check the SPKI SHA256 of CA certificates in the path
+   policy->_options is a caller provided dictionary, only its cf type has
+   been checked.
+ */
+static void SecPolicyCheckCAspkiSHA256(SecPVCRef pvc,
+                                       CFStringRef key) {
+    SecCertificateRef cert = NULL;
+    CFDataRef digest = NULL;
+
+    if (SecPVCGetCertificateCount(pvc) < 2) {
+        SecPVCSetResult(pvc, kSecPolicyCheckCAspkiSHA256, 0, kCFBooleanFalse);
+        return;
+    }
+
+    bool spkiSHA256match = false;
+    CFIndex count = SecPVCGetCertificateCount(pvc);
+    for (CFIndex i = 1; i < count && spkiSHA256match == false; i++) {
+        cert = SecPVCGetCertificateAtIndex(pvc, i);
+        digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(cert);
+
+        if (isDigestInPolicy(pvc, key, digest)) {
+            spkiSHA256match = true;
+        }
+
+        CFReleaseNull(digest);
+    }
+
+    if (spkiSHA256match == true) {
+        return;
+    }
+
+    for (CFIndex i = 1; i < count; i++) {
+        SecPVCSetResult(pvc, kSecPolicyCheckCAspkiSHA256, i, kCFBooleanFalse);
+    }
+}
+
+/*
+  Check the SPKI SHA256 of the leaf certificate.
+  policy->_options is a caller provided dictionary, only its cf type has
+  been checked.
+*/
+static void SecPolicyCheckLeafSPKISHA256(SecPVCRef pvc,
+                                         CFStringRef key) {
+    SecPolicyRef policy = SecPVCGetPolicy(pvc);
+
+    CFArrayRef leafSPKISHA256 = CFDictionaryGetValue(policy->_options, key);
+    if (isArray(leafSPKISHA256) == false) {
+        /* @@@ We can't return an error here and making the evaluation fail
+        won't help much either. */
+        return;
+    }
+
+    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+    CFDataRef digest = SecCertificateCopySubjectPublicKeyInfoSHA256Digest(leaf);
+    if (!digest) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+        return;
+    }
+
+    if (!CFArrayContainsValue(leafSPKISHA256, CFRangeMake(0, CFArrayGetCount(leafSPKISHA256)), digest)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
+
+    CFReleaseNull(digest);
+}
+
 /*
    policy->_options is a caller provided dictionary, only its cf type has
    been checked.
@@ -1984,14 +2050,14 @@ static void SecPolicyCheckKeySize(SecPVCRef pvc, CFStringRef key) {
     SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
 
     /* Don't check key size for user-anchored leafs */
-#if TARGET_OS_IPHONE
-    SecCertificateSourceRef userSource = kSecUserAnchorSource;
-#else
-    SecCertificateSourceRef userSource = kSecLegacyAnchorSource;
-#endif
-    if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) {
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, leaf)) {
+        return;
+    }
+#if TARGET_OS_OSX
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, leaf)) {
         return;
     }
+#endif
 
     for (ix = 0; ix < count; ++ix) {
         SecCertificateRef cert = SecPVCGetCertificateAtIndex(pvc, ix);
@@ -2020,10 +2086,10 @@ static void SecPolicyCheckSignatureHashAlgorithms(SecPVCRef pvc,
     CFIndex ix = 0, count = SecPVCGetCertificateCount(pvc);
 
     /* Ignore (a non-self-signed) anchor if it's trusted by the user */
-#if TARGET_OS_IPHONE
     bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1));
-#else
-    bool userAnchored = SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, SecPVCGetCertificateAtIndex(pvc, count - 1));
+#if TARGET_OS_OSX
+    userAnchored = userAnchored || SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource,
+                                                                SecPVCGetCertificateAtIndex(pvc, count - 1));
 #endif
     if (SecPathBuilderIsAnchored(pvc->builder) && userAnchored) {
         count--;
@@ -2178,7 +2244,7 @@ static bool is_configured_test_system_root(SecCertificateRef root, CFStringRef p
     CFDataRef rootHash = SecCertificateCopySHA256Digest(root);
     CFTypeRef value = CFPreferencesCopyAppValue(preference, CFSTR("com.apple.security"));
     require_quiet(isData(value), out);
-    require_quiet(kCFCompareEqualTo == CFDataCompare(rootHash, value), out);
+    require_quiet(CFEqual(rootHash, value), out);
     result = true;
 
 out:
@@ -2408,6 +2474,7 @@ out:
 static bool SecPolicyCheckSystemTrustValidityPeriodMaximums(CFAbsoluteTime notBefore, CFAbsoluteTime notAfter) {
     CFAbsoluteTime jul2016 = 489024000.0; // 1 July 2016 00:00:00 UTC
     CFAbsoluteTime mar2018 = 541555200.0; // 1 March 2018 00:00:00 UTC
+    CFAbsoluteTime sep2020 = 620611200.0; // 1 September 2020 00:00:00 UTC
     if (notBefore < jul2016) {
         /* Validity Period no greater than 60 months.
          60 months is no more than 5 years and 2 leap days (and 1 hour slip). */
@@ -2425,13 +2492,20 @@ static bool SecPolicyCheckSystemTrustValidityPeriodMaximums(CFAbsoluteTime notBe
             secnotice("policy", "System-trusted leaf validity period longer than 39 months and issued after 30 June 2016");
             return false;
         }
-    } else {
+    } else if (notBefore < sep2020) {
         /* Validity Period no greater than 825 days (and 1 hour slip). */
         CFAbsoluteTime maxPeriod = 60*60*24*825 + 3600;
         if (notAfter - notBefore > maxPeriod) {
             secnotice("policy", "System-trusted leaf validity period longer than 825 days and issued on or after 1 March 2018");
             return false;
         }
+    } else {
+        /* Validity Period no greater than 398 days (and no slip). HT211025 */
+        CFAbsoluteTime maxPeriod = 60*60*24*398;
+        if (notAfter - notBefore > maxPeriod) {
+            secnotice("policy", "System-trusted leaf validity period longer than 398 days and issued on or after 1 September 2020");
+            return false;
+        }
     }
     return true;
 }
@@ -2471,14 +2545,14 @@ static void SecPolicyCheckValidityPeriodMaximums(SecPVCRef pvc, CFStringRef key)
     }
 
     /* Don't check validity periods against maximums for user-anchored leafs */
-#if TARGET_OS_IPHONE
-    SecCertificateSourceRef userSource = kSecUserAnchorSource;
-#else
-    SecCertificateSourceRef userSource = kSecLegacyAnchorSource;
-#endif
-    if (SecPVCIsAnchorPerConstraints(pvc, userSource, leaf)) {
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, leaf)) {
         return;
     }
+#if TARGET_OS_OSX
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, leaf)) {
+        return;
+    }
+#endif
 
     /* all other trust */
     if (!SecPolicyCheckOtherTrustValidityPeriodMaximums(notBefore, notAfter)) {
@@ -2498,18 +2572,33 @@ static void SecPolicyCheckServerAuthEKU(SecPVCRef pvc, CFStringRef key) {
         if (!SecPolicyCheckCertExtendedKeyUsage(leaf, CFSTR("1.3.6.1.5.5.7.3.1"))) { // server auth EKU
             SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
         }
+        /* if any subCA cert has an EKU, it must have the server auth EKU */
+        if (count > 2) { // chain has subCAs
+            for (int ix = 1; ix < count - 1; ix++) { // iterate through subCAs
+                SecCertificateRef subCA = SecPVCGetCertificateAtIndex(pvc, ix);
+                CFArrayRef eku = NULL;
+                if ((eku = SecCertificateCopyExtendedKeyUsage(subCA)) && CFArrayGetCount(eku)) { // subCA has EKU set
+                    if (!SecPolicyCheckCertExtendedKeyUsage(subCA, CFSTR("1.3.6.1.5.5.7.3.1")) && // check server auth EKU
+                        !SecPolicyCheckCertExtendedKeyUsage(subCA, CFSTR("2.5.29.37.0"))) { // check anyEKU
+                        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+                    }
+                }
+                CFReleaseNull(eku);
+            }
+        }
         return;
     }
 
     /* skip user/admin-anchored chains */
-#if TARGET_OS_IPHONE
-    SecCertificateSourceRef userSource = kSecUserAnchorSource;
-#else
-    SecCertificateSourceRef userSource = kSecLegacyAnchorSource;
-#endif
-    if (SecPVCIsAnchorPerConstraints(pvc, userSource, root)) {
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecUserAnchorSource, root)) {
         return;
     }
+#if TARGET_OS_OSX
+    if (SecPVCIsAnchorPerConstraints(pvc, kSecLegacyAnchorSource, root)) {
+        return;
+    }
+#endif
+
 
     /* All other anchor types must be compliant if issued on or after 1 July 2019 */
     CFAbsoluteTime notBefore = SecCertificateNotValidBefore(leaf);
@@ -2521,6 +2610,18 @@ static void SecPolicyCheckServerAuthEKU(SecPVCRef pvc, CFStringRef key) {
     }
 }
 
+static void SecPolicyCheckCTRequired(SecPVCRef pvc, CFStringRef key) {
+    SecCertificatePathVCRef path = SecPathBuilderGetPath(pvc->builder);
+    SecCertificatePathVCSetRequiresCT(path, kSecPathCTRequiredOverridable);
+}
+
+static void SecPolicyCheckNotCA(SecPVCRef pvc, CFStringRef key) {
+    SecCertificateRef leaf = SecPVCGetCertificateAtIndex(pvc, 0);
+    if (SecCertificateIsCA(leaf)) {
+        SecPVCSetResult(pvc, key, 0, kCFBooleanFalse);
+    }
+}
+
 void SecPolicyServerInitialize(void) {
        gSecPolicyLeafCallbacks = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
                &kCFTypeDictionaryKeyCallBacks, NULL);
@@ -2635,6 +2736,9 @@ static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CF
      */
 #if TARGET_OS_OSX
     CFDictionaryRef options = CFArrayGetValueAtIndex(exceptions, 0);
+    if (!isDictionary(options)) {
+        return false;
+    }
     /* Type 2 */
     if (exceptionsCount == 1 && (ix > 0 || !CFDictionaryContainsKey(options, kSecCertificateDetailSHA1Digest))) {
         /* SHA1Digest not allowed */
@@ -2665,6 +2769,9 @@ static bool SecPVCIsExceptedError(SecPVCRef pvc, CFIndex ix, CFStringRef key, CF
     /* Type 1 */
     if (ix >= exceptionsCount) { return false; }
     CFDictionaryRef exception = CFArrayGetValueAtIndex(exceptions, ix);
+    if (!isDictionary(exception)) {
+        return false;
+    }
 
     /* Compare the cert hash */
     if (!CFDictionaryContainsKey(exception, kSecCertificateDetailSHA1Digest)) { return false; }
@@ -3296,7 +3403,7 @@ static bool SecPVCCallerIsApplication(CFDataRef clientAuditToken, CFTypeRef appR
     SecRequirementRef requirement = NULL;
     CFStringRef stringRequirement = NULL;
 
-    require(appRef && clientAuditToken, out);
+    require_quiet(appRef && clientAuditToken, out);
     require(CFGetTypeID(appRef) == SecTrustedApplicationGetTypeID(), out);
     require_noerr(SecTrustedApplicationCopyRequirement((SecTrustedApplicationRef)appRef, &requirement), out);
     require(requirement, out);
@@ -3484,16 +3591,16 @@ static void SecPVCCheckUsageConstraints(SecPVCRef pvc) {
             /* If we already think the PVC is ok and this cert is from one of the user/
              * admin anchor sources, trustRoot, trustAsRoot, and Invalid (no constraints),
              * all mean we should use the special "Proceed" trust result. */
-#if TARGET_OS_IPHONE
             if (SecPathBuilderIsAnchorSource(pvc->builder, kSecUserAnchorSource) &&
-                SecCertificateSourceContains(kSecUserAnchorSource, cert))
-#else
+                SecCertificateSourceContains(kSecUserAnchorSource, cert)) {
+                pvc->result = kSecTrustResultProceed;
+            }
+#if TARGET_OS_OSX
             if (SecPathBuilderIsAnchorSource(pvc->builder, kSecLegacyAnchorSource) &&
-                SecCertificateSourceContains(kSecLegacyAnchorSource, cert))
-#endif
-            {
+                SecCertificateSourceContains(kSecLegacyAnchorSource, cert)) {
                 pvc->result = kSecTrustResultProceed;
             }
+#endif
         }
     }
 }
@@ -3574,7 +3681,10 @@ static void SecPVCCheckIssuerDateConstraints(SecPVCRef pvc) {
     }
 }
 
-static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) {
+static bool SecPVCPolicyPermitsCTRequired(SecPVCRef pvc) {
+#if TARGET_OS_BRIDGE
+    return false;
+#else // !TARGET_OS_BRIDGE
     if (!pvc || !pvc->policies) {
         return false;
     }
@@ -3582,15 +3692,22 @@ static bool SecPVCIsSSLServerAuthenticationPolicy(SecPVCRef pvc) {
     if (!policy) {
         return false;
     }
+    // SSL policy
     CFStringRef policyName = SecPolicyGetName(policy);
     if (CFEqualSafe(policyName, kSecPolicyNameSSLServer)) {
         return true;
     }
+    // SSL policy by another name
     CFDictionaryRef options = policy->_options;
     if (options && CFDictionaryGetValue(options, kSecPolicyCheckSSLHostname)) {
         return true;
     }
+    // Policy explicitly requires CT
+    if (options && CFDictionaryGetValue(options, kSecPolicyCheckCTRequired)) {
+        return true;
+    }
     return false;
+#endif // !TARGET_OS_BRIDGE
 }
 
 /* ASSUMPTIONS:
@@ -3609,7 +3726,7 @@ static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
        Note that CT will already be required if there is a not-after date
        constraint present (set in SecRVCProcessValidDateConstraints).
     */
-    if (SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
+    if (SecPVCPolicyPermitsCTRequired(pvc)) {
         CFIndex ix, certCount = SecCertificatePathVCGetCount(path);
         SecCertificateRef certificate = SecPathBuilderGetCertificateAtIndex(pvc->builder, 0);
         CFAbsoluteTime earliestNotAfter = 31556908800.0;  /* default: 3001-01-01 00:00:00-0000 */
@@ -3644,15 +3761,16 @@ static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
 
     /* Path is not CT validated, so check if CT was required. */
     SecPathCTPolicy ctp = SecCertificatePathVCRequiresCT(path);
-    if (ctp <= kSecPathCTNotRequired || !SecPVCIsSSLServerAuthenticationPolicy(pvc)) {
+    if (ctp <= kSecPathCTNotRequired || !SecPVCPolicyPermitsCTRequired(pvc)) {
         return;
     }
 
     /* We need to have a recent log list or the CT check may have failed due to the list being out of date.
      * Also, honor the CT kill switch. */
     SecOTAPKIRef otaref = SecOTAPKICopyCurrentOTAPKIRef();
+    CFDictionaryRef trustedLogs = SecPathBuilderCopyTrustedLogs(pvc->builder);
     if (!SecOTAPKIKillSwitchEnabled(otaref, kOTAPKIKillSwitchCT) &&
-        SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable)) {
+        (SecOTAPKIAssetStalenessLessThanSeconds(otaref, kSecOTAPKIAssetStalenessDisable) || trustedLogs)) {
         /* CT was required. Error is always set on leaf certificate. */
         if (ctp != kSecPathCTRequiredOverridable) {
             /* Normally kSecPolicyCheckCTRequired is recoverable */
@@ -3663,6 +3781,7 @@ static void SecPVCCheckRequireCTConstraints(SecPVCRef pvc) {
         }
     }
     CFReleaseNull(otaref);
+    CFReleaseNull(trustedLogs);
 }
 
 /* "Deep" copy the details array */
index 5672e48f96e8b47517fbe76aeb2fd40483db5f41..4fdb34b95698e0d68515a60ea40bfc05490cb623 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2016-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -203,6 +203,14 @@ static double htond(double h) {
     return n;
 }
 
+/* Obtain swapped value of the 32-bit integer referenced by the given pointer.
+   Since a generic void or char pointer may not be aligned on a 4-byte boundary,
+   the UB sanitizer does not let us directly dereference it as *(uint32_t*).
+*/
+static uint32_t SecSwapInt32Ptr(const void* P) {
+    uint32_t _i=0; memcpy(&_i,P,sizeof(_i)); return OSSwapInt32(_i);
+}
+
 
 // MARK: -
 // MARK: Valid definitions
@@ -250,7 +258,7 @@ typedef CF_OPTIONS(CFOptionFlags, SecValidInfoFlags) {
 /* maximum allowed interval */
 #define kSecMaxUpdateInterval           (60.0 * 60 * 24 * 7)
 
-#define kSecRevocationBasePath          "/Library/Keychains/crls"
+/* filenames we use, relative to revocation info directory */
 #define kSecRevocationCurUpdateFile     "update-current"
 #define kSecRevocationDbFileName        "valid.sqlite3"
 #define kSecRevocationDbReplaceFile     ".valid_replace"
@@ -319,7 +327,7 @@ bool SecRevocationDbUpdateSchema(SecRevocationDbRef rdb);
 CFIndex SecRevocationDbGetUpdateFormat(void);
 bool _SecRevocationDbSetUpdateSource(SecRevocationDbConnectionRef dbc, CFStringRef source, CFErrorRef *error);
 bool SecRevocationDbSetUpdateSource(SecRevocationDbRef rdb, CFStringRef source);
-CFStringRef SecRevocationDbCopyUpdateSource(void);
+CF_RETURNS_RETAINED CFStringRef SecRevocationDbCopyUpdateSource(void);
 bool SecRevocationDbSetNextUpdateTime(CFAbsoluteTime nextUpdate, CFErrorRef *error);
 CFAbsoluteTime SecRevocationDbGetNextUpdateTime(void);
 dispatch_queue_t SecRevocationDbGetUpdateQueue(void);
@@ -623,8 +631,7 @@ static bool SecValidUpdateProcessData(SecRevocationDbConnectionRef dbc, CFIndex
         SecError(errSecParam, error, CFSTR("SecValidUpdateProcessData: data length is too short"));
         return result;
     }
-    /* get length of signed data */
-    uint32_t dataLength = OSSwapInt32(*((uint32_t *)p));
+    uint32_t dataLength = SecSwapInt32Ptr(p);
     bytesRemaining -= sizeof(uint32_t);
     p += sizeof(uint32_t);
 
@@ -632,7 +639,7 @@ static bool SecValidUpdateProcessData(SecRevocationDbConnectionRef dbc, CFIndex
     uint32_t plistCount = 1;
     uint32_t plistTotal = 1;
     if (format > kSecValidUpdateFormatG2) {
-        plistCount = OSSwapInt32(*((uint32_t *)p));
+        plistCount = SecSwapInt32Ptr(p);
         plistTotal = plistCount;
         bytesRemaining -= sizeof(uint32_t);
         p += sizeof(uint32_t);
@@ -652,7 +659,7 @@ static bool SecValidUpdateProcessData(SecRevocationDbConnectionRef dbc, CFIndex
         CFPropertyListRef propertyList = NULL;
         uint32_t plistLength = dataLength;
         if (format > kSecValidUpdateFormatG2) {
-            plistLength = OSSwapInt32(*((uint32_t *)p));
+            plistLength = SecSwapInt32Ptr(p);
             bytesRemaining -= sizeof(uint32_t);
             p += sizeof(uint32_t);
         }
@@ -942,9 +949,15 @@ static CF_RETURNS_RETAINED CFStringRef SecRevocationDbCopyServer(void) {
     /* Prefer a in-process setting for the update server, as used in testing */
     CFTypeRef value = CFPreferencesCopyAppValue(kUpdateServerKey, kSecPrefsDomain);
     if (!value) {
-        value = (CFStringRef)CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+        value = CFPreferencesCopyValue(kUpdateServerKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+    }
+    CFStringRef server = NULL;
+    if (isString(value)) {
+        server = (CFStringRef)value;
+    } else {
+        CFReleaseNull(value);
+        server = CFRetainSafe(SecRevocationDbGetDefaultServer());
     }
-    CFStringRef server = (isString(value)) ? (CFStringRef)value : CFRetainSafe(SecRevocationDbGetDefaultServer());
     return server;
 }
 
@@ -1125,6 +1138,56 @@ static CFStringRef SecValidInfoCopyFormatDescription(CFTypeRef cf, CFDictionaryR
  ==============================================================================
 */
 
+static CFIndex _SecRevocationDbGetUpdateVersion(CFStringRef server) {
+    // determine version of our current database
+    CFIndex version = SecRevocationDbGetVersion();
+    secdebug("validupdate", "got version %ld from db", (long)version);
+    if (version <= 0) {
+        if (gLastVersion > 0) {
+            secdebug("validupdate", "error getting version; using last good version: %ld", (long)gLastVersion);
+        }
+        version = gLastVersion;
+    }
+
+    // determine source of our current database
+    // (if this ever changes, we will need to reload the db)
+    CFStringRef db_source = SecRevocationDbCopyUpdateSource();
+    if (!db_source) {
+        db_source = (CFStringRef) CFRetain(kValidUpdateProdServer);
+    }
+
+    // determine whether we need to recreate the database
+    CFIndex db_version = SecRevocationDbGetSchemaVersion();
+    CFIndex db_format = SecRevocationDbGetUpdateFormat();
+    if (db_version < kSecRevocationDbSchemaVersion ||
+        db_format < kSecRevocationDbUpdateFormat ||
+        kCFCompareEqualTo != CFStringCompare(server, db_source, kCFCompareCaseInsensitive)) {
+        // we need to fully rebuild the db contents, so we set our version to 0.
+        version = gLastVersion = 0;
+    }
+    CFReleaseNull(db_source);
+    return version;
+}
+
+static bool _SecRevocationDbIsUpdateEnabled(void) {
+    CFTypeRef value = NULL;
+    // determine whether update fetching is enabled
+#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE
+    // Valid update fetching was initially enabled on macOS 10.13 and iOS 11.0.
+    // This conditional has been changed to include every platform and version
+    // except for those where the db should not be updated over the air.
+    bool updateEnabled = true;
+#else
+    bool updateEnabled = false;
+#endif
+    value = (CFBooleanRef)CFPreferencesCopyValue(kUpdateEnabledKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+    if (isBoolean(value)) {
+        updateEnabled = CFBooleanGetValue((CFBooleanRef)value);
+    }
+    CFReleaseNull(value);
+    return updateEnabled;
+}
+
 /* SecRevocationDbCheckNextUpdate returns true if we dispatched an
    update request, otherwise false.
 */
@@ -1183,52 +1246,15 @@ static bool _SecRevocationDbCheckNextUpdate(void) {
     // determine which server to query
     CFStringRef server = SecRevocationDbCopyServer();
 
-    // determine version of our current database
-    CFIndex version = SecRevocationDbGetVersion();
-    secdebug("validupdate", "got version %ld from db", (long)version);
-    if (version <= 0) {
-        if (gLastVersion > 0) {
-            secdebug("validupdate", "error getting version; using last good version: %ld", (long)gLastVersion);
-        }
-        version = gLastVersion;
-    }
+    // determine version to update from
+    CFIndex version = _SecRevocationDbGetUpdateVersion(server);
 
-    // determine source of our current database
-    // (if this ever changes, we will need to reload the db)
-    CFStringRef db_source = SecRevocationDbCopyUpdateSource();
-    if (!db_source) {
-        db_source = (CFStringRef) CFRetain(kValidUpdateProdServer);
-    }
-
-    // determine whether we need to recreate the database
-    CFIndex db_version = SecRevocationDbGetSchemaVersion();
-    CFIndex db_format = SecRevocationDbGetUpdateFormat();
-    if (db_version < kSecRevocationDbSchemaVersion ||
-        db_format < kSecRevocationDbUpdateFormat ||
-        kCFCompareEqualTo != CFStringCompare(server, db_source, kCFCompareCaseInsensitive)) {
-        // we need to fully rebuild the db contents, so we set our version to 0.
-        version = gLastVersion = 0;
-    }
-
-    // determine whether update fetching is enabled
-#if !TARGET_OS_WATCH && !TARGET_OS_BRIDGE
-    // Valid update fetching was initially enabled on macOS 10.13 and iOS 11.0.
-    // This conditional has been changed to include every platform and version
-    // except for those where the db should not be updated over the air.
-    bool updateEnabled = true;
-#else
-    bool updateEnabled = false;
-#endif
-    value = (CFBooleanRef)CFPreferencesCopyValue(kUpdateEnabledKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-    if (isBoolean(value)) {
-        updateEnabled = CFBooleanGetValue((CFBooleanRef)value);
-    }
-    CFReleaseNull(value);
+    // determine if update is enabled for this device
+    bool updateEnabled = _SecRevocationDbIsUpdateEnabled();
 
     // Schedule maintenance work
     bool result = SecValidUpdateSchedule(updateEnabled, server, version);
     CFReleaseNull(server);
-    CFReleaseNull(db_source);
     return result;
 }
 
@@ -1248,6 +1274,26 @@ void SecRevocationDbCheckNextUpdate(void) {
     sec_action_perform(action);
 }
 
+bool SecRevocationDbUpdate(CFErrorRef *error)
+{
+    // are we the db owner instance?
+    if (!isDbOwner()) {
+        return SecError(errSecWrPerm, error, CFSTR("Unable to update Valid DB from user agent"));
+    }
+
+    if (!_SecRevocationDbIsUpdateEnabled()) {
+        return SecError(errSecWrPerm, error, CFSTR("Valid updates not enabled on this device"));
+    }
+
+    CFStringRef server = SecRevocationDbCopyServer();
+    CFIndex version = _SecRevocationDbGetUpdateVersion(server);
+
+    secdebug("validupdate", "will fetch v%lu from \"%@\" now", (unsigned long)version, server);
+    bool result = SecValidUpdateUpdateNow(SecRevocationDbGetUpdateQueue(), server, version);
+    CFReleaseNull(server);
+    return result;
+}
+
 /*  This function verifies an update, in this format:
     1) unsigned 32-bit network-byte-order length of binary plist
     2) binary plist data
@@ -1260,7 +1306,7 @@ bool SecRevocationDbVerifyUpdate(void *update, CFIndex length) {
     if (!update || length <= (CFIndex)sizeof(uint32_t)) {
         return false;
     }
-    uint32_t plistLength = OSSwapInt32(*((uint32_t *)update));
+    uint32_t plistLength = SecSwapInt32Ptr(update);
     if ((plistLength + (CFIndex)(sizeof(uint32_t)*2)) > (uint64_t) length) {
         secdebug("validupdate", "ERROR: reported plist length (%lu)+%lu exceeds total length (%lu)\n",
                 (unsigned long)plistLength, (unsigned long)sizeof(uint32_t)*2, (unsigned long)length);
@@ -1268,7 +1314,7 @@ bool SecRevocationDbVerifyUpdate(void *update, CFIndex length) {
     }
     uint8_t *plistData = (uint8_t *)update + sizeof(uint32_t);
     uint8_t *sigData = (uint8_t *)plistData + plistLength;
-    uint32_t sigLength = OSSwapInt32(*((uint32_t *)sigData));
+    uint32_t sigLength = SecSwapInt32Ptr(sigData);
     sigData += sizeof(uint32_t);
     if ((plistLength + sigLength + (CFIndex)(sizeof(uint32_t) * 2)) != (uint64_t) length) {
         secdebug("validupdate", "ERROR: reported lengths do not add up to total length\n");
@@ -2389,10 +2435,10 @@ static bool _SecRevocationDbUpdateIssuers(SecRevocationDbConnectionRef dbc, int6
 }
 
 static SecValidInfoFormat _SecRevocationDbGetGroupFormatForData(SecRevocationDbConnectionRef dbc, int64_t groupId, CFDataRef data) {
-    /* determine existing format if groupId is supplied and this is a partial update,
+    /* determine existing format if groupId is supplied,
        otherwise return the expected format for the given data. */
     SecValidInfoFormat format = kSecValidInfoFormatUnknown;
-    if (groupId >= 0 && !dbc->fullUpdate) {
+    if (groupId >= 0) {
         format = _SecRevocationDbGetGroupFormat(dbc, groupId, NULL, NULL, NULL, NULL);
     }
     if (format == kSecValidInfoFormatUnknown && data != NULL) {
@@ -2587,7 +2633,7 @@ static bool _SecRevocationDbUpdateDateConstraints(SecRevocationDbConnectionRef d
         return ok; /* no dates supplied, so we have nothing to update for this issuer */
     }
 
-    if (!(notBeforeDate && notAfterDate) && !dbc->fullUpdate) {
+    if (!(notBeforeDate && notAfterDate)) {
         /* only one date was supplied, so check for existing date constraints */
         CFDateRef curNotBeforeDate = NULL;
         CFDateRef curNotAfterDate = NULL;
@@ -3170,8 +3216,8 @@ static bool _SecRevocationDbApplyGroupUpdate(SecRevocationDbConnectionRef dbc, C
     __block CFErrorRef localError = NULL;
 
     CFArrayRef issuers = (dict) ? (CFArrayRef)CFDictionaryGetValue(dict, CFSTR("issuer-hash")) : NULL;
-    /* if this is not a full update, then look for existing group id */
-    if (ok && isArray(issuers) && !dbc->fullUpdate) {
+    /* look for existing group id */
+    if (ok && isArray(issuers)) {
         CFIndex issuerIX, issuerCount = CFArrayGetCount(issuers);
         /* while we have issuers and haven't found a matching group id */
         for (issuerIX=0; issuerIX<issuerCount && groupId < 0; issuerIX++) {
@@ -3515,7 +3561,7 @@ static SecValidInfoRef _SecRevocationDbCopyMatching(SecRevocationDbConnectionRef
     CFErrorRef error = NULL;
     CFDataRef issuerHash = NULL;
 
-    require(dbc && certificate && issuer, errOut);
+    require_quiet(dbc && certificate && issuer, errOut);
     require(issuerHash = SecCertificateCopySHA256Digest(issuer), errOut);
 
     /* Check for the result in the cache. */
@@ -3536,7 +3582,7 @@ errOut:
 /* Return the update source as a retained CFStringRef.
    If the value cannot be obtained, NULL is returned.
 */
-CFStringRef SecRevocationDbCopyUpdateSource(void) {
+CF_RETURNS_RETAINED CFStringRef SecRevocationDbCopyUpdateSource(void) {
     __block CFStringRef result = NULL;
     SecRevocationDbWith(^(SecRevocationDbRef db) {
         (void) SecRevocationDbPerformRead(db, NULL, ^bool(SecRevocationDbConnectionRef dbc, CFErrorRef *blockError) {
index 8559cfb5869054c2306cc7d0c9fb44d98bfd6173..52a2a83fd6000fb536ec75adbe59490ebf48f211 100644 (file)
@@ -36,6 +36,7 @@
 #include <CoreFoundation/CFDate.h>
 #include <CoreFoundation/CFDictionary.h>
 #include <CoreFoundation/CFString.h>
+#include <CoreFoundation/CFError.h>
 #include <dispatch/dispatch.h>
 #include <Security/SecBase.h>
 
@@ -105,6 +106,12 @@ void SecValidInfoSetAnchor(SecValidInfoRef validInfo, SecCertificateRef anchor);
  */
 void SecRevocationDbCheckNextUpdate(void);
 
+/*!
+    @function SecRevocationDbUpdate
+    @abstract Trigger update now. For use in testing and tools.
+ */
+bool SecRevocationDbUpdate(CFErrorRef *error);
+
 /*!
        @function SecRevocationDbCopyMatching
        @abstract Returns a SecValidInfo reference if matching revocation (or allow list) info was found.
@@ -177,7 +184,7 @@ extern const CFStringRef kValidUpdateCarryServer;
  @abstract Returns the server source for updates of the revocation database.
  @result The base string of the server URI.
  */
-CFStringRef SecRevocationDbCopyUpdateSource(void);
+CF_RETURNS_RETAINED CFStringRef SecRevocationDbCopyUpdateSource(void);
 
 
 __END_DECLS
index e642f19375df5cf891c65bcb11121d88e31d3f12..e87f9eb978abdceededb98bda5454b017de157f1 100644 (file)
@@ -29,6 +29,7 @@
 #import "trust/trustd/SecRevocationServer.h"
 
 bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version);
+bool SecValidUpdateUpdateNow(dispatch_queue_t queue, CFStringRef server, CFIndex version);
 bool SecORVCBeginFetches(SecORVCRef orvc, SecCertificateRef cert);
 
 #endif /* _SECURITY_SECREVOCATIONNETWORKING_H_ */
index c1852066b79fec196e93d14bdedfe395bfbcc0ad..acbcd1181148af5fb621b293a1c10241727bfcc0 100644 (file)
@@ -197,9 +197,8 @@ didReceiveResponse:(NSURLResponse *)response
     (void)remove(updateFilePath);
 
     int fd;
-    off_t off;
     fd = open(updateFilePath, O_RDWR | O_CREAT | O_TRUNC, 0644);
-    if (fd < 0  || (off = lseek(fd, 0, SEEK_SET)) < 0) {
+    if (fd < 0) {
         secnotice("validupdate","unable to open %@ (errno %d)", self->_currentUpdateFileURL, errno);
     }
     if (fd >= 0) {
@@ -218,7 +217,7 @@ didReceiveResponse:(NSURLResponse *)response
     if (!self->_currentUpdateFile) {
         secnotice("validupdate", "failed to open %@: %@. canceling task %@", self->_currentUpdateFileURL, error, dataTask);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error];
+        [[TrustAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error];
 #endif // ENABLE_TRUSTD_ANALYTICS
         completionHandler(NSURLSessionResponseCancel);
         [self reschedule];
@@ -259,7 +258,7 @@ didCompleteWithError:(NSError *)error {
     if (error) {
         secnotice("validupdate", "Session %@ task %@ failed with error %@", session, task, error);
 #if ENABLE_TRUSTD_ANALYTICS
-        [[TrustdHealthAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error];
+        [[TrustAnalytics logger] logResultForEvent:TrustdHealthAnalyticsEventValidUpdate hardFailure:NO result:error];
 #endif // ENABLE_TRUSTD_ANALYTICS
         [self reschedule];
         /* close file before we leave */
@@ -288,30 +287,25 @@ didCompleteWithError:(NSError *)error {
 @interface ValidUpdateRequest : NSObject
 @property NSTimeInterval updateScheduled;
 @property NSURLSession *backgroundSession;
+@property NSURLSession *ephemeralSession;
 @end
 
 static ValidUpdateRequest *request = nil;
 
 @implementation ValidUpdateRequest
 
-- (NSURLSessionConfiguration *)validUpdateConfiguration {
-    /* preferences to override defaults */
-    CFTypeRef value = NULL;
-    bool updateOnWiFiOnly = true;
-    value = CFPreferencesCopyValue(kUpdateWiFiOnlyKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-    if (isBoolean(value)) {
-        updateOnWiFiOnly = CFBooleanGetValue((CFBooleanRef)value);
-    }
-    CFReleaseNull(value);
-    bool updateInBackground = true;
-    value = CFPreferencesCopyValue(kUpdateBackgroundKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
-    if (isBoolean(value)) {
-        updateInBackground = CFBooleanGetValue((CFBooleanRef)value);
-    }
-    CFReleaseNull(value);
-
+- (NSURLSessionConfiguration *)validUpdateConfiguration:(BOOL)background {
     NSURLSessionConfiguration *config = nil;
-    if (updateInBackground) {
+    if (background) {
+        /* preferences to override defaults */
+        CFTypeRef value = NULL;
+        bool updateOnWiFiOnly = true;
+        value = CFPreferencesCopyValue(kUpdateWiFiOnlyKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+        if (isBoolean(value)) {
+            updateOnWiFiOnly = CFBooleanGetValue((CFBooleanRef)value);
+        }
+        CFReleaseNull(value);
+
         config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier: @"com.apple.trustd.networking.background"];
         config.networkServiceType = NSURLNetworkServiceTypeBackground;
         config.discretionary = YES;
@@ -332,8 +326,9 @@ static ValidUpdateRequest *request = nil;
     return config;
 }
 
-- (void) createSession:(dispatch_queue_t)updateQueue forServer:(NSString *)updateServer {
-    NSURLSessionConfiguration *config = [self validUpdateConfiguration];
+- (NSURLSession *)createSession:(BOOL)background queue:(dispatch_queue_t)updateQueue forServer:(NSString *)updateServer
+{
+    NSURLSessionConfiguration *config = [self validUpdateConfiguration:background];
     ValidDelegate *delegate = [[ValidDelegate alloc] init];
     delegate.handler = ^(void) {
         request.updateScheduled = 0.0;
@@ -348,7 +343,23 @@ static ValidUpdateRequest *request = nil;
        We'll then dispatch the work on updateQueue and return from the callback. */
     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     queue.maxConcurrentOperationCount = 1;
-    _backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue];
+    return [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue];
+}
+
+- (void) createSessions:(dispatch_queue_t)updateQueue forServer:(NSString *)updateServer {
+    self.ephemeralSession = [self createSession:NO queue:updateQueue forServer:updateServer];
+
+    bool updateInBackground = true;
+    CFTypeRef value = CFPreferencesCopyValue(kUpdateBackgroundKey, kSecPrefsDomain, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
+    if (isBoolean(value)) {
+        updateInBackground = CFBooleanGetValue((CFBooleanRef)value);
+    }
+    CFReleaseNull(value);
+    if (updateInBackground) {
+        self.backgroundSession = [self createSession:YES queue:updateQueue forServer:updateServer];
+    } else {
+        self.backgroundSession = self.ephemeralSession;
+    }
 }
 
 - (BOOL) scheduleUpdateFromServer:(NSString *)server forVersion:(NSUInteger)version withQueue:(dispatch_queue_t)updateQueue {
@@ -399,7 +410,7 @@ static ValidUpdateRequest *request = nil;
         });
 
         if (!self.backgroundSession) {
-            [self createSession:updateQueue forServer:server];
+            [self createSessions:updateQueue forServer:server];
         } else {
             ValidDelegate *delegate = (ValidDelegate *)[self.backgroundSession delegate];
             delegate.currentUpdateServer = [server copy];
@@ -424,20 +435,68 @@ static ValidUpdateRequest *request = nil;
 
     return YES;
 }
+
+- (BOOL)updateNowFromServer:(NSString *)server version:(NSUInteger)version queue:(dispatch_queue_t)updateQueue
+{
+    if (!server) {
+        secnotice("validupdate", "invalid update request");
+        return NO;
+    }
+
+    if (!updateQueue) {
+        secnotice("validupdate", "missing update queue, skipping update");
+        return NO;
+    }
+
+    if (!self.ephemeralSession) {
+        [self createSessions:updateQueue forServer:server];
+    } else {
+        ValidDelegate *delegate = (ValidDelegate *)[self.ephemeralSession delegate];
+        delegate.currentUpdateServer = [server copy];
+    }
+
+    /* POWER LOG EVENT: scheduling our background download session now */
+    SecPLLogRegisteredEvent(@"ValidUpdateEvent", @{
+        @"timestamp" : @([[NSDate date] timeIntervalSince1970]),
+        @"event" : @"downloadScheduled",
+        @"version" : @(version)
+    });
+
+    NSURL *validUrl = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@/g3/v%ld",
+                                            server, (unsigned long)version]];
+    NSURLSessionDataTask *dataTask = [self.ephemeralSession dataTaskWithURL:validUrl];
+    dataTask.taskDescription = [NSString stringWithFormat:@"%lu",(unsigned long)version];
+    [dataTask resume];
+    secnotice("validupdate", "running foreground data task %@ at %f", dataTask, CFAbsoluteTimeGetCurrent());
+    return YES;
+}
+
 @end
 
+static void SecValidUpdateCreateValidUpdateRequest()
+{
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        @autoreleasepool {
+            request = [[ValidUpdateRequest alloc] init];
+        }
+    });
+}
+
 bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex version)  {
-        static dispatch_once_t onceToken;
-        dispatch_once(&onceToken, ^{
-            @autoreleasepool {
-                request = [[ValidUpdateRequest alloc] init];
-            }
-        });
+    SecValidUpdateCreateValidUpdateRequest();
     @autoreleasepool {
         return [request scheduleUpdateFromServer:(__bridge NSString*)server forVersion:version withQueue:queue];
     }
 }
 
+bool SecValidUpdateUpdateNow(dispatch_queue_t queue, CFStringRef server, CFIndex version) {
+    SecValidUpdateCreateValidUpdateRequest();
+    @autoreleasepool {
+        return [request updateNowFromServer:(__bridge NSString*)server version:version queue:queue];
+    }
+}
+
 /* MARK: - */
 /* MARK: OCSP Fetch Networking */
 #define OCSP_REQUEST_THRESHOLD 10
@@ -490,7 +549,7 @@ bool SecValidUpdateRequest(dispatch_queue_t queue, CFStringRef server, CFIndex v
             SecORVCConsumeOCSPResponse(orvc, ocspResponse, self.expiration, true, false);
             if (analytics && !orvc->done) {
                 /* We got an OCSP response that didn't pass validation */
-                analytics-> ocsp_validation_failed = true;
+                analytics->ocsp_validation_failed = true;
             }
         } else if (analytics) {
             /* We got something that wasn't an OCSP response (e.g. captive portal) --
index b0b5ac8699a183eb867508e481633198a3b172d1..abf32ece02d28ed20890f51fa3979e6b318278f7 100644 (file)
@@ -285,6 +285,11 @@ void SecORVCConsumeOCSPResponse(SecORVCRef rvc, SecOCSPResponseRef ocspResponse
                                         sr->certStatus == CS_Revoked ? SecOCSPResponseProducedAt(ocspResponse) : verifyTime), errOut);
 #endif
 
+    TrustAnalyticsBuilder *analytics = SecPathBuilderGetAnalyticsData(rvc->builder);
+    if (analytics && SecOCSPResponseIsWeakHash(ocspResponse)) {
+        analytics->ocsp_weak_hash = true;
+    }
+
     // If we get here, we have a properly signed ocsp response
     // but we haven't checked dates yet.
 
@@ -1017,12 +1022,16 @@ bool SecPathBuilderCheckRevocation(SecPathBuilderRef builder) {
          * This check resolves unrevocation events after the nextUpdate time. */
         bool old_cached_response = (!rvc->done && rvc->orvc->ocspResponse);
 
+        /* Check whether CA revocation additions match an issuer above us in this path.
+         * If so, we will attempt revocation checking below. */
+        bool has_ca_revocation = (certIX < SecCertificatePathVCIndexOfCAWithRevocationAdditions(path));
+
         /* If the cert is EV or if revocation checking was explicitly enabled, attempt to fire off an
          async http request for this cert's revocation status, unless we already successfully checked
          the revocation status of this cert based on the cache or stapled responses.  */
         bool allow_fetch = SecRevocationCanAccessNetwork(builder, first_check_done) &&
             (SecCertificatePathVCIsEV(path) || SecCertificatePathVCIsOptionallyEV(path) ||
-             SecPathBuilderGetRevocationMethod(builder) || old_cached_response);
+             SecPathBuilderGetRevocationMethod(builder) || old_cached_response || has_ca_revocation);
         if (rvc->done || !allow_fetch) {
             /* We got a cache hit or we aren't allowed to access the network */
             SecRVCUpdatePVC(rvc);
index 4552f3ceaffbb0d2f44ab34103b99bc03a06c1bc..401c22b87c2ad00395c93b2a81c9f9012cfaa299 100644 (file)
@@ -119,6 +119,8 @@ static bool SecWritePlistToFileInKeychainDirectory(uint64_t exceptionResetCount,
     if (localError) {
         if (error) {
             *error = localError;
+        } else {
+            CFReleaseNull(localError);
         }
         secerror("Permanent storage for the exceptions epoch is unavailable.");
         return status;
@@ -164,11 +166,14 @@ uint64_t SecTrustServerGetExceptionResetCount(CFErrorRef *error) {
      * That's expected when epoch is still 0 and there is nothing to store in permanent storage. (and later read)
      */
     if (localError && CFEqualSafe(CFErrorGetDomain(localError), kCFErrorDomainPOSIX) && CFErrorGetCode(localError) == ENXIO) {
-        CFRelease(localError);
-        localError = NULL;
+        CFReleaseNull(localError);
     }
-    if (error && localError) {
-        *error = localError;
+    if (localError) {
+        if (error) {
+            *error = localError;
+        } else {
+            CFReleaseNull(localError);
+        }
     }
     secinfo("trust", "exceptionResetCount: %llu (%s)", exceptionResetCount, error ? (*error ? "Error" : "OK") : "N/A");
     return exceptionResetCount;
index 8e1eeee02aab8a799f72ae90eb35d531e69aaed3..42d1a4d032932fab61c06a9364d479165252cdf2 100644 (file)
@@ -242,9 +242,7 @@ static void SecPathBuilderInit(SecPathBuilderRef builder, dispatch_queue_t build
          if we don't explicitly trust them. */
         CFArrayAppendValue(builder->parentSources, builder->appleAnchorSource);
         CFArrayAppendValue(builder->parentSources, kSecSystemAnchorSource);
- #if TARGET_OS_IPHONE
         CFArrayAppendValue(builder->parentSources, kSecUserAnchorSource);
- #endif
     }
     if (keychainsAllowed && builder->canAccessNetwork) {
         CFArrayAppendValue(builder->parentSources, kSecCAIssuerSource);
@@ -273,13 +271,12 @@ static void SecPathBuilderInit(SecPathBuilderRef builder, dispatch_queue_t build
          anchorSources if we are supposed to trust them. */
         CFArrayAppendValue(builder->anchorSources, builder->appleAnchorSource);
         if (keychainsAllowed) {
-#if TARGET_OS_IPHONE
-            CFArrayAppendValue(builder->anchorSources, kSecUserAnchorSource);
-#else /* TARGET_OS_OSX */
+#if TARGET_OS_OSX
             if (kSecLegacyAnchorSource->contains && kSecLegacyAnchorSource->copyParents) {
                 CFArrayAppendValue(builder->anchorSources, kSecLegacyAnchorSource);
             }
 #endif
+            CFArrayAppendValue(builder->anchorSources, kSecUserAnchorSource);
         }
         CFArrayAppendValue(builder->anchorSources, kSecSystemAnchorSource);
     }
@@ -466,6 +463,9 @@ CFSetRef SecPathBuilderGetAllPaths(SecPathBuilderRef builder)
 
 TrustAnalyticsBuilder *SecPathBuilderGetAnalyticsData(SecPathBuilderRef builder)
 {
+    if (!builder) {
+        return NULL;
+    }
     return builder->analyticsData;
 }
 
@@ -1364,6 +1364,20 @@ SecTrustServerEvaluateBlock(dispatch_queue_t builderQueue, CFDataRef clientAudit
     SecPathBuilderStep(builder);
 }
 
+static CFDataRef SecTrustServerCopySelfAuditToken(void)
+{
+    audit_token_t token;
+    kern_return_t kr;
+    mach_msg_type_number_t token_size = TASK_AUDIT_TOKEN_COUNT;
+    kr = task_info(mach_task_self(), TASK_AUDIT_TOKEN, (task_info_t)&token, &token_size);
+    if (kr != KERN_SUCCESS) {
+        secwarning("failed to get audit token for ourselves");
+        return NULL;
+    }
+
+    return CFDataCreate(NULL, (uint8_t *)&token, sizeof(token));
+}
+
 
 // NO_SERVER Shim code only, xpc interface should call SecTrustServerEvaluateBlock() directly
 SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef anchors, bool anchorsOnly, bool keychainsAllowed, CFArrayRef policies, CFArrayRef responses, CFArrayRef SCTs, CFArrayRef trustedLogs, CFAbsoluteTime verifyTime, __unused CFArrayRef accessGroups, CFArrayRef exceptions, CFArrayRef *pdetails, CFDictionaryRef *pinfo, CFArrayRef *pchain, CFErrorRef *perror) {
@@ -1371,13 +1385,16 @@ SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef an
     __block SecTrustResultType result = kSecTrustResultInvalid;
     __block dispatch_queue_t queue = dispatch_queue_create("com.apple.trustd.evaluation.recursive", DISPATCH_QUEUE_SERIAL);
 
+    /* make an audit token for ourselves */
+    CFDataRef audit_token = SecTrustServerCopySelfAuditToken();
+
     /* We need to use the async call with the semaphore here instead of a synchronous call because we may return from
      * SecPathBuilderStep while waiting for an asynchronous network call in order to complete the evaluation. That return
      * is necessary in the XPC interface in order to free up the workloop for other trust evaluations while we wait for
      * the networking to complete, but here, we need to make sure we wait for the network call (which will async back
      * onto our queue) to complete and signal us before we return to the "inline" caller. */
     dispatch_async(queue, ^{
-        SecTrustServerEvaluateBlock(queue, NULL, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, exceptions, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error) {
+        SecTrustServerEvaluateBlock(queue, audit_token, certificates, anchors, anchorsOnly, keychainsAllowed, policies, responses, SCTs, trustedLogs, verifyTime, accessGroups, exceptions, ^(SecTrustResultType tr, CFArrayRef details, CFDictionaryRef info, CFArrayRef chain, CFErrorRef error) {
             result = tr;
             if (tr == kSecTrustResultInvalid) {
                 if (perror) {
@@ -1404,6 +1421,7 @@ SecTrustResultType SecTrustServerEvaluate(CFArrayRef certificates, CFArrayRef an
     dispatch_semaphore_wait(done, DISPATCH_TIME_FOREVER);
     dispatch_release(done);
     dispatch_release_null(queue);
+    CFReleaseNull(audit_token);
 
     return result;
 }
index 898e71f30d1e4aaf81635de03e5d52ba7cd02115..50233ad5d25503236bf95f30736a99019c945f5b 100644 (file)
@@ -180,6 +180,7 @@ typedef CF_OPTIONS(uint8_t, TAValidStatus) {
 typedef struct {
     uint64_t start_time;
     bool suspected_mitm;
+    bool ca_fail_eku_check;
     // Certificate Transparency
     TA_SCTSource sct_sources;
     uint32_t number_scts;
@@ -202,6 +203,7 @@ typedef struct {
     uint64_t ocsp_fetch_time;
     uint32_t ocsp_fetch_failed;
     bool ocsp_validation_failed;
+    bool ocsp_weak_hash;
     // Valid
     TAValidStatus valid_status;
     bool valid_trigger_ocsp;
index 88de9d231fda3e4f6dbee02081256ebf77301515..04bc212c6806299929260103df963b9b598656ec 100644 (file)
@@ -64,6 +64,7 @@
 static dispatch_once_t kSecTrustStoreUserOnce;
 static SecTrustStoreRef kSecTrustStoreUser = NULL;
 
+#if TARGET_OS_IPHONE
 static const char copyParentsSQL[] = "SELECT data FROM tsettings WHERE subj=?";
 static const char containsSQL[] = "SELECT tset FROM tsettings WHERE sha1=?";
 static const char insertSQL[] = "INSERT OR REPLACE INTO tsettings(sha1,subj,tset,data)VALUES(?,?,?,?)";
@@ -71,6 +72,7 @@ static const char deleteSQL[] = "DELETE FROM tsettings WHERE sha1=?";
 static const char deleteAllSQL[] = "BEGIN EXCLUSIVE TRANSACTION; DELETE from tsettings; COMMIT TRANSACTION; VACUUM;";
 static const char copyAllSQL[] = "SELECT data,tset FROM tsettings ORDER BY sha1";
 static const char countAllSQL[] = "SELECT COUNT(*) FROM tsettings";
+#endif
 
 #define kSecTrustStoreName CFSTR("TrustStore")
 #define kSecTrustStoreDbExtension CFSTR("sqlite3")
@@ -92,7 +94,7 @@ struct __SecTrustStore {
 
 // MARK: -
 // MARK: Trust store functions
-
+#if TARGET_OS_IPHONE
 static int sec_create_path(const char *path)
 {
        char pathbuf[PATH_MAX];
@@ -594,3 +596,62 @@ bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents,
 errOutNotLocked:
     return ok;
 }
+
+#else // !TARGET_OS_IPHONE
+/* On macOS the trust store has nothing in it by default */
+static void SecTrustStoreInitUser(void) {
+    SecTrustStoreRef ts = (SecTrustStoreRef)malloc(sizeof(struct __SecTrustStore));
+    memset(ts, 0, sizeof(struct __SecTrustStore));
+    ts->readOnly = true;
+    kSecTrustStoreUser = ts;
+}
+
+SecTrustStoreRef SecTrustStoreForDomainName(CFStringRef domainName, CFErrorRef *error) {
+    if (CFEqual(CFSTR("user"), domainName)) {
+        dispatch_once(&kSecTrustStoreUserOnce, ^{ SecTrustStoreInitUser(); });
+        return kSecTrustStoreUser;
+    } else {
+        SecError(errSecParam, error, CFSTR("unknown domain: %@"), domainName);
+        return NULL;
+    }
+}
+
+bool _SecTrustStoreSetTrustSettings(SecTrustStoreRef ts,
+                                    SecCertificateRef certificate,
+                                    CFTypeRef trustSettingsDictOrArray, CFErrorRef *error) {
+    return SecError(errSecUnimplemented, error, CFSTR("trust store is not modifiable on this platform"));
+}
+
+bool SecTrustStoreRemoveCertificateWithDigest(SecTrustStoreRef ts, CFDataRef digest, CFErrorRef *error) {
+    return SecError(errSecUnimplemented, error, CFSTR("trust store is not modifiable on this platform"));
+}
+
+bool _SecTrustStoreRemoveAll(SecTrustStoreRef ts, CFErrorRef *error) {
+    return SecError(errSecUnimplemented, error, CFSTR("trust store is not modifiable on this platform"));
+}
+
+CFArrayRef SecTrustStoreCopyParents(SecTrustStoreRef ts,
+                                    SecCertificateRef certificate, CFErrorRef *error) {
+    CFArrayRef parents = NULL;
+    return parents;
+}
+
+bool SecTrustStoreContainsCertificateWithDigest(SecTrustStoreRef ts, CFDataRef digest, bool *contains, CFErrorRef *error) {
+    if (contains) {
+        *contains = false;
+    }
+    return true;
+}
+
+bool _SecTrustStoreCopyUsageConstraints(SecTrustStoreRef ts, CFDataRef digest, CFArrayRef *usageConstraints, CFErrorRef *error) {
+    return true;
+}
+
+bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents, CFErrorRef *error) {
+    CFMutableArrayRef CertsAndSettings = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+    if (CertsAndSettings) {
+        *trustStoreContents = CertsAndSettings;
+    }
+    return true;
+}
+#endif
index 41444de1299e7ce2165dc27c68525521ad57f6f8..64e0baf4e6943a263c1bb1596b9e32c07a7bf9e2 100644 (file)
@@ -1,15 +1,15 @@
 /*
- * Copyright (c) 2007-2009,2012-2014 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2007-2009,2012-2020 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,
@@ -17,7 +17,7 @@
  * 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@
  */
 
@@ -57,6 +57,9 @@ bool _SecTrustStoreCopyAll(SecTrustStoreRef ts, CFArrayRef *trustStoreContents,
 bool _SecTrustStoreSetCTExceptions(CFStringRef appID, CFDictionaryRef exceptions, CFErrorRef *error);
 CF_RETURNS_RETAINED CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *error);
 
+bool _SecTrustStoreSetCARevocationAdditions(CFStringRef appID, CFDictionaryRef additions, CFErrorRef *error);
+CF_RETURNS_RETAINED CFDictionaryRef _SecTrustStoreCopyCARevocationAdditions(CFStringRef appID, CFErrorRef *error);
+
 __END_DECLS
 
 #endif /* !_SECURITY_SECTRUSTSTORESERVER_H_ */
index acb0fb48b1e0ccaa5abff632ef9e8e9f9703615f..8c88c19c28e056bc412d533e01b3881181f813d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2018-2020 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -33,6 +33,9 @@
 #import "OTATrustUtilities.h"
 #include "SecTrustStoreServer.h"
 
+//
+// MARK : CT Exceptions
+//
 typedef bool(*exceptionsArrayValueChecker)(id _Nonnull obj);
 
 static bool checkDomainsValuesCompliance(id _Nonnull obj) {
@@ -184,7 +187,7 @@ CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *er
         int check = 0;
         static dispatch_once_t onceToken;
         dispatch_once(&onceToken, ^{
-            /* initialize gHashCTExceptions cache */
+            /* initialize gHasCTExceptions cache */
             NSError *read_error = nil;
             NSDictionary <NSString*,NSDictionary*> *allExceptions = readExceptionsFromDisk(&read_error);
             if (!allExceptions || [allExceptions count] == 0) {
@@ -202,7 +205,7 @@ CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *er
                     status = notify_check(notify_token, NULL);
                 }
                 if (status != NOTIFY_STATUS_OK) {
-                    secerror("failed to establish notification for CT exceptions: %ud", status);
+                    secerror("failed to establish notification for CT exceptions: %u", status);
                     notify_cancel(notify_token);
                     notify_token = 0;
                 }
@@ -266,3 +269,216 @@ CFDictionaryRef _SecTrustStoreCopyCTExceptions(CFStringRef appID, CFErrorRef *er
         return NULL;
     }
 }
+
+//
+// MARK: CA Revocation Additions
+//
+typedef bool(*additionsArrayValueChecker)(id _Nonnull obj);
+
+static bool checkCARevocationValuesCompliance(id _Nonnull obj) {
+    if (![obj isKindOfClass:[NSDictionary class]]) {
+        return false;
+    }
+    if (2 != [(NSDictionary*)obj count]) {
+        return false;
+    }
+    if (nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCARevocationHashAlgorithmKey] ||
+        nil == ((NSDictionary*)obj)[(__bridge NSString*)kSecCARevocationSPKIHashKey]) {
+        return false;
+    }
+    if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCARevocationHashAlgorithmKey] isKindOfClass:[NSString class]] ||
+        ![((NSDictionary*)obj)[(__bridge NSString*)kSecCARevocationSPKIHashKey] isKindOfClass:[NSData class]]) {
+        return false;
+    }
+    if (![((NSDictionary*)obj)[(__bridge NSString*)kSecCARevocationHashAlgorithmKey] isEqualToString:@"sha256"]) {
+        return false;
+    }
+    return true;
+}
+
+static bool checkCARevocationValues(NSString *key, id value, additionsArrayValueChecker checker, CFErrorRef *error) {
+    if (![value isKindOfClass:[NSArray class]]) {
+        return SecError(errSecParam, error, CFSTR("value for %@ is not an array in revocation additions dictionary"), key);
+    }
+
+    __block bool result = true;
+    [(NSArray*)value enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if (!checker(obj)) {
+            result = SecError(errSecParam, error, CFSTR("value %lu for %@ is not the expected type"), (unsigned long)idx, key);
+            *stop = true;
+        }
+    }];
+    return result;
+}
+
+static bool checkInputAdditionsAndSetAppAdditions(NSDictionary *inAdditions, NSMutableDictionary *appAdditions, CFErrorRef *error) {
+    __block bool result = true;
+    [inAdditions enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
+        if ([key isEqualToString:(__bridge NSString*)kSecCARevocationAdditionsKey]) {
+            if (!checkCARevocationValues(key, obj, checkCARevocationValuesCompliance, error)) {
+                *stop = YES;
+                result = false;
+                return;
+            }
+        } else {
+            result = SecError(errSecParam, error, CFSTR("unknown key (%@) in additions dictionary"), key);
+            *stop = YES;
+            result = false;
+            return;
+        }
+        if ([(NSArray*)obj count] == 0) {
+            [appAdditions removeObjectForKey:key];
+        } else {
+            appAdditions[key] = obj;
+        }
+    }];
+    return result;
+}
+
+static _Atomic bool gHasCARevocationAdditions = false;
+#define kSecCARevocationChanged "com.apple.trustd.ca.revocation-changed"
+
+static NSURL *CARevocationFileURL() {
+    return CFBridgingRelease(SecCopyURLForFileInSystemKeychainDirectory(CFSTR("CARevocation.plist")));
+}
+
+static NSDictionary <NSString*,NSDictionary*> *readRevocationAdditionsFromDisk(NSError **error) {
+    secdebug("ocsp", "reading CA revocation additions from disk");
+    NSDictionary <NSString*,NSDictionary*> *allAdditions = [NSDictionary dictionaryWithContentsOfURL:CARevocationFileURL()
+                                                                                                error:error];
+    return allAdditions;
+}
+
+bool _SecTrustStoreSetCARevocationAdditions(CFStringRef appID, CFDictionaryRef additions, CFErrorRef *error)  {
+    if (!SecOTAPKIIsSystemTrustd()) {
+        secerror("Unable to write CA revocation additions from user agent");
+        return SecError(errSecWrPerm, error, CFSTR("Unable to write CA revocation additions from user agent"));
+    }
+
+    if (!appID) {
+        secerror("application-identifier required to set CA revocation additions");
+        return SecError(errSecParam, error, CFSTR("application-identifier required to set CA revocation additions"));
+    }
+
+    @autoreleasepool {
+        NSError *nserror = nil;
+        NSMutableDictionary *allAdditions = [readRevocationAdditionsFromDisk(&nserror) mutableCopy];
+        NSMutableDictionary *appAdditions = NULL;
+        if (allAdditions && allAdditions[(__bridge NSString*)appID]) {
+            appAdditions = [allAdditions[(__bridge NSString*)appID] mutableCopy];
+        } else {
+            appAdditions = [NSMutableDictionary dictionary];
+            if (!allAdditions) {
+                allAdditions =  [NSMutableDictionary dictionary];
+            }
+        }
+
+        if (additions && (CFDictionaryGetCount(additions) > 0)) {
+            NSDictionary *inAdditions = (__bridge NSDictionary*)additions;
+            if (!checkInputAdditionsAndSetAppAdditions(inAdditions, appAdditions, error)) {
+                secerror("input additions have error: %@", error ? *error : nil);
+                return false;
+            }
+        }
+
+        if (!additions || [appAdditions count] == 0) {
+            [allAdditions removeObjectForKey:(__bridge NSString*)appID];
+        } else {
+            allAdditions[(__bridge NSString*)appID] = appAdditions;
+        }
+
+        if (![allAdditions writeToURL:CARevocationFileURL() error:&nserror]) {
+            secerror("failed to write CA revocation additions: %@", nserror);
+            if (error) {
+                *error = CFRetainSafe((__bridge CFErrorRef)nserror);
+            }
+            return false;
+        }
+        secnotice("ocsp", "wrote %lu CA revocation additions", (unsigned long)[allAdditions count]);
+        atomic_store(&gHasCARevocationAdditions, [allAdditions count] != 0);
+        notify_post(kSecCARevocationChanged);
+        return true;
+    }
+}
+
+CFDictionaryRef _SecTrustStoreCopyCARevocationAdditions(CFStringRef appID, CFErrorRef *error) {
+    @autoreleasepool {
+        /* Set us up for not reading the disk when there are never exceptions */
+        static int notify_token = 0;
+        int check = 0;
+        static dispatch_once_t onceToken;
+        dispatch_once(&onceToken, ^{
+            /* initialize gHasCARevocation cache */
+            NSError *read_error = nil;
+            NSDictionary <NSString*,NSDictionary*> *allAdditions = readRevocationAdditionsFromDisk(&read_error);
+            if (!allAdditions || [allAdditions count] == 0) {
+                secnotice("ocsp", "skipping further reads. no CA revocation additions found: %@", read_error);
+                atomic_store(&gHasCARevocationAdditions, false);
+            } else {
+                secnotice("ocsp", "have CA revocation additions. will need to read.");
+                atomic_store(&gHasCARevocationAdditions, true);
+            }
+
+            /* read-only trustds register for notfications from the read-write trustd */
+            if (!SecOTAPKIIsSystemTrustd()) {
+                uint32_t status = notify_register_check(kSecCARevocationChanged, &notify_token);
+                if (status == NOTIFY_STATUS_OK) {
+                    status = notify_check(notify_token, NULL);
+                }
+                if (status != NOTIFY_STATUS_OK) {
+                    secerror("failed to establish notification for CA revocation additions: %u", status);
+                    notify_cancel(notify_token);
+                    notify_token = 0;
+                }
+            }
+        });
+
+        /* Read the negative cached value as to whether there are any revocation additions to read */
+        if (!SecOTAPKIIsSystemTrustd()) {
+            /* Check whether we got a notification. If we didn't, and there are no additions set, return NULL.
+             * Otherwise, we need to read from disk */
+            uint32_t check_status = notify_check(notify_token, &check);
+            if (check_status == NOTIFY_STATUS_OK && check == 0 && !atomic_load(&gHasCARevocationAdditions)) {
+                return NULL;
+            }
+        } else if (!atomic_load(&gHasCARevocationAdditions)) {
+            return NULL;
+        }
+
+        /* We need to read the exceptions from disk */
+        NSError *read_error = nil;
+        NSDictionary <NSString*,NSDictionary*> *allAdditions = readRevocationAdditionsFromDisk(&read_error);
+        if (!allAdditions || [allAdditions count] == 0) {
+            secnotice("ocsp", "skipping further reads. no CA revocation additions found: %@", read_error);
+            atomic_store(&gHasCARevocationAdditions, false);
+            return NULL;
+        }
+
+        /* If the caller specified an appID, return only the exceptions for that appID */
+        if (appID) {
+            return CFBridgingRetain(allAdditions[(__bridge NSString*)appID]);
+        }
+
+        /* Otherwise, combine all the revocation additions into one array */
+        NSMutableArray *caAdditions = [NSMutableArray array];
+        [allAdditions enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull __unused key, NSDictionary * _Nonnull appAdditions,
+                                                           BOOL * _Nonnull __unused stop) {
+            if (appAdditions[(__bridge NSString*)kSecCARevocationAdditionsKey] &&
+                checkCARevocationValues((__bridge NSString*)kSecCARevocationAdditionsKey,
+                                        appAdditions[(__bridge NSString*)kSecCARevocationAdditionsKey],
+                                        checkCARevocationValuesCompliance, error)) {
+                [caAdditions addObjectsFromArray:appAdditions[(__bridge NSString*)kSecCARevocationAdditionsKey]];
+            }
+        }];
+        NSMutableDictionary *additions = [NSMutableDictionary dictionaryWithCapacity:2];
+        if ([caAdditions count] > 0) {
+            additions[(__bridge NSString*)kSecCARevocationAdditionsKey] = caAdditions;
+        }
+        if ([additions count] > 0) {
+            secdebug("ocsp", "found %lu CA revocation additions on disk", (unsigned long)[additions count]);
+            atomic_store(&gHasCARevocationAdditions, true);
+            return CFBridgingRetain(additions);
+        }
+        return NULL;
+    }
+}
index dc6f6d2e017ee07377efedd3b026976bf33123ea..1709fd9cf920326ea124e6062ec3e302e921b58b 100644 (file)
                <string>com.apple.MobileAsset.PKITrustSupplementals</string>
                <string>com.apple.MobileAsset.SecExperimentAssets</string>
        </array>
+       <key>com.apple.private.security.storage.trustd</key>
+       <true/>
+       <key>com.apple.private.security.storage.trustd-private</key>
+       <true/>
+       <key>com.apple.private.security.storage.SFAnalytics</key>
+       <true/>
        <key>seatbelt-profiles</key>
        <array>
                <string>trustd</string>
index f13684b10f411f098fc8c177adb92a94c3f3772c..e7f0a6a780779fd03aa54ae1bf9b42187f3e3e3c 100644 (file)
@@ -38,6 +38,7 @@
 (allow file-read* file-write*
        (subpath "/private/var/db/mds/")
        (subpath "/private/var/db/crls/")
+       (subpath "/private/var/protected/")
        (subpath "/System/Library/Security/")
        (subpath "/Library/Keychains/")
        (subpath "/private/var/root/Library/Caches/com.apple.nsurlsessiond/"))
     (global-name "com.apple.securityd.xpc")
     (global-name "com.apple.cfnetwork.cfnetworkagent")
     (global-name "com.apple.nsurlsessiond")
+    (global-name "com.apple.dnssd.service")
     (xpc-service-name "com.apple.powerlog.plxpclogger.xpc")
     (global-name "com.apple.nesessionmanager.content-filter"))
 
 (allow ipc-posix-shm
        (ipc-posix-name "com.apple.AppleDatabaseChanged"))
 
+ ;; Read IOKit properties for personalization
+ (allow iokit-get-properties
+    (iokit-property "image4-supported")
+    (iokit-property "Content")
+    (iokit-property "boot-uuid")
+    (iokit-property "IORegistryEntryPropertyKeys")
+    (iokit-property "IOClassNameOverride")
+    (iokit-property "Protocol Characteristics")
+    (iokit-property "board-id")
+    (iokit-property "chip-id")
+    (iokit-property "unique-chip-id")
+    (iokit-property "boot-manifest-hash")
+    (iokit-property "crypto-hash-method"))
+
 (allow network-outbound)
 (allow system-socket)
index efa5ea47abd5978156894a9850b9c65b09f7e2ea..c880b49aa3045e398924478e1c7b998f09b27adc 100644 (file)
                <string>com.apple.MobileAsset.PKITrustSupplementals</string>
                <string>com.apple.MobileAsset.SecExperimentAssets</string>
        </array>
+       <key>com.apple.private.security.storage.trustd</key>
+       <true/>
+       <key>com.apple.private.security.storage.trustd-private</key>
+       <true/>
+       <key>com.apple.private.security.storage.SFAnalytics</key>
+       <true/>
 </dict>
 </plist>
index 02e9808a552328c5641751effb21d3c2accf50df..fc51d32de03037f64ed06261d476564794d9113b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 Apple Inc.  All Rights Reserved.
+ * Copyright (c) 2017-2020 Apple Inc.  All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -305,7 +305,7 @@ static bool SecXPC_OTASecExperiment_GetAsset(SecurityClient * __unused client, x
     return result;
 }
 
-static bool SecXPC_OTAPKI_CopyTrustedCTLogs(SecurityClient * __unused client, xpc_object_t event,
+static bool SecXPC_OTAPKI_CopyTrustedCTLogs(SecurityClient * __unused client, xpc_object_t __unused event,
                                             xpc_object_t reply, CFErrorRef *error) {
     bool result = false;
     CFDictionaryRef trustedLogs = SecOTAPKICopyCurrentTrustedCTLogs(error);
@@ -381,6 +381,33 @@ static bool SecXPCTrustStoreCopyCTExceptions(SecurityClient * __unused client, x
     return false;
 }
 
+static bool SecXPCTrustStoreSetCARevocationAdditions(SecurityClient *client, xpc_object_t event,
+                                                     xpc_object_t reply, CFErrorRef *error) {
+    CFStringRef appID = NULL;
+    CFDictionaryRef additions = NULL;
+    if (!SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error) || !appID) {
+        /* We always want to set the app ID with the additions */
+        appID = SecTaskCopyApplicationIdentifier(client->task);
+    }
+    (void)SecXPCDictionaryCopyDictionaryOptional(event, kSecTrustRevocationAdditionsKey, &additions, error);
+    bool result = _SecTrustStoreSetCARevocationAdditions(appID, additions, error);
+    xpc_dictionary_set_bool(reply, kSecXPCKeyResult, result);
+    CFReleaseNull(additions);
+    CFReleaseNull(appID);
+    return false;
+}
+
+static bool SecXPCTrustStoreCopyCARevocationAdditions(SecurityClient * __unused client, xpc_object_t event,
+                                                      xpc_object_t reply, CFErrorRef *error) {
+    CFStringRef appID = NULL;
+    (void)SecXPCDictionaryCopyStringOptional(event, kSecTrustEventApplicationID, &appID, error);
+    CFDictionaryRef additions = _SecTrustStoreCopyCARevocationAdditions(appID, error);
+    SecXPCDictionarySetPListOptional(reply, kSecTrustRevocationAdditionsKey, additions, error);
+    CFReleaseNull(additions);
+    CFReleaseNull(appID);
+    return false;
+}
+
 #if TARGET_OS_IPHONE
 static bool SecXPCTrustGetExceptionResetCount(SecurityClient * __unused client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error) {
     uint64_t exceptionResetCount = SecTrustServerGetExceptionResetCount(error);
@@ -404,6 +431,12 @@ static bool SecXPCTrustIncrementExceptionResetCount(SecurityClient * __unused cl
 }
 #endif
 
+static bool SecXPC_Valid_Update(SecurityClient * __unused client, xpc_object_t __unused event,
+                                xpc_object_t reply, CFErrorRef *error) {
+    xpc_dictionary_set_uint64(reply, kSecXPCKeyResult, SecRevocationDbUpdate(error));
+    return true;
+}
+
 typedef bool(*SecXPCOperationHandler)(SecurityClient *client, xpc_object_t event, xpc_object_t reply, CFErrorRef *error);
 
 typedef struct {
@@ -433,6 +466,9 @@ struct trustd_operations {
     SecXPCServerOperation trust_get_exception_reset_count;
     SecXPCServerOperation trust_increment_exception_reset_count;
 #endif
+    SecXPCServerOperation trust_store_set_ca_revocation_additions;
+    SecXPCServerOperation trust_store_copy_ca_revocation_additions;
+    SecXPCServerOperation valid_update;
 };
 
 static struct trustd_operations trustd_ops = {
@@ -457,6 +493,9 @@ static struct trustd_operations trustd_ops = {
     .trust_get_exception_reset_count = { NULL, SecXPCTrustGetExceptionResetCount },
     .trust_increment_exception_reset_count = { kSecEntitlementModifyAnchorCertificates, SecXPCTrustIncrementExceptionResetCount },
 #endif
+    .trust_store_set_ca_revocation_additions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreSetCARevocationAdditions },
+    .trust_store_copy_ca_revocation_additions = {kSecEntitlementModifyAnchorCertificates, SecXPCTrustStoreCopyCARevocationAdditions },
+    .valid_update = { NULL, SecXPC_Valid_Update },
 };
 
 static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc_object_t event) {
@@ -618,6 +657,15 @@ static void trustd_xpc_dictionary_handler(const xpc_connection_t connection, xpc
                     server_op = &trustd_ops.trust_increment_exception_reset_count;
                     break;
 #endif
+                case kSecXPCOpSetCARevocationAdditions:
+                    server_op = &trustd_ops.trust_store_set_ca_revocation_additions;
+                    break;
+                case kSecXPCOpCopyCARevocationAdditions:
+                    server_op = &trustd_ops.trust_store_copy_ca_revocation_additions;
+                    break;
+                case kSecXPCOpValidUpdate:
+                    server_op = &trustd_ops.valid_update;
+                    break;
                 default:
                     break;
             }
index 0ed05260c7bd736968868d495586d9a1f0853f6b..19233f066f7a67f619b0e4232fabe74f7ecd4191 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018 Apple Inc.  All Rights Reserved.
+ * Copyright (c) 2018-2020 Apple Inc.  All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -73,6 +73,9 @@ struct trustd trustd_spi = {
     .sec_trust_get_exception_reset_count    = SecTrustServerGetExceptionResetCount,
     .sec_trust_increment_exception_reset_count = SecTrustServerIncrementExceptionResetCount,
 #endif
+    .sec_trust_store_set_ca_revocation_additions = _SecTrustStoreSetCARevocationAdditions,
+    .sec_trust_store_copy_ca_revocation_additions = _SecTrustStoreCopyCARevocationAdditions,
+    .sec_valid_update = SecRevocationDbUpdate,
 };
 #endif
 
index 17f372c256c27be6b90784e461e69e2cd23e5993..35f07f11336f635f373650a5283629e05d02909c 100644 (file)
@@ -21,23 +21,23 @@ OCTAGON_ON[sdk=appletv*] = 1
 TRUSTEDPEERS_ON = 0
 TRUSTEDPEERS_ON[sdk=macosx*] = 1
 TRUSTEDPEERS_ON[sdk=iphone*] = 1
-TRUSTEDPEERS_ON[sdk=bridgeos*] = 1
+TRUSTEDPEERS_ON[sdk=bridgeos*] = 0
 TRUSTEDPEERS_ON[sdk=watch*] = 1
 TRUSTEDPEERS_ON[sdk=appletv*] = 1
 
 // SecureObject Sync should only be on on iOS and macOS, but until we have octagon, its on on watch and TV
 SECUREOBJECTSYNC_ON[sdk=iphone*] = 1
-SECUREOBJECTSYNC_ON[sdk=bridgeos*] = 1
+SECUREOBJECTSYNC_ON[sdk=bridgeos*] = 0
 SECUREOBJECTSYNC_ON[sdk=watch*] = 1
 SECUREOBJECTSYNC_ON[sdk=appletv*] = 1
 SECUREOBJECTSYNC_ON[sdk=macos*] = 1
 
-// Shared web credentials is only supported on iOS
+// Shared web credentials is supported on iOS and macOS and Catalyst
 SHAREDWEBCREDENTIALS_ON[sdk=iphone*] = 1
 SHAREDWEBCREDENTIALS_ON[sdk=bridgeos*] = 0
 SHAREDWEBCREDENTIALS_ON[sdk=watch*] = 0
 SHAREDWEBCREDENTIALS_ON[sdk=appletv*] = 0
-SHAREDWEBCREDENTIALS_ON[sdk=macos*] = 0
+SHAREDWEBCREDENTIALS_ON[sdk=macos*] = 1
 
 ABC_BUGCAPTURE_ON[sdk=iphoneos*] = 1
 ABC_BUGCAPTURE_ON[sdk=iphonesimulator*] = 0
index 1960abdc0453c015916204c7c6c6a1ba18dc66be..eef498f415b3630f57833c520fe63542a02a7c68 100644 (file)
@@ -1,17 +1,18 @@
-       
-OTHER_LDFLAGS_MOCK_AKS_LIBRARY = -laks_mock -framework SecurityFoundation
+
+OTHER_LDFLAGS_AKS_ACL_LIBRARY = -laks_acl
+
+OTHER_LDFLAGS_MOCK_AKS_LIBRARY = -laks_mock $(OTHER_LDFLAGS_AKS_ACL_LIBRARY) -framework SecurityFoundation -framework ProtocolBuffer
 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
 OTHER_LDFLAGS_AKS_LIBRARY[sdk=watchos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness
 OTHER_LDFLAGS_AKS_LIBRARY[sdk=appletvos*] = -L$(SDKROOT)/usr/local/lib -laks -laks_real_witness
-OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphonesimulator*] = -laks_mock -Wl,-upward_framework,SecurityFoundation -Wl,-upward_framework,ProtocolBuffer
+OTHER_LDFLAGS_AKS_LIBRARY[sdk=iphonesimulator*] = -laks_mock $(OTHER_LDFLAGS_AKS_ACL_LIBRARY) -Wl,-upward_framework,SecurityFoundation -Wl,-upward_framework,ProtocolBuffer
 
 OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=macosx*] = -framework MobileKeyBag
 OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=iphoneos*] = -framework MobileKeyBag
 OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=watchos*] = -framework MobileKeyBag
 OTHER_LDFLAGS_MOBILE_KEYBAG[sdk=appletvos*] = -framework MobileKeyBag
 
-OTHER_LDFLAGS_AKS_ACL_LIBRARY = -laks_acl
 
 OTHER_LDFLAGS_ACM_LIBRARY[sdk=macosx*] = -lACM
 OTHER_LDFLAGS_ACM_LIBRARY[sdk=iphoneos*] = -lACM
@@ -24,8 +25,11 @@ OTHER_LDFLAGS_ACM_LIBRARY[sdk=watchsimulator*] =
 OTHER_LDFLAGS_AGGREGATEDICTIONARY[sdk=embedded] = -framework AggregateDictionary
 OTHER_LDFLAGS_APPLESYSTEMINFO[sdk=macos*] = -framework AppleSystemInfo
 OTHER_LDFLAGS_DIAGNOSTICSMESSAGESCLIENT[sdk=macosx*] = -lDiagnosticMessagesClient
-OTHER_LDFLAGS_MOBILEGESTALT[sdk=embedded*] = -lMobileGestalt
+OTHER_LDFLAGS_MOBILEGESTALT = -lMobileGestalt
 OTHER_LDFLAGS_IMG4DECODE[sdk=embedded] = -lImg4Decode
+OTHER_LDFLAGS_IMG4DECODE[sdk=macosx*] = -lImg4Decode
+OTHER_LDFLAGS_MSUDATAACCESSOR[sdk=embedded] = -framework MSUDataAccessor
+OTHER_LDFLAGS_MSUDATAACCESSOR[sdk=macosx*] = -framework MSUDataAccessor
 OTHER_LDFLAGS_UPWARD_FOUNDATION = -Wl,-upward_framework,Foundation
 OTHER_LDFLAGS_UPWARD_PROTOCOLBUFFER = -Wl,-upward_framework,ProtocolBuffer
 OTHER_LDFLAGS_UPWARD_SECURITY = -Wl,-upward_framework,Security
@@ -70,7 +74,9 @@ OTHER_LDFLAGS_COREFOLLOWUP[sdk=appletvsimulator*] =
 // The bridge appears to support protocol buffers.
 OTHER_LDFLAGS_PROTOBUF = -framework ProtocolBuffer
 
+OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=macos*] =
 OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=iphoneos*] = -framework SharedWebCredentials
+OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=iphonesimulator*] = -framework SharedWebCredentials
 OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=bridgeos*] =
 OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=watchos*] =
 OTHER_LDFLAGS_SHAREDWEBCREDENTIALS[sdk=appletvos*] =
@@ -87,6 +93,9 @@ OTHER_LDFLAGS_MOBILEASSET[sdk=bridgeos*] =
 OTHER_LDFLAGS_CORECDP = -weak_framework CoreCDP
 OTHER_LDFLAGS_CORECDP[sdk=bridgeos*] =
 
+OTHER_LDFLAGS_CLOUDSERVICES = -weak_framework CloudServices
+OTHER_LDFLAGS_CLOUDSERVICES[sdk=bridgeos*] =
+
 OTHER_LDFLAGS_SECURITYFOUNDATION = -framework SecurityFoundation
 OTHER_LDFLAGS_SECURITYFOUNDATION[sdk=bridgeos*] =
 
@@ -98,7 +107,7 @@ OTHER_LDFLAGS_IMCORE[sdk=bridgeos*] =
 OTHER_LDFLAGS_UserManagement[sdk=iphone*] = -framework UserManagement
 OTHER_LDFLAGS_UserManagement[sdk=macosx*] = -framework UserManagement
 OTHER_LDFLAGS_UserManagement[sdk=watch*] =
-OTHER_LDFLAGS_UserManagement[sdk=appletv*] =
+OTHER_LDFLAGS_UserManagement[sdk=appletv*] = -framework UserManagement
 
 OTHER_LDFLAGS_CrashReporterSupport[sdk=iphoneos*] = -framework CrashReporterSupport
 OTHER_LDFLAGS_CrashReporterSupport[sdk=macosx*] =
@@ -112,3 +121,10 @@ OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_1 = -weak_framework SymptomDiagnosticRep
 OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_0 =
 OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_ =
 OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER = $(OTHER_LDFLAGS_SYMPTOMDIAGNOSTICREPORTER_$(ABC_BUGCAPTURE_ON))
+
+// Convince Xcode to build platform-specific apps from a single target
+OTHER_LDFLAGS_AppFrameworks[sdk=macosx*] = -framework AppKit
+OTHER_LDFLAGS_AppFrameworks[sdk=embedded*] = -framework UIKit
+
+TEST_HOST_BINARY_PATH_IN_BUNDLE[sdk=macosx*] = Contents/MacOS/
+TEST_HOST_BINARY_PATH_IN_BUNDLE[sdk=embedded] =
index 195db7c328ffdf2fe46ab6189f3147ee2894be7b..7c1df3ce173bfcfdb374fc88bdb01f7a786fa0f4 100644 (file)
@@ -24,7 +24,10 @@ SECURITY_FUZZER_BASE_DIR = /AppleInternal/CoreOS/Fuzzers/Security
 // Apple Clang - Code Generation
 CLANG_TRIVIAL_AUTO_VAR_INIT = pattern
 
-WARNING_CFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-error=deprecated-declarations -Wno-error=implicit-retain-self -Wno-error=#warnings -Wno-error=unused-function -Wno-error=unused-variable
+CLANG_CXX_LANGUAGE_STANDARD = gnu++2a
+GCC_C_LANGUAGE_STANDARD = gnu2x
+
+WARNING_CFLAGS = -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Wno-error=deprecated-declarations -Wno-error=deprecated-implementations -Wno-error=implicit-retain-self -Wno-error=#warnings -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=documentation
 
 
 WARNING_CFLAGS[sdk=embedded*] = $(WARNING_CFLAGS) -Wformat=2
diff --git a/xcconfig/all_arches.xcconfig b/xcconfig/all_arches.xcconfig
deleted file mode 100644 (file)
index cf6cff5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-ARCHS[sdk=macosx*] = $(ARCHS_STANDARD_32_64_BIT)
diff --git a/xcconfig/framework_requiring_modern_objc_runtime.xcconfig b/xcconfig/framework_requiring_modern_objc_runtime.xcconfig
deleted file mode 100644 (file)
index 5c058bc..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// For frameworks that should only be built when the modern obj-c runtime is available.
-// This file must be updated when new architectures are introduced.
-
-VALID_ARCHS = armv6 armv7 armv7k arm64 x86_64 x86_64h
-
-VALID_ARCHS[sdk=*simulator*] = armv6 armv7 armv7k arm64 i386 x86_64 x86_64h
index bdbaaffc89949b846762194cbeb3f60e5b443e23..334eb30b44319bdbc9d9e1ffe5df69b22a81d2a9 100644 (file)
@@ -18,7 +18,7 @@ COPY_PHASE_STRIP = NO
 SKIP_INSTALL = YES
 COPY_PHASE_STRIP = NO
 
-GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_C_LANGUAGE_STANDARD = gnu2x
 
 HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES = NO
 
index a968320ecc7bc48a60d63c8d4614377e6b8fbd65..bd7311fe496adee4c560815d02c1af229b0785b9 100644 (file)
@@ -16,3 +16,7 @@ OCTAGON_FLAG_1 = -D OCTAGON
 OTHER_SWIFT_FLAGS = $(OCTAGON_FLAG_$(OCTAGON_ON))
 
 SWIFT_VERSION=5
+SWIFT_TREAT_WARNINGS_AS_ERRORS = YES
+
+TEST_BUILD_STYLE = _APPLEINTERNAL
+SYSTEM_FRAMEWORK_SEARCH_PATHS = $(inherited) ${PLATFORM_DIR}/Developer/AppleInternal/Library/Frameworks
index ae4aae17ceae9f84c9a6e4c3668af0e447470cba..26b4b1b028b6d8cbb7114c906afe7a522fc09a82 100644 (file)
@@ -8,8 +8,9 @@ for a in ${TEST_FRAMEWORK_SEARCH_PATHS}; do
     if test -d "${a}/${framework}" ; then
         dst="${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}"
 
-           mkdir -p "{dst}" || { echo "mkdir failed with: $?" ; exit 1; }
+           mkdir -p "${dst}" || { echo "mkdir failed with: $?" ; exit 1; }
         ditto  "${a}/${framework}" "${dst}/${framework}" || { echo "ditto failed with: $?" ; exit 1; }
+        find "${dst}/${framework}" \( -name Headers -o -name Modules -o -name '*.tbd' \) -delete
         xcrun codesign -s - -f "${dst}/${framework}" || { echo "codesign failed with: $?" ; exit 1; }
 
         found=yes